PacketData CGameServerPlayer::GetCharacterInfo() { PacketData outgoingPacket(std::begin(g_client0_login8), std::end(g_client0_login8)); { const uint32 setInitialPositionBase = 0x320; CSetInitialPositionPacket setInitialPosition; setInitialPosition.SetSourceId(PLAYER_ID); setInitialPosition.SetTargetId(PLAYER_ID); setInitialPosition.SetX(157.55f); setInitialPosition.SetY(0); setInitialPosition.SetZ(165.05f); setInitialPosition.SetAngle(-1.53f); auto setInitialPositionPacket = setInitialPosition.ToPacketData(); memcpy(outgoingPacket.data() + setInitialPositionBase, setInitialPositionPacket.data(), setInitialPositionPacket.size()); } auto playerActor = m_instance.GetActor<CPlayerActor>(PLAYER_ID); const auto& character = playerActor->GetCharacter(); const uint32 characterInfoBase = 0x368; *reinterpret_cast<uint32*>(&outgoingPacket[characterInfoBase + 0x20]) = CCharacter::GetModelFromTribe(character.tribe); *reinterpret_cast<uint32*>(&outgoingPacket[characterInfoBase + 0x28]) = character.size; *reinterpret_cast<uint32*>(&outgoingPacket[characterInfoBase + 0x30]) = character.GetColorInfo(); *reinterpret_cast<uint32*>(&outgoingPacket[characterInfoBase + 0x38]) = character.GetFaceInfo(); *reinterpret_cast<uint32*>(&outgoingPacket[characterInfoBase + 0x40]) = character.hairStyle << 10; *reinterpret_cast<uint32*>(&outgoingPacket[characterInfoBase + 0x48]) = character.voice; *reinterpret_cast<uint32*>(&outgoingPacket[characterInfoBase + 0x50]) = character.weapon1; //weapon 1 *reinterpret_cast<uint32*>(&outgoingPacket[characterInfoBase + 0x58]) = character.weapon2; //weapon 2? // *reinterpret_cast<uint32*>(&outgoingPacket[characterInfoBase + 0x68]) = 0; //weapon 3? *reinterpret_cast<uint32*>(&outgoingPacket[characterInfoBase + 0x88]) = character.headGear; //headGear *reinterpret_cast<uint32*>(&outgoingPacket[characterInfoBase + 0x90]) = character.bodyGear; //bodyGear *reinterpret_cast<uint32*>(&outgoingPacket[characterInfoBase + 0x98]) = character.legsGear; //legsGear *reinterpret_cast<uint32*>(&outgoingPacket[characterInfoBase + 0xA0]) = character.handsGear; //handsGear *reinterpret_cast<uint32*>(&outgoingPacket[characterInfoBase + 0xA8]) = character.feetGear; //feetGear *reinterpret_cast<uint32*>(&outgoingPacket[characterInfoBase + 0xB0]) = character.waistGear; //waistGear // *reinterpret_cast<uint32*>(&outgoingPacket[characterInfoBase + 0xB8]) = 0; //??? *reinterpret_cast<uint32*>(&outgoingPacket[characterInfoBase + 0xC0]) = character.rightEarGear; //rightEarGear *reinterpret_cast<uint32*>(&outgoingPacket[characterInfoBase + 0xC8]) = character.leftEarGear; //leftEarGear // *reinterpret_cast<uint32*>(&outgoingPacket[characterInfoBase + 0xD0]) = 0; //??? // *reinterpret_cast<uint32*>(&outgoingPacket[characterInfoBase + 0xD8]) = 0; //??? *reinterpret_cast<uint32*>(&outgoingPacket[characterInfoBase + 0xE0]) = character.rightFingerGear; //rightFingerGear *reinterpret_cast<uint32*>(&outgoingPacket[characterInfoBase + 0xE8]) = character.leftFingerGear; //leftFingerGear //Insert character name for(unsigned int i = 0; i < character.name.size(); i++) { outgoingPacket[characterInfoBase + 0x14C + i] = character.name[i]; } outgoingPacket[characterInfoBase + 0x14C + character.name.size()] = 0; return outgoingPacket; }
void CLobbyServerPlayer::ProcessStartSession(const PacketData& packetData) { uint32 clientTime = *reinterpret_cast<const uint32*>(&packetData[0x84]); //We assume clientTime is 0x50E0E812, but we need to generate a proper key later uint8 blowfishKey[0x10] = { 0xB4, 0xEE, 0x3F, 0x6C, 0x01, 0x6F, 0x5B, 0xD9, 0x71, 0x50, 0x0D, 0xB1, 0x85, 0xA2, 0xAB, 0x43 }; InitializeBlowfish(reinterpret_cast<char*>(blowfishKey), 0x10); CLog::GetInstance().LogMessage(LOG_NAME, "Received encryption key: 0x%0.8X.\r\n", clientTime); //Respond with acknowledgment std::vector<uint8> outgoingPacket(std::begin(g_secureConnectionAcknowledgment), std::end(g_secureConnectionAcknowledgment)); CPacketUtils::EncryptPacket(outgoingPacket); QueuePacket(outgoingPacket); }
void CLobbyServerPlayer::ProcessSelectCharacter(const PacketData& packetData) { uint32 characterId = *reinterpret_cast<const uint32*>(&packetData[0x28]); CLog::GetInstance().LogMessage(LOG_NAME, "SelectCharacter(id = %d).", characterId); const char* gameServerAddress = CAppConfig::GetInstance().GetPreferenceString(PREF_FFXIVD_GAMESERVER_ADDRESS); std::vector<uint8> outgoingPacket(std::begin(g_selectCharacterPacket), std::end(g_selectCharacterPacket)); *reinterpret_cast<uint32*>(outgoingPacket.data() + 0x38) = characterId; //Character Id (normally the actor id which is different from the id passed in that packet) *reinterpret_cast<uint16*>(outgoingPacket.data() + 0x86) = CGameServer::GAME_SERVER_PORT; strcpy(reinterpret_cast<char*>(outgoingPacket.data() + 0x88), gameServerAddress); CPacketUtils::EncryptPacket(outgoingPacket); QueuePacket(outgoingPacket); }
void CGameServerPlayer::SpawnNpc(uint32 id, uint32 appearanceId, uint32 stringId, float x, float y, float z, float angle) { PacketData outgoingPacket(std::begin(g_spawnNpc), std::end(g_spawnNpc)); uint32 packetIndex = 0x10; while(packetIndex < outgoingPacket.size()) { auto packetPtr = outgoingPacket.data() + packetIndex; uint16 subPacketSize = *reinterpret_cast<uint16*>(packetPtr + 0x00); uint16 subPacketCmd = *reinterpret_cast<uint16*>(packetPtr + 0x12); *reinterpret_cast<uint32*>(packetPtr + 0x4) = id; if(subPacketCmd == 0xCE || subPacketCmd == 0xCF) { *reinterpret_cast<float*>(packetPtr + 0x28) = x; *reinterpret_cast<float*>(packetPtr + 0x2C) = y; *reinterpret_cast<float*>(packetPtr + 0x30) = z; *reinterpret_cast<float*>(packetPtr + 0x34) = angle; } else if(subPacketCmd == 0xCC) { static int magicNumber = 0; *reinterpret_cast<uint8*>(packetPtr + 0x40) = 0x30 + magicNumber; magicNumber++; } else if(subPacketCmd == 0xD6) { *reinterpret_cast<uint32*>(packetPtr + 0x20) = appearanceId; } else if(subPacketCmd == 0x13D) { *reinterpret_cast<uint32*>(packetPtr + 0x20) = stringId; } packetIndex += subPacketSize; } assert(packetIndex == outgoingPacket.size()); { auto enemyActor = std::make_unique<CEnemyActor>(); enemyActor->GlobalPacketReady.connect([&] (CActor* actor, const PacketPtr& packet) { QueueToCurrentComposite(actor, packet); }); enemyActor->SetId(id); enemyActor->SetHp(ENEMY_INITIAL_HP); m_instance.AddActor(std::move(enemyActor)); } QueuePacket(outgoingPacket); }
void CLobbyServerPlayer::ProcessSessionAcknowledgement(const PacketData& packetData) { std::string sessionId = reinterpret_cast<const char*>(&packetData[0x30]); std::string clientVersion = reinterpret_cast<const char*>(&packetData[0x70]); CLog::GetInstance().LogMessage(LOG_NAME, "Got acknowledgment for secure session."); CLog::GetInstance().LogMessage(LOG_NAME, "SESSION_ID: %s", sessionId.c_str()); CLog::GetInstance().LogMessage(LOG_NAME, "CLIENT_VERSION: %s", clientVersion.c_str()); if(m_dbConnection.IsEmpty()) { CLog::GetInstance().LogMessage(LOG_NAME, "No database connection available. Bailing."); m_disconnect = true; return; } try { auto query = string_format("SELECT userId FROM ffxiv_sessions WHERE id = '%s' AND expiration > NOW()", sessionId.c_str()); auto result = m_dbConnection.Query(query.c_str()); if(result.GetRowCount() == 0) { throw std::runtime_error("Session expired or doesn't exist."); } auto row = result.FetchRow(); assert(row != nullptr); assert(result.GetFieldCount() == 1); m_userId = boost::lexical_cast<uint32>(row[0]); CLog::GetInstance().LogMessage(LOG_NAME, "User (id: %u) logged in.", m_userId); } catch(const std::exception& exception) { CLog::GetInstance().LogError(LOG_NAME, "Failed to validate user session (id: %s): %s.", sessionId.c_str(), exception.what()); m_disconnect = true; return; } std::vector<uint8> outgoingPacket(std::begin(g_loginAcknowledgment), std::end(g_loginAcknowledgment)); CPacketUtils::EncryptPacket(outgoingPacket); QueuePacket(outgoingPacket); }
void CGameServerPlayer::SendTeleportSequence(uint32 levelId, uint32 musicId, float x, float y, float z, float angle) { QueuePacket(PacketData(std::begin(g_client0_moor1), std::end(g_client0_moor1))); QueuePacket(PacketData(std::begin(g_client0_moor2), std::end(g_client0_moor2))); QueuePacket(PacketData(std::begin(g_client0_moor3), std::end(g_client0_moor3))); QueuePacket(PacketData(std::begin(g_client0_moor4), std::end(g_client0_moor4))); QueuePacket(PacketData(std::begin(g_client0_moor5), std::end(g_client0_moor5))); QueuePacket(PacketData(std::begin(g_client0_moor6), std::end(g_client0_moor6))); QueuePacket(PacketData(std::begin(g_client0_moor7), std::end(g_client0_moor7))); QueuePacket(PacketData(std::begin(g_client0_moor8), std::end(g_client0_moor8))); QueuePacket(PacketData(std::begin(g_client0_moor9), std::end(g_client0_moor9))); { CCompositePacket result; { CSetMusicPacket packet; packet.SetSourceId(PLAYER_ID); packet.SetTargetId(PLAYER_ID); packet.SetMusicId(musicId); result.AddPacket(packet.ToPacketData()); } { CSetWeatherPacket packet; packet.SetSourceId(PLAYER_ID); packet.SetTargetId(PLAYER_ID); packet.SetWeatherId(CSetWeatherPacket::WEATHER_CLEAR); result.AddPacket(packet.ToPacketData()); } { CSetMapPacket packet; packet.SetSourceId(PLAYER_ID); packet.SetTargetId(PLAYER_ID); packet.SetMapId(levelId); result.AddPacket(packet.ToPacketData()); } QueuePacket(result.ToPacketData()); } QueuePacket(PacketData(std::begin(g_client0_moor11), std::end(g_client0_moor11))); QueuePacket(PacketData(std::begin(g_client0_moor12), std::end(g_client0_moor12))); { PacketData outgoingPacket(std::begin(g_client0_moor13), std::end(g_client0_moor13)); { const uint32 setInitialPositionBase = 0x360; CSetInitialPositionPacket setInitialPosition; setInitialPosition.SetSourceId(PLAYER_ID); setInitialPosition.SetTargetId(PLAYER_ID); setInitialPosition.SetX(x); setInitialPosition.SetY(y); setInitialPosition.SetZ(z); setInitialPosition.SetAngle(angle); auto setInitialPositionPacket = setInitialPosition.ToPacketData(); memcpy(outgoingPacket.data() + setInitialPositionBase, setInitialPositionPacket.data(), setInitialPositionPacket.size()); } QueuePacket(outgoingPacket); } QueuePacket(GetInventoryInfo()); QueuePacket(PacketData(std::begin(g_client0_moor21), std::end(g_client0_moor21))); //QueuePacket(PacketData(std::begin(g_client0_moor22), std::end(g_client0_moor22))); if(!m_zoneMasterCreated) { //Zone Master QueuePacket(PacketData(std::begin(g_client0_moor23), std::end(g_client0_moor23))); /* QueuePacket(PacketData(std::begin(g_client0_moor24), std::end(g_client0_moor24))); QueuePacket(PacketData(std::begin(g_client0_moor25), std::end(g_client0_moor25))); QueuePacket(PacketData(std::begin(g_client0_moor26), std::end(g_client0_moor26))); QueuePacket(PacketData(std::begin(g_client0_moor27), std::end(g_client0_moor27))); QueuePacket(PacketData(std::begin(g_client0_moor28), std::end(g_client0_moor28))); QueuePacket(PacketData(std::begin(g_client0_moor29), std::end(g_client0_moor29))); QueuePacket(PacketData(std::begin(g_client0_moor30), std::end(g_client0_moor30))); QueuePacket(PacketData(std::begin(g_client0_moor31), std::end(g_client0_moor31))); QueuePacket(PacketData(std::begin(g_client0_moor32), std::end(g_client0_moor32))); QueuePacket(PacketData(std::begin(g_client0_moor33), std::end(g_client0_moor33))); QueuePacket(PacketData(std::begin(g_client0_moor34), std::end(g_client0_moor34))); QueuePacket(PacketData(std::begin(g_client0_moor35), std::end(g_client0_moor35))); QueuePacket(PacketData(std::begin(g_client0_moor36), std::end(g_client0_moor36))); QueuePacket(PacketData(std::begin(g_client0_moor37), std::end(g_client0_moor37))); */ //Enables chat? // QueuePacket(PacketData(std::begin(g_client0_moor38), std::end(g_client0_moor38))); { CCompositePacket packet; packet.AddPacket(PacketData(std::begin(g_client0_moor38), std::end(g_client0_moor38))); QueuePacket(packet.ToPacketData()); } // QueuePacket(PacketData(std::begin(g_client0_moor39), std::end(g_client0_moor39))); // QueuePacket(PacketData(std::begin(g_client0_moor40), std::end(g_client0_moor40))); ResetInstance(); //Only makes sense in Black Shroud for now if(levelId == CSetMapPacket::MAP_BLACKSHROUD) { const auto& actorDatabase = CGlobalData::GetInstance().GetActorDatabase(); for(const auto& actorInfo : actorDatabase.GetActors()) { SpawnNpc(actorInfo.id, actorInfo.baseModelId, actorInfo.nameStringId, std::get<0>(actorInfo.pos), std::get<1>(actorInfo.pos), std::get<2>(actorInfo.pos), 0); } } m_zoneMasterCreated = true; } }
void CLobbyServerPlayer::ProcessGetCharacters(const PacketData& packetData) { CLog::GetInstance().LogMessage(LOG_NAME, "GetCharacters"); if(m_dbConnection.IsEmpty()) { CLog::GetInstance().LogMessage(LOG_NAME, "No database connection available. Bailing."); m_disconnect = true; return; } PacketData outgoingPacket(std::begin(g_characterListPacket), std::end(g_characterListPacket)); CCharacter character; try { auto query = string_format("SELECT * FROM ffxiv_characters WHERE userId = %d", m_userId); auto result = m_dbConnection.Query(query.c_str()); if(result.GetRowCount() != 0) { character = CCharacter(result); } } catch(const std::exception& exception) { CLog::GetInstance().LogError(LOG_NAME, "Failed to fetch characters for user (id = %d): %s", m_userId, exception.what()); m_disconnect = true; return; } PacketData characterData(std::begin(g_characterData), std::end(g_characterData)); characterData[0x21] = CCharacter::GetModelFromTribe(character.tribe); characterData[0x9F] = character.tribe; characterData[0xC7] = character.guardian; characterData[0xC8] = character.birthMonth; characterData[0xC9] = character.birthDay; characterData[0xE8] = character.allegiance; *reinterpret_cast<uint32*>(&characterData[0x25]) = character.size; //size *reinterpret_cast<uint32*>(&characterData[0x29]) = character.GetColorInfo(); //hairColor + skinColor *reinterpret_cast<uint32*>(&characterData[0x2D]) = character.GetFaceInfo(); //face Stuff? *reinterpret_cast<uint32*>(&characterData[0x31]) = character.hairStyle << 10; //hair model *reinterpret_cast<uint32*>(&characterData[0x35]) = character.voice; //voice *reinterpret_cast<uint32*>(&characterData[0x39]) = character.weapon1; //weapon1 *reinterpret_cast<uint32*>(&characterData[0x3D]) = character.weapon2; //weapon2 *reinterpret_cast<uint32*>(&characterData[0x55]) = character.headGear; //headGear *reinterpret_cast<uint32*>(&characterData[0x59]) = character.bodyGear; //bodyGear *reinterpret_cast<uint32*>(&characterData[0x5D]) = character.legsGear; //legsGear *reinterpret_cast<uint32*>(&characterData[0x61]) = character.handsGear; //handsGear *reinterpret_cast<uint32*>(&characterData[0x65]) = character.feetGear; //feetGear *reinterpret_cast<uint32*>(&characterData[0x69]) = character.waistGear; //waistGear // *reinterpret_cast<uint32*>(&characterData[0x6D]) = 0; //??? *reinterpret_cast<uint32*>(&characterData[0x71]) = character.rightEarGear; //rightEarGear *reinterpret_cast<uint32*>(&characterData[0x75]) = character.leftEarGear; //leftEarGear // *reinterpret_cast<uint32*>(&characterData[0x79]) = 0; //??? // *reinterpret_cast<uint32*>(&characterData[0x7D]) = 0; //??? *reinterpret_cast<uint32*>(&characterData[0x81]) = character.rightFingerGear; //rightFingerGear *reinterpret_cast<uint32*>(&characterData[0x85]) = character.leftFingerGear; //leftFingerGear auto encodedCharacterData = Framework::ToBase64(characterData.data(), characterData.size()); std::replace(std::begin(encodedCharacterData), std::end(encodedCharacterData), '+', '-'); std::replace(std::begin(encodedCharacterData), std::end(encodedCharacterData), '/', '_'); static const uint32 characterInfoBase = 0x860; if(character.active) { for(unsigned int i = 0; i < encodedCharacterData.size(); i++) { outgoingPacket[characterInfoBase + 0x40 + i] = encodedCharacterData[i]; } *reinterpret_cast<uint32*>(&outgoingPacket[characterInfoBase + 0x00]) = 0x0158E7FC; *reinterpret_cast<uint32*>(&outgoingPacket[characterInfoBase + 0x04]) = character.id; *reinterpret_cast<uint32*>(&outgoingPacket[characterInfoBase + 0x0C]) = 0x000000F4; //Insert character name for(unsigned int i = 0; i < character.name.size(); i++) { outgoingPacket[characterInfoBase + 0x10 + i] = character.name[i]; } outgoingPacket[characterInfoBase + 0x10 + character.name.size()] = 0; } CPacketUtils::EncryptPacket(outgoingPacket); QueuePacket(outgoingPacket); }