<commit_before>#include "GameConnection.h"

#include <Common.h>
#include <Network/CommonNetwork.h>
#include <Util/Util.h>
#include <Logging/Logger.h>
#include <Network/GamePacket.h>
#include <Network/PacketDef/Lobby/ServerLobbyDef.h>
#include <Network/GamePacketParser.h>
#include <Crypt/md5.h>
#include <Crypt/blowfish.h>
#include <Config/ConfigMgr.h>

#include "ServerLobby.h"
#include "RestConnector.h"
#include "LobbySession.h"

#include "Forwards.h"

using namespace Sapphire;
using namespace Sapphire::Network::Packets;
using namespace Sapphire::Network::Packets::Server;

extern Lobby::ServerLobby g_serverLobby;
extern Lobby::RestConnector g_restConnector;

Lobby::GameConnection::GameConnection( Sapphire::Network::HivePtr pHive,
                                                Sapphire::Network::AcceptorPtr pAcceptor,
                                                FrameworkPtr pFw ) :
  Sapphire::Network::Connection( pHive, pFw ),
  m_pAcceptor( pAcceptor ),
  m_bEncryptionInitialized( false )
{
}

Lobby::GameConnection::~GameConnection()
{

}


// overwrite the parents onConnect for our game socket needs
void Lobby::GameConnection::onAccept( const std::string& host, uint16_t port )
{
  auto connection = make_GameConnection( m_hive, m_pAcceptor, m_pFw );
  m_pAcceptor->accept( connection );

  Logger::info( "Connect from {0}", m_socket.remote_endpoint().address().to_string() );
}


void Lobby::GameConnection::onDisconnect()
{
  Logger::debug( "DISCONNECT" );
}

void Lobby::GameConnection::onRecv( std::vector< uint8_t >& buffer )
{
  m_packets.insert( std::end( m_packets ), std::begin( buffer ), std::end( buffer ) );
  // This is assumed packet always start with valid FFXIVARR_PACKET_HEADER for now.
  FFXIVARR_PACKET_HEADER packetHeader{};
  const auto headerResult = getHeader( m_packets, 0, packetHeader );

  if( headerResult == Incomplete )
    return;

  if( headerResult == Malformed )
  {
    Logger::info( "Dropping connection due to malformed packet header." );
    disconnect();
    return;
  }

  // Dissect packet list
  std::vector< FFXIVARR_PACKET_RAW > packetList;
  const auto packetResult = getPackets( m_packets, sizeof( struct FFXIVARR_PACKET_HEADER ),
                                        packetHeader, packetList );

  if( packetResult == Incomplete )
    return;

  if( packetResult == Malformed )
  {
    Logger::info( "Dropping connection due to malformed packets." );
    disconnect();
    return;
  }

  // Handle it
  handlePackets( packetHeader, packetList );
  m_packets.clear();

}

void Lobby::GameConnection::onError( const asio::error_code& error )
{
  Logger::info( "GameConnection closed: {0}", error.message() );
}

void
Lobby::GameConnection::sendError( uint64_t sequence, uint32_t errorcode, uint16_t messageId, uint32_t tmpId )
{
  auto errorPacket = makeLobbyPacket< FFXIVIpcLobbyError >( tmpId );
  errorPacket->data().seq = sequence;
  errorPacket->data().error_id = errorcode;
  errorPacket->data().message_id = messageId;

  LobbyPacketContainer pRP( m_encKey );
  pRP.addPacket( errorPacket );
  sendPacket( pRP );
}

