Server Editor.cpp 54 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086
  1. /******************************************************************************/
  2. #include "stdafx.h"
  3. /******************************************************************************/
  4. EditorServer EditServer;
  5. /******************************************************************************/
  6. /******************************************************************************/
  7. void EditorServer::ConvertHeight(C Heightmap &src, Image &dest, flt area_size)
  8. {
  9. dest.createSoftTry(src.resolution(), src.resolution(), 1, IMAGE_F32);
  10. REPD(y, dest.h())
  11. REPD(x, dest.w())dest.pixF(x, y)=src.height(x, y)*area_size;
  12. }
  13. void EditorServer::ConvertHeight(Image &src, Heightmap &dest, flt area_size) // 'src' will get modified !!
  14. {
  15. src.resize(dest.resolution(), dest.resolution(), FILTER_BEST, true, false, true);
  16. REPD(y, dest.resolution())
  17. REPD(x, dest.resolution())dest.height(x, y, src.pixelF(x, y)/area_size);
  18. }
  19. void EditorServer::ConvertColor(C Heightmap &src, Image &dest)
  20. {
  21. dest.createSoftTry(src.resolution(), src.resolution(), 1, IMAGE_R8G8B8);
  22. REPD(y, dest.h())
  23. REPD(x, dest.w())dest.color(x, y, src.color(x, y));
  24. }
  25. void EditorServer::ConvertColor(Image &src, Heightmap &dest) // 'src' will get modified !!
  26. {
  27. src.resize(dest.resolution(), dest.resolution(), FILTER_BEST, true, false, true);
  28. REPD(y, dest.resolution())
  29. REPD(x, dest.resolution())dest.color(x, y, src.color(x, y));
  30. }
  31. void EditorServer::ConvertMaterial(C Heightmap &src, Edit::MaterialMap &dest)
  32. {
  33. Memt<UID> materials; materials.setNum(src.materials()); REPAO(materials)=src.material(i).id(); // set material palette
  34. dest.create(src.resolution());
  35. REPD(y, dest.resolution())
  36. REPD(x, dest.resolution())
  37. {
  38. VecB4 m, i;
  39. src.getMaterial(x, y, m, i);
  40. dest.set(x, y, InRange(m.x, materials) ? materials[m.x] : UIDZero,
  41. InRange(m.y, materials) ? materials[m.y] : UIDZero,
  42. InRange(m.z, materials) ? materials[m.z] : UIDZero,
  43. InRange(m.w, materials) ? materials[m.w] : UIDZero, i);
  44. }
  45. }
  46. void EditorServer::ConvertMaterial(Edit::MaterialMap &src, Heightmap &dest) // 'src' will get modified !!
  47. {
  48. src.resize(dest.resolution());
  49. REPD(y, dest.resolution())
  50. REPD(x, dest.resolution())
  51. {
  52. UID m[4];
  53. VecB4 i;
  54. src .get(x, y, m[0], m[1], m[2], m[3], i);
  55. dest.setMaterial(x, y, Proj.gamePath(m[0]), Proj.gamePath(m[1]), Proj.gamePath(m[2]), Proj.gamePath(m[3]), i);
  56. }
  57. }
  58. bool EditorServer::Client::update()
  59. {
  60. if(!::EE::Edit::EditorServer::Client::update())return false;
  61. int timeout=0;
  62. check_again:
  63. if(EditServer.busy)return true; // don't do anything if the editor is busy, wait until it finishes processing to update clients
  64. if(queued>=0) // if there was a queued command to be processed later, at this stage the 'EditServer' is no longer busy (if any publishing was requested, then it already finished)
  65. {
  66. File &f=connection.data.reset().putByte(queued);
  67. switch(queued)
  68. {
  69. case Edit::EI_EXPORT_APP: f.putBool(PublishOk); break; // save last publishing result
  70. }
  71. f.pos(0); connection.send(f);
  72. queued=-1;
  73. }
  74. if(connection_version_ok)
  75. if(connection.receive(timeout))
  76. {
  77. if(!EditServer.received) // if that's the first command we've received this frame
  78. {
  79. EditServer.received =true;
  80. EditServer.start_time=Time.curTimeMs(); // set time at the moment of first command receival, do this before processing of the command
  81. }
  82. byte cmd=connection.data.getByte();
  83. switch(cmd)
  84. {
  85. default: return false; // invalid command
  86. // PROJECT
  87. case Edit::EI_GET_PROJECTS_PATH:
  88. {
  89. File &f=connection.data.reset().putByte(Edit::EI_GET_PROJECTS_PATH).putStr(ProjectsPath); f.pos(0); connection.send(f);
  90. }break;
  91. case Edit::EI_SET_PROJECTS_PATH:
  92. {
  93. File &f=connection.data; Projs.proj_path.set(f.getStr());
  94. f.reset().putByte(Edit::EI_SET_PROJECTS_PATH).putBool(true); f.pos(0); connection.send(f);
  95. }break;
  96. case Edit::EI_GET_PROJECTS:
  97. {
  98. File &f=connection.data.reset().putByte(Edit::EI_GET_PROJECTS);
  99. Mems<Edit::Project> projects; projects.setNum(Projs.proj_data.elms());
  100. REPAO(projects).set(Projs.proj_data[i].id, Projs.proj_data[i].name);
  101. projects.save(f); f.pos(0); connection.send(f);
  102. }break;
  103. case Edit::EI_GET_PROJECT:
  104. {
  105. File &f=connection.data.reset().putByte(Edit::EI_GET_PROJECT).putUID(Proj.id); f.pos(0); connection.send(f);
  106. }break;
  107. case Edit::EI_SET_PROJECT:
  108. {
  109. UID proj_id; connection.data>>proj_id;
  110. if( proj_id!=Proj.id)
  111. {
  112. if(SaveChanges(null)) // nothing to save
  113. {
  114. EditServer.busy=true; // set as busy, so we don't respond to this client until we finish changing projects
  115. Projects::Elm *proj=Projs.findProj(proj_id);
  116. if( proj)if(!Projs.open(*proj))proj=null;
  117. if(!proj)StateProjectList.set(StateFadeTime);
  118. }
  119. }
  120. }break;
  121. // SETTINGS
  122. case Edit::EI_GET_DATA_PATH:
  123. {
  124. File &f=connection.data.reset().putByte(Edit::EI_GET_DATA_PATH)<<Proj.game_path; f.pos(0); connection.send(f);
  125. }break;
  126. // ELMS
  127. case Edit::EI_GET_ELMS:
  128. {
  129. Mems <Edit::Elm> mems;
  130. //Memc <Edit.Elm> memc;
  131. MemPtr<Edit::Elm> elms;
  132. if(Proj.valid())
  133. {
  134. const bool include_removed=true;
  135. if(include_removed)
  136. {
  137. mems.setNum(Proj.elms.elms()); FREPA(mems)
  138. {
  139. Edit::Elm &elm= mems[i];
  140. Elm &src=Proj.elms[i];
  141. elm.type =Edit::ELM_TYPE(src.type);
  142. elm.removed = src. removed();
  143. elm.publish =!src.noPublish();
  144. elm. id= src. id;
  145. elm.parent_id= src.parent_id;
  146. elm.name = src.name;
  147. elm.src_file = src.srcFile();
  148. }
  149. elms.point(mems);
  150. }else
  151. {
  152. /*memc.reserve(Proj.elms.elms());
  153. Proj.floodExisting(Proj.root, memc);
  154. elms.point(memc); */
  155. }
  156. }
  157. File &f=connection.data.reset().putByte(Edit::EI_GET_ELMS).putBool(elms); if(elms)elms.save(f); f.pos(0); connection.send(f);
  158. }break;
  159. case Edit::EI_GET_ELMS_SELECTED:
  160. {
  161. bool ok=false;
  162. Mems<UID> elms;
  163. if(Proj.valid())
  164. {
  165. ok=true;
  166. Proj.setListCurSel();
  167. elms=Proj.list_sel;
  168. }
  169. File &f=connection.data.reset().putByte(Edit::EI_GET_ELMS_SELECTED).putBool(ok); if(ok)elms.saveRaw(f); f.pos(0);
  170. connection.send(f);
  171. }break;
  172. case Edit::EI_SET_ELMS_SELECTED:
  173. {
  174. File &f=connection.data;
  175. bool ok=false;
  176. if(Proj.valid())
  177. {
  178. Mems<UID> elms; if(ok=elms.loadRaw(f))Proj.elmSelect(elms);
  179. }
  180. f.reset().putByte(Edit::EI_SET_ELMS_SELECTED).putBool(ok); f.pos(0); connection.send(f);
  181. }break;
  182. case Edit::EI_RLD_ELMS:
  183. {
  184. File &f=connection.data; bool remember_result=f.getBool();
  185. bool ok=false;
  186. if(Proj.valid())
  187. {
  188. Mems<UID> elms; if(elms.loadRaw(f))ok=Proj.elmReload(elms, remember_result);
  189. }
  190. f.reset().putByte(Edit::EI_RLD_ELMS).putBool(ok); f.pos(0); connection.send(f);
  191. }break;
  192. case Edit::EI_RLD_ELMS_CANCEL:
  193. {
  194. File &f=connection.data;
  195. bool ok=false;
  196. if(Proj.valid())
  197. {
  198. Mems<UID> elms; if(ok=elms.loadRaw(f))Proj.cancelReload(elms);
  199. }
  200. f.reset().putByte(Edit::EI_RLD_ELMS_CANCEL).putBool(ok); f.pos(0); connection.send(f);
  201. }break;
  202. case Edit::EI_RLD_ELMS_GET_RESULT:
  203. {
  204. File &f=connection.data;
  205. bool ok=false;
  206. Mems<Edit::IDParam<Edit::RELOAD_RESULT> > results;
  207. Mems<UID> elms; if(Proj.valid() && elms.loadRaw(f)){ok=true; Importer.getResult(elms, results);}
  208. f.reset().putByte(Edit::EI_RLD_ELMS_GET_RESULT).putBool(ok); if(ok)results.save(f); f.pos(0); connection.send(f);
  209. }break;
  210. case Edit::EI_RLD_ELMS_FORGET_RESULT:
  211. {
  212. File &f=connection.data;
  213. bool ok=false;
  214. Mems<UID> elms; if(ok=elms.loadRaw(f))Importer.forgetResult(elms);
  215. f.reset().putByte(Edit::EI_RLD_ELMS_FORGET_RESULT).putBool(ok); f.pos(0); connection.send(f);
  216. }break;
  217. case Edit::EI_NEW_ELM:
  218. {
  219. File &f =connection.data; ELM_TYPE type=ELM_TYPE(f.getByte()); Str name=f.getStr(); UID parent=f.getUID();
  220. Elm *elm=(Proj.valid() ? Proj.newElm(type, parent, &name) : null);
  221. f.reset().putByte(Edit::EI_NEW_ELM).putUID(AsID(elm)).pos(0); connection.send(f);
  222. }break;
  223. case Edit::EI_NEW_WORLD:
  224. {
  225. File &f =connection.data; Str name=f.getStr(); int area_size=f.getInt(); int terrain_res=f.getInt(); UID parent=f.getUID();
  226. Elm *elm=(Proj.valid() ? Proj.newWorld(name, area_size, terrain_res, parent, false) : null);
  227. f.reset().putByte(Edit::EI_NEW_WORLD).putUID(AsID(elm)).pos(0); connection.send(f);
  228. }break;
  229. case Edit::EI_SET_ELM_NAME:
  230. {
  231. bool ok=false;
  232. if(Proj.valid())
  233. {
  234. Memc<Edit::IDParam<Str> > elms; if(elms.load(connection.data))
  235. {
  236. ok=true;
  237. Proj.setElmNames(elms);
  238. }
  239. }
  240. File &f=connection.data.reset().putByte(Edit::EI_SET_ELM_NAME).putBool(ok); f.pos(0); connection.send(f);
  241. }break;
  242. case Edit::EI_SET_ELM_REMOVED:
  243. {
  244. bool ok=false;
  245. if(Proj.valid())
  246. {
  247. Memc<Edit::IDParam<bool> > elms; if(elms.load(connection.data))
  248. {
  249. ok=true;
  250. Memc<UID> remove, restore; FREPA(elms)if(elms[i].value)remove.add(elms[i].id);else restore.add(elms[i].id);
  251. Proj.remove (remove, false);
  252. Proj.restore(restore);
  253. }
  254. }
  255. File &f=connection.data.reset().putByte(Edit::EI_SET_ELM_REMOVED).putBool(ok); f.pos(0); connection.send(f);
  256. }break;
  257. case Edit::EI_SET_ELM_PUBLISH:
  258. {
  259. bool ok=false;
  260. if(Proj.valid())
  261. {
  262. Memc<Edit::IDParam<bool> > elms; if(elms.load(connection.data))
  263. {
  264. ok=true;
  265. Memc<UID> publish, no_publish; FREPA(elms)if(elms[i].value)publish.add(elms[i].id);else no_publish.add(elms[i].id);
  266. Proj.disablePublish(no_publish, false);
  267. Proj. enablePublish( publish);
  268. }
  269. }
  270. File &f=connection.data.reset().putByte(Edit::EI_SET_ELM_PUBLISH).putBool(ok); f.pos(0); connection.send(f);
  271. }break;
  272. case Edit::EI_SET_ELM_PARENT:
  273. {
  274. bool ok=false;
  275. if(Proj.valid())
  276. {
  277. Memc<Edit::IDParam<UID> > elms; if(elms.load(connection.data))
  278. {
  279. ok=true;
  280. Proj.setElmParent(elms);
  281. }
  282. }
  283. File &f=connection.data.reset().putByte(Edit::EI_SET_ELM_PARENT).putBool(ok); f.pos(0); connection.send(f);
  284. }break;
  285. case Edit::EI_SET_ELM_SRC_FILE:
  286. {
  287. bool ok=false;
  288. if(Proj.valid())
  289. {
  290. Memc<Edit::IDParam<Str> > elms; if(elms.load(connection.data))
  291. {
  292. ok=true;
  293. TimeStamp time; time.getUTC();
  294. FREPA(elms)if(Elm *elm=Proj.findElm(elms[i].id))
  295. {
  296. elm->setSrcFile(elms[i].value, time);
  297. Server.setElmShort(elm->id);
  298. }
  299. }
  300. }
  301. File &f=connection.data.reset().putByte(Edit::EI_SET_ELM_SRC_FILE).putBool(ok); f.pos(0); connection.send(f);
  302. }break;
  303. // WORLD
  304. case Edit::EI_GET_WORLD:
  305. {
  306. File &f=connection.data.reset().putByte(Edit::EI_GET_WORLD).putUID(WorldEdit.elm_id); f.pos(0); connection.send(f);
  307. }break;
  308. case Edit::EI_SET_WORLD:
  309. {
  310. File &f=connection.data; UID world_id=f.getUID();
  311. WorldEdit.activate(Proj.findElm(world_id, ELM_WORLD));
  312. f.reset().putByte(Edit::EI_SET_WORLD).putBool(WorldEdit.elm_id==world_id).pos(0); connection.send(f);
  313. }break;
  314. case Edit::EI_GET_WORLD_AREA_SIZE:
  315. {
  316. File &f=connection.data; UID world_id=f.getUID();
  317. int area_size=0; if(Elm *world=Proj.findElm(world_id, ELM_WORLD))if(ElmWorld *data=world->worldData())area_size=data->area_size;
  318. f.reset().putByte(Edit::EI_GET_WORLD_AREA_SIZE).putInt(area_size); f.pos(0); connection.send(f);
  319. }break;
  320. case Edit::EI_GET_WORLD_TERRAIN_RES:
  321. {
  322. File &f=connection.data; UID world_id=f.getUID();
  323. int terrain_res=0; if(Elm *world=Proj.findElm(world_id, ELM_WORLD))if(ElmWorld *data=world->worldData())terrain_res=data->hmRes();
  324. f.reset().putByte(Edit::EI_GET_WORLD_TERRAIN_RES).putInt(terrain_res); f.pos(0); connection.send(f);
  325. }break;
  326. case Edit::EI_GET_WORLD_TERRAIN_AREAS:
  327. {
  328. File &f=connection.data; UID world_id=f.getUID();
  329. bool ok=false; RectI areas;
  330. if(Elm *world=Proj.findElm(world_id, ELM_WORLD))if(WorldVer *world_ver=Proj.worldVerGet(world_id))
  331. {
  332. ok=true; areas=world_ver->getTerrainAreas();
  333. }
  334. f.reset().putByte(Edit::EI_GET_WORLD_TERRAIN_AREAS).putBool(ok); if(ok)f<<areas; f.pos(0); connection.send(f);
  335. }break;
  336. // WORLD TERRAIN
  337. case Edit::EI_DEL_WORLD_TERRAIN:
  338. {
  339. File &f=connection.data; UID world_id=f.getUID(); VecI2 area_xy; area_xy.x=f.decIntV(); area_xy.y=f.decIntV();
  340. bool ok=false;
  341. if(Elm *world=Proj.findElm(world_id, ELM_WORLD))
  342. {
  343. ok=true;
  344. Proj.hmDel(world_id, area_xy);
  345. Synchronizer.delayedSetArea(world_id, area_xy);
  346. }
  347. f.reset().putByte(Edit::EI_DEL_WORLD_TERRAIN).putBool(ok).pos(0); connection.send(f);
  348. }break;
  349. case Edit::EI_GET_WORLD_TERRAIN_IS:
  350. {
  351. File &f=connection.data; UID world_id=f.getUID(); VecI2 area_xy; area_xy.x=f.decIntV(); area_xy.y=f.decIntV();
  352. bool is=false;
  353. if(Elm *world=Proj.findElm(world_id, ELM_WORLD))
  354. if(WorldVer *world_ver=Proj.worldVerGet(world_id))is=world_ver->hasHm(area_xy);
  355. f.reset().putByte(Edit::EI_GET_WORLD_TERRAIN_IS).putBool(is).pos(0); connection.send(f);
  356. }break;
  357. case Edit::EI_GET_WORLD_TERRAIN_HEIGHT:
  358. {
  359. File &f=connection.data; UID world_id=f.getUID(); VecI2 area_xy; area_xy.x=f.decIntV(); area_xy.y=f.decIntV();
  360. bool ok=false;
  361. Image height;
  362. if(Elm *world=Proj.findElm(world_id, ELM_WORLD))
  363. if(world->worldData()->valid())
  364. if(WorldVer *world_ver=Proj.worldVerGet(world_id))
  365. {
  366. ok=true;
  367. Heightmap temp, *hm=null;
  368. if(hm=Proj.hmGet(world_id, area_xy, temp))ConvertHeight(*hm, height, world->worldData()->area_size);
  369. }
  370. f.reset().putByte(Edit::EI_GET_WORLD_TERRAIN_HEIGHT).putBool(ok); if(ok)height.save(f); f.pos(0); connection.send(f);
  371. }break;
  372. case Edit::EI_SET_WORLD_TERRAIN_HEIGHT:
  373. {
  374. File &f=connection.data; UID world_id=f.getUID(); VecI2 area_xy; area_xy.x=f.decIntV(); area_xy.y=f.decIntV(); UID material_id=f.getUID(); Image height;
  375. bool ok=false;
  376. if(height.load(f))
  377. if(Elm *world=Proj.findElm(world_id, ELM_WORLD))
  378. if(world->worldData()->valid())
  379. if(WorldVer *world_ver=Proj.worldVerGet(world_id))
  380. {
  381. AreaVer *dest_area_ver=world_ver->areas.find(area_xy);
  382. if(!Proj.findElm(material_id, ELM_MTRL))material_id=Proj.hm_mtrl_id; // use default material if specified doesn't exist
  383. if(material_id.valid() || (dest_area_ver && dest_area_ver->hasHm())) // we have a valid material or there already exists terrain (which has material set)
  384. {
  385. ok=true;
  386. Heightmap hm;
  387. hm.create(world->worldData()->hm_res, 0, Proj.gamePath(material_id), false, null, null, null, null, null, null, null, null);
  388. ConvertHeight(height, hm, world->worldData()->area_size);
  389. AreaVer area_ver;
  390. area_ver.hm_height_time.getUTC();
  391. area_ver.hm_mtrl_time =(dest_area_ver ? dest_area_ver->hm_removed_time.u : 0)+1; // don't inherit material if the heightmap is currently removed
  392. area_ver.hm_color_time =(dest_area_ver ? dest_area_ver->hm_removed_time.u : 0)+1; // don't inherit color if the heightmap is currently removed
  393. if(Proj.hmUpdate(world_id, area_xy, AREA_SYNC_HM, area_ver, hm))Synchronizer.delayedSetArea(world_id, area_xy);
  394. }
  395. }
  396. f.reset().putByte(Edit::EI_SET_WORLD_TERRAIN_HEIGHT).putBool(ok).pos(0); connection.send(f);
  397. }break;
  398. case Edit::EI_GET_WORLD_TERRAIN_COLOR:
  399. {
  400. File &f=connection.data; UID world_id=f.getUID(); VecI2 area_xy; area_xy.x=f.decIntV(); area_xy.y=f.decIntV();
  401. bool ok=false;
  402. Image color;
  403. if(Elm *world=Proj.findElm(world_id, ELM_WORLD))
  404. if(WorldVer *world_ver=Proj.worldVerGet(world_id))
  405. {
  406. ok=true;
  407. Heightmap temp, *hm=null;
  408. if(hm=Proj.hmGet(world_id, area_xy, temp))ConvertColor(*hm, color);
  409. }
  410. f.reset().putByte(Edit::EI_GET_WORLD_TERRAIN_COLOR).putBool(ok); if(ok)color.save(f); f.pos(0); connection.send(f);
  411. }break;
  412. case Edit::EI_SET_WORLD_TERRAIN_COLOR:
  413. {
  414. File &f=connection.data; UID world_id=f.getUID(); VecI2 area_xy; area_xy.x=f.decIntV(); area_xy.y=f.decIntV(); UID material_id=f.getUID(); Image color;
  415. bool ok=false;
  416. if(color.load(f))
  417. if(Elm *world=Proj.findElm(world_id, ELM_WORLD))
  418. if(world->worldData()->valid())
  419. if(WorldVer *world_ver=Proj.worldVerGet(world_id))
  420. {
  421. AreaVer *dest_area_ver=world_ver->areas.find(area_xy);
  422. if(!Proj.findElm(material_id, ELM_MTRL))material_id=Proj.hm_mtrl_id; // use default material if specified doesn't exist
  423. if(material_id.valid() || (dest_area_ver && dest_area_ver->hasHm())) // we have a valid material or there already exists terrain (which has material set)
  424. {
  425. ok=true;
  426. Heightmap hm;
  427. hm.create(world->worldData()->hm_res, 0, Proj.gamePath(material_id), false, null, null, null, null, null, null, null, null);
  428. ConvertColor(color, hm);
  429. // the destination heightmap may not exist or be removed, in that case we want to create it (height_time must be one more than dest removed_time)
  430. AreaVer area_ver;
  431. area_ver.hm_height_time=(dest_area_ver ? dest_area_ver->hm_removed_time.u : 0)+1;
  432. area_ver.hm_mtrl_time =(dest_area_ver ? dest_area_ver->hm_removed_time.u : 0)+1; // don't inherit material if the heightmap is currently removed
  433. area_ver.hm_color_time.getUTC();
  434. if(Proj.hmUpdate(world_id, area_xy, AREA_SYNC_HM, area_ver, hm))Synchronizer.delayedSetArea(world_id, area_xy);
  435. }
  436. }
  437. f.reset().putByte(Edit::EI_SET_WORLD_TERRAIN_COLOR).putBool(ok).pos(0); connection.send(f);
  438. }break;
  439. case Edit::EI_GET_WORLD_TERRAIN_MATERIAL:
  440. {
  441. File &f=connection.data; UID world_id=f.getUID(); VecI2 area_xy; area_xy.x=f.decIntV(); area_xy.y=f.decIntV();
  442. bool ok=false;
  443. Edit::MaterialMap material;
  444. if(Elm *world=Proj.findElm(world_id, ELM_WORLD))
  445. if(WorldVer *world_ver=Proj.worldVerGet(world_id))
  446. {
  447. ok=true;
  448. Heightmap temp, *hm=null;
  449. if(hm=Proj.hmGet(world_id, area_xy, temp))ConvertMaterial(*hm, material);
  450. }
  451. f.reset().putByte(Edit::EI_GET_WORLD_TERRAIN_MATERIAL).putBool(ok); if(ok)material.save(f); f.pos(0); connection.send(f);
  452. }break;
  453. case Edit::EI_SET_WORLD_TERRAIN_MATERIAL:
  454. {
  455. File &f=connection.data; UID world_id=f.getUID(); VecI2 area_xy; area_xy.x=f.decIntV(); area_xy.y=f.decIntV(); Edit::MaterialMap material;
  456. bool ok=false;
  457. if(material.load(f))
  458. if(Elm *world=Proj.findElm(world_id, ELM_WORLD))
  459. if(world->worldData()->valid())
  460. if(WorldVer *world_ver=Proj.worldVerGet(world_id))
  461. {
  462. AreaVer *dest_area_ver=world_ver->areas.find(area_xy);
  463. ok=true;
  464. Heightmap hm;
  465. hm.create(world->worldData()->hm_res, 0, S, false, null, null, null, null, null, null, null, null);
  466. ConvertMaterial(material, hm);
  467. // the destination heightmap may not exist or be removed, in that case we want to create it (height_time must be one more than dest removed_time)
  468. AreaVer area_ver;
  469. area_ver.hm_height_time=(dest_area_ver ? dest_area_ver->hm_removed_time.u : 0)+1;
  470. area_ver.hm_mtrl_time .getUTC();
  471. area_ver.hm_color_time =(dest_area_ver ? dest_area_ver->hm_removed_time.u : 0)+1; // don't inherit color if the heightmap is currently removed
  472. if(Proj.hmUpdate(world_id, area_xy, AREA_SYNC_HM, area_ver, hm))Synchronizer.delayedSetArea(world_id, area_xy);
  473. }
  474. f.reset().putByte(Edit::EI_SET_WORLD_TERRAIN_MATERIAL).putBool(ok).pos(0); connection.send(f);
  475. }break;
  476. case Edit::EI_GET_WORLD_TERRAIN:
  477. {
  478. File &f=connection.data; UID world_id=f.getUID(); VecI2 area_xy; area_xy.x=f.decIntV(); area_xy.y=f.decIntV(); bool expects_color=f.getBool();
  479. bool ok=false;
  480. Image height, color;
  481. Edit::MaterialMap material;
  482. if(Elm *world=Proj.findElm(world_id, ELM_WORLD))
  483. if(world->worldData()->valid())
  484. if(WorldVer *world_ver=Proj.worldVerGet(world_id))
  485. {
  486. ok=true;
  487. Heightmap temp, *hm=null;
  488. if(hm=Proj.hmGet(world_id, area_xy, temp))
  489. {
  490. ConvertHeight (*hm, height, world->worldData()->area_size);
  491. ConvertMaterial(*hm, material);
  492. if(expects_color)ConvertColor (*hm, color);
  493. }
  494. }
  495. f.reset().putByte(Edit::EI_GET_WORLD_TERRAIN).putBool(ok); if(ok){height.save(f); material.save(f); if(expects_color)color.save(f);} f.pos(0);
  496. connection.send(f);
  497. }break;
  498. case Edit::EI_SET_WORLD_TERRAIN:
  499. {
  500. File &f=connection.data; UID world_id=f.getUID(); VecI2 area_xy; area_xy.x=f.decIntV(); area_xy.y=f.decIntV(); bool has_color=f.getBool();
  501. Image height, color; Edit::MaterialMap material;
  502. bool ok=false;
  503. if( height .load(f))
  504. if( material.load(f))
  505. if(has_color ? color .load(f) : true)
  506. if(Elm *world=Proj.findElm(world_id, ELM_WORLD))
  507. if(world->worldData()->valid())
  508. if(WorldVer *world_ver=Proj.worldVerGet(world_id))
  509. {
  510. AreaVer *dest_area_ver=world_ver->areas.find(area_xy);
  511. ok=true;
  512. Heightmap hm;
  513. hm.create(world->worldData()->hm_res, 0, S, false, null, null, null, null, null, null, null, null);
  514. ConvertHeight (height , hm, world->worldData()->area_size);
  515. ConvertMaterial(material, hm);
  516. if(has_color)ConvertColor (color , hm);
  517. // the destination heightmap may not exist or be removed, in that case we want to create it (height_time must be one more than dest removed_time)
  518. AreaVer area_ver; TimeStamp utc; utc.getUTC();
  519. area_ver.hm_height_time=utc;
  520. area_ver.hm_mtrl_time =utc;
  521. area_ver.hm_color_time =utc;
  522. if(Proj.hmUpdate(world_id, area_xy, AREA_SYNC_HM, area_ver, hm))Synchronizer.delayedSetArea(world_id, area_xy);
  523. }
  524. f.reset().putByte(Edit::EI_SET_WORLD_TERRAIN).putBool(ok).pos(0); connection.send(f);
  525. }break;
  526. // WORLD OBJECTS
  527. case Edit::EI_NEW_WORLD_OBJ:
  528. {
  529. File &f=connection.data; UID world_id=f.getUID();
  530. bool ok=false;
  531. if(Elm *world=Proj.findElm(world_id, ELM_WORLD))
  532. if(world->worldData()->valid())
  533. if(flt area_size=world->worldData()->area_size)
  534. {
  535. Memc<Edit::WorldObjParams> objs; if(objs.load(f))
  536. {
  537. ok=true;
  538. Memc<ObjData> area_objs;
  539. Memc<UID > added_objs;
  540. Heightmap hm_temp, *hm=null;
  541. for(; objs.elms(); )
  542. {
  543. bool have_area=false, have_hm=false;
  544. VecI2 area_xy;
  545. Heightmap *hm=null;
  546. REPA(objs) // go from end because we're removing
  547. {
  548. Edit::WorldObjParams &src=objs[i];
  549. VecI2 obj_area=Floor(src.matrix.pos.xz()/area_size);
  550. if(!have_area){have_area=true; area_xy=obj_area;} // setup area of the first object
  551. if(obj_area==area_xy) // object matches target area
  552. {
  553. if(Elm *obj_elm=Proj.findElm(src.id, ELM_OBJ)) // if it's a valid ELM_OBJ
  554. {
  555. ObjData &dest=area_objs.New().create(src, Proj.edit_path);
  556. if(src.align_to_terrain || src.align_to_terrain_normal>EPS) // want to align
  557. {
  558. if(!have_hm) // load heightmap
  559. {
  560. have_hm=true;
  561. hm=Proj.hmGet(world_id, area_xy, hm_temp);
  562. }
  563. if(hm)
  564. {
  565. if(src.align_to_terrain) // set position
  566. {
  567. dest.matrix.pos.y=HmHeight(*hm, area_size, area_xy, dest.matrix.pos);
  568. }
  569. if(src.align_to_terrain_normal>EPS) // align to terrain normal
  570. {
  571. // get object mesh
  572. MeshPtr mesh;
  573. if(ElmObj *obj_data=obj_elm->objData())mesh=Proj.gamePath(obj_data->mesh_id);
  574. Vec normal=HmNormalAvg(*hm, area_size, area_xy, dest.matrix, mesh ? mesh->ext : Extent(0.5f));
  575. dest.matrix.orn()*=Matrix3().setRotation(Vec(0, 1, 0), normal, Sat(src.align_to_terrain_normal));
  576. }
  577. }
  578. }
  579. added_objs.add(dest.id); // add the world object id (and not the ELM_OBJ id)
  580. }
  581. objs.remove(i); // we've processed it so remove it
  582. }
  583. }
  584. // insert those objects
  585. if(area_objs.elms())
  586. {
  587. Proj.syncObj(world_id, area_xy, area_objs);
  588. area_objs.clear();
  589. }
  590. }
  591. Synchronizer.delayedSetObj(world_id, added_objs);
  592. }
  593. }
  594. f.reset().putByte(Edit::EI_NEW_WORLD_OBJ).putBool(ok).pos(0); connection.send(f);
  595. }break;
  596. case Edit::EI_GET_WORLD_OBJ_BASIC:
  597. {
  598. File &f=connection.data; UID world_id=f.getUID(); bool limit_areas=f.getBool(); RectI areas; if(limit_areas)f>>areas; bool only_selected=f.getBool(); bool include_removed=f.getBool();
  599. Memc<UID> world_obj_instance_ids; world_obj_instance_ids.loadRaw(f); world_obj_instance_ids.sort(Compare); bool limit_obj_ids=(world_obj_instance_ids.elms()>0);
  600. bool ok=false;
  601. Memc<Edit::WorldObjDesc> objs;
  602. if(Elm *world=Proj.findElm(world_id, ELM_WORLD))
  603. if(world->worldData()->valid())
  604. if(WorldVer *world_ver=Proj.worldVerGet(world_id))
  605. {
  606. ok=true;
  607. if(only_selected)
  608. {
  609. if(world_id==WorldEdit.elm_id)REPA(Selection)
  610. {
  611. Obj &src=Selection[i];
  612. if(src.area)
  613. if(include_removed ? true : !src.removed)
  614. if(limit_areas ? Cuts(src.area->xy, areas) : true )
  615. if(limit_obj_ids ? world_obj_instance_ids.binaryHas(src.id, Compare) : true )
  616. {
  617. Edit::WorldObjDesc &obj=objs.New();
  618. obj.instance_id=src.id;
  619. obj. elm_obj_id=src.params.base.id();
  620. obj. matrix=src.matrix;
  621. obj. removed=src.removed;
  622. obj. selected=true;
  623. }
  624. }
  625. }else
  626. {
  627. MapLock ml(world_ver->obj);
  628. if(limit_obj_ids)
  629. {
  630. FREPA(world_obj_instance_ids)
  631. {
  632. C UID &src_id=world_obj_instance_ids[i];
  633. if(C ObjVer *src =world_ver->obj.find(src_id)) // if object actually exists
  634. if(include_removed ? true : !src->removed())
  635. if(limit_areas ? Cuts(src->area_xy, areas) : true )
  636. {
  637. Edit::WorldObjDesc &obj=objs.New();
  638. obj.instance_id=src_id;
  639. obj. elm_obj_id=src->elm_obj_id;
  640. obj. matrix=src->matrix();
  641. obj. removed=src->removed();
  642. obj. selected=Selection.has(src_id);
  643. }
  644. }
  645. }else
  646. {
  647. REPA(world_ver->obj)
  648. {
  649. C UID &src_id=world_ver->obj.lockedKey (i);
  650. C ObjVer &src =world_ver->obj.lockedData(i);
  651. if(include_removed ? true : !src.removed())
  652. if(limit_areas ? Cuts(src.area_xy, areas) : true )
  653. {
  654. Edit::WorldObjDesc &obj=objs.New();
  655. obj.instance_id=src_id;
  656. obj. elm_obj_id=src.elm_obj_id;
  657. obj. matrix=src.matrix();
  658. obj. removed=src.removed();
  659. obj. selected=Selection.has(src_id);
  660. }
  661. }
  662. }
  663. }
  664. }
  665. f.reset().putByte(Edit::EI_GET_WORLD_OBJ_BASIC).putBool(ok); if(ok)objs.save(f); f.pos(0); connection.send(f);
  666. }break;
  667. case Edit::EI_GET_WORLD_OBJ_FULL:
  668. {
  669. File &f=connection.data; UID world_id=f.getUID(); bool limit_areas=f.getBool(); RectI areas; if(limit_areas)f>>areas; bool only_selected=f.getBool(); bool include_removed=f.getBool(); bool include_removed_params=f.getBool();
  670. Memc<UID> world_obj_instance_ids; world_obj_instance_ids.loadRaw(f); bool limit_obj_ids=(world_obj_instance_ids.elms()>0);
  671. bool ok=false;
  672. Memc<Edit::WorldObjData> objs;
  673. if(Elm *world=Proj.findElm(world_id, ELM_WORLD))
  674. if(world->worldData()->valid())
  675. if(WorldVer *world_ver=Proj.worldVerGet(world_id))
  676. {
  677. ok=true;
  678. if(world_obj_instance_ids.elms()) // filter out selected objects
  679. {
  680. REPA(world_obj_instance_ids)
  681. {
  682. C UID &src_id=world_obj_instance_ids[i];
  683. if(C ObjVer *src =world_ver->obj.find(src_id)) // if object actually exists
  684. if(include_removed ? true : !src->removed())
  685. if(limit_areas ? Cuts(src->area_xy, areas) : true )
  686. if(only_selected ? Selection.has(src_id) : true )continue;
  687. world_obj_instance_ids.remove(i); // doesn't meet the criteria so remove it
  688. }
  689. }else // setup objects based on criteria
  690. {
  691. if(only_selected)
  692. {
  693. if(world_id==WorldEdit.elm_id)REPA(Selection)
  694. {
  695. Obj &src=Selection[i];
  696. if(src.area)
  697. if(include_removed ? true : !src.removed)
  698. if(limit_areas ? Cuts(src.area->xy, areas) : true )world_obj_instance_ids.add(src.id);
  699. }
  700. }else
  701. {
  702. MapLock ml(world_ver->obj);
  703. REPA(world_ver->obj)
  704. {
  705. C UID &src_id=world_ver->obj.lockedKey (i);
  706. C ObjVer &src =world_ver->obj.lockedData(i);
  707. if(include_removed ? true : !src.removed())
  708. if(limit_areas ? Cuts(src.area_xy, areas) : true )world_obj_instance_ids.add(src_id);
  709. }
  710. }
  711. }
  712. // gather all areas
  713. Memc<VecI2> areas;
  714. REPA(world_obj_instance_ids)
  715. if(C ObjVer *src=world_ver->obj.find(world_obj_instance_ids[i]))
  716. areas.binaryInclude(src->area_xy, Compare);
  717. world_obj_instance_ids.sort(Compare); // sort obj id's because that's required for the 'objGet' below
  718. Memc<ObjData> area_objs;
  719. FREPA(areas)
  720. {
  721. Proj.objGet(world_id, areas[i], world_obj_instance_ids, area_objs);
  722. FREPA(area_objs)
  723. {
  724. C ObjData &src=area_objs[i];
  725. Edit::WorldObjData &obj=objs.New();
  726. obj.instance_id=src.id;
  727. obj. elm_obj_id=src.params.base.id();
  728. obj. matrix=src.matrix;
  729. obj. removed=src.removed;
  730. obj. selected=Selection.has(src.id);
  731. src.params.copyTo(obj, include_removed_params);
  732. }
  733. area_objs.clear();
  734. }
  735. }
  736. f.reset().putByte(Edit::EI_GET_WORLD_OBJ_FULL).putBool(ok); if(ok)objs.save(f); f.pos(0); connection.send(f);
  737. }break;
  738. // WORLD WAYPOINTS
  739. case Edit::EI_GET_WORLD_WAYPOINT_LIST:
  740. {
  741. File &f=connection.data; UID world_id=f.getUID();
  742. f.reset().putByte(Edit::EI_GET_WORLD_WAYPOINT_LIST);
  743. bool ok=false; Memc<UID> waypoints;
  744. if(C Elm *world=Proj.findElm(world_id, ELM_WORLD))
  745. if(world->worldData()->valid())
  746. if(C WorldVer *world_ver=Proj.worldVerGet(world_id))
  747. {
  748. ok=true;
  749. FREPA(world_ver->waypoints)if(Proj.waypointExists(world_id, world_ver->waypoints.lockedKey(i)))waypoints.add(world_ver->waypoints.lockedKey(i));
  750. }
  751. f.putBool(ok); if(ok)waypoints.saveRaw(f); f.pos(0); connection.send(f);
  752. }break;
  753. // WORLD CAMERA
  754. case Edit::EI_GET_WORLD_CAM:
  755. {
  756. File &f=connection.data.reset().putByte(Edit::EI_GET_WORLD_CAM); WorldEdit.v4.view[Edit::Viewport4::VIEW_FRONT].camera.save(f); f.pos(0);
  757. connection.send(f);
  758. }break;
  759. case Edit::EI_SET_WORLD_CAM:
  760. {
  761. File &f=connection.data; Camera cam; bool ok=cam.load(f); if(ok)WorldEdit.v4.view[Edit::Viewport4::VIEW_FRONT].camera=cam;
  762. f.reset().putByte(Edit::EI_SET_WORLD_CAM).putBool(ok).pos(0); connection.send(f);
  763. }break;
  764. // WORLD DRAW
  765. case Edit::EI_DRAW_WORLD_LINES:
  766. {
  767. File &f=connection.data; bool ok=WorldEdit.lines.load(f);
  768. f.reset().putByte(Edit::EI_DRAW_WORLD_LINES).putBool(ok).pos(0); connection.send(f);
  769. }break;
  770. // IMAGE
  771. case Edit::EI_GET_IMAGE:
  772. {
  773. File &f=connection.data; UID elm_id=f.getUID();
  774. Image image; bool ok=Proj.imageGet(elm_id, image);
  775. f.reset().putByte(Edit::EI_GET_IMAGE).putBool(ok); if(ok)image.save(f); f.pos(0); connection.send(f);
  776. }break;
  777. case Edit::EI_SET_IMAGE:
  778. {
  779. File &f=connection.data; UID elm_id=f.getUID(); Image image;
  780. bool ok=false; if(image.load(f))if(Proj.imageSet(elm_id, image))ok=true;
  781. f.reset().putByte(Edit::EI_SET_IMAGE).putBool(ok).pos(0); connection.send(f);
  782. }break;
  783. // CODE
  784. case Edit::EI_GET_CODE:
  785. {
  786. File &f=connection.data; UID elm_id=f.getUID();
  787. Str code; bool ok=Proj.codeGet(elm_id, code);
  788. f.reset().putByte(Edit::EI_GET_CODE).putBool(ok); if(ok)code.save(f); f.pos(0); connection.send(f);
  789. }break;
  790. case Edit::EI_SET_CODE:
  791. {
  792. File &f=connection.data; UID elm_id=f.getUID(); Str code=f.getStr();
  793. bool ok=Proj.codeSet(elm_id, code);
  794. f.reset().putByte(Edit::EI_SET_CODE).putBool(ok).pos(0); connection.send(f);
  795. }break;
  796. case Edit::EI_CODE_SYNC_IMPORT:
  797. {
  798. File &f=connection.data;
  799. f.reset().putByte(Edit::EI_CODE_SYNC_IMPORT).putBool(Proj.valid() && Proj.codeImport(false)).pos(0); connection.send(f);
  800. }break;
  801. case Edit::EI_CODE_SYNC_EXPORT:
  802. {
  803. File &f=connection.data;
  804. f.reset().putByte(Edit::EI_CODE_SYNC_EXPORT).putBool(Proj.valid() && Proj.codeExport(false)).pos(0); connection.send(f);
  805. }break;
  806. // FILE
  807. case Edit::EI_GET_FILE:
  808. {
  809. File &f=connection.data; UID elm_id=f.getUID();
  810. File data; bool ok=Proj.fileRead(elm_id, data);
  811. f.reset().putByte(Edit::EI_GET_FILE).putBool(ok); if(ok)data.copy(f); f.pos(0); connection.send(f);
  812. }break;
  813. case Edit::EI_SET_FILE:
  814. {
  815. File &f=connection.data; UID elm_id=f.getUID();
  816. bool ok=Proj.fileSet(elm_id, f);
  817. f.reset().putByte(Edit::EI_SET_FILE).putBool(ok).pos(0); connection.send(f);
  818. }break;
  819. // MTRL
  820. case Edit::EI_GET_MTRL_CUR:
  821. {
  822. File &f=connection.data.reset().putByte(Edit::EI_GET_MTRL_CUR).putUID(MtrlEdit.elm_id); f.pos(0); connection.send(f);
  823. }break;
  824. case Edit::EI_SET_MTRL_CUR:
  825. {
  826. File &f=connection.data; UID elm_id=f.getUID();
  827. MtrlEdit.activate(Proj.findElm(elm_id));
  828. f.reset().putByte(Edit::EI_SET_MTRL_CUR).putBool(MtrlEdit.elm_id==elm_id); f.pos(0); connection.send(f);
  829. }break;
  830. case Edit::EI_GET_MTRL:
  831. {
  832. File &f=connection.data; UID elm_id=f.getUID();
  833. EditMaterial mtrl; bool ok=Proj.mtrlGet(elm_id, mtrl);
  834. f.reset().putByte(Edit::EI_GET_MTRL).putBool(ok); if(ok){Edit::Material edit_mtrl; mtrl.copyTo(edit_mtrl); edit_mtrl.save(f);} f.pos(0); connection.send(f);
  835. }break;
  836. case Edit::EI_SET_MTRL:
  837. {
  838. File &f=connection.data; UID elm_id=f.getUID(); byte set=f.getByte(); Edit::Material mtrl; bool ok=mtrl.load(f);
  839. if(ok)
  840. {
  841. bool reload_textures=FlagTest(set, 1), adjust_params=FlagTest(set, 2);
  842. ok=Proj.mtrlSync(elm_id, mtrl, reload_textures, adjust_params);
  843. }
  844. f.reset().putByte(Edit::EI_SET_MTRL).putBool(ok); f.pos(0); connection.send(f);
  845. }break;
  846. case Edit::EI_RLD_MTRL_TEX:
  847. {
  848. File &f=connection.data; UID elm_id=f.getUID(); byte texs=f.getByte();
  849. bool base=FlagTest(texs, 1), reflection=FlagTest(texs, 2), detail=FlagTest(texs, 4), macro=FlagTest(texs, 8), light=FlagTest(texs, 16);
  850. bool ok=Proj.mtrlReloadTextures(elm_id, base, reflection, detail, macro, light);
  851. f.reset().putByte(Edit::EI_RLD_MTRL_TEX).putBool(ok); f.pos(0); connection.send(f);
  852. }break;
  853. case Edit::EI_MUL_MTRL_TEX_COL:
  854. {
  855. File &f=connection.data; UID elm_id=f.getUID();
  856. bool ok=Proj.mtrlMulTexCol(elm_id);
  857. f.reset().putByte(Edit::EI_MUL_MTRL_TEX_COL).putBool(ok); f.pos(0); connection.send(f);
  858. }break;
  859. // MESH
  860. case Edit::EI_GET_MESH:
  861. {
  862. File &f=connection.data; UID elm_id=f.getUID();
  863. bool ok=false; Matrix matrix; File data;
  864. if(Elm *elm=Proj.findElm(elm_id))
  865. {
  866. if(elm->type==ELM_OBJ){ok=true; matrix.identity(); elm=Proj.objToMeshElm(elm);} // if this is an object, then set ok to true, in case it has no mesh, we will just send empty data
  867. if(elm && elm->type==ELM_MESH)if(ok=data.readTry(Proj.editPath(*elm)))matrix=elm->meshData()->transform();
  868. }
  869. f.reset().putByte(Edit::EI_GET_MESH).putBool(ok); if(ok){f<<matrix; data.copy(f);} f.pos(0); connection.send(f);
  870. }break;
  871. case Edit::EI_SET_MESH:
  872. {
  873. File &f=connection.data; UID elm_id=f.getUID();
  874. bool ok=Proj.meshSet(elm_id, f);
  875. f.reset().putByte(Edit::EI_SET_MESH).putBool(ok).pos(0); connection.send(f);
  876. }break;
  877. // ANIM
  878. case Edit::EI_GET_ANIM_CUR:
  879. {
  880. File &f=connection.data.reset().putByte(Edit::EI_GET_ANIM_CUR).putUID(AnimEdit.elm_id); f.pos(0); connection.send(f);
  881. }break;
  882. case Edit::EI_SET_ANIM_CUR:
  883. {
  884. File &f=connection.data; UID elm_id=f.getUID();
  885. AnimEdit.activate(Proj.findElm(elm_id));
  886. f.reset().putByte(Edit::EI_SET_ANIM_CUR).putBool(AnimEdit.elm_id==elm_id); f.pos(0); connection.send(f);
  887. }break;
  888. case Edit::EI_GET_ANIM:
  889. {
  890. File &f=connection.data; UID elm_id=f.getUID();
  891. Animation anim; bool ok=Proj.animGet(elm_id, anim);
  892. f.reset().putByte(Edit::EI_GET_ANIM).putBool(ok); if(ok)anim.save(f); f.pos(0); connection.send(f);
  893. }break;
  894. case Edit::EI_SET_ANIM:
  895. {
  896. File &f=connection.data; UID elm_id=f.getUID(); Animation anim;
  897. bool ok=false; if(anim.load(f))ok=Proj.animSet(elm_id, anim);
  898. f.reset().putByte(Edit::EI_SET_ANIM).putBool(ok).pos(0); connection.send(f);
  899. }break;
  900. // OBJ
  901. case Edit::EI_GET_OBJ_CUR:
  902. {
  903. File &f=connection.data.reset().putByte(Edit::EI_GET_OBJ_CUR).putUID(ObjEdit.obj_id); f.pos(0); connection.send(f);
  904. }break;
  905. case Edit::EI_SET_OBJ_CUR:
  906. {
  907. File &f=connection.data; UID elm_id=f.getUID();
  908. Elm *elm=Proj.findElm(elm_id);
  909. if(elm)switch(elm->type)
  910. {
  911. case ELM_MESH: elm=Proj.meshToObjElm(elm); break;
  912. case ELM_SKEL: elm=Proj.skelToObjElm(elm); break;
  913. }
  914. ObjEdit.activate(elm);
  915. f.reset().putByte(Edit::EI_SET_OBJ_CUR).putBool(ObjEdit.obj_id==elm_id); f.pos(0); connection.send(f);
  916. }break;
  917. case Edit::EI_GET_OBJ:
  918. {
  919. File &f=connection.data; UID elm_id=f.getUID(); bool include_removed_params=f.getBool();
  920. bool ok=false; Edit::ObjData data;
  921. if(Elm *elm=Proj.findElm(elm_id))
  922. if(elm->type==ELM_OBJ || elm->type==ELM_OBJ_CLASS)
  923. if(EditObjectPtr params=Proj.editPath(elm_id))
  924. {
  925. ok=true;
  926. params->copyTo(data, include_removed_params);
  927. }
  928. f.reset().putByte(Edit::EI_GET_OBJ).putBool(ok); if(ok)data.save(f); f.pos(0); connection.send(f);
  929. }break;
  930. case Edit::EI_MODIFY_OBJ:
  931. {
  932. File &f=connection.data; UID elm_id=f.getUID(); Memc<Edit::ObjChange> changes; changes.load(f, Proj.game_path);
  933. bool ok=Proj.modifyObj(elm_id, changes);
  934. f.reset().putByte(Edit::EI_MODIFY_OBJ).putBool(ok); f.pos(0); connection.send(f);
  935. }break;
  936. // APP
  937. case Edit::EI_SET_ACTIVE_APP:
  938. {
  939. File &f=connection.data; bool ok=Proj.activateApp(f.getUID());
  940. f.reset().putByte(Edit::EI_SET_ACTIVE_APP).putBool(ok); f.pos(0); connection.send(f);
  941. }break;
  942. case Edit::EI_EXPORT_APP:
  943. {
  944. File &f=connection.data; Edit::EXPORT_MODE mode=Edit::EXPORT_MODE(f.getByte()); bool data=f.getBool(); f.reset(); bool ok=CodeEdit.Export(mode, data);
  945. if(ok && StateNext==&StatePublish) // if export request initiated publishing state, then don't reply now, but wait until publishing finishes
  946. {
  947. queued=cmd; return true; // queue this command to be processed ASAP, return and don't process any other commands, because we still haven't replied to this command yet
  948. }
  949. f.putByte(Edit::EI_EXPORT_APP).putBool(ok); f.pos(0); connection.send(f);
  950. }break;
  951. // BUILD SETTINGS
  952. case Edit::EI_BUILD_DEBUG:
  953. {
  954. File &f=connection.data; CodeEdit.configDebug(f.getBool());
  955. f.reset().putByte(Edit::EI_BUILD_DEBUG).putBool(true); f.pos(0); connection.send(f);
  956. }break;
  957. case Edit::EI_BUILD_32BIT:
  958. {
  959. File &f=connection.data; CodeEdit.config32Bit(f.getBool());
  960. f.reset().putByte(Edit::EI_BUILD_32BIT).putBool(true); f.pos(0); connection.send(f);
  961. }break;
  962. case Edit::EI_BUILD_DX9:
  963. {
  964. File &f=connection.data; CodeEdit.configDX9(f.getBool());
  965. f.reset().putByte(Edit::EI_BUILD_DX9).putBool(true); f.pos(0); connection.send(f);
  966. }break;
  967. case Edit::EI_BUILD_EXE:
  968. {
  969. File &f=connection.data; CodeEdit.configEXE(Edit::EXE_TYPE(f.getByte()));
  970. f.reset().putByte(Edit::EI_BUILD_EXE).putBool(true); f.pos(0); connection.send(f);
  971. }break;
  972. case Edit::EI_BUILD_PATHS:
  973. {
  974. File &f=connection.data; CodeEdit.exportPaths(f.getBool());
  975. f.reset().putByte(Edit::EI_BUILD_PATHS).putBool(true); f.pos(0); connection.send(f);
  976. }break;
  977. }
  978. // try to process a few commands at the same time
  979. {
  980. timeout=(EditServer.start_time+(App.active() ? 2 : 32))-Time.curTimeMs(); // if is active then wait only up to 2 ms (1st in case we're at the end of that ms, and 2nd to actually have 1 left, otherwise do 32 ms wait for 30 fps)
  981. if(timeout>=0)goto check_again;
  982. }
  983. }
  984. return true;
  985. }
  986. void EditorServer::update(bool busy)
  987. {
  988. T.busy =busy;
  989. T.received=false;
  990. ::EE::ConnectionServer::update();
  991. if(!received && !busy && !App.active())Time.wait(10);
  992. }
  993. EditorServer::EditorServer() : busy(false), received(false), start_time(0) {clients.replaceClass<Client>();}
  994. EditorServer::Client::Client() : queued(-1) {}
  995. /******************************************************************************/