gameConnection.cpp 92 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971
  1. //-----------------------------------------------------------------------------
  2. // Copyright (c) 2012 GarageGames, LLC
  3. //
  4. // Permission is hereby granted, free of charge, to any person obtaining a copy
  5. // of this software and associated documentation files (the "Software"), to
  6. // deal in the Software without restriction, including without limitation the
  7. // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
  8. // sell copies of the Software, and to permit persons to whom the Software is
  9. // furnished to do so, subject to the following conditions:
  10. //
  11. // The above copyright notice and this permission notice shall be included in
  12. // all copies or substantial portions of the Software.
  13. //
  14. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  19. // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
  20. // IN THE SOFTWARE.
  21. //-----------------------------------------------------------------------------
  22. //~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
  23. // Arcane-FX for MIT Licensed Open Source version of Torque 3D from GarageGames
  24. // Copyright (C) 2015 Faust Logic, Inc.
  25. //~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
  26. #include "platform/platform.h"
  27. #include "T3D/gameBase/gameConnection.h"
  28. #include "platform/profiler.h"
  29. #include "core/dnet.h"
  30. #include "core/util/safeDelete.h"
  31. #include "core/stream/bitStream.h"
  32. #include "console/consoleTypes.h"
  33. #include "console/simBase.h"
  34. #include "sfx/sfxProfile.h"
  35. #include "sfx/sfxDescription.h"
  36. #include "app/game.h"
  37. #include "app/auth.h"
  38. #include "T3D/camera.h"
  39. #include "T3D/gameBase/gameProcess.h"
  40. #include "T3D/gameBase/gameConnectionEvents.h"
  41. #include "console/engineAPI.h"
  42. #include "math/mTransform.h"
  43. #ifdef TORQUE_EXPERIMENTAL_EC
  44. #include "T3D/entity.h"
  45. #include "T3D/components/coreInterfaces.h"
  46. #endif
  47. #ifdef TORQUE_HIFI_NET
  48. #include "T3D/gameBase/hifi/hifiMoveList.h"
  49. #elif defined TORQUE_EXTENDED_MOVE
  50. #include "T3D/gameBase/extended/extendedMoveList.h"
  51. #else
  52. #include "T3D/gameBase/std/stdMoveList.h"
  53. #endif
  54. #ifdef AFX_CAP_DATABLOCK_CACHE
  55. #include "core/stream/fileStream.h"
  56. #endif
  57. #include "afx/arcaneFX.h"
  58. //----------------------------------------------------------------------------
  59. #define MAX_MOVE_PACKET_SENDS 4
  60. #define ControlRequestTime 5000
  61. const U32 GameConnection::CurrentProtocolVersion = 12;
  62. const U32 GameConnection::MinRequiredProtocolVersion = 12;
  63. //----------------------------------------------------------------------------
  64. IMPLEMENT_CONOBJECT(GameConnection);
  65. S32 GameConnection::mLagThresholdMS = 0;
  66. Signal<void(F32)> GameConnection::smFovUpdate;
  67. Signal<void()> GameConnection::smPlayingDemo;
  68. ConsoleDocClass( GameConnection,
  69. "@brief The game-specific subclass of NetConnection.\n\n"
  70. "The GameConnection introduces the concept of the control object. The control object "
  71. "is simply the object that the client is associated with that network connection controls. By "
  72. "default the control object is an instance of the Player class, but can also be an instance "
  73. "of Camera (when editing the mission, for example), or any other ShapeBase derived class as "
  74. "appropriate for the game.\n\n"
  75. "Torque uses a model in which the server is the authoritative master of the simulation. To "
  76. "prevent clients from cheating, the server simulates all player moves and then tells the "
  77. "client where his player is in the world. This model, while secure, can have problems. If "
  78. "the network latency is high, this round-trip time can give the player a very noticeable sense "
  79. "of movement lag. To correct this problem, the game uses a form of prediction - it simulates "
  80. "the movement of the control object on the client and on the server both. This way the client "
  81. "doesn't need to wait for round-trip verification of his moves. Only in the case of a force "
  82. "acting on the control object on the server that doesn't exist on the client does the client's "
  83. "position need to be forcefully changed.\n\n"
  84. "To support this, all control objects (derivative of ShapeBase) must supply a writePacketData() "
  85. "and readPacketData() function that send enough data to accurately simulate the object on the "
  86. "client. These functions are only called for the current control object, and only when the "
  87. "server can determine that the client's simulation is somehow out of sync with the server. This "
  88. "occurs usually if the client is affected by a force not present on the server (like an "
  89. "interpolating object) or if the server object is affected by a server only force (such as the "
  90. "impulse from an explosion).\n\n"
  91. "The Move structure is a 32 millisecond snapshot of player input, containing x, y, and z "
  92. "positional and rotational changes as well as trigger state changes. When time passes in the "
  93. "simulation moves are collected (depending on how much time passes), and applied to the current "
  94. "control object on the client. The same moves are then packed over to the server in "
  95. "GameConnection::writePacket(), for processing on the server's version of the control object.\n\n"
  96. "@see @ref Networking, NetConnection, ShapeBase\n\n"
  97. "@ingroup Networking\n");
  98. //----------------------------------------------------------------------------
  99. IMPLEMENT_CALLBACK( GameConnection, onConnectionTimedOut, void, (), (),
  100. "@brief Called on the client when the connection to the server times out.\n\n");
  101. IMPLEMENT_CALLBACK( GameConnection, onConnectionAccepted, void, (), (),
  102. "@brief Called on the client when the connection to the server has been established.\n\n");
  103. IMPLEMENT_CALLBACK( GameConnection, onConnectRequestTimedOut, void, (), (),
  104. "@brief Called when connection attempts have timed out.\n\n");
  105. IMPLEMENT_CALLBACK( GameConnection, onConnectionDropped, void, (const char* reason), (reason),
  106. "@brief Called on the client when the connection to the server has been dropped.\n\n"
  107. "@param reason The reason why the connection was dropped.\n\n");
  108. IMPLEMENT_CALLBACK( GameConnection, onConnectRequestRejected, void, (const char* reason), (reason),
  109. "@brief Called on the client when the connection to the server has been rejected.\n\n"
  110. "@param reason The reason why the connection request was rejected.\n\n");
  111. IMPLEMENT_CALLBACK( GameConnection, onConnectionError, void, (const char* errorString), (errorString),
  112. "@brief Called on the client when there is an error with the connection to the server.\n\n"
  113. "@param errorString The connection error text.\n\n");
  114. IMPLEMENT_CALLBACK( GameConnection, onDrop, void, (const char* disconnectReason), (disconnectReason),
  115. "@brief Called on the server when the client's connection has been dropped.\n\n"
  116. "@param disconnectReason The reason why the connection was dropped.\n\n");
  117. IMPLEMENT_CALLBACK( GameConnection, initialControlSet, void, (), (),
  118. "@brief Called on the client when the first control object has been set by the "
  119. "server and we are now ready to go.\n\n"
  120. "A common action to perform when this callback is called is to switch the GUI "
  121. "canvas from the loading screen and over to the 3D game GUI.");
  122. IMPLEMENT_CALLBACK( GameConnection, onControlObjectChange, void, (), (),
  123. "@brief Called on the client when the control object has been changed by the "
  124. "server.\n\n");
  125. IMPLEMENT_CALLBACK( GameConnection, setLagIcon, void, (bool state), (state),
  126. "@brief Called on the client to display the lag icon.\n\n"
  127. "When the connection with the server is lagging, this callback is called to "
  128. "allow the game GUI to display some indicator to the player.\n\n"
  129. "@param state Set to true if the lag icon should be displayed.\n\n");
  130. IMPLEMENT_CALLBACK( GameConnection, onDataBlocksDone, void, (U32 sequence), (sequence),
  131. "@brief Called on the server when all datablocks has been sent to the client.\n\n"
  132. "During phase 1 of the mission download, all datablocks are sent from the server "
  133. "to the client. Once all datablocks have been sent, this callback is called and "
  134. "the mission download procedure may move on to the next phase.\n\n"
  135. "@param sequence The sequence is common between the server and client and ensures "
  136. "that the client is acting on the most recent mission start process. If an errant "
  137. "network packet (one that was lost but has now been found) is received by the client "
  138. "with an incorrect sequence, it is just ignored. This sequence number is updated on "
  139. "the server every time a mission is loaded.\n\n"
  140. "@see GameConnection::transmitDataBlocks()\n\n");
  141. IMPLEMENT_GLOBAL_CALLBACK( onDataBlockObjectReceived, void, (U32 index, U32 total), (index, total),
  142. "@brief Called on the client each time a datablock has been received.\n\n"
  143. "This callback is typically used to notify the player of how far along "
  144. "in the datablock download process they are.\n\n"
  145. "@param index The index of the datablock just received.\n"
  146. "@param total The total number of datablocks to be received.\n\n"
  147. "@see GameConnection, GameConnection::transmitDataBlocks(), GameConnection::onDataBlocksDone()\n\n"
  148. "@ingroup Networking\n");
  149. IMPLEMENT_CALLBACK( GameConnection, onFlash, void, (bool state), (state),
  150. "@brief Called on the client when the damage flash or white out states change.\n\n"
  151. "When the server changes the damage flash or white out values, this callback is called "
  152. "either is on or both are off. Typically this is used to enable the flash postFx.\n\n"
  153. "@param state Set to true if either the damage flash or white out conditions are active.\n\n");
  154. #ifdef AFX_CAP_DATABLOCK_CACHE
  155. StringTableEntry GameConnection::server_cache_filename = "";
  156. StringTableEntry GameConnection::client_cache_filename = "";
  157. bool GameConnection::server_cache_on = false;
  158. bool GameConnection::client_cache_on = false;
  159. #endif
  160. //----------------------------------------------------------------------------
  161. GameConnection::GameConnection()
  162. {
  163. mRolloverObj = NULL;
  164. mPreSelectedObj = NULL;
  165. mSelectedObj = NULL;
  166. mChangedSelectedObj = false;
  167. mPreSelectTimestamp = 0;
  168. zoned_in = false;
  169. #ifdef AFX_CAP_DATABLOCK_CACHE
  170. client_db_stream = new InfiniteBitStream;
  171. server_cache_CRC = 0xffffffff;
  172. #endif
  173. mLagging = false;
  174. mControlObject = NULL;
  175. mCameraObject = NULL;
  176. #ifdef TORQUE_HIFI_NET
  177. mMoveList = new HifiMoveList();
  178. #elif defined TORQUE_EXTENDED_MOVE
  179. mMoveList = new ExtendedMoveList();
  180. #else
  181. mMoveList = new StdMoveList();
  182. #endif
  183. mMoveList->setConnection( this );
  184. mDataBlockModifiedKey = 0;
  185. mMaxDataBlockModifiedKey = 0;
  186. mAuthInfo = NULL;
  187. mControlForceMismatch = false;
  188. mConnectArgc = 0;
  189. for(U32 i = 0; i < MaxConnectArgs; i++)
  190. mConnectArgv[i] = 0;
  191. mJoinPassword = NULL;
  192. mMissionCRC = 0xffffffff;
  193. mDamageFlash = mWhiteOut = 0;
  194. mCameraPos = 0;
  195. mCameraSpeed = 10;
  196. mCameraFov = 90.f;
  197. mUpdateCameraFov = false;
  198. mAIControlled = false;
  199. mLastPacketTime = 0;
  200. mDisconnectReason[0] = 0;
  201. //blackout vars
  202. mBlackOut = 0.0f;
  203. mBlackOutTimeMS = 0;
  204. mBlackOutStartTimeMS = 0;
  205. mFadeToBlack = false;
  206. // first person
  207. mFirstPerson = true;
  208. mUpdateFirstPerson = false;
  209. // Control scheme
  210. mUpdateControlScheme = false;
  211. mAbsoluteRotation = false;
  212. mAddYawToAbsRot = false;
  213. mAddPitchToAbsRot = false;
  214. mVisibleGhostDistance = 0.0f;
  215. clearDisplayDevice();
  216. }
  217. GameConnection::~GameConnection()
  218. {
  219. setDisplayDevice(NULL);
  220. delete mAuthInfo;
  221. for(U32 i = 0; i < mConnectArgc; i++)
  222. dFree(mConnectArgv[i]);
  223. dFree(mJoinPassword);
  224. delete mMoveList;
  225. #ifdef AFX_CAP_DATABLOCK_CACHE
  226. delete client_db_stream;
  227. #endif
  228. }
  229. //----------------------------------------------------------------------------
  230. void GameConnection::setVisibleGhostDistance(F32 dist)
  231. {
  232. mVisibleGhostDistance = dist;
  233. }
  234. F32 GameConnection::getVisibleGhostDistance()
  235. {
  236. return mVisibleGhostDistance;
  237. }
  238. bool GameConnection::canRemoteCreate()
  239. {
  240. return true;
  241. }
  242. void GameConnection::setConnectArgs(U32 argc, const char **argv)
  243. {
  244. if(argc > MaxConnectArgs)
  245. argc = MaxConnectArgs;
  246. mConnectArgc = argc;
  247. for(U32 i = 0; i < mConnectArgc; i++)
  248. mConnectArgv[i] = dStrdup(argv[i]);
  249. }
  250. void GameConnection::setJoinPassword(const char *password)
  251. {
  252. mJoinPassword = dStrdup(password);
  253. }
  254. DefineEngineMethod( GameConnection, setJoinPassword, void, (const char* password),,
  255. "@brief On the client, set the password that will be passed to the server.\n\n"
  256. "On the server, this password is compared with what is stored in $pref::Server::Password. "
  257. "If $pref::Server::Password is empty then the client's sent password is ignored. Otherwise, "
  258. "if the passed in client password and the server password do not match, the CHR_PASSWORD "
  259. "error string is sent back to the client and the connection is immediately terminated.\n\n"
  260. "This password checking is performed quite early on in the connection request process so as "
  261. "to minimize the impact of multiple failed attempts -- also known as hacking.")
  262. {
  263. object->setJoinPassword(password);
  264. }
  265. ConsoleMethod(GameConnection, setConnectArgs, void, 3, 17,
  266. "(const char* args) @brief On the client, pass along a variable set of parameters to the server.\n\n"
  267. "Once the connection is established with the server, the server calls its onConnect() method "
  268. "with the client's passed in parameters as aruments.\n\n"
  269. "@see GameConnection::onConnect()\n\n")
  270. {
  271. StringStackWrapper args(argc - 2, argv + 2);
  272. object->setConnectArgs(args.count(), args);
  273. }
  274. void GameConnection::onTimedOut()
  275. {
  276. if(isConnectionToServer())
  277. {
  278. Con::printf("Connection to server timed out");
  279. onConnectionTimedOut_callback();
  280. }
  281. else
  282. {
  283. Con::printf("Client %d timed out.", getId());
  284. setDisconnectReason("TimedOut");
  285. }
  286. }
  287. void GameConnection::onConnectionEstablished(bool isInitiator)
  288. {
  289. if(isInitiator)
  290. {
  291. setGhostFrom(false);
  292. setGhostTo(true);
  293. setSendingEvents(true);
  294. setTranslatesStrings(true);
  295. setIsConnectionToServer();
  296. mServerConnection = this;
  297. Con::printf("Connection established %d", getId());
  298. onConnectionAccepted_callback();
  299. }
  300. else
  301. {
  302. setGhostFrom(true);
  303. setGhostTo(false);
  304. setSendingEvents(true);
  305. setTranslatesStrings(true);
  306. Sim::getClientGroup()->addObject(this);
  307. mMoveList->init();
  308. const char *argv[MaxConnectArgs + 2];
  309. argv[0] = "onConnect";
  310. argv[1] = NULL; // Filled in later
  311. for(U32 i = 0; i < mConnectArgc; i++)
  312. argv[i + 2] = mConnectArgv[i];
  313. // NOTE: Need to fallback to Con::execute() as IMPLEMENT_CALLBACK does not
  314. // support variadic functions.
  315. Con::execute(this, mConnectArgc + 2, argv);
  316. }
  317. }
  318. void GameConnection::onConnectTimedOut()
  319. {
  320. onConnectRequestTimedOut_callback();
  321. }
  322. void GameConnection::onDisconnect(const char *reason)
  323. {
  324. if(isConnectionToServer())
  325. {
  326. Con::printf("Connection with server lost.");
  327. onConnectionDropped_callback(reason);
  328. mMoveList->init();
  329. }
  330. else
  331. {
  332. Con::printf("Client %d disconnected.", getId());
  333. setDisconnectReason(reason);
  334. }
  335. }
  336. void GameConnection::onConnectionRejected(const char *reason)
  337. {
  338. onConnectRequestRejected_callback(reason);
  339. }
  340. void GameConnection::handleStartupError(const char *errorString)
  341. {
  342. onConnectRequestRejected_callback(errorString);
  343. }
  344. void GameConnection::writeConnectAccept(BitStream *stream)
  345. {
  346. Parent::writeConnectAccept(stream);
  347. stream->write(getProtocolVersion());
  348. }
  349. bool GameConnection::readConnectAccept(BitStream *stream, const char **errorString)
  350. {
  351. if(!Parent::readConnectAccept(stream, errorString))
  352. return false;
  353. U32 protocolVersion;
  354. stream->read(&protocolVersion);
  355. if(protocolVersion < MinRequiredProtocolVersion || protocolVersion > CurrentProtocolVersion)
  356. {
  357. *errorString = "CHR_PROTOCOL"; // this should never happen unless someone is faking us out.
  358. return false;
  359. }
  360. return true;
  361. }
  362. void GameConnection::writeConnectRequest(BitStream *stream)
  363. {
  364. Parent::writeConnectRequest(stream);
  365. stream->writeString(TORQUE_APP_NAME);
  366. stream->write(CurrentProtocolVersion);
  367. stream->write(MinRequiredProtocolVersion);
  368. stream->writeString(mJoinPassword);
  369. stream->write(mConnectArgc);
  370. for(U32 i = 0; i < mConnectArgc; i++)
  371. stream->writeString(mConnectArgv[i]);
  372. }
  373. bool GameConnection::readConnectRequest(BitStream *stream, const char **errorString)
  374. {
  375. if(!Parent::readConnectRequest(stream, errorString))
  376. return false;
  377. U32 currentProtocol, minProtocol;
  378. char gameString[256];
  379. stream->readString(gameString);
  380. if(dStrcmp(gameString, TORQUE_APP_NAME))
  381. {
  382. *errorString = "CHR_GAME";
  383. return false;
  384. }
  385. stream->read(&currentProtocol);
  386. stream->read(&minProtocol);
  387. char joinPassword[256];
  388. stream->readString(joinPassword);
  389. if(currentProtocol < MinRequiredProtocolVersion)
  390. {
  391. *errorString = "CHR_PROTOCOL_LESS";
  392. return false;
  393. }
  394. if(minProtocol > CurrentProtocolVersion)
  395. {
  396. *errorString = "CHR_PROTOCOL_GREATER";
  397. return false;
  398. }
  399. setProtocolVersion(currentProtocol < CurrentProtocolVersion ? currentProtocol : CurrentProtocolVersion);
  400. const char *serverPassword = Con::getVariable("pref::Server::Password");
  401. if(serverPassword[0])
  402. {
  403. if(dStrcmp(joinPassword, serverPassword))
  404. {
  405. *errorString = "CHR_PASSWORD";
  406. return false;
  407. }
  408. }
  409. stream->read(&mConnectArgc);
  410. if(mConnectArgc > MaxConnectArgs)
  411. {
  412. *errorString = "CR_INVALID_ARGS";
  413. return false;
  414. }
  415. ConsoleValueRef connectArgv[MaxConnectArgs + 3];
  416. ConsoleValue connectArgvValue[MaxConnectArgs + 3];
  417. for(U32 i = 0; i < mConnectArgc+3; i++)
  418. {
  419. connectArgv[i].value = &connectArgvValue[i];
  420. connectArgvValue[i].init();
  421. }
  422. for(U32 i = 0; i < mConnectArgc; i++)
  423. {
  424. char argString[256];
  425. stream->readString(argString);
  426. mConnectArgv[i] = dStrdup(argString);
  427. connectArgv[i + 3] = mConnectArgv[i];
  428. }
  429. connectArgvValue[0].setStackStringValue("onConnectRequest");
  430. connectArgvValue[1].setIntValue(0);
  431. char buffer[256];
  432. Net::addressToString(getNetAddress(), buffer);
  433. connectArgvValue[2].setStackStringValue(buffer);
  434. // NOTE: Cannot convert over to IMPLEMENT_CALLBACK as it has variable args.
  435. const char *ret = Con::execute(this, mConnectArgc + 3, connectArgv);
  436. if(ret[0])
  437. {
  438. *errorString = ret;
  439. return false;
  440. }
  441. return true;
  442. }
  443. //----------------------------------------------------------------------------
  444. //----------------------------------------------------------------------------
  445. void GameConnection::connectionError(const char *errorString)
  446. {
  447. if(isConnectionToServer())
  448. {
  449. Con::printf("Connection error: %s.", errorString);
  450. onConnectionError_callback(errorString);
  451. }
  452. else
  453. {
  454. Con::printf("Client %d packet error: %s.", getId(), errorString);
  455. setDisconnectReason("Packet Error.");
  456. }
  457. deleteObject();
  458. }
  459. void GameConnection::setAuthInfo(const AuthInfo *info)
  460. {
  461. mAuthInfo = new AuthInfo;
  462. *mAuthInfo = *info;
  463. }
  464. const AuthInfo *GameConnection::getAuthInfo()
  465. {
  466. return mAuthInfo;
  467. }
  468. //----------------------------------------------------------------------------
  469. void GameConnection::setControlObject(GameBase *obj)
  470. {
  471. if(mControlObject == obj)
  472. return;
  473. if(mControlObject && mControlObject != mCameraObject)
  474. mControlObject->setControllingClient(0);
  475. if(obj)
  476. {
  477. // Nothing else is permitted to control this object.
  478. if (GameBase* coo = obj->getControllingObject())
  479. coo->setControlObject(0);
  480. if (GameConnection *con = obj->getControllingClient())
  481. {
  482. if(this != con)
  483. {
  484. // was it controlled via camera or control
  485. if(con->getControlObject() == obj)
  486. con->setControlObject(0);
  487. else
  488. con->setCameraObject(0);
  489. }
  490. }
  491. // We are now the controlling client of this object.
  492. obj->setControllingClient(this);
  493. // Update the camera's FOV to match the new control object
  494. //but only if we don't have a specific camera object
  495. if (!mCameraObject)
  496. setControlCameraFov(obj->getCameraFov());
  497. }
  498. // Okay, set our control object.
  499. mControlObject = obj;
  500. mControlForceMismatch = true;
  501. if(mCameraObject.isNull())
  502. setScopeObject(mControlObject);
  503. }
  504. void GameConnection::setCameraObject(GameBase *obj)
  505. {
  506. if(mCameraObject == obj)
  507. return;
  508. if(mCameraObject && mCameraObject != mControlObject)
  509. mCameraObject->setControllingClient(0);
  510. if(obj)
  511. {
  512. // nothing else is permitted to control this object
  513. if(GameBase *coo = obj->getControllingObject())
  514. coo->setControlObject(0);
  515. if(GameConnection *con = obj->getControllingClient())
  516. {
  517. if(this != con)
  518. {
  519. // was it controlled via camera or control
  520. if(con->getControlObject() == obj)
  521. con->setControlObject(0);
  522. else
  523. con->setCameraObject(0);
  524. }
  525. }
  526. // we are now the controlling client of this object
  527. obj->setControllingClient(this);
  528. }
  529. // Okay, set our camera object.
  530. mCameraObject = obj;
  531. if(mCameraObject.isNull())
  532. setScopeObject(mControlObject);
  533. else
  534. {
  535. setScopeObject(mCameraObject);
  536. // if this is a client then set the fov and active image
  537. if(isConnectionToServer())
  538. {
  539. F32 fov = mCameraObject->getDefaultCameraFov();
  540. //GameSetCameraFov(fov);
  541. smFovUpdate.trigger(fov);
  542. }
  543. }
  544. }
  545. GameBase* GameConnection::getCameraObject()
  546. {
  547. // If there is no camera object, or if we're first person, return
  548. // the control object.
  549. if( !mControlObject.isNull() && (mCameraObject.isNull() || mFirstPerson))
  550. return mControlObject;
  551. return mCameraObject;
  552. }
  553. static S32 sChaseQueueSize = 0;
  554. static MatrixF* sChaseQueue = 0;
  555. static S32 sChaseQueueHead = 0;
  556. static S32 sChaseQueueTail = 0;
  557. bool GameConnection::getControlCameraTransform(F32 dt, MatrixF* mat)
  558. {
  559. GameBase* obj = getCameraObject();
  560. if(!obj)
  561. return false;
  562. GameBase* cObj = obj;
  563. while((cObj = cObj->getControlObject()) != 0)
  564. {
  565. if(cObj->useObjsEyePoint())
  566. obj = cObj;
  567. }
  568. if (dt)
  569. {
  570. if (mFirstPerson || obj->onlyFirstPerson())
  571. {
  572. if (mCameraPos > 0)
  573. if ((mCameraPos -= mCameraSpeed * dt) <= 0)
  574. mCameraPos = 0;
  575. }
  576. else
  577. {
  578. if (mCameraPos < 1)
  579. if ((mCameraPos += mCameraSpeed * dt) > 1)
  580. mCameraPos = 1;
  581. }
  582. }
  583. if (!sChaseQueueSize || mFirstPerson || obj->onlyFirstPerson())
  584. obj->getCameraTransform(&mCameraPos,mat);
  585. else
  586. {
  587. MatrixF& hm = sChaseQueue[sChaseQueueHead];
  588. MatrixF& tm = sChaseQueue[sChaseQueueTail];
  589. obj->getCameraTransform(&mCameraPos,&hm);
  590. *mat = tm;
  591. if (dt)
  592. {
  593. if ((sChaseQueueHead += 1) >= sChaseQueueSize)
  594. sChaseQueueHead = 0;
  595. if (sChaseQueueHead == sChaseQueueTail)
  596. if ((sChaseQueueTail += 1) >= sChaseQueueSize)
  597. sChaseQueueTail = 0;
  598. }
  599. }
  600. return true;
  601. }
  602. bool GameConnection::getControlCameraHeadTransform(IDisplayDevice *display, MatrixF *transform)
  603. {
  604. GameBase* obj = getCameraObject();
  605. if (!obj)
  606. return false;
  607. GameBase* cObj = obj;
  608. while ((cObj = cObj->getControlObject()) != 0)
  609. {
  610. if (cObj->useObjsEyePoint())
  611. obj = cObj;
  612. }
  613. obj->getEyeCameraTransform(display, -1, transform);
  614. return true;
  615. }
  616. bool GameConnection::getControlCameraEyeTransforms(IDisplayDevice *display, MatrixF *transforms)
  617. {
  618. GameBase* obj = getCameraObject();
  619. if(!obj)
  620. return false;
  621. GameBase* cObj = obj;
  622. while((cObj = cObj->getControlObject()) != 0)
  623. {
  624. if(cObj->useObjsEyePoint())
  625. obj = cObj;
  626. }
  627. // Perform operation on left & right eyes. For each we need to calculate the world space
  628. // of the rotated eye offset and add that onto the camera world space.
  629. for (U32 i=0; i<2; i++)
  630. {
  631. obj->getEyeCameraTransform(display, i, &transforms[i]);
  632. }
  633. return true;
  634. }
  635. bool GameConnection::getControlCameraDefaultFov(F32 * fov)
  636. {
  637. //find the last control object in the chain (client->player->turret->whatever...)
  638. GameBase *obj = getCameraObject();
  639. GameBase *cObj = NULL;
  640. while (obj)
  641. {
  642. cObj = obj;
  643. obj = obj->getControlObject();
  644. }
  645. if (cObj)
  646. {
  647. *fov = cObj->getDefaultCameraFov();
  648. return(true);
  649. }
  650. return(false);
  651. }
  652. bool GameConnection::getControlCameraFov(F32 * fov)
  653. {
  654. //find the last control object in the chain (client->player->turret->whatever...)
  655. GameBase *obj = getCameraObject();
  656. GameBase *cObj = NULL;
  657. while (obj)
  658. {
  659. cObj = obj;
  660. obj = obj->getControlObject();
  661. }
  662. if (cObj)
  663. {
  664. #ifdef TORQUE_EXPERIMENTAL_EC
  665. if (Entity* ent = dynamic_cast<Entity*>(cObj))
  666. {
  667. if (CameraInterface* camInterface = ent->getComponent<CameraInterface>())
  668. {
  669. *fov = camInterface->getCameraFov();
  670. }
  671. }
  672. else
  673. {
  674. *fov = cObj->getCameraFov();
  675. }
  676. #else
  677. *fov = cObj->getCameraFov();
  678. #endif
  679. return(true);
  680. }
  681. return(false);
  682. }
  683. bool GameConnection::isValidControlCameraFov(F32 fov)
  684. {
  685. //find the last control object in the chain (client->player->turret->whatever...)
  686. GameBase *obj = getCameraObject();
  687. GameBase *cObj = NULL;
  688. while (obj)
  689. {
  690. cObj = obj;
  691. obj = obj->getControlObject();
  692. }
  693. if (cObj)
  694. {
  695. #ifdef TORQUE_EXPERIMENTAL_EC
  696. if (Entity* ent = dynamic_cast<Entity*>(cObj))
  697. {
  698. if (CameraInterface* camInterface = ent->getComponent<CameraInterface>())
  699. {
  700. return camInterface->isValidCameraFov(fov);
  701. }
  702. }
  703. else
  704. {
  705. return cObj->isValidCameraFov(fov);
  706. }
  707. #else
  708. return cObj->isValidCameraFov(fov);
  709. #endif
  710. }
  711. return NULL;
  712. }
  713. bool GameConnection::setControlCameraFov(F32 fov)
  714. {
  715. //find the last control object in the chain (client->player->turret->whatever...)
  716. GameBase *obj = getCameraObject();
  717. GameBase *cObj = NULL;
  718. while (obj)
  719. {
  720. cObj = obj;
  721. obj = obj->getControlObject();
  722. }
  723. if (cObj)
  724. {
  725. #ifdef TORQUE_EXPERIMENTAL_EC
  726. F32 newFov = 90.f;
  727. if (Entity* ent = dynamic_cast<Entity*>(cObj))
  728. {
  729. if (CameraInterface* camInterface = ent->getComponent<CameraInterface>())
  730. {
  731. camInterface->setCameraFov(mClampF(fov, MinCameraFov, MaxCameraFov));
  732. newFov = camInterface->getCameraFov();
  733. }
  734. else
  735. {
  736. Con::errorf("Attempted to setControlCameraFov, but we don't have a camera!");
  737. }
  738. }
  739. else
  740. {
  741. // allow shapebase to clamp fov to its datablock values
  742. cObj->setCameraFov(mClampF(fov, MinCameraFov, MaxCameraFov));
  743. newFov = cObj->getCameraFov();
  744. }
  745. #else
  746. // allow shapebase to clamp fov to its datablock values
  747. cObj->setCameraFov(mClampF(fov, MinCameraFov, MaxCameraFov));
  748. F32 newFov = cObj->getCameraFov();
  749. #endif
  750. // server fov of client has 1degree resolution
  751. if( S32(newFov) != S32(mCameraFov) || newFov != fov )
  752. mUpdateCameraFov = true;
  753. mCameraFov = newFov;
  754. return(true);
  755. }
  756. return(false);
  757. }
  758. bool GameConnection::getControlCameraVelocity(Point3F *vel)
  759. {
  760. if (GameBase* obj = getCameraObject()) {
  761. *vel = obj->getVelocity();
  762. return true;
  763. }
  764. return false;
  765. }
  766. bool GameConnection::isControlObjectRotDampedCamera()
  767. {
  768. if (Camera* cam = dynamic_cast<Camera*>(getCameraObject())) {
  769. if(cam->isRotationDamped())
  770. return true;
  771. }
  772. return false;
  773. }
  774. void GameConnection::setFirstPerson(bool firstPerson)
  775. {
  776. mFirstPerson = firstPerson;
  777. mUpdateFirstPerson = true;
  778. }
  779. //----------------------------------------------------------------------------
  780. void GameConnection::setControlSchemeParameters(bool absoluteRotation, bool addYawToAbsRot, bool addPitchToAbsRot)
  781. {
  782. mAbsoluteRotation = absoluteRotation;
  783. mAddYawToAbsRot = addYawToAbsRot;
  784. mAddPitchToAbsRot = addPitchToAbsRot;
  785. mUpdateControlScheme = true;
  786. }
  787. //----------------------------------------------------------------------------
  788. bool GameConnection::onAdd()
  789. {
  790. if (!Parent::onAdd())
  791. return false;
  792. return true;
  793. }
  794. void GameConnection::onRemove()
  795. {
  796. if(isNetworkConnection())
  797. {
  798. sendDisconnectPacket(mDisconnectReason);
  799. }
  800. else if (isLocalConnection() && isConnectionToServer())
  801. {
  802. // We're a client-side but local connection
  803. // delete the server side of the connection on our local server so that it updates
  804. // clientgroup and what not (this is so that we can disconnect from a local server
  805. // without needing to destroy and recreate the server before we can connect to it
  806. // again).
  807. // Safe-delete as we don't know whether the server connection is currently being
  808. // worked on.
  809. getRemoteConnection()->safeDeleteObject();
  810. setRemoteConnectionObject(NULL);
  811. }
  812. if(!isConnectionToServer())
  813. {
  814. onDrop_callback(mDisconnectReason);
  815. }
  816. if (mControlObject)
  817. mControlObject->setControllingClient(0);
  818. Parent::onRemove();
  819. }
  820. void GameConnection::setDisconnectReason(const char *str)
  821. {
  822. dStrncpy(mDisconnectReason, str, sizeof(mDisconnectReason) - 1);
  823. mDisconnectReason[sizeof(mDisconnectReason) - 1] = 0;
  824. }
  825. //----------------------------------------------------------------------------
  826. void GameConnection::handleRecordedBlock(U32 type, U32 size, void *data)
  827. {
  828. switch(type)
  829. {
  830. case BlockTypeMove:
  831. mMoveList->pushMove(*((Move *) data));
  832. if(isRecording()) // put it back into the stream
  833. recordBlock(type, size, data);
  834. break;
  835. default:
  836. Parent::handleRecordedBlock(type, size, data);
  837. break;
  838. }
  839. }
  840. void GameConnection::writeDemoStartBlock(ResizeBitStream *stream)
  841. {
  842. // write all the data blocks to the stream:
  843. for(SimObjectId i = DataBlockObjectIdFirst; i <= DataBlockObjectIdLast; i++)
  844. {
  845. SimDataBlock *data;
  846. if(Sim::findObject(i, data))
  847. {
  848. stream->writeFlag(true);
  849. SimDataBlockEvent evt(data);
  850. evt.pack(this, stream);
  851. stream->validate();
  852. }
  853. }
  854. stream->writeFlag(false);
  855. stream->write(mFirstPerson);
  856. stream->write(mCameraPos);
  857. stream->write(mCameraSpeed);
  858. // Control scheme
  859. stream->write(mAbsoluteRotation);
  860. stream->write(mAddYawToAbsRot);
  861. stream->write(mAddPitchToAbsRot);
  862. stream->writeString(Con::getVariable("$Client::MissionFile"));
  863. mMoveList->writeDemoStartBlock(stream);
  864. // dump all the "demo" vars associated with this connection:
  865. SimFieldDictionaryIterator itr(getFieldDictionary());
  866. SimFieldDictionary::Entry *entry;
  867. while((entry = *itr) != NULL)
  868. {
  869. if(!dStrnicmp(entry->slotName, "demo", 4))
  870. {
  871. stream->writeFlag(true);
  872. stream->writeString(entry->slotName + 4);
  873. stream->writeString(entry->value);
  874. stream->validate();
  875. }
  876. ++itr;
  877. }
  878. stream->writeFlag(false);
  879. Parent::writeDemoStartBlock(stream);
  880. stream->validate();
  881. // dump out the control object ghost id
  882. S32 idx = mControlObject ? getGhostIndex(mControlObject) : -1;
  883. stream->write(idx);
  884. if(mControlObject)
  885. {
  886. #ifdef TORQUE_NET_STATS
  887. U32 beginPos = stream->getBitPosition();
  888. #endif
  889. mControlObject->writePacketData(this, stream);
  890. #ifdef TORQUE_NET_STATS
  891. // TYPEOF( mControlObject )->getNetInfo().updateNetStatWriteData( stream->getBitPosition() - beginPos );
  892. mControlObject->getClassRep()->updateNetStatWriteData( stream->getBitPosition() - beginPos);
  893. #endif
  894. }
  895. idx = mCameraObject ? getGhostIndex(mCameraObject) : -1;
  896. stream->write(idx);
  897. if(mCameraObject && mCameraObject != mControlObject)
  898. {
  899. #ifdef TORQUE_NET_STATS
  900. U32 beginPos = stream->getBitPosition();
  901. #endif
  902. mCameraObject->writePacketData(this, stream);
  903. #ifdef TORQUE_NET_STATS
  904. mCameraObject->getClassRep()->updateNetStatWriteData( stream->getBitPosition() - beginPos);
  905. #endif
  906. }
  907. mLastControlRequestTime = Platform::getVirtualMilliseconds();
  908. }
  909. bool GameConnection::readDemoStartBlock(BitStream *stream)
  910. {
  911. while(stream->readFlag())
  912. {
  913. SimDataBlockEvent evt;
  914. evt.unpack(this, stream);
  915. evt.process(this);
  916. }
  917. while(mDataBlockLoadList.size())
  918. {
  919. preloadNextDataBlock(false);
  920. if(mErrorBuffer.isNotEmpty())
  921. return false;
  922. }
  923. stream->read(&mFirstPerson);
  924. stream->read(&mCameraPos);
  925. stream->read(&mCameraSpeed);
  926. // Control scheme
  927. stream->read(&mAbsoluteRotation);
  928. stream->read(&mAddYawToAbsRot);
  929. stream->read(&mAddPitchToAbsRot);
  930. char buf[256];
  931. stream->readString(buf);
  932. Con::setVariable("$Client::MissionFile",buf);
  933. mMoveList->readDemoStartBlock(stream);
  934. // read in all the demo vars associated with this recording
  935. // they are all tagged on to the object and start with the
  936. // string "demo"
  937. while(stream->readFlag())
  938. {
  939. StringTableEntry slotName = StringTable->insert("demo");
  940. char array[256];
  941. char value[256];
  942. stream->readString(array);
  943. stream->readString(value);
  944. setDataField(slotName, array, value);
  945. }
  946. bool ret = Parent::readDemoStartBlock(stream);
  947. // grab the control object
  948. S32 idx;
  949. stream->read(&idx);
  950. GameBase * obj = 0;
  951. if(idx != -1)
  952. {
  953. obj = dynamic_cast<GameBase*>(resolveGhost(idx));
  954. setControlObject(obj);
  955. obj->readPacketData(this, stream);
  956. }
  957. // Get the camera object, and read it in if it's different
  958. S32 idx2;
  959. stream->read(&idx2);
  960. obj = 0;
  961. if(idx2 != -1 && idx2 != idx)
  962. {
  963. obj = dynamic_cast<GameBase*>(resolveGhost(idx2));
  964. setCameraObject(obj);
  965. obj->readPacketData(this, stream);
  966. }
  967. return ret;
  968. }
  969. void GameConnection::demoPlaybackComplete()
  970. {
  971. static const char* demoPlaybackArgv[1] = { "demoPlaybackComplete" };
  972. static StringStackConsoleWrapper demoPlaybackCmd(1, demoPlaybackArgv);
  973. Sim::postCurrentEvent(Sim::getRootGroup(), new SimConsoleEvent(demoPlaybackCmd.argc, demoPlaybackCmd.argv, false));
  974. Parent::demoPlaybackComplete();
  975. }
  976. void GameConnection::ghostPreRead(NetObject * nobj, bool newGhost)
  977. {
  978. Parent::ghostPreRead( nobj, newGhost );
  979. mMoveList->ghostPreRead(nobj,newGhost);
  980. }
  981. void GameConnection::ghostReadExtra(NetObject * nobj, BitStream * bstream, bool newGhost)
  982. {
  983. Parent::ghostReadExtra( nobj, bstream, newGhost );
  984. mMoveList->ghostReadExtra(nobj, bstream, newGhost);
  985. }
  986. void GameConnection::ghostWriteExtra(NetObject * nobj, BitStream * bstream)
  987. {
  988. Parent::ghostWriteExtra( nobj, bstream);
  989. mMoveList->ghostWriteExtra(nobj, bstream);
  990. }
  991. //----------------------------------------------------------------------------
  992. void GameConnection::readPacket(BitStream *bstream)
  993. {
  994. bstream->clearStringBuffer();
  995. bstream->clearCompressionPoint();
  996. if (isConnectionToServer())
  997. {
  998. mMoveList->clientReadMovePacket(bstream);
  999. // selected object - do we have a change in status?
  1000. if (bstream->readFlag())
  1001. {
  1002. if (bstream->readFlag())
  1003. {
  1004. S32 gIndex = bstream->readInt(NetConnection::GhostIdBitSize);
  1005. setSelectedObj(static_cast<SceneObject*>(resolveGhost(gIndex)));
  1006. }
  1007. else
  1008. setSelectedObj(NULL);
  1009. }
  1010. bool hadFlash = mDamageFlash > 0 || mWhiteOut > 0;
  1011. mDamageFlash = 0;
  1012. mWhiteOut = 0;
  1013. if(bstream->readFlag())
  1014. {
  1015. if(bstream->readFlag())
  1016. mDamageFlash = bstream->readFloat(7);
  1017. if(bstream->readFlag())
  1018. mWhiteOut = bstream->readFloat(7) * 1.5;
  1019. if(!hadFlash)
  1020. {
  1021. // Started a damage flash or white out
  1022. onFlash_callback(true);
  1023. }
  1024. else
  1025. {
  1026. if(!(mDamageFlash > 0 || mWhiteOut > 0))
  1027. {
  1028. // Received a zero damage flash and white out.
  1029. onFlash_callback(false);
  1030. }
  1031. }
  1032. }
  1033. else if(hadFlash)
  1034. {
  1035. // Catch those cases where both the damage flash and white out are at zero
  1036. // on the server but we did not receive an exact zero packet due to
  1037. // precision over the network issues. No problem as the flag we just
  1038. // read (which is false if we're here) has also told us about the change.
  1039. onFlash_callback(false);
  1040. }
  1041. if ( bstream->readFlag() ) // gIndex != -1
  1042. {
  1043. if ( bstream->readFlag() ) // mMoveList->isMismatch() || mControlForceMismatch
  1044. {
  1045. // the control object is dirty...so we get an update:
  1046. bool callScript = false;
  1047. bool controlObjChange = false;
  1048. if(mControlObject.isNull())
  1049. callScript = true;
  1050. S32 gIndex = bstream->readInt(NetConnection::GhostIdBitSize);
  1051. GameBase* obj = dynamic_cast<GameBase*>(resolveGhost(gIndex));
  1052. if (mControlObject != obj)
  1053. {
  1054. setControlObject(obj);
  1055. controlObjChange = true;
  1056. }
  1057. #ifdef TORQUE_NET_STATS
  1058. U32 beginSize = bstream->getBitPosition();
  1059. #endif
  1060. obj->readPacketData(this, bstream);
  1061. #ifdef TORQUE_NET_STATS
  1062. obj->getClassRep()->updateNetStatReadData(bstream->getBitPosition() - beginSize);
  1063. #endif
  1064. // let move list know that control object is dirty
  1065. mMoveList->markControlDirty();
  1066. if(callScript)
  1067. {
  1068. initialControlSet_callback();
  1069. }
  1070. if(controlObjChange)
  1071. {
  1072. onControlObjectChange_callback();
  1073. }
  1074. }
  1075. else
  1076. {
  1077. // read out the compression point
  1078. Point3F pos;
  1079. bstream->read(&pos.x);
  1080. bstream->read(&pos.y);
  1081. bstream->read(&pos.z);
  1082. bstream->setCompressionPoint(pos);
  1083. }
  1084. }
  1085. if (bstream->readFlag())
  1086. {
  1087. bool callScript = false;
  1088. if (mCameraObject.isNull())
  1089. callScript = true;
  1090. S32 gIndex = bstream->readInt(NetConnection::GhostIdBitSize);
  1091. GameBase* obj = dynamic_cast<GameBase*>(resolveGhost(gIndex));
  1092. setCameraObject(obj);
  1093. obj->readPacketData(this, bstream);
  1094. if (callScript)
  1095. initialControlSet_callback();
  1096. }
  1097. else
  1098. setCameraObject(0);
  1099. // server changed control scheme
  1100. if(bstream->readFlag())
  1101. {
  1102. bool absoluteRotation = bstream->readFlag();
  1103. bool addYawToAbsRot = bstream->readFlag();
  1104. bool addPitchToAbsRot = bstream->readFlag();
  1105. setControlSchemeParameters(absoluteRotation, addYawToAbsRot, addPitchToAbsRot);
  1106. mUpdateControlScheme = false;
  1107. }
  1108. // server changed first person
  1109. if(bstream->readFlag())
  1110. {
  1111. setFirstPerson(bstream->readFlag());
  1112. mUpdateFirstPerson = false;
  1113. }
  1114. // server forcing a fov change?
  1115. if(bstream->readFlag())
  1116. {
  1117. S32 fov = bstream->readInt(8);
  1118. setControlCameraFov((F32)fov);
  1119. // don't bother telling the server if we were able to set the fov
  1120. F32 setFov;
  1121. if(getControlCameraFov(&setFov) && (S32(setFov) == fov))
  1122. mUpdateCameraFov = false;
  1123. // update the games fov info
  1124. smFovUpdate.trigger((F32)fov);
  1125. }
  1126. }
  1127. else
  1128. {
  1129. mMoveList->serverReadMovePacket(bstream);
  1130. mCameraPos = bstream->readFlag() ? 1.0f : 0.0f;
  1131. if (bstream->readFlag())
  1132. mControlForceMismatch = true;
  1133. // client changed control scheme
  1134. if(bstream->readFlag())
  1135. {
  1136. bool absoluteRotation = bstream->readFlag();
  1137. bool addYawToAbsRot = bstream->readFlag();
  1138. bool addPitchToAbsRot = bstream->readFlag();
  1139. setControlSchemeParameters(absoluteRotation, addYawToAbsRot, addPitchToAbsRot);
  1140. mUpdateControlScheme = false;
  1141. }
  1142. // client changed first person
  1143. if(bstream->readFlag())
  1144. {
  1145. setFirstPerson(bstream->readFlag());
  1146. mUpdateFirstPerson = false;
  1147. }
  1148. // check fov change.. 1degree granularity on server
  1149. if(bstream->readFlag())
  1150. {
  1151. S32 fov = mClamp(bstream->readInt(8), S32(MinCameraFov), S32(MaxCameraFov));
  1152. setControlCameraFov((F32)fov);
  1153. // may need to force client back to a valid fov
  1154. F32 setFov;
  1155. if(getControlCameraFov(&setFov) && (S32(setFov) == fov))
  1156. mUpdateCameraFov = false;
  1157. }
  1158. }
  1159. Parent::readPacket(bstream);
  1160. bstream->clearCompressionPoint();
  1161. bstream->clearStringBuffer();
  1162. if (isConnectionToServer())
  1163. {
  1164. PROFILE_START(ClientCatchup);
  1165. ClientProcessList::get()->clientCatchup(this);
  1166. PROFILE_END();
  1167. }
  1168. }
  1169. void GameConnection::writePacket(BitStream *bstream, PacketNotify *note)
  1170. {
  1171. bstream->clearCompressionPoint();
  1172. bstream->clearStringBuffer();
  1173. GamePacketNotify *gnote = (GamePacketNotify *) note;
  1174. U32 startPos = bstream->getBitPosition();
  1175. if (isConnectionToServer())
  1176. {
  1177. mMoveList->clientWriteMovePacket(bstream);
  1178. bstream->writeFlag(mCameraPos == 1);
  1179. // if we're recording, we want to make sure that we get periodic updates of the
  1180. // control object "just in case" - ie if the math copro is different between the
  1181. // recording machine (SIMD vs FPU), we get periodic corrections
  1182. bool forceUpdate = false;
  1183. if(isRecording())
  1184. {
  1185. U32 currentTime = Platform::getVirtualMilliseconds();
  1186. if(currentTime - mLastControlRequestTime > ControlRequestTime)
  1187. {
  1188. mLastControlRequestTime = currentTime;
  1189. forceUpdate=true;;
  1190. }
  1191. }
  1192. bstream->writeFlag(forceUpdate);
  1193. // Control scheme changed?
  1194. if(bstream->writeFlag(mUpdateControlScheme))
  1195. {
  1196. bstream->writeFlag(mAbsoluteRotation);
  1197. bstream->writeFlag(mAddYawToAbsRot);
  1198. bstream->writeFlag(mAddPitchToAbsRot);
  1199. mUpdateControlScheme = false;
  1200. }
  1201. // first person changed?
  1202. if(bstream->writeFlag(mUpdateFirstPerson))
  1203. {
  1204. bstream->writeFlag(mFirstPerson);
  1205. mUpdateFirstPerson = false;
  1206. }
  1207. // camera fov changed? (server fov resolution is 1 degree)
  1208. if(bstream->writeFlag(mUpdateCameraFov))
  1209. {
  1210. bstream->writeInt(mClamp(S32(mCameraFov), S32(MinCameraFov), S32(MaxCameraFov)), 8);
  1211. mUpdateCameraFov = false;
  1212. }
  1213. DEBUG_LOG(("PKLOG %d CLIENTMOVES: %d", getId(), bstream->getCurPos() - startPos));
  1214. }
  1215. else
  1216. {
  1217. mMoveList->serverWriteMovePacket(bstream);
  1218. // get the ghost index of the control object, and write out
  1219. // all the damage flash & white out
  1220. S32 gIndex = -1;
  1221. if (mChangedSelectedObj)
  1222. {
  1223. S32 gidx;
  1224. // send NULL player
  1225. if ((mSelectedObj == NULL) || mSelectedObj.isNull())
  1226. {
  1227. bstream->writeFlag(true);
  1228. bstream->writeFlag(false);
  1229. mChangedSelectedObj = false;
  1230. }
  1231. // send ghost-idx
  1232. else if ((gidx = getGhostIndex(mSelectedObj)) != -1)
  1233. {
  1234. Con::printf("SEND OBJECT SELECTION");
  1235. bstream->writeFlag(true);
  1236. bstream->writeFlag(true);
  1237. bstream->writeInt(gidx, NetConnection::GhostIdBitSize);
  1238. mChangedSelectedObj = false;
  1239. }
  1240. // not fully changed yet
  1241. else
  1242. {
  1243. bstream->writeFlag(false);
  1244. mChangedSelectedObj = true;
  1245. }
  1246. }
  1247. else
  1248. bstream->writeFlag(false);
  1249. if (!mControlObject.isNull())
  1250. {
  1251. gIndex = getGhostIndex(mControlObject);
  1252. F32 flash = mControlObject->getDamageFlash();
  1253. F32 whiteOut = mControlObject->getWhiteOut();
  1254. if(bstream->writeFlag(flash != 0 || whiteOut != 0))
  1255. {
  1256. if(bstream->writeFlag(flash != 0))
  1257. bstream->writeFloat(flash, 7);
  1258. if(bstream->writeFlag(whiteOut != 0))
  1259. bstream->writeFloat(whiteOut/1.5, 7);
  1260. }
  1261. }
  1262. else
  1263. bstream->writeFlag(false);
  1264. if (bstream->writeFlag(gIndex != -1))
  1265. {
  1266. // assume that the control object will write in a compression point
  1267. if(bstream->writeFlag(mMoveList->isMismatch() || mControlForceMismatch))
  1268. {
  1269. #ifdef TORQUE_DEBUG_NET
  1270. if (mMoveList->isMismatch())
  1271. Con::printf("packetDataChecksum disagree!");
  1272. else
  1273. Con::printf("packetDataChecksum disagree! (force)");
  1274. #endif
  1275. bstream->writeInt(gIndex, NetConnection::GhostIdBitSize);
  1276. #ifdef TORQUE_NET_STATS
  1277. U32 beginSize = bstream->getBitPosition();
  1278. #endif
  1279. mControlObject->writePacketData(this, bstream);
  1280. #ifdef TORQUE_NET_STATS
  1281. mControlObject->getClassRep()->updateNetStatWriteData(bstream->getBitPosition() - beginSize);
  1282. #endif
  1283. mControlForceMismatch = false;
  1284. }
  1285. else
  1286. {
  1287. // we'll have to use the control object's position as the compression point
  1288. // should make this lower res for better space usage:
  1289. Point3F coPos = mControlObject->getPosition();
  1290. bstream->write(coPos.x);
  1291. bstream->write(coPos.y);
  1292. bstream->write(coPos.z);
  1293. bstream->setCompressionPoint(coPos);
  1294. }
  1295. }
  1296. DEBUG_LOG(("PKLOG %d CONTROLOBJECTSTATE: %d", getId(), bstream->getCurPos() - startPos));
  1297. startPos = bstream->getBitPosition();
  1298. if (!mCameraObject.isNull() && mCameraObject != mControlObject)
  1299. {
  1300. gIndex = getGhostIndex(mCameraObject);
  1301. if (bstream->writeFlag(gIndex != -1))
  1302. {
  1303. bstream->writeInt(gIndex, NetConnection::GhostIdBitSize);
  1304. mCameraObject->writePacketData(this, bstream);
  1305. }
  1306. }
  1307. else
  1308. bstream->writeFlag( false );
  1309. // Control scheme changed?
  1310. if(bstream->writeFlag(mUpdateControlScheme))
  1311. {
  1312. bstream->writeFlag(mAbsoluteRotation);
  1313. bstream->writeFlag(mAddYawToAbsRot);
  1314. bstream->writeFlag(mAddPitchToAbsRot);
  1315. mUpdateControlScheme = false;
  1316. }
  1317. // first person changed?
  1318. if(bstream->writeFlag(mUpdateFirstPerson))
  1319. {
  1320. bstream->writeFlag(mFirstPerson);
  1321. mUpdateFirstPerson = false;
  1322. }
  1323. // server forcing client fov?
  1324. gnote->cameraFov = -1;
  1325. if(bstream->writeFlag(mUpdateCameraFov))
  1326. {
  1327. gnote->cameraFov = mClamp(S32(mCameraFov), S32(MinCameraFov), S32(MaxCameraFov));
  1328. bstream->writeInt(gnote->cameraFov, 8);
  1329. mUpdateCameraFov = false;
  1330. }
  1331. DEBUG_LOG(("PKLOG %d PINGCAMSTATE: %d", getId(), bstream->getCurPos() - startPos));
  1332. }
  1333. Parent::writePacket(bstream, note);
  1334. bstream->clearCompressionPoint();
  1335. bstream->clearStringBuffer();
  1336. }
  1337. void GameConnection::detectLag()
  1338. {
  1339. //see if we're lagging...
  1340. S32 curTime = Sim::getCurrentTime();
  1341. if (curTime - mLastPacketTime > mLagThresholdMS)
  1342. {
  1343. if (!mLagging)
  1344. {
  1345. mLagging = true;
  1346. setLagIcon_callback(true);
  1347. }
  1348. }
  1349. else if (mLagging)
  1350. {
  1351. mLagging = false;
  1352. setLagIcon_callback(false);
  1353. }
  1354. }
  1355. GameConnection::GamePacketNotify::GamePacketNotify()
  1356. {
  1357. // need to fill in empty notifes for demo start block
  1358. cameraFov = 0;
  1359. }
  1360. NetConnection::PacketNotify *GameConnection::allocNotify()
  1361. {
  1362. return new GamePacketNotify;
  1363. }
  1364. void GameConnection::packetReceived(PacketNotify *note)
  1365. {
  1366. //record the time so we can tell if we're lagging...
  1367. mLastPacketTime = Sim::getCurrentTime();
  1368. // If we wanted to do something special, we grab our note like this:
  1369. //GamePacketNotify *gnote = (GamePacketNotify *) note;
  1370. Parent::packetReceived(note);
  1371. }
  1372. void GameConnection::packetDropped(PacketNotify *note)
  1373. {
  1374. Parent::packetDropped(note);
  1375. GamePacketNotify *gnote = (GamePacketNotify *) note;
  1376. if(gnote->cameraFov != -1)
  1377. mUpdateCameraFov = true;
  1378. }
  1379. //----------------------------------------------------------------------------
  1380. void GameConnection::play2D(SFXProfile* profile)
  1381. {
  1382. postNetEvent(new Sim2DAudioEvent(profile));
  1383. }
  1384. void GameConnection::play3D(SFXProfile* profile, const MatrixF *transform)
  1385. {
  1386. if ( !transform )
  1387. play2D(profile);
  1388. else if ( !mControlObject )
  1389. postNetEvent(new Sim3DAudioEvent(profile,transform));
  1390. else
  1391. {
  1392. // TODO: Maybe improve this to account for the duration
  1393. // of the sound effect and if the control object can get
  1394. // into hearing range within time?
  1395. // Only post the event if it's within audible range
  1396. // of the control object.
  1397. Point3F ear,pos;
  1398. transform->getColumn(3,&pos);
  1399. mControlObject->getTransform().getColumn(3,&ear);
  1400. if ((ear - pos).len() < profile->getDescription()->mMaxDistance)
  1401. postNetEvent(new Sim3DAudioEvent(profile,transform));
  1402. }
  1403. }
  1404. void GameConnection::doneScopingScene()
  1405. {
  1406. // Could add special post-scene scoping here, such as scoping
  1407. // objects not visible to the camera, but visible to sensors.
  1408. }
  1409. void GameConnection::preloadDataBlock(SimDataBlock *db)
  1410. {
  1411. mDataBlockLoadList.push_back(db);
  1412. if(mDataBlockLoadList.size() == 1)
  1413. preloadNextDataBlock(false);
  1414. }
  1415. void GameConnection::fileDownloadSegmentComplete()
  1416. {
  1417. // this is called when a the file list has finished processing...
  1418. // at this point we can try again to add the object
  1419. // subclasses can override this to do, for example, datablock redos.
  1420. if(mDataBlockLoadList.size())
  1421. preloadNextDataBlock(mNumDownloadedFiles != 0);
  1422. Parent::fileDownloadSegmentComplete();
  1423. }
  1424. void GameConnection::preloadNextDataBlock(bool hadNewFiles)
  1425. {
  1426. if(!mDataBlockLoadList.size())
  1427. return;
  1428. while(mDataBlockLoadList.size())
  1429. {
  1430. // only check for new files if this is the first load, or if new
  1431. // files were downloaded from the server.
  1432. // if(hadNewFiles)
  1433. // gResourceManager->setMissingFileLogging(true);
  1434. // gResourceManager->clearMissingFileList();
  1435. SimDataBlock *object = mDataBlockLoadList[0];
  1436. if(!object)
  1437. {
  1438. // a null object is used to signify that the last ghost in the list is down
  1439. mDataBlockLoadList.pop_front();
  1440. AssertFatal(mDataBlockLoadList.size() == 0, "Error! Datablock save list should be empty!");
  1441. sendConnectionMessage(DataBlocksDownloadDone, mDataBlockSequence);
  1442. // gResourceManager->setMissingFileLogging(false);
  1443. #ifdef AFX_CAP_DATABLOCK_CACHE
  1444. // This should be the last of the datablocks. An argument of false
  1445. // indicates that this is a client save.
  1446. if (clientCacheEnabled())
  1447. saveDatablockCache(false);
  1448. #endif
  1449. return;
  1450. }
  1451. mFilesWereDownloaded = hadNewFiles;
  1452. if(!object->preload(false, mErrorBuffer))
  1453. {
  1454. mFilesWereDownloaded = false;
  1455. // make sure there's an error message if necessary
  1456. if(mErrorBuffer.isEmpty())
  1457. setLastError("Invalid packet. (object preload)");
  1458. // if there were new files, make sure the error message
  1459. // is the one from the last time we tried to add this object
  1460. if(hadNewFiles)
  1461. {
  1462. mErrorBuffer = mLastFileErrorBuffer;
  1463. // gResourceManager->setMissingFileLogging(false);
  1464. return;
  1465. }
  1466. // object failed to load, let's see if it had any missing files
  1467. if(isLocalConnection() /*|| !gResourceManager->getMissingFileList(mMissingFileList)*/)
  1468. {
  1469. // no missing files, must be an error
  1470. // connection will automagically delete the ghost always list
  1471. // when this error is reported.
  1472. // gResourceManager->setMissingFileLogging(false);
  1473. return;
  1474. }
  1475. // ok, copy the error buffer out to a scratch pad for now
  1476. mLastFileErrorBuffer = mErrorBuffer;
  1477. //mErrorBuffer = String();
  1478. // request the missing files...
  1479. mNumDownloadedFiles = 0;
  1480. sendNextFileDownloadRequest();
  1481. break;
  1482. }
  1483. mFilesWereDownloaded = false;
  1484. // gResourceManager->setMissingFileLogging(false);
  1485. mDataBlockLoadList.pop_front();
  1486. hadNewFiles = true;
  1487. }
  1488. }
  1489. void GameConnection::onEndGhosting()
  1490. {
  1491. Parent::onEndGhosting();
  1492. // Reset move list. All the moves are obsolete now and furthermore,
  1493. // if we don't clear out the list now we might run in danger of
  1494. // getting backlogged later on what is a list full of obsolete moves.
  1495. mMoveList->reset();
  1496. }
  1497. //----------------------------------------------------------------------------
  1498. //localconnection only blackout functions
  1499. void GameConnection::setBlackOut(bool fadeToBlack, S32 timeMS)
  1500. {
  1501. mFadeToBlack = fadeToBlack;
  1502. mBlackOutStartTimeMS = Sim::getCurrentTime();
  1503. mBlackOutTimeMS = timeMS;
  1504. //if timeMS <= 0 set the value instantly
  1505. if (mBlackOutTimeMS <= 0)
  1506. mBlackOut = (mFadeToBlack ? 1.0f : 0.0f);
  1507. }
  1508. F32 GameConnection::getBlackOut()
  1509. {
  1510. S32 curTime = Sim::getCurrentTime();
  1511. //see if we're in the middle of a black out
  1512. if (curTime < mBlackOutStartTimeMS + mBlackOutTimeMS)
  1513. {
  1514. S32 elapsedTime = curTime - mBlackOutStartTimeMS;
  1515. F32 timePercent = F32(elapsedTime) / F32(mBlackOutTimeMS);
  1516. mBlackOut = (mFadeToBlack ? timePercent : 1.0f - timePercent);
  1517. }
  1518. else
  1519. mBlackOut = (mFadeToBlack ? 1.0f : 0.0f);
  1520. //return the blackout time
  1521. return mBlackOut;
  1522. }
  1523. void GameConnection::handleConnectionMessage(U32 message, U32 sequence, U32 ghostCount)
  1524. {
  1525. if(isConnectionToServer())
  1526. {
  1527. if(message == DataBlocksDone)
  1528. {
  1529. mDataBlockLoadList.push_back(NULL);
  1530. mDataBlockSequence = sequence;
  1531. if(mDataBlockLoadList.size() == 1)
  1532. preloadNextDataBlock(true);
  1533. }
  1534. }
  1535. else
  1536. {
  1537. if(message == DataBlocksDownloadDone)
  1538. {
  1539. if(getDataBlockSequence() == sequence)
  1540. {
  1541. onDataBlocksDone_callback( getDataBlockSequence() );
  1542. }
  1543. }
  1544. }
  1545. Parent::handleConnectionMessage(message, sequence, ghostCount);
  1546. }
  1547. //----------------------------------------------------------------------------
  1548. DefineEngineMethod( GameConnection, transmitDataBlocks, void, (S32 sequence),,
  1549. "@brief Sent by the server during phase 1 of the mission download to send the datablocks to the client.\n\n"
  1550. "SimDataBlocks, also known as just datablocks, need to be transmitted to the client "
  1551. "prior to the client entering the game world. These represent the static data that "
  1552. "most objects in the world reference. This is typically done during the standard "
  1553. "mission start phase 1 when following Torque's example mission startup sequence.\n\n"
  1554. "When the datablocks have all been transmitted, onDataBlocksDone() is called to move "
  1555. "the mission start process to the next phase."
  1556. "@param sequence The sequence is common between the server and client and ensures "
  1557. "that the client is acting on the most recent mission start process. If an errant "
  1558. "network packet (one that was lost but has now been found) is received by the client "
  1559. "with an incorrect sequence, it is just ignored. This sequence number is updated on "
  1560. "the server every time a mission is loaded.\n\n"
  1561. "@tsexample\n"
  1562. "function serverCmdMissionStartPhase1Ack(%client, %seq)\n"
  1563. "{\n"
  1564. " // Make sure to ignore calls from a previous mission load\n"
  1565. " if (%seq != $missionSequence || !$MissionRunning)\n"
  1566. " return;\n"
  1567. " if (%client.currentPhase != 0)\n"
  1568. " return;\n"
  1569. " %client.currentPhase = 1;\n"
  1570. "\n"
  1571. " // Start with the CRC\n"
  1572. " %client.setMissionCRC( $missionCRC );\n"
  1573. "\n"
  1574. " // Send over the datablocks...\n"
  1575. " // OnDataBlocksDone will get called when have confirmation\n"
  1576. " // that they've all been received.\n"
  1577. " %client.transmitDataBlocks($missionSequence);\n"
  1578. "}\n"
  1579. "@endtsexample\n\n"
  1580. "@see GameConnection::onDataBlocksDone()\n\n")
  1581. {
  1582. // Set the datablock sequence.
  1583. object->setDataBlockSequence(sequence);
  1584. // Store a pointer to the datablock group.
  1585. SimDataBlockGroup* pGroup = Sim::getDataBlockGroup();
  1586. // Determine the size of the datablock group.
  1587. const U32 iCount = pGroup->size();
  1588. // If this is the local client...
  1589. #ifdef AFX_CAP_DATABLOCK_CACHE
  1590. if (GameConnection::getLocalClientConnection() == object && !GameConnection::serverCacheEnabled())
  1591. #else
  1592. if (GameConnection::getLocalClientConnection() == object)
  1593. #endif
  1594. {
  1595. // Set up a pointer to the datablock.
  1596. SimDataBlock* pDataBlock = 0;
  1597. // Set up a buffer for the datablock send.
  1598. U8 iBuffer[16384];
  1599. BitStream mStream(iBuffer, 16384);
  1600. // Iterate through all the datablocks...
  1601. for (U32 i = 0; i < iCount; i++)
  1602. {
  1603. // Get a pointer to the datablock in question...
  1604. pDataBlock = (SimDataBlock*)(*pGroup)[i];
  1605. // Set the client's new modified key.
  1606. object->setMaxDataBlockModifiedKey(pDataBlock->getModifiedKey());
  1607. // Pack the datablock stream.
  1608. mStream.setPosition(0);
  1609. mStream.clearCompressionPoint();
  1610. pDataBlock->packData(&mStream);
  1611. // Unpack the datablock stream.
  1612. mStream.setPosition(0);
  1613. mStream.clearCompressionPoint();
  1614. pDataBlock->unpackData(&mStream);
  1615. // Call the console function to set the number of blocks to be sent.
  1616. onDataBlockObjectReceived_callback(i, iCount);
  1617. // Preload the datablock on the dummy client.
  1618. pDataBlock->preload(false, NetConnection::getErrorBuffer());
  1619. }
  1620. // Get the last datablock (if any)...
  1621. if (pDataBlock)
  1622. {
  1623. // Ensure the datablock modified key is set.
  1624. object->setDataBlockModifiedKey(object->getMaxDataBlockModifiedKey());
  1625. // Ensure that the client knows that the datablock send is done...
  1626. object->sendConnectionMessage(GameConnection::DataBlocksDone, object->getDataBlockSequence());
  1627. }
  1628. if (iCount == 0)
  1629. {
  1630. //if we have no datablocks to send, we still need to be able to complete the level load process
  1631. //so fire off our callback anyways
  1632. object->sendConnectionMessage(GameConnection::DataBlocksDone, object->getDataBlockSequence());
  1633. }
  1634. }
  1635. else
  1636. {
  1637. // Otherwise, store the current datablock modified key.
  1638. const S32 iKey = object->getDataBlockModifiedKey();
  1639. // Iterate through the datablock group...
  1640. U32 i = 0;
  1641. for (; i < iCount; i++)
  1642. {
  1643. // If the datablock's modified key has already been set, break out of the loop...
  1644. if (((SimDataBlock*)(*pGroup)[i])->getModifiedKey() > iKey)
  1645. {
  1646. break;
  1647. }
  1648. }
  1649. // If this is the last datablock in the group...
  1650. if (i == iCount)
  1651. {
  1652. // Ensure that the client knows that the datablock send is done...
  1653. object->sendConnectionMessage(GameConnection::DataBlocksDone, object->getDataBlockSequence());
  1654. // Then exit out since nothing else needs to be done.
  1655. return;
  1656. }
  1657. // Set the maximum datablock modified key value.
  1658. object->setMaxDataBlockModifiedKey(iKey);
  1659. // Get the minimum number of datablocks...
  1660. const U32 iMax = getMin(i + DataBlockQueueCount, iCount);
  1661. // Iterate through the remaining datablocks...
  1662. for (;i < iMax; i++)
  1663. {
  1664. // Get a pointer to the datablock in question...
  1665. SimDataBlock* pDataBlock = (SimDataBlock*)(*pGroup)[i];
  1666. // Post the datablock event to the client.
  1667. object->postNetEvent(new SimDataBlockEvent(pDataBlock, i, iCount, object->getDataBlockSequence()));
  1668. }
  1669. }
  1670. }
  1671. DefineEngineMethod( GameConnection, activateGhosting, void, (),,
  1672. "@brief Called by the server during phase 2 of the mission download to start sending ghosts to the client.\n\n"
  1673. "Ghosts represent objects on the server that are in scope for the client. These need "
  1674. "to be synchronized with the client in order for the client to see and interact with them. "
  1675. "This is typically done during the standard mission start phase 2 when following Torque's "
  1676. "example mission startup sequence.\n\n"
  1677. "@tsexample\n"
  1678. "function serverCmdMissionStartPhase2Ack(%client, %seq, %playerDB)\n"
  1679. "{\n"
  1680. " // Make sure to ignore calls from a previous mission load\n"
  1681. " if (%seq != $missionSequence || !$MissionRunning)\n"
  1682. " return;\n"
  1683. " if (%client.currentPhase != 1.5)\n"
  1684. " return;\n"
  1685. " %client.currentPhase = 2;\n"
  1686. "\n"
  1687. " // Set the player datablock choice\n"
  1688. " %client.playerDB = %playerDB;\n"
  1689. "\n"
  1690. " // Update mod paths, this needs to get there before the objects.\n"
  1691. " %client.transmitPaths();\n"
  1692. "\n"
  1693. " // Start ghosting objects to the client\n"
  1694. " %client.activateGhosting();\n"
  1695. "}\n"
  1696. "@endtsexample\n\n"
  1697. "@see @ref ghosting_scoping for a description of the ghosting system.\n\n")
  1698. {
  1699. object->activateGhosting();
  1700. }
  1701. DefineEngineMethod( GameConnection, resetGhosting, void, (),,
  1702. "@brief On the server, resets the connection to indicate that ghosting has been disabled.\n\n"
  1703. "Typically when a mission has ended on the server, all connected clients are informed of this change "
  1704. "and their connections are reset back to a starting state. This method resets a connection on the "
  1705. "server to indicate that ghosts are no longer being transmitted. On the client end, all ghost "
  1706. "information will be deleted.\n\n"
  1707. "@tsexample\n"
  1708. " // Inform the clients\n"
  1709. " for (%clientIndex = 0; %clientIndex < ClientGroup.getCount(); %clientIndex++)\n"
  1710. " {\n"
  1711. " // clear ghosts and paths from all clients\n"
  1712. " %cl = ClientGroup.getObject(%clientIndex);\n"
  1713. " %cl.endMission();\n"
  1714. " %cl.resetGhosting();\n"
  1715. " %cl.clearPaths();\n"
  1716. " }\n"
  1717. "@endtsexample\n\n"
  1718. "@see @ref ghosting_scoping for a description of the ghosting system.\n\n")
  1719. {
  1720. object->resetGhosting();
  1721. }
  1722. DefineEngineMethod( GameConnection, setControlObject, bool, (GameBase* ctrlObj),,
  1723. "@brief On the server, sets the object that the client will control.\n\n"
  1724. "By default the control object is an instance of the Player class, but can also be an instance "
  1725. "of Camera (when editing the mission, for example), or any other ShapeBase derived class as "
  1726. "appropriate for the game.\n\n"
  1727. "@param ctrlObj The GameBase object on the server to control.")
  1728. {
  1729. if(!ctrlObj)
  1730. return false;
  1731. object->setControlObject(ctrlObj);
  1732. return true;
  1733. }
  1734. DefineEngineMethod( GameConnection, clearDisplayDevice, void, (),,
  1735. "@brief Clear any display device.\n\n"
  1736. "A display device may define a number of properties that are used during rendering.\n\n")
  1737. {
  1738. object->clearDisplayDevice();
  1739. }
  1740. DefineEngineMethod( GameConnection, getControlObject, GameBase*, (),,
  1741. "@brief On the server, returns the object that the client is controlling."
  1742. "By default the control object is an instance of the Player class, but can also be an instance "
  1743. "of Camera (when editing the mission, for example), or any other ShapeBase derived class as "
  1744. "appropriate for the game.\n\n"
  1745. "@see GameConnection::setControlObject()\n\n")
  1746. {
  1747. return object->getControlObject();
  1748. }
  1749. DefineEngineMethod( GameConnection, isAIControlled, bool, (),,
  1750. "@brief Returns true if this connection is AI controlled.\n\n"
  1751. "@see AIConnection")
  1752. {
  1753. return object->isAIControlled();
  1754. }
  1755. DefineEngineMethod( GameConnection, isControlObjectRotDampedCamera, bool, (),,
  1756. "@brief Returns true if the object being controlled by the client is making use "
  1757. "of a rotation damped camera.\n\n"
  1758. "@see Camera")
  1759. {
  1760. return object->isControlObjectRotDampedCamera();
  1761. }
  1762. DefineEngineMethod( GameConnection, play2D, bool, (SFXProfile* profile),,
  1763. "@brief Used on the server to play a 2D sound that is not attached to any object.\n\n"
  1764. "@param profile The SFXProfile that defines the sound to play.\n\n"
  1765. "@tsexample\n"
  1766. "function ServerPlay2D(%profile)\n"
  1767. "{\n"
  1768. " // Play the given sound profile on every client.\n"
  1769. " // The sounds will be transmitted as an event, not attached to any object.\n"
  1770. " for(%idx = 0; %idx < ClientGroup.getCount(); %idx++)\n"
  1771. " ClientGroup.getObject(%idx).play2D(%profile);\n"
  1772. "}\n"
  1773. "@endtsexample\n\n")
  1774. {
  1775. if(!profile)
  1776. return false;
  1777. object->play2D(profile);
  1778. return true;
  1779. }
  1780. DefineEngineMethod( GameConnection, play3D, bool, (SFXProfile* profile, TransformF location),,
  1781. "@brief Used on the server to play a 3D sound that is not attached to any object.\n\n"
  1782. "@param profile The SFXProfile that defines the sound to play.\n"
  1783. "@param location The position and orientation of the 3D sound given in the form of \"x y z ax ay az aa\".\n\n"
  1784. "@tsexample\n"
  1785. "function ServerPlay3D(%profile,%transform)\n"
  1786. "{\n"
  1787. " // Play the given sound profile at the given position on every client\n"
  1788. " // The sound will be transmitted as an event, not attached to any object.\n"
  1789. " for(%idx = 0; %idx < ClientGroup.getCount(); %idx++)\n"
  1790. " ClientGroup.getObject(%idx).play3D(%profile,%transform);\n"
  1791. "}\n"
  1792. "@endtsexample\n\n")
  1793. {
  1794. if(!profile)
  1795. return false;
  1796. MatrixF mat = location.getMatrix();
  1797. object->play3D(profile,&mat);
  1798. return true;
  1799. }
  1800. DefineEngineMethod( GameConnection, chaseCam, bool, (S32 size),,
  1801. "@brief Sets the size of the chase camera's matrix queue.\n\n"
  1802. "@note This sets the queue size across all GameConnections.\n\n"
  1803. "@note This is not currently hooked up.\n\n")
  1804. {
  1805. if (size != sChaseQueueSize)
  1806. {
  1807. SAFE_DELETE_ARRAY(sChaseQueue);
  1808. sChaseQueueSize = size;
  1809. sChaseQueueHead = sChaseQueueTail = 0;
  1810. if (size)
  1811. {
  1812. sChaseQueue = new MatrixF[size];
  1813. return true;
  1814. }
  1815. }
  1816. return false;
  1817. }
  1818. DefineEngineMethod( GameConnection, getControlCameraDefaultFov, F32, (),,
  1819. "@brief Returns the default field of view as used by the control object's camera.\n\n")
  1820. {
  1821. F32 fov = 0.0f;
  1822. if(!object->getControlCameraDefaultFov(&fov))
  1823. return(0.0f);
  1824. return(fov);
  1825. }
  1826. DefineEngineMethod( GameConnection, setControlCameraFov, void, (F32 newFOV),,
  1827. "@brief On the server, sets the control object's camera's field of view.\n\n"
  1828. "@param newFOV New field of view (in degrees) to force the control object's camera to use. This value "
  1829. "is clamped to be within the range of 1 to 179 degrees.\n\n"
  1830. "@note When transmitted over the network to the client, the resolution is limited to "
  1831. "one degree. Any fraction is dropped.")
  1832. {
  1833. object->setControlCameraFov(newFOV);
  1834. }
  1835. DefineEngineMethod( GameConnection, getControlCameraFov, F32, (),,
  1836. "@brief Returns the field of view as used by the control object's camera.\n\n")
  1837. {
  1838. F32 fov = 0.0f;
  1839. if(!object->getControlCameraFov(&fov))
  1840. return(0.0f);
  1841. return(fov);
  1842. }
  1843. DefineEngineMethod( GameConnection, getDamageFlash, F32, (),,
  1844. "@brief On the client, get the control object's damage flash level.\n\n"
  1845. "@return flash level\n")
  1846. {
  1847. return object->getDamageFlash();
  1848. }
  1849. DefineEngineMethod( GameConnection, getWhiteOut, F32, (),,
  1850. "@brief On the client, get the control object's white-out level.\n\n"
  1851. "@return white-out level\n")
  1852. {
  1853. return object->getWhiteOut();
  1854. }
  1855. DefineEngineMethod( GameConnection, setBlackOut, void, (bool doFade, S32 timeMS),,
  1856. "@brief On the server, sets the client's 3D display to fade to black.\n\n"
  1857. "@param doFade Set to true to fade to black, and false to fade from black.\n"
  1858. "@param timeMS Time it takes to perform the fade as measured in ms.\n\n"
  1859. "@note Not currently hooked up, and is not synchronized over the network.")
  1860. {
  1861. object->setBlackOut(doFade, timeMS);
  1862. }
  1863. DefineEngineMethod( GameConnection, setMissionCRC, void, (S32 CRC),,
  1864. "@brief On the server, transmits the mission file's CRC value to the client.\n\n"
  1865. "Typically, during the standard mission start phase 1, the mission file's CRC value "
  1866. "on the server is send to the client. This allows the client to determine if the mission "
  1867. "has changed since the last time it downloaded this mission and act appropriately, such as "
  1868. "rebuilt cached lightmaps.\n\n"
  1869. "@param CRC The mission file's CRC value on the server.\n\n"
  1870. "@tsexample\n"
  1871. "function serverCmdMissionStartPhase1Ack(%client, %seq)\n"
  1872. "{\n"
  1873. " // Make sure to ignore calls from a previous mission load\n"
  1874. " if (%seq != $missionSequence || !$MissionRunning)\n"
  1875. " return;\n"
  1876. " if (%client.currentPhase != 0)\n"
  1877. " return;\n"
  1878. " %client.currentPhase = 1;\n"
  1879. "\n"
  1880. " // Start with the CRC\n"
  1881. " %client.setMissionCRC( $missionCRC );\n"
  1882. "\n"
  1883. " // Send over the datablocks...\n"
  1884. " // OnDataBlocksDone will get called when have confirmation\n"
  1885. " // that they've all been received.\n"
  1886. " %client.transmitDataBlocks($missionSequence);\n"
  1887. "}\n"
  1888. "@endtsexample\n\n")
  1889. {
  1890. if(object->isConnectionToServer())
  1891. return;
  1892. object->postNetEvent(new SetMissionCRCEvent(CRC));
  1893. }
  1894. DefineEngineMethod( GameConnection, delete, void, (const char* reason), (""),
  1895. "@brief On the server, disconnect a client and pass along an optional reason why.\n\n"
  1896. "This method performs two operations: it disconnects a client connection from the server, "
  1897. "and it deletes the connection object. The optional reason is sent in the disconnect packet "
  1898. "and is often displayed to the user so they know why they've been disconnected.\n\n"
  1899. "@param reason [optional] The reason why the user has been disconnected from the server.\n\n"
  1900. "@tsexample\n"
  1901. "function kick(%client)\n"
  1902. "{\n"
  1903. " messageAll( 'MsgAdminForce', '\\c2The Admin has kicked %1.', %client.playerName);\n"
  1904. "\n"
  1905. " if (!%client.isAIControlled())\n"
  1906. " BanList::add(%client.guid, %client.getAddress(), $Pref::Server::KickBanTime);\n"
  1907. " %client.delete(\"You have been kicked from this server\");\n"
  1908. "}\n"
  1909. "@endtsexample\n\n")
  1910. {
  1911. object->setDisconnectReason(reason);
  1912. object->deleteObject();
  1913. }
  1914. //--------------------------------------------------------------------------
  1915. void GameConnection::consoleInit()
  1916. {
  1917. Con::addVariable("$pref::Net::LagThreshold", TypeS32, &mLagThresholdMS,
  1918. "@brief How long between received packets before the client is considered as lagging (in ms).\n\n"
  1919. "This is used by GameConnection to determine if the client is lagging. "
  1920. "If the client is indeed lagging, setLagIcon() is called to inform the user in some way. i.e. "
  1921. "display an icon on screen.\n\n"
  1922. "@see GameConnection, GameConnection::setLagIcon()\n\n"
  1923. "@ingroup Networking\n");
  1924. // Con::addVariable("specialFog", TypeBool, &SceneGraph::useSpecial);
  1925. #ifdef AFX_CAP_DATABLOCK_CACHE
  1926. Con::addVariable("$Pref::Server::DatablockCacheFilename", TypeString, &server_cache_filename);
  1927. Con::addVariable("$pref::Client::DatablockCacheFilename", TypeString, &client_cache_filename);
  1928. Con::addVariable("$Pref::Server::EnableDatablockCache", TypeBool, &server_cache_on);
  1929. Con::addVariable("$pref::Client::EnableDatablockCache", TypeBool, &client_cache_on);
  1930. #endif
  1931. }
  1932. DefineEngineMethod( GameConnection, startRecording, void, (const char* fileName),,
  1933. "@brief On the client, starts recording the network connection's traffic to a demo file.\n\n"
  1934. "It is often useful to play back a game session. This could be for producing a "
  1935. "demo of the game that will be shown at a later time, or for debugging a game. "
  1936. "By recording the entire network stream it is possible to later play game the game "
  1937. "exactly as it unfolded during the actual play session. This is because all user "
  1938. "control and server results pass through the connection.\n\n"
  1939. "@param fileName The file name to use for the demo recording.\n\n"
  1940. "@see GameConnection::stopRecording(), GameConnection::playDemo()")
  1941. {
  1942. char expFileName[1024];
  1943. Con::expandScriptFilename(expFileName, sizeof(expFileName), fileName);
  1944. object->startDemoRecord(expFileName);
  1945. }
  1946. DefineEngineMethod( GameConnection, stopRecording, void, (),,
  1947. "@brief On the client, stops the recording of a connection's network traffic to a file.\n\n"
  1948. "@see GameConnection::startRecording(), GameConnection::playDemo()")
  1949. {
  1950. object->stopRecording();
  1951. }
  1952. DefineEngineMethod( GameConnection, playDemo, bool, (const char* demoFileName),,
  1953. "@brief On the client, play back a previously recorded game session.\n\n"
  1954. "It is often useful to play back a game session. This could be for producing a "
  1955. "demo of the game that will be shown at a later time, or for debugging a game. "
  1956. "By recording the entire network stream it is possible to later play game the game "
  1957. "exactly as it unfolded during the actual play session. This is because all user "
  1958. "control and server results pass through the connection.\n\n"
  1959. "@returns True if the playback was successful. False if there was an issue, such as "
  1960. "not being able to open the demo file for playback.\n\n"
  1961. "@see GameConnection::startRecording(), GameConnection::stopRecording()")
  1962. {
  1963. char filename[1024];
  1964. Con::expandScriptFilename(filename, sizeof(filename), demoFileName);
  1965. // Note that calling onConnectionEstablished will change the values in argv!
  1966. object->onConnectionEstablished(true);
  1967. object->setEstablished();
  1968. if(!object->replayDemoRecord(filename))
  1969. {
  1970. Con::printf("Unable to open demo file %s.", filename);
  1971. object->deleteObject();
  1972. return false;
  1973. }
  1974. // After demo has loaded, execute the scene re-light the scene
  1975. //SceneLighting::lightScene(0, 0);
  1976. GameConnection::smPlayingDemo.trigger();
  1977. return true;
  1978. }
  1979. DefineEngineMethod( GameConnection, isDemoPlaying, bool, (),,
  1980. "@brief Returns true if a previously recorded demo file is now playing.\n\n"
  1981. "@see GameConnection::playDemo()")
  1982. {
  1983. return object->isPlayingBack();
  1984. }
  1985. DefineEngineMethod( GameConnection, isDemoRecording, bool, (),,
  1986. "@brief Returns true if a demo file is now being recorded.\n\n"
  1987. "@see GameConnection::startRecording(), GameConnection::stopRecording()")
  1988. {
  1989. return object->isRecording();
  1990. }
  1991. DefineEngineMethod( GameConnection, listClassIDs, void, (),,
  1992. "@brief List all of the classes that this connection knows about, and what their IDs are. Useful for debugging network problems.\n\n"
  1993. "@note The list is sent to the console.\n\n")
  1994. {
  1995. Con::printf("--------------- Class ID Listing ----------------");
  1996. Con::printf(" id | name");
  1997. for(AbstractClassRep *rep = AbstractClassRep::getClassList();
  1998. rep;
  1999. rep = rep->getNextClass())
  2000. {
  2001. ConsoleObject *obj = rep->create();
  2002. if(obj && rep->getClassId(object->getNetClassGroup()) >= 0)
  2003. Con::printf("%7.7d| %s", rep->getClassId(object->getNetClassGroup()), rep->getClassName());
  2004. delete obj;
  2005. }
  2006. }
  2007. DefineEngineStaticMethod( GameConnection, getServerConnection, S32, (),,
  2008. "@brief On the client, this static mehtod will return the connection to the server, if any.\n\n"
  2009. "@returns The SimObject ID of the server connection, or -1 if none is found.\n\n")
  2010. {
  2011. if(GameConnection::getConnectionToServer())
  2012. return GameConnection::getConnectionToServer()->getId();
  2013. else
  2014. {
  2015. Con::errorf("GameConnection::getServerConnection - no connection available.");
  2016. return -1;
  2017. }
  2018. }
  2019. DefineEngineMethod( GameConnection, setCameraObject, bool, (GameBase* camera),,
  2020. "@brief On the server, set the connection's camera object used when not viewing "
  2021. "through the control object.\n\n"
  2022. "@see GameConnection::getCameraObject() and GameConnection::clearCameraObject()\n\n")
  2023. {
  2024. if(!camera)
  2025. return false;
  2026. object->setCameraObject(camera);
  2027. return true;
  2028. }
  2029. DefineEngineMethod( GameConnection, getCameraObject, SimObject*, (),,
  2030. "@brief Returns the connection's camera object used when not viewing through the control object.\n\n"
  2031. "@see GameConnection::setCameraObject() and GameConnection::clearCameraObject()\n\n")
  2032. {
  2033. SimObject *obj = dynamic_cast<SimObject*>(object->getCameraObject());
  2034. return obj;
  2035. }
  2036. DefineEngineMethod( GameConnection, clearCameraObject, void, (),,
  2037. "@brief Clear the connection's camera object reference.\n\n"
  2038. "@see GameConnection::setCameraObject() and GameConnection::getCameraObject()\n\n")
  2039. {
  2040. object->setCameraObject(NULL);
  2041. }
  2042. DefineEngineMethod( GameConnection, isFirstPerson, bool, (),,
  2043. "@brief Returns true if this connection is in first person mode.\n\n"
  2044. "@note Transition to first person occurs over time via mCameraPos, so this "
  2045. "won't immediately return true after a set.\n\n")
  2046. {
  2047. // Note: Transition to first person occurs over time via mCameraPos, so this
  2048. // won't immediately return true after a set.
  2049. return object->isFirstPerson();
  2050. }
  2051. DefineEngineMethod( GameConnection, setFirstPerson, void, (bool firstPerson),,
  2052. "@brief On the server, sets this connection into or out of first person mode.\n\n"
  2053. "@param firstPerson Set to true to put the connection into first person mode.\n\n")
  2054. {
  2055. object->setFirstPerson(firstPerson);
  2056. }
  2057. DefineEngineMethod( GameConnection, setControlSchemeParameters, void, (bool absoluteRotation, bool addYawToAbsRot, bool addPitchToAbsRot),,
  2058. "@brief Set the control scheme that may be used by a connection's control object.\n\n"
  2059. "@param absoluteRotation Use absolute rotation values from client, likely through ExtendedMove.\n"
  2060. "@param addYawToAbsRot Add relative yaw control to the absolute rotation calculation. Only useful when absoluteRotation is true.\n\n" )
  2061. {
  2062. object->setControlSchemeParameters(absoluteRotation, addYawToAbsRot, addPitchToAbsRot);
  2063. }
  2064. DefineEngineMethod( GameConnection, getControlSchemeAbsoluteRotation, bool, (),,
  2065. "@brief Get the connection's control scheme absolute rotation property.\n\n"
  2066. "@return True if the connection's control object should use an absolute rotation control scheme.\n\n"
  2067. "@see GameConnection::setControlSchemeParameters()\n\n")
  2068. {
  2069. return object->getControlSchemeAbsoluteRotation();
  2070. }
  2071. DefineEngineMethod( GameConnection, setVisibleGhostDistance, void, (F32 dist),,
  2072. "@brief Sets the distance that objects around it will be ghosted. If set to 0, "
  2073. "it may be defined by the LevelInfo.\n\n"
  2074. "@dist - is the max distance\n\n"
  2075. )
  2076. {
  2077. object->setVisibleGhostDistance(dist);
  2078. }
  2079. DefineEngineMethod( GameConnection, getVisibleGhostDistance, F32, (),,
  2080. "@brief Gets the distance that objects around the connection will be ghosted.\n\n"
  2081. "@return S32 of distance.\n\n"
  2082. )
  2083. {
  2084. return object->getVisibleGhostDistance();
  2085. }
  2086. // The object selection code here is, in part, based, on functionality described
  2087. // in the following resource:
  2088. // Object Selection in Torque by Dave Myers
  2089. // http://www.garagegames.com/index.php?sec=mg&mod=resource&page=view&qid=7335
  2090. ConsoleMethod(GameConnection, setSelectedObj, bool, 3, 4, "(object, [propagate_to_client])")
  2091. {
  2092. SceneObject* pending_selection;
  2093. if (!Sim::findObject(argv[2], pending_selection))
  2094. return false;
  2095. bool propagate_to_client = (argc > 3) ? dAtob(argv[3]) : false;
  2096. object->setSelectedObj(pending_selection, propagate_to_client);
  2097. return true;
  2098. }
  2099. ConsoleMethod(GameConnection, getSelectedObj, S32, 2, 2, "()")
  2100. {
  2101. SimObject* selected = object->getSelectedObj();
  2102. return (selected) ? selected->getId(): -1;
  2103. }
  2104. ConsoleMethod(GameConnection, clearSelectedObj, void, 2, 3, "([propagate_to_client])")
  2105. {
  2106. bool propagate_to_client = (argc > 2) ? dAtob(argv[2]) : false;
  2107. object->setSelectedObj(NULL, propagate_to_client);
  2108. }
  2109. ConsoleMethod(GameConnection, setPreSelectedObjFromRollover, void, 2, 2, "()")
  2110. {
  2111. object->setPreSelectedObjFromRollover();
  2112. }
  2113. ConsoleMethod(GameConnection, clearPreSelectedObj, void, 2, 2, "()")
  2114. {
  2115. object->clearPreSelectedObj();
  2116. }
  2117. ConsoleMethod(GameConnection, setSelectedObjFromPreSelected, void, 2, 2, "()")
  2118. {
  2119. object->setSelectedObjFromPreSelected();
  2120. }
  2121. void GameConnection::setSelectedObj(SceneObject* so, bool propagate_to_client)
  2122. {
  2123. if (!isConnectionToServer())
  2124. {
  2125. // clear previously selected object
  2126. if (mSelectedObj)
  2127. clearNotify(mSelectedObj);
  2128. // save new selection
  2129. mSelectedObj = so;
  2130. // mark selected object
  2131. if (mSelectedObj)
  2132. deleteNotify(mSelectedObj);
  2133. // mark selection dirty
  2134. if (propagate_to_client)
  2135. mChangedSelectedObj = true;
  2136. return;
  2137. }
  2138. // clear previously selected object
  2139. if (mSelectedObj)
  2140. {
  2141. mSelectedObj->setSelectionFlags(mSelectedObj->getSelectionFlags() & ~SceneObject::SELECTED);
  2142. clearNotify(mSelectedObj);
  2143. Con::executef(this, "onObjectDeselected", mSelectedObj->getIdString());
  2144. }
  2145. // save new selection
  2146. mSelectedObj = so;
  2147. // mark selected object
  2148. if (mSelectedObj)
  2149. {
  2150. mSelectedObj->setSelectionFlags(mSelectedObj->getSelectionFlags() | SceneObject::SELECTED);
  2151. deleteNotify(mSelectedObj);
  2152. }
  2153. // mark selection dirty
  2154. //mChangedSelectedObj = true;
  2155. // notify appropriate script of the change
  2156. if (mSelectedObj)
  2157. Con::executef(this, "onObjectSelected", mSelectedObj->getIdString());
  2158. }
  2159. void GameConnection::setRolloverObj(SceneObject* so)
  2160. {
  2161. // save new selection
  2162. mRolloverObj = so;
  2163. // notify appropriate script of the change
  2164. Con::executef(this, "onObjectRollover", (mRolloverObj) ? mRolloverObj->getIdString() : "");
  2165. }
  2166. void GameConnection::setPreSelectedObjFromRollover()
  2167. {
  2168. mPreSelectedObj = mRolloverObj;
  2169. mPreSelectTimestamp = Platform::getRealMilliseconds();
  2170. }
  2171. void GameConnection::clearPreSelectedObj()
  2172. {
  2173. mPreSelectedObj = 0;
  2174. mPreSelectTimestamp = 0;
  2175. }
  2176. void GameConnection::setSelectedObjFromPreSelected()
  2177. {
  2178. U32 now = Platform::getRealMilliseconds();
  2179. if (now - mPreSelectTimestamp < arcaneFX::sTargetSelectionTimeoutMS)
  2180. setSelectedObj(mPreSelectedObj);
  2181. mPreSelectedObj = 0;
  2182. }
  2183. void GameConnection::onDeleteNotify(SimObject* obj)
  2184. {
  2185. if (obj == mSelectedObj)
  2186. setSelectedObj(NULL);
  2187. Parent::onDeleteNotify(obj);
  2188. }
  2189. #ifdef AFX_CAP_DATABLOCK_CACHE
  2190. void GameConnection::tempDisableStringBuffering(BitStream* bs) const
  2191. {
  2192. bs->setStringBuffer(0);
  2193. }
  2194. void GameConnection::restoreStringBuffering(BitStream* bs) const
  2195. {
  2196. bs->clearStringBuffer();
  2197. }
  2198. // rewind to stream postion and then move raw bytes into client_db_stream
  2199. // for caching purposes.
  2200. void GameConnection::repackClientDatablock(BitStream* bstream, S32 start_pos)
  2201. {
  2202. static U8 bit_buffer[Net::MaxPacketDataSize];
  2203. if (!clientCacheEnabled() || !client_db_stream)
  2204. return;
  2205. S32 cur_pos = bstream->getCurPos();
  2206. S32 n_bits = cur_pos - start_pos;
  2207. if (n_bits <= 0)
  2208. return;
  2209. bstream->setCurPos(start_pos);
  2210. bstream->readBits(n_bits, bit_buffer);
  2211. bstream->setCurPos(cur_pos);
  2212. //S32 start_pos2 = client_db_stream->getCurPos();
  2213. client_db_stream->writeBits(n_bits, bit_buffer);
  2214. }
  2215. #define CLIENT_CACHE_VERSION_CODE 47241113
  2216. void GameConnection::saveDatablockCache(bool on_server)
  2217. {
  2218. InfiniteBitStream bit_stream;
  2219. BitStream* bstream = 0;
  2220. if (on_server)
  2221. {
  2222. SimDataBlockGroup *g = Sim::getDataBlockGroup();
  2223. // find the first one we haven't sent:
  2224. U32 i, groupCount = g->size();
  2225. S32 key = this->getDataBlockModifiedKey();
  2226. for (i = 0; i < groupCount; i++)
  2227. if (((SimDataBlock*)(*g)[i])->getModifiedKey() > key)
  2228. break;
  2229. // nothing to save
  2230. if (i == groupCount)
  2231. return;
  2232. bstream = &bit_stream;
  2233. for (;i < groupCount; i++)
  2234. {
  2235. SimDataBlock* obj = (SimDataBlock*)(*g)[i];
  2236. GameConnection* gc = this;
  2237. NetConnection* conn = this;
  2238. SimObjectId id = obj->getId();
  2239. if (bstream->writeFlag(gc->getDataBlockModifiedKey() < obj->getModifiedKey())) // A - flag
  2240. {
  2241. if (obj->getModifiedKey() > gc->getMaxDataBlockModifiedKey())
  2242. gc->setMaxDataBlockModifiedKey(obj->getModifiedKey());
  2243. bstream->writeInt(id - DataBlockObjectIdFirst,DataBlockObjectIdBitSize); // B - int
  2244. S32 classId = obj->getClassId(conn->getNetClassGroup());
  2245. bstream->writeClassId(classId, NetClassTypeDataBlock, conn->getNetClassGroup()); // C - id
  2246. bstream->writeInt(i, DataBlockObjectIdBitSize); // D - int
  2247. bstream->writeInt(groupCount, DataBlockObjectIdBitSize + 1); // E - int
  2248. obj->packData(bstream);
  2249. }
  2250. }
  2251. }
  2252. else
  2253. {
  2254. bstream = client_db_stream;
  2255. }
  2256. if (bstream->getPosition() <= 0)
  2257. return;
  2258. // zero out any leftover bits short of an even byte count
  2259. U32 n_leftover_bits = (bstream->getPosition()*8) - bstream->getCurPos();
  2260. if (n_leftover_bits >= 0 && n_leftover_bits <= 8)
  2261. {
  2262. // note - an unusual problem regarding setCurPos() results when there
  2263. // are no leftover bytes. Adding a buffer byte in this case avoids the problem.
  2264. if (n_leftover_bits == 0)
  2265. n_leftover_bits = 8;
  2266. U8 bzero = 0;
  2267. bstream->writeBits(n_leftover_bits, &bzero);
  2268. }
  2269. // this is where we actually save the file
  2270. const char* filename = (on_server) ? server_cache_filename : client_cache_filename;
  2271. if (filename && filename[0] != '\0')
  2272. {
  2273. FileStream* f_stream;
  2274. if((f_stream = FileStream::createAndOpen(filename, Torque::FS::File::Write )) == NULL)
  2275. {
  2276. Con::printf("Failed to open file '%s'.", filename);
  2277. return;
  2278. }
  2279. U32 save_sz = bstream->getPosition();
  2280. if (!on_server)
  2281. {
  2282. f_stream->write((U32)CLIENT_CACHE_VERSION_CODE);
  2283. f_stream->write(save_sz);
  2284. f_stream->write(server_cache_CRC);
  2285. f_stream->write((U32)CLIENT_CACHE_VERSION_CODE);
  2286. }
  2287. f_stream->write(save_sz, bstream->getBuffer());
  2288. // zero out any leftover bytes short of a 4-byte multiple
  2289. while ((save_sz % 4) != 0)
  2290. {
  2291. f_stream->write((U8)0);
  2292. save_sz++;
  2293. }
  2294. delete f_stream;
  2295. }
  2296. if (!on_server)
  2297. client_db_stream->clear();
  2298. }
  2299. static bool afx_saved_db_cache = false;
  2300. static U32 afx_saved_db_cache_CRC = 0xffffffff;
  2301. void GameConnection::resetDatablockCache()
  2302. {
  2303. afx_saved_db_cache = false;
  2304. afx_saved_db_cache_CRC = 0xffffffff;
  2305. }
  2306. ConsoleFunction(resetDatablockCache, void, 1, 1, "resetDatablockCache()")
  2307. {
  2308. GameConnection::resetDatablockCache();
  2309. }
  2310. ConsoleFunction(isDatablockCacheSaved, bool, 1, 1, "resetDatablockCache()")
  2311. {
  2312. return afx_saved_db_cache;
  2313. }
  2314. ConsoleFunction(getDatablockCacheCRC, S32, 1, 1, "getDatablockCacheCRC()")
  2315. {
  2316. return (S32)afx_saved_db_cache_CRC;
  2317. }
  2318. ConsoleFunction(extractDatablockCacheCRC, S32, 2, 2, "extractDatablockCacheCRC(filename)")
  2319. {
  2320. FileStream f_stream;
  2321. const char* fileName = argv[1];
  2322. if(!f_stream.open(fileName, Torque::FS::File::Read))
  2323. {
  2324. Con::errorf("Failed to open file '%s'.", fileName);
  2325. return -1;
  2326. }
  2327. U32 stream_sz = f_stream.getStreamSize();
  2328. if (stream_sz < 4*32)
  2329. {
  2330. Con::errorf("File '%s' is not a valid datablock cache.", fileName);
  2331. f_stream.close();
  2332. return -1;
  2333. }
  2334. U32 pre_code; f_stream.read(&pre_code);
  2335. U32 save_sz; f_stream.read(&save_sz);
  2336. U32 crc_code; f_stream.read(&crc_code);
  2337. U32 post_code; f_stream.read(&post_code);
  2338. f_stream.close();
  2339. if (pre_code != post_code)
  2340. {
  2341. Con::errorf("File '%s' is not a valid datablock cache.", fileName);
  2342. return -1;
  2343. }
  2344. if (pre_code != (U32)CLIENT_CACHE_VERSION_CODE)
  2345. {
  2346. Con::errorf("Version of datablock cache file '%s' does not match version of running software.", fileName);
  2347. return -1;
  2348. }
  2349. return (S32)crc_code;
  2350. }
  2351. ConsoleFunction(setDatablockCacheCRC, void, 2, 2, "setDatablockCacheCRC(crc)")
  2352. {
  2353. GameConnection *conn = GameConnection::getConnectionToServer();
  2354. if(!conn)
  2355. return;
  2356. U32 crc_u = (U32)dAtoi(argv[1]);
  2357. conn->setServerCacheCRC(crc_u);
  2358. }
  2359. ConsoleMethod( GameConnection, saveDatablockCache, void, 2, 2, "saveDatablockCache()")
  2360. {
  2361. if (GameConnection::serverCacheEnabled() && !afx_saved_db_cache)
  2362. {
  2363. // Save the datablocks to a cache file. An argument
  2364. // of true indicates that this is a server save.
  2365. object->saveDatablockCache(true);
  2366. afx_saved_db_cache = true;
  2367. afx_saved_db_cache_CRC = 0xffffffff;
  2368. static char filename_buffer[1024];
  2369. String filename(Torque::Path::CleanSeparators(object->serverCacheFilename()));
  2370. Con::expandScriptFilename(filename_buffer, sizeof(filename_buffer), filename.c_str());
  2371. Torque::Path givenPath(Torque::Path::CompressPath(filename_buffer));
  2372. Torque::FS::FileNodeRef fileRef = Torque::FS::GetFileNode(givenPath);
  2373. if ( fileRef == NULL )
  2374. Con::errorf("saveDatablockCache() failed to get CRC for file '%s'.", filename.c_str());
  2375. else
  2376. afx_saved_db_cache_CRC = (S32)fileRef->getChecksum();
  2377. }
  2378. }
  2379. ConsoleMethod( GameConnection, loadDatablockCache, void, 2, 2, "loadDatablockCache()")
  2380. {
  2381. if (GameConnection::clientCacheEnabled())
  2382. {
  2383. object->loadDatablockCache();
  2384. }
  2385. }
  2386. ConsoleMethod( GameConnection, loadDatablockCache_Begin, bool, 2, 2, "loadDatablockCache_Begin()")
  2387. {
  2388. if (GameConnection::clientCacheEnabled())
  2389. {
  2390. return object->loadDatablockCache_Begin();
  2391. }
  2392. return false;
  2393. }
  2394. ConsoleMethod( GameConnection, loadDatablockCache_Continue, bool, 2, 2, "loadDatablockCache_Continue()")
  2395. {
  2396. if (GameConnection::clientCacheEnabled())
  2397. {
  2398. return object->loadDatablockCache_Continue();
  2399. }
  2400. return false;
  2401. }
  2402. static char* afx_db_load_buf = 0;
  2403. static U32 afx_db_load_buf_sz = 0;
  2404. static BitStream* afx_db_load_bstream = 0;
  2405. void GameConnection::loadDatablockCache()
  2406. {
  2407. if (!loadDatablockCache_Begin())
  2408. return;
  2409. while (loadDatablockCache_Continue())
  2410. ;
  2411. }
  2412. bool GameConnection::loadDatablockCache_Begin()
  2413. {
  2414. if (!client_cache_filename || client_cache_filename[0] == '\0')
  2415. {
  2416. Con::errorf("No filename was specified for the client datablock cache.");
  2417. return false;
  2418. }
  2419. // open cache file
  2420. FileStream f_stream;
  2421. if(!f_stream.open(client_cache_filename, Torque::FS::File::Read))
  2422. {
  2423. Con::errorf("Failed to open file '%s'.", client_cache_filename);
  2424. return false;
  2425. }
  2426. // get file size
  2427. U32 stream_sz = f_stream.getStreamSize();
  2428. if (stream_sz <= 4*4)
  2429. {
  2430. Con::errorf("File '%s' is too small to be a valid datablock cache.", client_cache_filename);
  2431. f_stream.close();
  2432. return false;
  2433. }
  2434. // load header data
  2435. U32 pre_code; f_stream.read(&pre_code);
  2436. U32 save_sz; f_stream.read(&save_sz);
  2437. U32 crc_code; f_stream.read(&crc_code);
  2438. U32 post_code; f_stream.read(&post_code);
  2439. // validate header info
  2440. if (pre_code != post_code)
  2441. {
  2442. Con::errorf("File '%s' is not a valid datablock cache.", client_cache_filename);
  2443. f_stream.close();
  2444. return false;
  2445. }
  2446. if (pre_code != (U32)CLIENT_CACHE_VERSION_CODE)
  2447. {
  2448. Con::errorf("Version of datablock cache file '%s' does not match version of running software.", client_cache_filename);
  2449. f_stream.close();
  2450. return false;
  2451. }
  2452. // allocated the in-memory buffer
  2453. afx_db_load_buf_sz = stream_sz - (4*4);
  2454. afx_db_load_buf = new char[afx_db_load_buf_sz];
  2455. // load data from file into memory
  2456. if (!f_stream.read(stream_sz, afx_db_load_buf))
  2457. {
  2458. Con::errorf("Failed to read data from file '%s'.", client_cache_filename);
  2459. f_stream.close();
  2460. delete [] afx_db_load_buf;
  2461. afx_db_load_buf = 0;
  2462. afx_db_load_buf_sz = 0;
  2463. return false;
  2464. }
  2465. // close file
  2466. f_stream.close();
  2467. // At this point we have the whole cache in memory
  2468. // create a bitstream from the in-memory buffer
  2469. afx_db_load_bstream = new BitStream(afx_db_load_buf, afx_db_load_buf_sz);
  2470. return true;
  2471. }
  2472. bool GameConnection::loadDatablockCache_Continue()
  2473. {
  2474. if (!afx_db_load_bstream)
  2475. return false;
  2476. // prevent repacking of datablocks during load
  2477. BitStream* save_client_db_stream = client_db_stream;
  2478. client_db_stream = 0;
  2479. bool all_finished = false;
  2480. // loop through at most 16 datablocks
  2481. BitStream *bstream = afx_db_load_bstream;
  2482. for (S32 i = 0; i < 16; i++)
  2483. {
  2484. S32 save_pos = bstream->getCurPos();
  2485. if (!bstream->readFlag())
  2486. {
  2487. all_finished = true;
  2488. break;
  2489. }
  2490. bstream->setCurPos(save_pos);
  2491. SimDataBlockEvent evt;
  2492. evt.unpack(this, bstream);
  2493. evt.process(this);
  2494. }
  2495. client_db_stream = save_client_db_stream;
  2496. if (all_finished)
  2497. {
  2498. delete afx_db_load_bstream;
  2499. afx_db_load_bstream = 0;
  2500. delete [] afx_db_load_buf;
  2501. afx_db_load_buf = 0;
  2502. afx_db_load_buf_sz = 0;
  2503. return false;
  2504. }
  2505. return true;
  2506. }
  2507. #endif