Clone of PhatAC @ https://github.com/floaterxk/PhatAC

Client.cpp 20KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814
  1. #include "StdAfx.h"
  2. #include "Client.h"
  3. #include "ClientEvents.h"
  4. // Network access
  5. #include "Network.h"
  6. #include "PacketController.h"
  7. #include "BinaryReader.h"
  8. #include "BinaryWriter.h"
  9. // Database access
  10. #include "Database.h"
  11. #include "AccountDatabase.h"
  12. #include "CharacterDatabase.h"
  13. // World access
  14. #include "World.h"
  15. // Player access
  16. #include "PhysicsObj.h"
  17. #include "Monster.h"
  18. #include "Player.h"
  19. // Command access
  20. #include "ClientCommands.h"
  21. ///////////
  22. // Name: CClient
  23. // Desc: Presents an interface for client/server interaction.
  24. ///////////
  25. CClient::CClient(SOCKADDR_IN *peer, WORD slot, char *account, int accessLevel)
  26. {
  27. memcpy(&m_vars.addr, peer, sizeof(SOCKADDR_IN));
  28. m_vars.slot = slot;
  29. m_vars.account = account;
  30. m_vars.initdats = FALSE;
  31. m_vars.inworld = FALSE;
  32. m_vars.needchars = TRUE;
  33. m_AccessLevel = accessLevel;
  34. m_pPC = new CPacketController(this);
  35. m_pEvents = new CClientEvents(this);
  36. }
  37. CClient::~CClient()
  38. {
  39. SafeDelete(m_pEvents);
  40. SafeDelete(m_pPC);
  41. }
  42. void CClient::IncomingBlob(BlobPacket_s *pData)
  43. {
  44. if (!IsAlive())
  45. return;
  46. if (!m_pPC || !m_pPC->IsAlive())
  47. return;
  48. m_pPC->IncomingBlob(pData);
  49. }
  50. void CClient::Think()
  51. {
  52. if (!IsAlive())
  53. return;
  54. if (m_pPC)
  55. {
  56. if (m_pPC->HasConnection())
  57. {
  58. WorldThink();
  59. }
  60. m_pPC->Think();
  61. //If the packetcontroller is dead, so are we.
  62. if (!m_pPC->IsAlive())
  63. Kill(__FILE__, __LINE__);
  64. }
  65. else
  66. Kill(__FILE__, __LINE__);
  67. }
  68. void CClient::ThinkOutbound()
  69. {
  70. if (!IsAlive())
  71. return;
  72. if (m_pPC && m_pPC - IsAlive())
  73. {
  74. m_pPC->ThinkOutbound();
  75. }
  76. }
  77. void CClient::WorldThink()
  78. {
  79. if (!m_vars.inworld)
  80. {
  81. if (!m_vars.initdats)
  82. {
  83. //'PHAT AC'
  84. BinaryWriter EraseFile;
  85. /*
  86. EraseFile.WriteDWORD( 0xF7BB );
  87. EraseFile.WriteDWORD( 7 );
  88. EraseFile.WriteDWORD( 0xEFE9FFFF );
  89. EraseFile.WriteDWORD( 0xEDEAFFFF );
  90. EraseFile.WriteDWORD( 0xEEEAFFFF );
  91. EraseFile.WriteDWORD( 0xEFEAFFFF );
  92. EraseFile.WriteDWORD( 0xF0EAFFFF );
  93. EraseFile.WriteDWORD( 0xEEE9FFFF );
  94. EraseFile.WriteDWORD( 0xEFE9FFFF );
  95. SendNetMessage(EraseFile.GetData(), EraseFile.GetSize(), EVENT_MSG);
  96. */
  97. //CUSTOM BLOCKS!
  98. WIN32_FIND_DATA data;
  99. if (g_pDB->DataFileFindFirst("land\\cell-*", &data))
  100. {
  101. DWORD dwCount = 1;
  102. DWORD dwID;
  103. sscanf(data.cFileName, "cell-%08X", &dwID);
  104. BinaryWriter CustomBlocks;
  105. CustomBlocks.WriteDWORD(dwID);
  106. while (g_pDB->DataFileFindNext(&data))
  107. {
  108. sscanf(data.cFileName, "cell-%08X", &dwID);
  109. CustomBlocks.WriteDWORD(dwID);
  110. dwCount++;
  111. if ((dwID & 0xFFFF) == 0xFFFF) {
  112. CustomBlocks.WriteDWORD(dwID & 0xFFFFFFFE);
  113. dwCount++;
  114. }
  115. }
  116. BinaryWriter EraseCustomBlocks;
  117. EraseCustomBlocks.WriteDWORD(0xF7BB);
  118. EraseCustomBlocks.WriteDWORD(dwCount);
  119. EraseCustomBlocks.AppendData(CustomBlocks.GetData(), CustomBlocks.GetSize());
  120. // LOG(Temp, Normal, "Erasing custom blocks: %lu\n", dwCount);
  121. SendNetMessage(EraseCustomBlocks.GetData(), EraseCustomBlocks.GetSize(), EVENT_MSG);
  122. g_pDB->DataFileFindClose();
  123. }
  124. BinaryWriter UpdateDats;
  125. UpdateDats.WriteLong(0xF7B8);
  126. UpdateDats.WriteLong(m_vars.portalstamp);
  127. UpdateDats.WriteLong(0);
  128. UpdateDats.WriteLong(m_vars.cellstamp);
  129. UpdateDats.WriteLong(0);
  130. UpdateDats.WriteLong(0);
  131. UpdateDats.WriteLong(0);
  132. SendNetMessage(UpdateDats.GetData(), UpdateDats.GetSize(), EVENT_MSG);
  133. SendNetMessage(UpdateDats.GetData(), UpdateDats.GetSize(), EVENT_MSG);
  134. m_vars.initdats = TRUE;
  135. }
  136. if (m_vars.needchars)
  137. {
  138. UpdateLoginScreen();
  139. m_vars.needchars = FALSE;
  140. }
  141. }
  142. m_pEvents->Think();
  143. }
  144. void CClient::UpdateLoginScreen()
  145. {
  146. char *account = (char*)m_vars.account.c_str();
  147. DWORD pdwGUIDs[5];
  148. DWORD dwCount = g_pDB->CharDB()->GetCharacters(account, pdwGUIDs);
  149. BinaryWriter CharacterList;
  150. CharacterList.WriteLong(0xF658);
  151. CharacterList.WriteLong(0);
  152. CharacterList.WriteLong(dwCount);
  153. _CHARDESC desc;
  154. for (unsigned int i = 0; i < dwCount; i++)
  155. {
  156. g_pDB->CharDB()->GetCharacterDesc(pdwGUIDs[i], &desc);
  157. CharacterList.WriteLong(desc.dwGUID);
  158. CharacterList.WriteString(desc.szName);
  159. CharacterList.WriteLong(desc.dwDeletePeriod);
  160. }
  161. CharacterList.WriteLong(0);
  162. CharacterList.WriteLong(11);
  163. CharacterList.WriteString(account);
  164. CharacterList.WriteLong(1);
  165. CharacterList.WriteLong(1);
  166. SendNetMessage(CharacterList.GetData(), CharacterList.GetSize(), PRIVATE_MSG);
  167. /*std::string strMOTD = "You are in the world of PHATAC.\n\n";
  168. strMOTD += "Welcome to Asheron's Call!\n\n";
  169. strMOTD += "Sat 04/18/2004\n=============\nFeatures added\nAbout a months worth..\n\n\n";
  170. strMOTD += "Sat 03/20/2004\n=============\nFeatures added:\n....\n\n\n";
  171. strMOTD += "Wed 03/17/2004\n=============\nFeatures added:\nStraf & Backwards movement now uses decoded Formulas.\nCombat modes now properly animate.\nNow documenting build changes. All previous info is estimated.\n\n\n";
  172. strMOTD += "Tue 03/16/2004\n=============\nFeatures added:\nTeleporting to players. (@tele)\nTeleporting to coordinates. (@teleto)\n\n\n";
  173. strMOTD += "Sun 03/14/2004\n=============\nFeatures added:\nParticle effects. (@effect)\nRunning anim w/ decoded Formulas.\nWorldstate save/restore for ID propagation.\nSingle-state emote animations.\n\n\n";
  174. strMOTD += "Wed 03/10/2004\n=============\nFeatures added:\nMultiplayer.\nRoaming.\n\n\n";
  175. strMOTD += "Wed 03/03/2004\n=============\nEmulator packet controllers (netcode) complete.\n\n\n";
  176. strMOTD += "Mon 03/01/2004\n=============\nEmulator is born.\n\n\n";*/
  177. /*
  178. BinaryWriter ServerMOTD;
  179. ServerMOTD.WriteLong( 0xF65A );
  180. ServerMOTD.WriteString( csprintf("Currently %u clients connected.\n", g_pGlobals->GetClientCount() ) );
  181. ServerMOTD.WriteString( g_pWorld->GetMOTD() );
  182. SendNetMessage(ServerMOTD.GetData(), ServerMOTD.GetSize(), PRIVATE_MSG);
  183. */
  184. BinaryWriter ServerName;
  185. ServerName.WriteLong(0xF7E1);
  186. ServerName.WriteLong(0x32); // Num connections
  187. ServerName.WriteLong(-1); // Max connections
  188. ServerName.WriteString("PhatAC");
  189. SendNetMessage(ServerName.GetData(), ServerName.GetSize(), PRIVATE_MSG);
  190. BinaryWriter ServerUnk;
  191. ServerUnk.WriteLong(0xF7E5);
  192. ServerUnk.WriteLong(1); // servers region
  193. ServerUnk.WriteLong(1); // name rule language
  194. ServerUnk.WriteLong(1); // product id
  195. ServerUnk.WriteLong(2); // supports languages (2)
  196. ServerUnk.WriteLong(0); // language #1
  197. ServerUnk.WriteLong(1); // language #2
  198. SendNetMessage(ServerUnk.GetData(), ServerUnk.GetSize(), EVENT_MSG);
  199. }
  200. void CClient::EnterWorld()
  201. {
  202. DWORD EnterWorld = 0xF7DF; // 0xF7C7;
  203. SendNetMessage(&EnterWorld, sizeof(DWORD), 9);
  204. LOG(Client, Normal, "Client #%u is entering the world.\n", m_vars.slot);
  205. m_vars.inworld = TRUE;
  206. }
  207. void CClient::ExitWorld()
  208. {
  209. DWORD ExitWorld = 0xF653;
  210. SendNetMessage(&ExitWorld, sizeof(DWORD), PRIVATE_MSG);
  211. LOG(Client, Normal, "Client #%u is exiting the world.\n", m_vars.slot);
  212. m_pPC->ResetEvent();
  213. UpdateLoginScreen();
  214. m_vars.inworld = FALSE;
  215. }
  216. void CClient::SendNetMessage(BinaryWriter* pMessage, WORD group, BOOL event, BOOL del)
  217. {
  218. if (!pMessage)
  219. return;
  220. SendNetMessage(pMessage->GetData(), pMessage->GetSize(), group, event);
  221. if (del)
  222. delete pMessage;
  223. }
  224. void CClient::SendNetMessage(void *data, DWORD length, WORD group, BOOL game_event)
  225. {
  226. if (!IsAlive())
  227. return;
  228. if (!data || !length)
  229. return;
  230. if (length > 4)
  231. {
  232. DWORD dwMessageCode = *((DWORD *)data);
  233. //if ( dwMessageCode == 0x0000F745 )
  234. // OutputConsoleBytes( data, length );
  235. }
  236. if (m_pPC && m_pPC->IsAlive())
  237. {
  238. if (!game_event)
  239. m_pPC->SendNetMessage(data, length, group);
  240. else
  241. {
  242. EventHeader *Event = (EventHeader *)new BYTE[sizeof(EventHeader) + length];
  243. Event->dwF7B0 = 0xF7B0;
  244. Event->dwPlayer = m_pEvents->GetPlayerID();
  245. Event->dwSequence = m_pPC->GetNextEvent();
  246. memcpy((BYTE *)Event + sizeof(EventHeader), data, length);
  247. m_pPC->SendNetMessage(Event, sizeof(EventHeader) + length, group);
  248. delete[] Event;
  249. }
  250. }
  251. }
  252. BOOL CClient::CheckNameValidity(const char *name)
  253. {
  254. int len = (int)strlen(name);
  255. if ((len < 3) || (len > 16))
  256. return FALSE;
  257. int i = 0;
  258. while (i < len)
  259. {
  260. char letter = name[i];
  261. if (!(letter >= 'A' && letter <= 'Z') && !(letter >= 'a' || letter <= 'z') &&
  262. /*!(letter == '\'') && */!(letter == ' ') && !(letter == '-'))
  263. break;
  264. i++;
  265. }
  266. if (i == len) return TRUE;
  267. return FALSE;
  268. }
  269. void CClient::CreateCharacter(BinaryReader *in)
  270. {
  271. DWORD dwError = 5;
  272. char *szAccount = in->ReadString();
  273. if (!szAccount || strcmp(szAccount, m_vars.account.c_str()))
  274. return;
  275. if (in->ReadDWORD() != 1) return;
  276. DWORD dwRace = in->ReadDWORD(); // 5
  277. DWORD dwGender = in->ReadDWORD(); // 1
  278. DWORD dwForeheadTex = in->ReadDWORD(); // 6
  279. DWORD dwNoseTex = in->ReadDWORD(); // 1
  280. DWORD dwChinTex = in->ReadDWORD(); // 1
  281. DWORD dwHairColor = in->ReadDWORD(); // 0
  282. DWORD dwEyeColor = in->ReadDWORD(); // 0
  283. DWORD dwHairStyle = in->ReadDWORD(); // 1
  284. DWORD dwHatType = in->ReadDWORD(); // -1
  285. DWORD dwHatColor = in->ReadDWORD(); // 0
  286. DWORD dwShirtType = in->ReadDWORD(); // 0
  287. DWORD dwShirtColor = in->ReadDWORD(); // 2
  288. DWORD dwPantsType = in->ReadDWORD(); // 0
  289. DWORD dwPantsColor = in->ReadDWORD(); // 2
  290. DWORD dwShoeType = in->ReadDWORD(); // 0
  291. DWORD dwShoeColor = in->ReadDWORD(); // 2
  292. DWORD dwSkinPalette = in->ReadDWORD();
  293. float flSkinShade = in->ReadFloat();
  294. DWORD dwHairPalette = in->ReadDWORD();
  295. float flHairShade = in->ReadFloat();
  296. DWORD dwHatPalette = in->ReadDWORD();
  297. float flHatShade = in->ReadFloat();
  298. DWORD dwPantsPalette = in->ReadDWORD();
  299. float flPantsShade = in->ReadFloat();
  300. DWORD dwShirtPalette = in->ReadDWORD();
  301. float flShirtShade = in->ReadFloat();
  302. DWORD dwShoePalette = in->ReadDWORD();
  303. float dwShoeShade = in->ReadFloat();
  304. DWORD dwProfession = in->ReadDWORD(); // 0
  305. DWORD dwStrength = in->ReadDWORD(); // 10
  306. DWORD dwEndurance = in->ReadDWORD(); // 20
  307. DWORD dwCoordination = in->ReadDWORD(); // 30
  308. DWORD dwQuickness = in->ReadDWORD(); // 80
  309. DWORD dwFocus = in->ReadDWORD(); // 90
  310. DWORD dwSelf = in->ReadDWORD(); // 100
  311. DWORD dwUnknown = in->ReadDWORD(); // -1
  312. DWORD dwAccessLevel = in->ReadDWORD(); // 1 //0xE40 = sentinels.
  313. DWORD dwNumSkills = in->ReadDWORD(); // 0x37 (55)
  314. DWORD *dwSkillStatus = (DWORD *)in->ReadArray(dwNumSkills * sizeof(DWORD));
  315. char *szCharacterName = in->ReadString();
  316. DWORD dwUnknown2 = in->ReadDWORD();
  317. DWORD dwUnknown3 = in->ReadDWORD();
  318. DWORD dwStarterTown = in->ReadDWORD();
  319. DWORD dwUnknown4 = in->ReadDWORD();
  320. if (in->GetLastError()) goto BadData;
  321. //should convert name by removing duplicate spaces, '-', or '\''
  322. if (!CheckNameValidity(szCharacterName))
  323. {
  324. dwError = 4;
  325. goto BadData;
  326. }
  327. //should check variables to make sure everythings within restriction
  328. //wHairTextures[m_wGender][m_wHairStyle];
  329. //WORD wHairTextures[2][4] = { { 0x10B8, 0x10B8, 0x10B8, 0x10B7 }, { 0x11FD, 0x11FD, 0x11FD, 0x10B7 } };
  330. //group 4, 0x0000F643, 0x00000001, <guid>, <char name[str]>, 0x00000000
  331. {
  332. DWORD dwGUID = 0;
  333. CCharacterDatabase* pCharDB;
  334. if ((pCharDB = g_pDB->CharDB()) && g_pWorld)
  335. {
  336. _CHARDESC buffer;
  337. if (!pCharDB->GetCharacterDesc(szCharacterName, &buffer))
  338. {
  339. dwGUID = g_pWorld->GenerateGUID(ePlayerGUID);
  340. pCharDB->CreateCharacterDesc(GetAccount(), dwGUID, szCharacterName);
  341. }
  342. }
  343. if (dwGUID != 0)
  344. {
  345. BinaryWriter Success;
  346. Success.WriteDWORD(0xF643);
  347. Success.WriteDWORD(1);
  348. Success.WriteDWORD(dwGUID);
  349. Success.WriteString(szCharacterName);
  350. Success.WriteDWORD(0);
  351. SendNetMessage(Success.GetData(), Success.GetSize(), PRIVATE_MSG);
  352. }
  353. else
  354. {
  355. BinaryWriter BadCharGen;
  356. BadCharGen.WriteDWORD(0xF643);
  357. BadCharGen.WriteDWORD(3); // name already exists
  358. SendNetMessage(BadCharGen.GetData(), BadCharGen.GetSize(), PRIVATE_MSG);
  359. }
  360. }
  361. return;
  362. BadData:
  363. {
  364. BinaryWriter BadCharGen;
  365. BadCharGen.WriteDWORD(0xF643);
  366. BadCharGen.WriteDWORD(dwError);
  367. SendNetMessage(BadCharGen.GetData(), BadCharGen.GetSize(), PRIVATE_MSG);
  368. }
  369. }
  370. void CClient::SendLandblock(DWORD dwFileID)
  371. {
  372. TURBINEFILE* pLandData = g_pCell->GetFile(dwFileID);
  373. if (!pLandData)
  374. {
  375. if (m_pEvents)
  376. {
  377. m_pEvents->SendText(csprintf("Your client is requesting cell data (#%08X) that this server does not have!", dwFileID), 1);
  378. m_pEvents->SendText("If you are in portal mode, type /render radius 5 to escape. The server administrator should reconfigure the server with a FULL cell.dat file!", 1);
  379. }
  380. return;
  381. }
  382. if ((dwFileID & 0xFFFF) != 0xFFFF)
  383. {
  384. LOG(Client, Warning, "Client requested landblock %08X - should end in 0xFFFF\n", dwFileID);
  385. }
  386. TURBINEFILE* pObjData = NULL;
  387. DWORD dwObjFileID = 0;
  388. if (pLandData->GetLength() >= 8) {
  389. DWORD dwFlags = *((DWORD *)pLandData->GetData());
  390. BOOL bHasObjects = ((dwFlags & 1) ? TRUE : FALSE);
  391. dwObjFileID = (dwFileID & 0xFFFF0000) | 0xFFFE;
  392. pObjData = g_pCell->GetFile(dwObjFileID);
  393. }
  394. if (pLandData)
  395. {
  396. BinaryWriter BlockPackage;
  397. BlockPackage.WriteDWORD(0xF7E2);
  398. DWORD dwFileSize = pLandData->GetLength();
  399. BYTE* pbFileData = pLandData->GetData();
  400. DWORD dwPackageSize = (DWORD)((dwFileSize * 1.02f) + 12 + 1);
  401. BYTE* pbPackageData = new BYTE[dwPackageSize];
  402. if (Z_OK != compress2(pbPackageData, &dwPackageSize, pbFileData, dwFileSize, Z_BEST_COMPRESSION))
  403. {
  404. LOG(Client, Error, "Error compressing LandBlock package!\n");
  405. }
  406. BlockPackage.WriteDWORD(1);
  407. BlockPackage.WriteDWORD(2);
  408. BlockPackage.WriteDWORD(1);
  409. BlockPackage.WriteDWORD(dwFileID);
  410. BlockPackage.WriteDWORD(1);
  411. BlockPackage.WriteBYTE(1); // Compressed
  412. BlockPackage.WriteDWORD(2);
  413. BlockPackage.WriteDWORD(dwPackageSize + sizeof(DWORD) * 2);
  414. BlockPackage.WriteDWORD(dwFileSize);
  415. BlockPackage.AppendData(pbPackageData, dwPackageSize);
  416. BlockPackage.Align();
  417. delete[] pbPackageData;
  418. delete pLandData;
  419. //LOG(Temp, Normal, "Sent landblock %08X ..\n", dwFileID);
  420. SendNetMessage(BlockPackage.GetData(), BlockPackage.GetSize(), EVENT_MSG, FALSE);
  421. }
  422. if (pObjData)
  423. {
  424. BinaryWriter BlockInfoPackage;
  425. BlockInfoPackage.WriteDWORD(0xF7E2);
  426. DWORD dwFileSize = pObjData->GetLength();
  427. BYTE* pbFileData = pObjData->GetData();
  428. DWORD dwPackageSize = (DWORD)((dwFileSize * 1.02f) + 12 + 1);
  429. BYTE* pbPackageData = new BYTE[dwPackageSize];
  430. if (Z_OK != compress2(pbPackageData, &dwPackageSize, pbFileData, dwFileSize, Z_BEST_COMPRESSION))
  431. {
  432. LOG(Client, Error, "Error compressing LandBlockInfo package!\n");
  433. }
  434. BlockInfoPackage.WriteDWORD(1);
  435. BlockInfoPackage.WriteDWORD(2);
  436. BlockInfoPackage.WriteDWORD(2); // 1 for 0xFFFF, 2 for 0xFFFE
  437. BlockInfoPackage.WriteDWORD(dwObjFileID);
  438. BlockInfoPackage.WriteDWORD(1);
  439. BlockInfoPackage.WriteBYTE(1);
  440. BlockInfoPackage.WriteDWORD(2);
  441. BlockInfoPackage.WriteDWORD(dwPackageSize + sizeof(DWORD) * 2);
  442. BlockInfoPackage.WriteDWORD(dwFileSize);
  443. BlockInfoPackage.AppendData(pbPackageData, dwPackageSize);
  444. BlockInfoPackage.Align();
  445. delete[] pbPackageData;
  446. delete pObjData;
  447. //LOG(Temp, Normal, "Sent objectblock %08X ..\n", dwObjFileID);
  448. SendNetMessage(BlockInfoPackage.GetData(), BlockInfoPackage.GetSize(), EVENT_MSG, FALSE);
  449. }
  450. //if (m_pEvents)
  451. // m_pEvents->SendText( csprintf("The server has sent you block #%04X!", dwFileID >> 16), 1);
  452. }
  453. void CClient::SendLandcell(DWORD dwFileID)
  454. {
  455. TURBINEFILE* pCellData = g_pCell->GetFile(dwFileID);
  456. if (!pCellData)
  457. {
  458. if (m_pEvents)
  459. {
  460. m_pEvents->SendText(csprintf("Your client is requesting cell data (#%08X) that this server does not have!", dwFileID), 1);
  461. m_pEvents->SendText("If you are in portal mode, type /render radius 5 to escape. The server administrator should reconfigure the server with a FULL cell.dat file!", 1);
  462. }
  463. return;
  464. }
  465. if (pCellData)
  466. {
  467. BinaryWriter CellPackage;
  468. CellPackage.WriteDWORD(0xF7E2);
  469. DWORD dwFileSize = pCellData->GetLength();
  470. BYTE* pbFileData = pCellData->GetData();
  471. DWORD dwPackageSize = (DWORD)((dwFileSize * 1.02f) + 12 + 1);
  472. BYTE* pbPackageData = new BYTE[dwPackageSize];
  473. if (Z_OK != compress2(pbPackageData, &dwPackageSize, pbFileData, dwFileSize, Z_BEST_COMPRESSION))
  474. {
  475. // These are CEnvCell if I recall correctly
  476. LOG(Client, Error, "Error compressing landcell package!\n");
  477. }
  478. CellPackage.WriteDWORD(1);
  479. CellPackage.WriteDWORD(2);
  480. CellPackage.WriteDWORD(3);
  481. CellPackage.WriteDWORD(dwFileID);
  482. CellPackage.WriteDWORD(1);
  483. CellPackage.WriteBYTE(1);
  484. CellPackage.WriteDWORD(2);
  485. CellPackage.WriteDWORD(dwPackageSize + sizeof(DWORD) * 2);
  486. CellPackage.WriteDWORD(dwFileSize);
  487. CellPackage.AppendData(pbPackageData, dwPackageSize);
  488. CellPackage.Align();
  489. delete[] pbPackageData;
  490. delete pCellData;
  491. //LOG(Temp, Normal, "Sent cell %08X ..\n", dwFileID);
  492. SendNetMessage(CellPackage.GetData(), CellPackage.GetSize(), EVENT_MSG, FALSE);
  493. }
  494. //if (m_pEvents)
  495. // m_pEvents->SendText( csprintf("The server has sent you cell #%04X!", dwFileID >> 16), 1);
  496. }
  497. void CClient::ProcessMessage(BYTE *data, DWORD length, WORD group)
  498. {
  499. BinaryReader in(data, length);
  500. DWORD dwMessageCode = in.ReadDWORD();
  501. #ifdef _DEBUG
  502. // LOG(Client, Normal, "Processing message 0x%X (size %d):\n", dwMessageCode, length);
  503. #endif
  504. if (in.GetLastError())
  505. {
  506. LOG(Client, Warning, "Error processing message.\n");
  507. return;
  508. }
  509. switch (dwMessageCode)
  510. {
  511. case 0xF653:
  512. {
  513. if (m_vars.inworld)
  514. {
  515. m_pEvents->BeginLogout();
  516. }
  517. break;
  518. }
  519. break;
  520. case 0xF656: // Create Character
  521. {
  522. if (!m_vars.inworld)
  523. {
  524. CreateCharacter(&in);
  525. }
  526. break;
  527. }
  528. case 0xF6EA: // Request Object
  529. {
  530. if (m_vars.inworld)
  531. {
  532. DWORD dwEID = in.ReadDWORD();
  533. if (in.GetLastError()) break;
  534. CBasePlayer *pPlayer;
  535. if ((m_pEvents) && (pPlayer = m_pEvents->GetPlayer()))
  536. {
  537. CPhysicsObj *pTarget = pPlayer->FindChild(dwEID);
  538. if (!pTarget)
  539. pTarget = g_pWorld->FindWithinPVS(pPlayer, dwEID);
  540. if (pTarget)
  541. pPlayer->MakeAware(pTarget);
  542. }
  543. }
  544. break;
  545. }
  546. case 0xF7E6:
  547. {
  548. BinaryWriter ServerUnk2;
  549. ServerUnk2.WriteLong(0xF7EA);
  550. SendNetMessage(ServerUnk2.GetData(), ServerUnk2.GetSize(), 5);
  551. break;
  552. }
  553. case 0xF7EA:
  554. {
  555. //BinaryWriter EndDDD;
  556. //EndDDD.WriteDWORD(0xF7EA);
  557. //SendNetMessage(EndDDD.GetData(), EndDDD.GetSize(), EVENT_MSG);
  558. break;
  559. }
  560. case 0xF7E3: // Request File Data was 0xF7A9
  561. {
  562. // This doesn't work for some reason.
  563. if (m_vars.inworld)
  564. {
  565. DWORD dwFileClass = in.ReadDWORD();
  566. DWORD dwFileID = in.ReadDWORD();
  567. if (in.GetLastError()) break;
  568. switch (dwFileClass)
  569. {
  570. default:
  571. LOG(Client, Warning, "Unknown download request: %08X %d\n", dwFileID, dwFileClass);
  572. break;
  573. case 1:
  574. SendLandblock(dwFileID); // 1 is landblock 0xFFFF
  575. break;
  576. // 2 is 0xFFFE the landblock environment info I believe, but client never requests it directly, it is sent with landblocks
  577. case 3:
  578. SendLandcell(dwFileID); // 0x100+
  579. break;
  580. }
  581. }
  582. break;
  583. }
  584. case 0xF7B1:
  585. {
  586. //should check the sequence
  587. if (m_vars.inworld)
  588. {
  589. m_pEvents->ProcessEvent(&in);
  590. }
  591. break;
  592. }
  593. case 0xF7C8:
  594. {
  595. if (!m_vars.inworld)
  596. {
  597. EnterWorld();
  598. }
  599. break;
  600. }
  601. case 0xF657:
  602. {
  603. if (m_vars.inworld)
  604. {
  605. DWORD dwGUID = in.ReadDWORD();
  606. char* szName = in.ReadString();
  607. if (in.GetLastError()) break;
  608. m_pEvents->LoginCharacter(dwGUID, /*szName*/GetAccount());
  609. }
  610. break;
  611. }
  612. default:
  613. LOG(Client, Warning, "Unhandled message %08X from the client.\n", dwMessageCode);
  614. break;
  615. }
  616. //if ( dwMessageCode != 0xF7B1 )
  617. // LOG(Temp, Normal, "Received message %04X\n", dwMessageCode);
  618. }
  619. BOOL CClient::CheckAccount(const char* cmp)
  620. {
  621. return !strcmp(m_vars.account.c_str(), cmp);
  622. }
  623. int CClient::GetAccessLevel()
  624. {
  625. return m_AccessLevel;
  626. }
  627. BOOL CClient::CheckAddress(SOCKADDR_IN *peer)
  628. {
  629. return !memcmp(GetHostAddress(), peer, sizeof(SOCKADDR_IN));
  630. }
  631. WORD CClient::GetIndex()
  632. {
  633. return m_vars.slot;
  634. }
  635. const char* CClient::GetAccount()
  636. {
  637. return m_vars.account.c_str();
  638. }
  639. const char* CClient::GetDescription()
  640. {
  641. // Must lead with index or the kick/ban feature won't function.
  642. return csprintf("#%u %s \"%s\"", m_vars.slot, inet_ntoa(m_vars.addr.sin_addr), m_vars.account.c_str());
  643. }
  644. void CClient::SetLoginData(DWORD dwUnixTime, DWORD dwPortalStamp, DWORD dwCellStamp)
  645. {
  646. m_vars.logintime = g_pGlobals->Time();
  647. m_vars.unixtime = dwUnixTime;
  648. m_vars.portalstamp = dwPortalStamp;
  649. m_vars.cellstamp = dwCellStamp;
  650. m_vars.initdats = FALSE;
  651. }
  652. SOCKADDR_IN* CClient::GetHostAddress()
  653. {
  654. return &m_vars.addr;
  655. }