void Lobby::GameConnection::getCharList( FFXIVARR_PACKET_RAW& packet, uint32_t tmpId )
{
  uint64_t sequence = *reinterpret_cast< uint64_t* >( &packet.data[ 0 ] + 0x10 );
  Logger::info( "Sequence [{0}]", sequence );

  Logger::info( "[{0}] ReqCharList", m_pSession->getAccountID() );
  LobbyPacketContainer pRP( m_encKey );

  auto serverListPacket = makeLobbyPacket< FFXIVIpcServerList >( tmpId );
  serverListPacket->data().seq = 1;
  serverListPacket->data().offset = 0;
  serverListPacket->data().numServers = 1;
  serverListPacket->data().server[ 0 ].id = g_serverLobby.getConfig().global.general.worldID;
  serverListPacket->data().server[ 0 ].index = 0;
  serverListPacket->data().final = 1;
  strcpy( serverListPacket->data().server[ 0 ].name, g_serverLobby.getConfig().worldName.c_str() );
  pRP.addPacket( serverListPacket );

  auto retainerListPacket = makeLobbyPacket< FFXIVIpcRetainerList >( tmpId );
  retainerListPacket->data().padding[ 8 ] = 1;
  pRP.addPacket( retainerListPacket );

  sendPacket( pRP );

  auto charList = g_restConnector.getCharList( ( char* ) m_pSession->getSessionId() );

  uint32_t charIndex = 0;

  for( uint8_t i = 0; i < 4; i++ )
  {
    auto charListPacket = makeLobbyPacket< FFXIVIpcCharList >( tmpId );
    charListPacket->data().seq = sequence;
    charListPacket->data().numInPacket = 2;
    charListPacket->data().counter = i * 4;

    for( uint8_t j = 0; j < 2; j++ )
    {
      if( charIndex < charList.size() && charList.size() != 0 )
      {
        FFXIVIpcCharList::CharaDetails details;
        memset( &details, 0, sizeof( FFXIVIpcCharList::CharaDetails ) );

        auto& charEntry = charList[ charIndex ];
        details.uniqueId = std::get< 1 >( charEntry );
        details.contentId = std::get< 2 >( charEntry );
        details.serverId = g_serverLobby.getConfig().global.general.worldID;
        details.serverId1 = g_serverLobby.getConfig().global.general.worldID;
        details.index = charIndex;
        strcpy( details.charDetailJson, std::get< 3 >( charEntry ).c_str() );
        strcpy( details.nameChara, std::get< 0 >( charEntry ).c_str() );
        strcpy( details.nameServer, g_serverLobby.getConfig().worldName.c_str() );
        strcpy( details.nameServer1, g_serverLobby.getConfig().worldName.c_str() );

        charListPacket->data().charaDetails[ j ] = details;

        Logger::debug( "[{0}] {1} - {2} - {3} - {4} - {5}",
                       charIndex,
                       details.index,
                       std::get< 0 >( charEntry ),
                       std::get< 1 >( charEntry ),
                       std::get< 2 >( charEntry ),
                       std::get< 3 >( charEntry ) );
      }
      charIndex++;
    }


    // TODO: Eventually move to account info storage
    if( i == 3 )
    {
      charListPacket->data().entitledExpansion = 2;
      charListPacket->data().maxCharOnWorld = 25;
      charListPacket->data().unknown8 = 8;
      charListPacket->data().veteranRank = 12;
      charListPacket->data().counter = ( i * 4 ) + 1;
      charListPacket->data().unknown4 = 128;
    }
    LobbyPacketContainer pRP( m_encKey );
    pRP.addPacket( charListPacket );
    sendPacket( pRP );

  }
}

void Lobby::GameConnection::enterWorld( FFXIVARR_PACKET_RAW& packet, uint32_t tmpId )<commit_msg>enable viera/hrothgar character creation<commit_after>#include "GameConnection.h"

#include <Common.h>
#include <Network/CommonNetwork.h>
#include <Util/Util.h>
#include <Logging/Logger.h>
#include <Network/GamePacket.h>
#include <Network/PacketDef/Lobby/ServerLobbyDef.h>
#include <Network/GamePacketParser.h>
#include <Crypt/md5.h>
#include <Crypt/blowfish.h>
#include <Config/ConfigMgr.h>

#include "ServerLobby.h"
#include "RestConnector.h"
#include "LobbySession.h"

#include "Forwards.h"

using namespace Sapphire;
using namespace Sapphire::Network::Packets;
using namespace Sapphire::Network::Packets::Server;

extern Lobby::ServerLobby g_serverLobby;
extern Lobby::RestConnector g_restConnector;

Lobby::GameConnection::GameConnection( Sapphire::Network::HivePtr pHive,
                                                Sapphire::Network::AcceptorPtr pAcceptor,
                                                FrameworkPtr pFw ) :
  Sapphire::Network::Connection( pHive, pFw ),
  m_pAcceptor( pAcceptor ),
  m_bEncryptionInitialized( false )
{
}

Lobby::GameConnection::~GameConnection()
{

}


// overwrite the parents onConnect for our game socket needs
void Lobby::GameConnection::onAccept( const std::string& host, uint16_t port )
{
  auto connection = make_GameConnection( m_hive, m_pAcceptor, m_pFw );
  m_pAcceptor->accept( connection );

  Logger::info( "Connect from {0}", m_socket.remote_endpoint().address().to_string() );
}


void Lobby::GameConnection::onDisconnect()
{
  Logger::debug( "DISCONNECT" );
}

void Lobby::GameConnection::onRecv( std::vector< uint8_t >& buffer )
{
  m_packets.insert( std::end( m_packets ), std::begin( buffer ), std::end( buffer ) );
  // This is assumed packet always start with valid FFXIVARR_PACKET_HEADER for now.
  FFXIVARR_PACKET_HEADER packetHeader{};
  const auto headerResult = getHeader( m_packets, 0, packetHeader );

  if( headerResult == Incomplete )
    return;

  if( headerResult == Malformed )
  {
    Logger::info( "Dropping connection due to malformed packet header." );
    disconnect();
    return;
  }

  // Dissect packet list
  std::vector< FFXIVARR_PACKET_RAW > packetList;
  const auto packetResult = getPackets( m_packets, sizeof( struct FFXIVARR_PACKET_HEADER ),
                                        packetHeader, packetList );

  if( packetResult == Incomplete )
    return;

  if( packetResult == Malformed )
  {
    Logger::info( "Dropping connection due to malformed packets." );
    disconnect();
    return;
  }

  // Handle it
  handlePackets( packetHeader, packetList );
  m_packets.clear();

}

