Initial MSVC 2008 projects workspace
This commit is contained in:
110
L2C_Server/net/ClientPacketHandler.cpp
Normal file
110
L2C_Server/net/ClientPacketHandler.cpp
Normal file
@@ -0,0 +1,110 @@
|
||||
#include "pch.h"
|
||||
#include "Log.h"
|
||||
#include "l2c_utils.h"
|
||||
#include "net/GameClient/GameClient.h"
|
||||
#include "ClientPacketHandler.h"
|
||||
#include "ServerPackets.h"
|
||||
#include "GS.h"
|
||||
|
||||
ClientPacketHandler::ClientPacketHandler( GameClient *cl )
|
||||
{
|
||||
m_cl = cl;
|
||||
}
|
||||
|
||||
ClientPacketHandler::~ClientPacketHandler()
|
||||
{
|
||||
m_cl = NULL;
|
||||
}
|
||||
|
||||
void ClientPacketHandler::handlePacket( L2GamePacket *pack )
|
||||
{
|
||||
L2GamePacket *reply = NULL;
|
||||
unsigned char opcode = pack->getByteAt(2);
|
||||
|
||||
switch( m_cl->getState() )
|
||||
{
|
||||
case CLIENT_STATE_CONNECTED:
|
||||
{
|
||||
switch( opcode )
|
||||
{
|
||||
case 0x0E: reply = ProtocolVersion( pack ); break;
|
||||
case 0x2B: reply = AuthLogin( pack ); break;
|
||||
default: invalidPacket( pack, opcode, 0 ); break;
|
||||
}
|
||||
} break;
|
||||
case CLIENT_STATE_AUTHED:
|
||||
{
|
||||
switch( opcode )
|
||||
{
|
||||
case 0x00: reply = Logout( pack ); break;
|
||||
case 0x0C: reply = CharacterCreate( pack ); break;
|
||||
case 0x12: reply = CharacterSelect( pack ); break;
|
||||
case 0x13: reply = NewCharacter( pack ); break;
|
||||
case 0xD0:
|
||||
{
|
||||
unsigned int opcode2 = pack->getByteAt(3) | (pack->getByteAt(4) << 8);
|
||||
switch( opcode2 )
|
||||
{
|
||||
case 0x0036: reply = RequestGotoLobby( pack ); break;
|
||||
default: invalidPacket( pack, opcode, opcode2 ); break;
|
||||
}
|
||||
} break;
|
||||
default: invalidPacket( pack, opcode, 0 ); break;
|
||||
}
|
||||
} break;
|
||||
case CLIENT_STATE_IN_GAME:
|
||||
{
|
||||
switch( opcode )
|
||||
{
|
||||
case 0x00: reply = Logout( pack ); break;
|
||||
case 0xD0:
|
||||
{
|
||||
unsigned int opcode2 = pack->getByteAt(3) | (pack->getByteAt(4) << 8);
|
||||
switch( opcode2 )
|
||||
{
|
||||
case 0x0001: break; // RequestManorList
|
||||
default: invalidPacket( pack, opcode, opcode2 ); break;
|
||||
}
|
||||
} break;
|
||||
default: invalidPacket( pack, opcode, 0 ); break;
|
||||
}
|
||||
} break;
|
||||
}
|
||||
|
||||
if( reply )
|
||||
{
|
||||
m_cl->sendPacket( reply, true ); // true - delete reply immediately
|
||||
}
|
||||
}
|
||||
|
||||
void ClientPacketHandler::invalidPacket( L2GamePacket *p, unsigned int opcode, unsigned int opcode2 )
|
||||
{
|
||||
unsigned int plen = p->getPacketSize();
|
||||
unsigned char *buf = (unsigned char *)p->getBytesPtr();
|
||||
ClientState st = m_cl->getState();
|
||||
wchar_t sn[32] = {0};
|
||||
wcscpy( sn, L"Unknown" );
|
||||
switch( st )
|
||||
{
|
||||
case CLIENT_STATE_OFFLINE: wcscpy( sn, L"OFFLINE" ); break;
|
||||
case CLIENT_STATE_CONNECTED: wcscpy( sn, L"CONNECTED" ); break;
|
||||
case CLIENT_STATE_AUTHED: wcscpy( sn, L"AUTHED" ); break;
|
||||
case CLIENT_STATE_IN_GAME: wcscpy( sn, L"IN_GAME" ); break;
|
||||
}
|
||||
if( opcode2 == 0 )
|
||||
LogWarning( L"%s: Invalid packet 0x%02X (len %u) in state: [%s]", m_cl->toString(), opcode, plen, sn );
|
||||
else
|
||||
LogWarning( L"%s: Invalid packet 0x%02X:%04X (len %u) in state: [%s]", m_cl->toString(), opcode, opcode2, plen, sn );
|
||||
unsigned int i = 0;
|
||||
while( i < plen )
|
||||
{
|
||||
wchar_t str[32] = {0};
|
||||
swprintf( str, 32, L"%02X ", buf[i] );
|
||||
LogFull( false, false, RGB(200,200,200), RGB(0,0,0), str );
|
||||
if( i>0 && (i%16 == 0) ) LogFull( false, true, RGB(200,200,200), RGB(0,0,0), L"" );
|
||||
i++;
|
||||
}
|
||||
LogFull( false, true, RGB(128,0,0), RGB(255,255,255), L"" );
|
||||
LogFull( false, true, RGB(128,0,0), RGB(255,255,255), L"dump end" );
|
||||
}
|
||||
|
28
L2C_Server/net/ClientPacketHandler.h
Normal file
28
L2C_Server/net/ClientPacketHandler.h
Normal file
@@ -0,0 +1,28 @@
|
||||
#pragma once
|
||||
|
||||
class GameClient;
|
||||
|
||||
class ClientPacketHandler
|
||||
{
|
||||
public:
|
||||
ClientPacketHandler( GameClient *cl );
|
||||
~ClientPacketHandler();
|
||||
|
||||
public:
|
||||
void handlePacket( L2GamePacket *pack );
|
||||
|
||||
protected:
|
||||
L2GamePacket *ProtocolVersion( L2GamePacket *pack );
|
||||
L2GamePacket *AuthLogin( L2GamePacket *pack );
|
||||
L2GamePacket *NewCharacter( L2GamePacket *pack );
|
||||
L2GamePacket *CharacterCreate( L2GamePacket *pack );
|
||||
L2GamePacket *RequestGotoLobby( L2GamePacket *pack );
|
||||
L2GamePacket *Logout( L2GamePacket *pack );
|
||||
L2GamePacket *CharacterSelect( L2GamePacket *pack );
|
||||
|
||||
protected:
|
||||
void invalidPacket( L2GamePacket *p, unsigned int opcode, unsigned int opcode2 );
|
||||
|
||||
protected:
|
||||
GameClient *m_cl;
|
||||
};
|
237
L2C_Server/net/ClientPool.cpp
Normal file
237
L2C_Server/net/ClientPool.cpp
Normal file
@@ -0,0 +1,237 @@
|
||||
#include "pch.h"
|
||||
#include "Log.h"
|
||||
#include "ClientPool.h"
|
||||
#include "GS.h"
|
||||
#include "utils/Exception.h"
|
||||
|
||||
ClientPool::ClientPool()
|
||||
{
|
||||
m_clients = new std::vector<GameClient *>();
|
||||
}
|
||||
|
||||
ClientPool::~ClientPool()
|
||||
{
|
||||
if( m_clients )
|
||||
{
|
||||
delete m_clients;
|
||||
m_clients = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
int ClientPool::getCurrentOnline()
|
||||
{
|
||||
int ret = 0;
|
||||
m_lock.Lock();
|
||||
if( m_clients ) ret = m_clients->size();
|
||||
m_lock.Unlock();
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool ClientPool::addClient( SOCKET s_cl, const char *ip, int port )
|
||||
{
|
||||
if( !m_clients || !ip || (s_cl == INVALID_SOCKET) || (port == 0) ) return false;
|
||||
bool ret = false;
|
||||
m_lock.Lock();
|
||||
// check current online
|
||||
int max_online = GameServer::getInstance()->getMaxPlayers();
|
||||
int cur_online = m_clients->size();
|
||||
if( cur_online < max_online )
|
||||
{
|
||||
// create client
|
||||
GameClient *pl = new GameClient( s_cl, ip, port );
|
||||
if( pl )
|
||||
{
|
||||
m_clients->push_back( pl );
|
||||
ret = pl->startThread();
|
||||
}
|
||||
}
|
||||
else // maximum online reached
|
||||
{
|
||||
LogWarning( L"Maximum online count (%d) is reached, cannot accept new clients", max_online );
|
||||
ret = false;
|
||||
// close client connection
|
||||
L2PNet_shutdown( s_cl );
|
||||
L2PNet_closesocket( s_cl );
|
||||
}
|
||||
m_lock.Unlock();
|
||||
return ret;
|
||||
}
|
||||
|
||||
void ClientPool::disconnectAllPlayers()
|
||||
{
|
||||
if( !m_clients ) return;
|
||||
m_lock.Lock();
|
||||
try
|
||||
{
|
||||
std::vector<GameClient *>::iterator iter;
|
||||
for( iter = m_clients->begin(); iter != m_clients->end(); iter++ )
|
||||
{
|
||||
GameClient *pl = (*iter);
|
||||
if( pl )
|
||||
{
|
||||
pl->disconnectForceAndWaitThreadToStop( true, false );
|
||||
delete pl;
|
||||
}
|
||||
}
|
||||
m_clients->clear();
|
||||
}
|
||||
catch( std::exception& e )
|
||||
{
|
||||
LogError( L"ClientPool::disconnectAllPlayers(): excpt %S", e.what() );
|
||||
}
|
||||
catch( Exception& e )
|
||||
{
|
||||
LogError( L"ClientPool::disconnectAllPlayers(): Exception: %S", e.what() );
|
||||
e.logStackTrace();
|
||||
}
|
||||
m_lock.Unlock();
|
||||
}
|
||||
|
||||
bool ClientPool::disconnectPlayerByAccount( const wchar_t *accountName, bool reasonDualLogin )
|
||||
{
|
||||
if( !m_clients ) return false;
|
||||
bool ret = false;
|
||||
m_lock.Lock();
|
||||
try
|
||||
{
|
||||
std::vector<GameClient *>::iterator iter;
|
||||
for( iter = m_clients->begin(); iter != m_clients->end(); iter++ )
|
||||
{
|
||||
GameClient *pl = (*iter);
|
||||
if( pl )
|
||||
{
|
||||
if( wcscmp( accountName, pl->getAccount() ) == 0 )
|
||||
{
|
||||
pl->disconnectForceAndWaitThreadToStop( false, reasonDualLogin );
|
||||
m_clients->erase( iter );
|
||||
ret = true;
|
||||
delete pl;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch( std::exception& e )
|
||||
{
|
||||
LogError( L"ClientPool::disconnectPlayerByAccount( %s ): excpt %S", accountName, e.what() );
|
||||
}
|
||||
catch( Exception& e )
|
||||
{
|
||||
LogError( L"ClientPool::disconnectPlayerByAccount(): Exception: %S", e.what() );
|
||||
e.logStackTrace();
|
||||
}
|
||||
m_lock.Unlock();
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool ClientPool::notifyClientThreadEnded( GameClient *ptr )
|
||||
{
|
||||
if( !m_clients || !ptr ) return false;
|
||||
bool ret = false;
|
||||
m_lock.Lock();
|
||||
try
|
||||
{
|
||||
std::vector<GameClient *>::iterator iter;
|
||||
for( iter = m_clients->begin(); iter != m_clients->end(); iter++ )
|
||||
{
|
||||
GameClient *pl = (*iter);
|
||||
if( pl == ptr )
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
LogDebug( L"ClientPool: deleted player %s", pl->toString() );
|
||||
#endif
|
||||
m_clients->erase( iter );
|
||||
ret = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch( std::exception& e )
|
||||
{
|
||||
LogError( L"ClientPool::notifyClientThreadEnded(): excpt %S", e.what() );
|
||||
}
|
||||
catch( Exception& e )
|
||||
{
|
||||
LogError( L"ClientPool::notifyClientThreadEnded(): Exception: %S", e.what() );
|
||||
e.logStackTrace();
|
||||
}
|
||||
m_lock.Unlock();
|
||||
if( !ret )
|
||||
{
|
||||
LogWarning( L"ClientPool: not found player to del %s", ptr->toString() );
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
void ClientPool::notifyClientAuthResponse( const wchar_t *accountName, bool ok )
|
||||
{
|
||||
if( !m_clients || !accountName ) return;
|
||||
m_lock.Lock();
|
||||
try
|
||||
{
|
||||
std::vector<GameClient *>::iterator iter;
|
||||
for( iter = m_clients->begin(); iter != m_clients->end(); iter++ )
|
||||
{
|
||||
GameClient *pl = (*iter);
|
||||
if( pl )
|
||||
{
|
||||
if( wcscmp( pl->getAccount(), accountName ) == 0 )
|
||||
{
|
||||
if( !ok ) // client auth failed
|
||||
{
|
||||
pl->disconnectForceAndWaitThreadToStop( false, false );
|
||||
m_clients->erase( iter );
|
||||
delete pl;
|
||||
}
|
||||
else // auth ok
|
||||
{
|
||||
pl->notifySessionKeysOK();
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch( std::exception& e )
|
||||
{
|
||||
LogError( L"ClientPool::notifyClientAuthResponse(): excpt %S", e.what() );
|
||||
}
|
||||
catch( Exception& e )
|
||||
{
|
||||
LogError( L"ClientPool::notifyClientAuthResponse(): Exception: %S", e.what() );
|
||||
e.logStackTrace();
|
||||
}
|
||||
m_lock.Unlock();
|
||||
}
|
||||
|
||||
void ClientPool::dumpClientsToLog()
|
||||
{
|
||||
if( !m_clients ) return;
|
||||
int n = 0;
|
||||
Log( L"===== ClientPool clients dump =====" );
|
||||
m_lock.Lock();
|
||||
try
|
||||
{
|
||||
std::vector<GameClient *>::iterator iter;
|
||||
for( iter = m_clients->begin(); iter != m_clients->end(); iter++ )
|
||||
{
|
||||
GameClient *pl = (*iter);
|
||||
if( pl )
|
||||
{
|
||||
Log( L" %d: %s", n, pl->toString() );
|
||||
n++;
|
||||
}
|
||||
}
|
||||
m_clients->clear();
|
||||
}
|
||||
catch( std::exception& e )
|
||||
{
|
||||
LogError( L"ClientPool::dumpClientsToLog(): excpt %S", e.what() );
|
||||
}
|
||||
catch( Exception& e )
|
||||
{
|
||||
LogError( L"ClientPool::dumpClientsToLog(): Exception: %S", e.what() );
|
||||
e.logStackTrace();
|
||||
}
|
||||
m_lock.Unlock();
|
||||
Log( L"===== ClientPool clients dump end =====" );
|
||||
}
|
29
L2C_Server/net/ClientPool.h
Normal file
29
L2C_Server/net/ClientPool.h
Normal file
@@ -0,0 +1,29 @@
|
||||
#pragma once
|
||||
#include "l2c_utils.h"
|
||||
#include "net/GameClient/GameClient.h"
|
||||
|
||||
class ClientPool
|
||||
{
|
||||
public:
|
||||
ClientPool();
|
||||
~ClientPool();
|
||||
|
||||
public:
|
||||
int getCurrentOnline();
|
||||
|
||||
public:
|
||||
bool addClient( SOCKET s_cl, const char *ip, int port );
|
||||
|
||||
public:
|
||||
void disconnectAllPlayers();
|
||||
bool disconnectPlayerByAccount( const wchar_t *accountName, bool reasonDualLogin );
|
||||
bool notifyClientThreadEnded( GameClient *ptr );
|
||||
void notifyClientAuthResponse( const wchar_t *accountName, bool ok );
|
||||
|
||||
public:
|
||||
void dumpClientsToLog();
|
||||
|
||||
protected:
|
||||
CriticalSection m_lock;
|
||||
std::vector<GameClient *> *m_clients;
|
||||
};
|
115
L2C_Server/net/GameClient/GameClient.cpp
Normal file
115
L2C_Server/net/GameClient/GameClient.cpp
Normal file
@@ -0,0 +1,115 @@
|
||||
#include "pch.h"
|
||||
#include "l2c_utils.h"
|
||||
#include "GameClient.h"
|
||||
|
||||
GameClient::GameClient( SOCKET s_cl, const char *ip, int port )
|
||||
{
|
||||
setUnused();
|
||||
if( ip )
|
||||
{
|
||||
strncpy( m_ip, ip, 16 ); m_ip[16] = 0;
|
||||
l2c_ansi_to_unicode( m_ip, m_wip, 16 );
|
||||
}
|
||||
m_port = port;
|
||||
m_sock = s_cl;
|
||||
m_was_force_disconnected = false;
|
||||
m_flagStop = m_isRunning = false;
|
||||
swprintf( m_tostring, 128, L"Client [IP: %s:%d]", m_wip, m_port );
|
||||
m_ph = new ClientPacketHandler( this );
|
||||
}
|
||||
|
||||
GameClient::~GameClient()
|
||||
{
|
||||
if( m_ph )
|
||||
{
|
||||
delete m_ph;
|
||||
m_ph = NULL;
|
||||
}
|
||||
if( m_obf )
|
||||
{
|
||||
delete m_obf;
|
||||
m_obf = NULL;
|
||||
}
|
||||
if( m_player )
|
||||
{
|
||||
delete m_player; // really? some notification?
|
||||
m_player = NULL;
|
||||
}
|
||||
setUnused();
|
||||
}
|
||||
|
||||
void GameClient::setUnused()
|
||||
{
|
||||
// zero our members
|
||||
m_account[0] = 0;
|
||||
memset( m_playKey, 0, sizeof(m_playKey) );
|
||||
memset( m_loginKey, 0, sizeof(m_loginKey) );
|
||||
m_ip[0] = 0;
|
||||
m_wip[0] = 0;
|
||||
m_port = 0;
|
||||
m_sock = INVALID_SOCKET;
|
||||
m_tostring[0] = 0;
|
||||
m_state = CLIENT_STATE_OFFLINE;
|
||||
m_xor_enabled = false;
|
||||
memset( m_xor_key_recv, 0, sizeof(m_xor_key_recv) );
|
||||
memset( m_xor_key_send, 0, sizeof(m_xor_key_send) );
|
||||
m_protocolIsOk = false;
|
||||
m_netStats.clear();
|
||||
m_opcodeObfuscationSeed = 0;
|
||||
m_obf = NULL;
|
||||
m_player = NULL;
|
||||
}
|
||||
|
||||
const wchar_t *GameClient::getAccount() const { return (const wchar_t *)m_account; }
|
||||
void GameClient::getPlayKey( unsigned char *buffer ) const { memcpy( buffer, m_playKey, 8 ); }
|
||||
void GameClient::getLoginKey( unsigned char *buffer ) const { memcpy( buffer, m_loginKey, 8 ); }
|
||||
const char *GameClient::getIpA() const { return (const char *)m_ip; }
|
||||
const wchar_t *GameClient::getIpW() const { return (const wchar_t *)m_wip; }
|
||||
int GameClient::getPort() const { return m_port; }
|
||||
const wchar_t *GameClient::toString() const { return (const wchar_t *)m_tostring; }
|
||||
ClientState GameClient::getState() const { return m_state; }
|
||||
bool GameClient::isProtocolOk() const { return m_protocolIsOk; }
|
||||
const GameClientNetStats *GameClient::getNetStats() const { return &m_netStats; }
|
||||
unsigned int GameClient::getOpcodeObfuscationSeed() const { return m_opcodeObfuscationSeed; }
|
||||
L2PCodeObfuscator *GameClient::getOpcodeObfuscator() { return m_obf; }
|
||||
GamePlayer *GameClient::getPlayer() { return m_player; }
|
||||
|
||||
void GameClient::setAccount( const wchar_t *acc )
|
||||
{
|
||||
if( acc )
|
||||
{
|
||||
wcsncpy( m_account, acc, sizeof(m_account)/sizeof(wchar_t) );
|
||||
m_account[sizeof(m_account)/sizeof(wchar_t) - 1] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void GameClient::setSessionKeys( const unsigned char *playKey, const unsigned char *loginKey )
|
||||
{
|
||||
memcpy( m_playKey, playKey, 8 );
|
||||
memcpy( m_loginKey, loginKey, 8 );
|
||||
}
|
||||
|
||||
void GameClient::setProtocolOk( bool b ) { m_protocolIsOk = b; }
|
||||
|
||||
void GameClient::setOpcodeObfuscationSeed( unsigned int s )
|
||||
{
|
||||
m_opcodeObfuscationSeed = s;
|
||||
if( m_obf )
|
||||
{
|
||||
delete m_obf;
|
||||
m_obf = NULL;
|
||||
}
|
||||
if( s != 0 )
|
||||
{
|
||||
m_obf = new L2PCodeObfuscator();
|
||||
m_obf->init_tables( m_opcodeObfuscationSeed );
|
||||
}
|
||||
}
|
||||
|
||||
void GameClient::setPlayer( GamePlayer *newPlayer, bool changeState, ClientState newState )
|
||||
{
|
||||
if( m_player ) delete m_player;
|
||||
m_player = NULL;
|
||||
if( newPlayer ) m_player = newPlayer;
|
||||
if( changeState ) m_state = newState;
|
||||
}
|
78
L2C_Server/net/GameClient/GameClient.h
Normal file
78
L2C_Server/net/GameClient/GameClient.h
Normal file
@@ -0,0 +1,78 @@
|
||||
#pragma once
|
||||
#include "enums.h"
|
||||
#include "net/ClientPacketHandler.h"
|
||||
#include "GameClientNetStats.h"
|
||||
#include "world/model/character/GamePlayer.h"
|
||||
|
||||
class GameClient
|
||||
{
|
||||
public:
|
||||
GameClient( SOCKET s_cl, const char *ip, int port );
|
||||
virtual ~GameClient();
|
||||
virtual void setUnused();
|
||||
|
||||
public:
|
||||
const wchar_t *getAccount() const;
|
||||
void getPlayKey( unsigned char *buffer ) const;
|
||||
void getLoginKey( unsigned char *buffer ) const;
|
||||
const char *getIpA() const;
|
||||
const wchar_t *getIpW() const;
|
||||
int getPort() const;
|
||||
const wchar_t *toString() const;
|
||||
ClientState getState() const;
|
||||
bool isProtocolOk() const;
|
||||
const GameClientNetStats *getNetStats() const;
|
||||
unsigned int getOpcodeObfuscationSeed() const;
|
||||
L2PCodeObfuscator *getOpcodeObfuscator();
|
||||
GamePlayer *getPlayer();
|
||||
|
||||
public:
|
||||
void setAccount( const wchar_t *acc );
|
||||
void setSessionKeys( const unsigned char *playKey, const unsigned char *loginKey );
|
||||
void setProtocolOk( bool b ) ;
|
||||
void setOpcodeObfuscationSeed( unsigned int s );
|
||||
void setPlayer( GamePlayer *newPlayer, bool changeState = false, ClientState newState = CLIENT_STATE_OFFLINE );
|
||||
|
||||
public:
|
||||
// begins client processing, starts thread
|
||||
bool startThread();
|
||||
// stops all client activity, disconnects socket, optionally sends packet before client close
|
||||
void disconnectForceAndWaitThreadToStop( bool server_shutdown, bool reasonDualLogin );
|
||||
// signal thread to stop (no wait to stop)
|
||||
void signalThreadStop( bool setMarkToDeleteSelfAndCleanupClientPool );
|
||||
bool sendPacket( L2GamePacket *pack, bool deleteAfterSend = false );
|
||||
void enable_XOR_crypt( bool bEnable, unsigned char *initial_key );
|
||||
void notifySessionKeysOK();
|
||||
|
||||
protected:
|
||||
// signals to stop and waits for thread to stop
|
||||
bool stopThread();
|
||||
static DWORD WINAPI ClientThread( LPVOID lpvParam );
|
||||
|
||||
protected:
|
||||
// informational stings
|
||||
char m_ip[16];
|
||||
wchar_t m_wip[16];
|
||||
int m_port;
|
||||
wchar_t m_account[128];
|
||||
wchar_t m_tostring[128];
|
||||
// network-related vars
|
||||
SOCKET m_sock;
|
||||
bool m_was_force_disconnected;
|
||||
bool m_flagStop;
|
||||
bool m_isRunning;
|
||||
CriticalSection m_cs_send;
|
||||
ClientState m_state;
|
||||
bool m_xor_enabled;
|
||||
unsigned char m_xor_key_send[16];
|
||||
unsigned char m_xor_key_recv[16];
|
||||
ClientPacketHandler *m_ph;
|
||||
bool m_protocolIsOk;
|
||||
GameClientNetStats m_netStats;
|
||||
unsigned int m_opcodeObfuscationSeed;
|
||||
L2PCodeObfuscator *m_obf;
|
||||
unsigned char m_playKey[8];
|
||||
unsigned char m_loginKey[8];
|
||||
//
|
||||
GamePlayer *m_player;
|
||||
};
|
67
L2C_Server/net/GameClient/GameClientNet.cpp
Normal file
67
L2C_Server/net/GameClient/GameClientNet.cpp
Normal file
@@ -0,0 +1,67 @@
|
||||
#include "pch.h"
|
||||
#include "Log.h"
|
||||
#include "l2c_utils.h"
|
||||
#include "GameClient.h"
|
||||
#include "GS.h"
|
||||
#include "../ServerPackets.h"
|
||||
#include "utils/Exception.h"
|
||||
|
||||
bool GameClient::sendPacket( L2GamePacket *pack, bool deleteAfterSend /*= false*/ )
|
||||
{
|
||||
if( !pack ) return false;
|
||||
if( m_sock == INVALID_SOCKET ) return false;
|
||||
//
|
||||
int r = 0;
|
||||
unsigned int sentLen = 0;
|
||||
unsigned int pack_size = pack->getPacketSize();
|
||||
bool ret = true;
|
||||
// encode xor if xor enabled
|
||||
if( m_xor_enabled )
|
||||
{
|
||||
// KeyPacket is first packet sent to client by server.
|
||||
// it is never encrypted
|
||||
if( m_netStats.ullPacketsSent > 0 )
|
||||
pack->encodeXOR( m_xor_key_send );
|
||||
}
|
||||
// send packet (lock before send, release lock after send)
|
||||
m_cs_send.Lock();
|
||||
r = L2PacketSend( m_sock, pack, 2000, &sentLen );
|
||||
m_cs_send.Unlock();
|
||||
// delete pack, if set to do so
|
||||
if( deleteAfterSend ) delete pack;
|
||||
// validate send OK
|
||||
if( r<=0 || (sentLen != pack_size) ) // some error
|
||||
{
|
||||
ret = false;
|
||||
throw Exception( "%S: send error: sent %u, retval %d", toString(), sentLen, r );
|
||||
}
|
||||
// count stats
|
||||
m_netStats.addSentPacket( sentLen );
|
||||
//
|
||||
return ret;
|
||||
}
|
||||
|
||||
void GameClient::enable_XOR_crypt( bool bEnable, unsigned char *initial_key )
|
||||
{
|
||||
m_xor_enabled = bEnable;
|
||||
if( bEnable )
|
||||
{
|
||||
memcpy( m_xor_key_recv, initial_key, sizeof(m_xor_key_recv) );
|
||||
memcpy( m_xor_key_send, initial_key, sizeof(m_xor_key_send) );
|
||||
}
|
||||
else
|
||||
{
|
||||
memset( m_xor_key_recv, 0, sizeof(m_xor_key_recv) );
|
||||
memset( m_xor_key_send, 0, sizeof(m_xor_key_send) );
|
||||
}
|
||||
}
|
||||
|
||||
void GameClient::notifySessionKeysOK()
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
LogDebug( L"GameClient::notifySessionKeysOK()" );
|
||||
#endif
|
||||
m_state = CLIENT_STATE_AUTHED;
|
||||
swprintf( m_tostring, 128, L"Client Acc: %s [IP %s:%d]", m_account, m_wip, m_port );
|
||||
sendPacket( ServerPackets::CharacterSelectionInfo( this ), true );
|
||||
}
|
25
L2C_Server/net/GameClient/GameClientNetStats.cpp
Normal file
25
L2C_Server/net/GameClient/GameClientNetStats.cpp
Normal file
@@ -0,0 +1,25 @@
|
||||
#include "pch.h"
|
||||
#include "GameClientNetStats.h"
|
||||
|
||||
GameClientNetStats::GameClientNetStats()
|
||||
{
|
||||
clear();
|
||||
}
|
||||
|
||||
void GameClientNetStats::clear()
|
||||
{
|
||||
ullPacketsSent = ullBytesSent = ullPacketsRcvd = ullBytesRcvd = 0;
|
||||
}
|
||||
|
||||
void GameClientNetStats::addSentPacket( unsigned long long len )
|
||||
{
|
||||
ullPacketsSent++;
|
||||
ullBytesSent += len;
|
||||
}
|
||||
|
||||
void GameClientNetStats::addRcvdPacket( unsigned long long len )
|
||||
{
|
||||
ullPacketsRcvd++;
|
||||
ullBytesRcvd += len;
|
||||
}
|
||||
|
15
L2C_Server/net/GameClient/GameClientNetStats.h
Normal file
15
L2C_Server/net/GameClient/GameClientNetStats.h
Normal file
@@ -0,0 +1,15 @@
|
||||
#pragma once
|
||||
|
||||
class GameClientNetStats
|
||||
{
|
||||
public:
|
||||
GameClientNetStats();
|
||||
void clear();
|
||||
void addSentPacket( unsigned long long len );
|
||||
void addRcvdPacket( unsigned long long len );
|
||||
public:
|
||||
unsigned long long ullPacketsSent;
|
||||
unsigned long long ullBytesSent;
|
||||
unsigned long long ullPacketsRcvd;
|
||||
unsigned long long ullBytesRcvd;
|
||||
};
|
188
L2C_Server/net/GameClient/GameClientThread.cpp
Normal file
188
L2C_Server/net/GameClient/GameClientThread.cpp
Normal file
@@ -0,0 +1,188 @@
|
||||
#include "pch.h"
|
||||
#include "Log.h"
|
||||
#include "l2c_utils.h"
|
||||
#include "GameClient.h"
|
||||
#include "GS.h"
|
||||
#include "utils/Exception.h"
|
||||
|
||||
bool GameClient::startThread()
|
||||
{
|
||||
if( m_isRunning ) return false;
|
||||
m_flagStop = false;
|
||||
unsigned int tid = 0;
|
||||
HANDLE hThread = (HANDLE)_beginthreadex( NULL, 0,
|
||||
(unsigned int (__stdcall *)(void *))GameClient::ClientThread, (void *)this,
|
||||
0, &tid );
|
||||
bool ret = false;
|
||||
if( hThread != NULL )
|
||||
{
|
||||
ret = true;
|
||||
CloseHandle( hThread );
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool GameClient::stopThread()
|
||||
{
|
||||
if( !m_isRunning ) return false;
|
||||
m_flagStop = true;
|
||||
while( m_isRunning ) Sleep(50);
|
||||
m_flagStop = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
void GameClient::disconnectForceAndWaitThreadToStop( bool server_shutdown, bool reasonDualLogin )
|
||||
{
|
||||
m_was_force_disconnected = true;
|
||||
// TODO: send SystemMessage about account in use if dual login
|
||||
if( reasonDualLogin )
|
||||
{
|
||||
}
|
||||
// TODO: send ServerClose / ExRestartClient? if server shutdown
|
||||
if( server_shutdown )
|
||||
{
|
||||
}
|
||||
stopThread(); // stops thread; thread cleanups socket himself
|
||||
}
|
||||
|
||||
void GameClient::signalThreadStop( bool setMarkToDeleteSelfAndCleanupClientPool )
|
||||
{
|
||||
m_flagStop = true;
|
||||
m_was_force_disconnected = !setMarkToDeleteSelfAndCleanupClientPool;
|
||||
}
|
||||
|
||||
|
||||
DWORD WINAPI GameClient::ClientThread( LPVOID lpvParam )
|
||||
{
|
||||
GameClient *pl = (GameClient *)lpvParam;
|
||||
pl->m_was_force_disconnected = false;
|
||||
GameServer *gs = GameServer::getInstance();
|
||||
pl->m_isRunning = true;
|
||||
pl->m_state = CLIENT_STATE_CONNECTED;
|
||||
pl->m_netStats.clear(); // reset nework statistics
|
||||
|
||||
int r, bReadyRead, bReadyWrite;
|
||||
unsigned char *packbuffer = NULL;
|
||||
unsigned int rcvdLen = 0;
|
||||
L2GamePacket *pack = NULL;
|
||||
|
||||
try
|
||||
{
|
||||
// allocate packets recv buffer
|
||||
packbuffer = (unsigned char *)malloc( 65536 );
|
||||
if( !packbuffer ) throw std::bad_alloc( "allocate packbuffer (64 Kb) failed" );
|
||||
|
||||
// packets recv loop
|
||||
while( !pl->m_flagStop )
|
||||
{
|
||||
// wait for socket ready to receive data
|
||||
r = L2PNet_select( pl->m_sock, L2PNET_SELECT_READ, 100, &bReadyRead, &bReadyWrite );
|
||||
if( r == 0 )
|
||||
{
|
||||
// select timout
|
||||
// update world state? move moving objects?...
|
||||
continue;
|
||||
}
|
||||
if( r == -1 ) // select error
|
||||
{
|
||||
LogError( L"%s: L2PNet_select() error!", pl->toString() );
|
||||
throw Exception( "select error" );
|
||||
}
|
||||
|
||||
// recv packet
|
||||
r = L2PacketReceive_buffer( pl->m_sock, 1000, &rcvdLen, packbuffer );
|
||||
if( r <= 0 )
|
||||
{
|
||||
if( r == 0 )
|
||||
{
|
||||
LogWarning( L"%s: closed connection? (received %u, retval %d)", pl->toString(), rcvdLen, r );
|
||||
pl->m_flagStop = true;
|
||||
break;
|
||||
}
|
||||
if( r < 0 )
|
||||
{
|
||||
LogError( L"%s: failed to receive packet (received %u, retval %d)", pl->toString(), rcvdLen, r );
|
||||
throw Exception( "network packet receive error" );
|
||||
}
|
||||
}
|
||||
|
||||
// count stats
|
||||
pl->m_netStats.addRcvdPacket( rcvdLen );
|
||||
|
||||
// create packet object
|
||||
pack = new L2GamePacket( packbuffer, rcvdLen );
|
||||
|
||||
// decode XOR if enabled
|
||||
if( pl->m_xor_enabled ) pack->decodeXOR( pl->m_xor_key_recv );
|
||||
|
||||
// deobfuscate opcode if enabled
|
||||
if( pl->m_opcodeObfuscationSeed > 0 )
|
||||
{
|
||||
// HACK: here buffer that should be constant, is modified (but length is not changed thoug)
|
||||
pl->m_obf->decodeIDs( (unsigned char *)pack->getBytesPtr() );
|
||||
}
|
||||
|
||||
#ifdef _DEBUG
|
||||
int opcode = pack->getByteAt(2);
|
||||
LogDebug( L"%s: opcode %02X", pl->toString(), opcode );
|
||||
#endif
|
||||
|
||||
// handle game client packet...
|
||||
pl->m_ph->handlePacket( pack );
|
||||
|
||||
// free packet object
|
||||
delete pack; pack = NULL;
|
||||
}
|
||||
}
|
||||
catch( L2P_Exception& e )
|
||||
{
|
||||
LogError( L"ClientThread: %s: L2Packets exception: %S", pl->toString(), e.what() );
|
||||
}
|
||||
catch( std::bad_alloc& e )
|
||||
{
|
||||
LogError( L"ClientThread: %s: bad_alloc %S", pl->toString(), e.what() );
|
||||
}
|
||||
catch( std::exception& e )
|
||||
{
|
||||
LogError( L"ClientThread: %s: std::excpt %S", pl->toString(), e.what() );
|
||||
}
|
||||
catch( Exception& e )
|
||||
{
|
||||
LogError( L"ClientThread: Exception: %S", e.what() );
|
||||
e.logStackTrace();
|
||||
}
|
||||
|
||||
// player disconnected - remove player account from login server list of authed accounts
|
||||
if( pl->m_account[0] ) // has authed??
|
||||
gs->logoutAccountFromLoginServer( pl->m_account );
|
||||
|
||||
// cleanup socket
|
||||
L2PNet_shutdown( pl->m_sock );
|
||||
L2PNet_closesocket( pl->m_sock );
|
||||
pl->m_sock = INVALID_SOCKET;
|
||||
pl->m_state = CLIENT_STATE_OFFLINE;
|
||||
// cleanup opcode obfuscator
|
||||
if( pl->m_obf )
|
||||
{
|
||||
delete pl->m_obf;
|
||||
pl->m_obf = NULL;
|
||||
pl->m_opcodeObfuscationSeed = 0;
|
||||
}
|
||||
|
||||
// free packets buffer
|
||||
if( packbuffer ) free( packbuffer ); packbuffer = NULL;
|
||||
|
||||
// mark self as finished
|
||||
pl->m_isRunning = false;
|
||||
|
||||
// notify GS ClientPool about client stop, if needed
|
||||
if( !pl->m_was_force_disconnected )
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
LogDebug( L"ClientThread s: Calling ClientPool to cleanup & deleting self", pl->toString() );
|
||||
#endif
|
||||
gs->getClientPool()->notifyClientThreadEnded( pl );
|
||||
delete pl;
|
||||
}
|
||||
return 0;
|
||||
}
|
11
L2C_Server/net/ServerPackets.h
Normal file
11
L2C_Server/net/ServerPackets.h
Normal file
@@ -0,0 +1,11 @@
|
||||
#pragma once
|
||||
|
||||
class ServerPackets
|
||||
{
|
||||
public:
|
||||
static L2GamePacket *KeyPacket( GameClient *pl );
|
||||
static L2GamePacket *CharacterSelectionInfo( GameClient *pl );
|
||||
static L2GamePacket *NewCharacterSuccess( GameClient *pl );
|
||||
static L2GamePacket *CharCreateFail( GameClient *pl, int reason );
|
||||
static L2GamePacket *CharCreateOK( GameClient *pl );
|
||||
};
|
33
L2C_Server/net/clientpackets/c_AuthLogin.cpp
Normal file
33
L2C_Server/net/clientpackets/c_AuthLogin.cpp
Normal file
@@ -0,0 +1,33 @@
|
||||
#include "pch.h"
|
||||
#include "Log.h"
|
||||
#include "l2c_utils.h"
|
||||
#include "net/GameClient/GameClient.h"
|
||||
#include "../ClientPacketHandler.h"
|
||||
#include "../ServerPackets.h"
|
||||
#include "GS.h"
|
||||
|
||||
/* _loginName = readS().toLowerCase();
|
||||
_playKey2 = readD();
|
||||
_playKey1 = readD();
|
||||
_loginKey1 = readD();
|
||||
_loginKey2 = readD(); */
|
||||
L2GamePacket *ClientPacketHandler::AuthLogin( L2GamePacket *pack )
|
||||
{
|
||||
GameServer *gs = GameServer::getInstance();
|
||||
pack->getPacketType();
|
||||
wchar_t login[128] = {0};
|
||||
unsigned char loginKey[8] = {0,0,0,0,0,0,0,0};
|
||||
unsigned char playKey[8] = {0,0,0,0,0,0,0,0};
|
||||
wcsncpy( login, pack->readUnicodeStringPtr(), 128 ); login[127] = 0;
|
||||
pack->readBytes( playKey+4, 4 );
|
||||
pack->readBytes( playKey, 4 );
|
||||
pack->readBytes( loginKey, 8 );
|
||||
//
|
||||
m_cl->setAccount( login );
|
||||
m_cl->setSessionKeys( playKey, loginKey );
|
||||
//
|
||||
if( gs->getConfig()->Debug ) LogDebug( L"%s: AuthLogin %s", m_cl->toString(), login );
|
||||
gs->addWaitingClientAndSendPlayerAuthRequest( login, loginKey, playKey );
|
||||
return NULL;
|
||||
}
|
||||
|
213
L2C_Server/net/clientpackets/c_CharacterCreate.cpp
Normal file
213
L2C_Server/net/clientpackets/c_CharacterCreate.cpp
Normal file
@@ -0,0 +1,213 @@
|
||||
#include "pch.h"
|
||||
#include "Log.h"
|
||||
#include "l2c_utils.h"
|
||||
#include "net/GameClient/GameClient.h"
|
||||
#include "../ClientPacketHandler.h"
|
||||
#include "../ServerPackets.h"
|
||||
#include "GS.h"
|
||||
#include "utils/Utils.h"
|
||||
#include "datatables/CharNameTable.h"
|
||||
#include "datatables/CharTemplateTable.h"
|
||||
#include "datatables/ItemTable.h"
|
||||
|
||||
L2GamePacket *ClientPacketHandler::CharacterCreate( L2GamePacket *pack )
|
||||
{
|
||||
pack->getPacketType();
|
||||
const wchar_t *name = pack->readUnicodeStringPtr(); // _name = readS();
|
||||
int race = pack->readD(); // _race = readD();
|
||||
int sex = pack->readD(); // _sex = readD();
|
||||
int classId = pack->readD(); // _classId = readD();
|
||||
pack->readD(); //_int = readD();
|
||||
pack->readD(); //_str = readD();
|
||||
pack->readD(); //_con = readD();
|
||||
pack->readD(); //_men = readD();
|
||||
pack->readD(); //_dex = readD();
|
||||
pack->readD(); //_wit = readD();
|
||||
int hairStyle = pack->readD(); //_hairStyle = readD();
|
||||
int hairColor = pack->readD(); //_hairColor = readD();
|
||||
int face = pack->readD(); //_face = readD();
|
||||
|
||||
// CharacterCreate
|
||||
GameServer *gs = GameServer::getInstance();
|
||||
|
||||
int name_len = wcslen( name );
|
||||
if( name_len < 1 || name_len > 16 )
|
||||
{
|
||||
if( gs->getConfig()->Debug )
|
||||
LogWarning( L"%s: Character Creation Failure: Character name [%s] is invalid. "
|
||||
L"Message generated: Your title cannot exceed 16 characters in length. Please try again.",
|
||||
m_cl->toString(), name );
|
||||
return ServerPackets::CharCreateFail( m_cl, L2Game_CharCreateFail::REASON_16_ENG_CHARS );
|
||||
}
|
||||
|
||||
// alphanumeric name
|
||||
if( !Utils_isValidCharName( name ) )
|
||||
{
|
||||
if( gs->getConfig()->Debug )
|
||||
LogWarning( L"%s: Character Creation Failure: Character name [%s] is invalid. "
|
||||
L"Message generated: Incorrect name. Please try again.", m_cl->toString(), name );
|
||||
return ServerPackets::CharCreateFail( m_cl, L2Game_CharCreateFail::REASON_INCORRECT_NAME );
|
||||
}
|
||||
|
||||
bool create_ok = false;
|
||||
|
||||
CharNameTable::getInstance()->LockDB();
|
||||
if( !CharNameTable::getInstance()->doesCharNameExist( name ) )
|
||||
{
|
||||
// check maximum char count
|
||||
int current_char_count = CharNameTable::getInstance()->getAccountCharCount( m_cl->getAccount() );
|
||||
// TODO: CharacterCreate maximum char count may be in GS config?
|
||||
if( current_char_count >= 7 )
|
||||
{
|
||||
if( gs->getConfig()->Debug ) LogWarning( L"%s: Max number of characters reached. Creation failed.", m_cl->toString() );
|
||||
CharNameTable::getInstance()->UnlockDB();
|
||||
return ServerPackets::CharCreateFail( m_cl, L2Game_CharCreateFail::REASON_TOO_MANY_CHARACTERS );
|
||||
}
|
||||
|
||||
// get class template
|
||||
const L2PlayerTemplate *tmpl = CharTemplateTable::getTemplate( classId );
|
||||
if( !tmpl )
|
||||
{
|
||||
LogError( L"%s: CharacterCreate: template is NULL!", m_cl->toString() );
|
||||
CharNameTable::getInstance()->UnlockDB();
|
||||
return ServerPackets::CharCreateFail( m_cl, L2Game_CharCreateFail::REASON_CREATION_FAILED );
|
||||
}
|
||||
// base class must be 1 lvl
|
||||
if( tmpl->classBaseLevel > 1 )
|
||||
{
|
||||
LogError( L"%s: CharacterCreate: template base level must be 1, but: %d!",
|
||||
m_cl->toString(), tmpl->classBaseLevel );
|
||||
CharNameTable::getInstance()->UnlockDB();
|
||||
return ServerPackets::CharCreateFail( m_cl, L2Game_CharCreateFail::REASON_CREATION_FAILED );
|
||||
}
|
||||
|
||||
// generate new objectId for char
|
||||
unsigned int oid = gs->getIdFactory()->getNextObjectId();
|
||||
|
||||
// get race by class id
|
||||
const ClassId *class_id = ClassIdTree::getInstance()->getClassId( classId );
|
||||
assert( class_id != NULL );
|
||||
int race_real = (int)class_id->getRace();
|
||||
if( race_real != race )
|
||||
LogWarning( L"%s: possible hacker: invalid race in CharacterCreate (%d)!=(%d)",
|
||||
m_cl->toString(), race, race_real );
|
||||
|
||||
// insert new character into DB
|
||||
MysqlQuery q;
|
||||
q.create(
|
||||
L"INSERT INTO characters ("
|
||||
L"account_name,charId,char_name,level,maxHp,curHp,maxCp,curCp,maxMp,curMp,"
|
||||
L"x,y,z,heading,"
|
||||
L"face,hairStyle,hairColor,sex,exp,sp,karma,fame,pvpkills,pkkills,clanid,race,classid,"
|
||||
L"deletetime,cancraft,title,accesslevel,online,isin7sdungeon,clan_privs,wantspeace,base_class,"
|
||||
L"newbie,nobless,power_grade,last_recom_date) values ("
|
||||
L"'%s',%u,'%s',1, %d,%d,%d,%d,%d,%d, " // acc,oid,charName, ...
|
||||
L"%d,%d,%d,0, " // x,y,z,heading
|
||||
L"%d,%d,%d, %d,0,0,0,0,0,0,0,%d,%d, " // face,hs,hc, ..
|
||||
L"0,0,'',0,0,0,0,0,%d, " // deltime, ...
|
||||
L"1,0,0,%u)", /////////////////////////////////////////////////////////////////////////
|
||||
m_cl->getAccount(), oid, name, (int)(tmpl->baseHpMax), (int)(tmpl->baseHpMax),
|
||||
(int)(tmpl->baseCpMax), (int)(tmpl->baseCpMax), (int)(tmpl->baseMpMax), (int)(tmpl->baseMpMax),
|
||||
tmpl->spawnX, tmpl->spawnY, tmpl->spawnZ,
|
||||
face, hairStyle, hairColor, sex, race_real, classId, classId, (unsigned int)time( NULL )
|
||||
);
|
||||
MysqlConnection *con = gs->getDBConnection();
|
||||
if( con->executeQuery( q ) )
|
||||
{
|
||||
create_ok = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
LogError( L"%s: CharacterCreate: cannot create: MySQL error: %s\n", m_cl->toString(), con->getErrorStr() );
|
||||
}
|
||||
q.clear();
|
||||
|
||||
// add shortcuts
|
||||
//(int slotId, int pageId, int shortcutType, int shortcutId, int shortcutLevel, int characterType)
|
||||
// add attack shortcut L2ShortCut(0, 0, 3, 2, 0, 1);
|
||||
q.create( L"INSERT INTO character_shortcuts (charId,slot,page,type,shortcut_id,level,class_index) VALUES ('%u',0,0,3,2,0,1)", oid );
|
||||
if( !con->executeQuery( q ) ) LogError( L"CharacterCreate: shortcuts: MySQL: %s", con->getErrorStr() );
|
||||
// add take shortcut L2ShortCut(3, 0, 3, 5, 0, 1);
|
||||
q.create( L"INSERT INTO character_shortcuts (charId,slot,page,type,shortcut_id,level,class_index) VALUES ('%u',3,0,3,5,0,1)", oid );
|
||||
if( !con->executeQuery( q ) ) LogError( L"CharacterCreate: shortcuts: MySQL: %s", con->getErrorStr() );
|
||||
// add sit shortcut L2ShortCut(10, 0, 3, 0, 0, 1);
|
||||
q.create( L"INSERT INTO character_shortcuts (charId,slot,page,type,shortcut_id,level,class_index) VALUES ('%u',10,0,3,0,0,1)", oid );
|
||||
if( !con->executeQuery( q ) ) LogError( L"CharacterCreate: shortcuts: MySQL: %s", con->getErrorStr() );
|
||||
|
||||
// add start items
|
||||
const std::list<L2PlayerTemplate::PcTemplateItem> itemsList = tmpl->getItems();
|
||||
std::list<L2PlayerTemplate::PcTemplateItem>::const_iterator itemsListIter = itemsList.begin();
|
||||
while( itemsListIter != itemsList.end() )
|
||||
{
|
||||
L2PlayerTemplate::PcTemplateItem item = (*itemsListIter);
|
||||
const L2ItemTemplate *item_tmpl = ItemTable::getInstance()->getTemplate( item.getItemId() );
|
||||
if( !item_tmpl )
|
||||
{
|
||||
LogError( L"CharacterCreate: cannot add starter item: template NULL (%d)", item.getItemId() );
|
||||
continue;
|
||||
}
|
||||
//
|
||||
q.clear();
|
||||
unsigned int item_oid = gs->getIdFactory()->getNextObjectId();
|
||||
if( item.isEquipped() )
|
||||
{
|
||||
// location set to paperdoll
|
||||
q.create( L"INSERT INTO items (owner_id,item_id,count,loc,loc_data,enchant_level,"
|
||||
L"object_id,custom_type1,custom_type2,mana_left,time) VALUES "
|
||||
L"('%u','%d','%d','PAPERDOLL','%d',0,'%u','%d','%d','%d','%d')",
|
||||
oid, item.getItemId(), item.getAmount(), (int)item_tmpl->getBodyPart(),
|
||||
item_oid, item_tmpl->getType1(), item_tmpl->getType2(),
|
||||
item_tmpl->getDuration(), item_tmpl->getTime() );
|
||||
}
|
||||
else
|
||||
{
|
||||
// location set to inventory
|
||||
q.create( L"INSERT INTO items (owner_id,item_id,count,loc,loc_data,enchant_level,"
|
||||
L"object_id,custom_type1,custom_type2,mana_left,time) VALUES "
|
||||
L"('%u','%d','%d','INVENTORY','%d',0,'%u','%d','%d','%d','%d')",
|
||||
oid, item.getItemId(), item.getAmount(), (int)item_tmpl->getBodyPart(),
|
||||
item_oid, item_tmpl->getType1(), item_tmpl->getType2(),
|
||||
item_tmpl->getDuration(), item_tmpl->getTime() );
|
||||
}
|
||||
if( !con->executeQuery( q ) )
|
||||
LogError( L"CharacterCreate: cannot add starter item: MySQL error: %s", con->getErrorStr() );
|
||||
// add tutbook shortcut
|
||||
if( item.getItemId() == 5588 ) // CharacterCreate add Tutorial Guide...
|
||||
{
|
||||
// L2ShortCut(11, 0, 1, item.getObjectId(), 0, 1);
|
||||
q.create( L"INSERT INTO character_shortcuts (charId,slot,page,type,shortcut_id,level,class_index) "
|
||||
L"VALUES ('%u',11,0,1,'%u',0,1)", oid, item_oid );
|
||||
if( !con->executeQuery( q ) )
|
||||
LogError( L"CharacterCreate add Tutorial Guide: MySQL: %s", con->getErrorStr() );
|
||||
}
|
||||
//
|
||||
itemsListIter++;
|
||||
}
|
||||
q.clear();
|
||||
|
||||
// TODO: CharacterCreate add starting skills (need SkillTable & SkillLearn)
|
||||
|
||||
gs->releaseDBConnection( con );
|
||||
}
|
||||
else
|
||||
{
|
||||
if( gs->getConfig()->Debug )
|
||||
LogWarning( L"%s: Character Creation Failure: REASON_NAME_ALREADY_EXISTS.", m_cl->toString() );
|
||||
CharNameTable::getInstance()->UnlockDB();
|
||||
return ServerPackets::CharCreateFail( m_cl, L2Game_CharCreateFail::REASON_NAME_ALREADY_EXISTS );
|
||||
}
|
||||
CharNameTable::getInstance()->UnlockDB();
|
||||
|
||||
if( !create_ok )
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return ServerPackets::CharCreateOK( m_cl );
|
||||
}
|
||||
|
||||
/*
|
||||
private static final String INSERT_CHARACTER = "INSERT INTO characters (account_name,charId,char_name,level,maxHp,curHp,maxCp,curCp,maxMp,curMp,face,hairStyle,hairColor,sex,exp,sp,karma,fame,pvpkills,pkkills,clanid,race,classid,deletetime,cancraft,title,accesslevel,online,isin7sdungeon,clan_privs,wantspeace,base_class,newbie,nobless,power_grade,last_recom_date) values (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)";
|
||||
private static final String UPDATE_CHARACTER = "UPDATE characters SET level=?,maxHp=?,curHp=?,maxCp=?,curCp=?,maxMp=?,curMp=?,face=?,hairStyle=?,hairColor=?,sex=?,heading=?,x=?,y=?,z=?,exp=?,expBeforeDeath=?,sp=?,karma=?,fame=?,pvpkills=?,pkkills=?,rec_have=?,rec_left=?,clanid=?,race=?,classid=?,deletetime=?,title=?,accesslevel=?,online=?,isin7sdungeon=?,clan_privs=?,wantspeace=?,base_class=?,onlinetime=?,punish_level=?,punish_timer=?,newbie=?,nobless=?,power_grade=?,subpledge=?,last_recom_date=?,lvl_joined_academy=?,apprentice=?,sponsor=?,varka_ketra_ally=?,clan_join_expiry_time=?,clan_create_expiry_time=?,char_name=?,death_penalty_level=?,bookmarkslot=?,vitality_points=? WHERE charId=?";
|
||||
private static final String RESTORE_CHARACTER = "SELECT account_name, charId, char_name, level, maxHp, curHp, maxCp, curCp, maxMp, curMp, face, hairStyle, hairColor, sex, heading, x, y, z, exp, expBeforeDeath, sp, karma, fame, pvpkills, pkkills, clanid, race, classid, deletetime, cancraft, title, rec_have, rec_left, accesslevel, online, char_slot, lastAccess, clan_privs, wantspeace, base_class, onlinetime, isin7sdungeon, punish_level, punish_timer, newbie, nobless, power_grade, subpledge, last_recom_date, lvl_joined_academy, apprentice, sponsor, varka_ketra_ally,clan_join_expiry_time,clan_create_expiry_time,death_penalty_level,bookmarkslot,vitality_points FROM characters WHERE charId=?";
|
||||
*/
|
44
L2C_Server/net/clientpackets/c_CharacterSelect.cpp
Normal file
44
L2C_Server/net/clientpackets/c_CharacterSelect.cpp
Normal file
@@ -0,0 +1,44 @@
|
||||
#include "pch.h"
|
||||
#include "Log.h"
|
||||
#include "l2c_utils.h"
|
||||
#include "net/GameClient/GameClient.h"
|
||||
#include "../ClientPacketHandler.h"
|
||||
#include "../ServerPackets.h"
|
||||
#include "GS.h"
|
||||
|
||||
|
||||
L2GamePacket *ClientPacketHandler::CharacterSelect( L2GamePacket *pack )
|
||||
{
|
||||
L2GamePacket *ret = NULL;
|
||||
pack->getPacketType();
|
||||
int charSlot = pack->readD();
|
||||
LogDebug( L"CharacterSelect: charSlot : %d", charSlot );
|
||||
// create &load player for game client if not exists
|
||||
if( m_cl->getPlayer() == NULL )
|
||||
{
|
||||
GamePlayer *pl = new GamePlayer( m_cl, 0 );
|
||||
// TODO: CharacterSelect: load char from base
|
||||
m_cl->setPlayer( pl, true, CLIENT_STATE_IN_GAME ); // sets state to IN_GAME
|
||||
//
|
||||
L2Game_CharSelected *p = new L2Game_CharSelected();
|
||||
ret = p;
|
||||
p->p_char_name[0] = 0;
|
||||
p->p_opcodeObfuscatorSeed = rand();
|
||||
p->p_title[0] = 0;
|
||||
p->p_classId = 0;
|
||||
p->p_level = 1;
|
||||
unsigned char playKey[8];
|
||||
m_cl->getPlayKey( playKey );
|
||||
p->p_sessionId = playKey[0] | (playKey[1] << 8) | (playKey[2] << 16) | (playKey[3] << 24); // playOkID1
|
||||
//
|
||||
p->create( L2_VERSION_T23 );
|
||||
//
|
||||
m_cl->setOpcodeObfuscationSeed( p->p_opcodeObfuscatorSeed );
|
||||
}
|
||||
else
|
||||
LogError( L"Net: %s: CharacterSelect: already has player attached to GameClient?? Bad Bad Error or Cheater!",
|
||||
m_cl->toString() );
|
||||
//
|
||||
return ret;
|
||||
}
|
||||
|
27
L2C_Server/net/clientpackets/c_Logout.cpp
Normal file
27
L2C_Server/net/clientpackets/c_Logout.cpp
Normal file
@@ -0,0 +1,27 @@
|
||||
#include "pch.h"
|
||||
#include "Log.h"
|
||||
#include "l2c_utils.h"
|
||||
#include "net/GameClient/GameClient.h"
|
||||
#include "../ClientPacketHandler.h"
|
||||
#include "../ServerPackets.h"
|
||||
#include "GS.h"
|
||||
|
||||
L2GamePacket *ClientPacketHandler::Logout( L2GamePacket *pack )
|
||||
{
|
||||
pack->getPacketType();
|
||||
L2GamePacket *ret = NULL;
|
||||
switch( m_cl->getState() )
|
||||
{
|
||||
case CLIENT_STATE_OFFLINE:
|
||||
case CLIENT_STATE_CONNECTED:
|
||||
case CLIENT_STATE_AUTHED:
|
||||
ret = NULL;
|
||||
m_cl->signalThreadStop( true ); // we can just disconnect player now
|
||||
break;
|
||||
case CLIENT_STATE_IN_GAME:
|
||||
// TODO: check if player can logout here and now
|
||||
// answer with RestartResponse (LogoutOK) or (LogoutFailed)
|
||||
break;
|
||||
}
|
||||
return ret;
|
||||
}
|
13
L2C_Server/net/clientpackets/c_NewCharacter.cpp
Normal file
13
L2C_Server/net/clientpackets/c_NewCharacter.cpp
Normal file
@@ -0,0 +1,13 @@
|
||||
#include "pch.h"
|
||||
#include "Log.h"
|
||||
#include "l2c_utils.h"
|
||||
#include "net/GameClient/GameClient.h"
|
||||
#include "../ClientPacketHandler.h"
|
||||
#include "../ServerPackets.h"
|
||||
#include "GS.h"
|
||||
|
||||
L2GamePacket *ClientPacketHandler::NewCharacter( L2GamePacket *pack )
|
||||
{
|
||||
pack = NULL; // just trigger
|
||||
return ServerPackets::NewCharacterSuccess( m_cl );
|
||||
}
|
37
L2C_Server/net/clientpackets/c_ProtocolVersion.cpp
Normal file
37
L2C_Server/net/clientpackets/c_ProtocolVersion.cpp
Normal file
@@ -0,0 +1,37 @@
|
||||
#include "pch.h"
|
||||
#include "Log.h"
|
||||
#include "l2c_utils.h"
|
||||
#include "net/GameClient/GameClient.h"
|
||||
#include "../ClientPacketHandler.h"
|
||||
#include "../ServerPackets.h"
|
||||
#include "GS.h"
|
||||
|
||||
L2GamePacket *ClientPacketHandler::ProtocolVersion( L2GamePacket *pack )
|
||||
{
|
||||
GameServer *gs = GameServer::getInstance();
|
||||
pack->getPacketType();
|
||||
int pv = pack->readD();
|
||||
// just server ping?
|
||||
if( pv == -2 )
|
||||
{
|
||||
m_cl->setProtocolOk( false );
|
||||
m_cl->signalThreadStop( true );
|
||||
if( gs->getConfig()->Debug ) LogDebug( L"%s: received server ping from client (%d)", m_cl->toString(), pv );
|
||||
return NULL;
|
||||
}
|
||||
// protocol version validation
|
||||
if( gs->getConfig()->Debug ) LogDebug( L"%s: protocol version %d", m_cl->toString(), pv );
|
||||
if( pv < gs->getConfig()->min_game_protocol_version ||
|
||||
pv > gs->getConfig()->max_game_protocol_version )
|
||||
{
|
||||
m_cl->setProtocolOk( false );
|
||||
m_cl->signalThreadStop( true );
|
||||
LogWarning( L"%s: invalid protocol version %d (must be [%d..%d])",
|
||||
m_cl->toString(), pv,
|
||||
gs->getConfig()->min_game_protocol_version,
|
||||
gs->getConfig()->max_game_protocol_version );
|
||||
}
|
||||
else m_cl->setProtocolOk( true );
|
||||
// reply KeyPacket
|
||||
return ServerPackets::KeyPacket( m_cl );
|
||||
}
|
15
L2C_Server/net/clientpackets/c_RequestGotoLobby.cpp
Normal file
15
L2C_Server/net/clientpackets/c_RequestGotoLobby.cpp
Normal file
@@ -0,0 +1,15 @@
|
||||
#include "pch.h"
|
||||
#include "Log.h"
|
||||
#include "l2c_utils.h"
|
||||
#include "net/GameClient/GameClient.h"
|
||||
#include "../ClientPacketHandler.h"
|
||||
#include "../ServerPackets.h"
|
||||
#include "GS.h"
|
||||
|
||||
|
||||
L2GamePacket *ClientPacketHandler::RequestGotoLobby( L2GamePacket *pack )
|
||||
{
|
||||
pack = NULL; // unused here
|
||||
return ServerPackets::CharacterSelectionInfo( m_cl );
|
||||
}
|
||||
|
15
L2C_Server/net/serverpackets/s_CharCreateFail.cpp
Normal file
15
L2C_Server/net/serverpackets/s_CharCreateFail.cpp
Normal file
@@ -0,0 +1,15 @@
|
||||
#include "pch.h"
|
||||
#include "Log.h"
|
||||
#include "l2c_utils.h"
|
||||
#include "net/GameClient/GameClient.h"
|
||||
#include "../ServerPackets.h"
|
||||
#include "GS.h"
|
||||
|
||||
L2GamePacket *ServerPackets::CharCreateFail( GameClient *pl, int reason )
|
||||
{
|
||||
pl = NULL; // reference to player not needed
|
||||
L2Game_CharCreateFail *p = new L2Game_CharCreateFail();
|
||||
p->p_reasonCode = (unsigned int)reason;
|
||||
p->create( L2_VERSION_T23 );
|
||||
return p;
|
||||
}
|
14
L2C_Server/net/serverpackets/s_CharCreateOK.cpp
Normal file
14
L2C_Server/net/serverpackets/s_CharCreateOK.cpp
Normal file
@@ -0,0 +1,14 @@
|
||||
#include "pch.h"
|
||||
#include "Log.h"
|
||||
#include "l2c_utils.h"
|
||||
#include "net/GameClient/GameClient.h"
|
||||
#include "../ServerPackets.h"
|
||||
#include "GS.h"
|
||||
|
||||
L2GamePacket *ServerPackets::CharCreateOK( GameClient *pl )
|
||||
{
|
||||
pl = NULL; // reference to player not needed
|
||||
L2Game_CharCreateSuccess *p = new L2Game_CharCreateSuccess();
|
||||
p->create( L2_VERSION_T23 );
|
||||
return p;
|
||||
}
|
225
L2C_Server/net/serverpackets/s_CharacterSelectionInfo.cpp
Normal file
225
L2C_Server/net/serverpackets/s_CharacterSelectionInfo.cpp
Normal file
@@ -0,0 +1,225 @@
|
||||
#include "pch.h"
|
||||
#include "Log.h"
|
||||
#include "l2c_utils.h"
|
||||
#include "net/GameClient/GameClient.h"
|
||||
#include "../ServerPackets.h"
|
||||
#include "GS.h"
|
||||
#include "world/templates/item/L2ItemTemplate.h"
|
||||
|
||||
L2GamePacket *ServerPackets::CharacterSelectionInfo( GameClient *pl )
|
||||
{
|
||||
GameServer *gs = GameServer::getInstance();
|
||||
MysqlConnection *con = gs->getDBConnection();
|
||||
L2Game_CharSelectionInfoBlock csb[7];
|
||||
memset( &csb, 0, sizeof(csb) );
|
||||
int i = 0;
|
||||
int num_chars = 0;
|
||||
unsigned int max_lastAccess = 0;
|
||||
int activeCharIndex = -1;
|
||||
MysqlQuery q;
|
||||
q.create( L"SELECT account_name, charId, char_name, level, maxHp, curHp, maxMp, curMp, face, hairStyle, "
|
||||
L"hairColor, sex, heading, x, y, z, exp, sp, karma, pvpkills, pkkills, clanid, race, classid, "
|
||||
L"deletetime, cancraft, title, rec_have, rec_left, accesslevel, online, char_slot, lastAccess, "
|
||||
L"base_class, transform_id FROM characters WHERE account_name='%s' LIMIT 7", pl->getAccount() );
|
||||
if( con->executeQuery( q ) )
|
||||
{
|
||||
i = 0;
|
||||
while( q.getNextRow() )
|
||||
{
|
||||
unsigned int lastAccess = q.getFieldUInt( "lastAccess" );
|
||||
if( lastAccess > max_lastAccess )
|
||||
{
|
||||
max_lastAccess = lastAccess;
|
||||
activeCharIndex = i;
|
||||
}
|
||||
//
|
||||
q.getFieldStrW( 0, csb[i].accountName, 32 );
|
||||
csb[i].charID = q.getFieldUInt( 1 );
|
||||
q.getFieldStrW( 2, csb[i].charName, 32 );
|
||||
csb[i].level = q.getFieldUInt( 3 );
|
||||
csb[i].HP_max = q.getFieldDouble( 4 );
|
||||
csb[i].HP_cur = q.getFieldDouble( 5 );
|
||||
csb[i].MP_max = q.getFieldDouble( 6 );
|
||||
csb[i].MP_cur = q.getFieldDouble( 7 );
|
||||
csb[i].face = q.getFieldUInt( 8 );
|
||||
csb[i].hairStyle = q.getFieldUInt( 9 );
|
||||
csb[i].hairColor = q.getFieldUInt( 10 );
|
||||
csb[i].sex = q.getFieldUInt( 11 );
|
||||
//q.getFieldUInt( 12, ???? ); // no heading
|
||||
csb[i].x = q.getFieldInt( 13 );
|
||||
csb[i].y = q.getFieldInt( 14 );
|
||||
csb[i].z = q.getFieldInt( 15 );
|
||||
csb[i].Exp = q.getFieldUInt64( 16 );
|
||||
csb[i].SP = q.getFieldUInt( 17 );
|
||||
csb[i].karma = q.getFieldUInt( 18 );
|
||||
csb[i].PVP_kills = q.getFieldUInt( 19 );
|
||||
csb[i].PK_kills = q.getFieldUInt( 20 );
|
||||
csb[i].clanID = q.getFieldUInt( 21 );
|
||||
csb[i].race = q.getFieldUInt( 22 );
|
||||
csb[i].classID = q.getFieldUInt( 23 );
|
||||
csb[i].deleteSeconds = q.getFieldUInt( 24 );
|
||||
//q.getFieldUInt( 25, can craft??? );
|
||||
//q.getFieldStrW( 26, title?? );
|
||||
//q.getFieldUInt( 27, rec_have );
|
||||
csb[i].baseClassID = q.getFieldUInt( "base_class" );
|
||||
csb[i].isActive = 1;
|
||||
// fake
|
||||
//csb[i].iid_chest = 0x0967; // DC Robe
|
||||
//csb[i].iid_R_hand = 0x2ec2; // Common Branch of Mother tree
|
||||
//
|
||||
i++;
|
||||
}
|
||||
num_chars = i;
|
||||
}
|
||||
else
|
||||
{
|
||||
LogError( L"CharacterSelectionInfo: MySQL error: %s", con->getErrorStr() );
|
||||
}
|
||||
|
||||
// TODO: load also equipped inventory items
|
||||
for( i=0; i<num_chars; i++ )
|
||||
{
|
||||
q.clear();
|
||||
q.create( L"SELECT object_id,item_id,loc_data,enchant_level FROM items WHERE owner_id=%u AND loc='PAPERDOLL'", csb[i].charID );
|
||||
if( con->executeQuery( q ) )
|
||||
{
|
||||
while( q.getNextRow() )
|
||||
{
|
||||
int slot = q.getFieldInt( "loc_data" );
|
||||
int item_id = q.getFieldInt( "item_id" );
|
||||
int enchant_level = q.getFieldInt( "enchant_level" );
|
||||
//
|
||||
switch( slot )
|
||||
{
|
||||
case 1: csb[i].iid_R_ear = item_id; break;
|
||||
case 2: csb[i].iid_L_ear = item_id; break;
|
||||
//case 3: LREAR
|
||||
case 4: csb[i].iid_neck = item_id; break;
|
||||
case 5: csb[i].iid_L_finger = item_id; break;
|
||||
case 6: csb[i].iid_R_finger = item_id; break;
|
||||
//case 7: LRFINGER
|
||||
case 8: csb[i].iid_head = item_id; break;
|
||||
case 9: csb[i].iid_R_hand = item_id; break;
|
||||
case 10: csb[i].iid_L_hand = item_id; break;
|
||||
case 11: csb[i].iid_gloves = item_id; break;
|
||||
case 12: csb[i].iid_chest = item_id; break;
|
||||
case 13: csb[i].iid_legs = item_id; break;
|
||||
case 14: csb[i].iid_feet = item_id; break;
|
||||
case 15: csb[i].iid_back = item_id; break;
|
||||
case 16: csb[i].iid_R_hand = csb[i].iid_L_hand = item_id; break; // LRHAND
|
||||
case 17: csb[i].iid_chest = item_id; break; // fullarmor?
|
||||
case 18: csb[i].iid_hair = item_id; break;
|
||||
//case 19: ALLDRESS
|
||||
case 20: csb[i].iid_hair_2 = item_id; break;
|
||||
case 21: csb[i].iid_hair_all = item_id; break;
|
||||
case 22: csb[i].iid_R_bracelet = item_id; break;
|
||||
case 23: csb[i].iid_L_bracelet = item_id; break;
|
||||
// 24..29 DECOs
|
||||
case 30: csb[i].iid_belt = item_id; break;
|
||||
}
|
||||
if( slot == SLOT_R_HAND && enchant_level > 0 ) // weapon
|
||||
csb[i].enchantEffect = (unsigned char)(enchant_level & 0x000000FF);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LogError( L"CharacterSelectionInfo: MySQL error: %s", con->getErrorStr() );
|
||||
}
|
||||
}
|
||||
q.clear();
|
||||
gs->releaseDBConnection( con );
|
||||
|
||||
// retreive playOk1
|
||||
unsigned char playKey[8];
|
||||
memset( playKey, 0, 8 );
|
||||
pl->getPlayKey( playKey );
|
||||
unsigned int playOk1 = *(unsigned int *)&playKey[0];
|
||||
//
|
||||
L2GamePacket *p = new L2GamePacket();
|
||||
p->setPacketType( 0x09 );
|
||||
p->writeD( num_chars ); // number of chars
|
||||
p->writeD( 0x07 ); // server max_chars
|
||||
p->writeC( 0x00 ); // 0x00
|
||||
//
|
||||
for( i=0; i<num_chars; i++ )
|
||||
{
|
||||
p->writeS( csb[i].charName );
|
||||
p->writeUInt( csb[i].charID );
|
||||
p->writeS( pl->getAccount() );
|
||||
p->writeUInt( playOk1 ); // TODO: playOK id 1
|
||||
p->writeUInt( csb[i].clanID );
|
||||
p->writeD( 0x00 );
|
||||
//
|
||||
p->writeUInt( csb[i].sex );
|
||||
p->writeUInt( csb[i].race );
|
||||
p->writeUInt( csb[i].baseClassID );
|
||||
p->writeUInt( (i == activeCharIndex) ? 0x01 : 0x00 ); // is active
|
||||
//
|
||||
p->writeInt( csb[i].x );
|
||||
p->writeInt( csb[i].y );
|
||||
p->writeInt( csb[i].z );
|
||||
p->writeDouble( csb[i].HP_cur );
|
||||
p->writeDouble( csb[i].MP_cur );
|
||||
//
|
||||
p->writeUInt( csb[i].SP );
|
||||
p->writeUInt64( csb[i].Exp );
|
||||
p->writeUInt( csb[i].level );
|
||||
//
|
||||
p->writeUInt( csb[i].karma );
|
||||
p->writeUInt( csb[i].PK_kills );
|
||||
p->writeUInt( csb[i].PVP_kills );
|
||||
//
|
||||
p->writeD( 0x00 ); p->writeD( 0x00 ); p->writeD( 0x00 ); p->writeD( 0x00 );
|
||||
p->writeD( 0x00 ); p->writeD( 0x00 ); p->writeD( 0x00 ); // 7 0x00
|
||||
//
|
||||
// 26 inventory item ids // TODO: equipment ids
|
||||
p->writeD( csb[i].iid_hair_all ); //writeD(charInfoPackage.getPaperdollItemId(Inventory.PAPERDOLL_HAIRALL));
|
||||
p->writeD( csb[i].iid_R_ear ); //writeD(charInfoPackage.getPaperdollItemId(Inventory.PAPERDOLL_REAR));
|
||||
p->writeD( csb[i].iid_L_ear ); //writeD(charInfoPackage.getPaperdollItemId(Inventory.PAPERDOLL_LEAR));
|
||||
p->writeD( csb[i].iid_neck ); //writeD(charInfoPackage.getPaperdollItemId(Inventory.PAPERDOLL_NECK));
|
||||
p->writeD( csb[i].iid_R_finger ); //writeD(charInfoPackage.getPaperdollItemId(Inventory.PAPERDOLL_RFINGER));
|
||||
p->writeD( csb[i].iid_L_finger ); //writeD(charInfoPackage.getPaperdollItemId(Inventory.PAPERDOLL_LFINGER));
|
||||
p->writeD( csb[i].iid_head ); //writeD(charInfoPackage.getPaperdollItemId(Inventory.PAPERDOLL_HEAD));
|
||||
p->writeD( csb[i].iid_R_hand ); //writeD(charInfoPackage.getPaperdollItemId(Inventory.PAPERDOLL_RHAND));
|
||||
p->writeD( csb[i].iid_L_hand ); //writeD(charInfoPackage.getPaperdollItemId(Inventory.PAPERDOLL_LHAND));
|
||||
p->writeD( csb[i].iid_gloves ); //writeD(charInfoPackage.getPaperdollItemId(Inventory.PAPERDOLL_GLOVES));
|
||||
p->writeD( csb[i].iid_chest ); //writeD(charInfoPackage.getPaperdollItemId(Inventory.PAPERDOLL_CHEST));
|
||||
p->writeD( csb[i].iid_legs ); //writeD(charInfoPackage.getPaperdollItemId(Inventory.PAPERDOLL_LEGS));
|
||||
p->writeD( csb[i].iid_feet ); //writeD(charInfoPackage.getPaperdollItemId(Inventory.PAPERDOLL_FEET));
|
||||
p->writeD( csb[i].iid_back ); //writeD(charInfoPackage.getPaperdollItemId(Inventory.PAPERDOLL_BACK));
|
||||
p->writeD( csb[i].iid_LR_hand ); //writeD(charInfoPackage.getPaperdollItemId(Inventory.PAPERDOLL_LRHAND));
|
||||
p->writeD( csb[i].iid_hair ); //writeD(charInfoPackage.getPaperdollItemId(Inventory.PAPERDOLL_HAIR));
|
||||
p->writeD( csb[i].iid_hair_2 ); //writeD(charInfoPackage.getPaperdollItemId(Inventory.PAPERDOLL_HAIR2));
|
||||
p->writeD( csb[i].iid_R_bracelet ); //writeD(charInfoPackage.getPaperdollItemId(Inventory.PAPERDOLL_RBRACELET));
|
||||
p->writeD( csb[i].iid_L_bracelet ); //writeD(charInfoPackage.getPaperdollItemId(Inventory.PAPERDOLL_LBRACELET));
|
||||
p->writeD( 0x00 ); //writeD(charInfoPackage.getPaperdollItemId(Inventory.PAPERDOLL_DECO1));
|
||||
p->writeD( 0x00 ); //writeD(charInfoPackage.getPaperdollItemId(Inventory.PAPERDOLL_DECO2));
|
||||
p->writeD( 0x00 ); //writeD(charInfoPackage.getPaperdollItemId(Inventory.PAPERDOLL_DECO3));
|
||||
p->writeD( 0x00 ); //writeD(charInfoPackage.getPaperdollItemId(Inventory.PAPERDOLL_DECO4));
|
||||
p->writeD( 0x00 ); //writeD(charInfoPackage.getPaperdollItemId(Inventory.PAPERDOLL_DECO5));
|
||||
p->writeD( 0x00 ); //writeD(charInfoPackage.getPaperdollItemId(Inventory.PAPERDOLL_DECO6));
|
||||
p->writeD( csb[i].iid_belt ); //writeD(charInfoPackage.getPaperdollItemId(Inventory.PAPERDOLL_BELT));
|
||||
//
|
||||
p->writeUInt( csb[i].hairStyle );
|
||||
p->writeUInt( csb[i].hairColor );
|
||||
p->writeUInt( csb[i].face );
|
||||
//LogDebug( L"Writing hs,hc,face = %u,%u,%u", csb[i].hairStyle, csb[i].hairColor, csb[i].face );
|
||||
//
|
||||
p->writeDouble( csb[i].HP_max );
|
||||
p->writeDouble( csb[i].MP_max );
|
||||
//
|
||||
p->writeUInt( csb[i].deleteSeconds );
|
||||
p->writeUInt( csb[i].classID ); // not base classid
|
||||
p->writeUInt( 0x00 ); // TODO: is last used char
|
||||
//
|
||||
p->writeC( 0x00 ); // TODO: enchant Effect
|
||||
p->writeD( 0x00 ); // TODO: aug. ID
|
||||
p->writeD( 0x00 ); // transformID is always 0 here
|
||||
}
|
||||
//
|
||||
//FILE *_f = fopen( "CharacterSelectionInfo.log", "wt" );
|
||||
//p->dumpToFile( _f );
|
||||
//fclose( _f );
|
||||
//
|
||||
return p;
|
||||
}
|
27
L2C_Server/net/serverpackets/s_KeyPacket.cpp
Normal file
27
L2C_Server/net/serverpackets/s_KeyPacket.cpp
Normal file
@@ -0,0 +1,27 @@
|
||||
#include "pch.h"
|
||||
#include "Log.h"
|
||||
#include "l2c_utils.h"
|
||||
#include "net/GameClient/GameClient.h"
|
||||
#include "../ServerPackets.h"
|
||||
#include "GS.h"
|
||||
|
||||
L2GamePacket *ServerPackets::KeyPacket( GameClient *pl )
|
||||
{
|
||||
#ifdef ENABLE_OBF
|
||||
unsigned int obf_seed = rand();
|
||||
#else
|
||||
unsigned int obf_seed = 0;
|
||||
#endif
|
||||
pl->setOpcodeObfuscationSeed( obf_seed );
|
||||
//
|
||||
L2Game_KeyPacket *p = new L2Game_KeyPacket();
|
||||
p->p_protocolIsOK = pl->isProtocolOk();
|
||||
p->p_obfuscatorSeed = obf_seed;
|
||||
p->p_serverId = (unsigned char)GameServer::getInstance()->getServerId();
|
||||
// initial key is random bytes...
|
||||
L2Game_KeyPacket::createInitialHellboundKey( p->p_initialKey, p->p_initialKey );
|
||||
p->create( L2_VERSION_T23 );
|
||||
// enable crypt on client
|
||||
pl->enable_XOR_crypt( true, p->p_initialKey );
|
||||
return p;
|
||||
}
|
106
L2C_Server/net/serverpackets/s_NewCharacterSuccess.cpp
Normal file
106
L2C_Server/net/serverpackets/s_NewCharacterSuccess.cpp
Normal file
@@ -0,0 +1,106 @@
|
||||
#include "pch.h"
|
||||
#include "Log.h"
|
||||
#include "l2c_utils.h"
|
||||
#include "net/GameClient/GameClient.h"
|
||||
#include "../ServerPackets.h"
|
||||
#include "GS.h"
|
||||
//
|
||||
#include "world/model/base/ClassIdTree.h"
|
||||
#include "datatables/CharTemplateTable.h"
|
||||
|
||||
/*
|
||||
Server: Len 967 [NewCharacterSuccess]
|
||||
C7 03
|
||||
0D // opcode
|
||||
0C 00 00 00 // number of templates
|
||||
|
||||
// [ for each template ]
|
||||
|
||||
00 00 00 00 // race
|
||||
00 00 00 00 // class id
|
||||
46 00 00 00 // 0x46
|
||||
28 00 00 00 // base STR
|
||||
0A 00 00 00 // 0x0A
|
||||
46 00 00 00 // 0x46
|
||||
1E 00 00 00 // base DEX
|
||||
0A 00 00 00
|
||||
46 00 00 00
|
||||
2B 00 00 00 // base CON
|
||||
0A 00 00 00
|
||||
46 00 00 00
|
||||
15 00 00 00 // base INT
|
||||
0A 00 00 00
|
||||
46 00 00 00
|
||||
0B 00 00 00 // base WIT
|
||||
0A 00 00 00
|
||||
46 00 00 00
|
||||
19 00 00 00 // base MEN
|
||||
0A 00 00 00
|
||||
*/
|
||||
|
||||
L2GamePacket *ServerPackets::NewCharacterSuccess( GameClient *pl )
|
||||
{
|
||||
pl = NULL; // reference to player is not needed here
|
||||
//
|
||||
unsigned int numTemplates = 0;
|
||||
L2Game_NewCharacterTemplate tmpl[32];
|
||||
int ic = 0;
|
||||
ClassIdTree *cidtree = ClassIdTree::getInstance();
|
||||
for( ic = 0; ic < ClassIdTree::NUM_CLASS_IDS; ic++ )
|
||||
{
|
||||
// no Inspector, though it's base class
|
||||
if( ic == ClassId::CID_INSPECTOR ) continue;
|
||||
// get ClassId if class
|
||||
const ClassId *cid = cidtree->getClassId( ic );
|
||||
if( cid )
|
||||
{
|
||||
// no parents, base classes
|
||||
if( cid->getParentId() == ClassId::CID_NONE )
|
||||
{
|
||||
// get template base stats for class
|
||||
const L2PlayerTemplate *plt = CharTemplateTable::getTemplate( ic );
|
||||
if( plt )
|
||||
{
|
||||
tmpl[numTemplates].classID = ic;
|
||||
tmpl[numTemplates].base_CON = plt->baseCON;
|
||||
tmpl[numTemplates].base_DEX = plt->baseDEX;
|
||||
tmpl[numTemplates].base_INT = plt->baseINT;
|
||||
tmpl[numTemplates].base_MEN = plt->baseMEN;
|
||||
tmpl[numTemplates].base_STR = plt->baseSTR;
|
||||
tmpl[numTemplates].base_WIT = plt->baseWIT;
|
||||
tmpl[numTemplates].race = (int)plt->race;
|
||||
numTemplates++;
|
||||
}
|
||||
}
|
||||
}
|
||||
if( numTemplates >= 32 ) break;
|
||||
}
|
||||
//
|
||||
L2GamePacket *p = new L2GamePacket();
|
||||
p->setPacketType( 0x0D ); // NewCharacterSuccess
|
||||
p->writeUInt( numTemplates );
|
||||
for( ic = 0; ic < (int)numTemplates; ic++ )
|
||||
{
|
||||
p->writeD( tmpl[ic].race );
|
||||
p->writeD( tmpl[ic].classID );
|
||||
p->writeD( 0x46 );
|
||||
p->writeD( tmpl[ic].base_STR );
|
||||
p->writeD( 0x0A );
|
||||
p->writeD( 0x46 );
|
||||
p->writeD( tmpl[ic].base_DEX );
|
||||
p->writeD( 0x0A );
|
||||
p->writeD( 0x46 );
|
||||
p->writeD( tmpl[ic].base_CON );
|
||||
p->writeD( 0x0A );
|
||||
p->writeD( 0x46 );
|
||||
p->writeD( tmpl[ic].base_INT );
|
||||
p->writeD( 0x0A );
|
||||
p->writeD( 0x46 );
|
||||
p->writeD( tmpl[ic].base_WIT );
|
||||
p->writeD( 0x0A );
|
||||
p->writeD( 0x46 );
|
||||
p->writeD( tmpl[ic].base_MEN );
|
||||
p->writeD( 0x0A );
|
||||
}
|
||||
return p;
|
||||
}
|
Reference in New Issue
Block a user