messages.cpp 43 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622
  1. /*
  2. ** Command & Conquer Renegade(tm)
  3. ** Copyright 2025 Electronic Arts Inc.
  4. **
  5. ** This program is free software: you can redistribute it and/or modify
  6. ** it under the terms of the GNU General Public License as published by
  7. ** the Free Software Foundation, either version 3 of the License, or
  8. ** (at your option) any later version.
  9. **
  10. ** This program is distributed in the hope that it will be useful,
  11. ** but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. ** GNU General Public License for more details.
  14. **
  15. ** You should have received a copy of the GNU General Public License
  16. ** along with this program. If not, see <http://www.gnu.org/licenses/>.
  17. */
  18. /***********************************************************************************************
  19. *** Confidential - Westwood Studios ***
  20. ***********************************************************************************************
  21. * *
  22. * Project Name : Commando *
  23. * *
  24. * $Archive:: /Commando/Code/Commando/messages.cpp $*
  25. * *
  26. * $Author:: Steve_t $*
  27. * *
  28. * $Modtime:: 2/22/02 7:15p $*
  29. * *
  30. * $Revision:: 229 $*
  31. * *
  32. *---------------------------------------------------------------------------------------------*
  33. * Functions: *
  34. * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  35. #include "cnetwork.h"
  36. #include <stdio.h>
  37. #include "playermanager.h"
  38. #include "gameobjmanager.h"
  39. #include "textdisplay.h"
  40. #include "input.h"
  41. #include "combatgmode.h"
  42. #include "WWAudio.h"
  43. #include "systimer.h"
  44. #include "multihud.h"
  45. #include "useroptions.h"
  46. #include "devoptions.h"
  47. #include "god.h"
  48. #include "playertype.h"
  49. #include "translatedb.h"
  50. #include "string_ids.h"
  51. #include "wolgmode.h"
  52. #include "bitpackids.h"
  53. #include "msgstatlistgroup.h"
  54. #include "vistable.h"
  55. #include "pscene.h"
  56. #include "staticanimphys.h"
  57. #include "combat.h"
  58. #include "gametype.h"
  59. #include "colors.h"
  60. #include "networkobject.h"
  61. #include "building.h"
  62. #include "vendor.h"
  63. #include "networkobjectfactorymgr.h"
  64. #include "networkobjectfactory.h"
  65. #include "networkobjectmgr.h"
  66. #include "cstextobj.h"
  67. #include "loadingevent.h"
  68. #include "clientcontrol.h"
  69. #include "wwprofile.h"
  70. #include "changeteamevent.h"
  71. #include "DlgMPTeamSelect.h"
  72. #include "dlgmessagebox.h"
  73. #include "apppacketstats.h"
  74. #include "clientpingmanager.h"
  75. #include "priority.h"
  76. #include "crandom.h"
  77. #include "wwmath.h"
  78. #include "clienthintmanager.h"
  79. #include "packetmgr.h"
  80. #include "specialbuilds.h"
  81. #include "gameinitmgr.h"
  82. #include "dlgcncwinscreen.h"
  83. #include "consolemode.h"
  84. #include "CDKeyAuth.h"
  85. static int LastSortedSecond;
  86. static const float max_update_rate = 140.0f; // Priority 1 update rate
  87. static const float min_update_rate = 5000.0f; // Priority 0.001 update rate
  88. static const float unseen_update_rate = 10000.0f; // Priority 0 update rate.
  89. static const unsigned short infinity_update_rate = 0xffff; // Lowest update rate - no updates at all.
  90. //-----------------------------------------------------------------------------
  91. //
  92. // This is the most crucial place for server filtering
  93. //
  94. void cNetwork::Tell_Client_About_Dynamic_Objects
  95. (
  96. int client_id,
  97. Vector3 & dest_pos
  98. )
  99. {
  100. #ifndef BETACLIENT
  101. if (cDevOptions::UseNewTCADO.Is_False()) {
  102. WWPROFILE("TCADO");
  103. WWASSERT(client_id >= 0);
  104. WWASSERT(cNetwork::I_Am_Server());
  105. if (Get_Server_Rhost(client_id) == NULL) {
  106. return;
  107. }
  108. if (cNetwork::I_Am_Client() && client_id == cNetwork::Get_My_Id())
  109. {
  110. //
  111. // Server does not send to his own client.
  112. //
  113. return;
  114. }
  115. int i;
  116. VisTableClass *pvs = NULL;
  117. int count = 0;
  118. {
  119. WWPROFILE("GetVis");
  120. pvs = COMBAT_SCENE->Get_Vis_Table (dest_pos);
  121. count = NetworkObjectMgrClass::Get_Object_Count();
  122. }
  123. /*
  124. ** List of objects requiring frequent updates.
  125. */
  126. static DynamicVectorClass<NetworkObjectClass *> object_list;
  127. /*
  128. ** List of objects requiring guaranteed updates. We can't schedule these.
  129. */
  130. static DynamicVectorClass<NetworkObjectClass *> g_object_list;
  131. object_list.Clear();
  132. g_object_list.Clear();
  133. SoldierGameObj * player_ptr = GameObjManager::Find_Soldier_Of_Client_ID(client_id);
  134. {
  135. WWPROFILE("ListBuild");
  136. /*
  137. ** Go through the object list once and figure out all the priorities.
  138. */
  139. for (int index = 0; index < count; index ++) {
  140. NetworkObjectClass * p_object = NetworkObjectMgrClass::Get_Object(index);
  141. if (p_object == NULL) {
  142. continue;
  143. }
  144. float priority = 0.0f;
  145. if (p_object->Get_App_Packet_Type() == APPPACKETTYPE_SERVERFPS) {
  146. priority = 0.05f;
  147. p_object->Set_Cached_Priority(priority);
  148. object_list.Add(p_object);
  149. } else {
  150. /*
  151. ** Get the base priority. This is just distance from where the server thinks the client is.
  152. */
  153. priority = cPriority::Compute_Object_Priority(client_id, dest_pos, p_object);
  154. p_object->Set_Cached_Priority(priority);
  155. /*
  156. ** If we can't see it at all, ignore it unless the priority is really high. A really high priority might indicate
  157. ** an object update request from the client.
  158. */
  159. if (priority < 1.0f) {
  160. int vis_id = p_object->Get_Vis_ID ();
  161. if (pvs && vis_id != -1 && !pvs->Get_Bit(vis_id)) {
  162. priority = 0.0f;
  163. }
  164. }
  165. if (p_object->Get_Object_Dirty_Bit(client_id, NetworkObjectClass::BIT_CREATION) ||
  166. p_object->Get_Object_Dirty_Bit(client_id, NetworkObjectClass::BIT_RARE) ||
  167. p_object->Get_Object_Dirty_Bit(client_id, NetworkObjectClass::BIT_OCCASIONAL)) {
  168. g_object_list.Add(p_object);
  169. } else {
  170. if (p_object == player_ptr) {
  171. priority = 0.8f;
  172. }
  173. p_object->Set_Cached_Priority(priority);
  174. if (priority > 0.001f) {
  175. /*
  176. ** Work out the export size if we don't know it already.
  177. */
  178. if (p_object->Get_Frequent_Update_Export_Size() == 0) {
  179. cPacket packet;
  180. int bits_before = packet.Get_Bit_Write_Position();
  181. packet.Add(p_object->Get_Network_ID());
  182. packet.Add(p_object->Get_Object_Dirty_Bits(client_id));
  183. packet.Add(p_object->Is_Delete_Pending());
  184. int bits_now = packet.Get_Bit_Write_Position();
  185. p_object->Export_Frequent (packet);
  186. int bits_after = packet.Get_Bit_Write_Position();
  187. int packet_size = 0;
  188. if (bits_now < bits_after) {
  189. packet_size = (bits_after - bits_before) / 8;
  190. /*
  191. ** Add the packet header.
  192. */
  193. packet_size += cPacket::Get_Packet_Header_Size();
  194. p_object->Set_Frequent_Update_Export_Size(packet_size);
  195. } else {
  196. /*
  197. ** For some reason, some objects have a frequent bit set but there is no frequent update export.
  198. */
  199. p_object->Set_Frequent_Update_Export_Size(0);
  200. }
  201. }
  202. object_list.Add(p_object);
  203. }
  204. }
  205. }
  206. }
  207. }
  208. /*
  209. ** Now we have two lists. One list of non-guaranteed objects that we would like to send and another list of guaranteed
  210. ** objects we 'must' send.
  211. */
  212. /*
  213. ** Sort the non-guaranteed list.
  214. ** Bubble sort for now, quick sort later.
  215. */
  216. NetworkObjectClass *temp_obj;
  217. /*
  218. ** Get our budget in bits per second for this guy.
  219. */
  220. cRemoteHost *r_host = cNetwork::Get_Server_Rhost(client_id);
  221. int bits_per_second = r_host->Get_Target_Bps();
  222. /*
  223. ** Convert to bytes.
  224. */
  225. int bytes_per_second = bits_per_second >> 3;
  226. /*
  227. ** We have NetUpdateRate updates per second.
  228. */
  229. int net_update_rate = cUserOptions::NetUpdateRate.Get();
  230. /*
  231. ** Work out how many bytes we can send per update.
  232. */
  233. int avail_bytes_per_update = bytes_per_second / net_update_rate;
  234. /*
  235. ** Factor in the bandwidth multiplier.
  236. */
  237. float mult = Get_Server_Rhost(client_id)->Get_Bandwidth_Multiplier();
  238. if (r_host->Get_Flood()) {
  239. if (r_host->Get_Target_Bps() < 14400) {
  240. mult = 0.7f;
  241. } else {
  242. mult = 1.0f;
  243. }
  244. }
  245. avail_bytes_per_update = (int) (mult * (float)avail_bytes_per_update);
  246. unsigned long time = TIMEGETTIME();
  247. /*
  248. ** Don't use more than 50% of the available bytes per update for guaranteed packets.
  249. */
  250. unsigned long bytes_out = 0;
  251. unsigned long max_bytes = avail_bytes_per_update; //(avail_bytes_per_update >> 1); //* 3) / 4;
  252. /*
  253. ** Figure a compression ratio of 2:1
  254. */
  255. max_bytes += bytes_out << 1;
  256. {
  257. WWPROFILE("SendG");
  258. /*
  259. ** Send the guaranteed stuff first. This has to be done anyway so let's see how much of it there is.
  260. */
  261. bool full = false;
  262. for (i=0 ; i<g_object_list.Count() ; i++) {
  263. temp_obj = g_object_list[i];
  264. if (!full || temp_obj->Get_App_Packet_Type() == APPPACKETTYPE_CLIENTBBOEVENT) {
  265. bytes_out += (Send_Object_Update(temp_obj, client_id) >> 3);
  266. temp_obj->Set_Last_Update_Time(client_id, time);
  267. }
  268. /*
  269. ** See if we are using too much bandwidth and don't send more if we are.
  270. */
  271. if (!full && bytes_out > max_bytes) {
  272. #ifdef WWDEBUG
  273. if (cDevOptions::ExtraNetDebug.Is_True()) {
  274. WWDEBUG_SAY(("*** WARNING: Tell_Client_About_Dynamic_Objects - Insufficient bandwidth to send all guaranteed packets ***\n"));
  275. WWDEBUG_SAY(("*** After %d objects, bytes_out = %d, max_bytes = %d\n", i, bytes_out, max_bytes));
  276. }
  277. #endif //WWDEBUG
  278. avail_bytes_per_update >>= 1;
  279. full = true;
  280. //break;
  281. }
  282. }
  283. }
  284. /*
  285. ** Work out the average priority. We will need this later when balancing bandwidth budgets between clients.
  286. */
  287. float average_priority = 0.0f;
  288. int num_priorities = 0;
  289. {
  290. WWPROFILE("CalcRate");
  291. for (i=0 ; i<object_list.Count() ; i++) {
  292. temp_obj = object_list[i];
  293. if (temp_obj->Get_App_Packet_Type() != APPPACKETTYPE_SERVERFPS) {
  294. float pri = temp_obj->Get_Cached_Priority();
  295. /*
  296. ** Don't count unseen objects or objects we are getting hints for.
  297. */
  298. if (pri > 0.001f && pri < 1.0f) {
  299. average_priority += pri;
  300. num_priorities++;
  301. }
  302. }
  303. }
  304. if (num_priorities) {
  305. average_priority = average_priority / (float)num_priorities;
  306. Get_Server_Rhost(client_id)->Set_Average_Priority(average_priority);
  307. /*
  308. ** Remaining objects get updated based on priority.
  309. ** Just set the rate based on priority then we will go back in a second pass and adjust it according to remaining bandwidth.
  310. */
  311. float ms_low = max_update_rate;
  312. float ms_high = min_update_rate;
  313. float spread = ms_high - ms_low;
  314. int total_bps = 0;
  315. for (i=0 ; i<object_list.Count() ; i++) {
  316. temp_obj = object_list[i];
  317. float pri = temp_obj->Get_Cached_Priority();
  318. unsigned long update_rate = infinity_update_rate; //0;
  319. if (pri > 0.025f) { //01f) {
  320. update_rate = (unsigned long)(((1.0f - pri) * spread) + ms_low);
  321. }
  322. temp_obj->Set_Update_Rate(client_id, (unsigned short) update_rate);
  323. if (update_rate != infinity_update_rate) {
  324. int bps = (1000.0f / update_rate) * temp_obj->Get_Frequent_Update_Export_Size();
  325. total_bps += bps;
  326. }
  327. }
  328. /*
  329. ** Make that number a per update figure.
  330. */
  331. total_bps = total_bps / net_update_rate;
  332. /*
  333. ** Now, scale the update rate based on available bandwidth.
  334. */
  335. float factor = 1.0;
  336. if (total_bps) {
  337. factor = avail_bytes_per_update / total_bps;
  338. if (factor < 0.00001f) {
  339. factor = 0.00001f;
  340. }
  341. }
  342. unsigned short rate;
  343. float float_rate;
  344. for (i=0 ; i<object_list.Count() ; i++) {
  345. temp_obj = object_list[i];
  346. float obj_upd_rate = (float)temp_obj->Get_Update_Rate(client_id);
  347. if (obj_upd_rate != infinity_update_rate) {
  348. float_rate = obj_upd_rate / factor;
  349. rate = (unsigned short) float_rate;
  350. temp_obj->Set_Update_Rate(client_id, rate);
  351. }
  352. }
  353. } else {
  354. Get_Server_Rhost(client_id)->Set_Average_Priority(0.0f);
  355. }
  356. }
  357. {
  358. WWPROFILE("SendN");
  359. /*
  360. ** Send those packets whos time has come.
  361. */
  362. for (i=0 ; i<object_list.Count() ; i++) {
  363. temp_obj = object_list[i];
  364. unsigned long rate = (unsigned long)temp_obj->Get_Update_Rate(client_id);
  365. if (rate != (unsigned long)infinity_update_rate) {
  366. if (time - temp_obj->Get_Last_Update_Time(client_id) > rate) {
  367. Send_Object_Update(temp_obj, client_id);
  368. temp_obj->Set_Last_Update_Time(client_id, time);
  369. }
  370. }
  371. }
  372. }
  373. REF_PTR_RELEASE(pvs);
  374. } else {
  375. /*
  376. **
  377. ** Optimized version of TCADO
  378. **
  379. **
  380. **
  381. **
  382. */
  383. const unsigned char dirty_check = (NetworkObjectClass::BIT_FREQUENT ^ 0xffffffff) & (NetworkObjectClass::BIT_CREATION | NetworkObjectClass::BIT_RARE | NetworkObjectClass::BIT_OCCASIONAL);
  384. WWPROFILE("TCADO");
  385. WWASSERT(client_id >= 0);
  386. WWASSERT(cNetwork::I_Am_Server());
  387. if (Get_Server_Rhost(client_id) == NULL) {
  388. return;
  389. }
  390. if (cNetwork::I_Am_Client() && client_id == cNetwork::Get_My_Id())
  391. {
  392. //
  393. // Server does not send to his own client.
  394. //
  395. return;
  396. }
  397. cRemoteHost *r_host = cNetwork::Get_Server_Rhost(client_id);
  398. bool update_priorities = (r_host->Get_Priority_Update_Counter() == 0) ? true : false;
  399. r_host->Increment_Priority_Count();
  400. int i;
  401. VisTableClass *pvs = NULL;
  402. int count = 0;
  403. bool global_packet_allowance_full = false;
  404. NetworkObjectClass *temp_obj;
  405. unsigned long time = TIMEGETTIME();
  406. int global_count = 0;
  407. /*
  408. ** Get our budget in bits per second for this guy.
  409. */
  410. int bits_per_second = r_host->Get_Target_Bps();
  411. /*
  412. ** Adjust the cut off threshold for vis hidden objects further out if more bandwidth is available.
  413. */
  414. float min_vis_distance = 15.0f;
  415. if (bits_per_second > 60000) {
  416. min_vis_distance = 50.0f;
  417. }
  418. /*
  419. ** Convert to bytes.
  420. */
  421. int bytes_per_second = bits_per_second >> 3;
  422. /*
  423. ** We have NetUpdateRate updates per second.
  424. */
  425. int net_update_rate = cUserOptions::NetUpdateRate.Get();
  426. /*
  427. ** Work out how many bytes we can send per update.
  428. */
  429. int avail_bytes_per_update = bytes_per_second / net_update_rate;
  430. /*
  431. ** Don't use more than 50% of the available bytes per update for guaranteed packets.
  432. */
  433. unsigned long bytes_out = 0;
  434. unsigned long max_bytes = avail_bytes_per_update; //(avail_bytes_per_update >> 1); //* 3) / 4;
  435. /*
  436. ** Figure a compression ratio of 2:1 for guaranteed packets.
  437. */
  438. //max_bytes <<= 1;
  439. {
  440. WWPROFILE("GetVis");
  441. if (update_priorities) {
  442. pvs = COMBAT_SCENE->Get_Vis_Table(dest_pos);
  443. }
  444. }
  445. count = NetworkObjectMgrClass::Get_Object_Count();
  446. /*
  447. ** List of objects requiring frequent updates.
  448. */
  449. static DynamicVectorClass<NetworkObjectClass *> object_list(500);
  450. object_list.Reset_Active();
  451. object_list.Set_Growth_Step(100);
  452. SoldierGameObj * player_ptr = GameObjManager::Find_Soldier_Of_Client_ID(client_id);
  453. {
  454. WWPROFILE("ListBuild");
  455. /*
  456. ** Go through the object list once and figure out all the priorities.
  457. */
  458. for (int index = 0; index < count; index ++) {
  459. NetworkObjectClass * p_object = NetworkObjectMgrClass::Get_Object(index);
  460. if (p_object == NULL) {
  461. continue;
  462. }
  463. float priority = 0.0f;
  464. /*
  465. ** SERVERFPS events are low priority but must have some kind of priority.
  466. */
  467. if (p_object->Get_App_Packet_Type() == APPPACKETTYPE_SERVERFPS) {
  468. priority = 0.05f;
  469. p_object->Set_Cached_Priority_2(client_id, priority);
  470. object_list.Add(p_object);
  471. } else {
  472. unsigned char dirty = p_object->Get_Object_Dirty_Bits(client_id);
  473. if (dirty & dirty_check) {
  474. /*
  475. ** This is a guaranteed packet update. Just send it right away.
  476. */
  477. if (!global_packet_allowance_full || p_object->Get_App_Packet_Type() == APPPACKETTYPE_CLIENTBBOEVENT) {
  478. bytes_out += (Send_Object_Update(p_object, client_id) >> 3);
  479. p_object->Set_Last_Update_Time(client_id, time);
  480. }
  481. global_count++;
  482. /*
  483. ** See if we are using too much bandwidth and don't send any more guaranteed packets if we are.
  484. */
  485. if (!global_packet_allowance_full && bytes_out > max_bytes) {
  486. #ifdef WWDEBUG
  487. if (cDevOptions::ExtraNetDebug.Is_True()) {
  488. WWDEBUG_SAY(("*** WARNING: Tell_Client_About_Dynamic_Objects - Insufficient bandwidth to send all guaranteed packets ***\n"));
  489. WWDEBUG_SAY(("*** After %d objects, bytes_out = %d, max_bytes = %d\n", global_count, bytes_out, max_bytes));
  490. }
  491. #endif //WWDEBUG
  492. global_packet_allowance_full = true;
  493. }
  494. } else {
  495. /*
  496. ** Get the base priority. This is how important we think this object is to this client.
  497. */
  498. if ((dirty & NetworkObjectClass::BIT_FREQUENT) != 0) {
  499. priority = p_object->Get_Cached_Priority_2(client_id);
  500. if (p_object == player_ptr) {
  501. if (player_ptr->Is_In_Vehicle()) {
  502. priority = 0.1f;
  503. } else {
  504. priority = 0.8f;
  505. }
  506. } else {
  507. if (p_object->Get_Client_Hint_Count(client_id) > 0) {
  508. priority = 1.0f;
  509. p_object->Reset_Client_Hint_Count(client_id);
  510. } else {
  511. /*
  512. ** If we can't see it at all, ignore it unless the priority is really high. A really high priority might indicate
  513. ** an object update request from the client.
  514. */
  515. /*
  516. ** Even if the client can't see the object, it's probably a good idea to update it if it's really
  517. ** close to the client. Say 15 meters.
  518. */
  519. if (update_priorities) {
  520. int vis_id = p_object->Get_Vis_ID();
  521. bool hidden = false;
  522. if (pvs && vis_id != -1 && !pvs->Get_Bit(vis_id)) {
  523. hidden = true;
  524. }
  525. if (hidden) {
  526. int distance = cPriority::Get_Object_Distance_2(dest_pos, p_object);
  527. if (distance > min_vis_distance) {
  528. /*
  529. ** Allow some very infrequent updates for distant, hidden objects on broadband connections.
  530. */
  531. if (bits_per_second > 100000 && distance < 150.0f) {
  532. priority = 0.01f;
  533. } else {
  534. priority = 0.0f;
  535. }
  536. } else {
  537. /*
  538. ** It's hidden, but close (maybe as close at 15 meters), so it's probably somewhat important to us.
  539. */
  540. priority = 0.2f;
  541. }
  542. } else {
  543. /*
  544. ** Figure out the priority if it's time or if we couldn't see the object last frame but we can now.
  545. */
  546. //if (update_priorities || priority == 0.0f) {
  547. priority = cPriority::Compute_Object_Priority_2(client_id, dest_pos, p_object, false, player_ptr);
  548. p_object->Set_Cached_Priority_2(client_id, priority);
  549. //}
  550. }
  551. }
  552. }
  553. }
  554. p_object->Set_Cached_Priority_2(client_id, priority);
  555. if (priority > 0.001f) {
  556. /*
  557. ** Work out the export size if we don't know it already.
  558. */
  559. if (p_object->Get_Frequent_Update_Export_Size() == 0) {
  560. cPacket packet;
  561. int bits_before = packet.Get_Bit_Write_Position();
  562. packet.Add(p_object->Get_Network_ID());
  563. packet.Add(p_object->Get_Object_Dirty_Bits_2(client_id));
  564. packet.Add(p_object->Is_Delete_Pending());
  565. int bits_now = packet.Get_Bit_Write_Position();
  566. p_object->Export_Frequent (packet);
  567. int bits_after = packet.Get_Bit_Write_Position();
  568. int packet_size = 0;
  569. if (bits_now < bits_after) {
  570. packet_size = (bits_after - bits_before) / 8;
  571. /*
  572. ** Add the packet header.
  573. */
  574. packet_size += cPacket::Get_Packet_Header_Size();
  575. p_object->Set_Frequent_Update_Export_Size(packet_size);
  576. } else {
  577. /*
  578. ** For some reason, some objects have a frequent bit set but there is no frequent update export.
  579. */
  580. p_object->Set_Frequent_Update_Export_Size(0xff);
  581. }
  582. }
  583. /*
  584. ** Add this object to our update list.
  585. */
  586. if (p_object->Get_Frequent_Update_Export_Size() > 0 && p_object->Get_Frequent_Update_Export_Size() < 0xff) {
  587. object_list.Add(p_object);
  588. }
  589. }
  590. }
  591. }
  592. }
  593. }
  594. }
  595. /*
  596. ** Now we have a list of non-guaranteed objects that we would like to send.
  597. */
  598. /*
  599. ** Factor in the bandwidth multiplier.
  600. */
  601. float mult = Get_Server_Rhost(client_id)->Get_Bandwidth_Multiplier();
  602. if (r_host->Get_Flood()) {
  603. if (r_host->Get_Target_Bps() < 14400) {
  604. mult = 0.7f;
  605. } else {
  606. mult = 1.0f;
  607. }
  608. }
  609. avail_bytes_per_update = (int) (mult * (float)avail_bytes_per_update);
  610. /*
  611. ** If we used tons of bandwidth on guaranteed packets then throttle back on non-guaranteed stuff.
  612. */
  613. if (global_packet_allowance_full) {
  614. avail_bytes_per_update >>= 1;
  615. }
  616. /*
  617. ** Work out the average priority. We will need this later when balancing bandwidth budgets between clients.
  618. */
  619. float average_priority = 0.0f;
  620. int num_priorities = 0;
  621. {
  622. WWPROFILE("CalcRate");
  623. for (i=0 ; i<object_list.Count() ; i++) {
  624. temp_obj = object_list[i];
  625. if (temp_obj->Get_App_Packet_Type() != APPPACKETTYPE_SERVERFPS) {
  626. float pri = temp_obj->Get_Cached_Priority_2(client_id);
  627. /*
  628. ** Don't count unseen objects or objects we are getting hints for.
  629. */
  630. if (pri > 0.001f && pri < 1.0f) {
  631. average_priority += pri;
  632. num_priorities++;
  633. }
  634. }
  635. }
  636. if (num_priorities) {
  637. average_priority = average_priority / (float)num_priorities;
  638. Get_Server_Rhost(client_id)->Set_Average_Priority(average_priority);
  639. /*
  640. ** Remaining objects get updated based on priority.
  641. ** Just set the rate based on priority then we will go back in a second pass and adjust it according to remaining bandwidth.
  642. */
  643. float ms_low = max_update_rate;
  644. float ms_high = min_update_rate;
  645. float spread = ms_high - ms_low;
  646. int total_bps = 0;
  647. for (i=0 ; i<object_list.Count() ; i++) {
  648. temp_obj = object_list[i];
  649. float pri = temp_obj->Get_Cached_Priority_2(client_id);
  650. unsigned long update_rate = infinity_update_rate; //0;
  651. if (pri > 0.025f) { //01f) {
  652. update_rate = (unsigned long)(((1.0f - pri) * spread) + ms_low);
  653. } else {
  654. if (pri > 0.009f) {
  655. update_rate = min_update_rate;
  656. }
  657. }
  658. temp_obj->Set_Update_Rate(client_id, (unsigned short) update_rate);
  659. if (update_rate != infinity_update_rate) {
  660. int bps = (1000.0f / update_rate) * temp_obj->Get_Frequent_Update_Export_Size();
  661. total_bps += bps;
  662. }
  663. }
  664. /*
  665. ** Make that number a per update figure.
  666. */
  667. total_bps = total_bps / net_update_rate;
  668. /*
  669. ** Now, scale the update rate based on available bandwidth.
  670. */
  671. float factor = 1.0;
  672. if (total_bps) {
  673. factor = avail_bytes_per_update / total_bps;
  674. if (factor < 0.00001f) {
  675. factor = 0.00001f;
  676. }
  677. }
  678. unsigned short rate;
  679. float float_rate;
  680. for (i=0 ; i<object_list.Count() ; i++) {
  681. temp_obj = object_list[i];
  682. float obj_upd_rate = (float)temp_obj->Get_Update_Rate(client_id);
  683. if (obj_upd_rate != infinity_update_rate && obj_upd_rate < (min_update_rate + WWMATH_EPSILON)) {
  684. float_rate = obj_upd_rate / factor;
  685. rate = (unsigned short) float_rate;
  686. temp_obj->Set_Update_Rate(client_id, rate);
  687. }
  688. }
  689. } else {
  690. Get_Server_Rhost(client_id)->Set_Average_Priority(0.0f);
  691. }
  692. }
  693. {
  694. WWPROFILE("SendN");
  695. /*
  696. ** Send those packets whos time has come.
  697. */
  698. for (i=0 ; i<object_list.Count() ; i++) {
  699. temp_obj = object_list[i];
  700. unsigned long rate = (unsigned long)temp_obj->Get_Update_Rate(client_id);
  701. if (rate != (unsigned long)infinity_update_rate) {
  702. if (time - temp_obj->Get_Last_Update_Time(client_id) > rate) {
  703. Send_Object_Update(temp_obj, client_id);
  704. temp_obj->Set_Last_Update_Time(client_id, time);
  705. }
  706. }
  707. }
  708. }
  709. if (pvs) {
  710. REF_PTR_RELEASE(pvs);
  711. }
  712. }
  713. #endif // not BETACLIENT
  714. }
  715. //-----------------------------------------------------------------------------
  716. void cNetwork::Tell_Server_About_Dynamic_Objects
  717. (
  718. void
  719. )
  720. {
  721. #ifndef FREEDEDICATEDSERVER
  722. WWASSERT (cNetwork::I_Am_Client());
  723. //
  724. // Loop over each network object
  725. //
  726. int count = NetworkObjectMgrClass::Get_Object_Count();
  727. //int debug_count = 0;
  728. for (int index = 0; index < count; index ++) {
  729. NetworkObjectClass * object = NetworkObjectMgrClass::Get_Object(index);
  730. //
  731. // Should we send update information for this object?
  732. //
  733. if (object != NULL && object->Is_Client_Dirty(0))
  734. {
  735. //
  736. // Transmit the object's data to the server
  737. //
  738. Send_Object_Update(object, 0);
  739. //debug_count++;
  740. }
  741. }
  742. //unsigned long time = TIMEGETTIME() / 1000;
  743. //WWDEBUG_SAY(("Updated %d objects at %d\n", debug_count, time));
  744. #endif // !FREEDEDICATEDSERVER
  745. }
  746. //-----------------------------------------------------------------------------
  747. void cNetwork::Tell_Client_About_Delete_Notifications(int client_id)
  748. {
  749. #ifndef BETACLIENT
  750. WWASSERT (client_id >= 0);
  751. WWASSERT (cNetwork::I_Am_Server ());
  752. if (Get_Server_Rhost (client_id) == NULL) {
  753. return;
  754. }
  755. //
  756. // Loop over each network object
  757. //
  758. int count = NetworkObjectMgrClass::Get_Object_Count ();
  759. for (int index = 0; index < count; index ++) {
  760. NetworkObjectClass *object = NetworkObjectMgrClass::Get_Object (index);
  761. //
  762. // Is this object going to be deleted soon?
  763. //
  764. if (object != NULL && object->Is_Delete_Pending ()) {
  765. //
  766. // Does the local client need this information?
  767. //
  768. bool send = true;
  769. if (cNetwork::I_Am_Client() &&
  770. client_id == cNetwork::Get_My_Id ())
  771. {
  772. send = false;
  773. }
  774. if (send)
  775. {
  776. //
  777. // Transmit the object's data to the client
  778. //
  779. Send_Object_Update (object, client_id);
  780. }
  781. }
  782. }
  783. return ;
  784. #endif // not BETACLIENT
  785. }
  786. //-----------------------------------------------------------------------------
  787. int
  788. cNetwork::Send_Object_Update(NetworkObjectClass *object, int client_id)
  789. {
  790. WWPROFILE( "send obj upd" );
  791. WWASSERT(client_id >= 0);
  792. Debug_Network_Prolific((
  793. "Sending update for object %d to %s",
  794. object->Get_Network_ID (), Get_Client_String(client_id)));
  795. WWASSERT(object->Get_Network_ID() > 0);
  796. // Track number of bits sent.
  797. int bits_sent = 0;
  798. //
  799. // Build a packet that will contain enough information about
  800. // the object so the client will be able to import the data
  801. //
  802. cPacket packet;
  803. packet.Add(object->Get_Network_ID());
  804. packet.Add(object->Get_Object_Dirty_Bits(client_id));
  805. packet.Add(object->Is_Delete_Pending());
  806. //packet.Add(object->Get_App_Packet_Type());
  807. BYTE type = object->Get_App_Packet_Type();
  808. int bits_start = packet.Get_Bit_Write_Position();
  809. //
  810. // Send mode is unreliable unless creation/rare/occasional data is present.
  811. //
  812. int mode = SEND_UNRELIABLE;
  813. //
  814. // TSS101101
  815. //
  816. if (object->Is_Delete_Pending()) {
  817. mode = SEND_RELIABLE;
  818. }
  819. //
  820. // Add creation information to the packet (if necessary)
  821. //
  822. if (object->Get_Object_Dirty_Bit (client_id, NetworkObjectClass::BIT_CREATION)) {
  823. int bits_before = packet.Get_Bit_Write_Position();
  824. //
  825. // Add the class id of the object so it can be created on the client.
  826. //
  827. uint32 net_classid = object->Get_Network_Class_ID ();
  828. packet.Add (net_classid);
  829. //
  830. // Lookup the factory for this object
  831. //
  832. NetworkObjectFactoryClass *factory = NetworkObjectFactoryMgrClass::Find_Factory (net_classid);
  833. WWASSERT (factory != NULL);
  834. //
  835. // Store any data in the packet that's needed in order
  836. // to create the object on the client
  837. //
  838. factory->Prep_Packet (object, packet);
  839. //
  840. // Send object-specific data to the client
  841. //
  842. object->Export_Creation (packet);
  843. int bits_after = packet.Get_Bit_Write_Position();
  844. cAppPacketStats::Increment_Bits_Sent_Tier(type, PACKET_TIER_CREATION, bits_after - bits_before);
  845. mode = SEND_RELIABLE;
  846. }
  847. //
  848. // Add rare information to the packet (if necessary)
  849. //
  850. if (object->Get_Object_Dirty_Bit (client_id, NetworkObjectClass::BIT_RARE)) {
  851. int bits_before = packet.Get_Bit_Write_Position();
  852. object->Export_Rare (packet);
  853. int bits_after = packet.Get_Bit_Write_Position();
  854. cAppPacketStats::Increment_Bits_Sent_Tier(type, PACKET_TIER_RARE, bits_after - bits_before);
  855. mode = SEND_RELIABLE;
  856. }
  857. //
  858. // Add occasional information to the packet (if necessary)
  859. //
  860. if (object->Get_Object_Dirty_Bit (client_id, NetworkObjectClass::BIT_OCCASIONAL)) {
  861. int bits_before = packet.Get_Bit_Write_Position();
  862. object->Export_Occasional (packet);
  863. int bits_after = packet.Get_Bit_Write_Position();
  864. cAppPacketStats::Increment_Bits_Sent_Tier(type, PACKET_TIER_OCCASIONAL, bits_after - bits_before);
  865. mode = SEND_RELIABLE;
  866. }
  867. //
  868. // Add frequent information to the packet (if necessary)
  869. //
  870. if (object->Get_Object_Dirty_Bit (client_id, NetworkObjectClass::BIT_FREQUENT)) {
  871. int bits_before = packet.Get_Bit_Write_Position();
  872. object->Export_Frequent (packet);
  873. int bits_after = packet.Get_Bit_Write_Position();
  874. cAppPacketStats::Increment_Bits_Sent_Tier(type, PACKET_TIER_FREQUENT, bits_after - bits_before);
  875. }
  876. int bits_end = packet.Get_Bit_Write_Position();
  877. if (mode == SEND_RELIABLE && object->Get_Unreliable_Override() == true) {
  878. //
  879. // The normal rules would make us send this packet reliably, but this
  880. // has been explicitly overridden.
  881. //
  882. mode = SEND_UNRELIABLE;
  883. }
  884. //
  885. // Trying just not sending the packet if there is nothing in it.
  886. //
  887. if (object->Is_Delete_Pending() || (bits_end > bits_start)) {
  888. bits_sent = packet.Get_Bit_Write_Position();
  889. //
  890. // Send the packet to the client or server
  891. //
  892. if (client_id > 0) {
  893. //WWDEBUG_SAY(("Sending update for object %d\n", object->Get_Network_ID()));
  894. Server_Send_Packet(packet, mode, client_id);
  895. } else {
  896. Client_Send_Packet(packet, mode);
  897. }
  898. }
  899. #ifdef WWDEBUG
  900. if (client_id > 0) {
  901. //
  902. // It is useful to be able to generate a bunch of
  903. // extra bandwidth
  904. //
  905. for (int i = 0; i < cDevOptions::SpamCount.Get (); i ++) {
  906. WWDEBUG_SAY(("Sending spam\n"));
  907. Server_Send_Packet(packet, mode, client_id);
  908. }
  909. }
  910. #endif // WWDEBUG
  911. //
  912. // Reset the dirty bits for this client
  913. //
  914. object->Set_Object_Dirty_Bit (client_id, NetworkObjectClass::BIT_CREATION, false);
  915. object->Set_Object_Dirty_Bit (client_id, NetworkObjectClass::BIT_RARE, false);
  916. object->Set_Object_Dirty_Bit (client_id, NetworkObjectClass::BIT_OCCASIONAL, false);
  917. //if (client_id > 0)
  918. {
  919. //
  920. // This is a server send. Record stats.
  921. //
  922. /*
  923. //if (type == APPPACKETTYPE_UNKNOWN)
  924. if (type == APPPACKETTYPE_SIMPLE)
  925. {
  926. WWDEBUG_SAY(("WTF is this?\n"));
  927. }
  928. /**/
  929. //
  930. // Record stats
  931. //
  932. cAppPacketStats::Increment_Packets_Sent(type);
  933. cAppPacketStats::Increment_Bits_Sent(type, bits_end - bits_start);
  934. }
  935. return(bits_sent);
  936. }
  937. //-----------------------------------------------------------------------------
  938. void cNetwork::Intermission_Over_Processing(void)
  939. {
  940. WWDEBUG_SAY(("cNetwork::Intermission_Over_Processing\n"));
  941. WWASSERT(cNetwork::I_Am_Server());
  942. //
  943. // Terminate the win screen dialog
  944. //
  945. CNCWinScreenMenuClass::Close_Dialog ();
  946. //
  947. // Destroy any commando's, let them be recreated afresh
  948. //
  949. for (
  950. SLNode<cPlayer> * objnode = cPlayerManager::Get_Player_Object_List()->Head();
  951. objnode; objnode =
  952. objnode->Next()) {
  953. cPlayer * p_player = objnode->Data();
  954. WWASSERT(p_player != NULL);
  955. Delete_Player_Objects(p_player->Get_Id());
  956. if (p_player->Is_Human()) {
  957. //
  958. // Set their ingame flag to false.
  959. // They will each notify us when they have finished loading.
  960. //
  961. p_player->Set_Is_In_Game(false);
  962. if (cNetwork::PServerConnection) {
  963. cNetwork::PServerConnection->Set_Rhost_Is_In_Game(p_player->Get_Id(), false);
  964. }
  965. }
  966. }
  967. if (cGameData::Is_Manual_Exit()) {
  968. GameInitMgrClass::Set_Needs_Game_Exit_All(true);
  969. } else {
  970. //
  971. // If we have to quit out now then don't do a core restart.
  972. //
  973. if (The_Game () != NULL && The_Game ()->Is_Map_Cycle_Over () == false) {
  974. extern bool g_b_core_restart;
  975. g_b_core_restart = true;
  976. GameModeClass *game_mode = GameModeManager::Find("WOL");
  977. if (game_mode && game_mode->Is_Active()) {
  978. WolGameModeClass* wol_game = (WolGameModeClass*) game_mode;
  979. if (wol_game->Post_Game_Check()) {
  980. g_b_core_restart = false;
  981. }
  982. }
  983. } else {
  984. GameInitMgrClass::Set_Needs_Game_Exit (true);
  985. }
  986. }
  987. //
  988. // TSS092601
  989. //
  990. WWASSERT(PTheGameData != NULL);
  991. The_Game()->IsIntermission.Set(false);
  992. }
  993. //-----------------------------------------------------------------------------
  994. void cNetwork::End_Game_Test(void)
  995. {
  996. #ifndef BETACLIENT
  997. WWASSERT(cNetwork::I_Am_Server());
  998. if (IS_MISSION || !GameModeManager::Find("Combat")->Is_Active()) {
  999. return;
  1000. }
  1001. WWASSERT(PTheGameData != NULL);
  1002. if (The_Game()->IsIntermission.Is_True()) {
  1003. if (The_Game()->Get_Intermission_Time_Remaining() < WWMATH_EPSILON) {
  1004. Intermission_Over_Processing();
  1005. }
  1006. } else {
  1007. //
  1008. // Sort teams and players once a second
  1009. //
  1010. bool is_game_over = The_Game()->Is_Game_Over();
  1011. bool sort=is_game_over;
  1012. int seconds=cMathUtil::Round(TimeManager::Get_Seconds());
  1013. if (!sort) {
  1014. if (seconds!=LastSortedSecond) {
  1015. LastSortedSecond=seconds;
  1016. sort=true;
  1017. }
  1018. }
  1019. if (sort) {
  1020. cTeamManager::Sort_Teams();
  1021. cPlayerManager::Sort_Players(true);
  1022. }
  1023. if (is_game_over) {
  1024. The_Game()->Game_Over_Processing();
  1025. }
  1026. }
  1027. #endif // not BETACLIENT
  1028. }
  1029. //-----------------------------------------------------------------------------
  1030. void cNetwork::Shared_Client_And_Server_Think(void)
  1031. {
  1032. WWASSERT(I_Am_Client() || I_Am_Server());
  1033. WWASSERT(PTheGameData != NULL);
  1034. The_Game()->Think();
  1035. Hibernation_Think();
  1036. }
  1037. //-----------------------------------------------------------------------------
  1038. bool cNetwork::Client_Think(void)
  1039. {
  1040. bool ret_code = false;
  1041. #ifndef FREEDEDICATEDSERVER
  1042. if (PClientConnection->Is_Destroy()) {
  1043. Cleanup_Client();
  1044. return(ret_code);
  1045. }
  1046. if (!PClientConnection->Have_Id()) {
  1047. return(ret_code);
  1048. }
  1049. //
  1050. // Client reload if necessary
  1051. //
  1052. WWASSERT(PTheGameData != NULL);
  1053. if (I_Am_Only_Client() &&
  1054. The_Game()->IsIntermission.Is_True() &&
  1055. The_Game()->Get_Intermission_Time_Remaining() < WWMATH_EPSILON)
  1056. {
  1057. //
  1058. // Terminate the win screen dialog
  1059. //
  1060. CNCWinScreenMenuClass::Close_Dialog ();
  1061. //
  1062. // See if we have the next map in the cycle.
  1063. //
  1064. bool quit = false;
  1065. if (The_Game()->Is_Map_Cycle_Over()) {
  1066. quit = true;
  1067. } else {
  1068. if (!The_Game()->Is_Map_Valid()) {
  1069. quit = true;
  1070. }
  1071. }
  1072. if (quit) {
  1073. //
  1074. // If the map looping is over, then quit the game
  1075. //
  1076. GameInitMgrClass::Set_Needs_Game_Exit (true);
  1077. } else {
  1078. extern bool g_b_core_restart;
  1079. g_b_core_restart = true;
  1080. }
  1081. }
  1082. cClientPingManager::Think();
  1083. cClientHintManager::Think();
  1084. WWASSERT(Receiver!= NULL);
  1085. ret_code = Receiver->Client_Update_Dynamic_Objects();
  1086. //
  1087. // Pop up the team change dialog if it is appropriate and we have not already
  1088. // done so.
  1089. //
  1090. if (!HaveDoneTeamChangeDialog && cChangeTeamEvent::Is_Change_Team_Possible()
  1091. && DlgMsgBox::Get_Current_Count() == 0) {
  1092. HaveDoneTeamChangeDialog = true;
  1093. DlgMPTeamSelect::DoDialog(*The_Game());
  1094. }
  1095. //
  1096. // Pop up the MOTD dialog if appropriate.
  1097. //
  1098. if (!HaveDoneMotdDialog) {
  1099. if (I_Am_Only_Client()) {
  1100. if ((DlgMsgBox::Get_Current_Count() == 0)
  1101. && GameModeManager::Find("Combat") != NULL && GameModeManager::Find("Combat")->Is_Active()
  1102. && The_Game() != NULL && ::wcslen(The_Game()->Get_Motd()) > 0) {
  1103. DlgMsgBox::DoDialog(TRANSLATE (IDS_MENU_MOTD), The_Game()->Get_Motd());
  1104. HaveDoneMotdDialog = true;
  1105. }
  1106. } else {
  1107. HaveDoneMotdDialog = true;
  1108. }
  1109. }
  1110. #endif // !FREEDEDICATEDSERVER
  1111. return(ret_code);
  1112. }
  1113. //-----------------------------------------------------------------------------
  1114. VisTableClass * cNetwork::Peek_Temp_Vis_Table(void)
  1115. {
  1116. bool alloc_new_table = false;
  1117. if (VisTable == NULL) {
  1118. alloc_new_table = true;
  1119. } else if (VisTable->Get_Bit_Count() != COMBAT_SCENE->Get_Vis_Table_Size()) {
  1120. alloc_new_table = true;
  1121. }
  1122. if (alloc_new_table) {
  1123. REF_PTR_RELEASE(VisTable);
  1124. VisTable = new VisTableClass(COMBAT_SCENE->Get_Vis_Table_Size(), 0);
  1125. }
  1126. WWASSERT(VisTable != NULL);
  1127. VisTable->Reset_All();
  1128. return VisTable;
  1129. }
  1130. //-----------------------------------------------------------------------------
  1131. void cNetwork::Hibernation_Think(void)
  1132. {
  1133. if (COMBAT_SCENE != NULL) {
  1134. //
  1135. // The server can't let any player go into hibernation or updates will cease to be sent for that player.
  1136. //
  1137. if (I_Am_Server() && !IS_MISSION) {
  1138. for (
  1139. SLNode<BaseGameObj> * p_objnode = GameObjManager::Get_Game_Obj_List()->Head();
  1140. p_objnode;
  1141. p_objnode = p_objnode->Next()) {
  1142. PhysicalGameObj * p_phys_go = p_objnode->Data()->As_PhysicalGameObj();
  1143. if (p_phys_go != NULL) {
  1144. p_phys_go->Reset_Hibernating();
  1145. }
  1146. }
  1147. } else {
  1148. VisTableClass * p_vis_table = Peek_Temp_Vis_Table();
  1149. WWASSERT(p_vis_table != NULL);
  1150. //
  1151. // Build a union of all players' PVS's
  1152. //
  1153. for (
  1154. SLNode<SmartGameObj> * p_smart_objnode = GameObjManager::Get_Smart_Game_Obj_List()->Head();
  1155. p_smart_objnode;
  1156. p_smart_objnode = p_smart_objnode->Next()) {
  1157. WWASSERT(p_smart_objnode->Data() != NULL);
  1158. SoldierGameObj * p_soldier = p_smart_objnode->Data()->As_SoldierGameObj();
  1159. if (p_soldier != NULL && p_soldier->Has_Player()) {
  1160. Vector3 player_pos;
  1161. p_soldier->Get_Position(&player_pos);
  1162. player_pos.Z += 2; // Start near the player's head
  1163. VisTableClass * p_player_pvs = COMBAT_SCENE->Get_Vis_Table(player_pos);
  1164. if (p_player_pvs == NULL) {
  1165. p_vis_table = NULL;
  1166. break;
  1167. } else {
  1168. p_vis_table->Merge(*p_player_pvs);
  1169. REF_PTR_RELEASE(p_player_pvs);
  1170. }
  1171. }
  1172. }
  1173. //
  1174. // Reset hibernating on anything visible
  1175. //
  1176. Vector3 star_pos(0,0,0);
  1177. if ( COMBAT_STAR ) {
  1178. COMBAT_STAR->Get_Position( &star_pos );
  1179. }
  1180. for (
  1181. SLNode<BaseGameObj> * p_objnode = GameObjManager::Get_Game_Obj_List()->Head();
  1182. p_objnode;
  1183. p_objnode = p_objnode->Next()) {
  1184. PhysicalGameObj * p_phys_go = p_objnode->Data()->As_PhysicalGameObj();
  1185. if (p_phys_go != NULL) {
  1186. PhysClass * p_phys_obj = p_phys_go->Peek_Physical_Object();
  1187. if (p_phys_obj != NULL &&
  1188. (p_vis_table == NULL || p_vis_table->Get_Bit(p_phys_obj->Get_Vis_Object_ID()))) {
  1189. // Only if within 300m of the star;
  1190. #define MIN_HIB_DISTANCE 300
  1191. Vector3 pos;
  1192. p_phys_go->Get_Position( &pos );
  1193. pos -= star_pos;
  1194. if ( pos.Length2() < MIN_HIB_DISTANCE * MIN_HIB_DISTANCE ) {
  1195. p_phys_go->Reset_Hibernating();
  1196. }
  1197. }
  1198. }
  1199. }
  1200. }
  1201. }
  1202. }
  1203. //-----------------------------------------------------------------------------
  1204. bool cNetwork::Server_Think(void)
  1205. {
  1206. WWASSERT(I_Am_Server());
  1207. bool ret_code = false;
  1208. {
  1209. WWPROFILE( "God Think" );
  1210. if (GameModeManager::Find( "Combat" )->Is_Active()) {
  1211. cGod::Think();
  1212. }
  1213. }
  1214. {
  1215. WWPROFILE( "End_Game_Test" );
  1216. End_Game_Test();
  1217. }
  1218. //
  1219. // Update clients about dynamic & static objects
  1220. //
  1221. WWASSERT(Receiver!= NULL);
  1222. //
  1223. // TSS121101
  1224. // The following I_Am_Server test seems to be necessary. In v 85
  1225. // we were getting occasional I_Am_Server asserts on the server
  1226. // inside Server_Update_Dynamic_Objects.
  1227. //
  1228. if (I_Am_Server())
  1229. {
  1230. {
  1231. WWPROFILE( "svrupd dyn" );
  1232. ret_code = Receiver->Server_Update_Dynamic_Objects();
  1233. }
  1234. {
  1235. WWPROFILE( "svrupd del" );
  1236. Receiver->Server_Send_Delete_Notifications();
  1237. }
  1238. }
  1239. return(ret_code);
  1240. }
  1241. //-----------------------------------------------------------------------------
  1242. void cNetwork::Server_Kill_Connection( int client_id )
  1243. {
  1244. WWASSERT(client_id >= 0);
  1245. WWASSERT(I_Am_Server());
  1246. PServerConnection->Destroy_Connection( client_id );
  1247. WWDEBUG_SAY(("cNetwork::Server_Kill_Connection for client %d\n", client_id));
  1248. }
  1249. //-----------------------------------------------------------------------------
  1250. void cNetwork::Delete_Player_Objects(int client_id)
  1251. {
  1252. WWDEBUG_SAY(("cNetwork::Delete_Player_Objects %d\n", client_id));
  1253. WWASSERT(I_Am_Server());
  1254. //
  1255. // Delete all objects controlled by this guy; inform all clients.
  1256. //
  1257. SLNode<BaseGameObj> * objnode;
  1258. for (objnode = GameObjManager::Get_Game_Obj_List()->Head(); objnode; objnode = objnode->Next()) {
  1259. WWASSERT(objnode->Data() != NULL);
  1260. PhysicalGameObj * p_phys_obj = objnode->Data()->As_PhysicalGameObj();
  1261. if (p_phys_obj != NULL) {
  1262. SmartGameObj * p_smart_obj = p_phys_obj->As_SmartGameObj();
  1263. if (p_smart_obj != NULL &&
  1264. (p_smart_obj->Get_Control_Owner() == client_id))
  1265. {
  1266. //
  1267. // Destroy the object
  1268. //
  1269. p_smart_obj->Set_Delete_Pending ();
  1270. }
  1271. }
  1272. }
  1273. }
  1274. //-----------------------------------------------------------------------------
  1275. //
  1276. // Call this after a client leaves or breaks connection.
  1277. //
  1278. //void cNetwork::Cleanup_After_Client(int client_id, bool is_departure_graceful)
  1279. void cNetwork::Cleanup_After_Client(int client_id)
  1280. {
  1281. WWDEBUG_SAY(("cNetwork::Cleanup_After_Client %d\n", client_id));
  1282. WWASSERT(I_Am_Server());
  1283. Remove_Player(client_id);
  1284. Delete_Player_Objects(client_id);
  1285. NetworkObjectMgrClass::Delete_Client_Objects(client_id);
  1286. //
  1287. // We need to special-case these new delete notifications or delete_pending
  1288. // will clear them first.
  1289. //
  1290. WWASSERT(Receiver!= NULL);
  1291. Receiver->Server_Send_Delete_Notifications();
  1292. NetworkObjectMgrClass::Restore_Dirty_Bits(client_id);
  1293. CCDKeyAuth::DisconnectUser(client_id);
  1294. }
  1295. //-----------------------------------------------------------------------------
  1296. void cNetwork::Remove_Player(int player_id)
  1297. {
  1298. WWDEBUG_SAY(("cNetwork::Remove_Player %d\n", player_id));
  1299. WWASSERT(I_Am_Server());
  1300. cPlayer * p_player = cPlayerManager::Find_Player(player_id);
  1301. //
  1302. // We can't remove the player structure because we wish to retain
  1303. // it for scoring etc
  1304. //
  1305. if (p_player != NULL) {
  1306. p_player->Increment_Total_Time();
  1307. p_player->Set_Is_Active(false);
  1308. StringClass str(128, true);
  1309. p_player->Get_Name().Convert_To(str);
  1310. ConsoleBox.Print_Maybe("Player %s left the game\n", str.Peek_Buffer());
  1311. }
  1312. if (p_player != NULL && IS_MULTIPLAY) {
  1313. Test_For_Team_Defaulting(p_player);
  1314. }
  1315. }
  1316. //-----------------------------------------------------------------------------
  1317. void cNetwork::Test_For_Team_Defaulting(cPlayer * p_player)
  1318. {
  1319. //
  1320. // If all players on the winning team bail, take punitive action:
  1321. // reverse the team scores of Nod and GDI.
  1322. //
  1323. WWDEBUG_SAY(("cNetwork::Test_For_Team_Defaulting\n"));
  1324. WWASSERT(p_player != NULL);
  1325. WWASSERT(IS_MULTIPLAY);
  1326. int count_nod = cPlayerManager::Tally_Team_Size(PLAYERTYPE_NOD);
  1327. int count_gdi = cPlayerManager::Tally_Team_Size(PLAYERTYPE_GDI);
  1328. cTeam * p_team_nod = cTeamManager::Find_Team(PLAYERTYPE_NOD);
  1329. WWASSERT(p_team_nod != NULL);
  1330. cTeam * p_team_gdi = cTeamManager::Find_Team(PLAYERTYPE_GDI);
  1331. WWASSERT(p_team_gdi != NULL);
  1332. float score_nod = p_team_nod->Get_Score();
  1333. float score_gdi = p_team_gdi->Get_Score();
  1334. if (p_player->Get_Player_Type() == PLAYERTYPE_NOD &&
  1335. count_nod == 0 &&
  1336. score_nod > score_gdi) {
  1337. WWDEBUG_SAY(("Reversing Nod and GDI scores due to Nod defaulting.\n"));
  1338. p_team_gdi->Set_Score(score_nod);
  1339. p_team_nod->Set_Score(score_gdi);
  1340. }
  1341. else if (p_player->Get_Player_Type() == PLAYERTYPE_GDI &&
  1342. count_gdi == 0 &&
  1343. score_gdi > score_nod) {
  1344. WWDEBUG_SAY(("Reversing Nod and GDI scores due to GDI defaulting.\n"));
  1345. p_team_gdi->Set_Score(score_nod);
  1346. p_team_nod->Set_Score(score_gdi);
  1347. }
  1348. }