void Lobby::GameConnection::onError( const asio::error_code& error )
{
  Logger::info( "GameConnection closed: {0}", error.message() );
}

void
Lobby::GameConnection::sendError( uint64_t sequence, uint32_t errorcode, uint16_t messageId, uint32_t tmpId )
{
  auto errorPacket = makeLobbyPacket< FFXIVIpcLobbyError >( tmpId );
  errorPacket->data().seq = sequence;
  errorPacket->data().error_id = errorcode;
  errorPacket->data().message_id = messageId;

  LobbyPacketContainer pRP( m_encKey );
  pRP.addPacket( errorPacket );
  sendPacket( pRP );
}

void Lobby::GameConnection::getCharList( FFXIVARR_PACKET_RAW& packet, uint32_t tmpId )
{
  uint64_t sequence = *reinterpret_cast< uint64_t* >( &packet.data[ 0 ] + 0x10 );
  Logger::info( "Sequence [{0}]", sequence );

  Logger::info( "[{0}] ReqCharList", m_pSession->getAccountID() );
  LobbyPacketContainer pRP( m_encKey );

  auto serverListPacket = makeLobbyPacket< FFXIVIpcServerList >( tmpId );
  serverListPacket->data().seq = 1;
  serverListPacket->data().offset = 0;
  serverListPacket->data().numServers = 1;
  serverListPacket->data().server[ 0 ].id = g_serverLobby.getConfig().global.general.worldID;
  serverListPacket->data().server[ 0 ].index = 0;
  serverListPacket->data().final = 1;
  strcpy( serverListPacket->data().server[ 0 ].name, g_serverLobby.getConfig().worldName.c_str() );
  pRP.addPacket( serverListPacket );

  auto retainerListPacket = makeLobbyPacket< FFXIVIpcRetainerList >( tmpId );
  retainerListPacket->data().padding[ 8 ] = 1;
  pRP.addPacket( retainerListPacket );

  sendPacket( pRP );

  auto charList = g_restConnector.getCharList( ( char* ) m_pSession->getSessionId() );

  uint32_t charIndex = 0;

  for( uint8_t i = 0; i < 4; i++ )
  {
    auto charListPacket = makeLobbyPacket< FFXIVIpcCharList >( tmpId );
    charListPacket->data().seq = sequence;
    charListPacket->data().numInPacket = 2;
    charListPacket->data().counter = i * 4;

    for( uint8_t j = 0; j < 2; j++ )
    {
      if( charIndex < charList.size() && charList.size() != 0 )
      {
        FFXIVIpcCharList::CharaDetails details;
        memset( &details, 0, sizeof( FFXIVIpcCharList::CharaDetails ) );

        auto& charEntry = charList[ charIndex ];
        details.uniqueId = std::get< 1 >( charEntry );
        details.contentId = std::get< 2 >( charEntry );
        details.serverId = g_serverLobby.getConfig().global.general.worldID;
        details.serverId1 = g_serverLobby.getConfig().global.general.worldID;
        details.index = charIndex;
        strcpy( details.charDetailJson, std::get< 3 >( charEntry ).c_str() );
        strcpy( details.nameChara, std::get< 0 >( charEntry ).c_str() );
        strcpy( details.nameServer, g_serverLobby.getConfig().worldName.c_str() );
        strcpy( details.nameServer1, g_serverLobby.getConfig().worldName.c_str() );

        charListPacket->data().charaDetails[ j ] = details;

        Logger::debug( "[{0}] {1} - {2} - {3} - {4} - {5}",
                       charIndex,
                       details.index,
                       std::get< 0 >( charEntry ),
                       std::get< 1 >( charEntry ),
                       std::get< 2 >( charEntry ),
                       std::get< 3 >( charEntry ) );
      }
      charIndex++;
    }


    // TODO: Eventually move to account info storage
    if( i == 3 )
    {
      charListPacket->data().entitledExpansion = 3;
      charListPacket->data().maxCharOnWorld = 25;
      charListPacket->data().unknown8 = 8;
      charListPacket->data().veteranRank = 12;
      charListPacket->data().counter = ( i * 4 ) + 1;
      charListPacket->data().unknown4 = 128;
    }
    LobbyPacketContainer pRP( m_encKey );
    pRP.addPacket( charListPacket );
    sendPacket( pRP );

  }
}

void Lobby::GameConnection::enterWorld( FFXIVARR_PACKET_RAW& packet, uint32_t tmpId )
{'fraction_non_alphanumeric': 0.13530375107229198, 'fraction_numerical': 0.012789518833346331, 'mean_word_length': 3.491768826619965, 'pattern_counts': {'":': 0, '<': 59, '<?xml version=': 0, '>': 101, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 10, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3923821', 'n_tokens_mistral': 4334, 'n_tokens_neox': 4131, 'n_words': 855}