875 lines
31 KiB
C++
875 lines
31 KiB
C++
#include "stdafx.h"
|
|
#include "ConfigIni.h"
|
|
#include "Logger.h"
|
|
#include "GameClient.h"
|
|
#include "GameListener.h"
|
|
#include "ProtocolConverter.h"
|
|
#include "L2PacketTypes.h"
|
|
#include "RadarDllWnd.h"
|
|
#include "PacketInjector.h"
|
|
|
|
extern class CConfig g_cfg;
|
|
|
|
// Parameters:
|
|
//
|
|
// returns true if packet was modified
|
|
// if packet was not modified:
|
|
// sets (*newLen) to len;
|
|
// sets (*newBytes) to bytes
|
|
// - caller should ignore newLen and newBytes content in this case
|
|
// - caller should send original packet
|
|
// if packet was modified:
|
|
// sets (*newLen) to new length of packet
|
|
// sets (*newBytes) to point to new bytes buffer
|
|
// - newBytes are properly encoded if needed,
|
|
// - caller just should send newBytes and free them after sending
|
|
// if packet should be dropped:
|
|
// sets (*newLen) to -1
|
|
// - caller should ignore newLen and newBytes content
|
|
// - caller should not send any packet :)
|
|
//
|
|
bool GameClient::PP_full_fromServer( unsigned char *bytes, unsigned int len,
|
|
unsigned char **newBytes, unsigned int *newLen )
|
|
{
|
|
//
|
|
(*newBytes) = bytes;
|
|
(*newLen) = len;
|
|
//
|
|
int i = 0;
|
|
bool bPacketWasModified = false;
|
|
if( !bytes || len<1 ) return bPacketWasModified;
|
|
if( len<3 )
|
|
{
|
|
log_error( LOG_WARNING, "PP_full_fromServer(): packet len < 3!\n" );
|
|
return bPacketWasModified;
|
|
}
|
|
|
|
// should we decrypt it?
|
|
if( this->xor_enabled ) L2GamePacket::decodeXOR_buffer( bytes, len, this->key_server_sc );
|
|
|
|
// log packet here, when it is decrypted, if log game packets enabled
|
|
if( this->logfile ) logPacket( bytes, len, true ); // true - from server
|
|
|
|
// parse it
|
|
unsigned char ptype = bytes[2];
|
|
unsigned short int ptype2 = 0x0000;
|
|
unsigned short int ptype3 = 0x0000;
|
|
if( len >= 5 )
|
|
{
|
|
ptype2 |= (unsigned short int)(bytes[3] & 0xFFFF);
|
|
ptype2 |= (unsigned short int)(bytes[4] << 8 & 0xFFFF);
|
|
}
|
|
if( len >= 7 )
|
|
{
|
|
ptype3 |= (unsigned short int)(bytes[5] & 0xFFFF);
|
|
ptype3 |= (unsigned short int)(bytes[6] << 8 & 0xFFFF);
|
|
}
|
|
|
|
// obfuscator
|
|
class L2PCodeObfuscator *lpco;
|
|
lpco = (class L2PCodeObfuscator *)this->clsObfuscator;
|
|
|
|
// opcode obfuscation is NOT used for Server -> Client packets!
|
|
/*if( lpco )
|
|
{
|
|
if( lpco->isEnabled() && (g_cfg.L2_version != (int)L2_VERSION_T23) )
|
|
{
|
|
unsigned char pcode_prev = ptype;
|
|
unsigned short pcode2_prev = ptype2;
|
|
bool decode_res = lpco->decodeOpcode( ptype, ptype2, ptype3 );
|
|
if( decode_res )
|
|
{
|
|
if( pcode2_prev == ptype2 )
|
|
log_error( LOG_DEBUG, "PP_full_fromServer(): de-obfuscated %02X -> %02X\n", pcode_prev, ptype );
|
|
else
|
|
log_error( LOG_DEBUG, "PP_full_fromServer(): de-obfuscated %02X:%02X -> %02X:%02X\n",
|
|
pcode_prev, pcode2_prev, ptype, ptype2 );
|
|
}
|
|
else
|
|
log_error( LOG_ERROR, "PP_full_fromServer(): ERROR de-obfuscating %02X\n", pcode_prev, ptype );
|
|
}
|
|
}*/
|
|
// opcode obfuscation is NOT used for Server -> Client packets!
|
|
|
|
L2PacketTypes_LogServer( (L2_VERSION)g_cfg.L2_version, this->state, ptype, ptype2, ptype3 );
|
|
|
|
// exception handler block
|
|
try
|
|
{
|
|
|
|
switch( this->state )
|
|
{
|
|
case GCST_CONNECTED:
|
|
{
|
|
switch( ptype )
|
|
{
|
|
case 0x2e: // Hellbound: KeyPacket, FirstKey
|
|
{
|
|
// check length...
|
|
if( len < 25 )
|
|
{
|
|
log_error( LOG_WARNING, "Received KeyPacket len = %u, but must be 25! Some bot-protection?\n" );
|
|
log_error( LOG_WARNING, "Or old L2Rebellion-based fucking Java server?\n", len );
|
|
}
|
|
// try parse KeyPacket
|
|
L2Game_KeyPacket *p_key = new L2Game_KeyPacket( bytes, len );
|
|
p_key->parse();
|
|
this->opcodeObfuscator = p_key->p_obfuscatorSeed;
|
|
memcpy( this->key_client_cs, p_key->p_initialKey, 16 );
|
|
// check allowed proto
|
|
if( !p_key->p_protocolIsOK ) log_error( LOG_ERROR, "Server tells this protocolVersion is not supported!\n" );
|
|
delete p_key;
|
|
// create copies of keys
|
|
memcpy( this->key_client_sc, this->key_client_cs, sizeof(this->key_client_cs) );
|
|
memcpy( this->key_server_sc, this->key_client_cs, sizeof(this->key_client_cs) );
|
|
memcpy( this->key_server_cs, this->key_client_cs, sizeof(this->key_client_cs) );
|
|
this->xor_enabled = true;
|
|
log_error( LOG_DEBUGDUMP, "Server: 2e KeyPacket: key: " );
|
|
for( i=0; i<16; i++ ) log_error_np( LOG_DEBUGDUMP, "%02X ", this->key_client_cs[i] );
|
|
log_error_np( LOG_DEBUGDUMP, "\n" );
|
|
// log obfuscator, if it is != 0x00000000
|
|
LOG_LEVEL log_level = LOG_DEBUGDUMP;
|
|
if( this->opcodeObfuscator != 0x00000000 )
|
|
{
|
|
log_level = LOG_WARNING;
|
|
log_error( log_level, "Server: 2e KeyPacket: Obfuscator: 0x%04X\n", this->opcodeObfuscator );
|
|
// delete obfuscator, if exists
|
|
if( lpco )
|
|
{
|
|
lpco->clear();
|
|
delete lpco;
|
|
this->clsObfuscator = NULL;
|
|
}
|
|
lpco = new L2PCodeObfuscator();
|
|
lpco->setVersionMode( (L2_VERSION)g_cfg.L2_version );
|
|
lpco->init_tables( this->opcodeObfuscator );
|
|
this->clsObfuscator = (void *)lpco;
|
|
}
|
|
else log_error( LOG_PACKETNAME, "Server: 2e KeyPacket: not using obfuscation key! OK\n" );
|
|
} break; // KeyPacket
|
|
case 0x09: // CharacterSelectionInfo // Hellbound
|
|
{
|
|
//int nChars = bytes[3];
|
|
//log_error( LOG_PACKETNAME, "Server: 09 CharacterSelectionInfo: %d chars\n", nChars );
|
|
this->state = GCST_AUTHED;
|
|
this->postNotify( GCN_STATECHANGE, this->state );
|
|
log_error( LOG_DEBUG, "Server: 09 CharacterSelectionInfo: switch state to AUTHED\n" );
|
|
} break; // CharacterSelectionInfo
|
|
//default:
|
|
// {
|
|
// LOG_LEVEL log_level = LOG_PACKETNAME;
|
|
// if( g_cfg.WarnUnknownPacketsToStdout ) log_level = LOG_WARNING;
|
|
// log_error( log_level, "Server: Unknown packet %02X in state: CONNECTED\n",
|
|
// (unsigned int)ptype );
|
|
// if( g_cfg.DumpUnknownToStdout )
|
|
// {
|
|
// printf( "============================================\n" );
|
|
// L2GamePacket *p = new L2GamePacket( bytes, len );
|
|
// p->dumpToFile( stdout );
|
|
// delete p;
|
|
// printf( "============================================\n" );
|
|
// }
|
|
// } break;
|
|
} // switch( ptype )
|
|
} break; // GCST_CONNECTED
|
|
|
|
|
|
case GCST_AUTHED:
|
|
{
|
|
switch( ptype )
|
|
{
|
|
case 0x09: // CharacterSelectionInfo // Hellbound
|
|
{
|
|
int nChars = bytes[3];
|
|
log_error( LOG_PACKETNAME, "Server: 09 CharacterSelectionInfo: %d chars\n", nChars );
|
|
} break; // CharacterSelectionInfo
|
|
case 0x0b: // CharSelected
|
|
{
|
|
this->state = GCST_IN_GAME;
|
|
log_error( LOG_DEBUG, "Server: 0b CharSelected: switch state from AUTHED to IN_GAME\n" );
|
|
// parse
|
|
L2Game_CharSelected *p_charsel = new L2Game_CharSelected( bytes, len );
|
|
p_charsel->parse();
|
|
this->opcodeObfuscator = p_charsel->p_opcodeObfuscatorSeed;
|
|
delete p_charsel;
|
|
// obfuscator manage
|
|
if( this->opcodeObfuscator != 0x00000000 )
|
|
{
|
|
log_error( LOG_WARNING, "Opcode obfuscation is enabled in CharSelected packet, 0x%08X\n",
|
|
this->opcodeObfuscator );
|
|
// delete obfuscator, if exists
|
|
if( lpco )
|
|
{
|
|
lpco->clear();
|
|
delete lpco;
|
|
this->clsObfuscator = NULL;
|
|
}
|
|
lpco = new L2PCodeObfuscator();
|
|
lpco->setVersionMode( (L2_VERSION)g_cfg.L2_version );
|
|
lpco->init_tables( this->opcodeObfuscator );
|
|
this->clsObfuscator = (void *)lpco;
|
|
}
|
|
} break;
|
|
//case 0x0d: // NewCharacterSuccess
|
|
// {
|
|
// int nTemplates = bytes[3];
|
|
// log_error( LOG_PACKETNAME, "Server: 0d NewCharacterSuccess; char_templates: %d\n",
|
|
// nTemplates );
|
|
// } break; // NewCharacterSuccess
|
|
//case 0x0f: // CharCreateOK
|
|
// {
|
|
// log_error( LOG_PACKETNAME, "Server: 0f CharCreateOK\n" );
|
|
// } break; // CharCreateOK
|
|
//case 0x73: // SSQInfo // Hellbound
|
|
// {
|
|
// log_error( LOG_PACKETNAME, "Server: 73 SSQInfo\n" );
|
|
// // FIXED: SSQInfo should not change client state to IN_GAME, only CharSelected should
|
|
// //this->state = GCST_IN_GAME;
|
|
// //this->postNotify( GCN_STATECHANGE, this->state );
|
|
// } break; // SSQInfo
|
|
//default:
|
|
// {
|
|
// LOG_LEVEL log_level = LOG_PACKETNAME;
|
|
// if( g_cfg.WarnUnknownPacketsToStdout ) log_level = LOG_WARNING;
|
|
// log_error( log_level, "Server: Unknown packet %02X in state: AUTHED\n",
|
|
// (unsigned int)ptype );
|
|
// if( g_cfg.DumpUnknownToStdout )
|
|
// {
|
|
// printf( "============================================\n" );
|
|
// L2GamePacket *p = new L2GamePacket( bytes, len );
|
|
// p->dumpToFile( stdout );
|
|
// delete p;
|
|
// printf( "============================================\n" );
|
|
// }
|
|
// } break;
|
|
} // switch( ptype )
|
|
} break; // GCST_AUTHED
|
|
|
|
|
|
case GCST_IN_GAME:
|
|
{
|
|
switch( ptype )
|
|
{
|
|
case 0x00: // Die
|
|
{
|
|
//log_error( LOG_PACKETNAME, "Server: 00 Die\n" );
|
|
ai.notifyEventPacket( UAI_PEVENT_DIE, bytes, len );
|
|
} break; // Die
|
|
case 0x01: // Revive
|
|
{
|
|
//log_error( LOG_PACKETNAME, "Server: 01 Revive\n" );
|
|
ai.notifyEventPacket( UAI_PEVENT_REVIVE, bytes, len );
|
|
} break; // Revive
|
|
case 0x05: // SpawnItem
|
|
{
|
|
ai.notifyEventPacket( UAI_PEVENT_SPAWNITEM, bytes, len );
|
|
} break; // SpawnItem
|
|
case 0x06: // SellList
|
|
{
|
|
if( ProtoConv_IsEnabled() )
|
|
if( ProtoConv_ConvertPacket( bytes, len, newBytes, newLen ) )
|
|
bPacketWasModified = true; // it will be encoded again in the end of this function ;)
|
|
} break; // SellList
|
|
case 0x07: // BuyList
|
|
{
|
|
if( ProtoConv_IsEnabled() )
|
|
if( ProtoConv_ConvertPacket( bytes, len, newBytes, newLen ) )
|
|
bPacketWasModified = true; // it will be encoded again in the end of this function ;)
|
|
} break; // BuyList
|
|
case 0x08: // DeleteObject
|
|
{
|
|
//log_error( LOG_PACKETNAME, "Server: 08 DeleteObject\n" );
|
|
ai.notifyEventPacket( UAI_PEVENT_DELETEOBJECT, bytes, len );
|
|
} break; // DeleteObject
|
|
case 0x0b: // CharSelected (must be in AUTHED state, but it fixes problem on some L2J servers that do not send SSQInfo packet)
|
|
{
|
|
this->state = GCST_IN_GAME;
|
|
log_error( LOG_DEBUG, "Server: 0b CharSelected: switch state from IN_GAME to IN_GAME\n" );
|
|
// parse
|
|
L2Game_CharSelected *p_charsel = new L2Game_CharSelected( bytes, len );
|
|
p_charsel->parse();
|
|
this->opcodeObfuscator = p_charsel->p_opcodeObfuscatorSeed;
|
|
delete p_charsel;
|
|
// obfuscator manage
|
|
if( this->opcodeObfuscator != 0x00000000 )
|
|
{
|
|
log_error( LOG_WARNING, "Opcode obfuscation is enabled in CharSelected packet, 0x%08X\n",
|
|
this->opcodeObfuscator );
|
|
// delete obfuscator, if exists
|
|
if( lpco )
|
|
{
|
|
lpco->clear();
|
|
delete lpco;
|
|
this->clsObfuscator = NULL;
|
|
}
|
|
lpco = new L2PCodeObfuscator();
|
|
lpco->setVersionMode( (L2_VERSION)g_cfg.L2_version );
|
|
lpco->init_tables( this->opcodeObfuscator );
|
|
this->clsObfuscator = (void *)lpco;
|
|
}
|
|
} break;
|
|
case 0x0c: // NpcInfo (mob) [CharInfo morphed]?
|
|
{
|
|
//log_error( LOG_PACKETNAME, "Server: 0c NpcInfo\n" );
|
|
ai.notifyEventPacket( UAI_PEVENT_NPCINFO, bytes, len );
|
|
} break;
|
|
case 0x11: // ItemList
|
|
{
|
|
//log_error( LOG_PACKETNAME, "Server: 11 ItemList\n" );
|
|
ai.notifyEventPacket( UAI_PEVENT_ITEMLIST, bytes, len );
|
|
if( ProtoConv_IsEnabled() )
|
|
if( ProtoConv_ConvertPacket( bytes, len, newBytes, newLen ) )
|
|
bPacketWasModified = true; // it will be encoded again in the end of this function ;)
|
|
} break; // ItemList
|
|
//case 0x12: // SunRise
|
|
// {
|
|
// log_error( LOG_PACKETNAME, "Server: 12 SunRise\n" );
|
|
// } break;
|
|
case 0x14: // TradeStart
|
|
{
|
|
if( ProtoConv_IsEnabled() )
|
|
if( ProtoConv_ConvertPacket( bytes, len, newBytes, newLen ) )
|
|
bPacketWasModified = true;
|
|
} break; // TradeStart
|
|
case 0x16: // DropItem
|
|
{
|
|
ai.notifyEventPacket( UAI_PEVENT_DROPITEM, bytes, len );
|
|
} break;
|
|
//case 0x17: // GetItem
|
|
// {
|
|
// // TODO: Items handling
|
|
// log_error( LOG_USERAI, "Server: 17 GetItem\n" );
|
|
// } break;
|
|
case 0x18: // StatusUpdate
|
|
{
|
|
ai.notifyEventPacket( UAI_PEVENT_STATUSUPDATE, bytes, len );
|
|
} break; // StatusUpdate
|
|
case 0x19: // NpcHtmlMessage
|
|
{
|
|
ai.UAI_process_NpcHtml( bytes, len );
|
|
} break; // NpcHtmlMessage
|
|
case 0x1A: // TradeOwnAdd
|
|
{
|
|
if( ProtoConv_IsEnabled() )
|
|
if( ProtoConv_ConvertPacket( bytes, len, newBytes, newLen ) )
|
|
bPacketWasModified = true;
|
|
} break; // TradeOwnAdd
|
|
case 0x1B: // TradeOtherAdd
|
|
{
|
|
if( ProtoConv_IsEnabled() )
|
|
if( ProtoConv_ConvertPacket( bytes, len, newBytes, newLen ) )
|
|
bPacketWasModified = true;
|
|
} break; // TradeOtherAdd
|
|
//case 0x1F: // ActionFailed
|
|
// {
|
|
// log_error( LOG_PACKETNAME, "Server: 1F ActionFailed\n" );
|
|
// } break; // ActionFailed
|
|
case 0x21: // InventoryUpdate
|
|
{
|
|
ai.notifyEventPacket( UAI_PEVENT_INVENTORYUPDATE, bytes, len );
|
|
if( ProtoConv_IsEnabled() )
|
|
if( ProtoConv_ConvertPacket( bytes, len, newBytes, newLen ) )
|
|
bPacketWasModified = true; // it will be encoded again in the end of this function ;)
|
|
} break; // InventoryUpdate
|
|
case 0x22: // TeleportToLocation
|
|
{
|
|
ai.notifyEventPacket( UAI_PEVENT_TELEPORTTOLOCATION, bytes, len );
|
|
} break; // TeleportToLocation
|
|
case 0x23: // TargetSelected
|
|
{
|
|
ai.notifyEventPacket( UAI_PEVENT_TARGETSELECTED, bytes, len );
|
|
} break; // TargetSelected
|
|
case 0x24: // TargetUnselected
|
|
{
|
|
ai.notifyEventPacket( UAI_PEVENT_TARGETUNSELECTED, bytes, len );
|
|
} break; // TargetUnselected
|
|
//case 0x25: // AutoAttackStart
|
|
// {
|
|
// log_error( LOG_PACKETNAME, "Server: 25 AutoAttackStart\n" );
|
|
// } break; // AutoAttackStart
|
|
//case 0x26: // AutoAttackStop
|
|
// {
|
|
// log_error( LOG_PACKETNAME, "Server: 26 AutoAttackStop\n" );
|
|
// } break; // AutoAttackStop
|
|
//case 0x27: // SocialAction
|
|
// {
|
|
// log_error( LOG_PACKETNAME, "Server: 27 SocialAction\n" );
|
|
// } break; // SocialAction
|
|
case 0x28: // ChangeMoveType
|
|
{
|
|
ai.UAI_process_ChangeMoveType( bytes, len );
|
|
} break; // ChangeMoveType
|
|
case 0x29: // ChangeWaitType
|
|
{
|
|
ai.UAI_process_ChangeWaitType( bytes, len );
|
|
} break; // ChangeWaitType
|
|
case 0x2f: // MoveToLocation
|
|
{
|
|
// some pc/npc moves, also user (player) moves possibly
|
|
//log_error( LOG_PACKETNAME, "Server: 2f MoveToLocation\n" );
|
|
ai.notifyEventPacket( UAI_PEVENT_MOVETOLOCATION, bytes, len );
|
|
} break; // MoveToLocation
|
|
//case 0x30: // NpcSay
|
|
// {
|
|
// log_error( LOG_PACKETNAME, "Server: 30 NpcSay\n" );
|
|
// } break; // NpcSay
|
|
case 0x31: // CharInfo
|
|
{
|
|
//log_error( LOG_PACKETNAME, "Server: 31 CharInfo\n" );
|
|
ai.notifyEventPacket( UAI_PEVENT_CHARINFO, bytes, len );
|
|
} break; // CharInfo
|
|
case 0x32: // UserInfo
|
|
{
|
|
//log_error( LOG_PACKETNAME, "Server: 32 UserInfo\n" );
|
|
ai.notifyEventPacket( UAI_PEVENT_USERINFO, bytes, len );
|
|
} break; // UserInfo
|
|
//case 0x33: // Attack
|
|
// {
|
|
// log_error( LOG_PACKETNAME, "Server: 33 Attack\n" );
|
|
// //ai.notifyEventPacket( UAI_PEVENT_ATTACK, bytes, len );
|
|
// } break;
|
|
//case 0x41: // WareHouseDepositList
|
|
// {
|
|
// log_error( LOG_PACKETNAME, "Server: 41 WareHouseDepositList\n" );
|
|
// // TODO: protocol convert WareHouseDepositList
|
|
// } break;
|
|
//case 0x42: // WareHouseWithdrawalList
|
|
// {
|
|
// log_error( LOG_PACKETNAME, "Server: 42 WareHouseWithdrawalList\n" );
|
|
// // TODO: protocol convert WareHouseWithdrawalList
|
|
// } break;
|
|
//case 0x44: // ShortCutRegister
|
|
// {
|
|
// log_error( LOG_PACKETNAME, "Server: 44 ShortCutRegister\n" );
|
|
// } break; // ShortCutRegister
|
|
//case 0x45: // ShortCutInit
|
|
// {
|
|
// log_error( LOG_PACKETNAME, "Server: 45 ShortCutInit\n" );
|
|
// } break; // ShortCutInit
|
|
case 0x47: // StopMove
|
|
{
|
|
ai.notifyEventPacket( UAI_PEVENT_STOPMOVE, bytes, len );
|
|
} break;
|
|
case 0x48: // MagicSkillUse
|
|
{
|
|
ai.notifyEventPacket( UAI_PEVENT_MAGICSKILLUSE, bytes, len );
|
|
} break; // MagicSkillUse
|
|
case 0x49: // MagicSkillCanceld
|
|
{
|
|
ai.notifyEventPacket( UAI_PEVENT_MAGICSKILLCANCELLED, bytes, len );
|
|
} break; // MagicSkillCanceld
|
|
//case 0x4A: // CreatureSay
|
|
// {
|
|
// log_error( LOG_PACKETNAME, "Server: 4A CreatureSay\n" );
|
|
// // TODO: CreatureSay parse
|
|
// } break; // CreatureSay
|
|
case 0x41: // WarehouseDepositList
|
|
{
|
|
if( ProtoConv_IsEnabled() )
|
|
if( ProtoConv_ConvertPacket( bytes, len, newBytes, newLen ) )
|
|
bPacketWasModified = true;
|
|
} break; // WarehouseDepositList
|
|
case 0x42: // WarehouseWithdrawList
|
|
{
|
|
if( ProtoConv_IsEnabled() )
|
|
if( ProtoConv_ConvertPacket( bytes, len, newBytes, newLen ) )
|
|
bPacketWasModified = true;
|
|
} break; // WarehouseWithdrawList
|
|
//case 0x4C: // DoorInfo
|
|
// {
|
|
// log_error( LOG_OK, "DoorInfo\n" );
|
|
// } break; // DoorInfo
|
|
//case 0x4D: // DoorStatusUpdate
|
|
// {
|
|
// log_error( LOG_OK, "DoorStatusUpdate\n" );
|
|
// } break; // DoorStatusUpdate
|
|
case 0x4E: // PartySmallWindowAll
|
|
{
|
|
ai.notifyEventPacket( UAI_PEVENT_PARTYALL, bytes, len );
|
|
} break; // PartySmallWindowAll
|
|
case 0x4F: // PartySmallWindowAdd
|
|
{
|
|
ai.notifyEventPacket( UAI_PEVENT_PARTYADD, bytes, len );
|
|
} break; // PartySmallWindowAdd
|
|
case 0x50: // PartySmallWindowDeleteAll
|
|
{
|
|
ai.notifyEventPacket( UAI_PEVENT_PARTYDELALL, bytes, len );
|
|
} break; // PartySmallWindowDeleteAll
|
|
case 0x51: // PartySmallWindowDelete
|
|
{
|
|
ai.notifyEventPacket( UAI_PEVENT_PARTYDEL, bytes, len );
|
|
} break; // PartySmallWindowDelete
|
|
case 0x52: // PartySmallWindowUpdate
|
|
{
|
|
ai.notifyEventPacket( UAI_PEVENT_PARTYUPDATE, bytes, len );
|
|
} break; // PartySmallWindowUpdate
|
|
//case 0x54: // MagicSkillLaunched
|
|
// {
|
|
// log_error( LOG_PACKETNAME, "Server: 54 MagicSkillLaunched\n" );
|
|
// L2GamePacket *msl = new L2GamePacket();
|
|
// msl->setBytes( bytes, len );
|
|
// msl->readReset();
|
|
// msl->getPacketType();
|
|
// unsigned int oid = msl->readUInt(); // caster id
|
|
// int skillId = msl->readD(); // skill id
|
|
// int skillLvl = msl->readD(); // skill lvl
|
|
// delete msl;
|
|
// if( oid == this->ai.usr.objectID )
|
|
// {
|
|
// log_error_np( LOG_OK, "You launched skill %d lvl %d\n", skillId, skillLvl );
|
|
// }
|
|
// } break; // MagicSkillLaunched
|
|
//case 0x5A: // PledgeShowMemberListAll
|
|
// {
|
|
// log_error( LOG_PACKETNAME, "Server: 5A PledgeShowMemberListAll\n" );
|
|
// } break; // PledgeShowMemberListAll
|
|
//case 0x5B: // PledgeShowMemberListUpdate
|
|
// {
|
|
// log_error( LOG_PACKETNAME, "Server: 5B PledgeShowMemberListUpdate\n" );
|
|
// } break; // PledgeShowMemberListUpdate
|
|
//case 0x5C: // PledgeShowMemberListAdd
|
|
// {
|
|
// log_error( LOG_PACKETNAME, "Server: 5C PledgeShowMemberListAdd\n" );
|
|
// } break; // PledgeShowMemberListAdd
|
|
case 0x5F: // SkillList
|
|
{
|
|
ai.notifyEventPacket( UAI_PEVENT_SKILLLIST, bytes, len );
|
|
} break; // SkillList
|
|
//case 0x62: // SystemMessage
|
|
// {
|
|
// log_error( LOG_PACKETNAME, "Server: 62 SystemMessage\n" );
|
|
// } break; // SystemMessage
|
|
case 0x6b: // SetupGauge
|
|
{
|
|
ai.notifyEventPacket( UAI_PEVENT_SETUPGAUGE, bytes, len );
|
|
} break; // SetupGauge
|
|
//case 0x6c: // VehicleDeparture
|
|
// {
|
|
// log_error( LOG_PACKETNAME, "Server: 6C VehicleDeparture\n" );
|
|
// } break;
|
|
//case 0x72: // MoveToPawn
|
|
// {
|
|
// log_error( LOG_PACKETNAME, "Server: 72 MoveToPawn\n" );
|
|
// } break; // MoveToPawn
|
|
case 0x71: // RestartResponse (RestartOK)
|
|
{
|
|
L2GamePacket *pack = new L2GamePacket( bytes, len );
|
|
pack->getPacketType(); // 0x71
|
|
int restartOK = pack->readD();
|
|
if( restartOK == 0x01 )
|
|
{
|
|
// notify user AI that user is not in game
|
|
ai.userLogout();
|
|
//log_error( LOG_PACKETNAME, "Server: 71 RestartResponse (RestartOK)\n" );
|
|
this->state = GCST_AUTHED;
|
|
log_error( LOG_DEBUG, "Server: 71 RestartResponse: switch state to AUTHED\n" );
|
|
this->postNotify( GCN_STATECHANGE, this->state );
|
|
}
|
|
else
|
|
log_error( LOG_USERAI, "RestartResponse: logout failed!\n" );
|
|
delete pack;
|
|
} break; // RestartResponse
|
|
case 0x74: // GameGuardQuery
|
|
{
|
|
//log_error( LOG_PACKETNAME, "Server: 74 GameGuardQuery\n" );
|
|
// if enabled, radar can emulate GameGuard reply to standard L2J Query
|
|
if( g_cfg.ReplyL2JGameGuardQuery )
|
|
{
|
|
L2GamePacket *pack = new L2GamePacket( bytes, len );
|
|
pack->getPacketType();
|
|
unsigned int q1 = pack->readUInt();
|
|
unsigned int q2 = pack->readUInt();
|
|
unsigned int q3 = pack->readUInt();
|
|
unsigned int q4 = pack->readUInt();
|
|
delete pack;
|
|
pack = NULL;
|
|
// parse request
|
|
if( q1 == 0x27533DD9 && q2 == 0x2E72A51D && q3 == 0x2017038B && q4 == 0xC35B1EA3 )
|
|
{
|
|
log_error( LOG_WARNING, "Received standard l2J GameGuardQuery, replying :)\n" );
|
|
// reply with well known answer
|
|
PGen_GameGuardReply_L2J();
|
|
}
|
|
else
|
|
{
|
|
log_error( LOG_WARNING, "Received unknown GameGuardQuery 0x%08X 0x%08X 0x%08X 0x%08X!\n",
|
|
q1, q2, q3, q4 );
|
|
// do nothing...
|
|
}
|
|
} // if( g_cfg.ReplyL2JGameGuardQuery )
|
|
} break; // GameGuardQuery
|
|
//case 0x75: // FriendList
|
|
// {
|
|
// log_error( LOG_PACKETNAME, "Server: 75 FriendList\n" );
|
|
// } break; // FriendList
|
|
//case 0x79: // ValidateLocation
|
|
// {
|
|
// log_error( LOG_PACKETNAME, "Server: 79 ValidateLocation\n" );
|
|
// } break; // ValidateLocation
|
|
//case 0x7B: // ShowBoard
|
|
// {
|
|
// log_error( LOG_PACKETNAME, "Server: 7B ShowBoard\n" );
|
|
// } break; // ShowBoard
|
|
case 0x84: // LeaveWorld
|
|
{
|
|
//log_error( LOG_PACKETNAME, "Server: 84 LeaveWorld\n" );
|
|
// simple trigger
|
|
ai.userLogout();
|
|
} break; // LeaveWorld
|
|
case 0x85: // AbnormalStatusUpdate
|
|
{
|
|
ai.notifyEventPacket( UAI_PEVENT_ABNORMALSTATUSUPDATE, bytes, len );
|
|
} break; // AbnormalStatusUpdate
|
|
//case 0x86: // QuestList
|
|
// {
|
|
// log_error( LOG_PACKETNAME, "Server: 86 QuestList\n" );
|
|
// } break; // QuestList
|
|
case 0x89: // PledgeInfo
|
|
{
|
|
// writeC(0x89);
|
|
// writeD(_clan.getClanId());
|
|
// writeS(_clan.getName());
|
|
// writeS(_clan.getAllyName());
|
|
unsigned int clanID = bytes[3] | (bytes[4] << 8) | (bytes[5] << 16) | (bytes[6] << 24);
|
|
//wchar_t clan_name[128] = {0};
|
|
//wchar_t ally_name[128] = {0};
|
|
unsigned int offset = 7; // 2(plen) + 1(pcode) + 4(clanID);
|
|
//wcscpy( clan_name, (const wchar_t *)(bytes + offset) ); // wcscpy is too slow...
|
|
const wchar_t *clan_name = (const wchar_t *)( bytes + offset );
|
|
offset += wcslen( clan_name ) * 2 + 2; // now we can read ally_name from offset
|
|
//wcscpy( ally_name, (const wchar_t *)(bytes + offset) ); // wcscpy is too slow...
|
|
const wchar_t *ally_name = (const wchar_t *)( bytes + offset );
|
|
ClanList_Add( clanID, clan_name, ally_name );
|
|
log_error( LOG_PACKETNAME, "Server: 89 PledgeInfo %u [%S] Ally: [%S]\n",
|
|
clanID, clan_name, ally_name );
|
|
RadarWnd_ForceUpdateCharsList(); // force update chars list
|
|
} break; // PledgeInfo
|
|
//case 0x8C: // Ride
|
|
// {
|
|
// log_error( LOG_PACKETNAME, "Server: 8C Ride\n" );
|
|
// } break; // Ride
|
|
//case 0x9F: // StaticObject
|
|
// {
|
|
// log_error( LOG_PACKETNAME, "Server: 9F StaticObject\n" );
|
|
// L2GamePacket *so = new L2GamePacket();
|
|
// so->setBytes( bytes, len );
|
|
// so->getPacketType(); // read 0x9F
|
|
// unsigned int staticObjectID = so->readUInt();
|
|
// unsigned int objectID = so->readUInt();
|
|
// unsigned int soType = so->readUInt();
|
|
// so->readUInt();
|
|
// so->readUInt();
|
|
// unsigned int isClosed = so->readUInt();
|
|
// so->readUInt();
|
|
// int curHp = so->readInt();
|
|
// int maxHp = so->readInt();
|
|
// if( soType == 1 ) // this is door
|
|
// {
|
|
// char dooropen[32];
|
|
// strcpy( dooropen, "OPEN" );
|
|
// if( isClosed ) strcpy( dooropen, "CLOSED" );
|
|
// log_error_np( LOG_OK, "Door id [%u] objectId [%u] is %s (HP %d / %d)\n",
|
|
// staticObjectID, objectID, dooropen, curHp, maxHp );
|
|
// }
|
|
// else log_error_np( LOG_OK, "StaticObject %u is not door\n", staticObjectID );
|
|
// delete so;
|
|
// } break; // StaticObject
|
|
case 0xA1: // PrivateStoreListSell
|
|
{
|
|
//log_error( LOG_PACKETNAME, "Server: A1 PrivateStoreListSell\n" );
|
|
if( ProtoConv_IsEnabled() )
|
|
if( ProtoConv_ConvertPacket( bytes, len, newBytes, newLen ) )
|
|
bPacketWasModified = true;
|
|
} break; // PrivateStoreListSell
|
|
//case 0xA2: // PrivateStoreMsgSell
|
|
// {
|
|
// //log_error( LOG_PACKETNAME, "Server: A2 PrivateStoreMsgSell\n" );
|
|
// } break; // PrivateStoreMsgSell
|
|
case 0xB9: // MyTargetSelected
|
|
{
|
|
//log_error( LOG_PACKETNAME, "Server: B9 MyTargetSelected [%u]\n", objectID );
|
|
ai.notifyEventPacket( UAI_PEVENT_MYTARGETSELECTED, bytes, len );
|
|
} break; // MyTargetSelected
|
|
case 0xBE: // PrivateStoreListBuy
|
|
{
|
|
//log_error( LOG_PACKETNAME, "Server: BE PrivateStoreListBuy\n" );
|
|
if( ProtoConv_IsEnabled() )
|
|
if( ProtoConv_ConvertPacket( bytes, len, newBytes, newLen ) )
|
|
bPacketWasModified = true;
|
|
} break; // PrivateStoreListBuy
|
|
//case 0xBF: // PrivateStoreMsgBuy
|
|
// {
|
|
// log_error( LOG_PACKETNAME, "Server: BF PrivateStoreMsgBuy\n" );
|
|
// } break; // PrivateStoreMsgBuy
|
|
case 0xC7: // SkillCoolTime
|
|
{
|
|
ai.notifyEventPacket( UAI_PEVENT_SKILLCOOLTIME, bytes, len );
|
|
} break; // SkillCoolTime
|
|
//case 0xCD: // PledgeStatusChanged
|
|
// {
|
|
// log_error( LOG_PACKETNAME, "Server: CD PledgeStatusChanged\n" );
|
|
// } break; // PledgeStatusChanged
|
|
case 0xCE: // RelationChanged
|
|
{
|
|
//log_error( LOG_PACKETNAME, "Server: CE RelationChanged\n" );
|
|
ai.notifyEventPacket( UAI_PEVENT_RELATIONCHANGED, bytes, len );
|
|
if( ProtoConv_IsEnabled() )
|
|
if( ProtoConv_ConvertPacket( bytes, len, newBytes, newLen ) )
|
|
bPacketWasModified = true; // it will be encoded again in the end of this function ;)
|
|
} break; // RelationChanged
|
|
//case 0xE5: // HennaInfo
|
|
// {
|
|
// log_error( LOG_PACKETNAME, "Server: E5 HennaInfo\n" );
|
|
// } break; // HennaInfo
|
|
//case 0xE8: // SendMacroList
|
|
// {
|
|
// log_error( LOG_PACKETNAME, "Server: E8 SendMacroList\n" );
|
|
// } break; // SendMacroList
|
|
//case 0xF2: // ClientSetTime
|
|
// {
|
|
// log_error( LOG_PACKETNAME, "Server: F2 ClientSetTime\n" );
|
|
// } break; // ClientSetTime
|
|
case 0xF4: // PartySpelled
|
|
{
|
|
ai.notifyEventPacket( UAI_PEVENT_PARTYSPELLED, bytes, len );
|
|
} break;
|
|
//case 0xF9: // EtcStatusUpdate
|
|
// {
|
|
// log_error( LOG_PACKETNAME, "Server: F9 EtcStatusUpdate\n" );
|
|
// } break; // EtcStatusUpdate
|
|
case 0xFA: // ShortBuffStatusUpdate
|
|
{
|
|
ai.notifyEventPacket( UAI_PEVENT_SHORTBUFFSTATUSUPDATE, bytes, len );
|
|
} break; // ShortBuffStatusUpdate
|
|
//case 0xFD: // AgitDecoInfo
|
|
// {
|
|
// log_error( LOG_PACKETNAME, "Server: FD AgitDecoInfo\n" );
|
|
// } break; // AgitDecoInfo
|
|
case 0xFE: // double-byte packet
|
|
{
|
|
ptype2 = 0x00;
|
|
if( len >= 5 )
|
|
{
|
|
ptype2 |= (unsigned short int)(bytes[3] & 0xFFFF);
|
|
ptype2 |= (unsigned short int)(bytes[4] << 8 & 0xFFFF);
|
|
switch( ptype2 )
|
|
{
|
|
//case 0x01: // ExRegenMax
|
|
// {
|
|
// log_error( LOG_PACKETNAME, "Server: FE:01 ExRegenMax\n" );
|
|
// } break;
|
|
//case 0x0c: // ExAutoSoulShot FE:0C
|
|
// {
|
|
// log_error( LOG_PACKETNAME, "Server: FE:0C ExAutoSoulShot\n" );
|
|
// } break;
|
|
//case 0x22: // ExSendManorList FE:22
|
|
// {
|
|
// log_error( LOG_PACKETNAME, "Server: FE:22 ExSendManorList\n" );
|
|
// } break;
|
|
//case 0x2f: // ExStorageMaxCount FE:2f
|
|
// {
|
|
// log_error( LOG_PACKETNAME, "Server: FE:2F ExStorageMaxCount\n" );
|
|
// } break;
|
|
//case 0x32: // ExPCCafePointInfo FE:32
|
|
// {
|
|
// log_error( LOG_PACKETNAME, "Server: FE:32 ExPCCafePointInfo\n" );
|
|
// } break;
|
|
//case 0x33: // ExSetCompassZoneCode FE:33
|
|
// {
|
|
// log_error( LOG_PACKETNAME, "Server: FE:33 ExSetCompassZoneCode\n" );
|
|
// } break;
|
|
//case 0x3a: // PledgeSkillList FE:3A
|
|
// {
|
|
// log_error( LOG_PACKETNAME, "Server: FE:3A PledgeSkillList\n" );
|
|
// } break;
|
|
case 0x3f: // PledgeReceiveWarList FE:3F
|
|
{
|
|
log_error( LOG_PACKETNAME, "Server: FE:3F PledgeReceiveWarList\n" );
|
|
ai.notifyEventPacket( UAI_PEVENT_PLEDGERECEIVEWARLIST, bytes, len );
|
|
} break;
|
|
//case 0x40: // PledgeReceiveSubPledgeCreated FE:40
|
|
// {
|
|
// log_error( LOG_PACKETNAME, "Server: FE:40 PledgeReceiveSubPledgeCreated\n" );
|
|
// } break;
|
|
//case 0x5f: // ExBasicActionList FE:5F
|
|
// {
|
|
// log_error( LOG_PACKETNAME, "Server: FE:5F ExBasicActionList\n" );
|
|
// } break;
|
|
case 0x8D: // Gracia Final FE:8D ExNpcQuestHtmlMessage
|
|
{
|
|
if( g_cfg.L2_version >= (int)L2_VERSION_T23 )
|
|
ai.UAI_process_NpcHtml( bytes, len );
|
|
} break;
|
|
//case 0xAC: // possibly old ExBrExtraUserInfo
|
|
// {
|
|
// log_error( LOG_WARNING, "[PACK] possibly old ExBrExtraUserInfo FE:AC\n" );
|
|
// } break; // possibly old ExBrExtraUserInfo
|
|
case 0xB7: // ExBuySellListPacket
|
|
{
|
|
if( ProtoConv_IsEnabled() )
|
|
if( ProtoConv_ConvertPacket( bytes, len, newBytes, newLen ) )
|
|
bPacketWasModified = true; // it will be encoded again in the end of this function ;)
|
|
} break; // ExBuySellListPacket
|
|
//default: log_error( LOG_PACKETNAME, "Server: Unknown opcode2 %04X for IN_GAME packet 0xFE\n",
|
|
// (unsigned int)ptype2 ); break;
|
|
}
|
|
}
|
|
else log_error( LOG_WARNING, "Server: (IN_GAME) sent 0xFE without second opcode!\n" );
|
|
} break; // double-byte packet
|
|
//default:
|
|
// {
|
|
// LOG_LEVEL log_level = LOG_PACKETNAME;
|
|
// if( g_cfg.WarnUnknownPacketsToStdout ) log_level = LOG_WARNING;
|
|
// log_error( log_level, "Server: Unknown packet %02X in state: IN_GAME\n",
|
|
// (unsigned int)ptype );
|
|
// if( g_cfg.DumpUnknownToStdout )
|
|
// {
|
|
// printf( "============================================\n" );
|
|
// L2GamePacket *p = new L2GamePacket( bytes, len );
|
|
// p->dumpToFile( stdout );
|
|
// delete p;
|
|
// printf( "============================================\n" );
|
|
// }
|
|
// } break;
|
|
} // switch( ptype )
|
|
} break; // GCST_IN_GAME
|
|
} // switch( state )
|
|
|
|
} // try
|
|
catch( L2P_Exception& e )
|
|
{
|
|
log_error( LOG_ERROR, "L2P_Exception in PP_full_fromServer\n", e.what() );
|
|
}
|
|
|
|
// all encoding takes place ONLY IF PACKET IS NOT SET TO DROP!!!!
|
|
if( (*newLen) != -1 )
|
|
{
|
|
// re-encode packet again, independently if it was modified or not.
|
|
// ... BUT NEVER ENCODE KeyPacket 0x2E! (though XOR is enabled now)
|
|
// this encodes only original unmodified packet!!!
|
|
if( (bPacketWasModified == false) && (ptype != 0x2e) )
|
|
{
|
|
//PP_full_reencode_packet( bytes, len, this->key_client_sc );
|
|
//log_error( LOG_ERROR, "PP_full_reencode_packet() FAILED\n" );
|
|
//log_error( LOG_OK, "Encoding unmodified packet\n" );
|
|
if( this->xor_enabled ) L2GamePacket::encodeXOR_buffer( bytes, len, this->key_client_sc );
|
|
}
|
|
// encode only modified packet, if packet was modified
|
|
if( bPacketWasModified == true )
|
|
{
|
|
// log modified packet here, when it is decrypted, if log game packets enabled
|
|
if( this->logfile )
|
|
{
|
|
fprintf( this->logfile, "Next is modified:\n" );
|
|
logPacket( (*newBytes), (*newLen), true ); // true - from server
|
|
}
|
|
|
|
//log_error( LOG_OK, "Encoding modified packet\n" ); // <==DEL
|
|
if( this->xor_enabled ) L2GamePacket::encodeXOR_buffer( (*newBytes), (*newLen), this->key_client_sc );
|
|
}
|
|
}
|
|
//else log_error( LOG_OK, "Server: No encode - DROP packet!\n" );
|
|
|
|
return bPacketWasModified;
|
|
}
|