Server.cpp 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494
  1. /******************************************************************************/
  2. #include "stdafx.h"
  3. /******************************************************************************/
  4. ServerClass Server;
  5. /******************************************************************************/
  6. /******************************************************************************/
  7. bool ServerClass::loggedIn()C {return logged_in;}
  8. bool ServerClass::canRead()C {return loggedIn() && proj_opened;}
  9. bool ServerClass::canWrite()C {return loggedIn() && proj_opened && CanWrite (access);}
  10. bool ServerClass::canWriteCode()C {return loggedIn() && proj_opened && CanWriteCode(access);}
  11. bool ServerClass::smallBuf()C {return queued()<=ServerSendBufSize;}
  12. long ServerClass::sentTotal()C {return sent+::EE::Connection::sent ();}
  13. long ServerClass::rcvdTotal()C {return rcvd+::EE::Connection::received();}
  14. void ServerClass::clearProj()
  15. {
  16. texs.clear();
  17. world_vers.del();
  18. mini_map_vers.del();
  19. Synchronizer.clearSync();
  20. }
  21. void ServerClass::logout() {stopConnect();}
  22. void ServerClass::stopConnect()
  23. {
  24. Misc.online.set("Offline");
  25. ::EE::Connection::del();
  26. logged_email.del();
  27. if(projects.elms())
  28. {
  29. projects.del();
  30. if(StateActive==&StateProjectList)Projs.refresh();
  31. }
  32. after_connect=version_sent=version_ok=logged_in=reconnect=allow_reconnect=proj_opened=send_proj_settings=false; access=UA_NO_ACCESS; action=NONE;
  33. clearProj();
  34. }
  35. void ServerClass::startConnect(ACTION action)
  36. {
  37. T.action=action;
  38. sent+=::EE::Connection::sent ();
  39. rcvd+=::EE::Connection::received();
  40. clientConnectToServer(conn_addr);
  41. after_connect=true;
  42. }
  43. void ServerClass::connect(SockAddr &addr, C Str &email, C Str &pass, bool allow_reconnect)
  44. {
  45. stopConnect();
  46. Misc.online.set("Connecting");
  47. conn_addr =addr;
  48. conn_email=email;
  49. conn_pass =pass;
  50. T.allow_reconnect=allow_reconnect;
  51. startConnect(LOGIN);
  52. }
  53. void ServerClass::Register(Str name)
  54. {
  55. if(conn_addr.valid() && ValidEmail(conn_email) && ValidPass(conn_pass))
  56. {
  57. stopConnect();
  58. conn_name=name;
  59. startConnect(REGISTER);
  60. }
  61. }
  62. void ServerClass::forgotPass(SockAddr &addr, C Str &email)
  63. {
  64. stopConnect();
  65. conn_addr =addr;
  66. conn_email=email;
  67. startConnect(FORGOT_PASS);
  68. }
  69. void ServerClass::changePass(SockAddr &addr, C Str &email, C Str &new_pass, uint change_pass_key)
  70. {
  71. stopConnect();
  72. conn_addr =addr;
  73. conn_email =email;
  74. conn_pass =new_pass;
  75. conn_pass_key=change_pass_key;
  76. startConnect(CHANGE_PASS);
  77. }
  78. void ServerClass::licenseKey(C Str &license_key ) {if(loggedIn()) ClientSendLicenseKey (T, license_key);}
  79. void ServerClass::projectOpen(C UID &proj_id, C Str &proj_name) {if(loggedIn()){ClientSendProjectOpen (T, proj_id, proj_name); proj_opened=proj_id.valid();}}
  80. void ServerClass::projectDataRequest( ) {if(canRead ()) ClientSendGetProjectData(T);}
  81. void ServerClass::projectSetSettings( ) {if(canWrite())send_proj_settings=true;}
  82. void ServerClass::syncCodes( Memc<ElmTypeVer > &elms ) {if(canRead ())ClientSendGetCodeVer (T, elms);}
  83. void ServerClass::syncCodes(C Memc<ElmCodeData> &elms ) {if(canWrite())ClientSendSetCodeData(T, elms);}
  84. void ServerClass::newElm( Elm &elm ) {if(canWrite())ClientSendNewElm (T, elm );}
  85. void ServerClass::renameElm( Elm &elm ) {if(canWrite())ClientSendRenameElm (T, elm.id, elm.name , elm. name_time);}
  86. void ServerClass::setElmParent( Elm &elm ) {if(canWrite())ClientSendSetElmParent (T, elm.id, elm.parent_id, elm.parent_time);}
  87. void ServerClass::removeElms(Memc<UID> &elms, bool removed , C TimeStamp &time) {if(canWrite())ClientSendRemoveElms (T, elms , removed , time);}
  88. void ServerClass::noPublishElms(Memc<UID> &elms, bool no_publish, C TimeStamp &time) {if(canWrite())ClientSendNoPublishElms(T, elms , no_publish, time);}
  89. void ServerClass::getElmNames(Memc<UID> &elms ) {if(canRead ())ClientSendGetElmNames (T, elms);}
  90. void ServerClass::getTextures(Memc<UID> &texs ) {if(canRead ())ClientSendGetTextures (T, texs);}
  91. void ServerClass::getElmShort(Memc<UID> &elms ) {if(canRead ())ClientSendGetElmShort (T, elms);}
  92. void ServerClass::getElmLong(Memc<UID> &elms ) {if(canRead ())ClientSendGetElmLong (T, elms);}
  93. void ServerClass::getElmLong( C UID &elm_id ) {Memc<UID> elms; elms.add(elm_id); getElmLong(elms);}
  94. void ServerClass::setTex(C UID &tex_id) {if(canWrite() && tex_id.valid() && texs.binaryInclude(tex_id, Compare))Synchronizer.setTex(tex_id);}
  95. void ServerClass::setElmShort(C UID &elm_id) {if(canWrite())Synchronizer.setElmShort(elm_id);}
  96. void ServerClass::setElmLong(C UID &elm_id) {if(canWrite())Synchronizer.setElmLong (elm_id);}
  97. void ServerClass::setElmFull(C UID &elm_id) {if(canWrite())Synchronizer.setElmFull (elm_id);}
  98. void ServerClass::setWaypoint(C UID &world_id, C UID &waypoint_id, C Version &waypoint_ver, EditWaypoint &waypoint) {if(canWrite())ClientSendSetWorldWaypoint(T, world_id, waypoint_id, waypoint_ver, waypoint);}
  99. void ServerClass::setLake(C UID &world_id, C UID & lake_id, C Version & lake_ver, Lake &lake ) {if(canWrite())ClientSendSetWorldLake (T, world_id, lake_id, lake_ver, lake );}
  100. void ServerClass::setRiver(C UID &world_id, C UID & river_id, C Version & river_ver, River &river ) {if(canWrite())ClientSendSetWorldRiver (T, world_id, river_id, river_ver, river );}
  101. void ServerClass::getWorldVer(C UID &world_id ) {if(canRead() && world_id.valid() && !world_vers.find(world_id))ClientSendGetWorldVer (T, world_id );}
  102. void ServerClass::getWorldAreas(C UID &world_id, Memc<AreaSync> &areas ) {if(canRead() && world_id.valid() )ClientSendGetWorldAreas (T, world_id, areas );}
  103. void ServerClass::getWorldWaypoints(C UID &world_id, Memc<UID > &waypoints) {if(canRead() && world_id.valid() )ClientSendGetWorldWaypoints(T, world_id, waypoints);}
  104. void ServerClass::getWorldLakes(C UID &world_id, Memc<UID > &lakes ) {if(canRead() && world_id.valid() )ClientSendGetWorldLakes (T, world_id, lakes );}
  105. void ServerClass::getWorldRivers(C UID &world_id, Memc<UID > &rivers ) {if(canRead() && world_id.valid() )ClientSendGetWorldRivers (T, world_id, rivers );}
  106. void ServerClass::getMiniMapVer(C UID &mini_map_id ) {if(canRead() && mini_map_id.valid() && !mini_map_vers.find(mini_map_id))ClientSendGetMiniMapVer (T, mini_map_id );}
  107. void ServerClass::getMiniMapImages(C UID &mini_map_id, Memc<VecI2> &images) {if(canRead() && mini_map_id.valid() )ClientSendGetMiniMapImages(T, mini_map_id, images);}
  108. void ServerClass::setMiniMapSettings(C UID &mini_map_id, C Game::MiniMap::Settings &settings, C TimeStamp &settings_time) {if(canWrite() && mini_map_id.valid())ClientSendSetMiniMapSettings(T, mini_map_id, settings, settings_time);}
  109. void ServerClass::update(ProjectEx *proj, bool busy)
  110. {
  111. if(reconnect && Time.realTime()>=reconnect_time)connect(conn_addr, conn_email, conn_pass, true);
  112. if(after_connect)
  113. {
  114. // check server state
  115. switch(state())
  116. {
  117. case CONNECT_INVALID : if(allow_reconnect || loggedIn()){stopConnect(); Misc.online.set("Connecting"); T.reconnect=true; reconnect_time=Time.realTime()+6;}else{if(!version_ok)Gui.msgBox(S, "Can't connect to server.\nYou have entered invalid server address,\nor the server is unavailable,\nor you're not connected to the Internet."); stopConnect();} break; // if 'version_ok' then it means we indeed got connected ok, but got disconnected to some other failure (like wrong password)
  118. case CONNECT_CONNECTING :
  119. case CONNECT_AWAIT_GREET : if(Server.life()>6000){Gui.msgBox(S, "Server Connection Timeout"); stopConnect();} break;
  120. case CONNECT_VERSION_CONFLICT: Gui.msgBox(S, "This application is of different version than the server application.\nPlease update both applications."); stopConnect(); break;
  121. case CONNECT_GREETED : if(!version_sent){version_sent=true; ClientSendVersion(T);} break;
  122. }
  123. // check if we have scheduled data to send
  124. if(version_ok)switch(action)
  125. {
  126. case LOGIN : action=NONE; ClientSendLogin (T, conn_email, conn_pass, ServerLicenseKey, OSVer()); break;
  127. case REGISTER : action=NONE; ClientSendRegister (T, conn_email, conn_pass, conn_name ); break;
  128. case FORGOT_PASS: action=NONE; ClientSendForgotPass(T, conn_email ); break;
  129. case CHANGE_PASS: action=NONE; ClientSendChangePass(T, conn_email, conn_pass, S, conn_pass_key ); break;
  130. }
  131. // check if any data received from server
  132. const uint time=Time.curTimeMs(), delay=16; // 1000ms/60fps
  133. for(; receive(0); )
  134. {
  135. switch(data.getByte())
  136. {
  137. case CS_VERSION_CHECK:
  138. {
  139. if(ClientRecvVersion(data))version_ok=true;else{Gui.msgBox(S, "This application is of different version than the server application.\nPlease update both applications."); stopConnect();}
  140. }break;
  141. case CS_LOGIN:
  142. {
  143. LOGIN_RESULT result; USER_ACCESS access; ClientRecvLogin(data, result, access);
  144. switch(result)
  145. {
  146. case LOGIN_EMAIL_FOUND_INVALID_PASS : Gui.msgBox(S, "Invalid password"); break;
  147. case LOGIN_EMAIL_NOT_FOUND_REGISTRATION_UNAVAILABLE: Gui.msgBox(S, "E-mail was not found.\nUser registration is disabled on this server."); break;
  148. case LOGIN_EMAIL_NOT_FOUND_REGISTRATION_AVAILABLE : ::Register.activate(); break;
  149. case LOGIN_LICENSE_USED : Gui.msgBox(S, "Server already has a different user using your License Key."); stopConnect(); break;
  150. case LOGIN_DEMO_USER_NOT_ALLOWED : Gui.msgBox(S, "Can't connect to server using demo version when the server has 2 or more clients."); stopConnect(); break;
  151. case LOGIN_SUCCESS:
  152. {
  153. if(access==UA_NO_ACCESS || !InRange(access, UA_NUM)){Gui.msgBox(S, "Your account doesn't have access to the server.\nPlease contact server administrator to enable access."); stopConnect();}else
  154. {
  155. logged_email=conn_email; logged_in=true; T.access=access; ClientSendProjectsListRequest(T);
  156. if(access==UA_READ_ONLY)Gui.msgBox(S, "Your account is limited to read-only operations.");
  157. Misc.online.set((access==UA_READ_ONLY) ? "Read Only" : "Online");
  158. if(proj)proj->resumeServer(); // needed if reconnected after lost connection
  159. }
  160. }break;
  161. }
  162. }break;
  163. case CS_REGISTER:
  164. {
  165. REGISTER_RESULT result; ClientRecvRegister(data, result);
  166. switch(result)
  167. {
  168. case REGISTER_REGISTRATION_UNAVAILABLE: Gui.msgBox(S, "User registration is disabled on this server."); break;
  169. case REGISTER_INVALID_EMAIL : Gui.msgBox(S, "Invalid e-mail for user registration."); break;
  170. case REGISTER_EMAIL_USED : Gui.msgBox(S, "E-mail entered for registration is already used."); break;
  171. case REGISTER_SUCCESS : Gui.msgBox(S, "Registration success.\nPlease contact the server administrator to activate your account."); break;
  172. }
  173. }break;
  174. case CS_FORGOT_PASS:
  175. {
  176. FORGOT_PASS_RESULT result; ClientRecvForgotPass(data, result);
  177. switch(result)
  178. {
  179. case FORGOT_PASS_EMAIL_NOT_FOUND: Gui.msgBox(S, "Invalid e-mail used in forgot password."); break;
  180. case FORGOT_PASS_KEY_SENT : ChangePass.activate(true); break;
  181. case FORGOT_PASS_NO_SEND_MAIL : Gui.msgBox(S, "Server doesn't support sending e-mails (it doesn't have SMTP installed).\nPlease contact the server administrator to change the password for you."); break;
  182. }
  183. }break;
  184. case CS_CHANGE_PASS:
  185. {
  186. CHANGE_PASS_RESULT result; ClientRecvChangePass(data, result);
  187. switch(result)
  188. {
  189. case CHANGE_PASS_INVALID_KEY : Gui.msgBox(S, "Invalid key."); ChangePass.hide(); break;
  190. case CHANGE_PASS_INVALID_PASS : Gui.msgBox(S, "Invalid current password."); break;
  191. case CHANGE_PASS_EMAIL_NOT_FOUND: Gui.msgBox(S, "Invalid e-mail for change password."); ChangePass.hide(); break;
  192. case CHANGE_PASS_SUCCESS : Gui.msgBox(S, "Password changed."); ChangePass.hide(); break;
  193. }
  194. }break;
  195. case CS_PROJECTS_LIST: ClientRecvProjectsList(data, projects); Projs.refresh(); break;
  196. case CS_PROJECT_DATA: if(proj)
  197. {
  198. Project temp; if(ClientRecvProjectData(data, temp))if(temp.id==proj->id)Synchronizer.sync(*proj, temp);
  199. }break;
  200. case CS_PROJECT_SETTINGS: if(proj)
  201. {
  202. Project temp; if(ClientRecvProjectSettings(data, temp))if(temp.id==proj->id)
  203. {
  204. if(proj-> syncSettings(temp)){ProjSettings.toGui(); CodeEdit.makeAuto();} // set auto header in case Data Encryption options have changed
  205. if(proj->newerSettings(temp))projectSetSettings(); // if after receiving settings from server we have newer values from it, then send it to the server
  206. }
  207. }break;
  208. case CS_NEW_ELM: if(proj)
  209. {
  210. Elm elm; UID proj_id; ClientRecvNewElm(data, elm, proj_id);
  211. if(proj_id==proj->id && proj->testElmsNum())
  212. {
  213. proj->setListCurSel();
  214. Elm &proj_elm=proj->getElm(elm.id); if(!proj_elm.type)Swap(elm, proj_elm); // if just added then swap, otherwise we can't create a new element if it already exists so do nothing
  215. proj->setList();
  216. }
  217. }break;
  218. case CS_RENAME_ELM: if(proj)
  219. {
  220. UID elm_id, proj_id; Str name; TimeStamp name_time; ClientRecvRenameElm(data, elm_id, name, name_time, proj_id);
  221. if(proj_id==proj->id)
  222. if(Elm *elm=proj->findElm(elm_id))
  223. if(name_time>elm->name_time)
  224. {
  225. proj->setElmName(*elm, name, name_time);
  226. proj->refresh(false, false);
  227. }
  228. }break;
  229. case CS_SET_ELM_PARENT: if(proj)
  230. {
  231. UID elm_id, parent_id, proj_id; TimeStamp parent_time; ClientRecvSetElmParent(data, elm_id, parent_id, parent_time, proj_id);
  232. if(proj_id==proj->id)
  233. if(Elm *elm=proj->findElm(elm_id))
  234. if(parent_time>elm->parent_time)
  235. {
  236. proj->setListCurSel(); elm->setParent(parent_id, parent_time);
  237. proj->setList();
  238. proj->activateSources(); // rebuild sources if needed
  239. }
  240. }break;
  241. case CS_REMOVE_ELMS: if(proj)
  242. {
  243. Memc<UID> elm_ids; bool removed; TimeStamp removed_time; UID proj_id; ClientRecvRemoveElms(data, elm_ids, removed, removed_time, proj_id);
  244. if(proj_id==proj->id)
  245. {
  246. proj->setListCurSel();
  247. FREPA(elm_ids)if(Elm *elm=proj->findElm(elm_ids[i]))if(removed_time>elm->removed_time)elm->setRemoved(removed, removed_time);
  248. proj->setList(false);
  249. proj->activateSources(); // rebuild sources if needed
  250. WorldEdit.delayedValidateRefs();
  251. }
  252. }break;
  253. case CS_NO_PUBLISH_ELMS: if(proj)
  254. {
  255. Memc<UID> elm_ids; bool no_publish; TimeStamp no_publish_time; UID proj_id; ClientRecvNoPublishElms(data, elm_ids, no_publish, no_publish_time, proj_id);
  256. if(proj_id==proj->id)
  257. {
  258. proj->setListCurSel();
  259. FREPA(elm_ids)if(Elm *elm=proj->findElm(elm_ids[i]))if(no_publish_time>elm->no_publish_time)elm->setNoPublish(no_publish, no_publish_time);
  260. proj->setList(false);
  261. proj->activateSources(); // rebuild sources if needed
  262. WorldEdit.delayedValidateRefs();
  263. }
  264. }break;
  265. case CS_GET_ELM_NAMES: if(proj)
  266. {
  267. Memc<ElmName> elm_names; UID proj_id; ClientRecvGetElmNames(data, elm_names, proj_id);
  268. if(proj_id==proj->id)
  269. {
  270. FREPA(elm_names)
  271. {
  272. ElmName &elm_name=elm_names[i];
  273. if(Elm *elm=proj->findElm(elm_name.id))if(elm_name.time>elm->name_time)proj->setElmName(*elm, elm_name.name, elm_name.time);
  274. }
  275. proj->refresh(false, false);
  276. }
  277. }break;
  278. case CS_SET_TEXTURE: if(proj)
  279. {
  280. UID tex_id, proj_id; File tex_data;
  281. if(ClientRecvSetTexture(data, tex_id, tex_data.writeMem(), proj_id))
  282. if(proj_id==proj->id)
  283. if(proj->includeTex(tex_id))
  284. {
  285. Str path=proj->texPath(tex_id);
  286. tex_data.pos(0); if(SafeOverwrite(tex_data, path)){SavedImage(path); proj->savedTex(tex_id, tex_data.size());}
  287. }
  288. }break;
  289. case CS_SET_ELM_FULL: if(proj)
  290. {
  291. Elm elm; UID proj_id; File elm_data, elm_extra;
  292. if(ClientRecvSetElmFull(data, elm, elm_data.writeMem(), elm_extra.writeMem(), proj_id))
  293. if(proj_id==proj->id && proj->testElmsNum())
  294. {
  295. bool created=false;
  296. proj->setListCurSel();
  297. Elm &proj_elm=proj->getElm(elm.id);
  298. if( !proj_elm.type) // doesn't exist yet
  299. {
  300. elm.opened(false); // keep received elements as closed
  301. Swap(proj_elm, elm);
  302. elm_data.pos(0); elm_extra.pos(0); proj->receivedData(proj_elm, elm_data, elm_extra);
  303. created=true;
  304. }else
  305. if(elm.type==proj_elm.type)
  306. {
  307. if(elm. name_time>proj_elm. name_time)proj->setElmName(proj_elm, elm.name , elm. name_time);
  308. if(elm. parent_time>proj_elm. parent_time)proj_elm.setParent ( elm.parent_id , elm. parent_time);
  309. if(elm. removed_time>proj_elm. removed_time)proj_elm.setRemoved ( elm.removed (), elm. removed_time);
  310. if(elm.no_publish_time>proj_elm.no_publish_time)proj_elm.setNoPublish( elm.noPublish(), elm.no_publish_time);
  311. if(elm.data && (!proj_elm.data || elm.data->ver!=proj_elm.data->ver))
  312. {
  313. elm_data.pos(0); elm_extra.pos(0); proj->syncElm(proj_elm, elm, elm_data, elm_extra, true);
  314. }
  315. }
  316. proj->setList();
  317. if(created)WorldEdit.delayedValidateRefs();
  318. }
  319. }break;
  320. case CS_SET_ELM_LONG: if(proj)
  321. {
  322. Elm elm; UID proj_id; File elm_data, elm_extra;
  323. if(ClientRecvSetElmLong(data, elm, elm_data.writeMem(), elm_extra.writeMem(), proj_id))
  324. if(proj_id==proj->id)
  325. if(Elm *proj_elm=proj->findElm(elm.id, elm.type))
  326. if(elm.data && (!proj_elm->data || elm.data->ver!=proj_elm->data->ver))
  327. {
  328. elm_data.pos(0); elm_extra.pos(0); proj->syncElm(*proj_elm, elm, elm_data, elm_extra, true);
  329. }
  330. }break;
  331. case CS_SET_ELM_SHORT: if(proj)
  332. {
  333. Elm elm; UID proj_id; File elm_data, elm_extra;
  334. if(ClientRecvSetElmShort(data, elm, elm_data.writeMem(), proj_id))
  335. if(proj_id==proj->id)
  336. if(Elm *proj_elm=proj->findElm(elm.id, elm.type))
  337. if(elm.data && (!proj_elm->data || elm.data->ver!=proj_elm->data->ver))
  338. {
  339. elm_data.pos(0); proj->syncElm(*proj_elm, elm, elm_data, elm_extra, false);
  340. }
  341. }break;
  342. case CS_GET_WORLD_VER: if(proj)
  343. {
  344. UID world_id, proj_id; WorldVer world_ver;
  345. ClientRecvGetWorldVer(data, world_ver, world_id, proj_id);
  346. if(proj_id==proj->id)
  347. if(WorldVer *server_world_ver=world_vers.get(world_id))
  348. {
  349. Swap(*server_world_ver, world_ver);
  350. Synchronizer.syncWorld(world_id);
  351. }
  352. }break;
  353. case CS_SET_WORLD_AREA: if(proj)
  354. {
  355. UID world_id, proj_id; VecI2 area_xy; byte area_sync_flag; AreaVer ver; Heightmap hm; Memc<ObjData> objs; Memc<UID> local_objs_newer;
  356. if(ClientRecvSetWorldArea(data, world_id, area_xy, area_sync_flag, ver, hm, objs, proj_id, proj->game_path, proj->edit_path))
  357. if(proj_id==proj->id)
  358. {
  359. proj->syncArea(world_id, area_xy, area_sync_flag, ver, hm, objs, &local_objs_newer);
  360. Synchronizer.setObjs(world_id, local_objs_newer);
  361. }
  362. }break;
  363. case CS_SET_WORLD_OBJS: if(proj)
  364. {
  365. UID world_id, proj_id; VecI2 area_xy; Memc<ObjData> objs;
  366. if(ClientRecvSetWorldObjs(data, world_id, area_xy, objs, proj->edit_path, proj_id))
  367. if(proj_id==proj->id)
  368. proj->syncObj(world_id, area_xy, objs);
  369. }break;
  370. case CS_SET_WORLD_WAYPOINT: if(proj)
  371. {
  372. UID world_id, waypoint_id, proj_id; Version waypoint_ver; EditWaypoint waypoint;
  373. if(ClientRecvSetWorldWaypoint(data, world_id, waypoint_id, waypoint_ver, waypoint, proj_id))
  374. if(proj_id==proj->id)
  375. proj->syncWaypoint(world_id, waypoint_id, waypoint_ver, waypoint);
  376. }break;
  377. case CS_SET_WORLD_LAKE: if(proj)
  378. {
  379. UID world_id, lake_id, proj_id; Version lake_ver; Lake lake;
  380. if(ClientRecvSetWorldLake(data, world_id, lake_id, lake_ver, lake, proj_id))
  381. if(proj_id==proj->id)
  382. proj->syncLake(world_id, lake_id, lake_ver, lake);
  383. }break;
  384. case CS_SET_WORLD_RIVER: if(proj)
  385. {
  386. UID world_id, river_id, proj_id; Version river_ver; River river;
  387. if(ClientRecvSetWorldRiver(data, world_id, river_id, river_ver, river, proj_id))
  388. if(proj_id==proj->id)
  389. proj->syncRiver(world_id, river_id, river_ver, river);
  390. }break;
  391. case CS_GET_MINI_MAP_VER: if(proj)
  392. {
  393. UID mini_map_id, proj_id; MiniMapVer mini_map_ver;
  394. ClientRecvGetMiniMapVer(data, mini_map_ver, mini_map_id, proj_id);
  395. if(proj_id==proj->id)
  396. if(MiniMapVer *server_mini_map_ver=mini_map_vers.get(mini_map_id))
  397. {
  398. Swap(*server_mini_map_ver, mini_map_ver);
  399. Synchronizer.syncMiniMap(mini_map_id);
  400. }
  401. }break;
  402. case CS_SET_MINI_MAP_SETTINGS: if(proj)
  403. {
  404. UID mini_map_id; Game::MiniMap::Settings settings; TimeStamp settings_time; UID proj_id;
  405. if(ClientRecvSetMiniMapSettings(data, mini_map_id, settings, settings_time, proj_id))
  406. if(proj_id==proj->id)
  407. if(proj->syncMiniMapSettings(mini_map_id, settings, settings_time))
  408. Preview.elmChanged(mini_map_id);
  409. }break;
  410. case CS_SET_MINI_MAP_IMAGE: if(proj)
  411. {
  412. UID mini_map_id, proj_id; VecI2 image_xy; File image_data; TimeStamp image_time;
  413. if(ClientRecvSetMiniMapImage(data, mini_map_id, image_xy, image_time, image_data.writeMem(), proj_id))
  414. if(proj_id==proj->id)
  415. if(proj->syncMiniMapImage(mini_map_id, image_xy, image_time, image_data))
  416. Preview.elmChanged(mini_map_id);
  417. }break;
  418. case CS_SET_CODE_DATA: if(proj)
  419. {
  420. Memc<ElmCodeData> elm_code_datas; UID proj_id;
  421. if(ClientRecvSetCodeData(data, elm_code_datas, proj_id))if(proj_id==proj->id)proj->syncCodes(elm_code_datas);
  422. }break;
  423. case CS_CODE_SYNC_STATUS: if(proj)
  424. {
  425. Memc<ElmCodeBase> elm_code_bases; bool resync; UID proj_id;
  426. ClientRecvCodeSyncStatus(data, elm_code_bases, resync, proj_id);
  427. if(proj_id==proj->id)proj->syncCodes(elm_code_bases, resync);
  428. }break;
  429. }
  430. if(Time.curTimeMs()-time>=delay)break;
  431. }
  432. // send project settings
  433. if(send_proj_settings && proj && proj->oldSettings()){send_proj_settings=false; ClientSendProjectSettings(T, *proj);}
  434. // update synchronizer
  435. Synchronizer.update();
  436. // add background thread commands to be sent
  437. Memc<File> cmds; if(Synchronizer.getCmds(cmds))FREPA(cmds)send(cmds[i], -1, false);
  438. // send all queued commands
  439. flush(0);
  440. }
  441. flt d=Time.realTime()-stats_time;
  442. if( d>=1)
  443. {
  444. stats_time=Time.realTime();
  445. sending=uint(sentTotal()-stats_sent)/d; stats_sent=sentTotal();
  446. rcving=uint(rcvdTotal()-stats_rcvd)/d; stats_rcvd=rcvdTotal();
  447. }
  448. Misc.online.desc(S+"Access: "+UserAccessText[access].name
  449. +"\nSent: "+FileSize (sentTotal())+ ", Received: " +FileSize (rcvdTotal())
  450. +"\nSending: "+FileSizeKB(sending )+"/s, Receiving: "+FileSizeKB(rcving)+"/s"
  451. "\nElements to send: "+(Synchronizer.queuedElms()+(queued()>0))); // if there is data in the buffer then count it as one extra element
  452. EditServer.update(busy);
  453. }
  454. ServerClass::~ServerClass() {stopConnect();}
  455. ServerClass::ServerClass() : after_connect(false), version_sent(false), version_ok(false), logged_in(false), reconnect(false), allow_reconnect(false), proj_opened(false), send_proj_settings(false), access(UA_NO_ACCESS), action(NONE), conn_pass_key(0), sending(0), rcving(0), sent(0), rcvd(0), stats_sent(0), stats_rcvd(0), reconnect_time(0), stats_time(0), world_vers(Compare), mini_map_vers(Compare) {}
  456. /******************************************************************************/