Initial MSVC 2008 projects workspace

This commit is contained in:
alexey.min
2012-02-01 05:25:08 +00:00
commit 03de3bdc95
1446 changed files with 476853 additions and 0 deletions

30
l2detect/AboutDialog.cpp Normal file
View File

@@ -0,0 +1,30 @@
#include "stdafx.h"
#include "Resource.h"
#include "AboutDialog.h"
// EXTERNALS
extern HINSTANCE g_radardll_hinst;
INT_PTR CALLBACK AboutDialogProc( HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam )
{
lParam;
switch( uMsg )
{
case WM_INITDIALOG: /*ConfigDlg_OnInitDialog( hDlg );*/ break;
case WM_COMMAND:
{
switch( LOWORD( wParam ) )
{
case IDOK: EndDialog( hDlg, TRUE ); break;
case IDCANCEL: EndDialog( hDlg, IDCANCEL ); break;
}
} break;
default: return FALSE; break;
}
return TRUE;
}
void AboutDialogStart( HWND hWndParent )
{
DialogBoxParam( g_radardll_hinst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWndParent, AboutDialogProc, 0 );
}

6
l2detect/AboutDialog.h Normal file
View File

@@ -0,0 +1,6 @@
#ifndef H_ABOUT_DLG
#define H_ABOUT_DLG
void AboutDialogStart( HWND hWndParent );
#endif

434
l2detect/BinTree.cpp Normal file
View File

@@ -0,0 +1,434 @@
#include "stdafx.h"
#include "BinTree.h"
BinTreeNode::BinTreeNode()
{
parent = left = right = NULL;
key = 0;
}
BinTreeNode::BinTreeNode( unsigned int keyInit )
{
parent = left = right = NULL;
key = keyInit;
//printf( "BinTreeNode() constructed with key %u\n", key );
}
BinTreeNode::~BinTreeNode()
{
//printf( "~BinTreeNode: destoyed %u\n", key );
}
//=============================================================
//=============================================================
//=============================================================
BinTree::~BinTree()
{
deleteAll();
}
void BinTree::deleteAll()
{
if( root )
{
del_recursive( root );
delete root;
root = NULL;
}
}
void BinTree::del_recursive( BinTreeNode *node )
{
if( !node ) return;
if( node->left )
{
//printf( "cur %u; delete left\n", node->key );
del_recursive( node->left );
delete node->left;
}
if( node->right )
{
//printf( "cur %u; delete right\n", node->key );
del_recursive( node->right );
delete node->right;
}
/*node->left = NULL;
node->right = NULL;
node->key = 0;*/
}
bool BinTree::addNode( BinTreeNode *node )
{
if( !node ) return false;
if( !root )
{
root = node;
root->parent = NULL;
return true;
}
BinTreeNode *cur = root;
//BinTreeNode *prev = root;
while( 1 )
{
//prev = cur;
if( node->key > cur->key )
{
if( cur->right == NULL )
{
//add to right
node->parent = cur;
cur->right = node;
return true;
}
else
{
cur = cur->right;
}
}
else if( node->key < cur->key )
{
if( cur->left == NULL )
{
// add to left
node->parent = cur;
cur->left = node;
return true;
}
else
{
cur = cur->left;
}
}
else if( node->key == cur->key )
{
return false;
}
}
// never executed!
return true;
}
#ifdef _DEBUG
bool BinTree::addNodeDebug( BinTreeNode *node, FILE *f )
{
if( !node )
{
fprintf( f, "BinTree::addNode(): node == NULL!\n" );
return false;
}
if( !root )
{
root = node;
root->parent = NULL;
fprintf( f, "BinTree::addNodeDebug(): added node key %u to root\n", node->key );
return true;
}
BinTreeNode *cur = root;
//BinTreeNode *prev = root;
while( 1 )
{
//prev = cur;
if( node->key > cur->key )
{
if( cur->right == NULL )
{
//add to right
node->parent = cur;
cur->right = node;
fprintf( f, "BinTree::addNodeDebug(): added node key %u to right of key %u\n",
node->key, cur->key );
return true;
}
else
{
cur = cur->right;
}
}
else if( node->key < cur->key )
{
if( cur->left == NULL )
{
// add to left
node->parent = cur;
cur->left = node;
fprintf( f, "BinTree::addNodeDebug(): added node key %u to left of key %u\n",
node->key, cur->key );
return true;
}
else
{
cur = cur->left;
}
}
else if( node->key == cur->key )
{
fprintf( f, "BinTree::addNodeDebug(): key %u already exists\n", node->key );
return false;
}
}
printf( "BinTree::addNode(): never executed!\n" );
return true;
}
#endif
BinTreeNode *BinTree::findNode( unsigned int key )
{
if( !root ) return NULL;
BinTreeNode *cur = root;
while( cur )
{
if( cur->key == key ) return cur;
if( key > cur->key ) cur = cur->right;
else if( key < cur->key ) cur = cur->left;
}
return cur;
}
bool BinTree::delNode( BinTreeNode *node )
{
if( !node ) return false;
if( (node->left == NULL) && (node->right == NULL) )
{
if( node->parent )
{
if( node->parent->left == node ) node->parent->left = NULL;
if( node->parent->right == node ) node->parent->right = NULL;
}
else root = NULL;
delete node;
return true;
}
// <20> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
if( node->left && (node->right == NULL) )
{
if( node->parent ) // <20> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
{
if( node->parent->left == node ) // <20><><EFBFBD><EFBFBD> - <20><><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
{
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><> <20><><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD>
node->parent->left = node->left;
}
if( node->parent->right == node ) // <20><><EFBFBD><EFBFBD> - <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
{
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><> <20><><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD>
node->parent->right = node->left;
}
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> - <20><><EFBFBD> <20><><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
node->left->parent = node->parent;
}
else // <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD> - <20><> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
{
root = node->left;
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> - <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>, <20> <20><><EFBFBD><EFBFBD> <20><><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
node->left->parent = NULL;
}
delete node;
return true;
}
// <20> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
if( node->right && (node->left == NULL) )
{
if( node->parent ) // <20> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
{
if( node->parent->left == node ) // <20><><EFBFBD><EFBFBD> - <20><><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
{
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD>
node->parent->left = node->right;
}
if( node->parent->right == node ) // <20><><EFBFBD><EFBFBD> - <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
{
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD>
node->parent->right = node->right;
}
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> - <20><><EFBFBD> <20><><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
node->right->parent = node->parent;
}
else // <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD> - <20><> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
{
root = node->right;
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> - <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>, <20> <20><><EFBFBD><EFBFBD> <20><><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
node->right->parent = NULL;
}
delete node;
return true;
}
// <20> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD> <20> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
if( node->left && node->right )
{
// <20><><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><> <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD>...
if( node->parent ) // <20> <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
{
node->left->parent = node->parent;
if( node->parent->left == node ) node->parent->left = node->left;
if( node->parent->right == node ) node->parent->right = node->left;
}
else
{
root = node->left;
node->left->parent = NULL;
}
// <20> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
addNode( node->right );
delete node;
}
return true;
}
bool BinTree::delNode( unsigned int key )
{
if( !root ) return false;
BinTreeNode *node = findNode( key );
if( node ) return delNode( node );
return false;
}
#ifdef _DEBUG
BinTreeNode *BinTree::findNodeDebug( unsigned int key, FILE *f )
{
if( !f ) return NULL;
if( !root ) return NULL;
fprintf( f, "BinTree::findNodeDebug( int key = %u )\n", key );
BinTreeNode *cur = root;
while( cur )
{
fprintf( f, "cur = 0x%p (key %u)\n", cur, cur->key );
if( cur->key == key ) { fprintf( f, "found key %u\n", cur->key ); return cur; }
if( key > cur->key ) { fprintf( f, "... > %u; right\n", cur->key ); cur = cur->right; continue; }
if( key < cur->key ) { fprintf( f, "... < %u; left\n", cur->key ); cur = cur->left; continue; }
}
if( cur ) fprintf( f, "returning 0x%p key %u\n", cur, cur->key );
else fprintf( f, "key %u not found\n", key );
return cur;
}
bool BinTree::delNodeDebug( unsigned int key, FILE *f )
{
if( !f || !root ) return false;
BinTreeNode *del = findNodeDebug( key, f );
if( del ) return delNodeDebug( del, f );
return false;
}
bool BinTree::delNodeDebug( BinTreeNode *node, FILE *f )
{
if( !node || !f ) return false;
fprintf( f, "delNodeDebug: del node key %u, parent = 0x%p\n", node->key, node->parent );
if( (node->left == NULL) && (node->right == NULL) )
{
fprintf( f, "case 0: no children\n" );
if( node->parent )
{
if( node->parent->left == node ) node->parent->left = NULL;
if( node->parent->right == node ) node->parent->right = NULL;
}
else root = NULL;
delete node;
return true;
}
// <20> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
if( node->left && (node->right == NULL) )
{
fprintf( f, "case 1: left exists\n" );
if( node->parent ) // <20> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
{
if( node->parent->left == node ) // <20><><EFBFBD><EFBFBD> - <20><><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
{
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><> <20><><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD>
node->parent->left = node->left;
}
if( node->parent->right == node ) // <20><><EFBFBD><EFBFBD> - <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
{
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><> <20><><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD>
node->parent->right = node->left;
}
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> - <20><><EFBFBD> <20><><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
node->left->parent = node->parent;
}
else // <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD> - <20><> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
{
root = node->left;
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> - <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>, <20> <20><><EFBFBD><EFBFBD> <20><><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
node->left->parent = NULL;
}
delete node;
return true;
}
// <20> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
if( node->right && (node->left == NULL) )
{
fprintf( f, "case 2: right exists\n" );
if( node->parent ) // <20> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
{
if( node->parent->left == node ) // <20><><EFBFBD><EFBFBD> - <20><><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
{
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD>
node->parent->left = node->right;
}
if( node->parent->right == node ) // <20><><EFBFBD><EFBFBD> - <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
{
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD>
node->parent->right = node->right;
}
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> - <20><><EFBFBD> <20><><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
node->right->parent = node->parent;
}
else // <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD> - <20><> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
{
root = node->right;
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> - <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>, <20> <20><><EFBFBD><EFBFBD> <20><><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
node->right->parent = NULL;
}
delete node;
return true;
}
// <20> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD> <20> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
if( node->left && node->right )
{
fprintf( f, "case 3: left and right exist\n" );
// <20><><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><> <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD>...
if( node->parent ) // <20> <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
{
node->left->parent = node->parent;
if( node->parent->left == node ) node->parent->left = node->left;
if( node->parent->right == node ) node->parent->right = node->left;
}
else
{
root = node->left;
node->left->parent = NULL;
}
// <20> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
addNodeDebug( node->right, f );
delete node;
}
return true;
}
void printTreeNode( FILE *f, int recur_count, BinTreeNode *node )
{
if( !node ) return;
int i;
//fprintf( f, "\n" );
if( node->parent )
{
if( node->parent->left == node ) fprintf( f, "LEFT " );
else if( node->parent->right == node ) fprintf( f, "RIGHT " );
else fprintf( f, "Parent unknown??? " );
}
else fprintf( f, "ROOT " );
for( i=0; i<recur_count; i++ ) fprintf( f, "." );
fprintf( f, "%d (0x%p)\n", node->key, node );
//fprintf( f, "\n" );
if( node->left ) printTreeNode( f, recur_count+1, node->left );
if( node->right ) printTreeNode( f, recur_count+1, node->right );
}
void BinTree::printTree( FILE *f )
{
if( !f ) return;
if( !root ) fprintf( f, "BinTree is empty!\n" );
printTreeNode( f, 1, root );
}
#endif

47
l2detect/BinTree.h Normal file
View File

@@ -0,0 +1,47 @@
#ifndef BINTREE_H_
#define BINTREE_H_
class BinTreeNode
{
public:
BinTreeNode();
BinTreeNode( unsigned int keyInit );
virtual ~BinTreeNode();
public:
BinTreeNode *parent;
BinTreeNode *left;
BinTreeNode *right;
unsigned int key;
};
class BinTree
{
public:
BinTree() { root = NULL; }
virtual ~BinTree();
public:
bool addNode( BinTreeNode *node );
BinTreeNode *findNode( unsigned int key );
bool delNode( BinTreeNode *node );
bool delNode( unsigned int key );
void deleteAll();
BinTreeNode *getRoot() const { return this->root; }
#ifdef _DEBUG
public:
bool addNodeDebug( BinTreeNode *node, FILE *f );
BinTreeNode *findNodeDebug( unsigned int key, FILE *f );
bool delNodeDebug( unsigned int key, FILE *f );
bool delNodeDebug( BinTreeNode *node, FILE *f );
void printTree( FILE *f );
#endif
protected:
void del_recursive( BinTreeNode *node );
protected:
BinTreeNode *root;
};
#endif /* BINTREE_H_ */

View File

@@ -0,0 +1,54 @@
#include "stdafx.h"
#include "BinTreeNode_Clan.h"
BinTreeNode_Clan::BinTreeNode_Clan(): BinTreeNode()
{
m_clanID = 0;
m_clanName[0] = m_allyName[0] = 0;
//
//wcscpy( m_str_null, L"NULL" );
}
BinTreeNode_Clan::BinTreeNode_Clan( unsigned int clanID,
const wchar_t *clanName,
const wchar_t *allyName ): BinTreeNode()
{
key = clanID;
m_clanID = clanID;
setClanName( clanName );
setAllyName( allyName );
//
//wcscpy( m_str_null, L"NULL" );
}
BinTreeNode_Clan::~BinTreeNode_Clan()
{
m_clanID = 0;
m_clanName[0] = m_allyName[0] = 0;
}
void BinTreeNode_Clan::setClanName( const wchar_t *clanName )
{
m_clanName[0] = 0;
if( clanName ) wcsncpy( m_clanName, clanName, 127 );
m_clanName[127] = 0;
}
void BinTreeNode_Clan::setAllyName( const wchar_t *allyName )
{
m_allyName[0] = 0;
if( allyName ) wcsncpy( m_allyName, allyName, 127 );
m_allyName[127] = 0;
}
const wchar_t *BinTreeNode_Clan::clanName() const
{
((class BinTreeNode_Clan *)this)->m_clanName[127] = 0; // for safe
return m_clanName;
}
const wchar_t *BinTreeNode_Clan::allyName() const
{
((class BinTreeNode_Clan *)this)->m_allyName[127] = 0; // for safe
return m_allyName;
}

View File

@@ -0,0 +1,33 @@
#ifndef BINTREENODE_CLAN_H_
#define BINTREENODE_CLAN_H_
#include "BinTree.h"
class BinTreeNode_Clan :public BinTreeNode
{
public:
BinTreeNode_Clan();
BinTreeNode_Clan( unsigned int clanID,
const wchar_t *clanName,
const wchar_t *allyName );
virtual ~BinTreeNode_Clan();
public:
void setClanID( unsigned int clanID ) { m_clanID = clanID; }
void setClanName( const wchar_t *clanName );
void setAllyName( const wchar_t *allyName );
public:
unsigned int clanID() const { return m_clanID; }
const wchar_t *clanName() const;
const wchar_t *allyName() const;
protected:
unsigned int m_clanID;
wchar_t m_clanName[128];
wchar_t m_allyName[128];
//protected:
//wchar_t m_str_null[16];
};
#endif /* BINTREENODE_CLAN_H_ */

209
l2detect/CharArray.cpp Normal file
View File

@@ -0,0 +1,209 @@
#include "stdafx.h"
#include "Logger.h"
#include "CharArray.h"
#include "WorldObjectTree.h"
#include "RadarDllWnd.h" // to post updates
class L2Player *chars_array[CHARARRAY_MAX_CHARS];
CRITICAL_SECTION charArray_cs;
//HWND charArray_updateHWND;
//UINT charArray_updateMSG;
UINT charArray_count;
void CharArray_Init()
{
charArray_count = 0;
//charArray_updateHWND = NULL;
//charArray_updateMSG = 0;
InitializeCriticalSection( &charArray_cs );
EnterCriticalSection( &charArray_cs );
int i;
for( i=0; i<CHARARRAY_MAX_CHARS; i++ )
{
chars_array[i] = new L2Player();
chars_array[i]->setUnused();
}
LeaveCriticalSection( &charArray_cs );
}
void CharArray_Lock() { EnterCriticalSection( &charArray_cs ); }
void CharArray_Unlock() { LeaveCriticalSection( &charArray_cs ); }
//void CharArray_SetUpdateCommand( HWND hWnd, UINT uMsg )
//{
// charArray_updateHWND = hWnd;
// charArray_updateMSG = uMsg;
//}
//
//void CharArray_PostUpdateMessage()
//{
// if( !charArray_updateHWND ) return;
// if( charArray_updateMSG < WM_USER ) return;
// PostMessage( charArray_updateHWND, charArray_updateMSG, 0, 0 );
//}
void CharArray_Free()
{
int i;
CharArray_Lock();
for( i=0; i<CHARARRAY_MAX_CHARS; i++ )
{
if( chars_array[i] ) delete chars_array[i];
chars_array[i] = NULL;
}
CharArray_Unlock();
charArray_count = 0;
}
void CharArray_AddCharInfo( L2Player *cha )
{
if( !cha ) return;
//log_error( LOG_DEBUG, "CharList_Add: [%S] (oid %u) %s %s %s [%d,%d,%d -> %u]... ",
// name, oid,
// L2Data_getRace( race ), L2Data_getSex( sex ), L2Data_getClass( baseClass ),
// x,y,z, heading );
CharArray_Lock();
// first try to find existing char in world object tree
int idx = -1;
L2OBJECT_TYPE objType = L2OT_NONE;
WorldObjectTree_GetInfoByObjectID( cha->objectID, &objType, &idx );
if( (idx>=0) && (idx<CHARARRAY_MAX_CHARS) && (objType == L2OT_PC) )
{
// update info on existing
if( !chars_array[idx] )
{
CharArray_Unlock();
return;
}
memcpy( chars_array[idx], cha, sizeof(class L2Player) );
//log_error( LOG_USERAI, "Char: Updated idx [%d] [%S]\n", idx, cha->name() );
// update in radar window
RadarWnd_UpdChar( cha->objectID );
}
else // add new
{
idx = CharArray_FindFreeIndex();
if( idx >= 0 )
{
//chars_array[idx]->setFromOther( cha );
memcpy( chars_array[idx], cha, sizeof(class L2Player) );
charArray_count++;
// add char to world object tree
WorldObjectTree_AddObject( cha->objectID, L2OT_PC, idx );
//log_error( LOG_USERAI, "Char: added new [%S] to idx[%d]\n", cha->name(), idx );
// add to radar window
RadarWnd_AddChar( cha->objectID );
}
else log_error( LOG_ERROR, "Error adding character [%S] to chars array! idx = %d\n", cha->getName(), idx );
}
CharArray_Unlock();
}
void CharArray_DeleteCharByObjectID( unsigned int objectID )
{
CharArray_Lock();
BOOL bDelOK = 0;
int idx = CharArray_FindCharByObjectID( objectID );
if( (idx>=0) && (idx<CHARARRAY_MAX_CHARS) )
{
chars_array[idx]->setUnused();
bDelOK = TRUE;
charArray_count--;
}
CharArray_Unlock();
if( bDelOK ) //CharArray_PostUpdateMessage();
RadarWnd_DelChar( objectID );
}
void CharArray_DeleteCharByIdx( int idx )
{
BOOL bDelOK = FALSE;
CharArray_Lock();
if( (idx>=0) && (idx<CHARARRAY_MAX_CHARS) )
{
if( chars_array[idx] )
{
unsigned int objectID = chars_array[idx]->objectID;
//log_error( LOG_USERAI, "Char: Deleted [%S] from [%d]\n", chars_array[idx]->name(), idx );
chars_array[idx]->setUnused();
bDelOK = TRUE;
charArray_count--;
// delete from WorldObjectTree
WorldObjectTree_DelObject( objectID );
RadarWnd_DelChar( objectID );
}
}
CharArray_Unlock();
//if( bDelOK ) CharArray_PostUpdateMessage();
}
void CharArray_DeleteAll()
{
CharArray_Lock();
int i;
for( i=0; i<CHARARRAY_MAX_CHARS; i++ )
{
if( chars_array[i] ) chars_array[i]->setUnused();
}
charArray_count = 0;
CharArray_Unlock();
}
/*void CharList_Display( FILE *f )
{
if( !f || !bt_chars ) return;
CharList_Lock();
fprintf( f, "===== Chars list =====\n" );
BinTreeNode *root = bt_chars->getRoot();
if( !root ) fprintf( f, "Chars list empty!\n" );
else CharList_displayNode( f, root );
fprintf( f, "======================\n" );
//bt_chars->printTree( f );
CharList_Unlock();
}*/
unsigned int CharArray_GetCount() { return charArray_count; }
int CharArray_FindCharByObjectID( unsigned int objectID )
{
int ret = -1;
int i;
CharArray_Lock();
for( i=0; i<CHARARRAY_MAX_CHARS; i++ )
{
if( chars_array[i] == NULL ) continue;
if( chars_array[i]->objectID == objectID )
{
ret = i;
break;
}
}
CharArray_Unlock();
return ret;
}
int CharArray_FindFreeIndex()
{
int i;
CharArray_Lock();
for( i=0; i<CHARARRAY_MAX_CHARS; i++ )
{
if( chars_array[i] == NULL )
{
chars_array[i] = new L2Player(); // allocate new
chars_array[i]->setUnused(); // and set as unused
CharArray_Unlock();
return i;
}
if( chars_array[i]->isUnused() )
{
CharArray_Unlock(); // just return index...
return i;
}
}
CharArray_Unlock();
return -1;
}

26
l2detect/CharArray.h Normal file
View File

@@ -0,0 +1,26 @@
#ifndef CHARLIST_H_
#define CHARLIST_H_
#define CHARARRAY_MAX_CHARS 1024
extern class L2Player *chars_array[CHARARRAY_MAX_CHARS];
void CharArray_Init();
void CharArray_Free();
void CharArray_Lock();
void CharArray_Unlock();
void CharArray_AddCharInfo( L2Player *cha );
void CharArray_DeleteCharByObjectID( unsigned int objectID );
void CharArray_DeleteCharByIdx( int idx );
void CharArray_DeleteAll();
int CharArray_FindCharByObjectID( unsigned int objectID );
int CharArray_FindFreeIndex();
//void CharArray_Display( FILE *f );
//void CharArray_SetUpdateCommand( HWND hWnd, UINT uMsg );
unsigned int CharArray_GetCount();
#endif /* CHARLIST_H_ */

227
l2detect/ClanList.cpp Normal file
View File

@@ -0,0 +1,227 @@
#include "stdafx.h"
#include "Logger.h"
#include "ClanList.h"
#include "BinTreeNode_Clan.h"
BinTree *bt_clans = NULL;
HWND clanList_updateHWND;
UINT clanList_updateMSG;
CRITICAL_SECTION clanList_cs;
UINT clanList_count;
void ClanList_Init()
{
clanList_count = 0;
clanList_updateHWND = NULL;
clanList_updateMSG = 0;
InitializeCriticalSection( &clanList_cs );
EnterCriticalSection( &clanList_cs );
if( bt_clans == NULL )
{
log_error( LOG_DEBUG, "ClanList_Init(): create bintree\n" );
bt_clans = new BinTree();
}
else
{
log_error( LOG_DEBUG, "ClanList_Init(): clear bintree\n" );
bt_clans->deleteAll();
}
LeaveCriticalSection( &clanList_cs );
}
void ClanList_Lock() { EnterCriticalSection( &clanList_cs ); }
void ClanList_Unlock() { LeaveCriticalSection( &clanList_cs ); }
void ClanList_SetUpdateCommand( HWND hWnd, UINT uMsg )
{
clanList_updateHWND = hWnd;
clanList_updateMSG = uMsg;
}
void ClanList_SendUpdate()
{
if( !clanList_updateHWND ) return;
if( clanList_updateMSG < WM_USER ) return;
PostMessage( clanList_updateHWND, clanList_updateMSG, 0, 0 );
}
void ClanList_Free()
{
if( !bt_clans ) log_error( LOG_DEBUG, "ClanList_Free() - already NULL\n" );
else
{
ClanList_Lock();
delete bt_clans;
bt_clans = NULL;
ClanList_Unlock();
ClanList_SendUpdate();
log_error( LOG_DEBUG, "ClanList_Free() - freed\n" );
}
clanList_count = 0;
}
void ClanList_Add( unsigned int clanID, const wchar_t *clanName, const wchar_t *allyName )
{
if( !clanName || !allyName ) return;
log_error( LOG_DEBUG, "ClanList_Add: [%S] (id %u) [%S]... ", clanName, clanID, allyName );
ClanList_Lock();
if( !bt_clans )
{
log_error( LOG_DEBUG, " (BinTree created)... \n" );
bt_clans = new BinTree();
}
BinTreeNode_Clan *node = new BinTreeNode_Clan( clanID, clanName, allyName );
// first try to find existing char
BinTreeNode *existing = bt_clans->findNode( clanID );
if( existing )
{
// update info on existing
BinTreeNode_Clan *cl = (BinTreeNode_Clan *)existing;
cl->setClanName( clanName );
cl->setAllyName( allyName );
cl->setClanID( clanID );
//printf( "Updated info for [%S]\n", clanName );
}
else // add new
{
//if( bt_clans->addNodeDebug( node, stdout ) ) log_error_np( LOG_DEBUG, "OK\n" );
if( bt_clans->addNode( node ) )
{
clanList_count++;
log_error_np( LOG_DEBUG, "OK\n" );
}
else
{
log_error_np( LOG_DEBUG, "FAILED\n" );
log_error( LOG_ERROR, "Error adding clan [%S] to clan list!\n", clanName );
delete node;
}
}
ClanList_Unlock();
ClanList_SendUpdate();
}
void ClanList_Delete( unsigned int clanID )
{
if( !bt_clans ) return;
log_error( LOG_DEBUG, "ClanList_Delete( %u )... ", clanID );
//if( bt_clans->delNodeDebug( oid, stdout ) ) log_error_np( LOG_DEBUG, "OK\n" );
ClanList_Lock();
if( bt_clans->delNode( clanID ) )
{
clanList_count--;
log_error_np( LOG_DEBUG, "OK\n" );
}
else
{
log_error_np( LOG_DEBUG, "FAILED\n" );
//log_error( LOG_ERROR, "Error deleting object %u from chars list!\n", oid );
}
ClanList_Unlock();
ClanList_SendUpdate();
}
void ClanList_DeleteAll()
{
if( !bt_clans ) return;
ClanList_Lock();
bt_clans->deleteAll();
clanList_count = 0;
ClanList_Unlock();
ClanList_SendUpdate();
}
void ClanList_displayNode( FILE *f, BinTreeNode *node )
{
if( !f || !node ) return;
BinTreeNode_Clan *btn = (BinTreeNode_Clan *)node;
fprintf( f, " %S Ally %S [%u]\n", btn->clanName(), btn->allyName(), btn->clanID() );
if( node->left ) ClanList_displayNode( f, node->left );
if( node->right ) ClanList_displayNode( f, node->right );
}
void ClanList_Display( FILE *f )
{
if( !f || !bt_clans ) return;
ClanList_Lock();
fprintf( f, "===== Clans list =====\n" );
BinTreeNode *root = bt_clans->getRoot();
if( !root ) fprintf( f, "Clans list empty!\n" );
else ClanList_displayNode( f, root );
fprintf( f, "======================\n" );
//bt_clans->printTree( f );
ClanList_Unlock();
}
unsigned int ClanList_GetCount() { return clanList_count; }
void ClanList_GetClansArray_ProcessNode( BinTreeNode_Clan **clans_array, int *pi, BinTreeNode *cur )
{
if( !cur || !clans_array || !pi ) return;
BinTreeNode_Clan *cl = (BinTreeNode_Clan *)cur;
clans_array[(*pi)] = new BinTreeNode_Clan( (*cl) );
clans_array[(*pi)]->left = clans_array[(*pi)]->right = NULL;
(*pi) = (*pi) + 1;
if( cur->left ) ClanList_GetClansArray_ProcessNode( clans_array, pi, cur->left );
if( cur->right ) ClanList_GetClansArray_ProcessNode( clans_array, pi, cur->right );
}
void *ClanList_GetClansArray()
{
if( !bt_clans ) return NULL;
if( clanList_count <= 0 )
{
clanList_count = 0;
return NULL;
}
BinTreeNode_Clan **clans_array = (BinTreeNode_Clan **)malloc( (sizeof(void *) * clanList_count ) );
if( !clans_array ) return NULL;
int i;
for( i=0; i<(int)clanList_count; i++ ) clans_array[i] = NULL;
BinTreeNode *cur;
ClanList_Lock();
cur = bt_clans->getRoot();
if( !cur )
{
ClanList_Unlock();
free( clans_array );
return NULL;
}
i = 0;
ClanList_GetClansArray_ProcessNode( clans_array, &i, cur );
ClanList_Unlock();
return clans_array;
}
void ClanList_FreeClansArray( void *p )
{
if( !p ) return;
free( p );
}
void ClanList_GetClanNameByID( unsigned int clanID, TCHAR *out )
{
if( !out || !bt_clans ) return;
out[0] = 0;
ClanList_Lock();
BinTreeNode_Clan *cl = (BinTreeNode_Clan *)bt_clans->findNode( clanID );
if( !cl )
{
ClanList_Unlock();
return;
}
#if defined(UNICODE) || defined(_UNICODE)
_tcscpy( out, cl->clanName() );
#else
WideCharToMultiByte( CP_ACP, 0, cl->clanName(), -1, out, 127, NULL, NULL );
#endif
ClanList_Unlock();
}

22
l2detect/ClanList.h Normal file
View File

@@ -0,0 +1,22 @@
#ifndef CLANLIST_H_
#define CLANLIST_H_
void ClanList_Init();
void ClanList_Free();
void ClanList_Add( unsigned int clanID, const wchar_t *clanName, const wchar_t *allyName );
void ClanList_Delete( unsigned int clanID );
void ClanList_DeleteAll();
void ClanList_Display( FILE *f );
void ClanList_SetUpdateCommand( HWND hWnd, UINT uMsg );
unsigned int ClanList_GetCount();
void *ClanList_GetClansArray();
void ClanList_FreeClansArray( void *p );
void ClanList_GetClanNameByID( unsigned int clanID, TCHAR *out );
#endif /* CLANLIST_H_ */

163
l2detect/ClanWarList.cpp Normal file
View File

@@ -0,0 +1,163 @@
#include "stdafx.h"
#include "ClanWarList.h"
#include "Logger.h"
ClanWarList::ClanWarList()
{
int i;
numDeclared = numUnderAttack = 0;
for( i=0; i<MAX_CLANWARS; i++ )
{
cnDeclared[i] = NULL;
cnUnderAttack[i] = NULL;
}
}
ClanWarList::~ClanWarList()
{
clear();
}
void ClanWarList::clear()
{
int i;
numDeclared = numUnderAttack = 0;
for( i=0; i<MAX_CLANWARS; i++ )
{
if( cnDeclared[i] ) free( cnDeclared[i] );
if( cnUnderAttack[i] ) free( cnUnderAttack[i] );
cnDeclared[i] = NULL;
cnUnderAttack[i] = NULL;
}
}
void ClanWarList::clearDeclared()
{
int i;
numDeclared = 0;
for( i=0; i<MAX_CLANWARS; i++ )
{
if( cnDeclared[i] ) free( cnDeclared[i] );
cnDeclared[i] = NULL;
}
}
void ClanWarList::clearUnderAttack()
{
int i;
numUnderAttack = 0;
for( i=0; i<MAX_CLANWARS; i++ )
{
if( cnUnderAttack[i] ) free( cnUnderAttack[i] );
cnUnderAttack[i] = NULL;
}
}
/*void ClanWarList::parse_PledgeReceiveWarList( const unsigned char *bytes, unsigned int length )
{
if( !bytes || (length<1) ) return;
L2GamePacket *p = new L2GamePacket( bytes, length );*/
void ClanWarList::parse_PledgeReceiveWarList( void *l2_game_packet )
{
if( !l2_game_packet ) return;
L2GamePacket *p = (L2GamePacket *)l2_game_packet;
//
p->getPacketType(); // 0xFE
p->readUShort(); // 0x003F
//
int i;
wchar_t *strTemp;
int tab = p->readInt();
// clear data
switch( tab )
{
case 0: clearDeclared(); break;
case 1: clearUnderAttack(); break;
}
//
p->readInt(); // page, always 0x00.. on L2J
int warsCount = p->readInt();
for( i=0; i<warsCount; i++ )
{
strTemp = p->readUnicodeString(); // clan name
p->readInt(); // ??
p->readInt(); // ??
// add
switch( tab )
{
case 0: { cnDeclared[i] = strTemp; numDeclared++; } break;
case 1: { cnUnderAttack[i] = strTemp; numUnderAttack++; } break;
}
}
//delete p; // packet deleted by calling function
#ifdef _DEBUG
log_error( LOG_USERAI, "PledgeReceiveWarList results: %d declared, %d under attack\n", numDeclared, numUnderAttack );
//log_error( LOG_USERAI, "Declared: " );
//for( i=0; i<numDeclared; i++ ) log_error_np( LOG_OK, "[%S] ", cnDeclared[i] );
//log_error_np( LOG_USERAI, "\n" );
//log_error( LOG_USERAI, "Under attack: " );
//for( i=0; i<numUnderAttack; i++ ) log_error_np( LOG_OK, "[%S] ", cnUnderAttack[i] );
//log_error_np( LOG_USERAI, "\n" );
#endif
}
/*
protected void writeImpl()
{
writeC(0xfe); // FE:3F PledgeReceiveWarList
writeH(0x3f);
writeD(_tab); // type : 0 = Declared, 1 = Under Attack
writeD(0x00); // page
writeD(_tab == 0 ? _clan.getWarList().size() : _clan.getAttackerList().size()); // warsCount
for(Integer i : _tab == 0 ? _clan.getWarList() : _clan.getAttackerList())
{
L2Clan clan = ClanTable.getInstance().getClan(i);
if (clan == null) continue;
writeS(clan.getName());
writeD(_tab); //??
writeD(_tab); //??
}
}
*/
CLANWARSTATE ClanWarList::getWarForClan( const wchar_t *wszClanName )
{
if( !wszClanName ) return CLANWAR_NOWAR;
if( (numDeclared == 0) && (numUnderAttack == 0) ) return CLANWAR_NOWAR;
CLANWARSTATE ret;;
int declared, underattack;
int i;
// declared?
declared = 0;
if( numDeclared > 0 )
{
for( i=0; i<numDeclared; i++ )
{
if( wcscmp( wszClanName, cnDeclared[i] ) == 0 )
{
declared = 1;
break;
}
}
}
// underattack?
underattack = 0;
if( numUnderAttack > 0 )
{
for( i=0; i<numUnderAttack; i++ )
{
if( wcscmp( wszClanName, cnUnderAttack[i] ) == 0 )
{
underattack = 1;
break;
}
}
}
ret = CLANWAR_NOWAR;
if( declared && !underattack ) ret = CLANWAR_DECLARED;
if( !declared && underattack ) ret = CLANWAR_UNDERATTACK;
if( declared && underattack ) ret = CLANWAR_BOTH;
return ret;
}

34
l2detect/ClanWarList.h Normal file
View File

@@ -0,0 +1,34 @@
#ifndef H_CLAN_WAR_LIST
#define H_CLAN_WAR_LIST
#define MAX_CLANWARS 32
typedef enum eCLANWARSTATE
{
CLANWAR_NOWAR = 0,
CLANWAR_DECLARED,
CLANWAR_UNDERATTACK,
CLANWAR_BOTH
} CLANWARSTATE, *LPCLANWARSTATE;
class ClanWarList
{
public:
ClanWarList();
~ClanWarList();
void clear();
void clearDeclared();
void clearUnderAttack();
//void parse_PledgeReceiveWarList( const unsigned char *bytes, unsigned int length );
void parse_PledgeReceiveWarList( void *l2_game_packet );
public:
CLANWARSTATE getWarForClan( const wchar_t *wszClanName );
public:
int numDeclared;
int numUnderAttack;
wchar_t *cnDeclared[MAX_CLANWARS];
wchar_t *cnUnderAttack[MAX_CLANWARS];
};
#endif

39
l2detect/ClassPri.cpp Normal file
View File

@@ -0,0 +1,39 @@
#include "stdafx.h"
#include "ClassPri.h"
ClassPriorities::ClassPriorities()
{
int i;
for( i=0; i<L2MaxClasses; i++ )
m_pri[i] = 0;
}
ClassPriorities::~ClassPriorities()
{
}
void ClassPriorities::initDefaultPriorityList()
{
int i;
for( i=0; i<L2MaxClasses; i++ ) setPriForClass( i, 10 );
setPriForClass( 97, 500 );
setPriForClass( 105, 400 );
setPriForClass( 16, 200 );
setPriForClass( 30, 100 );
}
void ClassPriorities::setPriForClass( int classId, int pri )
{
if( classId<0 || (classId>=L2MaxClasses) || (pri<0) ) return;
if( classId>=58 && classId<=87 ) return; // unused intreval 1
if( classId>=119 && classId<=122 ) return; // unused intreval 1
m_pri[classId] = pri;
}
int ClassPriorities::getPriForClass( int classId ) const
{
if( classId<0 || (classId>=L2MaxClasses) ) return -1;
if( classId>=58 && classId<=87 ) return -1; // unused intreval 1
if( classId>=119 && classId<=122 ) return -1; // unused intreval 1
return m_pri[classId];
}

20
l2detect/ClassPri.h Normal file
View File

@@ -0,0 +1,20 @@
#pragma once
#ifndef L2MaxClasses // if L2Data.h from L2Packets.h is not included...
#define L2MaxClasses 137 // >= Kamael
#endif
class ClassPriorities
{
public:
ClassPriorities();
~ClassPriorities();
public:
void initDefaultPriorityList();
void setPriForClass( int classId, int pri );
int getPriForClass( int classId ) const;
protected:
int m_pri[L2MaxClasses];
};

274
l2detect/ConfigDlg.cpp Normal file
View File

@@ -0,0 +1,274 @@
#include "stdafx.h"
#include "Resource.h"
#include "ConfigIni.h"
#include "ConfigDlg.h"
#include "Logger.h"
// listeners
#include "LoginListener.h"
#include "GameListener.h"
// EXTERNALS
extern HINSTANCE g_radardll_hinst;
// global app configuration
extern CConfig g_cfg;
extern LoginListener *g_plogin;
extern GameListener *g_pgame;
extern char g_error_logger_strtype[LOG_LEVELS][16]; // Warning!!! HACK!!!
void ConfigDlg_OnInitDialog( HWND hDlg );
void ConfigDlg_OnOK( HWND hDlg, BOOL bEndDialog );
void ConfigDlg_OnApply( HWND hDlg );
void ConfigDlg_UpateEnabledControls( HWND hDlg );
INT_PTR CALLBACK ConfigDlgProc( HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam )
{
lParam;
switch( uMsg )
{
case WM_INITDIALOG: ConfigDlg_OnInitDialog( hDlg ); break;
case WM_COMMAND:
{
switch( LOWORD( wParam ) )
{
case IDOK: ConfigDlg_OnOK( hDlg, TRUE ); break;
case IDCANCEL: EndDialog( hDlg, IDCANCEL ); break;
case IDC_APPLY: ConfigDlg_OnApply( hDlg ); break;
}
ConfigDlg_UpateEnabledControls( hDlg );
} break;
default: return FALSE; break;
}
return TRUE;
}
void ConfigDialogStart( HWND hWndParent )
{
DialogBoxParam( g_radardll_hinst, MAKEINTRESOURCE(IDD_CONFIG), hWndParent, ConfigDlgProc, 0 );
}
void ConfigDlg_OnInitDialog( HWND hDlg )
{
HWND h;
int i;
// L2 Version
h = GetDlgItem( hDlg, IDC_CB_L2VER );
SendMessage( h, CB_ADDSTRING, 0, (LPARAM)TEXT("Chaotic Throne 1 - The Kamael") );
SendMessage( h, CB_ADDSTRING, 0, (LPARAM)TEXT("Chaotic Throne 1.5 - Hellbound") );
SendMessage( h, CB_ADDSTRING, 0, (LPARAM)TEXT("Chaotic Throne 2 - Gracia Part 1") );
SendMessage( h, CB_ADDSTRING, 0, (LPARAM)TEXT("Chaotic Throne 2.2 - Gracia Part 2") );
SendMessage( h, CB_ADDSTRING, 0, (LPARAM)TEXT("Chaotic Throne 2.3 - Gracia Final") );
SendMessage( h, CB_ADDSTRING, 0, (LPARAM)TEXT("Chaotic Throne 2.4 - Gracia Epilogue") );
SendMessage( h, CB_SETCURSEL, (WPARAM)g_cfg.L2_version, 0 );
// L2 Client Version
h = GetDlgItem( hDlg, IDC_CB_L2CVER );
SendMessage( h, CB_ADDSTRING, 0, (LPARAM)TEXT("Chaotic Throne 1 - The Kamael") );
SendMessage( h, CB_ADDSTRING, 0, (LPARAM)TEXT("Chaotic Throne 1.5 - Hellbound") );
SendMessage( h, CB_ADDSTRING, 0, (LPARAM)TEXT("Chaotic Throne 2 - Gracia Part 1") );
SendMessage( h, CB_ADDSTRING, 0, (LPARAM)TEXT("Chaotic Throne 2.2 - Gracia Part 2") );
SendMessage( h, CB_ADDSTRING, 0, (LPARAM)TEXT("Chaotic Throne 2.3 - Gracia Final") );
SendMessage( h, CB_ADDSTRING, 0, (LPARAM)TEXT("Chaotic Throne 2.4 - Gracia Epilogue") );
SendMessage( h, CB_SETCURSEL, (WPARAM)g_cfg.L2_client_version, 0 );
// full mode enable
CheckDlgButton( hDlg, IDC_C_ENABLE_MODGT, g_cfg.EnableModifyGameTraffic );
// override game protocolversion
SetDlgItemInt( hDlg, IDC_E_OVERRIDE_GPV, g_cfg.OverrideGameProtocolVersion, FALSE );
// thread priority raise enable
CheckDlgButton( hDlg, IDC_C_ENABLE_THREADPRI, g_cfg.ThreadProirityRaiseEnable );
// reply L2J GameGuardQuery
CheckDlgButton( hDlg, IDC_C_GAMEGUARDREPLY, g_cfg.ReplyL2JGameGuardQuery );
// Gracia Epilogue protocol 148 hacks
CheckDlgButton( hDlg, IDC_C_EPILOGUE_148_146, g_cfg.GraciaEpilogueProtocol_148_hacks );
// L2Walker_DropRequestGMList
CheckDlgButton( hDlg, IDC_C_L2WDROPGMLIST, g_cfg.L2Walker_DropRequestGMList );
// L2Walker_FixMoveBackwardToLocation
CheckDlgButton( hDlg, IDC_C_L2WMOVEFIX, g_cfg.L2Walker_FixMoveBackwardToLocation );
// L2Walker_FixChangeWaitType2
CheckDlgButton( hDlg, IDC_C_L2WSITFIX, g_cfg.L2Walker_FixChangeWaitType2 );
// L2Walker_InjectStatusUpdate
CheckDlgButton( hDlg, IDC_C_L2WALKER_INJECTSTATUSUPDATE, g_cfg.L2Walker_InjectStatusUpdate );
// log level
h = GetDlgItem( hDlg, IDC_CB_LOGLEVEL );
for( i=LOG_OK; i<=LOGLEVEL_LAST; i++ )
{
char *pstr = g_error_logger_strtype[i];
SendMessageA( h, CB_ADDSTRING, 0, (LPARAM)pstr );
}
SendMessage( h, CB_SETCURSEL, (WPARAM)(int)g_cfg.WarnMessageLevel, 0 );
// Log Game Packets
CheckDlgButton( hDlg, IDC_C_LOGGAMEP, g_cfg.LogGamePackets );
// Log packets FileName Prefix
SetDlgItemTextA( hDlg, IDC_E_LOGFNPREFIX, g_cfg.LogGameFileNamePrefix );
// warn unknown packets
CheckDlgButton( hDlg, IDC_C_WARNUNKP, g_cfg.WarnUnknownPacketsToStdout );
// FakeListenLoginPort
SetDlgItemInt( hDlg, IDC_E_FLPORT, g_cfg.FakeListenLoginPort, TRUE );
// FakeListenGamePort
SetDlgItemInt( hDlg, IDC_E_FGPORT, g_cfg.FakeListenGamePort, TRUE );
// RealLoginServerIP
SetDlgItemTextA( hDlg, IDC_E_REALIP, g_cfg.RealLoginServerIP );
// RealLoginServerPort
SetDlgItemInt( hDlg, IDC_E_REALPORT, g_cfg.RealLoginServerPort, TRUE );
// PlayGameServerNo
//SetDlgItemInt( hDlg, IDC_E_PLAYGSNO, g_cfg.PlayGameServerNo, TRUE );
// forced game server select setting
SetDlgItemTextA( hDlg, IDC_E_FORCEGSIP, g_cfg.ForceGameServerIP );
SetDlgItemInt( hDlg, IDC_E_FORCEGSPORT, g_cfg.ForceGameServerPort, TRUE );
ConfigDlg_UpateEnabledControls( hDlg );
}
void ConfigDlg_OnOK( HWND hDlg, BOOL bEndDialog )
{
// L2 version
g_cfg.L2_version = (int)SendMessage( GetDlgItem( hDlg, IDC_CB_L2VER ), CB_GETCURSEL, 0, 0 );
// L2 client version
g_cfg.L2_client_version = (int)SendMessage( GetDlgItem( hDlg, IDC_CB_L2CVER ), CB_GETCURSEL, 0, 0 );
// full mode enable
g_cfg.EnableModifyGameTraffic = IsDlgButtonChecked( hDlg, IDC_C_ENABLE_MODGT );
// override game protocolversion
g_cfg.OverrideGameProtocolVersion = (int)GetDlgItemInt( hDlg, IDC_E_OVERRIDE_GPV, NULL, TRUE );
// thread priority raise enable
g_cfg.ThreadProirityRaiseEnable = IsDlgButtonChecked( hDlg, IDC_C_ENABLE_THREADPRI );
// reply L2J GameGuardQuery
g_cfg.ReplyL2JGameGuardQuery = IsDlgButtonChecked( hDlg, IDC_C_GAMEGUARDREPLY );
// Gracia Epilogue protocol 148 hacks
g_cfg.GraciaEpilogueProtocol_148_hacks = IsDlgButtonChecked( hDlg, IDC_C_EPILOGUE_148_146 );
// L2Walker_DropRequestGMList
g_cfg.L2Walker_DropRequestGMList = IsDlgButtonChecked( hDlg, IDC_C_L2WDROPGMLIST );
// L2Walker_FixMoveBackwardToLocation
g_cfg.L2Walker_FixMoveBackwardToLocation = IsDlgButtonChecked( hDlg, IDC_C_L2WMOVEFIX );
// L2Walker_FixChangeWaitType2
g_cfg.L2Walker_FixChangeWaitType2 = IsDlgButtonChecked( hDlg, IDC_C_L2WSITFIX );
// L2Walker_InjectStatusUpdate
g_cfg.L2Walker_InjectStatusUpdate = IsDlgButtonChecked( hDlg, IDC_C_L2WALKER_INJECTSTATUSUPDATE );
// log level
HWND h = GetDlgItem( hDlg, IDC_CB_LOGLEVEL );
g_cfg.WarnMessageLevel = (int)SendMessage( h, CB_GETCURSEL, 0, 0 );
//
// Log Game Packets
g_cfg.LogGamePackets = IsDlgButtonChecked( hDlg, IDC_C_LOGGAMEP );
// Log packets FileName Prefix
GetDlgItemTextA( hDlg, IDC_E_LOGFNPREFIX, g_cfg.LogGameFileNamePrefix,
sizeof(g_cfg.LogGameFileNamePrefix)-1 );
// warn unknown packets
g_cfg.WarnUnknownPacketsToStdout = IsDlgButtonChecked( hDlg, IDC_C_WARNUNKP );
//
// FakeListenLoginPort
g_cfg.FakeListenLoginPort = GetDlgItemInt( hDlg, IDC_E_FLPORT, NULL, TRUE );
// FakeListenGamePort
g_cfg.FakeListenGamePort = GetDlgItemInt( hDlg, IDC_E_FGPORT, NULL, TRUE );
// RealLoginServerIP
GetDlgItemTextA( hDlg, IDC_E_REALIP, g_cfg.RealLoginServerIP, sizeof(g_cfg.RealLoginServerIP) );
// RealLoginServerPort
g_cfg.RealLoginServerPort = GetDlgItemInt( hDlg, IDC_E_REALPORT, NULL, TRUE );
// PlayGameServerNo
//g_cfg.PlayGameServerNo = GetDlgItemInt( hDlg, IDC_E_PLAYGSNO, NULL, TRUE );
// forced GS settings
GetDlgItemTextA( hDlg, IDC_E_FORCEGSIP, g_cfg.ForceGameServerIP, sizeof(g_cfg.ForceGameServerIP) );
g_cfg.ForceGameServerPort = GetDlgItemInt( hDlg, IDC_E_FORCEGSPORT, NULL, TRUE );
//
g_cfg.SaveConfig();
if( bEndDialog == TRUE ) EndDialog( hDlg, IDOK );
}
void ConfigDlg_OnApply( HWND hDlg )
{
if( !g_plogin || !g_pgame ) return;
// get SOME config values and save config
ConfigDlg_OnOK( hDlg, FALSE );
//
// check in client is in game
bool running = false;
if( g_plogin )
if( g_plogin->isRunning() ) running = true;
if( g_pgame )
if( g_pgame->isRunning() ) running = true;
if( running )
{
log_error( LOG_WARNING, "ConfigDlg_OnApply(): warning: game is running!\n" );
int answer = MessageBox( hDlg,
TEXT("Warning! Listeners are running now!\n")
TEXT("If you press 'Yes', connection will be terminated.\n")
TEXT("If you press 'No', changes will no take effect until next connection.\n") ,
TEXT("Warning! Game running!"), MB_YESNO | MB_ICONWARNING );
if( answer == IDNO ) return;
log_error( LOG_WARNING, "ConfigDlg_OnApply(): connections will be terminated.\n" );
}
//
if( g_plogin ) g_plogin->signalStop(); // LoginListener may not be started in ingame mode at all
g_pgame->signalStop();
if( g_plogin ) // LoginListener may not be started in ingame mode at all
{
if( !g_plogin->waitStopped( 5000 ) )
{
ErrorLogger_FlushLogFile();
MessageBox( hDlg, TEXT("Login Listener stop wait failed! Terminated..."), TEXT("Warning!"), MB_ICONWARNING );
g_plogin->terminateThread();
}
} // LoginListener may not be started in ingame mode at all
if( !g_pgame->waitStopped( 5000 ) )
{
ErrorLogger_FlushLogFile();
MessageBox( hDlg, TEXT("Game Listener stop wait failed! Terminated..."), TEXT("Warning!"), MB_ICONWARNING );
g_pgame->terminateThread();
}
if( g_plogin ) // LoginListener may not be started in ingame mode at all
{
if( !g_plogin->start() )
{
ErrorLogger_FlushLogFile();
MessageBox( hDlg, TEXT("Login Listener start failed! O_o"), TEXT("Warning!"), MB_ICONWARNING );
}
} // LoginListener may not be started in ingame mode at all
if( !g_pgame->start() )
{
ErrorLogger_FlushLogFile();
MessageBox( hDlg, TEXT("Game Listener start failed! O_o"), TEXT("Warning!"), MB_ICONWARNING );
}
ErrorLogger_FlushLogFile();
}
void ConfigDlg_UpateEnabledControls( HWND hDlg )
{
HWND hs, hc;
hs = GetDlgItem( hDlg, IDC_CB_L2VER );
hc = GetDlgItem( hDlg, IDC_CB_L2CVER );
int srv_ver = ComboBox_GetCurSel( hs );
int cl_ver = ComboBox_GetCurSel( hc );
if( srv_ver == 5 && cl_ver == 5 )
EnableWindow( GetDlgItem( hDlg, IDC_C_EPILOGUE_148_146 ), TRUE );
else
{
CheckDlgButton( hDlg, IDC_C_EPILOGUE_148_146, 0 );
EnableWindow( GetDlgItem( hDlg, IDC_C_EPILOGUE_148_146 ), FALSE );
}
// disable some controls in ingame mode
if( g_cfg.isInGameMode == true )
{
EnableWindow( GetDlgItem( hDlg, IDC_C_L2WMOVEFIX ), FALSE );
EnableWindow( GetDlgItem( hDlg, IDC_C_L2WDROPGMLIST ), FALSE );
EnableWindow( GetDlgItem( hDlg, IDC_C_L2WSITFIX ), FALSE );
EnableWindow( GetDlgItem( hDlg, IDC_C_L2WALKER_INJECTSTATUSUPDATE ), FALSE );
EnableWindow( GetDlgItem( hDlg, IDC_E_FLPORT ), FALSE );
EnableWindow( GetDlgItem( hDlg, IDC_E_REALIP ), FALSE );
EnableWindow( GetDlgItem( hDlg, IDC_E_REALPORT ), FALSE );
//EnableWindow( GetDlgItem( hDlg, IDC_E_PLAYGSNO ), FALSE );
}
// also temporarily disable some controls
EnableWindow( GetDlgItem( hDlg, IDC_C_ENABLE_MODGT ), FALSE );
}

6
l2detect/ConfigDlg.h Normal file
View File

@@ -0,0 +1,6 @@
#ifndef H_CONFIG_DLG
#define H_CONFIG_DLG
void ConfigDialogStart( HWND hWndParent );
#endif

478
l2detect/ConfigIni.cpp Normal file
View File

@@ -0,0 +1,478 @@
#include "stdafx.h"
#include "ConfigIni.h"
CConfig::CConfig()
{
_initNull();
}
CConfig::~CConfig()
{
_initNull();
}
void CConfig::_initNull()
{
isInGameMode = false;
L2_version = 0;
L2_client_version = 0;
//
szCfgFileName[0] = FakeListenLoginIP[0] = FakeListenGameIP[0];
FakeListenLoginPort = FakeListenGamePort = 0;
// Forward connection to
RealLoginServerIP[0] = 0;
RealLoginServerPort = 0;
// Catch game server traffic
//PlayGameServerNo = 0;
ForceGameServerIP[0] = 0;
ForceGameServerPort = 0;
IngameGameServerPort = 7777;
// Logging setup
LogGamePackets = 0;
LogGameFileNamePrefix[0] = 0;
WarnUnknownPacketsToStdout = DumpUnknownToStdout = WarnMessageLevel = 0;
// hacks
EnableModifyGameTraffic = 0; // enable or disable game protocol-level hacks
OverrideGameProtocolVersion = 0;
ReplyL2JGameGuardQuery = 0;
GraciaEpilogueProtocol_148_hacks = 0;
// L2Walker fixes
L2Walker_DropRequestGMList = 0;
L2Walker_FixMoveBackwardToLocation = 1;
L2Walker_FixChangeWaitType2 = 1;
L2Walker_InjectStatusUpdate = 0;
// Invis GM
InvisGMTrackEnable = 1;
InvisGMSpeed = 400; // //gmspeed 4
}
bool CConfig::ReadConfig( const wchar_t *szConfigFileName )
{
if( !szConfigFileName ) return false;
char tempbuf[512] = {0};
WideCharToMultiByte( CP_ACP, 0, szConfigFileName, -1, tempbuf, 511, NULL, NULL );
return this->ReadConfig( tempbuf );
}
bool CConfig::ReadConfig( const char *szConfigFileName )
{
if( !szConfigFileName ) return false;
strcpy( this->szCfgFileName, szConfigFileName );
FILE *f = fopen( szConfigFileName, "rt" );
if( !f ) return false;
char line[512];
size_t ll; // line length
char *token = NULL;
while( !feof(f) )
{
memset( line, 0, sizeof(line) );
fgets( line, sizeof(line)-1, f );
if( line[0] == 0 ) /* line empty */ continue;
if( (line[0] == '#') || (line[0] == ';') ) /* pass comments */ continue;
/* remove NL & BR from end of line */
ll = strlen( line );
if( (line[ll-1] == '\r') || (line[ll-1] == '\n') ) line[ll-1] = 0;
if( (line[ll-2] == '\r') || (line[ll-2] == '\n') ) line[ll-2] = 0;
/* find '=' */
token = strchr( line, '=' );
if( token )
{
token++; // token points to next char after '='
while( (*token) && ((*token) == ' ') ) token++; // pass spaces
}
else
continue; /* no '=' symbol in line */
/* is there any string in token */
if( token[0] == 0 ) continue; /* token is an empty string.. */
/* find match */
if( strstr( line, "Lineage2Version" ) == line )
{
sscanf( token, "%d", &(this->L2_version) );
}
if( strstr( line, "Lineage2ClientVersion" ) == line )
{
sscanf( token, "%d", &(this->L2_client_version) );
}
if( strstr( line, "FakeListenLoginIP" ) == line )
{
strcpy( this->FakeListenLoginIP, token );
}
if( strstr( line, "FakeListenLoginPort" ) == line )
{
sscanf( token, "%d", &(this->FakeListenLoginPort) );
}
if( strstr( line, "FakeListenGameIP" ) == line )
{
strcpy( this->FakeListenGameIP, token );
}
if( strstr( line, "FakeListenGamePort" ) == line )
{
sscanf( token, "%d", &(this->FakeListenGamePort) );
}
if( strstr( line, "RealLoginServerIP" ) == line )
{
strcpy( this->RealLoginServerIP, token );
}
if( strstr( line, "RealLoginServerPort" ) == line )
{
sscanf( token, "%d", &(this->RealLoginServerPort) );
}
/*if( strstr( line, "PlayGameServerNo" ) == line )
{
sscanf( token, "%d", &(this->PlayGameServerNo) );
}*/
if( strstr( line, "ForceGameServerIP" ) == line )
{
strcpy( this->ForceGameServerIP, token );
}
if( strstr( line, "ForceGameServerPort" ) == line )
{
sscanf( token, "%d", &(this->ForceGameServerPort) );
}
if( strstr( line, "IngameGameServerPort" ) == line )
{
sscanf( token, "%d", &(this->IngameGameServerPort) );
}
if( strstr( line, "LogGamePackets" ) == line )
{
sscanf( token, "%d", &(this->LogGamePackets) );
}
if( strstr( line, "LogGameFileNamePrefix" ) == line )
{
strcpy( this->LogGameFileNamePrefix, token );
}
if( strstr( line, "WarnUnknownPacketsToStdout" ) == line )
{
sscanf( token, "%d", &(this->WarnUnknownPacketsToStdout) );
}
if( strstr( line, "DumpUnknownToStdout" ) == line )
{
sscanf( token, "%d", &(this->DumpUnknownToStdout) );
}
if( strstr( line, "WarnMessageLevel" ) == line )
{
sscanf( token, "%d", &(this->WarnMessageLevel) );
if( WarnMessageLevel < 0 ) WarnMessageLevel = 0;
}
if( strstr( line, "EnableModifyGameTraffic" ) == line )
{
sscanf( token, "%d", &(this->EnableModifyGameTraffic) );
}
if( strstr( line, "OverrideGameProtocolVersion" ) == line )
{
sscanf( token, "%d", &(this->OverrideGameProtocolVersion) );
}
if( strstr( line, "ReplyL2JGameGuardQuery" ) == line )
{
sscanf( token, "%d", &(this->ReplyL2JGameGuardQuery) );
}
if( strstr( line, "GraciaEpilogueProtocol_148_hacks" ) == line )
{
sscanf( token, "%d", &(this->GraciaEpilogueProtocol_148_hacks) );
}
if( strstr( line, "ThreadProirityRaiseEnable" ) == line )
{
sscanf( token, "%d", &(this->ThreadProirityRaiseEnable) );
}
if( strstr( line, "L2Walker_DropRequestGMList" ) == line )
{
sscanf( token, "%d", &(this->L2Walker_DropRequestGMList) );
}
if( strstr( line, "L2Walker_FixMoveBackwardToLocation" ) == line )
{
sscanf( token, "%d", &(this->L2Walker_FixMoveBackwardToLocation) );
}
if( strstr( line, "L2Walker_FixChangeWaitType2" ) == line )
{
sscanf( token, "%d", &(this->L2Walker_FixChangeWaitType2) );
}
if( strstr( line, "L2Walker_InjectStatusUpdate" ) == line )
{
sscanf( token, "%d", &(this->L2Walker_InjectStatusUpdate) );
}
if( strstr( line, "InvisGMTrackEnable" ) == line )
{
sscanf( token, "%d", &(this->InvisGMTrackEnable) );
}
if( strstr( line, "InvisGMSpeed" ) == line )
{
sscanf( token, "%d", &(this->InvisGMSpeed) );
}
}
fclose( f );
return true;
}
bool CConfig::SaveConfig()
{
if( szCfgFileName[0] == 0 ) return false;
FILE *f = fopen( szCfgFileName, "wt" );
if( !f ) return false;
// declared in L2PcodeObfuscator.h (include L2Packets.h)
//#define L2_VERSION_T1 0
//#define L2_VERSION_T15 1
//#define L2_VERSION_T2 2
//#define L2_VERSION_T22 3
fprintf( f, ""
"# First - configure Lineage2 game protocol version and L2 Client version.\n"
"# Supported versions are:\n"
"# * Chaotic Throne 1 - The Kamael = 0\n"
"# * Chaotic Throne 1.5 - Hellbound = 1\n"
"# * Chaotic Throne 2 - Gracia (Part 1) = 2\n"
"# * Chaotic Throne 2.2 - Gracia Part 2 = 3\n"
"# * Chaotic Throne 2.3 - Gracia Final = 4\n"
"# * Chaotic Throne 2.4 - Gracia Epilogue = 5\n"
"# default is 4 (CT2.3 Gracia Final)\n"
"Lineage2Version = %d\n"
"Lineage2ClientVersion = %d\n"
"\n\n",
L2_version, L2_client_version );
fprintf( f, ""
"# ===============\n"
"# Network setup \n"
"# ===============\n"
"\n"
"# =======================\n"
"# Listen ports setup \n"
"# * Ports on which program will bind listen sockets - local address\n"
"FakeListenLoginIP = %s\n"
"FakeListenLoginPort = %d\n"
"FakeListenGameIP = %s\n"
"FakeListenGamePort = %d\n"
"\n", FakeListenLoginIP, FakeListenLoginPort, FakeListenGameIP, FakeListenGamePort );
fprintf( f, ""
"# ========================\n"
"# Forward connection to \n"
"# * Where to redirect login connection - IP/hostname & port\n"
"RealLoginServerIP = %s\n"
"RealLoginServerPort = %d\n"
"\n", RealLoginServerIP, RealLoginServerPort );
// this was removed
/*fprintf( f, ""
"# ===========================\n"
"# Catch game server traffic \n"
"# * Which Game server's IP and port will be replaced in ServerList packet\n"
"# WARNING: this option is ignored!\n"
"PlayGameServerNo = %d\n"
"\n", PlayGameServerNo );*/
fprintf( f, "# You may force radar to redirect connection to specified game server IP:port.\n" );
fprintf( f, "# To do this, you must set BOTH ForceGameServerIP and ForceGameServerPort.\n" );
fprintf( f, "# if ForceGameServerIP == \"\" or ForceGameServerPort == 0 then feature is diabled.\n" );
fprintf( f, ""
"# ===========================\n"
"# Force choose game server by IP:port \n"
"# * independently of selection in server list window during login\n"
"# * if not set (empty string) - use selected server\n"
"ForceGameServerIP = %s\n"
"\n", ForceGameServerIP );
fprintf( f, ""
"# ===========================\n"
"# Force choose game server by IP:port \n"
"# * independently of selection in server list window during login\n"
"# * if = 0 - use selected server\n"
"ForceGameServerPort = %d\n"
"\n", ForceGameServerPort );
fprintf( f, ""
"# ===========================\n"
"# Catch following game traffic port in INGAME mode \n"
"IngameGameServerPort = %d\n"
"\n", IngameGameServerPort );
fprintf( f, ""
"# =========================================================================\n"
"# Logging Setup \n"
"# =========================================================================\n"
"# =========================================================================\n"
"# Warn messages level printed to stdout \n"
"# 0 - no messages to screen \n"
"# 1 - errors only ( Recommended :) ) \n"
"# 2 - errors, warnings \n"
"# 3 - errors, warnings, AI \n"
"# 4 - errors, warnings, AI, packet names \n"
"# 5 - errors, warnings, AI, packet names, debug messages \n"
"# 6 - errors, warnings, AI, packet names, debug messages, packet dumps \n"
"# Default: 1; it cannot be <0, but can be very big number. [0..0xFFFFFFFF]\n"
"WarnMessageLevel = %d\n"
"\n", WarnMessageLevel );
fprintf( f, ""
"# =========================================================================\n"
"# Warn about unknown packets? 1 - yes, 0 - no; (default: 0, no) \n"
"WarnUnknownPacketsToStdout = %d\n"
"\n", WarnUnknownPacketsToStdout );
fprintf( f, ""
"# ==========================================================================\n"
"# Full dump unknown packets to log? 0-no, 1-yes (Default: 0, not display)\n"
"DumpUnknownToStdout = %d\n"
"\n", DumpUnknownToStdout );
fprintf( f, ""
"# ====================================\n"
"# Enable or disable logging of Game Server packets 0-disable, 1-enable (Default: 0, disable)\n"
"LogGamePackets = %d\n"
"\n", LogGamePackets );
fprintf( f, ""
"# ====================================\n"
"# File name prefix for log file with game server packets log\n"
"# (file name will look like prefix_XXXXXXXX.txt, where XXX-current date/time unix timestamp)\n"
"# Default: prefix_\n"
"LogGameFileNamePrefix = %s\n"
"\n", LogGameFileNamePrefix );
fprintf( f, ""
"# ==========\n"
"# Hacks!!!! \n"
"# ==========\n"
" \n"
"# ========================================\n"
"# Enable or disable game packets modifying\n"
"# - If disabled (0), only passive sniffing if possible, NO ANY HACKS will work\n"
"# - If enabled (1), packet-level hacks WILL work. This setting is REQUIRED to be set to ENABLED\n"
"# if you want any hacks to work\n"
"# - 0-disable, 1-enable; (Default: 0, disable, passive SNIFFING ONLY)\n"
"EnableModifyGameTraffic = %d\n"
"\n", EnableModifyGameTraffic );
fprintf( f, ""
"# !!!!! Any hacks below will not work, if EnableModifyGameTraffic is set to 0 !!!!!\n"
"\n"
"# =====================================================================\n"
"# * Override game protocol version: change game protocol version number\n"
"# * in C->S ProtocolVersion packet to given number.\n"
"# * Value: 0 - disable this; any other number greater than 0: override to this number\n"
"# * Default: 0\n"
"OverrideGameProtocolVersion = %d\n"
"# Help on protocol versions (Official server):\n"
"# - T1 Kamael - 828\n"
"# - T1.5 Hellbound - 831 ?\n"
"# - T2 Gracia live - 851\n"
"# - T2.2 Gracia Part 2 - 12-17\n"
"# - T2.3 Gracia Final - 83-87\n"
"# - T2.4 Gracia Epilogue - 146\n"
"\n",
OverrideGameProtocolVersion );
fprintf( f, ""
"# If set to 1, L2Detect will send reply to standard L2J GameGuard query\n"
"# by itself, so it will be possible to play with GameGuard disabled\n"
"# on private servers where GameGuard is required.\n"
"# NOTE: L2Detect will NOT reply to unknown queries! You cannot be sure in it on official servers.\n"
"# (Default: disabled)\n"
"ReplyL2JGameGuardQuery = %d\n"
"\n",
ReplyL2JGameGuardQuery );
fprintf( f, ""
"# If set to 1, you know that server is using G.Epilogue protocol 148 and client\n"
"# is using G.Epilogue protocol 146; this setting will enable protocol conversion\n"
"# (converting some packets like ItemList, etc) between server and client, allowing\n"
"# clent with protocol 146 to play on server with protocol 148.\n"
"GraciaEpilogueProtocol_148_hacks = %d\n"
"\n",
GraciaEpilogueProtocol_148_hacks );
fprintf( f, ""
"# Fixes L2Walker wrong or old packets\n"
"L2Walker_DropRequestGMList = %d\n"
"L2Walker_FixMoveBackwardToLocation = %d\n"
"L2Walker_FixChangeWaitType2 = %d\n"
"L2Walker_InjectStatusUpdate = %d\n"
"\n",
L2Walker_DropRequestGMList,
L2Walker_FixMoveBackwardToLocation,
L2Walker_FixChangeWaitType2,
L2Walker_InjectStatusUpdate );
fprintf( f, ""
"# Enable/disable game listener thread priority above normal. Try changing this, if you have comp. lags...\n"
"# default: 0, disabled\n"
"ThreadProirityRaiseEnable = %d\n"
"\n",
ThreadProirityRaiseEnable );
fprintf( f, ""
"# Enable/disable invisible GM tracking\n"
"# default: 1, enabled\n"
"InvisGMTrackEnable = %d\n"
"\n",
InvisGMTrackEnable );
fprintf( f, ""
"# Invisible GM display speed\n"
"# default: 400, as //gmspeed 4\n"
"InvisGMSpeed = %d\n"
"\n",
InvisGMSpeed );
fclose( f );
return true;
}
void CConfig::SetDefault()
{
// declared in L2PcodeObfuscator.h (include L2Packets.h)
//#define L2_VERSION_T1 0
//#define L2_VERSION_T15 1
//#define L2_VERSION_T2 2
//#define L2_VERSION_T22 3
L2_version = 4;
L2_client_version = 4;
// Listen port setup
strcpy( FakeListenLoginIP, "127.0.0.1" );
FakeListenLoginPort = 9998;
strcpy( FakeListenGameIP, "127.0.0.1" );
FakeListenGamePort = 9999;
// Forward connection to
strcpy( RealLoginServerIP, "0.0.0.0" );
RealLoginServerPort = 2106;
// Catch game server traffic
//PlayGameServerNo = 0;
ForceGameServerIP[0] = 0;
ForceGameServerPort = 0;
IngameGameServerPort = 7777;
// Logging setup
LogGamePackets = 0;
LogGameFileNamePrefix[0] = 0;
WarnUnknownPacketsToStdout = 0;
DumpUnknownToStdout = 0;
WarnMessageLevel = 4;
// hacks
EnableModifyGameTraffic = 0; // enable or disable game protocol-level hacks
OverrideGameProtocolVersion = 0;
ReplyL2JGameGuardQuery = 0;
GraciaEpilogueProtocol_148_hacks = 0;
// L2Walker fixes
L2Walker_DropRequestGMList = 0;
L2Walker_FixMoveBackwardToLocation = 1;
L2Walker_FixChangeWaitType2 = 1;
L2Walker_InjectStatusUpdate = 0;
// tweaks
ThreadProirityRaiseEnable = 1;
// Invis GM
InvisGMTrackEnable = 0;
InvisGMSpeed = 400; // //gmspeed 4
}

69
l2detect/ConfigIni.h Normal file
View File

@@ -0,0 +1,69 @@
#ifndef CONFIGINI_H_
#define CONFIGINI_H_
class CConfig
{
public:
CConfig();
virtual ~CConfig();
public:
bool ReadConfig( const char *szConfigFileName );
bool ReadConfig( const wchar_t *szConfigFilename );
bool SaveConfig();
void SetDefault();
protected:
void _initNull();
public:
char szCfgFileName[256];
bool isInGameMode;
int L2_version;
int L2_client_version;
// Listen port setup
char FakeListenLoginIP[32];
int FakeListenLoginPort;
char FakeListenGameIP[32];
int FakeListenGamePort;
// Forward connection to
char RealLoginServerIP[128];
int RealLoginServerPort;
// Catch game server traffic
//int PlayGameServerNo; // removed!
char ForceGameServerIP[32];
int ForceGameServerPort;
int IngameGameServerPort;
// Logging setup
int LogGamePackets;
char LogGameFileNamePrefix[128];
int WarnUnknownPacketsToStdout;
int DumpUnknownToStdout;
int WarnMessageLevel;
// hacks
int EnableModifyGameTraffic; // enable or disable game protocol-level hacks
int OverrideGameProtocolVersion;
int ReplyL2JGameGuardQuery;
int GraciaEpilogueProtocol_148_hacks;
// L2Walker fixes
int L2Walker_DropRequestGMList;
int L2Walker_FixMoveBackwardToLocation;
int L2Walker_FixChangeWaitType2;
int L2Walker_InjectStatusUpdate;
// tweaks
int ThreadProirityRaiseEnable;
// invis GM detection
int InvisGMTrackEnable;
int InvisGMSpeed;
};
#endif /* CONFIGINI_H_ */

407
l2detect/DebugDlg.cpp Normal file
View File

@@ -0,0 +1,407 @@
#include "stdafx.h"
#include "Resource.h"
#include "ConfigIni.h"
#include "DebugDlg.h"
#include "ConfigDlg.h"
#include "Logger.h"
#include "LoginListener.h"
#include "GameListener.h"
#include "GameClient.h"
#include "net_hook.h"
// EXTERNALS
// global app configuration
extern class CConfig g_cfg; // in main.cpp
extern class GameClient *g_game_client; // in main.cpp
// global listeners
extern class LoginListener *g_plogin;
extern class GameListener *g_pgame;
#define TIMER_UPDATEINFO 1
BOOL DebugDlg_OnInitDialog( HWND hDlg );
void DebugDlg_OnBnClickedRunconfig( HWND hDlg );
void DebugDlg_OnBnClickedStartLL( HWND hDlg );
void DebugDlg_OnBnClickedStartGL( HWND hDlg );
void DebugDlg_OnBnClickedStopLL( HWND hDlg );
void DebugDlg_OnBnClickedStopGL( HWND hDlg );
void DebugDlg_OnBnClickedFlushLog( HWND hDlg );
void DebugDlg_OnBnClickedEnableConsole( HWND hDlg );
void DebugDlg_OnBnClickedDisableConsole( HWND hDlg );
void DebugDlg_OnBnClickedLoadWalker( HWND hDlg );
void DebugDlg_OnBnClickedUnloadWalker( HWND hDlg );
void DebugDlg_OnTimer( HWND hDlg, UINT_PTR nIDEvent );
void DebugDlg_updateInfo( HWND hDlg );
void DebugDlg_OnBnClickedValidateInterception( HWND hDlg );
void DebugDlg_OnBnClickedInterceptConnect( HWND hDlg );
void DebugDlg_OnBnClickedCheckVP( HWND hDlg );
void DebugDlg_OnBnClickedDumpAllRelations( HWND hDlg );
void DebugDlg_OnBnClickedPrintAddrTid( HWND hDlg );
INT_PTR CALLBACK DebugDlgProc( HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam )
{
UNREFERENCED_PARAMETER(lParam);
switch( uMsg )
{
case WM_INITDIALOG: DebugDlg_OnInitDialog( hDlg ); break;
case WM_TIMER: DebugDlg_OnTimer( hDlg, (UINT_PTR)wParam ); break;
case WM_COMMAND:
{
switch( LOWORD( wParam ) )
{
//case IDC_RUNCONFIG: DebugDlg_OnBnClickedRunconfig( hDlg ); break;
case IDC_STARTLL: DebugDlg_OnBnClickedStartLL( hDlg ); break;
case IDC_STOPLL: DebugDlg_OnBnClickedStopLL( hDlg ); break;
case IDC_STARTGL: DebugDlg_OnBnClickedStartGL( hDlg ); break;
case IDC_STOPGL: DebugDlg_OnBnClickedStopGL( hDlg ); break;
case IDC_FLUSH_LOG: DebugDlg_OnBnClickedFlushLog( hDlg ); break;
case IDC_B_CONENABLE: DebugDlg_OnBnClickedEnableConsole( hDlg ); break;
case IDC_B_CONDISABLE: DebugDlg_OnBnClickedDisableConsole( hDlg ); break;
case IDC_B_VALIDATEINTERCEPT: DebugDlg_OnBnClickedValidateInterception( hDlg ); break;
case IDC_B_INTERCEPTCONNECT: DebugDlg_OnBnClickedInterceptConnect( hDlg ); break;
case IDC_B_CHECK_VIRTUALPROTECTEX: DebugDlg_OnBnClickedCheckVP( hDlg ); break;
case IDC_B_LOADWALKER: DebugDlg_OnBnClickedLoadWalker( hDlg ); break;
case IDC_B_UNLOADWALKER: DebugDlg_OnBnClickedUnloadWalker( hDlg ); break;
case IDC_B_DUMP_ALL_RELATIONS: DebugDlg_OnBnClickedDumpAllRelations( hDlg ); break;
case IDC_B_PRINTADDRTID: DebugDlg_OnBnClickedPrintAddrTid( hDlg ); break;
case IDOK: EndDialog( hDlg, IDOK ); break;
case IDCANCEL: EndDialog( hDlg, IDCANCEL ); break;
}
} break;
default: return FALSE; break;
}
return TRUE;
}
void DebugDialogStart( HWND hWndParent, HINSTANCE hInst )
{
DialogBoxParam( hInst, MAKEINTRESOURCE(IDD_DEBUG), hWndParent, DebugDlgProc, NULL );
}
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> DebugDlg
BOOL DebugDlg_OnInitDialog( HWND hDlg )
{
DebugDlg_updateInfo( hDlg );
SetTimer( hDlg, TIMER_UPDATEINFO, 1000, NULL );
return TRUE;
}
//void DebugDlg_OnBnClickedRunconfig( HWND hDlg )
//{
// ConfigDialogStart( hDlg, g_radardll_hinst );
//}
void DebugDlg_OnBnClickedStartLL( HWND hDlg )
{
if( g_plogin )
{
if( g_plogin->isRunning() )
{
MessageBox( hDlg, TEXT("Login listener already running!"), TEXT("Ops!"), MB_ICONINFORMATION );
return;
}
if( !g_plogin->start() )
MessageBox( hDlg, TEXT("Login listener start failed!"), TEXT("Ops!"), MB_ICONINFORMATION );
}
}
void DebugDlg_OnBnClickedStartGL( HWND hDlg )
{
if( g_pgame )
{
if( g_pgame->isRunning() )
{
MessageBox( hDlg, TEXT("Game listener already running!"), TEXT("Ops!"), MB_ICONINFORMATION );
return;
}
if( !g_pgame->start() )
MessageBox( hDlg, TEXT("Game listener start failed!"), TEXT("Ops!"), MB_ICONINFORMATION );
}
}
void DebugDlg_OnBnClickedStopLL( HWND hDlg )
{
if( g_plogin )
{
if( !g_plogin->isRunning() )
{
MessageBox( hDlg, TEXT("Login listener already stopped!"), TEXT("Ops!"), MB_ICONINFORMATION );
return;
}
g_plogin->signalStop();
// wait 10 secs to stop
if( !g_plogin->waitStopped( 10000 ) )
{
g_plogin->terminateThread();
MessageBox( hDlg, TEXT("Login listener stop wait failed, terminated :("), TEXT("Ops!"), MB_ICONINFORMATION );
}
}
}
void DebugDlg_OnBnClickedStopGL( HWND hDlg )
{
if( g_pgame )
{
if( !g_pgame->isRunning() )
{
MessageBox( hDlg, TEXT("Game listener already stopped!"), TEXT("Ops!"), MB_ICONINFORMATION );
return;
}
g_pgame->signalStop();
// wait 10 secs to stop
if( !g_pgame->waitStopped( 10000 ) )
{
g_pgame->terminateThread();
MessageBox( hDlg, TEXT("Game listener stop wait failed, terminated :("), TEXT("Ops!"), MB_ICONINFORMATION );
}
}
}
void DebugDlg_OnBnClickedEnableConsole( HWND hDlg )
{
UNREFERENCED_PARAMETER(hDlg);
ErrorLogger_EnableLoggingToConsole( true );
}
void DebugDlg_OnBnClickedDisableConsole( HWND hDlg )
{
UNREFERENCED_PARAMETER(hDlg);
ErrorLogger_EnableLoggingToConsole( false );
}
void DebugDlg_OnTimer( HWND hDlg, UINT_PTR nIDEvent )
{
if( nIDEvent == TIMER_UPDATEINFO )
{
DebugDlg_updateInfo( hDlg );
}
}
void DebugDlg_updateInfo( HWND hDlg )
{
int run;
HWND hWndB;
// update LoginListener info
// LoginListener may not be started in ingame mode at all
if( g_plogin )
{
run = g_plogin->isRunning();
if( run )
{
SetDlgItemText( hDlg, IDC_ELLSTATUS, TEXT("ON") );
// start button
hWndB = GetDlgItem( hDlg, IDC_STARTLL );
if( hWndB ) EnableWindow( hWndB, FALSE );
// stop button
hWndB = GetDlgItem( hDlg, IDC_STOPLL );
if( hWndB ) EnableWindow( hWndB, TRUE );
}
else
{
SetDlgItemText( hDlg, IDC_ELLSTATUS, TEXT("Off") );
// start button
hWndB = GetDlgItem( hDlg, IDC_STARTLL );
if( hWndB ) EnableWindow( hWndB, TRUE );
// stop button
hWndB = GetDlgItem( hDlg, IDC_STOPLL );
if( hWndB ) EnableWindow( hWndB, FALSE );
}
}
else // all start & stop LL buttons disabled
{
// start button
hWndB = GetDlgItem( hDlg, IDC_STARTLL );
if( hWndB ) EnableWindow( hWndB, FALSE );
// stop button
hWndB = GetDlgItem( hDlg, IDC_STOPLL );
if( hWndB ) EnableWindow( hWndB, FALSE );
}
// update GameListener info
if( g_pgame )
{
run = g_pgame->isRunning();
if( run )
{
SetDlgItemText( hDlg, IDC_EGLSTATUS, TEXT("ON") );
// start button
hWndB = GetDlgItem( hDlg, IDC_STARTGL );
if( hWndB ) EnableWindow( hWndB, FALSE );
// stop button
hWndB = GetDlgItem( hDlg, IDC_STOPGL );
if( hWndB ) EnableWindow( hWndB, TRUE );
}
else
{
SetDlgItemText( hDlg, IDC_EGLSTATUS, TEXT("Off") );
// start button
hWndB = GetDlgItem( hDlg, IDC_STARTGL );
if( hWndB ) EnableWindow( hWndB, TRUE );
// stop button
hWndB = GetDlgItem( hDlg, IDC_STOPGL );
if( hWndB ) EnableWindow( hWndB, FALSE );
}
}
else // all start & stop GL buttons disabled
{
// start button
hWndB = GetDlgItem( hDlg, IDC_STARTGL );
if( hWndB ) EnableWindow( hWndB, FALSE );
// stop button
hWndB = GetDlgItem( hDlg, IDC_STOPGL );
if( hWndB ) EnableWindow( hWndB, FALSE );
}
if( g_game_client->getState() == GCST_IN_GAME )
{
TCHAR tstr[256];
// hp
wsprintf( tstr, _T("%d / %d"), g_game_client->ai.usr.hp, g_game_client->ai.usr.hp_max );
SetDlgItemText( hDlg, IDC_HP, tstr );
// mp
wsprintf( tstr, _T("%d / %d"), g_game_client->ai.usr.mp, g_game_client->ai.usr.mp_max );
SetDlgItemText( hDlg, IDC_MP, tstr );
// cp
wsprintf( tstr, _T("%d / %d"), g_game_client->ai.usr.cp, g_game_client->ai.usr.cp_max );
SetDlgItemText( hDlg, IDC_CP, tstr );
// char name
wsprintf( tstr, _T("%s (tit %s), Lv %d (%s/base %s)"),
g_game_client->ai.usr.charName, g_game_client->ai.usr.charTitle,
g_game_client->ai.usr.level,
g_game_client->ai.usr.getClassStr(), g_game_client->ai.usr.getBaseClassStr() );
SetDlgItemText( hDlg, IDC_CHARNAME, tstr );
}
else SetDlgItemText( hDlg, IDC_CHARNAME, TEXT("<Not in game!>") );
}
void DebugDlg_OnBnClickedFlushLog( HWND hDlg )
{
UNREFERENCED_PARAMETER( hDlg );
ErrorLogger_FlushLogFile();
}
void DebugDlg_OnBnClickedValidateInterception( HWND hDlg )
{
hDlg = NULL;
Hook_ValidateInterception_my();
}
void DebugDlg_OnBnClickedInterceptConnect( HWND hDlg )
{
hDlg = NULL;
Hook_InterceptConnect_my();
}
void DebugDlg_OnBnClickedCheckVP( HWND hDlg )
{
hDlg = NULL;
Hook_CheckVirtualProtect();
}
void DebugDlg_OnBnClickedLoadWalker( HWND hDlg )
{
HINSTANCE hDllL2Walker = GetModuleHandle( TEXT("L2Walker.dll") );
TCHAR text[256];
if( hDllL2Walker != NULL )
{
log_error( LOG_OK, "L2Walker.dll already loaded at 0x%p\n", (void *)hDllL2Walker );
wsprintf( text, TEXT("L2Walker.dll already loaded at 0x%p"), (void *)hDllL2Walker );
MessageBox( hDlg, text, TEXT("Cannot!"), MB_ICONWARNING );
return;
}
hDllL2Walker = LoadLibrary( TEXT("L2Walker.dll") );
if( !hDllL2Walker )
{
ErrorLogger_LogLastError( "LoadLibrary l2walker", GetLastError() );
MessageBox( hDlg, TEXT("Cannot load L2Walker.dll!\nError is in log."), TEXT("Cannot!"), MB_ICONSTOP );
return;
}
log_error( LOG_OK, "L2Walker.dll loaded at 0x%p\n", (void *)hDllL2Walker );
ErrorLogger_FlushLogFile();
// RVA 000196E0
}
void DebugDlg_OnBnClickedUnloadWalker( HWND hDlg )
{
HINSTANCE hDllL2Walker = GetModuleHandle( TEXT("L2Walker.dll") );
if( hDllL2Walker == NULL )
{
MessageBox( hDlg, TEXT("L2Walker.dll not loaded!"), TEXT("Cannot!"), MB_ICONWARNING );
return;
}
log_error( LOG_DEBUG, "FreeLibrary() for L2Walker.dll...\n" );
ErrorLogger_FlushLogFile();
FreeLibrary( hDllL2Walker );
log_error( LOG_OK, "L2Walker.dll unloaded.\n" );
ErrorLogger_FlushLogFile();
}
void str_relation( wchar_t *out, unsigned int relation )
{
out[0] = 0;
const unsigned int RELATION_PARTY1 = 0x00001; // party member
const unsigned int RELATION_PARTY2 = 0x00002; // party member
const unsigned int RELATION_PARTY3 = 0x00004; // party member
const unsigned int RELATION_PARTY4 = 0x00008; // party member (for information, see L2PcInstance.getRelation())
const unsigned int RELATION_PARTYLEADER = 0x00010; // true if is party leader
const unsigned int RELATION_HAS_PARTY = 0x00020; // true if is in party
const unsigned int RELATION_CLAN_MEMBER = 0x00040; // true if is in clan
const unsigned int RELATION_LEADER = 0x00080; // true if is clan leader
const unsigned int RELATION_CLAN_MATE = 0x00100; // true if is in same clan
const unsigned int RELATION_INSIEGE = 0x00200; // true if in siege
const unsigned int RELATION_ATTACKER = 0x00400; // true when attacker
const unsigned int RELATION_ALLY = 0x00800; // blue siege icon, cannot have if red
const unsigned int RELATION_ENEMY = 0x01000; // true when red icon, doesn't matter with blue
const unsigned int RELATION_1SIDED_WAR = 0x08000; // single fist
const unsigned int RELATION_MUTUAL_WAR = 0x04000; // double fist
const unsigned int RELATION_ALLY_MEMBER = 0x10000; // clan is in alliance
const unsigned int RELATION_TERRITORY_WAR= 0x80000; // show Territory War icon
if( relation & RELATION_PARTY1 ) wcscat( out, L"RELATION_PARTY1 " );
if( relation & RELATION_PARTY2 ) wcscat( out, L"RELATION_PARTY2 " );
if( relation & RELATION_PARTY3 ) wcscat( out, L"RELATION_PARTY3 " );
if( relation & RELATION_PARTY4 ) wcscat( out, L"RELATION_PARTY4 " );
if( relation & RELATION_PARTYLEADER ) wcscat( out, L"RELATION_PARTYLEADER " );
if( relation & RELATION_HAS_PARTY ) wcscat( out, L"RELATION_HAS_PARTY " );
if( relation & RELATION_CLAN_MEMBER ) wcscat( out, L"RELATION_CLAN_MEMBER " );
if( relation & RELATION_LEADER ) wcscat( out, L"RELATION_LEADER " );
if( relation & RELATION_CLAN_MATE ) wcscat( out, L"RELATION_CLAN_MATE " );
if( relation & RELATION_INSIEGE ) wcscat( out, L"RELATION_INSIEGE " );
if( relation & RELATION_ATTACKER ) wcscat( out, L"RELATION_ATTACKER " );
if( relation & RELATION_ALLY ) wcscat( out, L"RELATION_ALLY " );
if( relation & RELATION_ENEMY ) wcscat( out, L"RELATION_ENEMY " );
if( relation & RELATION_1SIDED_WAR ) wcscat( out, L"RELATION_1SIDED_WAR " );
if( relation & RELATION_MUTUAL_WAR ) wcscat( out, L"RELATION_MUTUAL_WAR " );
if( relation & RELATION_ALLY_MEMBER ) wcscat( out, L"RELATION_ALLY_MEMBER " );
if( relation & RELATION_TERRITORY_WAR ) wcscat( out, L"RELATION_TERRITORY_WAR " );
}
void DebugDlg_OnBnClickedDumpAllRelations( HWND hDlg )
{
UNREFERENCED_PARAMETER( hDlg );
CharArray_Lock();
int i;
FILE *f = fopen( "Relations.txt", "at" );
fwprintf( f, L"User: [%s] 0x%08X\n", g_game_client->ai.usr.charName, g_game_client->ai.usr.relation );
for( i=0; i<CHARARRAY_MAX_CHARS; i++ )
{
if( !chars_array[i] ) continue;
if( chars_array[i]->isUnused() ) continue;
wchar_t rel[512] = {0};
str_relation( rel, chars_array[i]->relation );
fwprintf( f, L"Char[%d]: [%s] 0x%08X [%s]\n", i, chars_array[i]->charName, chars_array[i]->relation, rel );
}
fprintf( f, "====== END =====\n" );
fclose( f );
CharArray_Unlock();
}
void DebugDlg_OnBnClickedPrintAddrTid( HWND hDlg )
{
UNREFERENCED_PARAMETER( hDlg );
void *addr = (void *)&(g_game_client->ai.dwThreadID);
log_error( LOG_OK, "&(g_game_client->ai.dwThreadID) = 0x%p\n", addr );
}

6
l2detect/DebugDlg.h Normal file
View File

@@ -0,0 +1,6 @@
#ifndef H_DEBUG_DLG
#define H_DEBUG_DLG
void DebugDialogStart( HWND hWndParent, HINSTANCE hInst );
#endif

77
l2detect/DistPri.cpp Normal file
View File

@@ -0,0 +1,77 @@
#include "stdafx.h"
#include "DistPri.h"
DistancePriorities::DistancePriorities()
{
removeAll();
}
DistancePriorities::~DistancePriorities()
{
removeAll();
}
int DistancePriorities::getPriorityForDistance( double dist ) const
{
if( dist > 10000.0 ) return 0; // too far
int idist = (int)dist, i=0, last_pri_mod = -1;
for( i=0; i<MAXN; i++ )
{
if( (m_min[i] >= 0) && (m_max[i] >= 0) )
{
last_pri_mod = m_pri_mod[i]; // remember last priority modifier
if( (m_min[i] <= idist) && (idist < m_max[i]) )
return m_pri_mod[i];
}
}
// if we still here, no range found for dist
// return latest priority from list
return last_pri_mod;
}
void DistancePriorities::removeAll()
{
int i;
for( i=0; i<MAXN; i++ )
{
m_min[i] = m_max[i] = -1;
m_pri_mod[i] = 0;
}
}
int DistancePriorities::addRangePri( int min, int max, int pri_mod )
{
if( min<0 || max<=min ) return -1; // invalid parameters
int i=0, idx = -1;
for( i=0; i<MAXN; i++ )
{
if( m_min[i] == -1 )
{
idx = i;
break;
}
}
if( idx == -1 ) return -1;
m_min[idx] = min;
m_max[idx] = max;
m_pri_mod[idx] = pri_mod;
return idx;
}
void DistancePriorities::initDefaultPriorities()
{
removeAll();
addRangePri( 0, 400, 50 ); // [0 .. 400)
addRangePri( 400, 600, 30 ); // [400 .. 600)
addRangePri( 600, 1000, 10 ); // [600 .. 1000)
}
void DistancePriorities::getRangeInfo( int range_idx, int *min, int *max, int *pri_mod )
{
if( (range_idx>=0) && (range_idx<MAXN) )
{
if( min ) (*min) = m_min[range_idx];
if( max ) (*max) = m_max[range_idx];
if( pri_mod ) (*pri_mod) = m_pri_mod[range_idx];
}
}

22
l2detect/DistPri.h Normal file
View File

@@ -0,0 +1,22 @@
#pragma once
class DistancePriorities
{
public:
static const int MAXN = 10; // maximum of 10 ranges
public:
DistancePriorities();
~DistancePriorities();
public:
void initDefaultPriorities();
void removeAll();
int getPriorityForDistance( double dist ) const;
int addRangePri( int min, int max, int pri_mod );
void getRangeInfo( int range_idx, int *min, int *max, int *pri_mod );
protected:
int m_min[MAXN];
int m_max[MAXN];
int m_pri_mod[MAXN];
};

49
l2detect/DlgPressKey.cpp Normal file
View File

@@ -0,0 +1,49 @@
#include "stdafx.h"
#include "Resource.h"
extern HINSTANCE g_radardll_hinst;
int g_dlgpk_vkey = 0;
HWND g_dlgpk_hdlg = NULL;
WNDPROC g_dlgpk_oldproc = NULL;
LRESULT CALLBACK DlgPressKey_StaticDlgProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
{
if( uMsg == WM_KEYUP )
{
g_dlgpk_vkey = (int)wParam;
PostMessage( g_dlgpk_hdlg, WM_CLOSE, 0, 0 );
return 0;
}
return CallWindowProc( g_dlgpk_oldproc, hWnd, uMsg, wParam, lParam );
}
INT_PTR CALLBACK DlgPressKey_DlgProc( HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam )
{
HWND hwndSt = NULL; wParam; lParam;
switch( uMsg )
{
case WM_INITDIALOG:
g_dlgpk_vkey = 0;
g_dlgpk_hdlg = hDlg;
hwndSt = GetDlgItem( hDlg, IDC_APPLY );
g_dlgpk_oldproc = (WNDPROC)(void *)(LONG_PTR)GetWindowLongPtr( hwndSt, GWLP_WNDPROC );
SetWindowLongPtr( hwndSt, GWLP_WNDPROC, (LONG_PTR)(void *)DlgPressKey_StaticDlgProc );
break;
case WM_CLOSE:
if( g_dlgpk_vkey == 0 )EndDialog( hDlg, IDCANCEL );
else EndDialog( hDlg, IDOK );
break;
default: return FALSE; break;
}
return TRUE;
}
int DlgPressKey_InputPressKey( HWND hWndParent )
{
g_dlgpk_vkey = 0;
INT_PTR ret = DialogBoxParam( g_radardll_hinst, MAKEINTRESOURCE(IDD_PRESSKEY),
hWndParent, DlgPressKey_DlgProc, 0 );
if( ret == IDCANCEL ) return 0;
return g_dlgpk_vkey;
}

3
l2detect/DlgPressKey.h Normal file
View File

@@ -0,0 +1,3 @@
#pragma once
int DlgPressKey_InputPressKey( HWND hWndParent );

163
l2detect/Dlg_FindInDB.cpp Normal file
View File

@@ -0,0 +1,163 @@
#include "stdafx.h"
#include "Dlg_FindInDB.h"
#include "Resource.h"
extern HINSTANCE g_radardll_hinst;
Dlg_FindInDB::Dlg_FindInDB( MODE mode )
{
m_mode = mode;
itemID = 0;
itemName[0] = 0;
itemNameW[0] = 0;
}
Dlg_FindInDB::~Dlg_FindInDB()
{
itemID = 0;
itemName[0] = 0;
itemNameW[0] = 0;
}
INT_PTR CALLBACK Dlg_FindInDB_Proc( HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam );
bool Dlg_FindInDB::runDialog( HWND hWndParent )
{
INT_PTR ret = DialogBoxParam( g_radardll_hinst,
MAKEINTRESOURCE(IDD_SR_FINDINDB), hWndParent, Dlg_FindInDB_Proc, (LPARAM)this );
if( ret == IDOK ) return true;
return false;
}
void Dlg_FindInDB_OnInitDialog( HWND hDlg, LPARAM lParam );
void Dlg_FindInDB_OnOK( HWND hDlg );
void Dlg_FindInDB_OnFind( HWND hDlg );
INT_PTR CALLBACK Dlg_FindInDB_Proc( HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam )
{
switch( uMsg )
{
case WM_INITDIALOG: Dlg_FindInDB_OnInitDialog( hDlg, lParam ); break;
case WM_COMMAND:
{
switch( LOWORD( wParam ) )
{
case IDOK: Dlg_FindInDB_OnOK( hDlg ); break;
case IDCANCEL: EndDialog( hDlg, IDCANCEL ); break;
case IDC_FIND: Dlg_FindInDB_OnFind( hDlg ); break;
}
} break;
default: return FALSE; break;
}
return TRUE;
}
void Dlg_FindInDB_OnInitDialog( HWND hDlg, LPARAM lParam )
{
SetWindowLongPtr( hDlg, GWLP_USERDATA, (LONG_PTR)lParam );
class Dlg_FindInDB *cls = (class Dlg_FindInDB *)lParam;
switch( cls->getMode() )
{
case Dlg_FindInDB::MODE_ITEM:
{
SetWindowText( hDlg, TEXT("Find item in DB") );
} break;
case Dlg_FindInDB::MODE_NPC:
{
SetWindowText( hDlg, TEXT("Find NPC in DB") );
} break;
case Dlg_FindInDB::NODE_SKILL:
{
SetWindowText( hDlg, TEXT("Find skill in DB") );
} break;
}
CheckDlgButton( hDlg, IDC_R_CONTAINS, BST_CHECKED );
HWND hwndLV = GetDlgItem( hDlg, IDC_LISTITEMS );
DWORD dwLvExStyle = LVS_EX_DOUBLEBUFFER | LVS_EX_FULLROWSELECT | LVS_EX_GRIDLINES;
SendMessage( hwndLV, LVM_SETEXTENDEDLISTVIEWSTYLE, (WPARAM)dwLvExStyle, (LPARAM)dwLvExStyle );
TCHAR text[256] = {0};
LVCOLUMN lvc;
lvc.mask = LVCF_FMT | LVCF_TEXT | LVCF_WIDTH | LVCF_SUBITEM;
lvc.fmt = LVCFMT_LEFT;
lvc.cx = 60;
lvc.iSubItem = 0;
lvc.pszText = text;
lstrcpy( text, TEXT("id") );
ListView_InsertColumn( hwndLV, 0, &lvc );
lvc.cx = 200;
lvc.iSubItem = 1;
lstrcpy( text, TEXT("name") );
ListView_InsertColumn( hwndLV, 1, &lvc );
}
void Dlg_FindInDB_OnOK( HWND hDlg )
{
HWND hwndLV = GetDlgItem( hDlg, IDC_LISTITEMS );
int iSel = ListView_GetNextItem( hwndLV, -1, LVNI_SELECTED );
if( iSel == -1 ) return;
class Dlg_FindInDB *cls = (class Dlg_FindInDB *)GetWindowLongPtr( hDlg, GWLP_USERDATA );
if( !cls ) return;
TCHAR text[256];
LVITEM lvi;
lvi.iItem = iSel;
lvi.iSubItem = 0;
lvi.mask = LVIF_TEXT;
lvi.pszText = text;
lvi.cchTextMax = 255;
ListView_GetItem( hwndLV, &lvi );
_stscanf( lvi.pszText, _T("%d"), &(cls->itemID) );
lvi.iSubItem = 1;
lvi.mask = LVIF_TEXT;
lvi.pszText = text;
lvi.cchTextMax = 255;
ListView_GetItem( hwndLV, &lvi );
#ifdef UNICODE
wcscpy( cls->itemNameW, lvi.pszText );
sprintf( cls->itemName, "%S", lvi.pszText );
#else
strcpy( cls->itemName, lvi.pszText );
wsprintfW( cls->itemNameW, L"%S", lvi.pszText );
#endif
EndDialog( hDlg, IDOK );
}
void Dlg_FindInDB_OnFind( HWND hDlg )
{
TCHAR text[256] = {0};
char toFind[256] = {0};
char queryString[256] = {0};
GetDlgItemTextA( hDlg, IDC_EDITNAME, toFind, 255 );
toFind[255] = 0;
HWND hwndLV = GetDlgItem( hDlg, IDC_LISTITEMS );
int starts_with = IsDlgButtonChecked( hDlg, IDC_R_STWITH );
int contains = IsDlgButtonChecked( hDlg, IDC_R_CONTAINS );
int ends_with = IsDlgButtonChecked( hDlg, IDC_R_ENWITH );
if( contains ) sprintf( queryString, "%%%s%%", toFind );
if( ends_with ) sprintf( queryString, "%%%s", toFind );
if( starts_with ) sprintf( queryString, "%s%%", toFind );
L2Data_DB_Result res;
res.inMaxRowsToGet = 32;
if( L2Data_DB_Query_Items_ByName( queryString, &res ) )
{
ListView_DeleteAllItems( hwndLV );
int nr = res.rowCount;
int i;
for( i=0; i<nr; i++ )
{
LVITEM lvi;
lvi.mask = LVIF_TEXT;
lvi.iItem = 999;
lvi.iSubItem = 0;
lvi.pszText = text;
wsprintf( text, TEXT("%S"), res.rows[i][0] );
int added_item = ListView_InsertItem( hwndLV, &lvi );
lvi.iItem = added_item;
lvi.iSubItem = 1;
lvi.pszText = text;
wsprintf( text, TEXT("%S"), res.rows[i][1] );
ListView_SetItem( hwndLV, &lvi );
}
L2Data_DB_Free_Result( &res );
}
}

31
l2detect/Dlg_FindInDB.h Normal file
View File

@@ -0,0 +1,31 @@
#ifndef H_DLG_FINDINDB
#define H_DLG_FINDINDB
class Dlg_FindInDB
{
public:
typedef enum eMODE
{
//MODE_NONE = 0,
MODE_ITEM = 1,
MODE_NPC,
NODE_SKILL
} MODE;
public:
Dlg_FindInDB( MODE mode );
~Dlg_FindInDB();
public:
bool runDialog( HWND hWndParent );
Dlg_FindInDB::MODE getMode() const { return this->m_mode; }
public: // results
unsigned int itemID;
char itemName[256];
wchar_t itemNameW[256];
protected:
MODE m_mode;
};
#endif

209
l2detect/GIArray.cpp Normal file
View File

@@ -0,0 +1,209 @@
#include "stdafx.h"
#include "Logger.h"
#include "GIArray.h"
GIArray *GIArray::s_instance = NULL;
int GIArray::s_refCount = 0;
GIArray *GIArray::getInstance()
{
if( !GIArray::s_instance )
{
GIArray::s_instance = new GIArray();
GIArray::s_refCount++;
log_error( LOG_DEBUG, "GIArray: created instance\n" );
}
return GIArray::s_instance;
}
void GIArray::freeInstance()
{
if( GIArray::s_instance )
{
GIArray::s_refCount--;
if( GIArray::s_refCount == 0 )
{
delete GIArray::s_instance;
GIArray::s_instance = NULL;
log_error( LOG_DEBUG, "GIArray: freed instance\n" );
}
}
}
void GIArray::Init()
{
giArray_updateHWND = NULL;
giArray_updateMSG = 0;
giArray_count = 0;
InitializeCriticalSection( &cs_gi_array );
int i;
for( i=0; i<GA_MAX_ITEMS; i++ ) gi_array[i] = new GroundItem();
}
void GIArray::Free()
{
Lock();
int i;
for( i=0; i<GA_MAX_ITEMS; i++ )
{
if( gi_array[i] != NULL )
{
delete gi_array[i];
gi_array[i] = NULL;
}
}
giArray_count = 0;
Unlock();
DeleteCriticalSection( &cs_gi_array );
}
int GIArray::AddGIInfo( GroundItem *pItemInfo )
{
Lock();
// Add new npc info
int idx = FindFreeIndex();
if( idx == -1 )
{
Unlock();
return -1;
}
if( !gi_array[idx] ) gi_array[idx] = new GroundItem();
if( !gi_array[idx] )
{
Unlock();
return -1;
}
memcpy( gi_array[idx], pItemInfo, sizeof(class GroundItem) );
giArray_count++;
Unlock();
//log_error( LOG_OK, "GIArray: Added new[%d]: iid [%u] (%d,%d,%d)\n",
// idx, gi_array[idx]->itemID, gi_array[idx]->x, gi_array[idx]->y, gi_array[idx]->z );
return idx;
}
void GIArray::UpdateGIInfo( int idx, GroundItem *pItemInfo )
{
Lock();
// update info on existing
if( !gi_array[idx] )
{
log_error( LOG_ERROR, "GIArray_UpdateGIInfo(): idx[%d] is free!\n", idx );
// try to allocate!
gi_array[idx] = new GroundItem();
if( !gi_array[idx] )
{
Unlock();
return;
}
}
if( gi_array[idx]->isUnused() ) log_error( LOG_ERROR, "GIArray_UpdateGIInfo(): idx[%d] is unused!\n", idx );
memcpy( gi_array[idx], pItemInfo, sizeof(class GroundItem) );
Unlock();
//log_error( LOG_OK, "GIArray: Updated[%d]: iid [%u] (%d,%d,%d)\n",
// idx, gi_array[idx]->itemID, gi_array[idx]->x, gi_array[idx]->y, gi_array[idx]->z );
}
void GIArray::DelGIByArrayIdx( int idx )
{
if( idx<0 || (idx>=GA_MAX_ITEMS) ) return;
Lock();
if( gi_array[idx] )
{
//log_error( LOG_OK, "GIArray: deleted %u from index %d OK\n", gi_array[idx]->objectID, idx );
gi_array[idx]->setUnused();
giArray_count--;
}
Unlock();
}
void GIArray::DeleteAll()
{
Lock();
int i;
for( i=0; i<GA_MAX_ITEMS; i++ )
{
if( gi_array[i] ) gi_array[i]->setUnused();
}
giArray_count = 0;
Unlock();
}
void GIArray::Lock()
{
EnterCriticalSection( &cs_gi_array );
}
void GIArray::Unlock()
{
LeaveCriticalSection( &cs_gi_array );
}
int GIArray::FindGIByObjectID( unsigned int objectID )
{
int ret = -1;
int i;
Lock();
for( i=0; i<GA_MAX_ITEMS; i++ )
{
if( gi_array[i] == NULL ) continue;
if( gi_array[i]->objectID == objectID )
{
ret = i;
break;
}
}
Unlock();
return ret;
}
int GIArray::FindFreeIndex()
{
int i;
Lock();
for( i=0; i<GA_MAX_ITEMS; i++ )
{
if( gi_array[i] == NULL )
{
gi_array[i] = new GroundItem(); // allocate new
gi_array[i]->setUnused(); // and set as unused
Unlock();
return i;
}
if( gi_array[i]->isUnused() )
{
Unlock();
return i;
}
}
Unlock();
log_error( LOG_ERROR, "GIArray_FindFreeIndex(): canot find free index, limit is %d!\n", GA_MAX_ITEMS );
return -1;
}
void GIArray::DisplayToConsole()
{
int i = 0;
unsigned int nDisplayed = 0;
log_error( LOG_USERAI, "=== Ground items: %d ===\n", giArray_count );
if( giArray_count > 0 )
{
Lock();
for( i=0; i<GA_MAX_ITEMS; i++ )
{
if( gi_array[i]->isUnused() )
log_error( LOG_USERAI, "GI: %2d: <unused>\n", i );
else
{
char itemName[256] = {0};
L2Data_DB_GetItemNamePicByID( gi_array[i]->itemID, itemName, NULL );
log_error( LOG_USERAI, "GI: %2d: itemID %u, objectID %u, count %d [%s]\n", i,
gi_array[i]->itemID, gi_array[i]->objectID,
gi_array[i]->count, itemName );
nDisplayed++;
}
if( nDisplayed >= giArray_count ) break;
}
Unlock();
}
log_error( LOG_USERAI, "=== Ground items End ===\n" );
}

43
l2detect/GIArray.h Normal file
View File

@@ -0,0 +1,43 @@
#ifndef H_GI_ARRAY
#define H_GI_ARRAY
#include "GroundItem.h"
class GIArray
{
public:
static GIArray *getInstance();
static void freeInstance();
protected:
static GIArray *s_instance;
static int s_refCount;
protected:
GIArray() { Init(); }
~GIArray() { Free(); }
public:
static const int GA_MAX_ITEMS = 512;
GroundItem *gi_array[GA_MAX_ITEMS];
public:
void Init();
void Free();
public:
int AddGIInfo( GroundItem *pGIInfo );
void UpdateGIInfo( int idx, GroundItem *pGIInfo );
void DelGIByArrayIdx( int idx );
void DeleteAll();
public:
void Lock();
void Unlock();
public:
int FindGIByObjectID( unsigned int objectID );
int FindFreeIndex();
public:
unsigned int getCount() const { return giArray_count; }
void DisplayToConsole();
protected:
unsigned int giArray_count;
CRITICAL_SECTION cs_gi_array;
HWND giArray_updateHWND;
UINT giArray_updateMSG;
};
#endif

209
l2detect/GameClient.cpp Normal file
View File

@@ -0,0 +1,209 @@
#include "stdafx.h"
#include "ConfigIni.h"
#include "Logger.h"
#include "GameClient.h"
#include "GameListener.h"
extern class GameListener *g_pgame; // main.cpp
extern class CConfig g_cfg; // main.cpp
GameClient::GameClient()
{
memset( key_client_sc, 0, sizeof(key_client_sc) );
memset( key_client_cs, 0, sizeof(key_client_cs) );
memset( key_server_sc, 0, sizeof(key_server_sc) );
memset( key_server_cs, 0, sizeof(key_server_cs) );
state = 0;
gameProtoVer = 0;
xor_enabled = false;
logfile = NULL;
logfileRaw = NULL;
this->resetCounters( false );
this->opcodeObfuscator = 0;
sock_client = INVALID_SOCKET;
sock_server = INVALID_SOCKET;
clsObfuscator = 0;
thisWasJustServerPing = false; // constructor
hWndNotify = NULL;
uMsgNotify = 0;
InitializeCriticalSection( &cs_send );
ai.clear();
}
GameClient::~GameClient()
{
state = 0;
gameProtoVer = 0;
xor_enabled = false;
if( logfile )
{
fflush( logfile );
fclose( logfile );
logfile = NULL;
}
this->resetCounters( false );
this->opcodeObfuscator = 0;
thisWasJustServerPing = false; // destructor
if( sock_client != INVALID_SOCKET )
{
//closesocket( sock_client );
L2PNet_closesocket( sock_client );
sock_client = INVALID_SOCKET;
}
if( sock_server != INVALID_SOCKET )
{
//closesocket( sock_server );
L2PNet_closesocket( sock_server );
sock_server = INVALID_SOCKET;
}
// delete obfuscator, if exists
if( this->clsObfuscator )
{
class L2PCodeObfuscator * lpco = (class L2PCodeObfuscator *)clsObfuscator;
lpco->clear();
delete lpco;
this->clsObfuscator = NULL;
}
ai.clear();
hWndNotify = NULL;
uMsgNotify = 0;
}
void GameClient::logPacket(
const unsigned char *bytes,
unsigned int len,
bool bFromServer )
{
if( !this->logfile || !bytes || (len<1) ) return;
//
//if( bFromServer ) return; //:)
//
if( bFromServer ) fprintf( logfile, "Server: " );
else fprintf( logfile, "Client: " );
if( len < 3 )
{
fprintf( logfile, "Warning: packet length = %u ( < 3!)\n", len );
return;
}
char pname[256] = {0};
L2_VERSION l2_version = (L2_VERSION)g_cfg.L2_version;
if( !bFromServer ) l2_version = (L2_VERSION)g_cfg.L2_client_version;
L2Packets_GetL2PacketName( l2_version, bFromServer, bytes[2], bytes[3], bytes[5], pname, 255 );
fprintf( logfile, "Len %4u [%s] | %02X %02X / %02X / ", len, pname,
bytes[0], bytes[1], bytes[2] );
int i;
for( i=3; i<(int)len; i++ )
{
fprintf( logfile, "%02X ", bytes[i] );
if( ((i-2) % 4) == 0 ) fprintf( logfile, " " );
}
fprintf( logfile, "\n" );
fflush( logfile );
}
void GameClient::logPacketRaw(
const unsigned char *bytes,
unsigned int len,
bool bFromServer )
{
if( !this->logfileRaw || !bytes || (len<1) ) return;
//
//if( bFromServer ) return; //:)
//
if( bFromServer ) fprintf( logfileRaw, "Server: " );
else fprintf( logfileRaw, "Client: " );
if( len < 3 )
{
fprintf( logfileRaw, "Warning: packet length = %u ( < 3!)\n", len );
return;
}
fprintf( logfileRaw, "Len %4u | %02X %02X / %02X / ", len,
bytes[0], bytes[1], bytes[2] );
int i;
for( i=3; i<(int)len; i++ )
{
fprintf( logfileRaw, "%02X ", bytes[i] );
if( ((i-2) % 4) == 0 ) fprintf( logfileRaw, " " );
}
fprintf( logfileRaw, "\n" );
fflush( logfileRaw );
}
void GameClient::resetConnectedState()
{
// reset state
state = 0;
// reset other session vars: game proto ver, XOR encrypting
gameProtoVer = 0;
xor_enabled = false;
// reset XOR encryting keys
memset( key_client_sc, 0, sizeof(key_client_sc) );
memset( key_client_cs, 0, sizeof(key_client_cs) );
memset( key_server_sc, 0, sizeof(key_server_sc) );
memset( key_server_cs, 0, sizeof(key_server_cs) );
// sockets
sock_client = INVALID_SOCKET;
sock_server = INVALID_SOCKET;
// obfuscator
opcodeObfuscator = 0;
if( this->clsObfuscator )
{
class L2PCodeObfuscator * lpco = (class L2PCodeObfuscator *)clsObfuscator;
lpco->clear();
delete lpco;
log_error( LOG_DEBUG, "GameClient::resetConnectedState(): deleted obfuscator class\n" );
this->clsObfuscator = NULL;
}
//thisWasJustServerPing = false; // NO!!! don't reset it here!
//hWndNotify = NULL;
//uMsgNotify = 0;
}
void GameClient::resetCounters( bool addFakePacket )
{
counters.resetCounters();
if( addFakePacket )
{
counters.addRcvdPacket( 10 );
counters.addSentPacket( 10 );
}
}
void GameClient::getCounters( GameClientCounters& out ) const
{
out = counters;
}
void GameClient::setCountersStartingExp( unsigned long long int exp )
{
if( counters.ullStartingExp == 0 )
counters.ullStartingExp = exp;
}
void GameClient::startCountersTimer()
{
counters.startTimer();
}
void GameClient::setNotifyWindow( HWND notifyHwnd, UINT notifyMsg )
{
this->hWndNotify = notifyHwnd;
this->uMsgNotify = notifyMsg;
}
void GameClient::postNotify( WPARAM wParam, LPARAM lParam )
{
if( hWndNotify == NULL || (uMsgNotify < WM_USER) ) return;
PostMessage( hWndNotify, uMsgNotify, wParam, lParam );
}
void GameClient::LockSend()
{
EnterCriticalSection( &cs_send );
}
void GameClient::UnlockSend()
{
LeaveCriticalSection( &cs_send );
}

132
l2detect/GameClient.h Normal file
View File

@@ -0,0 +1,132 @@
#ifndef FAKELOGIN_GAMECLIENT_H_
#define FAKELOGIN_GAMECLIENT_H_
#include "UserAI.h"
#include "GameClientCounters.h"
// client state
#define GCST_OFFLINE 0 // not connected to GS :)
#define GCST_CONNECTED 1 // just connected to GS
#define GCST_AUTHED 2 // passed GS auth, sees chars selection list
#define GCST_IN_GAME 3 // selectedc har and entered game
// window notification wParam
#define GCN_STATECHANGE 1 // lParam will hold new state
class GameClient
{
public:
GameClient();
virtual ~GameClient();
public: // sniffer functions
bool PC_sniff( SOCKET scl, unsigned char *sip, unsigned short int sport );
void PP_sniff_fromServer( unsigned char *bytes, unsigned int len );
void PP_sniff_fromClient( unsigned char *bytes, unsigned int len );
public:
// algorythm of processing with full packet modifying control
bool PC_full( SOCKET scl, unsigned char *sip, unsigned short int sport );
// 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 PP_full_fromServer( unsigned char *bytes, unsigned int len,
unsigned char **newBytes, unsigned int *newLen );
// 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 PP_full_fromClient( unsigned char *bytes, unsigned int len,
unsigned char **newBytes, unsigned int *newLen );
// if packet was modified, it will be encoded again before resending
bool PP_full_reencode_packet( unsigned char *bytes, unsigned int len, unsigned char *key );
public: // counters
void resetCounters( bool addFakePacket );
void getCounters( GameClientCounters& out ) const;
void setCountersStartingExp( unsigned long long int exp );
void startCountersTimer();
public:
int getState() const { return this->state; }
bool InjectPacketToServer( unsigned char *bytes, unsigned int len, bool doObfuscate );
bool InjectPacketToClient( unsigned char *bytes, unsigned int len );
//void setHealItemsTable( HealItemsTable *other );
void setNotifyWindow( HWND notifyHwnd, UINT notifyMsg );
protected:
void LockSend();
void UnlockSend();
void logPacket( const unsigned char *bytes, unsigned int len, bool bFromServer );
void logPacketRaw( const unsigned char *bytes, unsigned int len, bool bFromServer );
void resetConnectedState();
void postNotify( WPARAM wParam, LPARAM lParam );
public: // char state, inventory...
UserAI ai;
bool wasJustServerPing() { return thisWasJustServerPing; }
protected:
// protocol state vars
bool xor_enabled;
unsigned char key_client_sc[32]; // key S->C (to re-encrypt FOR client side)
unsigned char key_client_cs[32]; // key C->S (to decrypt FROM client side)
unsigned char key_server_sc[32]; // key S->C (to decrypt FROM server side)
unsigned char key_server_cs[32]; // key C->S (to re-encrypt FOR server side)
unsigned int gameProtoVer;
unsigned int opcodeObfuscator;
void *clsObfuscator;
bool thisWasJustServerPing; // remains true, when client just sends server ping
// system vars
CRITICAL_SECTION cs_send;
int state;
FILE *logfile;
FILE *logfileRaw;
// counters
GameClientCounters counters;
// sockets
SOCKET sock_client;
SOCKET sock_server;
// notify window
HWND hWndNotify;
UINT uMsgNotify;
};
#endif /*FAKELOGIN_GAMECLIENT_H_*/

View File

@@ -0,0 +1,60 @@
#include "stdafx.h"
#include "GameClientCounters.h"
GameClientCounters::GameClientCounters()
{
resetCounters();
}
GameClientCounters::GameClientCounters( const GameClientCounters& other )
{
this->operator=( other );
}
GameClientCounters& GameClientCounters::operator=( const GameClientCounters& other )
{
this->ullBytesRcvd = other.ullBytesRcvd;
this->ullBytesSent = other.ullBytesSent;
this->ullPacketsRcvd = other.ullPacketsRcvd;
this->ullPacketsSent = other.ullPacketsSent;
this->startTime = other.startTime;
this->ullStartingExp = other.ullStartingExp;
return (*this);
}
void GameClientCounters::resetCounters()
{
this->ullBytesRcvd = this->ullBytesSent =
this->ullPacketsRcvd = this->ullPacketsSent = 0;
this->startTime = 0;
this->ullStartingExp = 0;
}
void GameClientCounters::startTimer()
{
this->startTime = (unsigned)time( NULL );
}
void GameClientCounters::addSentPacket( unsigned long long int packetLen )
{
this->ullPacketsSent++;
this->ullBytesSent += packetLen;
}
void GameClientCounters::addRcvdPacket( unsigned long long int packetLen )
{
this->ullPacketsRcvd++;
this->ullBytesRcvd += packetLen;
}
void GameClientCounters::calcNowStats( GameClient_NetStats *s )
{
unsigned int timeNow = (unsigned)time(NULL);
s->timePassedSecs = ((double)(timeNow - startTime));
s->avgSendSpeed = ((double)ullBytesSent) / (s->timePassedSecs);
s->avgRecvSpeed = ((double)ullBytesRcvd) / (s->timePassedSecs);
s->avgSendPacketsPerSec = ((double)ullPacketsSent) / (s->timePassedSecs);
s->avgRecvPacketsPerSec = ((double)ullPacketsRcvd) / (s->timePassedSecs);
s->avgRecvPacketSize = ((double)ullBytesRcvd) / ((double)ullPacketsRcvd);
s->avgSendPacketSize = ((double)ullBytesSent) / ((double)ullPacketsSent);
}

View File

@@ -0,0 +1,39 @@
#ifndef H_GAME_CLIENT_COUNTERS
#define H_GAME_CLIENT_COUNTERS
class GameClient_NetStats
{
public:
double timePassedSecs;
double avgSendSpeed;
double avgRecvSpeed;
double avgSendPacketsPerSec;
double avgRecvPacketsPerSec;
double avgSendPacketSize;
double avgRecvPacketSize;
};
class GameClientCounters
{
public:
GameClientCounters();
GameClientCounters( const GameClientCounters& other );
GameClientCounters& operator=( const GameClientCounters& other );
public:
void resetCounters();
void startTimer();
public:
void addSentPacket( unsigned long long int packetLen );
void addRcvdPacket( unsigned long long int packetLen );
public:
void calcNowStats( GameClient_NetStats *s );
public:
unsigned int startTime;
unsigned long long int ullBytesSent;
unsigned long long int ullBytesRcvd;
unsigned long long int ullPacketsSent;
unsigned long long int ullPacketsRcvd;
unsigned long long int ullStartingExp;
};
#endif

View File

@@ -0,0 +1,341 @@
#include "stdafx.h"
#include "ConfigIni.h"
#include "Logger.h"
#include "GameClient.h"
#include "GameListener.h"
#include "CharArray.h"
#include "ClanList.h"
#include "ProtocolConverter.h"
//
#include "RadarDllWnd.h"
extern class CConfig g_cfg;
extern class GameListener *g_pgame;
bool GameClient::PC_full( SOCKET scl, unsigned char *sip, unsigned short int sport )
{
sock_client = INVALID_SOCKET;
sock_server = INVALID_SOCKET;
this->resetCounters( false );
log_error( LOG_DEBUG, "GameClient::ProcessClient_full() started\n" );
// assert
if( (scl == INVALID_SOCKET) || (!sip) || (sport<1) )
{
log_error( LOG_ERROR, "GameClient::ProcessClient_full(): start assert failed\n" );
return false;
}
// vars
bool retVal = false;
SOCKET sg = INVALID_SOCKET;
char ssip[16] = {0};
sprintf( ssip, "%d.%d.%d.%d", (int)sip[0], (int)sip[1], (int)sip[2], (int)sip[3] );
// first we should connect to real game server
// create real GS socket
sg = L2PNet_TCPsocket_create( true );
if( sg == INVALID_SOCKET )
{
log_error( LOG_ERROR, "GameClient::ProcessClient_full(): real GS socket create\n" );
return false;
}
// connect to real game server
log_error( LOG_DEBUG, "GameClient::ProcessClient_full(): Connecting to real game server %s:%d ", ssip, (int)sport );
L2PNet_connect( sg, ssip, sport );
int nTries = 20;
int r = 0;
while( nTries > 0 )
{
log_error_np( LOG_DEBUG, "." );
r = L2PNet_select( sg, L2PNET_SELECT_WRITE, 500, NULL, NULL );
if( r == 1 ) break;
nTries--;
}
if( r == 1 )
{
log_error_np( LOG_DEBUG, " Connected. Tries left: %d\n", nTries );
}
else
{
log_error_np( LOG_DEBUG, " Failed!\n", nTries );
log_error( LOG_ERROR, "PC_full(): cannot connect to real game server!\n" );
// close sockets
L2PNet_shutdown( scl );
L2PNet_closesocket( scl );
L2PNet_shutdown( sg );
L2PNet_closesocket( sg );
log_error_np( LOG_DEBUG, " Not connected.\n" );
return false;
}
// allocate receive buffer
unsigned char *packbuffer = (unsigned char *)malloc( 65536 ); // 64 Kb :)
if( !packbuffer )
{
log_error( LOG_ERROR, "PC_full(): cannot allocate 64 Kb packet receive buffer!\n" );
// close sockets
L2PNet_shutdown( scl );
L2PNet_closesocket( scl );
L2PNet_shutdown( sg );
L2PNet_closesocket( sg );
log_error_np( LOG_DEBUG, " Not connected.\n" );
return false;
}
// open log file
if( g_cfg.LogGamePackets )
{
char filename[256];
time_t nowTime;
time( &nowTime );
sprintf( filename, "%s%u.txt", g_cfg.LogGameFileNamePrefix, (unsigned int)nowTime );
this->logfile = fopen( filename, "wt" );
if( !logfile )
log_error( LOG_WARNING, "GameClient::PC_full(): Cannot open log file [%s] for writing!\n",
filename );
}
// set initial game client state
this->state = GCST_CONNECTED;
this->thisWasJustServerPing = false; // initial assign before any packet recieved
bool bWasModified = false;
this->sock_client = scl;
this->sock_server = sg;
ProtoConv_Init();
this->postNotify( GCN_STATECHANGE, this->state );
ai.notifyEvent( UAI_EVENT_START );
this->counters.startTimer();
// infinite loop
int recvTimeout = 120; // seconds
long recvTimeoutMsec = recvTimeout * 1000;
int selectTimeout = 1; // seconds
struct timeval tv;
fd_set fdReadSet;
unsigned char *newBytes = NULL;
unsigned int rcvdLen = 0;
unsigned int sentLen = 0;
unsigned int newLen = 0;
int wsaerr = 0;
unsigned int scode = 0;
while( 1 )
{
scode = g_pgame->getLastSignal();
if( scode == FLGS_STOP )
{
log_error( LOG_DEBUG, "GameClient::PC_full(): exit signal\n" );
break;
}
tv.tv_sec = selectTimeout;
tv.tv_usec = 0;
// check readability on sockets
FD_ZERO( &fdReadSet ); // zero set
FD_SET( scl, &fdReadSet ); // add client socket to read set
FD_SET( sg, &fdReadSet ); // add real GS socket to read set
//
r = L2PNet_select_wrapper_DUMB( 0, &fdReadSet, 0, 0, &tv );
if( r == 0 ) /* timeout failed */
{
log_error_np( LOG_DEBUGDUMP, "." );
}
else if( r == -1 ) /* select error */
{
log_error_np( LOG_DEBUGDUMP, "\nselect() ERROR\n" );
// TODO: what to do on select() error?
wsaerr = L2PNet_WSAGetLastError();
log_error( LOG_ERROR, "WinSock select() error %d: ", wsaerr );
L2PNet_WSAPrintLastError( ErrorLogger_GetLogFile(), wsaerr );
log_error_np( LOG_DEBUGDUMP, "\n" );
//log_error( LOG_ERROR, "ProcessClient_full(): socket select() ERROR!\n" );
//log_error( LOG_ERROR, "ProcessClient_full(): closing processing\n" );
//goto netError;
}
else if( r > 0 )
{
log_error_np( LOG_DEBUGDUMP, "\nselect(): number of sockets ready: %d\n", r );
// client sent something?
if( L2PNet_FD_ISSET( scl, &fdReadSet ) )
{
//log_error( LOG_DEBUGDUMP, "C->S (reading...)\n" );
// receive packet from client
r = L2PacketReceive_buffer( scl, recvTimeoutMsec, &rcvdLen, packbuffer );
//log_error( LOG_DEBUGDUMP, "Received %u bytes from client\n", rcvdLen );
if( (r == 0) && (rcvdLen == 0) )
{
log_error( LOG_WARNING, "Connection closed by client?\n" );
goto closeSocks;
}
if( r <= 0 )
{
log_error( LOG_ERROR, "L2PacketReceive() failed!\n" );
wsaerr = L2PNet_WSAGetLastError();
log_error( LOG_ERROR, "WinSock error %d: ", wsaerr );
L2PNet_WSAPrintLastError( ErrorLogger_GetLogFile(), wsaerr );
log_error_np( LOG_ERROR, "\n" );
goto netError;
}
// process it! :)
bWasModified = PP_full_fromClient( packbuffer, rcvdLen, &newBytes, &newLen );
if( newLen != -1 ) // -1 means - Drop packet
{
// resend packet to server after processing
LockSend();
r = L2PacketSend2( newBytes, sg, recvTimeoutMsec, &sentLen );
UnlockSend();
// if packet was not modified: newBytes points to the same memory as p points
// if packet was modified: newBytes points to new memory
// ... in this case we should free new memory separately
if( newBytes != packbuffer ) free( newBytes ); // :)
// in both cases newLen contains length to be sent
//log_error( LOG_DEBUGDUMP, "Sent %u bytes to server\n", sentLen );
if( sentLen != newLen ) // we must send newLen
{
log_error( LOG_ERROR, "PC_full(): After L2PacketSend2() C->S sentLen != newLen!!! (%u != %u, bWasModified = %d)\n",
sentLen, newLen, (int)bWasModified );
goto netError;
}
// counters
this->counters.addSentPacket( sentLen );
}
//else
//{
// log_error( LOG_DEBUGDUMP, "PC_full(): dropped packet...\n" );
//}
}
// server sent something?
if( L2PNet_FD_ISSET( sg, &fdReadSet ) )
{
//log_error( LOG_DEBUGDUMP, "S->C (reading...)\n" );
// receive packet from server
r = L2PacketReceive_buffer( sg, recvTimeoutMsec, &rcvdLen, packbuffer );
//log_error( LOG_DEBUGDUMP, "Received %u bytes from server\n", rcvdLen );
if( (r == 0) && (rcvdLen == 0) )
{
log_error( LOG_DEBUG, "Connection closed by server?\n" );
goto closeSocks;
}
if( r <= 0 )
{
log_error( LOG_ERROR, "L2PacketReceive() failed!\n" );
wsaerr = L2PNet_WSAGetLastError();
log_error( LOG_ERROR, "WinSock error %d: ", wsaerr );
L2PNet_WSAPrintLastError( ErrorLogger_GetLogFile(), wsaerr );
log_error_np( LOG_ERROR, "\n" );
goto netError;
}
// counters
this->counters.addRcvdPacket( rcvdLen );
// process it! :)
bWasModified = PP_full_fromServer( packbuffer, rcvdLen, &newBytes, &newLen );
if( newLen != -1 ) // -1 means - Drop packet
{
// resend packet to client
LockSend();
r = L2PacketSend2( newBytes, scl, recvTimeoutMsec, &sentLen );
UnlockSend();
// if packet was not modified: newBytes points to the same memory as p points
// if packet was modified: newBytes points to new memory
// ... in this case we should free new memory separately
if( newBytes != packbuffer )
{
//log_error( LOG_OK, "Packet was modified, freeing newBytes buffer (newLen = %u)\n", newLen );
free( newBytes ); // :)
}
// in both cases newLen contains length to be sent
//log_error( LOG_DEBUGDUMP, "Sent %u bytes to client\n", sentLen );
if( sentLen != newLen )
{
log_error( LOG_ERROR, "PC_full(): After L2PacketrSend2() S->C sent != rcvd!!! (%u != %u, bWasModified = %d)\n",
sentLen, newLen, (int)bWasModified );
goto netError;
}
} // newLen != -1
}
} // (r>0) // select() OK
}// while(1)
retVal = true;
netError:
retVal = true;
if( wsaerr > 0 )
{
retVal = false;
log_error( LOG_ERROR, "PC_full(): some error happened or network connection closed...\n" );
}
closeSocks:
// save radar window size
PostMessage( g_radardll_hwnd, WMMY_SAVE_WINDOW_SIZE, 0, 0 );
// logfile
if( this->logfile )
{
fclose( this->logfile );
this->logfile = NULL;
}
// free packbuffer
if( packbuffer ) free( packbuffer );
packbuffer = NULL;
// stop AI thread
ai.notifyEvent( UAI_EVENT_STOP );
// reset internal state
this->resetConnectedState();
// sockets
L2PNet_shutdown( scl );
L2PNet_closesocket( scl );
L2PNet_shutdown( sg );
L2PNet_closesocket( sg );
// lists
CharArray_DeleteAll();
ClanList_DeleteAll();
// switch state
this->state = GCST_OFFLINE;
this->postNotify( GCN_STATECHANGE, this->state );
// log counters
GameClient_NetStats netstats;
counters.calcNowStats( &netstats );
log_error_np( LOG_OK, "=============================================\n" );
log_error_np( LOG_OK, "Network usage stats:\n" );
log_error_np( LOG_OK, "Bytes, packets sent: %I64u, %I64u\n", counters.ullBytesSent, counters.ullPacketsSent );
log_error_np( LOG_OK, "Bytes, packets rcvd: %I64u, %I64u\n", counters.ullBytesRcvd, counters.ullPacketsRcvd );
log_error_np( LOG_OK, "Time connected: %0.2f seconds\n", netstats.timePassedSecs );
log_error_np( LOG_OK, "Avg send speed: %0.2f bytes/sec\n", netstats.avgSendSpeed );
log_error_np( LOG_OK, "Avg recv speed: %0.2f bytes/sec\n", netstats.avgRecvSpeed );
log_error_np( LOG_OK, "Avg send L2 packets: %0.2f packets/sec\n", netstats.avgSendPacketsPerSec );
log_error_np( LOG_OK, "Avg recv L2 packets: %0.2f packets/sec\n", netstats.avgRecvPacketsPerSec );
log_error_np( LOG_OK, "Avg out packet size: %0.2f bytes\n", netstats.avgSendPacketSize );
log_error_np( LOG_OK, "Avg in packet size: %0.2f bytes\n", netstats.avgRecvPacketSize );
log_error_np( LOG_OK, "=============================================\n" );
ErrorLogger_FlushLogFile();
//
log_error( LOG_DEBUG, "GameClient::PC_full() ending, returning %d\n", (int)retVal );
return retVal;
}
// if packet was modified, it will be encoded again before resending
bool GameClient::PP_full_reencode_packet( unsigned char *bytes, unsigned int len, unsigned char *key )
{
if( !this->xor_enabled ) return true; // no need to encrypt now - XOR keys not received yet
//if( !bytes || (len<3) || !key ) return false; // asserts
//L2GamePacket p;
//if( !p.setBytes( bytes, len ) ) return false;
//if( !p.encodeXOR( key ) ) return false;
//memcpy( bytes, p.getBytesPtr(), len );
// speed optimisation - remove constructor(), setBytes() calls and memcpy() call
bool ret = L2GamePacket::encodeXOR_buffer( bytes, len, key ); // encode directly in buffer
/*log_error( LOG_DEBUGDUMP, "PP_full_reencode_packet(): packet of len %u re-encode result: %d\n",
len, (int)ret );*/
return ret;
}

View File

@@ -0,0 +1,581 @@
#include "stdafx.h"
#include "ConfigIni.h"
#include "Logger.h"
#include "GameClient.h"
#include "GameListener.h"
#include "L2PacketTypes.h"
#include "accountBind.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 can ignore newLen and newBytes content in this case
// - caller can use newLen and newBytes instead of original values (they are the same)
// - caller should send original packet
// - caller should free original packet buffer
// 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
// - caller should also free original packet buffer
// if packet should be dropped:
// sets (*newLen) to -1
// - caller should ignore newLen and newBytes content
// - caller should not send any packet :)
// - caller should free original packet buffer
//
bool GameClient::PP_full_fromClient( unsigned char *bytes, unsigned int len,
unsigned char **newBytes, unsigned int *newLen )
{
// assume packet was not modified
(*newLen) = len;
(*newBytes) = bytes;
//
//int i = 0;
bool bPacketWasModified = false; // initially packet is not modified
if( !bytes || len<1 ) return bPacketWasModified;
if( len<3 )
{
log_error( LOG_WARNING, "PP_full_fromClient(): packet len < 3!\n" );
return bPacketWasModified;
}
// should we decrypt it?
if( this->xor_enabled ) L2GamePacket::decodeXOR_buffer( bytes, len, this->key_client_cs );
// 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;
if( lpco )
{
if( lpco->isEnabled() )
{
unsigned char pcode_prev = ptype;
unsigned short pcode2_prev = ptype2;
bool decode_res = false;
try
{
decode_res = lpco->decodeOpcode( ptype, ptype2 );
}
catch( L2P_DeObfuscateException& e )
{
log_error( LOG_ERROR, "PP_full_fromClient(): L2P_DeObfuscateException: %s\n", e.what() );
}
if( decode_res )
{
if( pcode2_prev == ptype2 ) // 2nd opcode not changed, not double-opcode packet
log_error( LOG_DEBUG, " **** de-obfuscated %02X -> %02X ****\n", pcode_prev, ptype );
else
log_error( LOG_DEBUG, " **** de-obfuscated %02X:%02X -> %02X:%02X ****\n",
pcode_prev, pcode2_prev, ptype, ptype2 );
}
else
log_error( LOG_ERROR, "PP_full_fromClient(): ERROR de-obfuscating %02X\n", pcode_prev );
}
}
// log packet here, when it is decrypted, and opcode is deobfuscated, if log game packets is enabled
if( this->logfile )
{
unsigned char prev_1 = bytes[2];
unsigned short prev_2 = bytes[3] | (bytes[4] << 8);
unsigned short prev_3 = bytes[5] | (bytes[6] << 8);
if( this->clsObfuscator )
{
// replace opcode byte in bytes array to de-obfuscated opcode
// to make log readable
bytes[2] = ptype;
if( len >= 5 )
{
bytes[3] = ptype2 & 0xFF;
bytes[4] = (ptype2 >> 8) & 0xFF;
if( len >= 7 )
{
bytes[5] = ptype3 & 0xFF;
bytes[6] = (ptype3 >> 8) & 0xFF;
}
}
}
logPacket( bytes, len, false ); // false - from client
if( this->clsObfuscator )
{
// restore opcode byte in bytes array to original
// to keep packet 'as is'
bytes[2] = prev_1;
if( len >= 5 )
{
bytes[3] = prev_2 & 0xFF;
bytes[4] = (prev_2 >> 8) & 0xFF;
if( len >= 7 )
{
bytes[5] = prev_3 & 0xFF;
bytes[6] = (prev_3 >> 8) & 0xFF;
}
}
}
}
L2PacketTypes_LogClient( (L2_VERSION)g_cfg.L2_client_version, this->state, ptype, ptype2, ptype3 );
// special handling packet sequential number
if( this->counters.ullPacketsSent == 0 )
{
// client sends first packet - ProtocolVersion
if( g_cfg.OverrideGameProtocolVersion > 0 )
{
// we can replace ProtocolVersion now...
int cur_pv = bytes[3] | (bytes[4]<<8) | (bytes[5]<<16) | (bytes[6]<<24);
// check for client pings server (usually: pv == -2 or 0xFFFFFFFE)
if( (cur_pv >= 0xFFFFFFF0) || (cur_pv < 0) )
{
log_error( LOG_PACKETNAME, "Received client ping server... no process\n" );
this->thisWasJustServerPing = true; // received client ping (full)
return false; // flag: packet was not modified, and no need to re-encode it
}
//
log_error( LOG_PACKETNAME, "Client: 0e ProtocolVersion: Overriding ProtocolVersion from %d to %d\n",
cur_pv, g_cfg.OverrideGameProtocolVersion );
bytes[3] = (unsigned char)( (g_cfg.OverrideGameProtocolVersion & 0x000000FF) );
bytes[4] = (unsigned char)( (g_cfg.OverrideGameProtocolVersion & 0x0000FF00) >> 8 );
if( g_cfg.OverrideGameProtocolVersion == 828 )
{
/* Overriding to Kamael T1. we must replace also last 4 bytes */
bytes[263] = 0x8D;
bytes[264] = 0x71;
bytes[265] = 0x5F;
bytes[266] = 0x08;
log_error( LOG_PACKETNAME, "Client: 0e ProtocolVersion: Overriding ProtocolVersion to T1: Kamael\n" );
}
if( g_cfg.OverrideGameProtocolVersion == 831 )
{
/* Overriding to Hellbound T1.5. we must replace also last 4 bytes */
bytes[263] = 0xFB;
bytes[264] = 0x87;
bytes[265] = 0xB9;
bytes[266] = 0x4A;
log_error( LOG_PACKETNAME, "Client: 0e ProtocolVersion: Overriding ProtocolVersion to T1.5: Hellbound\n" );
}
if( g_cfg.OverrideGameProtocolVersion == 851 )
{
/* Overriding to Gracia T2. we must replace also last 4 bytes */
bytes[263] = 0xDF;
bytes[264] = 0xB8;
bytes[265] = 0x3B;
bytes[266] = 0x54;
log_error( LOG_PACKETNAME, "Client: 0e ProtocolVersion: Overriding ProtocolVersion to T2: Gracia Part 1\n" );
}
if( g_cfg.OverrideGameProtocolVersion >= 12 && g_cfg.OverrideGameProtocolVersion <= 17 )
{
/* Overriding to Gracia T2.2. we must replace also last 4 bytes */
bytes[263] = 0xEB;
bytes[264] = 0xEF;
bytes[265] = 0x3D;
bytes[266] = 0xE6;
log_error( LOG_PACKETNAME, "Client: 0e ProtocolVersion: Overriding ProtocolVersion to T2.2: Gracia Part 2\n" );
}
if( g_cfg.OverrideGameProtocolVersion >= 83 && g_cfg.OverrideGameProtocolVersion <= 87 )
{
/* Overriding to Gracia T2.3. we must replace also last 4 bytes */
bytes[263] = 0x11;
bytes[264] = 0x5D;
bytes[265] = 0x1F;
bytes[266] = 0x60;
log_error( LOG_PACKETNAME, "Client: 0e ProtocolVersion: Overriding ProtocolVersion to T2.3: Gracia Final\n" );
}
if( g_cfg.OverrideGameProtocolVersion >= 146 && g_cfg.OverrideGameProtocolVersion <= 148 )
{
/* Overriding to Gracia T2.4. we must replace also last 4 bytes */
bytes[263] = 0xA6;
bytes[264] = 0x23;
bytes[265] = 0xF4;
bytes[266] = 0xFE;
log_error( LOG_PACKETNAME, "Client: 0e ProtocolVersion: Overriding ProtocolVersion to T2.4: Gracia Epilogue\n" );
}
return true; // flag that packet was modified :)
// we can use return here, because encoding is not required for this packet
// packet will be sent to server as is, without encoding
}
}
// special handling packet sequential number end
switch( this->state )
{
case GCST_CONNECTED:
{
switch( ptype )
{
//case 0x00: // ProtocolVersion // Interlude
case 0x0e: // ProtocolVersion // Hellbound
{
L2Game_ProtocolVersion *p = new L2Game_ProtocolVersion( bytes, len );
p->read_protoVer( &(this->gameProtoVer) );
delete p;
log_error( LOG_PACKETNAME, "Client: 0e ProtocolVersion %u\n", this->gameProtoVer );
if( this->gameProtoVer >= 0xFFFFFFF0 )
{
this->thisWasJustServerPing = true; // received client ping (full)
log_error( LOG_PACKETNAME, "Received client ping server... no process\n" );
}
} break; // ProtocolVersion
// case 0x08: // AuthLogin // Interlude
case 0x2b: // AuthLogin // Hellbound
{
L2Game_AuthLogin *p = new L2Game_AuthLogin( bytes, len );
char login[32] = {0};
p->read_login( login );
delete p;
log_error( LOG_DEBUG, "Client: 2b AuthLogin: Login: \"%s\"\n", login );
#ifdef _ACCOUNT_BIND
if( !isValidAccount( login ) )
{
log_error( LOG_ERROR, "Client: invalid account name (not bound to this). Exiting.\n" );
ErrorLogger_FlushLogFile();
L2PNet_shutdown( this->sock_client );
L2PNet_shutdown( this->sock_server );
Sleep( 2000 );
L2PNet_closesocket( this->sock_client );
L2PNet_closesocket( this->sock_server );
ExitProcess( 123 );
}
#endif
} break; // AuthLogin
//default:
// {
// log_error( LOG_DEBUGDUMP, "Client: 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; // CONNECTED
//case GCST_AUTHED:
//{
// switch( ptype )
// {
//case 0x00: // LogoutRequest
// {
// log_error( LOG_PACKETNAME, "Client: 00 LogoutRequest\n" );
// } break;
//case 0x12: // CharacterSelect // Hellbound
// {
// int charSlot = bytes[3];
// //L2Game_CharacterSelect *p = new L2Game_CharacterSelect( bytes, len );
// log_error( LOG_PACKETNAME, "Client: 12 CharacterSelect: #%d\n", charSlot );
// //this->state = GCST_IN_GAME;
// //log_error( LOG_DEBUG, "Client: 12 CharacterSelect: switch state to IN_GAME\n" );
// } break; // CharacterSelect
//case 0x13: // NewCharacter
// {
// log_error( LOG_PACKETNAME, "Client: 13 NewCharacter\n" );
// } break; // NewCharacter
//case 0x0c: // CharacterCreate
// {
// wchar_t charNameU[64] = {0};
// char charName[64] = {0};
// wcscpy( charNameU, (const wchar_t *)(bytes+3) );
// sprintf( charName, "%S", charNameU );
// log_error( LOG_PACKETNAME, "Client: 0c CharacterCreate [%s]\n", charName );
// } break; // CharacterCreate
//case 0xd0:
// {
// ptype2 = 0x0000;
// if( len >= 5 )
// {
// ptype2 |= (unsigned short int)(bytes[3] & 0xFFFF);
// ptype2 |= (unsigned short int)(bytes[4] << 8 & 0xFFFF);
// if( ptype2 == 0x0039 )
// {
// log_error( LOG_PACKETNAME, "Client: D0:39 RequestGotoLobby\n" );
// }
// else
// {
// log_error( LOG_WARNING, "Client: Unknown opcode2 %04X for state AUTHED packet 0xD0\n",
// (unsigned int)ptype2 );
// }
// }
// else
// log_error( LOG_WARNING, "Client: (AUTHED) sent 0xd0 without second opcode!\n" );
// } break; // double opcode packet
//default:
// {
// log_error( LOG_PACKETNAME, "Client: 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; // AUTHED
case GCST_IN_GAME:
{
switch( ptype )
{
//case 0x00: // LogoutRequest
// {
// log_error( LOG_PACKETNAME, "Client: 00 LogoutRequest\n" );
// } break;
case 0x0f: // MoveBackwardToLocation
{
//log_error( LOG_PACKETNAME, "Client: 0f MoveBackwardToLocation\n" );
if( g_cfg.L2Walker_FixMoveBackwardToLocation )
{
//log_error( LOG_OK, "Fixing L2Walker's MoveBackwardToLocation\n" );
if( len == 27 )
{
//log_error( LOG_OK, "It is L2Walker's packet\n" );
unsigned char *np = (unsigned char *)malloc( len + 4 );
if( np )
{
(*newBytes) = np;
(*newLen) = len + 4;
memcpy( np, bytes, len );
np[0] = ((unsigned char)31); // length of correct packet must be 31
np[1] = 0;
np[len + 0] = 0x01;
np[len + 1] = 0x00;
np[len + 2] = 0x00;
np[len + 3] = 0x00;
//
bPacketWasModified = true; // so it will be encoded in the end of this function
}
//else log_error( LOG_ERROR, "malloc() error!\n" );
}
//else if( len == 31 )
//{
// log_error( LOG_OK, "It is normal client's packet. No need to change\n" );
//}
//else log_error( LOG_ERROR, "Unknown MoveBackwardToLocation packet!\n" );
}
} break;
//case 0x11: // EnterWorld
// {
// log_error( LOG_PACKETNAME, "Client: 11 EnterWorld\n" );
// } break;
//case 0x14: // RequestItemList
// {
// log_error( LOG_PACKETNAME, "Client: 14 RequestItemList\n" );
// } break;
//case 0x19: // UseItem
// {
// log_error( LOG_PACKETNAME, "Client: 19 UseItem\n" );
// } break;
case 0x1F: // Action
{
//log_error( LOG_PACKETNAME, "Client: 1F Action\n" );
L2Game_Action *p = new L2Game_Action( bytes, len );
unsigned int actionObjectId = p->read_objectID();
p->read_originX();
p->read_originY();
p->read_originZ();
//char useShift = p->read_useShift();
delete p;
// notify LockTarget manager
ai.lockTargetMgr.onUserRequestAction( actionObjectId );
//
//if( useShift /* && g_cfg.altGameViewNpc */ )
//{
// L2OBJECT_TYPE objType = L2OT_NONE;
// int index = -1;
// if( WorldObjectTree_GetInfoByObjectID( oid, &objType, &index ) )
// {
// // disable Shift + click on NPC
// /*if( objType == L2OT_NPC )
// {
// L2Npc *npc = npc_array[index];
// char filename[256];
// sprintf( filename, "npc_%d_stats.txt", npc->templateID );
// FILE *f = fopen( filename, "wt" );
// fprintf( f, "x,y,z,heading: (%d,%d,%d) %u\n", npc->x, npc->y, npc->z, npc->heading );
// fprintf( f, "mAtkSpd, pAtkSpd: %d, %d\n", npc->mAtkSpd, npc->pAtkSpd );
// fprintf( f, "runSpeed, walkSpeed: %d, %d\n", npc->runSpeed, npc->walkSpeed );
// fprintf( f, "colR, colH: %0.2f, %0.2f\n", npc->collisionRadius, npc->collisionHeight );
// fprintf( f, "rhand, chest, lhand: %u, %u, %u\n", npc->iid_right_hand, npc->iid_chest, npc->iid_left_hand );
// fclose( f );
// }*/
// // maybe add Shift + click on player action? :)
// }
//}
} break;
case 0x22: // RequestLinkHtml
{
// this packet requires handling... it may be dropped if AI decides to
this->ai.UAI_process_RequestBypassToServer( bytes, len, newBytes, newLen );
} break;
case 0x23: // RequestBypassToServer
{
// this packet requires handling... it may be dropped if AI decides to
this->ai.UAI_process_RequestBypassToServer( bytes, len, newBytes, newLen );
} break;
case 0x36: // ChangeWaitType2
{
if( g_cfg.L2Walker_FixChangeWaitType2 )
{
log_error( LOG_OK, "Client: Fixing 36 ChangeWaitType2\n" );
// ChangeWaitType2 format:
// * Client: Len 7 | 07 00 / 36 / 00 00 00 00 - sit
// * Client: Len 7 | 07 00 / 36 / 01 00 00 00 - stand
// Instead of ChangeWaitType2 send RequestActionUse, so does client!
// only L2Walker sends ChangeWaitType2 :\
// RequestActionUse sit/stand format:
// * Client: Len 12 | 0C 00 / 56 / 00 00 00 00 00 00 00 00 00
// TODO: opcode obfuscate
unsigned char opcode_RequestActionUse = 0x56; // RequestActionUse
unsigned short doubleOpcode = 0x00;
if( this->clsObfuscator )
{
L2PCodeObfuscator *lpco = (L2PCodeObfuscator *)(this->clsObfuscator);
if( lpco->isEnabled() )
{
lpco->encodeOpcode( opcode_RequestActionUse, doubleOpcode );
log_error( LOG_DEBUG, "Fix ChangeWaitType2: obfuscated 56 -> %02X\n", opcode_RequestActionUse );
}
}
// create packet
L2GamePacket *gp = new L2GamePacket();
gp->setPacketType( opcode_RequestActionUse ); //gp->setPacketType( 0x56 ); // opcode :)
gp->writeUInt( 0 ); // actionID
gp->writeUInt( 0 ); // ctrlPressed
gp->writeUChar( 0 ); // shiftPressed
(*newLen) = gp->getPacketSize();
if( (*newLen) == 0x0C ) // new length must be = 12 bytes
{
log_error( LOG_OK, "Client: Fixed 36 ChangeWaitType2 OK\n" );
bPacketWasModified = true;
(*newBytes) = (unsigned char *)malloc( (*newLen) );
memcpy( (*newBytes), gp->getBytesPtr(), (*newLen) );
}
delete gp;
}
} break;
//case 0x39: // RequestMagicSkillUse
// {
// log_error( LOG_PACKETNAME, "Client: 39 RequestMagicSkillUse\n" );
// } break;
//case 0x3d: // RequestMagicSkillUse
// {
// log_error( LOG_PACKETNAME, "Client: 3D RequestShortCutReg\n" );
// } break;
case 0x48: // RequestTargetCanceld
{
//log_error( LOG_PACKETNAME, "Client: 48 RequestTargetCanceld\n" );
ai.lockTargetMgr.onUserRequestUnselectTarget();
} break;
//case 0x57: // RequestRestart
// {
// log_error( LOG_PACKETNAME, "Client: 57 RequestRestart\n" );
// //this->state = GCST_AUTHED;
// } break;
//case 0x59: // ValidatePosition
// {
// log_error( LOG_PACKETNAME, "Client: 59 ValidatePosition\n" );
// } break;
//case 0x65: // RequestPledgeInfo
// {
// // TODO: parse RequestPledgeInfo?
// log_error( LOG_OK, "Client: 65 RequestPledgeInfo\n" );
// } break;
case 0x8B: // RequestGmList
{
// RequestGmList kill packet?
//log_error( LOG_PACKETNAME, "Client: 8B RequestGmList\n" );
if( g_cfg.L2Walker_DropRequestGMList )
{
log_error( LOG_WARNING, "Client: Droppped RequestGMList!\n" );
(*newLen) = (unsigned int)-1; // mark to drop
}
} break;
//case 0xA6: // RequestSkillCoolTime
// {
// log_error( LOG_PACKETNAME, "Client: A6 RequestSkillCoolTime\n" );
// } break;
//case 0xCB: // GameGuardReply
// {
// log_error( LOG_PACKETNAME, "Client: CB GameGuardReply\n" );
// } break;
//case 0xd0:
// {
// ptype2 = 0x00;
// if( len >= 5 )
// {
// ptype2 |= (unsigned short int)(bytes[3] & 0xFFFF);
// ptype2 |= (unsigned short int)(bytes[4] << 8 & 0xFFFF);
// switch( ptype2 )
// {
// case 0x0065: // drop :)
// log_error( LOG_WARNING, "Client: Droppped D0:65 (RequestPostItemList in Epilogue)!\n" );
// (*newLen) = (unsigned int)-1; // mark to drop
// break;
// }
// }
// else
// log_error( LOG_WARNING, "Client: (IN_GAME) sent 0xD0 without second opcode!\n" );
// } break; // double opcode packet
//default:
// {
// log_error( LOG_PACKETNAME, "Client: 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; // IN_GAME
} // switch( state )
// all encoding takes place ONLY IF PACKET IS NOT SET TO DROP!!!!
if( (*newLen) != -1 )
{
// re-encode packet again =] olny encode original packetif it was not modified
//PP_full_reencode_packet( bytes, len, this->key_server_cs );
//log_error( LOG_ERROR, "PP_full_reencode_packet() C->S FAILED\n" );
if( !bPacketWasModified && this->xor_enabled ) L2GamePacket::encodeXOR_buffer( bytes, len, this->key_server_cs );
// if packet was modified, encode only modified packet (encode only that will be sent)
if( bPacketWasModified ) L2GamePacket::encodeXOR_buffer( (*newBytes), (*newLen), this->key_server_cs );
}
else log_error( LOG_PACKETNAME, "Client: No encode - DROP packet!\n" );
return bPacketWasModified;
}

View File

@@ -0,0 +1,873 @@
#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;
}
} 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;
}

View File

@@ -0,0 +1,78 @@
#include "stdafx.h"
#include "ConfigIni.h"
#include "Logger.h"
#include "GameClient.h"
#include "GameListener.h"
extern CConfig g_cfg;
// TODO: count obfuscator
bool GameClient::InjectPacketToServer( unsigned char *bytes, unsigned int len, bool doObfuscate )
{
if( !bytes || (len<3) ) return false;
if( this->sock_server == INVALID_SOCKET ) return false;
if( g_cfg.EnableModifyGameTraffic == 0 ) return false; // FIXED: do not allow traffic modification if not set
if( this->state == GCST_OFFLINE )
log_error( LOG_WARNING, "GameClient::InjectPacketToServer(): trying to send packet to server in state GCST_OFFLINE!\n" );
unsigned int sentLen = 0;
// TODO: obfuscate opcode before sending?
if( doObfuscate )
{
if( (this->opcodeObfuscator != 0x00) && (this->clsObfuscator) )
{
L2PCodeObfuscator *obf = (L2PCodeObfuscator *)(this->clsObfuscator);
unsigned char singleOpcode = bytes[2];
unsigned short doubleOpcode = bytes[3] | (bytes[4] << 8);
unsigned short tripleOpcode = bytes[5] | (bytes[6] << 8);
unsigned char prev_singleOpcode = singleOpcode;
unsigned short prev_doubleOpcode = doubleOpcode;
try
{
obf->encodeOpcode( singleOpcode, doubleOpcode, tripleOpcode );
}
catch( L2P_ObfuscateException& e )
{
log_error( LOG_ERROR, "GameClient::InjectPacketToServer: ObfuscationException: %s\n", e.what() );
}
// log
if( prev_doubleOpcode == doubleOpcode )
log_error( LOG_PACKETNAME, "InjectPacketToServer: obfuscated %02X -> %02X\n",
singleOpcode, prev_singleOpcode );
else
log_error( LOG_PACKETNAME, "InjectPacketToServer: obfuscated %02X:%02X -> %02X:%02X\n",
singleOpcode, doubleOpcode, prev_singleOpcode, prev_doubleOpcode );
// replace bytes in packet
bytes[2] = singleOpcode;
bytes[3] = doubleOpcode & 0xFF;
bytes[4] = (doubleOpcode >> 8) & 0xFF;
}
}
// encode XOR if enabled
if( this->xor_enabled ) L2GamePacket::encodeXOR_buffer( bytes, len, this->key_server_cs );
LockSend();
//int ret = L2PacketSend( bytes, sock_server, 5, 0, &sentLen );
//int ret = L2PacketSend2( bytes, sock_server, 5000, &sentLen );
L2PacketSend2( bytes, sock_server, 5000, &sentLen );
UnlockSend();
return true;
}
bool GameClient::InjectPacketToClient( unsigned char *bytes, unsigned int len )
{
if( !bytes || (len<3) ) return false;
if( this->sock_client == INVALID_SOCKET ) return false;
if( g_cfg.EnableModifyGameTraffic == 0 ) return false; // FIXED: do not allow traffic modification if not set
if( this->state == GCST_OFFLINE )
log_error( LOG_WARNING, "GameClient::InjectPacketToClient(): trying to send packet to client in state GCST_OFFLINE!\n" );
unsigned int sentLen = 0;
if( this->xor_enabled )
{
L2GamePacket::encodeXOR_buffer( bytes, len, this->key_client_sc );
}
LockSend();
int ret = L2PacketSend2( bytes, sock_client, 5000, &sentLen );
UnlockSend();
if( ret <= 0 ) log_error( LOG_ERROR, "InjectPacketToClient: send failed (sent %u bytes)\n", sentLen );
return true;
}

View File

@@ -0,0 +1,273 @@
#include "stdafx.h"
#include "ConfigIni.h"
#include "Logger.h"
#include "GameClient.h"
#include "GameListener.h"
#include "CharArray.h"
#include "ClanList.h"
extern class CConfig g_cfg;
extern class GameListener *g_pgame;
bool GameClient::PC_sniff( SOCKET scl, unsigned char *sip, unsigned short int sport )
{
sock_client = INVALID_SOCKET;
sock_server = INVALID_SOCKET;
this->resetCounters( false );
log_error( LOG_DEBUG, "GameClient::ProcessClient_onlySniff() started\n" );
// assert
if( (scl == INVALID_SOCKET) || (!sip) || (sport<1) )
{
log_error( LOG_ERROR, "GameClient::ProcessClient_onlySniff(): start assert failed\n" );
return false;
}
// vars
bool retVal = false;
SOCKET sg = INVALID_SOCKET;
char ssip[16] = {0};
sprintf( ssip, "%d.%d.%d.%d", (int)sip[0], (int)sip[1], (int)sip[2], (int)sip[3] );
// first we should connect to real game server
// create real GS socket
sg = L2PNet_TCPsocket_create( true );
if( sg == INVALID_SOCKET )
{
log_error( LOG_ERROR, "GameClient::ProcessClient_onlySniff(): real GS socket create\n" );
return false;
}
// connect to real game server
log_error( LOG_DEBUG, "GameClient::ProcessClient_onlySniff(): Connecting to real game server %s:%d ", ssip, (int)sport );
L2PNet_connect( sg, ssip, sport );
int nTries = 20;
int r = 0;
while( nTries > 0 )
{
log_error_np( LOG_DEBUG, "." );
r = L2PNet_select( sg, L2PNET_SELECT_WRITE, 500, NULL, NULL );
if( r == 1 ) break;
nTries--;
}
log_error_np( LOG_DEBUG, "\n" );
if( r == 1 )
{
log_error( LOG_DEBUG, "GameClient::ProcessClient_onlySniff(): Connected. Tries left: %d\n", nTries );
}
else
{
// close sockets
L2PNet_shutdown( scl );
L2PNet_closesocket( scl );
L2PNet_shutdown( sg );
L2PNet_closesocket( sg );
log_error( LOG_DEBUG, "GameClient::ProcessClient_onlySniff(): Not connected.\n" );
return false;
}
// open log file
if( g_cfg.LogGamePackets )
{
char filename[256];
char filename_raw[256];
time_t nowTime;
time( &nowTime );
sprintf( filename, "%s%u.txt",
g_cfg.LogGameFileNamePrefix,
(unsigned int)nowTime );
sprintf( filename_raw, "%s%u_raw.txt",
g_cfg.LogGameFileNamePrefix,
(unsigned int)nowTime );
this->logfile = fopen( filename, "wt" );
if( !logfile )
log_error( LOG_WARNING, "GameClient::ProcessClient_onlySniff(): Cannot open log file [%s] for writing!\n",
filename );
// open raw log data for not decrypted packets, if problems with decryption
// this->logfileRaw = fopen( filename_raw, "wt" );
}
// set initial game client state
this->state = GCST_CONNECTED;
this->sock_client = scl;
this->sock_server = sg;
this->postNotify( GCN_STATECHANGE, this->state );
this->counters.startTimer();
ai.notifyEvent( UAI_EVENT_START );
// infinite loop
int recvTimeout = 20; // seconds
long recvTimeoutMsec = recvTimeout * 1000;
int selectTimeout = 1; // seconds
struct timeval tv;
fd_set fdReadSet;
unsigned char *p = NULL;
unsigned int rcvdLen = 0;
unsigned int sentLen = 0;
unsigned int scode = 0;
while( 1 )
{
// first check are we signaled to exit?
scode = g_pgame->getLastSignal();
if( scode == FLGS_STOP )
{
log_error( LOG_DEBUG, "GameClient::ProcessClient_onlySniff(): exit signal\n" );
break;
}
tv.tv_sec = selectTimeout;
tv.tv_usec = 0;
// check readability on sockets
FD_ZERO( &fdReadSet ); // zero set
FD_SET( scl, &fdReadSet ); // add client socket to read set
FD_SET( sg, &fdReadSet ); // add real GS socket to read set
//r = select( 0, &fdReadSet, 0, 0, &tv );
r = L2PNet_select_wrapper_DUMB( 0, &fdReadSet, 0, 0, &tv );
if( r == 0 ) /* timeout failed */
{
log_error_np( LOG_DEBUGDUMP, "." );
}
else if( r == -1 ) /* select error */
{
log_error_np( LOG_DEBUGDUMP, "\nselect() ERROR\n" );
// TODO: what to do on select() error?
//int wsaerr = WSAGetLastError();
int wsaerr = L2PNet_WSAGetLastError();
log_error( LOG_ERROR, "WinSock error: " );
L2PNet_WSAPrintLastError( ErrorLogger_GetLogFile(), wsaerr );
log_error_np( LOG_DEBUGDUMP, "\n" );
//log_error( LOG_ERROR, "ProcessClient_onlySniff(): socket select() ERROR!\n" );
//log_error( LOG_ERROR, "ProcessClient_onlySniff(): closing processing\n" );
//goto netError;
}
else if( r > 0 )
{
log_error_np( LOG_DEBUGDUMP, "\nselect(): number of sockets ready: %d\n", r );
if( L2PNet_FD_ISSET( scl, &fdReadSet ) ) // client sent something?
{
log_error( LOG_DEBUGDUMP, "C->S (reading...)\n" );
// first receive packet from client
p = L2PacketReceive_malloc( scl, recvTimeoutMsec, &rcvdLen );
log_error( LOG_DEBUGDUMP, "Received %u bytes from client\n", rcvdLen );
if( p && (rcvdLen == 0) )
{
log_error( LOG_WARNING, "Connection closed by client?\n" );
goto closeSocks;
}
if( !p )
{
log_error( LOG_ERROR, "L2PacketReceive() failed!\n" );
goto netError;
}
// counters
this->counters.addSentPacket( rcvdLen );
// ... then resend packet to server
r = L2PacketSend2( p, sg, recvTimeout*1000, &sentLen );
log_error( LOG_DEBUGDUMP, "Sent %u bytes to server\n", sentLen );
if( rcvdLen != sentLen )
{
log_error( LOG_ERROR, "sent != rcvd!!! (%u != %u)\n", sentLen, rcvdLen );
goto netError;
}
// log raw bytes, before decode
logPacketRaw( p, rcvdLen, false );
// ... and only then process this packet
PP_sniff_fromClient( p, rcvdLen );
logPacket( p, rcvdLen, false );
free( p );
p = NULL;
}
if( L2PNet_FD_ISSET( sg, &fdReadSet ) ) // server sent something?
{
log_error( LOG_DEBUGDUMP, "S->C (reading...)\n" );
// first receive packet from server
p = L2PacketReceive_malloc( sg, recvTimeoutMsec, &rcvdLen );
log_error( LOG_DEBUGDUMP, "Received %u bytes from server\n", rcvdLen );
if( p && (rcvdLen == 0) )
{
log_error( LOG_WARNING, "Connection closed by server?\n" );
goto closeSocks;
}
if( !p )
{
log_error( LOG_ERROR, "L2PacketReceive() failed!\n" );
goto netError;
}
// counters
this->counters.addRcvdPacket( rcvdLen );
// .. then resend packet to client
r = L2PacketSend2( p, scl, recvTimeout*1000, &sentLen );
log_error( LOG_DEBUGDUMP, "Sent %u bytes to client\n", sentLen );
if( rcvdLen != sentLen )
{
log_error( LOG_ERROR, "sent != rcvd!!! (%u != %u)\n", sentLen, rcvdLen );
goto netError;
}
// log raw bytes, before decode
logPacketRaw( p, rcvdLen, true );
// ... and only then process it
PP_sniff_fromServer( p, rcvdLen );
logPacket( p, rcvdLen, true );
free( p );
p = NULL;
}
} // (r>0) // select() OK
}// while(1)
retVal = true;
netError:
log_error( LOG_ERROR, "PC_sniff(): some error happened or network connection closed...\n" );
if( p ) free( p );
p = NULL;
retVal = false;
closeSocks: // all cleanup
// logfile
if( this->logfile )
{
fclose( this->logfile );
this->logfile = NULL;
}
// stop AI thread
ai.notifyEvent( UAI_EVENT_STOP );
this->resetConnectedState();
// sockets
L2PNet_shutdown( scl );
L2PNet_closesocket( scl );
L2PNet_shutdown( sg );
L2PNet_closesocket( sg );
// lists
CharArray_DeleteAll();
ClanList_DeleteAll();
// state
this->state = GCST_OFFLINE;
this->postNotify( GCN_STATECHANGE, this->state );
// log counters
GameClient_NetStats netstats;
counters.calcNowStats( &netstats );
log_error_np( LOG_OK, "=============================================\n" );
log_error_np( LOG_OK, "Network usage stats:\n" );
log_error_np( LOG_OK, "Bytes, packets sent: %I64u, %I64u\n", counters.ullBytesSent, counters.ullPacketsSent );
log_error_np( LOG_OK, "Bytes, packets rcvd: %I64u, %I64u\n", counters.ullBytesRcvd, counters.ullPacketsRcvd );
log_error_np( LOG_OK, "Time connected: %0.2f seconds\n", netstats.timePassedSecs );
log_error_np( LOG_OK, "Avg send speed: %0.2f bytes/sec\n", netstats.avgSendSpeed );
log_error_np( LOG_OK, "Avg recv speed: %0.2f bytes/sec\n", netstats.avgRecvSpeed );
log_error_np( LOG_OK, "Avg send L2 packets: %0.2f packets/sec\n", netstats.avgSendPacketsPerSec );
log_error_np( LOG_OK, "Avg recv L2 packets: %0.2f packets/sec\n", netstats.avgRecvPacketsPerSec );
log_error_np( LOG_OK, "Avg out packet size: %0.2f bytes\n", netstats.avgSendPacketSize );
log_error_np( LOG_OK, "Avg in packet size: %0.2f bytes\n", netstats.avgRecvPacketSize );
log_error_np( LOG_OK, "=============================================\n" );
ErrorLogger_FlushLogFile();
//
log_error( LOG_DEBUG, "GameClient::PC_sniff() ending, returning %d\n", (int)retVal );
return retVal;
}

View File

@@ -0,0 +1,333 @@
#include "stdafx.h"
#include "ConfigIni.h"
#include "Logger.h"
#include "GameClient.h"
#include "GameListener.h"
#include "L2PacketTypes.h"
extern class CConfig g_cfg;
void GameClient::PP_sniff_fromClient( unsigned char *bytes, unsigned int len )
{
//int i = 0;
if( !bytes || len<1 ) return;
if( len<3 )
{
log_error( LOG_WARNING, "PP_sniff_fromClient(): packet len < 3!\n" );
log_error( LOG_WARNING, "PP_sniff_fromClient(): bytes=0x%p, len=%d\n", bytes, len );
return;
}
// should we decrypt it?
if( this->xor_enabled ) // yeah :)
{
if( !L2GamePacket::decodeXOR_buffer( bytes, len, this->key_client_cs ) )
log_error( LOG_ERROR, "PP_sniff_fromClient(): decodeXOR_buffer() failed!\n" );
}
// some vars
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;
if( lpco )
{
if( lpco->isEnabled() )
{
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_PACKETNAME, " **** de-obfuscated %02X -> %02X\n", pcode_prev, ptype );
else
log_error( LOG_PACKETNAME, " **** de-obfuscated %02X:%02X -> %02X:%02X\n",
pcode_prev, pcode2_prev, ptype, ptype2 );
}
else
log_error( LOG_ERROR, "PP_sniff_fromClient(): ERROR de-obfuscating %02X\n", pcode_prev );
}
}
L2PacketTypes_LogClient( (L2_VERSION)g_cfg.L2_client_version, this->state, ptype, ptype2, ptype3 );
// from client
switch( this->state )
{
case GCST_CONNECTED:
{
switch( ptype )
{
//case 0x00: // ProtocolVersion // Interlude
case 0x0e: // ProtocolVersion // Hellbound
{
L2Game_ProtocolVersion *p = new L2Game_ProtocolVersion( bytes, len );
p->read_protoVer( &(this->gameProtoVer) );
delete p;
log_error( LOG_PACKETNAME, "Client: 0e ProtocolVersion %u\n", this->gameProtoVer );
// client sends protocolVersion = 0xFFFFFFFF when it pings server (not tries to connect really)
if( this->gameProtoVer >= 0xFFFFFFF0 )
{
log_error( LOG_PACKETNAME, "Received client ping server... no process\n" );
this->thisWasJustServerPing = true; // received client ping (sniff)
}
} break; // ProtocolVersion
// case 0x08: // AuthLogin // Interlude
case 0x2b: // AuthLogin // Hellbound
{
L2Game_AuthLogin *p = new L2Game_AuthLogin( bytes, len );
char login[32] = {0};
p->read_login( login );
delete p;
log_error( LOG_PACKETNAME, "Client: 2b AuthLogin: Login: \"%s\"\n", login );
} break; // AuthLogin
default:
{
log_error( LOG_DEBUGDUMP, "Client: 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; // CONNECTED
case GCST_AUTHED:
{
switch( ptype )
{
//case 0x00: // LogoutRequest
// {
// log_error( LOG_PACKETNAME, "Client: 00 LogoutRequest\n" );
// } break;
case 0x12: // CharacterSelect // Hellbound
{
int charSlot = bytes[3];
//L2Game_CharacterSelect *p = new L2Game_CharacterSelect( bytes, len );
log_error( LOG_PACKETNAME, "Client: 12 CharacterSelect: #%d\n", charSlot );
//this->state = GCST_IN_GAME;
//log_error( LOG_DEBUG, "Client: 12 CharacterSelect: switch state to IN_GAME\n" );
} break; // CharacterSelect
//case 0x13: // NewCharacter
// {
// log_error( LOG_PACKETNAME, "Client: 13 NewCharacter\n" );
// } break; // NewCharacter
//case 0x0c: // CharacterCreate
// {
// wchar_t charNameU[64] = {0};
// char charName[64] = {0};
// wcscpy( charNameU, (const wchar_t *)(bytes+3) );
// sprintf( charName, "%S", charNameU );
// log_error( LOG_PACKETNAME, "Client: 0c CharacterCreate [%s]\n", charName );
// } break; // CharacterCreate
case 0xd0:
{
ptype2 = 0x0000;
if( len >= 5 )
{
ptype2 |= (unsigned short int)(bytes[3] & 0xFFFF);
ptype2 |= (unsigned short int)(bytes[4] << 8 & 0xFFFF);
if( ptype2 == 0x0039 )
{
log_error( LOG_PACKETNAME, "Client: d0:0039 RequestGotoLobby\n" );
}
else
{
log_error( LOG_WARNING, "Client: Unknown opcode2 %04X for state AUTHED packet 0xD0\n",
(unsigned int)ptype2 );
}
}
else
log_error( LOG_WARNING, "Client: (AUTHED) sent 0xd0 without second opcode!\n" );
} break; // double opcode packet
default:
{
log_error( LOG_PACKETNAME, "Client: 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; // AUTHED
case GCST_IN_GAME:
{
switch( ptype )
{
//case 0x00: // LogoutRequest
// {
// log_error( LOG_PACKETNAME, "Client: 00 LogoutRequest\n" );
// } break;
//case 0x0f: // MoveBackwardToLocation
// {
// log_error( LOG_PACKETNAME, "Client: 0f MoveBackwardToLocation\n" );
// } break;
//case 0x11: // EnterWorld
// {
// log_error( LOG_PACKETNAME, "Client: 11 EnterWorld\n" );
// } break;
//case 0x14: // RequestItemList
// {
// log_error( LOG_PACKETNAME, "Client: 14 RequestItemList\n" );
// } break;
//case 0x19: // UseItem
// {
// log_error( LOG_PACKETNAME, "Client: 19 UseItem\n" );
// } break;
case 0x1F: // Action
{
//log_error( LOG_PACKETNAME, "Client: 1F Action\n" );
L2Game_Action *p = new L2Game_Action( bytes, len );
unsigned int oid = p->read_objectID();
p->read_originX();
p->read_originY();
p->read_originZ();
char useShift = p->read_useShift();
delete p;
if( useShift /* && g_cfg.altGameViewNpc */ )
{
L2OBJECT_TYPE objType = L2OT_NONE;
int index = -1;
if( WorldObjectTree_GetInfoByObjectID( oid, &objType, &index ) )
{
if( objType == L2OT_NPC )
{
L2Npc *npc = npc_array[index];
char filename[256];
sprintf( filename, "npc_%d_stats.txt", npc->templateID );
FILE *f = fopen( filename, "wt" );
fprintf( f, "x,y,z,heading: (%d,%d,%d) %u\n", npc->x, npc->y, npc->z, npc->heading );
fprintf( f, "mAtkSpd, pAtkSpd: %d, %d\n", npc->mAtkSpd, npc->pAtkSpd );
fprintf( f, "runSpeed, walkSpeed: %d, %d\n", npc->runSpeed, npc->walkSpeed );
fprintf( f, "colR, colH: %0.2f, %0.2f\n", npc->collisionRadius, npc->collisionHeight );
fprintf( f, "rhand, chest, lhand: %u, %u, %u\n", npc->iid_right_hand, npc->iid_chest, npc->iid_left_hand );
fclose( f );
}
}
}
} break;
//case 0x23: // RequestBypassToServer
// {
// log_error( LOG_PACKETNAME, "Client: 23 RequestBypassToServer\n" );
// } break;
//case 0x39: // RequestMagicSkillUse
// {
// log_error( LOG_PACKETNAME, "Client: 39 RequestMagicSkillUse\n" );
// } break;
//case 0x3d: // RequestMagicSkillUse
// {
// log_error( LOG_PACKETNAME, "Client: 3D RequestShortCutReg\n" );
// } break;
//case 0x48: // RequestTargetCanceld
// {
// log_error( LOG_PACKETNAME, "Client: 48 RequestTargetCanceld\n" );
// } break;
//case 0x57: // RequestRestart
// {
// log_error( LOG_PACKETNAME, "Client: 57 RequestRestart\n" );
// //this->state = GCST_AUTHED;
// } break;
//case 0x59: // ValidatePosition
// {
// log_error( LOG_PACKETNAME, "Client: 59 ValidatePosition\n" );
// } break;
//case 0x65: // RequestPledgeInfo
// {
// // TODO: parse RequestPledgeInfo?
// log_error( LOG_PACKETNAME, "Client: 65 RequestPledgeInfo\n" );
// } break;
//case 0x8B: // RequestGmList
// {
// log_error( LOG_PACKETNAME, "Client: 8B RequestGmList\n" );
// } break;
//case 0xA6: // RequestSkillCoolTime
// {
// log_error( LOG_PACKETNAME, "Client: A6 RequestSkillCoolTime\n" );
// } break;
//case 0xCB: // GameGuardReply
// {
// log_error( LOG_PACKETNAME, "Client: CB GameGuardReply\n" );
// } break;
//case 0xd0:
// {
// ptype2 = 0x00;
// if( len >= 5 )
// {
// ptype2 |= (unsigned short int)(bytes[3] & 0xFFFF);
// ptype2 |= (unsigned short int)(bytes[4] << 8 & 0xFFFF);
// if( ptype2 == 0x01 )
// {
// log_error( LOG_PACKETNAME, "Client: D0:01 RequestManorList\n" );
// }
// else if( ptype2 == 0x0d )
// {
// log_error( LOG_PACKETNAME, "Client: D0:0D RequestAutoSoulShot\n" );
// }
// else if( ptype2 == 0x17 )
// {
// // TODO: RequestPledgeWarList
// log_error( LOG_PACKETNAME, "Client: D0:17 RequestPledgeWarList\n" );
// }
// else if( ptype2 == 0x21 )
// {
// log_error( LOG_PACKETNAME, "Client: D0:21 RequestKeyMapping\n" );
// }
// else if( ptype2 == 0x24 )
// {
// log_error( LOG_PACKETNAME, "Client: D0:24 RequestSaveInventoryOrder\n" );
// }
// else
// {
// log_error( LOG_WARNING, "Client: Unknown opcode2 %04X for IN_GAME packet 0xD0\n",
// (unsigned int)ptype2 );
// }
// }
// else
// log_error( LOG_WARNING, "Client: (IN_GAME) sent 0xD0 without second opcode!\n" );
// } break; // double opcode packet
default:
{
log_error( LOG_PACKETNAME, "Client: 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; // IN_GAME
} // switch( state )
}

View File

@@ -0,0 +1,589 @@
#include "stdafx.h"
#include "ConfigIni.h"
#include "Logger.h"
#include "GameClient.h"
#include "GameListener.h"
#include "CharArray.h"
#include "ClanList.h"
#include "L2PacketTypes.h"
extern class CConfig g_cfg;
void GameClient::PP_sniff_fromServer( unsigned char *bytes, unsigned int len )
{
int i = 0;
if( !bytes || len<1 ) return;
if( len<3 )
{
log_error( LOG_WARNING, "PP_sniff_fromServer(): packet len < 3!\n" );
log_error( LOG_WARNING, "PP_sniff_fromServer(): bytes=0x%p, len=%d\n", bytes, len );
return;
}
// should we decrypt it?
if( this->xor_enabled ) // yeah :)
{
if( !L2GamePacket::decodeXOR_buffer( bytes, len, this->key_client_sc ) )
log_error( LOG_ERROR, "PP_sniff_fromServer(): decodeXOR_buffer() failed!\n" );
}
// some vars
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;
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_PACKETNAME, "PP_sniff_fromServer(): de-obfuscated %02X -> %02X\n", pcode_prev, ptype );
else
log_error( LOG_PACKETNAME, "PP_sniff_fromServer(): de-obfuscated %02X:%02X -> %02X:%02X\n",
pcode_prev, pcode2_prev, ptype, ptype2 );
}
else
log_error( LOG_ERROR, "PP_snigg_fromServer(): ERROR de-obfuscating %02X\n", pcode_prev, ptype );
}
}
L2PacketTypes_LogServer( (L2_VERSION)g_cfg.L2_version, this->state, ptype, ptype2, ptype3 );
switch( this->state )
{
case GCST_CONNECTED:
{
switch( ptype )
{
//case 0x00: // Interlude: KeyPacket, FirstKey
case 0x2e: // Hellbound: KeyPacket, FirstKey
{
L2Game_KeyPacket *p = new L2Game_KeyPacket( bytes, len );
p->read_key( this->key_client_cs );
p->read_GameServerID();
this->opcodeObfuscator = p->read_OpcodeObfuscator();
L2Game_KeyPacket::createInitialHellboundKey( this->key_client_cs,
this->key_client_cs );
delete p;
memcpy( this->key_client_sc, this->key_client_cs,
sizeof(this->key_client_cs) );
this->xor_enabled = true;
log_error( LOG_PACKETNAME, "Server: 2e KeyPacket\n" );
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_T22();
// TODO: Obfuscator set L2 Version
lpco->setVersionMode( (L2_VERSION)g_cfg.L2_version );
lpco->init_tables( this->opcodeObfuscator );
this->clsObfuscator = (void *)lpco;
}
} 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;
log_error( LOG_DEBUG, "Server: 09 CharacterSelectionInfo: switch state to AUTHED\n" );
} break; // CharacterSelectionInfo
default:
{
log_error( LOG_PACKETNAME, "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
{
// TODO: CharSelected parse, get clan ID
wchar_t char_name[128] = {0};
wcscpy( char_name, (const wchar_t *)(bytes+3) );
log_error( LOG_PACKETNAME, "Server: 0b CharSelected: \"%S\"\n", char_name );
this->state = GCST_IN_GAME;
log_error( LOG_DEBUG, "Server: 0b CharSelected: switch state from AUTHED to IN_GAME\n" );
this->opcodeObfuscator = 0;
this->opcodeObfuscator = bytes[len-4] | (bytes[len-3] << 8) | (bytes[len-2] << 16) | (bytes[len-1] << 24);
if( this->opcodeObfuscator != 0x00000000 )
{
log_error( LOG_DEBUG, "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_T22();
// TODO: Obfuscator set L2 Version
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" );
this->state = GCST_IN_GAME;
log_error( LOG_PACKETNAME, "Server: 73 SSQInfo, switch state to IN_GAME\n" );
} break; // SSQInfo
default:
{
log_error( LOG_DEBUGDUMP, "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" );
// } break; // Die
//case 0x05: // SpawnItem
// {
// TODO: SpawnItem parse
/* protected final void writeImpl()
{
writeC(0x05);
writeD(_objectId);
writeD(_itemId);
writeD(_x);
writeD(_y);
writeD(_z);
// only show item count if it is a stackable item
writeD(_stackable);
writeD(_count);
writeD(0x00); //c2
}*/
// log_error( LOG_PACKETNAME, "Server: 05 SpawnItem\n" );
// } break; // SpawnItem
case 0x08: // DeleteObject
{
// TODO: parse DeleteObject
// [3,4,5,6] - objectId
//unsigned int oid = bytes[3] | (bytes[4] << 8) | (bytes[5] << 16) | (bytes[6] << 24);
//log_error( LOG_PACKETNAME, "Server: 08 DeleteObject %u\n", oid );
//CharArray_DeleteCharByObjectID( oid );
ai.notifyEventPacket( UAI_PEVENT_DELETEOBJECT, bytes, len );
} break; // DeleteObject
case 0x0b: // CharSelected
{
// TODO: CharSelected parse, get clan ID
wchar_t char_name[128] = {0};
wcscpy( char_name, (const wchar_t *)(bytes+3) );
log_error( LOG_PACKETNAME, "Server: 0b CharSelected: \"%S\"\n", char_name );
this->state = GCST_IN_GAME;
log_error( LOG_DEBUG, "Server: 0b CharSelected: switch state from IN_GAME to IN_GAME\n" );
this->opcodeObfuscator = bytes[len-4] | (bytes[len-3] << 8) | (bytes[len-2] << 16) | (bytes[len-1] << 24);
if( this->opcodeObfuscator != 0x00000000 )
{
log_error( LOG_DEBUG, "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_T22();
// TODO: Obfuscator set L2 Version
lpco->setVersionMode( (L2_VERSION)g_cfg.L2_version );
lpco->init_tables( this->opcodeObfuscator );
this->clsObfuscator = (void *)lpco;
}
} break;
case 0x0c: // NpcInfo (mob)?
{
/*unsigned int idTemplate = 0;
unsigned char *p = (unsigned char *)&idTemplate;
// bytes[2] is ptype(0x0c); objectID[3,4,5,6]; idTemplate[7,8,9,10]....
p[0] = bytes[7];
p[1] = bytes[8];
p[2] = bytes[9];
p[3] = bytes[10];
idTemplate -= 1000000; // ? :) L2J adds 1000000 to this field
// c,18d,4f,3d,5c,name,title!
int name_offset = 3 + 18*sizeof(int) + 4*sizeof(double) + 3*sizeof(int) + 5;
wchar_t name[128];
memset( name, 0, sizeof(name) );
wcsncpy( name, (const wchar_t *)(bytes+name_offset), 127 );
name[127] = 0;
log_error( LOG_PACKETNAME, "Server: 0c NpcInfo (mob/morphed char?): id_%u, [%S]\n",
idTemplate, name );*/
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 );
} break; // ItemList
case 0x18: // StatusUpdate
{
//log_error( LOG_PACKETNAME, "Server: 18 StatusUpdate\n" );
ai.notifyEventPacket( UAI_PEVENT_STATUSUPDATE, bytes, len );
} break; // StatusUpdate
//case 0x19: // NpcHtmlMessage
// {
// log_error( LOG_PACKETNAME, "Server: 19 NpcHtmlMessage\n" );
// } break; // NpcHtmlMessage
//case 0x1F: // ActionFailed
// {
// log_error( LOG_PACKETNAME, "Server: 1F ActionFailed\n" );
// } break; // ActionFailed
case 0x21: // InventoryUpdate
{
//log_error( LOG_PACKETNAME, "Server: 21 InventoryUpdate\n" );
ai.notifyEventPacket( UAI_PEVENT_INVENTORYUPDATE, bytes, len );
} break; // InventoryUpdate
case 0x23: // TargetSelected
{
// TODO: TargetSelected
/* writeC(0x23);
writeD(_objectId);
writeD(_targetObjId);
writeD(_x);
writeD(_y);
writeD(_z);
writeD(0x00); */
// bytes[0], bytes[1] - packet size; bytes[3] - pcode
unsigned int objectID = bytes[3] | (bytes[4] << 8) | (bytes[5] << 16) | (bytes[6] <<24);
unsigned int targetObjID = bytes[7] | (bytes[8] << 8) | (bytes[9] << 16) | (bytes[10] <<24);
log_error( LOG_PACKETNAME, "Server: 23 TargetSelected [%u] -> [%u]\n",
objectID, targetObjID );
ai.notifyEventPacket( UAI_PEVENT_TARGETSELECTED, bytes, len );
} break; // TargetSelected
case 0x24: // TargetUnselected
{
//log_error( LOG_PACKETNAME, "Server: 24 TargetUnselected\n" );
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
// {
// log_error( LOG_PACKETNAME, "Server: 28 ChangeMoveType\n" );
// } break; // ChangeMoveType
case 0x2f: // MoveToLocation
{
//
L2GamePacket *p = new L2GamePacket( bytes, len );
unsigned int oid = p->readUInt();
delete p;
int itsme = (int)( oid == ai.usr.objectID );
//
log_error( LOG_PACKETNAME, "Server: 2f MoveToLocation [%u] (my oid %u; its me: %d)\n",
oid, ai.usr.objectID, itsme );
ai.notifyEventPacket( UAI_PEVENT_MOVETOLOCATION, bytes, len );
} break; // MoveToLocation
case 0x31: // CharInfo
{
//log_error( LOG_PACKETNAME, "Server: 31 CharInfo\n" );
//CharList_Add( name, title, oid, x,y,z, heading, race, sex, baseClass, clanID );
ai.notifyEventPacket( UAI_PEVENT_CHARINFO, bytes, len );
} break; // NpcInfo
case 0x32: // UserInfo
{
//
ai.notifyEventPacket( UAI_PEVENT_USERINFO, bytes, len );
} break; // UserInfo
//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
// {
// log_error( LOG_PACKETNAME, "Server: 47 StopMove\n" );
// } break; // StopMove
//case 0x48: // MagicSkillUse
// {
// log_error( LOG_PACKETNAME, "Server: 48 MagicSkillUse\n" );
// } break; // MagicSkillUse
//case 0x4A: // CreatureSay
// {
// log_error( LOG_PACKETNAME, "Server: 4A CreatureSay\n" );
// // TODO: CreatureSay parse
// } break; // CreatureSay
//case 0x54: // MagicSkillLaunched
// {
// log_error( LOG_PACKETNAME, "Server: 54 MagicSkillLaunched\n" );
// } 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
// {
// log_error( LOG_PACKETNAME, "Server: 5F SkillList\n" );
// } break; // SkillList
//case 0x62: // SystemMessage
// {
// log_error( LOG_PACKETNAME, "Server: 62 SystemMessage\n" );
// } break; // SystemMessage
//case 0x6b: // SetupGauge
// {
// log_error( LOG_PACKETNAME, "Server: 6B SetupGauge\n" );
// } break; // SetupGauge
//case 0x72: // MoveToPawn
// {
// log_error( LOG_PACKETNAME, "Server: 72 MoveToPawn\n" );
// } break; // MoveToPawn
case 0x71: // RestartResponse (RestartOK)
{
// 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 );
} break; // RestartResponse
//case 0x74: // GameGuardQuery
// {
// log_error( LOG_PACKETNAME, "Server: 74 GameGuardQuery\n" );
// } break; // GameGuardQuery
//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" );
ai.userLogout();
} break; // LeaveWorld
//case 0x85: // AbnormalStatusUpdate
// {
// log_error( LOG_PACKETNAME, "Server: 85 AbnormalStatusUpdate\n" );
// } break; // AbnormalStatusUpdate
//case 0x86: // QuestList
// {
// log_error( LOG_PACKETNAME, "Server: 86 QuestList\n" );
// } break; // QuestList
case 0x89: // PledgeInfo
{
// TODO: parse 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) );
offset += wcslen( clan_name ) * 2 + 2; // now we can read ally_name from offset
wcscpy( 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 );
} break; // PledgeInfo
//case 0x9F: // StaticObject
// {
// log_error( LOG_PACKETNAME, "Server: 9F StaticObject\n" );
// } break; // StaticObject
//case 0xB9: // MyTargetSelected
// {
// unsigned int objectID = bytes[3] | (bytes[4] << 8) | (bytes[5] << 16) | (bytes[6] <<24);
// log_error( LOG_PACKETNAME, "Server: B9 MyTargetSelected [%u]\n", objectID );
// } break; // MyTargetSelected
//case 0xC7: // SkillCoolTime
// {
// log_error( LOG_PACKETNAME, "Server: C7 SkillCoolTime\n" );
// } 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 );
} 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 0xF9: // EtcStatusUpdate
// {
// log_error( LOG_PACKETNAME, "Server: F9 EtcStatusUpdate\n" );
// } break; // EtcStatusUpdate
//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 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 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
// {
// // TODO: PledgeReceiveWarList parse
// log_error( LOG_PACKETNAME, "Server: FE:3F PledgeReceiveWarList\n" );
// } 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;
// default: log_error( LOG_WARNING, "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_error( LOG_PACKETNAME, "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 )
}

383
l2detect/GameListener.cpp Normal file
View File

@@ -0,0 +1,383 @@
#include "stdafx.h"
#include "GameListener.h"
#include "ConfigIni.h"
#include "Logger.h"
#include "GameClient.h"
#include "LoginListener.h"
extern class CConfig g_cfg; // in main.cpp
extern class LoginListener *g_plogin; // in main.cpp
extern class GameClient *g_game_client; // in main.cpp
struct FLGT_INFO
{
class GameListener *cls;
};
void FGS_Thread_freeInfo( struct FLGT_INFO *pinfo )
{
if( pinfo->cls->m_listen_socket != INVALID_SOCKET )
{
L2PNet_shutdown( pinfo->cls->m_listen_socket );
L2PNet_closesocket( pinfo->cls->m_listen_socket );
pinfo->cls->m_listen_socket = INVALID_SOCKET;
}
if( pinfo->cls->m_hThread ) CloseHandle( pinfo->cls->m_hThread );
pinfo->cls->m_hThread = NULL;
pinfo->cls->m_signal = 0;
free( pinfo );
log_error( LOG_DEBUG, "FGS_Thread(): thread info struct freed\n" );
}
DWORD WINAPI FGS_Thread( LPVOID lpParam )
{
struct FLGT_INFO *pinfo = (struct FLGT_INFO *)lpParam;
lpParam = NULL;
if( !pinfo )
{
log_error( LOG_ERROR, "FGS_Thread(): lpParam is NULL! Exit\n" );
return 0;
}
class GameListener *cls = pinfo->cls;
if( !cls )
{
log_error( LOG_ERROR, "FGS_Thread(): pinfo->cls is NULL! Exit\n" );
FGS_Thread_freeInfo( pinfo );
return 0;
}
cls->m_signal = 0;
cls->m_listen_socket = INVALID_SOCKET;
SOCKET s = L2PNet_TCPsocket_create( true );
if( s == INVALID_SOCKET )
{
log_error( LOG_ERROR, "FGS_Thread(): socket create failed!\n" );
FGS_Thread_freeInfo( pinfo );
return 0;
}
int sbind_tries = 32;
bool bind_OK = false;
int FakeListenGamePort_prev = g_cfg.FakeListenGamePort;
while( sbind_tries > 0 )
{
if( L2PNet_bind( s, g_cfg.FakeListenGameIP, (unsigned short)g_cfg.FakeListenGamePort ) )
{
g_cfg.FakeListenGamePort++;
sbind_tries--;
continue;
}
else
{
bind_OK = true;
break;
}
}
if( !bind_OK )
{
log_error( LOG_ERROR, "FGS_Thread(): ERROR: all 32 attempts of socket binds failed\n" );
FGS_Thread_freeInfo( pinfo );
return 0;
}
log_error( LOG_DEBUG, "FGS_Thread(): successfully bound GameListener to %s:%d\n",
g_cfg.FakeListenGameIP, g_cfg.FakeListenGamePort );
if( L2PNet_listen( s ) )
{
log_error( LOG_ERROR, "FGS_Thread(): listen() failed\n" );
FGS_Thread_freeInfo( pinfo );
return 0;
}
cls->m_listen_socket = s;
log_error( LOG_DEBUG, "FGS_Thread(): started, listening at %s:%d\n",
g_cfg.FakeListenGameIP, g_cfg.FakeListenGamePort );
// raise thread priority if enabled
if( g_cfg.ThreadProirityRaiseEnable )
{
log_error( LOG_DEBUG, "FGS_Thread(): raising thread priority\n" );
if( !SetThreadPriority( GetCurrentThread(), THREAD_PRIORITY_HIGHEST ) )
log_error( LOG_WARNING, "FGS_Thread(): raise thread priority failed!\n" );
}
ErrorLogger_FlushLogFile();
bool processClient_result = false;
int r = 0;
char clientIP[32] = {0};
unsigned short int clientPort = 0;
SOCKET scl = INVALID_SOCKET;
int should_exit = 0;
unsigned int scode = 0; // signal to thread
while( 1 )
{
r = L2PNet_select( s, L2PNET_SELECT_READ, 50, NULL, NULL );
should_exit = 0;
scode = cls->getLastSignal();
if( scode == FLGS_STOP )
{
log_error( LOG_DEBUG, "FGS_Thread(): exit signal\n" );
should_exit = 1;
break;
}
if( should_exit == 1 ) break;
if( r == -1 )
{
log_error( LOG_ERROR, "FGS_Thread(): socket select() error\n" );
break;
}
if( r == 1 )
{
//log_error( LOG_DEBUG, "FGS_Thread: Somebody connected? :)\n" );
clientIP[0] = 0;
clientPort = 0;
scl = INVALID_SOCKET;
scl = L2PNet_accept( s, clientIP, &clientPort );
if( scl == INVALID_SOCKET )
{
log_error( LOG_ERROR, "FGS_Thread(): ERROR: accept failed...\n" );
}
else // Game client connected
{
log_error( LOG_DEBUG, "FGS_Thread(): accepted client %s:%d\n",
clientIP, clientPort );
PlayServerInfo sinfo;
memset( &sinfo, 0, sizeof(PlayServerInfo) );
cls->getPlayServerInfo( &sinfo );
should_exit = 0;
while( (sinfo.ip[0] == 0) || (sinfo.port == 0 ) )
{
log_error( LOG_DEBUG, "FGS_Thread(): PlayServerInfo is meaningless, "
"waiting for setting correct values...\n" );
sinfo.ip[0] = 0; sinfo.port = 0;
Sleep( 300 ); // wait 300 msec while threads switch :)
cls->getPlayServerInfo( &sinfo );
// enable stopping game server listener from this loop
should_exit = 0;
scode = cls->getLastSignal();
if( scode == FLGS_STOP )
{
log_error( LOG_DEBUG, "FGS_Thread: exit signal\n" );
should_exit = 1;
break; // break from first loop
}
}
if( should_exit ) break; // break from next (upper) loop
// wait for LoginListener is stopped in outgame mode
if( (g_cfg.isInGameMode == false) && g_plogin )
{
#ifdef _DEBUG
DWORD tc = GetTickCount();
log_error( LOG_DEBUG, "GameListener: waiting for LoginListener to stop in OOG mode...\n" );
#endif
g_plogin->waitStopped( 1000 );
#ifdef _DEBUG
DWORD tc_passed = GetTickCount() - tc;
log_error( LOG_DEBUG, "GameListener: wait for LoginListener to stop in OOG mode ended in %u msec\n",
tc_passed );
#endif
}
// initialize gameClient UserAI
g_game_client->ai.init();
/* only sniffer mode? */
if( g_cfg.EnableModifyGameTraffic == 0 )
{
//log_error( LOG_DEBUG, "FGS_Thread(): start ProcessClient, sniffing only\n" );
log_error( LOG_OK, "GameListener: start processing client, sniffing only\n" );
processClient_result = g_game_client->PC_sniff( scl, sinfo.ip, sinfo.port );
}
else
{
log_error( LOG_DEBUG, "FGS_Thread(): start ProcessClient, full processing mode\n" );
processClient_result = g_game_client->PC_full( scl, sinfo.ip, sinfo.port );
} // if( g_cfg.EnableModifyGameTraffic == 0 )
// TODO: better error handling
if( !processClient_result )
{
log_error( LOG_ERROR, "GameListener: FGS_Thread(): ProcessClient_xxxx() returned false, network error?\n" );
ErrorLogger_FlushLogFile();
}
if( cls->getLastSignal() == FLGS_STOP ) break;
// run login listener again in outgame mode
//if( processClient_result && (g_cfg.isInGameMode == false) )
if( g_cfg.isInGameMode == false )
{
if( g_plogin )
{
if( !g_game_client->wasJustServerPing() )
{
log_error( LOG_DEBUG, "GameListener: starting LoginListener again in outgame mode\n" );
if( !g_plogin->start() )
log_error( LOG_ERROR, "GameListener: failed starting LoginListener again in outgame mode!\n" );
}
else
{
if( g_plogin->isRunning() )
{
log_error( LOG_WARNING, "GameListener: GameClient ended, "
"but it was just server ping - no start LoginListener!\n" );
}
else
{
log_error( LOG_WARNING, "GameListener: GameClient ended after client->server ping, "
"but LoginListener is not running...? O_o\n" );
}
}
}
}
} // accept() OK
} // somebody connected?
} // while(1)
// restore prev. listen game port that was set in config after client processing ended
g_cfg.FakeListenGamePort = FakeListenGamePort_prev;
FGS_Thread_freeInfo( pinfo );
log_error( LOG_DEBUG, "FGS_Thread() ended\n" );
return 0;
}
/// class
GameListener::GameListener()
{
this->_initNull();
}
GameListener::~GameListener()
{
if( this->m_hThread ) CloseHandle( this->m_hThread );
this->_initNull();
}
bool GameListener::start()
{
// cleanup ?
if( this->m_hThread ) CloseHandle( this->m_hThread );
this->_initNull();
// alloc thread info struct
struct FLGT_INFO *pinfo = (struct FLGT_INFO *)malloc( sizeof( struct FLGT_INFO ) );
if( !pinfo ) return false;
// fill info
pinfo->cls = this;
// create thread object
this->m_hThread = NULL;
DWORD dwTID = 0;
this->m_hThread = (HANDLE)_beginthreadex(
NULL, // security
0, // stack size
(unsigned int (__stdcall*)(void *))FGS_Thread, // thread function
(void *)pinfo, // thread function argument - lpParam
0, // flags
(unsigned int *)(&dwTID) );
if( !this->m_hThread )
{
free( pinfo );
return false;
}
return true;
}
bool GameListener::waitStopped( unsigned int timeoutMsec )
{
if( !this->m_hThread ) return true;
DWORD wait_res = WaitForSingleObject( this->m_hThread, (DWORD)timeoutMsec );
if( wait_res != WAIT_OBJECT_0 )
{
log_error( LOG_DEBUG, "GameListener::waitStopped(): WaitForSingleObject() returned 0x%08X\n", wait_res );
if( wait_res == WAIT_TIMEOUT ) log_error( LOG_DEBUG, "GameListener::waitStopped(): WAIT_TIMEOUT\n" );
return false;
}
// wait OK, close kernel objects
if( this->m_hThread ) CloseHandle( this->m_hThread );
// initialize self
this->_initNull();
return true;
}
void GameListener::terminateThread()
{
if( this->m_hThread )
{
TerminateThread( this->m_hThread, 0xBAADF00D );
CloseHandle( this->m_hThread );
this->m_hThread = NULL;
this->m_signal = 0;
// thread resources
if( m_listen_socket != INVALID_SOCKET )
{
//sock_tcp_close_shutdown( m_listen_socket, SD_BOTH );
L2PNet_shutdown( m_listen_socket );
L2PNet_closesocket( m_listen_socket );
}
m_listen_socket = INVALID_SOCKET;
}
}
bool GameListener::isRunning() const
{
if( this->m_hThread != NULL ) return true;
return false;
}
void GameListener::_initNull()
{
m_hThread = NULL;
m_signal = 0;
m_sinfo.ip[0] = m_sinfo.ip[1] = m_sinfo.ip[2] = m_sinfo.ip[3] = 0;
m_sinfo.port = 0;
// thread resources
m_listen_socket = INVALID_SOCKET;
}
void GameListener::setPlayServerInfo( struct PlayServerInfo *pinfo )
{
if( !pinfo ) return;
// copy struct :)
memcpy( &(this->m_sinfo), pinfo, sizeof(struct PlayServerInfo) );
// enable forcing game server IP:port Select
if( g_cfg.ForceGameServerIP[0] && g_cfg.ForceGameServerPort )
{
in_addr force_addr;
force_addr.s_addr = L2PNet_inet_addr( g_cfg.ForceGameServerIP );
if( force_addr.s_addr == INADDR_NONE )
{
// try to resolve
L2PNet_resolveHostname( g_cfg.ForceGameServerIP, &force_addr );
}
m_sinfo.ip[0] = force_addr.S_un.S_un_b.s_b1;
m_sinfo.ip[1] = force_addr.S_un.S_un_b.s_b2;
m_sinfo.ip[2] = force_addr.S_un.S_un_b.s_b3;
m_sinfo.ip[3] = force_addr.S_un.S_un_b.s_b4;
m_sinfo.port = g_cfg.ForceGameServerPort & 0x0000FFFF;
log_error( LOG_WARNING, "GameListener: FORCED game server IP:port to %d.%d.%d.%d:%d\n",
(int)m_sinfo.ip[0], (int)m_sinfo.ip[1], (int)m_sinfo.ip[2], (int)m_sinfo.ip[3],
(int)m_sinfo.port );
}
//
log_error( LOG_DEBUG, "GameListener: set play server address: %d.%d.%d.%d:%d\n",
(int)m_sinfo.ip[0], (int)m_sinfo.ip[1], (int)m_sinfo.ip[2], (int)m_sinfo.ip[3],
(int)m_sinfo.port );
}
void GameListener::getPlayServerInfo( struct PlayServerInfo *pinfo ) const
{
if( !pinfo ) return;
memcpy( pinfo, &(this->m_sinfo), sizeof(struct PlayServerInfo) );
}

43
l2detect/GameListener.h Normal file
View File

@@ -0,0 +1,43 @@
#ifndef FAKEGAMELISTENER_H_
#define FAKEGAMELISTENER_H_
struct PlayServerInfo
{
unsigned char ip[4];
unsigned short int port;
};
// signals to thread
#define FLGS_STOP 1
class GameListener
{
friend void FGS_Thread_freeInfo( struct FLGT_INFO *pinfo );
friend DWORD WINAPI FGS_Thread( LPVOID lpParam );
public:
GameListener();
virtual ~GameListener();
public:
bool start();
void signal( unsigned int code ) { this->m_signal = code; }
void signalStop() { this->signal( FLGS_STOP ); }
bool waitStopped( unsigned int timeoutMsec );
unsigned int getLastSignal() const { return this->m_signal; }
void setLastSignal( unsigned int code ) { this->m_signal = code; }
void terminateThread();
public:
bool isRunning() const;
public:
void setPlayServerInfo( struct PlayServerInfo *pinfo );
void getPlayServerInfo( struct PlayServerInfo *pinfo ) const;
protected:
void _initNull();
protected:
HANDLE m_hThread;
unsigned int m_signal;
struct PlayServerInfo m_sinfo;
// thread resources
SOCKET m_listen_socket;
};
#endif /*FAKEGAMELISTENER_H_*/

10
l2detect/GroundItem.cpp Normal file
View File

@@ -0,0 +1,10 @@
#include "stdafx.h"
#include "GroundItem.h"
void GroundItem::setUnused()
{
L2Object::setUnused();
itemID = 0;
stackable = 0;
count = 0;
}

17
l2detect/GroundItem.h Normal file
View File

@@ -0,0 +1,17 @@
#ifndef H_GROUNDITEM
#define H_GROUNDITEM
class GroundItem: public L2Object
{
public:
GroundItem() { setUnused(); }
~GroundItem() { setUnused(); }
public:
virtual void setUnused();
public:
unsigned int itemID;
int stackable;
unsigned long long int count;
};
#endif

274
l2detect/HWID.cpp Normal file
View File

@@ -0,0 +1,274 @@
#include "stdafx.h"
#include "Logger.h"
#include "HWID.h"
#include "base64.h"
#include "L2Detect_auth.h"
const int max_pbsi = 3;
struct partial_boot_sector_info
{
LPSTR Fs; // file system name
DWORD FsOffs; // offset of file system name in the boot sector
DWORD SerialOffs; // offset of the serialnumber in the boot sector
};
void read_MBR( unsigned char *outbuffer )
{
//HANDLE hFile = CreateFileW( L"\\\\.\\PhysicalDrive0",
HANDLE hFile = CreateFileW( L"\\\\.\\c:",
GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL,
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL );
if( hFile == INVALID_HANDLE_VALUE )
{
DWORD le = GetLastError();
log_error( LOG_ERROR, "read_MBR(): CreateFile failed, errCode = %u\n", (unsigned)le );
return;
}
DWORD dwRead = 0;
if( ReadFile( hFile, outbuffer, 512, &dwRead, NULL ) == 0 )
{
DWORD le = GetLastError();
log_error( LOG_ERROR, "read_MBR(): ReadFile failed, errCode = %u\n", (unsigned)le );
}
CloseHandle( hFile );
log_error( LOG_DEBUG, "read_MBR(): ReadFile read %u bytes\n", (unsigned)dwRead );
}
void getHDDInfo( char *volumeSN, char *hwSN, char *fsName )
{
char szVolumeName[256] = {0};
char szFSName[256] = {0};
unsigned long dwVolumeSN = 0, dwMaxComponentLen = 0, dwFSFlags = 0;
if( !GetVolumeInformationA( "C:\\", szVolumeName, 256, &dwVolumeSN,
&dwMaxComponentLen, &dwFSFlags, szFSName, 256 ) ) return;
unsigned char MBR[512];
memset( MBR, 0, sizeof(MBR) );
read_MBR( MBR );
partial_boot_sector_info pbsi[max_pbsi] =
{
{"FAT32", 0x52, 0x43},
{"FAT", 0x36, 0x27},
{"NTFS", 0x03, 0x48}
};
// try to search for a valid boot sector
int i = 0;
for( i=0; i<max_pbsi; i++)
{
if( strncmp( pbsi[i].Fs, (const char *)(MBR + pbsi[i].FsOffs), strlen( pbsi[i].Fs ) ) == 0 )
{
// we found a valid signature
break;
}
}
if( i >= max_pbsi )
{
log_error( LOG_ERROR, "getHDDInfo(): Cannot get serial number of this file system!\n" );
return;
}
DWORD dwHWSN = 0;
memcpy( (void *)(&dwHWSN), (const void *)(MBR + pbsi[i].SerialOffs), sizeof(dwHWSN) );
// out data
sprintf( volumeSN, "%08X", dwVolumeSN );
sprintf( hwSN, "%08X", dwHWSN );
strcpy( fsName, szFSName );
}
void getBIOSInfo( char *out_ver )
{
out_ver[0] = 0;
HKEY hKey = NULL;
char systemBIOSdate[256];
char systemBIOSversion[1024];
//char out_ver[1024] = {0};
memset( systemBIOSdate, 0, sizeof(systemBIOSdate) );
memset( systemBIOSversion, 0, sizeof(systemBIOSversion) );
LONG result = 0;
// support Wow64
if( (result = RegOpenKeyExA( HKEY_LOCAL_MACHINE, "HARDWARE\\DESCRIPTION\\System", 0, KEY_READ | KEY_WOW64_64KEY, &hKey )) == 0 )
{
DWORD dwType = REG_SZ;
DWORD dwCbData = sizeof(systemBIOSdate);
// bios date
if( (result = RegQueryValueExA( hKey, "SystemBiosDate", NULL, &dwType, (LPBYTE)systemBIOSdate, &dwCbData )) == 0 )
{
strcat( out_ver, systemBIOSdate );
strcat( out_ver, "; " );
}
else
{
ErrorLogger_LogLastError( "getBIOSInfo(): RegQueryValueExA()", (DWORD)result );
// Windows x64 or 2003 versions? other reg keys:
// HKEY_LOCAL_MACHINE\\HARDWARE\\DESCRIPTION\\System\\BIOS\\BIOSReleaseDate
// HKEY_LOCAL_MACHINE\\HARDWARE\\DESCRIPTION\\System\\BIOS\\BIOSVersion
HKEY hKey2 = NULL;
result = RegOpenKeyExA( HKEY_LOCAL_MACHINE, "HARDWARE\\DESCRIPTION\\System\\BIOS", 0, KEY_READ | KEY_WOW64_64KEY, &hKey2 );
if( result == 0 )
{
dwType = REG_SZ;
dwCbData = sizeof(systemBIOSdate);
result = RegQueryValueExA( hKey2, "BIOSReleaseDate", NULL, &dwType, (LPBYTE)systemBIOSdate, &dwCbData );
if( result == 0 )
{
strcat( out_ver, systemBIOSdate );
strcat( out_ver, "; " );
}
else
ErrorLogger_LogLastError( "getBIOSInfo(): RegQueryValueExA() (win64)", (DWORD)result );
RegCloseKey( hKey2 );
}
else
ErrorLogger_LogLastError( "getBIOSInfo(): RegOpenKeyExA() (win64)", (DWORD)result );
}
//
// bios version
dwType = REG_MULTI_SZ;
dwCbData = sizeof(systemBIOSversion);
if( (result = RegQueryValueExA( hKey, "SystemBiosVersion", NULL, &dwType, (LPBYTE)systemBIOSversion, &dwCbData )) == 0 )
{
strcat( out_ver, systemBIOSversion );
char *pstr = systemBIOSversion + strlen(systemBIOSversion) + 1;
if( *pstr )
{
strcat( out_ver, "; " );
strcat( out_ver, pstr );
}
}
else
{
ErrorLogger_LogLastError( "getBIOSInfo(): RegQueryValueExA()", (DWORD)result );
// Windows x64 or 2003 versions? other reg keys
// HKEY_LOCAL_MACHINE\\HARDWARE\\DESCRIPTION\\System\\BIOS\\BIOSReleaseDate
// HKEY_LOCAL_MACHINE\\HARDWARE\\DESCRIPTION\\System\\BIOS\\BIOSVersion
HKEY hKey2 = NULL;
result = RegOpenKeyExA( HKEY_LOCAL_MACHINE, "HARDWARE\\DESCRIPTION\\System\\BIOS", 0, KEY_READ | KEY_WOW64_64KEY, &hKey2 );
if( result == 0 )
{
dwType = REG_SZ; // not REG_MULTI_SZ
dwCbData = sizeof(systemBIOSversion);
result = RegQueryValueExA( hKey2, "BIOSVersion", NULL, &dwType, (LPBYTE)systemBIOSversion, &dwCbData );
if( result == 0 )
strcat( out_ver, systemBIOSversion );
else
ErrorLogger_LogLastError( "getBIOSInfo(): RegQueryValueExA() (win64)", (DWORD)result );
RegCloseKey( hKey2 );
}
else
ErrorLogger_LogLastError( "getBIOSInfo(): RegOpenKeyExA() (win64)", (DWORD)result );
}
RegCloseKey( hKey );
}
else
ErrorLogger_LogLastError( "getBIOSInfo(): RegOpenKeyExA", (DWORD)result );
}
void getOSInfo( char *os_info )
{
OSVERSIONINFOEXA os;
memset( &os, 0, sizeof(os) );
os.dwOSVersionInfoSize = sizeof(os);
if( GetVersionExA( (OSVERSIONINFOA *)&os ) )
{
sprintf( os_info, "%d.%d.%d sp %d.%d",
os.dwMajorVersion, os.dwMinorVersion, os.dwBuildNumber,
(int)os.wServicePackMajor, (int)os.wServicePackMinor );
}
else log_error( LOG_ERROR, "getOSInfo(): GetVersionExA(): error!\n" );
}
void getCPUInfo( char *cpu )
{
cpu[0] = 0;
HKEY hKey = NULL;
char str[512] = {0};
if( RegOpenKeyExA( HKEY_LOCAL_MACHINE, "HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0", 0, KEY_READ, &hKey ) == 0 )
{
DWORD dwType = REG_SZ;
DWORD dwCbData = sizeof(str);
// vendor id
if( RegQueryValueExA( hKey, "VendorIdentifier", NULL, &dwType, (LPBYTE)str, &dwCbData ) == 0 )
{
strcat( cpu, str );
strcat( cpu, " " );
} else log_error( LOG_ERROR, "getCPUInfo(): RegQueryValueExA(): error!\n" );
// name
dwType = REG_SZ;
dwCbData = sizeof(str);
if( RegQueryValueExA( hKey, "ProcessorNameString", NULL, &dwType, (LPBYTE)str, &dwCbData ) == 0 )
{
strcat( cpu, str );
} else log_error( LOG_ERROR, "getCPUInfo(): RegQueryValueExA(): error!\n" );
// id
dwType = REG_SZ;
dwCbData = sizeof(str);
if( RegQueryValueExA( hKey, "Identifier", NULL, &dwType, (LPBYTE)str, &dwCbData ) == 0 )
{
strcat( cpu, str );
} else log_error( LOG_ERROR, "getCPUInfo(): RegQueryValueExA(): error!\n" );
RegCloseKey( hKey );
}
else log_error( LOG_ERROR, "getCPUInfo(): RegOpenKeyExA(): error!\n" );
}
void convert_to_urlsafe( char *s )
{
/*
* use '-' and '_' instead of '+' and '/'
* no line feeds
* padding character is '*' instead of '='
*/
while( (*s) )
{
if( (*s) == '+' ) (*s) = '-';
if( (*s) == '/' ) (*s) = '_';
if( (*s) == '=' ) (*s) = '*';
s++;
}
}
int getLocalHWID( char *out )
{
char globalIDString[4096] = {0};
char based[4096] = {0};
char volumeSN[256] = {0}, hwSN[256] = {0}, fsName[256] = {0};
char biosInfo[1024] = {0};
char os_info[1024] = {0};
char cpu_info[1024] = {0};
getHDDInfo( volumeSN, hwSN, fsName );
getBIOSInfo( biosInfo );
getOSInfo( os_info );
getCPUInfo( cpu_info );
sprintf( globalIDString, "%s|%s|%s|%s|%s|%s", volumeSN, hwSN, fsName, biosInfo, os_info, cpu_info );
log_error( LOG_DEBUG, "HWID: [%s]\n", globalIDString );
base64_encode_string( globalIDString, strlen(globalIDString), based );
convert_to_urlsafe( based );
strcpy( out, based );
return 1;
}
bool VerifyHWID()
{
char localHWID[4096];
char setHWID[4096];
memset( localHWID, 0, sizeof(localHWID) );
memset( setHWID, 0, sizeof(setHWID) );
getLocalHWID( localHWID );
//getHWID( setHWID );
//log_error( LOG_DEBUG, "Verify HWID: [%s] == [%s] ?...\n", localHWID, setHWID );
if( strcmp( localHWID, setHWID ) == 0 )
{
log_error( LOG_OK, "HWID verify OK\n" );
return true;
}
log_error( LOG_ERROR, "HWID verify error!\n" );
return false;
}

6
l2detect/HWID.h Normal file
View File

@@ -0,0 +1,6 @@
#ifndef H_HWID
#define H_HWID
bool VerifyHWID();
#endif

496
l2detect/HealItemsTable.cpp Normal file
View File

@@ -0,0 +1,496 @@
#include "stdafx.h"
#include "HealItemsTable.h"
#include "utils.h"
#include "Logger.h"
HealItem::HealItem()
{
itemName[0] = 0;
itemID = reuseDelayMsec = 0;
priority = 0;
lastUseTime = 0;
percentUse = 0;
}
HealItem::HealItem( const HealItem &other )
{
strcpy( itemName, other.itemName );
itemID = other.itemID;
reuseDelayMsec = other.reuseDelayMsec;
priority = other.priority;
lastUseTime = other.lastUseTime;
percentUse = other.percentUse;
}
/*HealItem& HealItem::operator=( const HealItem& other )
{
strcpy( itemName, other.itemName );
itemID = other.itemID;
reuseDelaySecs = other.reuseDelaySecs;
priority = other.priority;
lastUseTime = other.lastUseTime;
return (*this);
}*/
void HealItem::GetItemNameW( wchar_t *out )
{
if( !out ) return;
out[0] = 0;
if( itemName[0] == 0 ) return;
MultiByteToWideChar( CP_ACP, 0, itemName, -1, out, 127 );
}
HealItemsTable::HealItemsTable()
{
clear();
}
HealItemsTable::~HealItemsTable()
{
clear();
}
void HealItemsTable::clear()
{
int i;
for( i=0; i<MAXNUMHEALITEMS; i++ )
{
hp_healers[i].itemID = mp_healers[i].itemID = cp_healers[i].itemID = 0;
}
enableHealHP = true;
enableHealMP = true;
enableHealCP = true;
}
bool HealItemsTable::LoadFromFile( const char *fileName )
{
if( !fileName ) return false;
clear();
int last_added = 0;
FILE *f = fopen( fileName, "rt" );
if( !f ) return false;
char line[512] = {0};
//
char itemName[128] = {0};
unsigned int itemID = 0;
unsigned int reuseDelay = 0;
int priority = 0;
int percentUse = 0;
//
int cur_read = 0;
const int READ_CP = 1;
const int READ_HP = 2;
const int READ_MP = 3;
//
char *token;
char delim[] = "=;\r\n";
//
while( !feof( f ) )
{
if( freadline( f, line, sizeof(line)-1 ) == 0 ) continue;
if( line[0] == '#' ) continue;
if( strcmp( line, "[CP healers]" ) == 0 )
{
cur_read = READ_CP;
last_added = 0;
continue;
}
if( strcmp( line, "[HP healers]" ) == 0 )
{
cur_read = READ_HP;
last_added = 0;
continue;
}
if( strcmp( line, "[MP healers]" ) == 0 )
{
cur_read = READ_MP;
last_added = 0;
continue;
}
if( !strchr( line, '=' ) ) continue;
if( strstr( line, "CPHealEnable" ) == line )
{
token = strtok( line, "=" );
if( token ) token = strtok( NULL, "=" );
if( token ) sscanf( token, "%d", &(this->enableHealCP) );
continue;
}
if( strstr( line, "HPHealEnable" ) == line )
{
token = strtok( line, "=" );
if( token ) token = strtok( NULL, "=" );
if( token ) sscanf( token, "%d", &(this->enableHealHP) );
continue;
}
if( strstr( line, "MPHealEnable" ) == line )
{
token = strtok( line, "=" );
if( token ) token = strtok( NULL, "=" );
if( token ) sscanf( token, "%d", &(this->enableHealMP) );
continue;
}
// token itemName
token = strtok( line, delim );
if( !token ) continue;
strcpy( itemName, token );
// token itemID
token = strtok( NULL, delim );
if( !token ) continue;
sscanf( token, "%u", &itemID );
// token reuseDelay
token = strtok( NULL, delim );
if( !token ) continue;
sscanf( token, "%u", &reuseDelay );
// token priority
token = strtok( NULL, delim );
if( !token ) continue;
sscanf( token, "%d", &priority );
// token percentUse
token = strtok( NULL, delim );
if( !token ) continue;
sscanf( token, "%d", &percentUse );
// log
//switch( cur_read )
//{
//case READ_HP: log_error( LOG_USERAI, "HealItemTable: READ_HP: %s [ID=%u] (%d sec, %d priotiy)\n", itemName, itemID, reuseDelay, priority ); break;
//case READ_MP: log_error( LOG_USERAI, "HealItemTable: READ_MP: %s [ID=%u] (%d sec, %d priotiy)\n", itemName, itemID, reuseDelay, priority ); break;
//case READ_CP: log_error( LOG_USERAI, "HealItemTable: READ_CP: %s [ID=%u] (%d sec, %d priotiy)\n", itemName, itemID, reuseDelay, priority ); break;
//}
//
//add
switch( cur_read )
{
case READ_HP:
{
strcpy( hp_healers[last_added].itemName, itemName );
hp_healers[last_added].itemID = itemID;
hp_healers[last_added].reuseDelayMsec = reuseDelay;
hp_healers[last_added].priority = priority;
hp_healers[last_added].lastUseTime = 0;
hp_healers[last_added].percentUse = percentUse;
last_added++;
} break;
case READ_MP:
{
strcpy( mp_healers[last_added].itemName, itemName );
mp_healers[last_added].itemID = itemID;
mp_healers[last_added].reuseDelayMsec = reuseDelay;
mp_healers[last_added].priority = priority;
mp_healers[last_added].lastUseTime = 0;
mp_healers[last_added].percentUse = percentUse;
last_added++;
} break;
case READ_CP:
{
strcpy( cp_healers[last_added].itemName, itemName );
cp_healers[last_added].itemID = itemID;
cp_healers[last_added].reuseDelayMsec = reuseDelay;
cp_healers[last_added].priority = priority;
cp_healers[last_added].lastUseTime = 0;
cp_healers[last_added].percentUse = percentUse;
last_added++;
} break;
}
}
fclose( f );
sort();
return true;
}
void HealItemsTable::sort()
{
int i, j;
HealItem temp;
// hp healers
for( i=0; i<=(MAXNUMHEALITEMS-2); i++ )
{
for( j=i+1; j<=(MAXNUMHEALITEMS-1); j++ )
{
if( hp_healers[j].priority > hp_healers[i].priority )
{
// save temp
//temp = hp_healers[i];
strcpy( temp.itemName, hp_healers[i].itemName );
temp.itemID = hp_healers[i].itemID;
temp.priority = hp_healers[i].priority;
temp.reuseDelayMsec = hp_healers[i].reuseDelayMsec;
temp.percentUse = hp_healers[i].percentUse;
// copy j -=> i
//hp_healers[i] = hp_healers[j];
strcpy( hp_healers[i].itemName, hp_healers[j].itemName );
hp_healers[i].itemID = hp_healers[j].itemID;
hp_healers[i].priority = hp_healers[j].priority;
hp_healers[i].reuseDelayMsec = hp_healers[j].reuseDelayMsec;
hp_healers[i].percentUse = hp_healers[j].percentUse;
//restore i
//hp_healers[j] = temp;
strcpy( hp_healers[j].itemName, temp.itemName );
hp_healers[j].itemID = temp.itemID;
hp_healers[j].priority = temp.priority;
hp_healers[j].reuseDelayMsec = temp.reuseDelayMsec;
hp_healers[j].percentUse = temp.percentUse;
}
}
}
// mp healers
for( i=0; i<=(MAXNUMHEALITEMS-2); i++ )
{
for( j=i+1; j<=(MAXNUMHEALITEMS-1); j++ )
{
if( mp_healers[j].priority > mp_healers[i].priority )
{
// save temp
temp = mp_healers[i];
// copy j -=> i
mp_healers[i] = mp_healers[j];
//restore i
mp_healers[j] = temp;
}
}
}
// cp healers
for( i=0; i<=(MAXNUMHEALITEMS-2); i++ )
{
for( j=i+1; j<=(MAXNUMHEALITEMS-1); j++ )
{
if( cp_healers[j].priority > cp_healers[i].priority )
{
// save temp
temp = cp_healers[i];
// copy j -=> i
cp_healers[i] = cp_healers[j];
//restore i
cp_healers[j] = temp;
}
}
}
}
bool HealItemsTable::getHPItem( int idx, HealItem& out )
{
if( (idx<0) || (idx>=MAXNUMHEALITEMS) ) return false;
out.itemID = 0;
out.itemName[0] = 0;
if( hp_healers[idx].itemID == 0 ) return false;
//out = hp_healers[idx];
strcpy( out.itemName, hp_healers[idx].itemName );
out.itemID = hp_healers[idx].itemID;
out.lastUseTime = hp_healers[idx].lastUseTime;
out.priority = hp_healers[idx].priority;
out.reuseDelayMsec = hp_healers[idx].reuseDelayMsec;
out.percentUse = hp_healers[idx].percentUse;
return true;
}
bool HealItemsTable::getMPItem( int idx, HealItem& out )
{
if( (idx<0) || (idx>=MAXNUMHEALITEMS) ) return false;
out.itemID = 0;
out.itemName[0] = 0;
if( mp_healers[idx].itemID == 0 ) return false;
out = mp_healers[idx];
return true;
}
bool HealItemsTable::getCPItem( int idx, HealItem& out )
{
if( (idx<0) || (idx>=MAXNUMHEALITEMS) ) return false;
out.itemID = 0;
out.itemName[0] = 0;
if( cp_healers[idx].itemID == 0 ) return false;
out = cp_healers[idx];
return true;
}
// type: 0 - hp; 1 - mp; 2 - cp
bool HealItemsTable::markUsedNow( HEALITEM_TYPE type, int idx, unsigned int tickCount )
{
if( (idx<0) || (idx>=MAXNUMHEALITEMS) ) return false;
switch( type )
{
case HIT_HP:
{
if( hp_healers[idx].itemID == 0 ) return false;
hp_healers[idx].lastUseTime = tickCount;
} break;
case HIT_MP:
{
if( mp_healers[idx].itemID == 0 ) return false;
mp_healers[idx].lastUseTime = tickCount;
} break;
case HIT_CP:
{
if( cp_healers[idx].itemID == 0 ) return false;
cp_healers[idx].lastUseTime = tickCount;
} break;
default: return false; break;
}
return true;
}
bool HealItemsTable::delItemFromTable( HEALITEM_TYPE type, int index )
{
if( (index<0) || (index>=MAXNUMHEALITEMS) ) return false;
int i;
switch( type )
{
case HIT_MARKUSED_HP:
{
hp_healers[index].itemID = 0;
hp_healers[index].priority = 0;
// shift
i=index;
while( i<=(MAXNUMHEALITEMS-2) )
{
hp_healers[i] = hp_healers[i+1];
i++;
}
} break;
case HIT_MARKUSED_MP:
{
mp_healers[index].itemID = 0;
mp_healers[index].priority = 0;
// shift
i=index;
while( i<=(MAXNUMHEALITEMS-2) )
{
mp_healers[i] = mp_healers[i+1];
i++;
}
} break;
case HIT_MARKUSED_CP:
{
cp_healers[index].itemID = 0;
cp_healers[index].priority = 0;
// shift
i=index;
while( i<=(MAXNUMHEALITEMS-2) )
{
cp_healers[i] = cp_healers[i+1];
i++;
}
} break;
default: return false; break;
}
//sort();
return true;
}
bool HealItemsTable::SaveToFile( const char *fileName )
{
if( !fileName ) return false;
FILE *f = fopen( fileName, "wt" );
if( !f ) return false;
// header
fprintf( f,
"# Format:\n"
"# Item Name=ItemID;reuseDelay(milliSeconds);priority;activatePercent\n"
"# No spaces between '=', ';' !\n"
"# priority is number between 1 and 100, determines which item will be used first\n"
"# priority 0 means 'do not use this item' :)\n"
"# ActivatePercent is stat value in percent from maximum, when this item can be used\n"
"\n" );
int i;
// CP healers
fprintf( f,
"[CP healers]\n"
"CPHealEnable=%d\n", this->enableHealCP );
for( i=0; i<MAXNUMHEALITEMS; i++ )
{
if( this->cp_healers[i].itemID == 0 ) continue;
fprintf( f, "%s=%u;%u;%d;%d\n",
this->cp_healers[i].itemName,
this->cp_healers[i].itemID,
this->cp_healers[i].reuseDelayMsec,
this->cp_healers[i].priority,
this->cp_healers[i].percentUse );
}
fprintf( f, "\n" );
// HP healers
fprintf( f,
"[HP healers]\n"
"HPHealEnable=%d\n", this->enableHealHP );
for( i=0; i<MAXNUMHEALITEMS; i++ )
{
if( this->hp_healers[i].itemID == 0 ) continue;
fprintf( f, "%s=%u;%u;%d;%d\n",
this->hp_healers[i].itemName,
this->hp_healers[i].itemID,
this->hp_healers[i].reuseDelayMsec,
this->hp_healers[i].priority,
this->hp_healers[i].percentUse );
}
fprintf( f, "\n" );
// MP healers
fprintf( f,
"[MP healers]\n"
"MPHealEnable=%d\n", this->enableHealMP );
for( i=0; i<MAXNUMHEALITEMS; i++ )
{
if( this->mp_healers[i].itemID == 0 ) continue;
fprintf( f, "%s=%u;%u;%d;%d\n",
this->mp_healers[i].itemName,
this->mp_healers[i].itemID,
this->mp_healers[i].reuseDelayMsec,
this->mp_healers[i].priority,
this->mp_healers[i].percentUse );
}
fprintf( f, "\n" );
fclose( f );
return true;
}
bool HealItemsTable::addHealItem( HEALITEM_TYPE type, const HealItem *example )
{
if( !example ) return false;
int free_idx = -1;
int i;
unsigned int itemID;
for( i=0; i<MAXNUMHEALITEMS; i++ )
{
itemID = 0;
switch( type )
{
case HIT_HP: itemID = hp_healers[i].itemID; break;
case HIT_MP: itemID = mp_healers[i].itemID; break;
case HIT_CP: itemID = cp_healers[i].itemID; break;
}
if( itemID == 0 )
{
free_idx = i;
break;
}
}
if( free_idx == -1 ) return false;
switch( type )
{
case HIT_HP: hp_healers[free_idx] = (*example); break;
case HIT_MP: mp_healers[free_idx] = (*example); break;
case HIT_CP: cp_healers[free_idx] = (*example); break;
}
sort();
return true;
}
bool HealItemsTable::setHealItem( HEALITEM_TYPE type, int idx, const HealItem *example )
{
if( !example ) return false;
if( (idx<0) || (idx>=MAXNUMHEALITEMS) ) return false;
switch( type )
{
case HIT_HP: hp_healers[idx] = (*example); break;
case HIT_MP: mp_healers[idx] = (*example); break;
case HIT_CP: cp_healers[idx] = (*example); break;
default: return false; break;
}
return true;
}

66
l2detect/HealItemsTable.h Normal file
View File

@@ -0,0 +1,66 @@
#ifndef H_HEALITEMS_TABLE
#define H_HEALITEMS_TABLE
class HealItem
{
public:
HealItem();
HealItem( const HealItem &other );
//HealItem& operator=( const HealItem& other );
public:
void GetItemNameW( wchar_t *out );
public:
char itemName[128];
unsigned int itemID;
unsigned int reuseDelayMsec;
int priority;
unsigned int lastUseTime;
int percentUse;
};
#define MAXNUMHEALITEMS 16
// markUsedNow constants
#define HIT_MARKUSED_HP 0
#define HIT_MARKUSED_MP 1
#define HIT_MARKUSED_CP 2
class HealItemsTable
{
public:
typedef enum eHEALITEM_TYPE
{
HIT_HP = 0,
HIT_MP,
HIT_CP
} HEALITEM_TYPE;
public:
HealItemsTable();
~HealItemsTable();
public:
void clear();
bool LoadFromFile( const char *fileName );
bool SaveToFile( const char *fileName );
bool getHPItem( int idx, HealItem& out );
bool getMPItem( int idx, HealItem& out );
bool getCPItem( int idx, HealItem& out );
// type: 0 - hp; 1 - mp; 2 - cp
bool markUsedNow( HEALITEM_TYPE type, int idx, unsigned int tickCount );
bool delItemFromTable( HEALITEM_TYPE type, int index );
bool addHealItem( HEALITEM_TYPE type, const HealItem *example );
bool setHealItem( HEALITEM_TYPE type, int idx, const HealItem *example );
public:
int enableHealHP;
int enableHealMP;
int enableHealCP;
protected:
HealItem hp_healers[MAXNUMHEALITEMS];
HealItem mp_healers[MAXNUMHEALITEMS];
HealItem cp_healers[MAXNUMHEALITEMS];
void sort();
};
#endif

84
l2detect/L2Detect.ini Normal file
View File

@@ -0,0 +1,84 @@
# ===============
# Network setup
# ===============
# =======================
# Listen ports setup
# * Ports on which program will bind listen sockets - local address
FakeListenLoginIP = 127.0.0.1
FakeListenLoginPort = 2106
FakeListenGameIP = 127.0.0.1
FakeListenGamePort = 8777
# ========================
# Forward connection to
# * Where to redirect login connection - IP/hostname & port
RealLoginServerIP = 217.23.91.18
RealLoginServerPort = 2106
# ===========================
# Catch game server traffic
# * Which Game server's IP and port will be replaced in ServerList packet
PlayGameServerNo = 1
# =============
# Logging Setup
# =============
# =====================================
# Warn messages level printed to stdout
# 0 - no messages to screen
# 1 - errors only (Recommended :)
# 2 - errors, warnings
# 3 - errors, warnings, packet names
# 4 - errors, warnings, packet names, debug messages
# 5 - errors, warnings, packet names, debug messages, packet dumps
# Default: 1; it cannot be <0, but can be very big number. [0..0xFFFFFFFF]
WarnMessageLevel = 4
# ====================================
# If enabled, program will print something like:
# [PACKET] Unknown packet 00 in state: IN_GAME
# in WarnMessageLevel >= 3
WarnUnknownPacketsToStdout = 0
# ====================================
# Dump "unknown" packets to console window? 0-no, 1-yes (Default: 0, not display)
DumpUnknownToStdout = 0
# ====================================
# Enable or disable logging of Game Server packets 0-disable, 1-enable (Default: 0, disable)
LogGamePackets = 0
# ====================================
# File name prefix for log file with game server packets log
# (file name will look like prefix_XXXXXXXX.txt, where XXX-current date/time unix timestamp)
# Default: prefix_
LogGameFileNamePrefix = l2fan_
# ==========
# Hacks!!!!
# ==========
# ========================================
# Enable or disable game packets modifying
# - If disabled (0), only passive sniffing if possible, NO ANY HACKS will work
# - If enabled (1), packet-level hacks WILL work. This setting is REQUIRED to be set to ENABLED
# if you want any hacks to work
# - 0-disable, 1-enable; (Default: 0, disable, passive SNIFFING ONLY)
EnableModifyGameTraffic = 1
# !!!!! Any hacks below will not work, if EnableModifyGameTraffic is set to 0 !!!!!
# =====================================================================
# * Override game protocol version: change game protocol version number
# * in C->S ProtocolVersion packet to given number.
# * Value: 0 - disable this; any other number greater than 0: override to this number
# * Default: 0
OverrideGameProtocolVersion = 12
# Help on protocol versions (Official server):
# - T1 Kamael - 828
# - T1.5 Hellbound - 831 ?
# - T2 Gracia live - 851
# - T2.2 Gracia Part 2 - ???
# - T2.3 Gracia Final - ???

103
l2detect/L2Detect.rc Normal file
View File

@@ -0,0 +1,103 @@
#include "resource.h"
#include "targetver.h"
#include <windows.h>
#define IDC_STATIC -1
LANGUAGE LANG_ENGLISH, SUBLANG_DEFAULT
// common controls manifest
2 RT_MANIFEST "res\\xp_manifest.xml"
/////////////////////////////////////////////////////////////////////////////
// Dialogs
IDD_ABOUTBOX DIALOGEX 0, 0, 212, 110
STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "About L2Detect"
FONT 8, "MS Shell Dlg", 0, 0, 0x1
BEGIN
LTEXT "L2Detect, v 0.4",IDC_STATIC,75,18,114,8,SS_NOPREFIX
LTEXT "Copyright (C) 2008 Lexx :)",IDC_STATIC,74,33,114,8
DEFPUSHBUTTON "<22><>",IDOK,83,89,50,14,WS_GROUP
LTEXT "Special thanks to: fyyre, DistortNeo, KyberPrizrak, AllCheats.ru, l2wh.com, l2jserver.com",IDC_STATIC,49,50,131,27
ICON IDI_L2_BLACK,IDC_STATIC,25,15,21,20
END
IDD_CONFIG DIALOGEX 0,0,332,261
CAPTION "Network/Protocol Setup"
FONT 8,"MS Shell Dlg",400,0,1
STYLE WS_POPUP|WS_VISIBLE|WS_CAPTION|WS_SYSMENU|DS_MODALFRAME|DS_SETFONT|DS_FIXEDSYS
BEGIN
CONTROL "OK",IDOK,"Button",WS_CHILD|WS_VISIBLE|WS_TABSTOP|BS_DEFPUSHBUTTON,208,241,50,15
CONTROL "Cancel",IDCANCEL,"Button",WS_CHILD|WS_VISIBLE|WS_TABSTOP,262,241,50,15
CONTROL "OverrideGameProtocolVersion:",IDC_STATIC,"Static",WS_CHILD|WS_VISIBLE|WS_GROUP,16,84,100,9
CONTROL "",IDC_E_OVERRIDE_GPV,"Edit",WS_CHILD|WS_VISIBLE|WS_TABSTOP|ES_AUTOHSCROLL,120,81,40,15,WS_EX_CLIENTEDGE
CONTROL "Logging level:",IDC_STATIC,"Static",WS_CHILD|WS_VISIBLE|WS_GROUP,186,127,46,9
CONTROL "Enable modify Game Server Traffic",IDC_C_ENABLE_MODGT,"Button",WS_VISIBLE|WS_TABSTOP|BS_AUTOCHECKBOX,180,81,128,11
CONTROL "",IDC_CB_LOGLEVEL,"ComboBox",WS_CHILD|WS_VISIBLE|WS_VSCROLL|WS_TABSTOP|CBS_DROPDOWNLIST,258,127,60,87
CONTROL "ThreadPriorityRaiseEnable",IDC_C_ENABLE_THREADPRI,"Button",WS_VISIBLE|WS_TABSTOP|BS_AUTOCHECKBOX,180,96,100,11
CONTROL "L2Walker_Fix_MoveBackwardToLocation",IDC_C_L2WMOVEFIX,"Button",WS_VISIBLE|WS_TABSTOP|BS_AUTOCHECKBOX,16,144,146,11
CONTROL "Ports Setup",IDC_STATIC,"Button",WS_CHILD|WS_VISIBLE|BS_GROUPBOX,10,192,320,46
CONTROL "Listen Login Port:",IDC_STATIC,"Static",WS_CHILD|WS_VISIBLE|WS_GROUP,18,206,56,9
CONTROL "Listen Game Port:",IDC_STATIC,"Static",WS_CHILD|WS_VISIBLE|WS_GROUP,18,219,58,9
CONTROL "",IDC_E_FLPORT,"Edit",WS_CHILD|WS_VISIBLE|WS_TABSTOP|ES_AUTOHSCROLL,82,201,36,15,WS_EX_CLIENTEDGE
CONTROL "",IDC_E_FGPORT,"Edit",WS_CHILD|WS_VISIBLE|WS_TABSTOP|ES_AUTOHSCROLL,82,217,36,15,WS_EX_CLIENTEDGE
CONTROL "Real Login Server:",IDC_STATIC,"Static",WS_CHILD|WS_VISIBLE|WS_GROUP,126,203,60,9
CONTROL "",IDC_E_REALIP,"Edit",WS_CHILD|WS_VISIBLE|WS_TABSTOP|ES_AUTOHSCROLL,196,201,84,15,WS_EX_CLIENTEDGE
CONTROL ":",IDC_STATIC,"Static",WS_CHILD|WS_VISIBLE|WS_GROUP,284,201,8,9
CONTROL "",IDC_E_REALPORT,"Edit",WS_CHILD|WS_VISIBLE|WS_TABSTOP|ES_AUTOHSCROLL,290,201,32,15,WS_EX_CLIENTEDGE
CONTROL "Apply :)",IDC_APPLY,"Button",WS_CHILD|WS_VISIBLE|WS_TABSTOP,152,241,50,15
CONTROL "Log Game Packets",IDC_C_LOGGAMEP,"Button",WS_VISIBLE|WS_TABSTOP|BS_AUTOCHECKBOX,184,142,128,11
CONTROL "Log File Name Prefix:",IDC_STATIC,"Static",WS_CHILD|WS_VISIBLE|WS_GROUP,184,158,68,9
CONTROL "",IDC_E_LOGFNPREFIX,"Edit",WS_CHILD|WS_VISIBLE|WS_TABSTOP|ES_AUTOHSCROLL,258,155,60,15,WS_EX_CLIENTEDGE
CONTROL "Lineage II Server Protocol Version:",IDC_STATIC,"Static",WS_CHILD|WS_VISIBLE|WS_GROUP,20,16,112,8
CONTROL "",IDC_CB_L2VER,"ComboBox",WS_CHILD|WS_VISIBLE|WS_VSCROLL|WS_TABSTOP|CBS_DROPDOWNLIST,150,14,172,70
CONTROL "Lineage II Client Version:",IDC_STATIC,"Static",WS_CHILD|WS_VISIBLE|WS_GROUP,20,31,82,9
CONTROL "",IDC_CB_L2CVER,"ComboBox",WS_CHILD|WS_VISIBLE|WS_VSCROLL|WS_TABSTOP|CBS_DROPDOWNLIST,150,29,172,70
CONTROL "Lineage II Versions",IDC_STATIC,"Button",WS_CHILD|WS_VISIBLE|BS_GROUPBOX,8,5,318,61
CONTROL "Logging",IDC_STATIC,"Button",WS_CHILD|WS_VISIBLE|BS_GROUPBOX,178,116,148,70
CONTROL "L2Walker_Drop_RequestGMList",IDC_C_L2WDROPGMLIST,"Button",WS_VISIBLE|WS_TABSTOP|BS_AUTOCHECKBOX,16,132,146,11
CONTROL "WarnUnknownPackets",IDC_C_WARNUNKP,"Button",WS_VISIBLE|WS_TABSTOP|BS_AUTOCHECKBOX,184,171,88,11
CONTROL "L2Walker_Fix_ChangeWaitType2",IDC_C_L2WSITFIX,"Button",WS_VISIBLE|WS_TABSTOP|BS_AUTOCHECKBOX,16,155,146,11
CONTROL "Force Game Server IP:",IDC_STATIC,"Static",WS_CHILD|WS_VISIBLE|WS_GROUP,124,219,76,9
CONTROL "",IDC_E_FORCEGSIP,"Edit",WS_CHILD|WS_VISIBLE|WS_TABSTOP|ES_AUTOHSCROLL,204,217,76,15,WS_EX_CLIENTEDGE
CONTROL "",IDC_E_FORCEGSPORT,"Edit",WS_CHILD|WS_VISIBLE|WS_TABSTOP|ES_AUTOHSCROLL,290,217,32,15,WS_EX_CLIENTEDGE
CONTROL ":",IDC_STATIC,"Static",WS_CHILD|WS_VISIBLE|WS_GROUP,284,217,4,9
CONTROL "L2Walker fixes",IDC_STATIC,"Button",WS_CHILD|WS_VISIBLE|BS_GROUPBOX,8,116,162,70
CONTROL "L2Walker_Inject_StatusUpdate",IDC_C_L2WALKER_INJECTSTATUSUPDATE,"Button",WS_VISIBLE|WS_TABSTOP|BS_AUTOCHECKBOX,16,166,146,11
CONTROL "Misc hacks (be careful!!!)",IDC_STATIC,"Button",WS_CHILD|WS_VISIBLE|BS_GROUPBOX,8,72,318,41
CONTROL "Reply to L2J GameGuard query",IDC_C_GAMEGUARDREPLY,"Button",WS_CHILD|WS_VISIBLE|WS_TABSTOP|BS_AUTOCHECKBOX,16,97,134,11
CONTROL "Gracia Epilogue Server protocol 148 -> Client protocol 146 hacks (experimental!)",IDC_C_EPILOGUE_148_146,"Button",WS_CHILD|WS_VISIBLE|WS_TABSTOP|BS_AUTOCHECKBOX,18,46,302,11
END
IDD_DEBUG DIALOGEX 0,0,266,158
CAPTION "Debug"
FONT 8,"MS Shell Dlg",400,0,1
STYLE WS_POPUP|WS_VISIBLE|WS_CAPTION|WS_SYSMENU|DS_MODALFRAME|DS_SETFONT|DS_FIXEDSYS
BEGIN
CONTROL "Login listener status:",IDC_STATIC,"Static",WS_CHILD|WS_VISIBLE|WS_GROUP,7,7,68,8
CONTROL "Game listener status:",IDC_STATIC,"Static",WS_CHILD|WS_VISIBLE|WS_GROUP,7,25,69,8
CONTROL "",IDC_ELLSTATUS,"Edit",WS_CHILD|WS_VISIBLE|WS_TABSTOP|ES_READONLY|ES_AUTOHSCROLL,90,7,40,14,WS_EX_CLIENTEDGE
CONTROL "",IDC_EGLSTATUS,"Edit",WS_CHILD|WS_VISIBLE|WS_TABSTOP|ES_READONLY|ES_AUTOHSCROLL,89,23,40,14,WS_EX_CLIENTEDGE
CONTROL "Start LL",IDC_STARTLL,"Button",WS_CHILD|WS_VISIBLE|WS_TABSTOP,141,7,50,14
CONTROL "Start GL",IDC_STARTGL,"Button",WS_CHILD|WS_VISIBLE|WS_TABSTOP,142,23,50,14
CONTROL "Stop LL",IDC_STOPLL,"Button",WS_CHILD|WS_VISIBLE|WS_TABSTOP,197,7,50,14
CONTROL "Stop GL",IDC_STOPGL,"Button",WS_CHILD|WS_VISIBLE|WS_TABSTOP,198,23,50,14
CONTROL "Flush Log File",IDC_FLUSH_LOG,"Button",WS_CHILD|WS_VISIBLE|WS_TABSTOP,7,42,50,14
CONTROL "hp",IDC_HP,"Static",WS_VISIBLE|WS_GROUP|SS_SUNKEN|SS_LEFTNOWORDWRAP,7,61,72,11
CONTROL "mp",IDC_MP,"Static",WS_VISIBLE|WS_GROUP|SS_SUNKEN|SS_LEFTNOWORDWRAP,82,61,72,11
CONTROL "cp",IDC_CP,"Static",WS_VISIBLE|WS_GROUP|SS_SUNKEN|SS_LEFTNOWORDWRAP,156,61,72,11
CONTROL "char_name",IDC_CHARNAME,"Static",WS_CHILD|WS_VISIBLE|WS_GROUP|SS_SUNKEN,7,76,251,11
CONTROL "Enable Console",IDC_B_CONENABLE,"Button",WS_CHILD|WS_VISIBLE|WS_TABSTOP,65,42,64,14
CONTROL "Disable Console",IDC_B_CONDISABLE,"Button",WS_CHILD|WS_VISIBLE|WS_TABSTOP,141,42,63,14
CONTROL "Validate Interception",IDC_B_VALIDATEINTERCEPT,"Button",WS_CHILD|WS_VISIBLE|WS_TABSTOP,6,94,92,15
CONTROL "Intercept connect",IDC_B_INTERCEPTCONNECT,"Button",WS_CHILD|WS_VISIBLE|WS_TABSTOP,106,94,80,15
CONTROL "Check VP",IDC_B_CHECK_VIRTUALPROTECTEX,"Button",WS_CHILD|WS_VISIBLE|WS_TABSTOP,190,94,60,15
CONTROL "Load L2Walker.dll",IDC_B_LOADWALKER,"Button",WS_CHILD|WS_VISIBLE|WS_TABSTOP,7,116,75,14
CONTROL "Unload L2Walker.dll",IDC_B_UNLOADWALKER,"Button",WS_CHILD|WS_VISIBLE|WS_TABSTOP,90,116,76,15
CONTROL "Dump All Relations",IDC_B_DUMP_ALL_RELATIONS,"Button",WS_CHILD|WS_VISIBLE|WS_TABSTOP,8,136,86,15
CONTROL "Print address of UserAI::dwThreadID",IDC_B_PRINTADDRTID,"Button",WS_CHILD|WS_VISIBLE|WS_TABSTOP,102,136,136,15
END

6
l2detect/L2Detect_auth.h Normal file
View File

@@ -0,0 +1,6 @@
#ifndef H_L2DETECT_AUTH
#define H_L2DETECT_AUTH
extern "C" __declspec(dllimport) int getHWID( char *out );
#endif

BIN
l2detect/L2Detect_auth.lib Normal file

Binary file not shown.

122
l2detect/L2PacketTypes.cpp Normal file
View File

@@ -0,0 +1,122 @@
#include "stdafx.h"
#include "L2PacketTypes.h"
#include "Logger.h"
#include "ConfigIni.h"
extern class CConfig g_cfg;
// constants are the same as in GameClient.h
#define GCST_CONNECTED 1
#define GCST_AUTHED 2
#define GCST_IN_GAME 3
void L2PacketTypes_LogClient
(
L2_VERSION l2_version,
int state,
unsigned char ptype,
unsigned short ptype2,
unsigned short ptype3
)
{
char pname[256];
switch( state )
{
case GCST_CONNECTED:
{
switch( ptype )
{
case 0x0e: log_error( LOG_PACKETNAME, "Client: 0e ProtocolVersion\n" ); break;
case 0x2b: log_error( LOG_PACKETNAME, "Client: 2b AuthLogin\n" ); break;
default:
{
LOG_LEVEL log_level = LOG_PACKETNAME;
if( g_cfg.WarnUnknownPacketsToStdout ) log_level = LOG_WARNING;
log_error( log_level, "Client: Unknown packet %02X in state: CONNECTED\n", (unsigned int)ptype );
} break;
}
} break; // CONNECTED
case GCST_AUTHED:
{
switch( ptype )
{
case 0x00: log_error( LOG_PACKETNAME, "Client: 00 LogoutRequest\n" ); break;
case 0x12: log_error( LOG_PACKETNAME, "Client: 12 CharacterSelect\n" ); break;
case 0x13: log_error( LOG_PACKETNAME, "Client: 13 NewCharacter\n" ); break;
case 0x0c: log_error( LOG_PACKETNAME, "Client: 0c CharacterCreate\n" ); break;
case 0xd0:
{
switch( ptype2 )
{
case 0x0036: log_error( LOG_PACKETNAME, "Client: D0:36 RequestGotoLobby (Final)\n" ); break;
case 0x0039: log_error( LOG_PACKETNAME, "Client: D0:39 RequestGotoLobby\n" ); break;
default:
{
LOG_LEVEL log_level = LOG_PACKETNAME;
if( g_cfg.WarnUnknownPacketsToStdout ) log_level = LOG_WARNING;
log_error( log_level, "Client: Unknown opcode2 %04X in state AUTHED for packet 0xD0\n", (unsigned int)ptype2 );
} break;
}
} break; // double opcode packet
default:
{
LOG_LEVEL log_level = LOG_PACKETNAME;
if( g_cfg.WarnUnknownPacketsToStdout ) log_level = LOG_WARNING;
log_error( log_level, "Client: Unknown packet %02X in state: AUTHED\n", (unsigned int)ptype );
} break;
}
} break; // AUTHED
case GCST_IN_GAME:
{
L2Packets_GetL2PacketName( l2_version, false, ptype, ptype2, ptype3, pname, 255 );
if( ptype == 0xd0 )
{
if( ptype2 == 0x51 )
log_error( LOG_PACKETNAME, "Client: D0:51:%02X %s\n", ptype3, pname );
else
log_error( LOG_PACKETNAME, "Client: D0:%02X %s\n", ptype2, pname );
}
else
{
log_error( LOG_PACKETNAME, "Client: %02X %s\n", ptype, pname );
}
} break; // IN_GAME
} // switch( state )
}
void L2PacketTypes_LogServer
(
L2_VERSION l2_version,
int state,
unsigned char ptype,
unsigned short ptype2,
unsigned short ptype3
)
{
UNREFERENCED_PARAMETER(ptype3);
char pname[256];
switch( state )
{
case GCST_CONNECTED:
{
} break;
case GCST_AUTHED:
{
} break;
case GCST_IN_GAME:
{
L2Packets_GetL2PacketName( l2_version, true, ptype, ptype2, ptype2, pname, 255 );
if( ptype != 0xfe )
{
log_error( LOG_PACKETNAME, "Server: %02X %s\n", ptype, pname );
}
else
{
log_error( LOG_PACKETNAME, "Server: FE:%02X %s\n", ptype2, pname );
}
} break;
}
}

23
l2detect/L2PacketTypes.h Normal file
View File

@@ -0,0 +1,23 @@
#ifndef H_L2_PACKET_TYPES
#define H_L2_PACKET_TYPES
void L2PacketTypes_LogClient
(
L2_VERSION l2_version,
int state,
unsigned char ptype,
unsigned short ptype2,
unsigned short ptype3
);
void L2PacketTypes_LogServer
(
L2_VERSION l2_version,
int state,
unsigned char ptype,
unsigned short ptype2,
unsigned short ptype3
);
#endif

170
l2detect/Logger.cpp Normal file
View File

@@ -0,0 +1,170 @@
#include "stdafx.h"
#include "ConfigIni.h"
#include "Logger.h"
extern CConfig g_cfg;
// global ErrorLogger vars
bool g_error_logger_enabled;
bool g_error_logger_enabled_console;
FILE *g_error_logger_file;
bool g_error_logger_auto_prepend;
CRITICAL_SECTION g_error_logger_cs;
HANDLE g_error_logger_stdout;
// strings
char g_error_logger_strtype_unknown[16];
char g_error_logger_strtype[LOG_LEVELS][16];
void ErrorLogger_InitStrings()
{
strcpy( g_error_logger_strtype_unknown, "[??] " );
strcpy( g_error_logger_strtype[LOG_OK], "[++] " );
strcpy( g_error_logger_strtype[LOG_ERROR], "[--] " );
strcpy( g_error_logger_strtype[LOG_WARNING], "[WARN] " );
strcpy( g_error_logger_strtype[LOG_USERAI], "[AI] " );
strcpy( g_error_logger_strtype[LOG_PACKETNAME], "[PACK] " );
strcpy( g_error_logger_strtype[LOG_DEBUG], "[DBG] " );
strcpy( g_error_logger_strtype[LOG_DEBUGDUMP], "[DUMP] " );
}
void ErrorLogger_Init()
{
g_error_logger_enabled = false;
g_error_logger_enabled_console = false;
g_error_logger_file = stdout;
g_error_logger_auto_prepend = false;
g_error_logger_stdout = INVALID_HANDLE_VALUE;
InitializeCriticalSection( &g_error_logger_cs );
ErrorLogger_InitStrings();
}
void ErrorLogger_Enable( bool bEnable )
{
g_error_logger_enabled = bEnable;
}
void ErrorLogger_EnableLoggingToConsole( bool bEnable )
{
EnterCriticalSection( &g_error_logger_cs );
if( bEnable )
{
if( g_error_logger_enabled_console == false ) AllocConsole();
g_error_logger_stdout = GetStdHandle( STD_OUTPUT_HANDLE );
}
else
{
g_error_logger_stdout = INVALID_HANDLE_VALUE;
if( g_error_logger_enabled_console == true ) FreeConsole();
}
g_error_logger_enabled_console = bEnable;
LeaveCriticalSection( &g_error_logger_cs );
}
void ErrorLogger_SetLogFile( FILE *f )
{
EnterCriticalSection( &g_error_logger_cs );
if( !f ) g_error_logger_file = stdout; else g_error_logger_file = f;
LeaveCriticalSection( &g_error_logger_cs );
}
FILE *ErrorLogger_GetLogFile()
{
return g_error_logger_file;
}
void ErrorLogger_FlushLogFile()
{
EnterCriticalSection( &g_error_logger_cs );
if( g_error_logger_file ) fflush( g_error_logger_file );
LeaveCriticalSection( &g_error_logger_cs );
}
void ErrorLogger_SetAutoPrependErrorType( bool bPrepend )
{
g_error_logger_auto_prepend = bPrepend;
}
int log_error( LOG_LEVEL logLevel, const char *_Format, ... )
{
if( !g_error_logger_enabled ) return 0;
int ret = 0;
if( (logLevel < 0) || (!_Format) ) return 0;
if( logLevel > g_cfg.WarnMessageLevel ) return 0;
EnterCriticalSection( &g_error_logger_cs );
va_list l;
va_start( l, _Format );
if( g_error_logger_auto_prepend )
{
char *szPrepend = g_error_logger_strtype_unknown;
if( (logLevel >= LOG_OK) && (logLevel <= LOGLEVEL_LAST) )
szPrepend = g_error_logger_strtype[logLevel];
fprintf( g_error_logger_file, "%s", szPrepend );
// also write to console, if enabled
if( g_error_logger_enabled_console )
{
DWORD numWritten = 0;
WriteConsoleA( g_error_logger_stdout, szPrepend, (DWORD)strlen(szPrepend), &numWritten, NULL );
}
}
ret = vfprintf( g_error_logger_file, _Format, l );
// also write to console, if enabled
if( g_error_logger_enabled_console && (ret > 0) )
{
char *cbuffer = (char *)malloc( ret+1 );
if( cbuffer )
{
va_list l2;
va_start( l2, _Format );
vsprintf( cbuffer, _Format, l2 );
DWORD numWritten = 0;
WriteConsoleA( g_error_logger_stdout, cbuffer, (DWORD)strlen(cbuffer), &numWritten, NULL );
free( cbuffer );
}
}
LeaveCriticalSection( &g_error_logger_cs );
return ret;
}
// forces NO prepend even if set to
int log_error_np( LOG_LEVEL logLevel, const char *_Format, ... )
{
if( !g_error_logger_enabled ) return 0;
int ret = 0;
if( (logLevel < 0) || (!_Format) ) return 0;
if( logLevel > g_cfg.WarnMessageLevel ) return 0;
EnterCriticalSection( &g_error_logger_cs );
va_list l;
va_start( l, _Format );
// no prepend, just vfprintf
ret = vfprintf( g_error_logger_file, _Format, l );
// also write to console, if enabled?
if( g_error_logger_enabled_console && (ret > 0) )
{
char *cbuffer = (char *)malloc( ret+1 );
if( cbuffer )
{
va_list l2;
va_start( l2, _Format );
vsprintf( cbuffer, _Format, l2 );
DWORD numWritten = 0;
WriteConsoleA( g_error_logger_stdout, cbuffer, (DWORD)strlen(cbuffer), &numWritten, NULL );
free( cbuffer );
}
}
LeaveCriticalSection( &g_error_logger_cs );
return ret;
}
void ErrorLogger_FormatLastError( char *msg, size_t nMaxCount, DWORD error_code )
{
FormatMessageA( FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
NULL, error_code, 0, msg, nMaxCount, NULL );
}
void ErrorLogger_LogLastError( char *comment, DWORD error_code )
{
char errbuf[512];
errbuf[0] = 0;
ErrorLogger_FormatLastError( errbuf, 511, error_code );
log_error( LOG_ERROR, "%s: error code: %u (%s)\n", comment, (unsigned int)error_code, errbuf );
ErrorLogger_FlushLogFile();
}

33
l2detect/Logger.h Normal file
View File

@@ -0,0 +1,33 @@
#ifndef FL_ERRORLOGGER_H_
#define FL_ERRORLOGGER_H_
typedef enum eLOG_LEVEL
{
LOG_OK = 0,
LOG_ERROR, // 1
LOG_WARNING, // 2
LOG_USERAI, // 3
LOG_PACKETNAME, // 4
LOG_DEBUG, // 5
LOG_DEBUGDUMP, // 6
LOGLEVEL_LAST = LOG_DEBUGDUMP
} LOG_LEVEL;
#define LOG_LEVELS 7
void ErrorLogger_Init();
void ErrorLogger_Enable( bool bEnable );
void ErrorLogger_EnableLoggingToConsole( bool bEnable );
void ErrorLogger_SetLogFile( FILE *f );
FILE *ErrorLogger_GetLogFile();
void ErrorLogger_FlushLogFile();
void ErrorLogger_SetAutoPrependErrorType( bool bPrepend );
int log_error( LOG_LEVEL logLevel, const char *_Format, ... );
int log_error_np( LOG_LEVEL logLevel, const char *_Format, ... ); // forces NO prepend even if set to
void ErrorLogger_FormatLastError( char *msg, size_t nMaxCount, DWORD error_code );
void ErrorLogger_LogLastError( char *comment, DWORD error_code );
#endif /*FL_ERRORLOGGER_H_*/

719
l2detect/LoginClient.cpp Normal file
View File

@@ -0,0 +1,719 @@
#include "stdafx.h"
#include "ConfigIni.h"
#include "Logger.h"
#include "LoginClient.h"
extern class CConfig g_cfg;
/**
* Function replaces IP and port of server with ID = serverID
* in ServerList packet.
* Usage:
* unsigned char IP_new = {127,0,0,1};
* int port_new = 7777;
* unsigned int serverID = 1;
* bool ret = FL_ReplaceServerIPPort( rawBytes, rawBytesLen, serverID, IP_new, port_new );
*
* returns true on success, false on error
*/
bool FL_ReplaceServerIPPort( unsigned char *b, unsigned int blen )
{
if( !b || (blen<26) ) return false;
unsigned char fake_gsip[4] = {0,0,0,0};
unsigned long lInetAddr = L2PNet_inet_addr( g_cfg.FakeListenGameIP );
memcpy( (void *)&fake_gsip, (const void *)&lInetAddr, sizeof(lInetAddr) );
unsigned short int sport = (unsigned short int)g_cfg.FakeListenGamePort;
unsigned char cport[2] = {
(unsigned char)( sport & 0x00FF),
(unsigned char)((sport & 0xFF00) >> 8)
};
int gscount = (int)b[3];
const int ServerList_Header_Size = 5;
const int ServerList_OneServerInfo_Size = 21;
int pos = ServerList_Header_Size; // pass packet header
int i;
//while( pos < (int)blen )
log_error( LOG_DEBUG, "FL_ReplaceServerIPPort(): replacing IPs and ports for %d servers in list\n", gscount );
for( i=0; i<gscount; i++ )
{
pos = ServerList_Header_Size + (i * ServerList_OneServerInfo_Size);
//if( b[pos] == serverID )
//{
// found!
//log_error( LOG_DEBUG, "FL_ReplaceServerIPPort(): found server ID %d at offset %d\n",
// (int)serverID, pos );
// b[pos] is ServerID
// set new IP
b[pos+1] = fake_gsip[0];
b[pos+2] = fake_gsip[1];
b[pos+3] = fake_gsip[2];
b[pos+4] = fake_gsip[3];
// set new port
b[pos+5] = cport[0];
b[pos+6] = cport[1];
b[pos+7] = 0x00;
b[pos+8] = 0x00;
//return true;
//}
//else
//pos += ServerList_OneServerInfo_Size; // go to next serverID...
}
//log_error( LOG_WARNING, "FL_ReplaceServerIPPort(): not found server ID %d",
// (int)serverID );
//return false;
return true;
}
bool FL_RecalculateChechksum(
unsigned char *b,
unsigned int blen )
{
if( !b || (blen<26) ) return false; // some error?
L2LoginPacket lp;
unsigned int newlen = 0;
// set bytes, copy all except last 4 bytes - old checksum
if( !lp.setBytes( b, blen-4 ) )
{
log_error( LOG_ERROR,
"FL_RecalculateChechksum(): L2LoginPacket::setBytes( 0x%p, %u ) failed!\n",
b, blen-4 );
return false;
}
// append new checksum
lp.appendChecksum( false ); // do not append 4 bytes
// check resulting packet length - must be as original
newlen = lp.getPacketSize();
if( newlen == blen )
{
log_error( LOG_DEBUG, "FL_RecalculateChechksum(): newlen == blen, all OK\n" );
memcpy( b, lp.getBytesPtr(), newlen );
return true;
}
//else
log_error( LOG_ERROR, "FL_RecalculateChechksum(): newlen (%u) != oldlen (%u)\n", newlen, blen );
return false;
}
/**
* Was only for debugging
void GenerateFakePacket( L2Login_ServerList *p_sl )
{
if( !p_sl ) return;
// ugly! but this packet is known sure to work!
unsigned char b[] = {
0x22, 0x00, // length
0x04, 0x01, 0x01, // ptype, lastServer, nServers
0x01, // serverID
0x7F, 0x00, 0x00, 0x01, // serverIP
0x61, 0x1E, 0x00, 0x00, // serverPort
0x00, // age limit
0x01, // is PvP
0x00, 0x00, // current online
0x0A, 0x00, // max online
0x01, // is up
0x00, 0x00, 0x00, 0x00, 0x00, // flags...
0xA5, 0x4A, 0xAA, 0xCE, // <-- WTF is here????
0xB5, 0x54, 0xAA, 0xCE }; // here must be checksum
p_sl->setBytes( b, sizeof(b) );
}
*/
LoginClient::LoginClient()
{
memset( sessionKey1, 0, sizeof(sessionKey1) );
memset( sessionKey2, 0, sizeof(sessionKey2) );
gsIP[0] = gsIP[1] = gsIP[2] = gsIP[3] = 0;
gsPort = 0;
g_login_client = this;
state = LCST_OFFLINE;
}
LoginClient::~LoginClient()
{
g_login_client = NULL;
memset( sessionKey1, 0, sizeof(sessionKey1) );
memset( sessionKey2, 0, sizeof(sessionKey2) );
gsIP[0] = gsIP[1] = gsIP[2] = gsIP[3] = 0;
gsPort = 0;
state = LCST_OFFLINE;
}
bool LoginClient::getSessionKeys( unsigned char *sKey1, unsigned char *sKey2 )
{
if( !sKey1 || !sKey2 ) return false;
memcpy( sKey1, this->sessionKey1, 8 );
memcpy( sKey2, this->sessionKey2, 8 );
return true;
}
bool LoginClient::getPlayServerAddress( unsigned char *ip, unsigned short int *port )
{
if( !ip || !port ) return false;
memcpy( ip, this->gsIP, sizeof(this->gsIP) );
(*port) = this->gsPort;
return true;
}
bool LoginClient::ProcessClient( SOCKET scl )
{
bool retVal = false;
state = LCST_OFFLINE;
// connect to real login server
log_error( LOG_DEBUG, "Establishing redirecting connection to %s:%d ",
g_cfg.RealLoginServerIP, g_cfg.RealLoginServerPort );
SOCKET sr = L2PNet_TCPsocket_create( true );
if( sr == INVALID_SOCKET )
{
log_error_np( LOG_ERROR, "\n" );
log_error( LOG_ERROR, "ProcessClient(): cannot create socket!\n" );
return false;
}
L2PNet_connect( sr, g_cfg.RealLoginServerIP, (unsigned short)g_cfg.RealLoginServerPort );
int nTries = 20;
int r = 0;
while( nTries > 0 )
{
log_error_np( LOG_DEBUG, "." );
r = L2PNet_select( sr, L2PNET_SELECT_WRITE, 20000, NULL, NULL );
if( r == 1 ) break;
nTries--;
}
if( r == 1 )
{
log_error_np( LOG_DEBUG, " Connected. Tries left: %d\n", nTries );
state = LCST_CONNECTED;
}
else
{
state = LCST_OFFLINE;
// close sockets
L2PNet_shutdown( scl );
L2PNet_closesocket( scl );
L2PNet_shutdown( sr );
L2PNet_closesocket( sr );
log_error_np( LOG_DEBUG, " Not connected.\n" );
return false;
}
this->postNotify( LCN_STATECHANGE, 1 ); // connected
// TODO: Login server session vars
// login server session vars
unsigned char ls_sessionID[4] = {0,0,0,0};
unsigned int ls_sessionIDUInt = 0;
unsigned int ls_protoVer = 0;
unsigned char ls_RSA_pubKeyMod[128];
unsigned char ls_ggShit[16] = {0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0};
unsigned char ls_newBFKey[16] = {0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0};
unsigned int ls_ggAuthResponse = 0;
unsigned char ls_sessionKey1[8] = {0,0,0,0, 0,0,0,0};
unsigned char ls_sessionKey2[8] = {0,0,0,0, 0,0,0,0};
unsigned char ls_nGameServersCount = 0;
unsigned char ls_lastServerID = 0; // last server ID
unsigned char myGameServerIP[4] = {0,0,0,0};
//char sMyGSIP[16] = {0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0};
unsigned short int myGameServerPort = 0;
int ls_chosenGameServer = -1;
// login server session vars memset
memset( ls_RSA_pubKeyMod, 0, sizeof(ls_RSA_pubKeyMod) );
// network vars
int netTimeout = 30;
int i = 0;
unsigned char ptype = 0; // packet type byte
unsigned char *rraw = NULL; // raw packet bytes
unsigned int rcvdLen = 0;
unsigned int sentLen = 0;
// packet objects
L2LoginPacket *pack = NULL;
L2Login_Init *p_init = NULL;
//L2Login_RequestGGAuth *p_rgga = NULL;
L2Login_GGAuthResponse *p_ggar = NULL;
L2Login_LoginOK *p_lok = NULL;
//L2Login_LoginFail *p_lfail = NULL;
L2Login_ServerList *p_sl = NULL;
L2Login_RequestServerLogin *p_rgsl = NULL;
L2Login_PlayOK *p_pok = NULL;
//L2Login_PlayFail *p_pfail = NULL;
// ServerInfo struct
struct L2GameServerInfo gsi;
memset( &gsi, 0, sizeof(gsi) );
struct L2GameServerInfo gameservers_info[32];
memset( gameservers_info, 0, sizeof(gameservers_info) );
// debug file
//FILE *f = NULL;
// Init: receive Init packet from real login server
rcvdLen = 0;
rraw = L2PacketReceive_malloc( sr, netTimeout*1000, &rcvdLen );
if( !rraw ) { log_error( LOG_ERROR, "receive failed!\n" ); goto l_netError; }
log_error( LOG_DEBUG, "ProcessClient(): rcvd %u bytes of Init packet from server.\n", rcvdLen );
// resend it to client
sentLen = 0;
L2PacketSend2( rraw, scl, netTimeout*1000, &sentLen );
log_error( LOG_DEBUG, "ProcessClient(): resent %u bytes of Init packet to client.\n", sentLen );
if( sentLen != rcvdLen ) { log_error( LOG_ERROR, "rcvd != sent! (%u != %u)\n", rcvdLen, sentLen ); goto l_netError; }
// decode and parse server's Init packet
p_init = new L2Login_Init( rraw, rcvdLen );
if( p_init->decodeBlowfish( true ) ) // true - Use Static BF Key
{
if( p_init->decodeXOR() )
{
// read packet data
p_init->read_SessionID( ls_sessionID );
memcpy( &ls_sessionIDUInt, ls_sessionID, sizeof(ls_sessionID) );
ls_protoVer = p_init->read_ProtoVer();
p_init->read_RSA_pubKeyMod( ls_RSA_pubKeyMod );
p_init->read_GGShit( ls_ggShit );
p_init->read_DynamicBFKey( ls_newBFKey );
// printfs
log_error( LOG_DEBUGDUMP, "SessionID: %02X %02X %02X %02X\n",
ls_sessionID[0], ls_sessionID[1], ls_sessionID[2], ls_sessionID[3] );
log_error( LOG_DEBUGDUMP, "Protocol ver: %08X\n", ls_protoVer );
p_init->unscramble_RSA_PubKeyMod( ls_RSA_pubKeyMod );
log_error( LOG_DEBUGDUMP, "Dynamic Blowfish key: " );
i = 0;
while( i < 16 ) log_error_np( LOG_DEBUGDUMP, "%02X ", ls_newBFKey[i++] );
log_error_np( LOG_DEBUGDUMP, "\n" );
}
else log_error( LOG_ERROR, "XOR decode failed\n" );
}
else log_error( LOG_ERROR, "BF decode failed\n" );
delete p_init;
p_init = NULL;
// free raw pack buffer
free( rraw );
rraw = NULL;
// RequestGGAuth
// receive client's answer to server's Init packet. probably it is RequestGGAuth packet
rcvdLen = 0;
rraw = L2PacketReceive_malloc( scl, netTimeout*1000, &rcvdLen );
if( !rraw ) { log_error( LOG_ERROR, "receive failed!\n" ); goto l_netError; }
log_error( LOG_DEBUG, "ProcessClient(): rcvd %u bytes of RequestGGAuth packet from client.\n", rcvdLen );
// resend it to server
sentLen = 0;
L2PacketSend2( rraw, sr, netTimeout*1000, &sentLen );
log_error( LOG_DEBUG, "ProcessClient(): resent %u bytes of RequestGGAuth packet to server.\n", sentLen );
if( sentLen != rcvdLen ) { log_error( LOG_ERROR, "rcvd != sent! (%u != %u)\n", rcvdLen, sentLen ); goto l_netError; }
// try to decode and parse client's response
//p_rgga = new L2Login_RequestGGAuth( rraw, rcvdLen );
//p_rgga->setDynamicBFKey( ls_newBFKey, 16 );
//p_rgga->decodeBlowfish( false );
//p_rgga->dumpToFile( stdout );
//delete p_rgga;
//p_rgga = NULL;
// free raw pack buffer
free( rraw );
rraw = NULL;
// GGAuthResponse
// receive server's answer to client's RequstGGAuth packet
rcvdLen = 0;
rraw = L2PacketReceive_malloc( sr, netTimeout*1000, &rcvdLen );
if( !rraw ) { log_error( LOG_ERROR, "receive failed!\n" ); goto l_netError; }
log_error( LOG_DEBUG, "ProcessClient(): rcvd %u bytes of GGAuthResponse packet from server.\n", rcvdLen );
// resend it to client
sentLen = 0;
L2PacketSend2( rraw, scl, netTimeout*1000, &sentLen );
log_error( LOG_DEBUG, "ProcessClient(): resent %u bytes of GGAuthResponse packet to client.\n", sentLen );
if( sentLen != rcvdLen ) { log_error( LOG_ERROR, "rcvd != sent! (%u != %u)\n", rcvdLen, sentLen ); goto l_netError; }
p_ggar = new L2Login_GGAuthResponse( rraw, rcvdLen );
//if( p_ggar ) printf( "GGAuthResponse object created\n" );
//printf( "Setting bytes 0x%p %u len\n", rraw, rcvdLen );
//if( p_ggar->setBytes( rraw, rcvdLen ) )
// printf( "ProcessClient(): GGAuthResponse bytes set OK\n" );
p_ggar->setDynamicBFKey( ls_newBFKey, 16 );
p_ggar->decodeBlowfish( false );
ptype = p_ggar->getPacketType();
if( ptype != 0x0B )
log_error( LOG_WARNING, "Unknown GGAuthResponse code 0x%02X!!!!\n",
(unsigned int)ptype );
else
log_error( LOG_OK, "GGAuthResponse: bypass GameGuard authorization...\n" );
ls_ggAuthResponse = p_ggar->read_Response();
if( ls_ggAuthResponse != ls_sessionIDUInt )
{
log_error( LOG_WARNING, "sessionID != ggAuthResponse (%04X != %04X)\n",
ls_sessionIDUInt, ls_ggAuthResponse );
}
else log_error( LOG_DEBUG, "++++ SessionID == ggAuthResponse ++++\n" );
delete p_ggar;
p_ggar = NULL;
// free raw pack buffer
free( rraw );
rraw = NULL;
state = LCST_AUTHED_GG;
// RequestAuthLogin
// client must now attempt to login to server with its login and password
rcvdLen = 0;
rraw = L2PacketReceive_malloc( scl, netTimeout*1000, &rcvdLen );
if( !rraw ) { log_error( LOG_ERROR, "receive failed!\n" ); goto l_netError; }
log_error( LOG_DEBUG, "ProcessClient(): rcvd %u bytes of RequestAuthLogin packet from client.\n", rcvdLen );
// resend it to server
sentLen = 0;
//L2PacketSend( rraw, sr, netTimeout, 0, &sentLen );
L2PacketSend2( rraw, sr, netTimeout*1000, &sentLen );
log_error( LOG_DEBUG, "ProcessClient(): resent %u bytes of RequestAuthLogin packet to server.\n", sentLen );
if( sentLen != rcvdLen ) { log_error( LOG_ERROR, "rcvd != sent! (%u != %u)\n", rcvdLen, sentLen ); goto l_netError; }
// display RequestAuthLogin contents
//pack = new L2LoginPacket();
//pack->setBytes( rraw, sentLen );
//pack->setDynamicBFKey( ls_newBFKey, 16 );
//pack->decodeBlowfish( false );
//pack->dumpToFile( stdout );
//delete pack;
//pack = NULL;
// free raw pack buffer
free( rraw );
rraw = NULL;
// LoginOK / LoginFail
// Login server must now reply to RequestAuthLogin and tell us about result
rcvdLen = 0;
rraw = L2PacketReceive_malloc( sr, netTimeout*1000, &rcvdLen );
if( !rraw ) { log_error( LOG_ERROR, "receive failed!\n" ); goto l_netError; }
log_error( LOG_DEBUG, "ProcessClient(): rcvd %u bytes of response to RequestAuthLogin from server.\n", rcvdLen );
// resend it to client
sentLen = 0;
L2PacketSend2( rraw, scl, netTimeout*1000, &sentLen );
log_error( LOG_DEBUG, "ProcessClient(): resent %u bytes of response to client.\n", sentLen );
if( sentLen != rcvdLen ) { log_error( LOG_ERROR, "rcvd != sent! (%u != %u)\n", rcvdLen, sentLen ); goto l_netError; }
log_error( LOG_DEBUG, "Server answer to RequestAuthLogin:\n" );
pack = new L2LoginPacket( rraw, rcvdLen );
pack->setDynamicBFKey( ls_newBFKey, 16 );
pack->decodeBlowfish( false );
//pack->dumpToFile( stdout );
ptype = pack->getPacketType();
if( ptype == 0x03 )
{
log_error( LOG_DEBUG, "++++ Login OK! ++++\n" );
state = LCST_AUTHED_LOGIN;
p_lok = new L2Login_LoginOK();
p_lok->setBytes( pack->getBytesPtr(), pack->getPacketSize() );
p_lok->read_sessionKey1( ls_sessionKey1 );
delete p_lok;
p_lok = NULL;
log_error( LOG_DEBUGDUMP, "SessionKey1: " );
for( i=0; i<sizeof(ls_sessionKey1); i++ )
log_error_np( LOG_DEBUGDUMP, "%02X ", ls_sessionKey1[i] );
log_error_np( LOG_DEBUGDUMP, "\n" );
}
else if( ptype == 0x01 )
{
state = LCST_AUTH_ERROR;
log_error( LOG_ERROR, "---- Login failed! (invalid user/pass? server offline?) ----\n" );
goto l_netError;
}
else if( ptype == 0x02 )
{
state = LCST_AUTH_ERROR;
log_error( LOG_ERROR, "---- Login failed! (account banned?)----\n" );
goto l_netError;
}
else
log_error( LOG_WARNING, "???? unknown reply to RequestAuthLogin: packet type: 0x%02X\n",
(unsigned int)ptype );
delete pack;
pack = NULL;
// free raw pack buffer
free( rraw );
rraw = NULL;
// RequestServerList
// after receiving packet LoginOK client displays license agreement
// and after user clicks 'Agree' client sends RequestServerList packet
rcvdLen = 0;
rraw = L2PacketReceive_malloc( scl, netTimeout*1000, &rcvdLen );
if( !rraw ) { log_error( LOG_ERROR, "receive failed!\n" ); goto l_netError; }
log_error( LOG_DEBUG, "ProcessClient(): rcvd %u bytes of RequestServerList packet from client.\n", rcvdLen );
// resend it to server
sentLen = 0;
L2PacketSend2( rraw, sr, netTimeout*1000, &sentLen );
log_error( LOG_DEBUG, "ProcessClient(): resent %u bytes of RequestServerList packet to server.\n", sentLen );
if( sentLen != rcvdLen ) { log_error( LOG_ERROR, "rcvd != sent! (%u != %u)\n", rcvdLen, sentLen ); goto l_netError; }
// dump info about RequestServerList packet
// [cut]
// free raw pack buffer
free( rraw );
rraw = NULL;
// ServerList
// login server now sends to client list of Game servers
rcvdLen = 0;
rraw = L2PacketReceive_malloc( sr, netTimeout*1000, &rcvdLen );
if( !rraw ) { log_error( LOG_ERROR, "receive failed!\n" ); goto l_netError; }
log_error( LOG_DEBUG, "ProcessClient(): rcvd %u bytes of ServerList packet from server.\n", rcvdLen );
// TODO: ServerList: NO, do not resend! :) modify it!!!
// resend it to client
/*sentLen = 0;
L2PacketSend( rraw, scl, 5, 0, &sentLen );
log_error( LOG_DEBUG, "ProcessClient(): resent %u bytes of ServerList packet to client.\n", sentLen );
if( sentLen != rcvdLen ) { log_error( LOG_ERROR, "rcvd != sent! (%u != %u)\n", rcvdLen, sentLen ); goto l_netError; }*/
log_error( LOG_DEBUG, "ServerList packet:\n" );
p_sl = new L2Login_ServerList();
p_sl->setBytes( rraw, rcvdLen );
// out RAW
//printf( "RAW ServerList packet:\n" );
//p_sl->dumpToFile( stdout );
p_sl->setDynamicBFKey( ls_newBFKey, 16 );
p_sl->decodeBlowfish( false );
// out BF decoded
//printf( "BF Decoded ServerList packet:\n" );
//p_sl->dumpToFile( stdout );
// save to file :)
//f = fopen( "ServerList.txt", "wt" );
//if( f ) p_sl->dumpToFile( f );
//fclose( f );
// parse
ptype = p_sl->getPacketType();
if( ptype == 0x04 ) log_error( LOG_DEBUG, "++++ ServerList ++++\n" );
p_sl->read_header( &ls_nGameServersCount, &ls_lastServerID );
log_error_np( LOG_DEBUGDUMP, "\n" );
log_error( LOG_DEBUGDUMP, "ServerList: %d game servers, last server: %d\n",
(int)ls_nGameServersCount, (int)ls_lastServerID );
for( i=0; i<ls_nGameServersCount; i++ )
{
memset( &gsi, 0, sizeof(gsi) );
if( p_sl->read_next_GS_Info( &gsi ) )
{
log_error( LOG_DEBUGDUMP, "*** Server %d Info ***\n", i );
log_error( LOG_DEBUGDUMP, "*** Server ID: %d\n", (int)gsi.gsID );
log_error( LOG_DEBUGDUMP, "*** Server addr: %d.%d.%d.%d:%d\n",
(int)gsi.gsIP[0],
(int)gsi.gsIP[1],
(int)gsi.gsIP[2],
(int)gsi.gsIP[3],
(int)gsi.gsPort );
log_error( LOG_DEBUGDUMP, "*** Online: %d / %d (up: %d)\n", (int)gsi.gsPlayersOnline,
(int)gsi.gsPlayersMax, (int)gsi.gsIsUp );
log_error_np( LOG_DEBUGDUMP, "\n" );
// save this gameserver in array
memcpy( (&gameservers_info[i]), &gsi, sizeof(L2GameServerInfo) );
// is this GS chosen to play on? // ignore
/*if( ((int)gsi.gsID) == g_cfg.PlayGameServerNo )
{
log_error( LOG_DEBUGDUMP, "^^^^ we play here! ^^^^\n\n" );
memcpy( myGameServerIP, gsi.gsIP, 4 );
myGameServerPort = gsi.gsPort;
}*/
}
else
{
log_error( LOG_ERROR, "p_sl->read_next_GS_Info( &gsi ) failed!\n" );
}
}
// replace server IP and port to what we need to intercept GS connection
if( FL_ReplaceServerIPPort(
(unsigned char *)p_sl->getBytesPtr(),
p_sl->getPacketSize() ) )
{
log_error( LOG_DEBUG, "[++++] OK: ServerList packet modified\n" );
// packet modified, we must update checksum in it
if( FL_RecalculateChechksum(
(unsigned char *)p_sl->getBytesPtr(),
p_sl->getPacketSize() ) )
{
log_error( LOG_DEBUGDUMP, "[++++] OK: ServerList packet checksum recalculated\n" );
}
else
{
log_error( LOG_ERROR, "ServerList packet checksum recalculate error!\n" );
}
}
else log_error( LOG_ERROR, "ServerList packet modify error\n" );
//GenerateFakePacket( p_sl ); // was called for debug only
//printf( "================\n" );
//printf( "[I] ServerList packet after replacing its IP & port:\n" );
//p_sl->dumpToFile( stdout );
//printf( "=================\n" );
// encode modified packet again
p_sl->encodeBlowfish( false );
// out encoded
//printf( "BF Encoded ServerList packet:\n" );
//p_sl->dumpToFile( stdout );
//rcvdLen = p_sl->getPacketSize();
// resend it to client
log_error( LOG_DEBUG, "Now resend %u bytes of ServerList to client...\n", rcvdLen );
sentLen = 0;
//L2PacketSend( p_sl->getBytesPtr(), scl, netTimeout, 0, &sentLen );
L2PacketSend2( p_sl->getBytesPtr(), scl, netTimeout*1000, &sentLen );
log_error( LOG_DEBUG, "ProcessClient(): resent %u bytes of ServerList packet to client.\n", sentLen );
if( sentLen != rcvdLen ) { log_error( LOG_ERROR, "rcvd != sent! (%u != %u)\n", rcvdLen, sentLen ); goto l_netError; }
delete p_sl;
p_sl = NULL;
// free raw pack buffer
free( rraw );
rraw = NULL;
// RequestServerLogin
// client now must request server login
rcvdLen = 0;
//rraw = L2PacketReceive( scl, netTimeout, 0, &rcvdLen );
rraw = L2PacketReceive_malloc( scl, netTimeout*1000, &rcvdLen );
if( !rraw ) { log_error( LOG_ERROR, "receive failed!\n" ); goto l_netError; }
log_error( LOG_DEBUG, "ProcessClient(): rcvd %u bytes of RequestServerLogin packet from client.\n", rcvdLen );
// resend it to server
sentLen = 0;
//L2PacketSend( rraw, sr, netTimeout, 0, &sentLen );
L2PacketSend2( rraw, sr, netTimeout*1000, &sentLen );
log_error( LOG_DEBUG, "ProcessClient(): resent %u bytes of RequestServerLogin packet to server.\n", sentLen );
if( sentLen != rcvdLen ) { log_error( LOG_ERROR, "rcvd != sent! (%u != %u)\n", rcvdLen, sentLen ); goto l_netError; }
// dump info about RequestServerLogin packet
p_rgsl = new L2Login_RequestServerLogin( rraw, rcvdLen );
p_rgsl->setDynamicBFKey( ls_newBFKey, 16 );
p_rgsl->decodeBlowfish( false );
// out
//pack->dumpToFile( stdout );
ptype = p_rgsl->getPacketType();
if( ptype == 0x02 ) log_error( LOG_DEBUG, "++++ RequestServerLogin ++++\n" );
p_rgsl->readInt(); p_rgsl->readInt(); // pass sessionKey1
ls_chosenGameServer = (int)p_rgsl->read_GameServerID();
log_error( LOG_DEBUG, "[INFO]: Client chooses to play on gameserver %d\n", ls_chosenGameServer );
delete p_rgsl;
p_rgsl = NULL;
// free raw pack buffer
free( rraw );
rraw = NULL;
// copy info about chosen game server
if( (ls_chosenGameServer>=1) && (ls_chosenGameServer<=255) )
{
for( i=0; i<(int)ls_nGameServersCount; i++ )
{
if( gameservers_info[i].gsID == ls_chosenGameServer )
{
memcpy( &(myGameServerIP), &(gameservers_info[i].gsIP), 4 );
myGameServerPort = gameservers_info[i].gsPort;
break;
}
}
//g_cfg.PlayGameServerNo = ls_chosenGameServer; // PlayGameServerNo removed from config
log_error( LOG_DEBUG, "we play on GS #%d: %d.%d.%d.%d:%d\n",
ls_chosenGameServer,
(int)myGameServerIP[0], (int)myGameServerIP[1], (int)myGameServerIP[2], (int)myGameServerIP[3],
myGameServerPort );
}
else
{
log_error( LOG_ERROR, "Client choosed GS ID %d, which is INVALID! must be [1..255]\n", ls_chosenGameServer );
}
// PlayOK / PlayFail
// login server now sends to client if client can play o selected server
rcvdLen = 0;
//rraw = L2PacketReceive( sr, netTimeout, 0, &rcvdLen );
rraw = L2PacketReceive_malloc( sr, netTimeout*1000, &rcvdLen );
if( !rraw ) { log_error( LOG_ERROR, "receive failed!\n" ); goto l_netError; }
log_error( LOG_DEBUG, "ProcessClient(): rcvd %u bytes of response to RequestServerLogin packet from server.\n", rcvdLen );
// resend it to client
sentLen = 0;
L2PacketSend2( rraw, scl, netTimeout*1000, &sentLen );
log_error( LOG_DEBUG, "ProcessClient(): resent %u bytes of response to RequestServerLogin packet to client.\n", sentLen );
if( sentLen != rcvdLen ) { log_error( LOG_ERROR, "rcvd != sent! (%u != %u)\n", rcvdLen, sentLen ); goto l_netError; }
pack = new L2LoginPacket();
pack->setBytes( rraw, sentLen );
pack->setDynamicBFKey( ls_newBFKey, 16 );
pack->decodeBlowfish( false );
// out...
//printf( "\nResponse to RequestServerLogin:\n" );
//pack->dumpToFile( stdout );
// parse result
ptype = pack->getPacketType();
if( ptype == 0x06 ) // PlayFail
{
log_error( LOG_ERROR, "---- PlayFail! ----\n" );
goto l_netError;
}
else if( ptype == 0x07 ) // PlayOK!
{
log_error( LOG_DEBUG, "++++ PlayOK! ++++\n" );
p_pok = new L2Login_PlayOK();
p_pok->setBytes( pack->getBytesPtr(), pack->getPacketSize() );
p_pok->read_sessionKey2( ls_sessionKey2 );
delete p_pok;
p_pok = NULL;
log_error( LOG_DEBUGDUMP, "SessionKey#2: " );
for( i=0; i<8; i++ ) log_error_np( LOG_DEBUGDUMP, "%02X ", ls_sessionKey2[i] );
log_error_np( LOG_DEBUGDUMP, "\n" );
}
else
{
log_error( LOG_ERROR, "=====================================\n" );
log_error( LOG_ERROR, "???? Unknown packet type 0x%02X! ????\n",
(unsigned int)ptype );
pack->dumpToFile( stdout );
log_error( LOG_ERROR, "=====================================\n" );
goto l_netError;
}
// delete...
delete pack;
pack = NULL;
// free raw packet data
free( rraw );
rraw = NULL;
// mark as connected OK
retVal = true;
goto l_closeSockets; // jump over netError handler
l_netError:
log_error( LOG_ERROR, "ProcessClient(): some network error :\\\n" );
if( rraw ) free( rraw );
rraw = NULL;
retVal = false; // mark as connection failed
l_closeSockets:
// close sockets
L2PNet_shutdown( scl );
L2PNet_closesocket( scl );
L2PNet_shutdown( sr );
L2PNet_closesocket( sr );
state = LCST_OFFLINE;
// save data
memcpy( this->sessionKey1, ls_sessionKey1, sizeof(ls_sessionKey1) );
memcpy( this->sessionKey2, ls_sessionKey2, sizeof(ls_sessionKey2) );
this->gsPort = myGameServerPort;
memcpy( this->gsIP, myGameServerIP, sizeof(myGameServerIP) );
// notify radar window about disconnection
this->postNotify( LCN_STATECHANGE, 0 ); // disconnected
log_error( LOG_DEBUG, "ProcessClient(): ended client processing. Returning %d\n",
(int)retVal );
// return indicator
return retVal;
}
void LoginClient::setNotifyWindow( HWND notifyHwnd, UINT notifyMsg )
{
this->hWndNotify = notifyHwnd;
this->uMsgNotify = notifyMsg;
}
extern HWND g_radardll_hwnd;
void LoginClient::postNotify( WPARAM wParam, LPARAM lParam )
{
//if( hWndNotify == NULL || (uMsgNotify < WM_USER) ) return;
//PostMessage( hWndNotify, uMsgNotify, wParam, lParam );
PostMessage( g_radardll_hwnd, (WM_USER+106), wParam, lParam );
}
LoginClient *g_login_client = NULL;

43
l2detect/LoginClient.h Normal file
View File

@@ -0,0 +1,43 @@
#ifndef FAKELOGIN_LOGINCLIENT_H_
#define FAKELOGIN_LOGINCLIENT_H_
// client state
#define LCST_OFFLINE 0 // not connected to LS :)
#define LCST_CONNECTED 1 // just connected to LS
#define LCST_AUTHED_GG 2 // passed GG auth
#define LCST_AUTHED_LOGIN 3 // authorized
#define LCST_AUTH_ERROR 4 // auth error
// window notification wParam
#define LCN_STATECHANGE 1 // lParam will hold new state
class LoginClient
{
public:
LoginClient();
virtual ~LoginClient();
public:
bool ProcessClient( SOCKET scl );
bool getSessionKeys( unsigned char *sKey1, unsigned char *sKey2 );
bool getPlayServerAddress( unsigned char *ip, unsigned short int *port );
public:
void setNotifyWindow( HWND notifyHwnd, UINT notifyMsg );
void postNotify( WPARAM wParam, LPARAM lParam );
public:
int getState() { return state; }
protected:
int state;
protected:
unsigned char sessionKey1[8];
unsigned char sessionKey2[8];
unsigned char gsIP[4];
unsigned short int gsPort;
protected:
// notify window
HWND hWndNotify;
UINT uMsgNotify;
};
extern LoginClient *g_login_client;
#endif /*FAKELOGIN_LOGINCLIENT_H_*/

275
l2detect/LoginListener.cpp Normal file
View File

@@ -0,0 +1,275 @@
#include "stdafx.h"
#include "ConfigIni.h"
#include "Logger.h"
#include "LoginListener.h"
#include "LoginClient.h"
#include "GameListener.h"
extern class CConfig g_cfg; // declared in main.cpp
extern class GameListener *g_pgame; // declared in main.cpp
extern HWND g_radardll_hwnd; // declared in RadarDllWnd.cpp
struct FLLT_INFO
{
class LoginListener *cls;
};
void FLS_Thread_freeInfo( struct FLLT_INFO *pinfo )
{
if( pinfo->cls->m_listen_socket != INVALID_SOCKET )
{
L2PNet_shutdown( pinfo->cls->m_listen_socket );
L2PNet_closesocket( pinfo->cls->m_listen_socket );
pinfo->cls->m_listen_socket = INVALID_SOCKET;
}
if( pinfo->cls->m_hThread ) CloseHandle( pinfo->cls->m_hThread );
pinfo->cls->m_hThread = NULL;
pinfo->cls->m_signal = 0;
free( pinfo );
log_error( LOG_DEBUG, "FLS_Thread(): thread info struct freed\n" );
}
DWORD WINAPI LoginListener::FLS_Thread( LPVOID lpParam )
{
struct FLLT_INFO *pinfo = (struct FLLT_INFO *)lpParam;
lpParam = NULL;
if( !pinfo )
{
log_error( LOG_ERROR, "FLS_Thread(): lpParam is NULL! Exit\n" );
return 0;
}
class LoginListener *cls = pinfo->cls;
if( !cls )
{
log_error( LOG_ERROR, "FLS_Thread(): pinfo->cls is NULL! Exit\n" );
FLS_Thread_freeInfo( pinfo );
return 0;
}
cls->m_listen_socket = INVALID_SOCKET;
//DWORD wait_res = 0;
//SOCKET s = sock_tcp_create();
SOCKET s = L2PNet_TCPsocket_create( true );
if( s == INVALID_SOCKET )
{
log_error( LOG_ERROR, "FLS_Thread(): socket create failed!\n" );
FLS_Thread_freeInfo( pinfo );
return 0;
}
int mb_yes = 0;
int bind_fail = 0;
ll_bind:
bind_fail = L2PNet_bind( s, g_cfg.FakeListenLoginIP, (unsigned short)g_cfg.FakeListenLoginPort );
if( bind_fail )
{
log_error( LOG_ERROR, "FLS_Thread(): socket bind at %s:%d failed\n",
g_cfg.FakeListenLoginIP, g_cfg.FakeListenLoginPort );
int wsaerr = L2PNet_WSAGetLastError();
if( wsaerr == WSAEADDRINUSE )
{
wchar_t errmsg[256];
wsprintfW( errmsg, L"<EFBFBD><EFBFBD><EFBFBD><EFBFBD> %S:%d <20><><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>!\n"
L"<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD> <20><><EFBFBD>?",
g_cfg.FakeListenLoginIP, g_cfg.FakeListenLoginPort );
mb_yes = MessageBoxW( g_radardll_hwnd, errmsg, L"L2Detect: <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>!", MB_ICONSTOP | MB_YESNO );
if( mb_yes == IDYES ) goto ll_bind;
}
FLS_Thread_freeInfo( pinfo );
return 0;
}
if( L2PNet_listen( s ) )
{
log_error( LOG_ERROR, "FLS_Thread(): listen() failed\n" );
FLS_Thread_freeInfo( pinfo );
return 0;
}
cls->m_listen_socket = s;
log_error( LOG_DEBUG, "FLS_Thread(): started, listening at %s:%d\n",
g_cfg.FakeListenLoginIP, g_cfg.FakeListenLoginPort );
// raise thread priority
if( !SetThreadPriority( GetCurrentThread(), THREAD_PRIORITY_ABOVE_NORMAL ) )
log_error( LOG_WARNING, "FLS_Thread(): raise thread priority failed!\n" );
int r = 0;
char clientIP[32] = {0};
unsigned short clientPort = 0;
SOCKET scl = INVALID_SOCKET;
int rdyR = 0, rdyW = 0; // ready to recv/send
unsigned int scode = 0; // signal to thread
int should_exit = 0;
while( 1 )
{
should_exit = 0;
//r = sock_tcp_wait_ready_to_recv( s, 0, 500000 );
rdyR = 0;
r = L2PNet_select( s, L2PNET_SELECT_READ, 500, &rdyR, &rdyW );
scode = cls->getLastSignal();
if( scode == FLLS_STOP )
{
log_error( LOG_DEBUG, "FLS_Thread(): exit signal\n" );
should_exit = 1;
}
if( should_exit ) break; // break while()
if( r == -1 )
{
log_error( LOG_ERROR, "FLS_Thread(): socket select() error\n" );
break;
}
if( r == 1 && rdyR )
{
//log_error( LOG_DEBUG, "FLS_Thread(): Somebody connected? :)\n" );
clientIP[0] = 0;
clientPort = 0;
scl = INVALID_SOCKET;
//scl = sock_tcp_accept( s, clientIP, &clientPort );
scl = L2PNet_accept( s, clientIP, &clientPort );
if( scl == INVALID_SOCKET )
{
log_error( LOG_ERROR, "FLS_Thread(): accept() failed...\n" );
}
else
{
//log_error( LOG_DEBUG, "FLS_Thread(): accepted client %s:%d\n", clientIP, clientPort );
log_error( LOG_OK, "LoginListener: accepted client %s:%d\n", clientIP, clientPort );
LoginClient lc;
if( lc.ProcessClient( scl ) )
{
unsigned char sKey1[8] = {0,0,0,0, 0,0,0,0};
unsigned char sKey2[8] = {0,0,0,0, 0,0,0,0};
struct PlayServerInfo sinfo;
lc.getSessionKeys( sKey1, sKey2 );
lc.getPlayServerAddress( sinfo.ip, &(sinfo.port) );
// ONLY IN OUTGAME MODE stop listener after successful client acception
if( g_cfg.isInGameMode == false )
{
// stop listener after successful client acception
log_error( LOG_DEBUG, "FLS_Thread(): LoginListener stopping self in outgame mode, "
"after client accepted, freeing port %s:%d\n",
g_cfg.FakeListenLoginIP, g_cfg.FakeListenLoginPort );
//cls->signalStop();
should_exit = 1;
}
if( !g_pgame )
{
log_error( LOG_ERROR, "FLS_Thread(): Game listener is NULL????" );
}
else
{
// set play server info to game listener
g_pgame->setPlayServerInfo( &sinfo );
}
}
}
} // somebody connected?
if( should_exit ) break; // break while()
} // while(1)
//sock_tcp_close_shutdown( s, SD_BOTH );
// network sockets clenup done by FLS_Thread_freeInfo()
FLS_Thread_freeInfo( pinfo );
log_error( LOG_DEBUG, "FLS_Thread() ended\n" );
return 0;
}
/// class
LoginListener::LoginListener()
{
this->_initNull();
}
LoginListener::~LoginListener()
{
if( this->m_hThread ) CloseHandle( this->m_hThread );
this->_initNull();
}
bool LoginListener::start()
{
// cleanup ?
if( this->m_hThread ) CloseHandle( this->m_hThread );
this->_initNull();
// alloc thread info struct
struct FLLT_INFO *pinfo = (struct FLLT_INFO *)malloc( sizeof( struct FLLT_INFO ) );
if( !pinfo ) return false;
// fill info
pinfo->cls = this;
// create thread object
this->m_hThread = NULL;
DWORD dwTID = 0;
this->m_hThread = (HANDLE)_beginthreadex(
NULL, // security
0, // stack size
(unsigned int (__stdcall*)(void *))FLS_Thread, // thread function
(void *)pinfo, // thread function argument - lpParam
0, // flags
(unsigned int *)(&dwTID) );
if( !this->m_hThread )
{
free( pinfo );
return false;
}
return true;
}
bool LoginListener::waitStopped( unsigned int timeoutMsec )
{
if( !this->m_hThread ) return true;
DWORD wait_res = WaitForSingleObject( this->m_hThread, (DWORD)timeoutMsec );
if( wait_res != WAIT_OBJECT_0 )
{
log_error( LOG_DEBUG, "LoginListener::waitStopped(): WaitForSingleObject() returned 0x%08X\n", wait_res );
if( wait_res == WAIT_TIMEOUT ) log_error( LOG_DEBUG, "LoginListener::waitStopped(): WAIT_TIMEOUT\n" );
return false;
}
// wait OK, close kernel objects
if( this->m_hThread ) CloseHandle( this->m_hThread );
// initialize self
this->_initNull();
return true;
}
void LoginListener::terminateThread()
{
if( this->m_hThread )
{
TerminateThread( this->m_hThread, 0xBAADF00D );
CloseHandle( this->m_hThread );
this->m_hThread = NULL;
this->m_signal = 0;
// thread resources
if( m_listen_socket != INVALID_SOCKET )
{
//sock_tcp_close_shutdown( m_listen_socket, SD_BOTH );
L2PNet_shutdown( m_listen_socket );
L2PNet_closesocket( m_listen_socket );
}
m_listen_socket = INVALID_SOCKET;
}
}
void LoginListener::_initNull()
{
m_hThread = NULL;
m_signal = 0;
// thread resources
m_listen_socket = INVALID_SOCKET;
}
bool LoginListener::isRunning() const
{
if( this->m_hThread != NULL ) return true;
return false;
}

34
l2detect/LoginListener.h Normal file
View File

@@ -0,0 +1,34 @@
#ifndef FAKELOGINLISTENER_H_
#define FAKELOGINLISTENER_H_
// signals to thread
#define FLLS_STOP 1
class LoginListener
{
friend void FLS_Thread_freeInfo( struct FLLT_INFO *pinfo );
protected:
static DWORD WINAPI FLS_Thread( LPVOID lpParam );
public:
LoginListener();
virtual ~LoginListener();
public:
bool start();
void signal( unsigned int code ) { this->m_signal = code; }
void signalStop() { this->signal( FLLS_STOP ); }
bool waitStopped( unsigned int timeoutMsec );
unsigned int getLastSignal() const { return this->m_signal; }
void setLastSignal( unsigned int code ) { this->m_signal = code; }
void terminateThread();
public:
bool isRunning() const;
protected:
void _initNull();
protected:
HANDLE m_hThread;
unsigned int m_signal;
// thread resources
SOCKET m_listen_socket;
};
#endif /*FAKELOGINLISTENER_H_*/

204
l2detect/NpcArray.cpp Normal file
View File

@@ -0,0 +1,204 @@
#include "stdafx.h"
#include "NpcArray.h"
#include "Logger.h"
#include "WorldObjectTree.h"
#include "RadarDllWnd.h"
L2Npc *npc_array[NPCA_MAX_NPCS];
CRITICAL_SECTION cs_npc_array;
//HWND npcArray_updateHWND;
//UINT npcArray_updateMSG;
// forward
//void NpcArray_PostUpdateMessage();
void NpcArray_Init()
{
//npcArray_updateHWND = NULL;
//npcArray_updateMSG = 0;
InitializeCriticalSection( &cs_npc_array );
int i;
for( i=0; i<NPCA_MAX_NPCS; i++ ) npc_array[i] = new L2Npc();
}
void NpcArray_Free()
{
NpcArray_Lock();
int i;
for( i=0; i<NPCA_MAX_NPCS; i++ )
{
if( npc_array[i] != NULL )
{
delete npc_array[i];
npc_array[i] = NULL;
}
}
NpcArray_Unlock();
DeleteCriticalSection( &cs_npc_array );
}
void NpcArray_AddNpcInfo( L2Npc *pNpcInfo )
{
NpcArray_Lock();
int idx = -1;
L2OBJECT_TYPE type;
/*BOOL bRet = */WorldObjectTree_GetInfoByObjectID( pNpcInfo->objectID, &type, &idx );
//
if( (idx == -1) || (type != L2OT_NPC) )
{
// Add new npc info
idx = NpcArray_FindFreeIndex();
if( idx == -1 )
{
NpcArray_Unlock();
return;
}
if( !npc_array[idx] ) npc_array[idx] = new L2Npc();
if( !npc_array[idx] )
{
NpcArray_Unlock();
return;
}
memcpy( npc_array[idx], pNpcInfo, sizeof(class L2Npc) );
//log_error( LOG_OK, "NpcArray: Added new[%d]: [%S] [%S] (%d,%d,%d) tpml %u, oid %u\n",
// idx, name, title, x,y,z, templateID, objectID );
// add to WorldObjectTree
WorldObjectTree_AddObject( pNpcInfo->objectID, L2OT_NPC, idx );
// add to radar window
RadarWnd_AddNpc( pNpcInfo->objectID );
}
else if( (idx>=0) && (idx<NPCA_MAX_NPCS) && (type==L2OT_NPC) )
{
// update info on existing NPC
if( !npc_array[idx] )
{
// try to allocate!
npc_array[idx] = new L2Npc();
if( !npc_array[idx] )
{
NpcArray_Unlock();
return;
}
}
memcpy( npc_array[idx], pNpcInfo, sizeof(class L2Npc) );
//log_error( LOG_OK, "NpcArray: Updated[%d]: [%S] [%S] (%d,%d,%d) tpml %u, oid %u\n",
// idx, name, title, x,y,z, templateID, objectID );
RadarWnd_UpdNpc( npc_array[idx]->objectID );
}
NpcArray_Unlock();
}
void NpcArray_DelNPC( unsigned int objectID )
{
NpcArray_Lock();
int idx = NpcArray_FindNPCByObjectID( objectID );
if( idx == -1 )
{
NpcArray_Unlock();
return;
}
if( npc_array[idx] )
{
npc_array[idx]->setUnused();
}
//log_error( LOG_OK, "NpcArray: deleted " );
// delete also from world object tree
WorldObjectTree_DelObject( objectID );
NpcArray_Unlock();
// del from radar window
RadarWnd_DelNpc( objectID );
}
void NpcArray_DelNPCByIdx( int idx )
{
if( idx<0 || (idx>=NPCA_MAX_NPCS) ) return;
NpcArray_Lock();
if( npc_array[idx] )
{
unsigned int objectID = npc_array[idx]->objectID;
npc_array[idx]->setUnused();
//log_error( LOG_OK, "NpcArray: deleted npc %u from index OK\n", objectID, idx );
// delete from world object tree
WorldObjectTree_DelObject( objectID );
// del from radar window
RadarWnd_DelNpc( objectID );
}
NpcArray_Unlock();
}
void NpcArray_Lock()
{
EnterCriticalSection( &cs_npc_array );
}
void NpcArray_Unlock()
{
LeaveCriticalSection( &cs_npc_array );
}
int NpcArray_FindNPCByObjectID( unsigned int objectID )
{
int ret = -1;
int i;
NpcArray_Lock();
for( i=0; i<NPCA_MAX_NPCS; i++ )
{
if( npc_array[i] == NULL ) continue;
if( npc_array[i]->objectID == objectID )
{
ret = i;
break;
}
}
NpcArray_Unlock();
return ret;
}
int NpcArray_FindFreeIndex()
{
int i;
NpcArray_Lock();
for( i=0; i<NPCA_MAX_NPCS; i++ )
{
if( npc_array[i] == NULL )
{
npc_array[i] = new L2Npc(); // allocate new
npc_array[i]->setUnused(); // and set as unused
NpcArray_Unlock();
return i;
}
if( npc_array[i]->isUnused() )
{
NpcArray_Unlock();
return i;
}
}
NpcArray_Unlock();
return -1;
}
//void NpcArray_SetUpdateCommand( HWND hWnd, UINT uMsg )
//{
// npcArray_updateHWND = hWnd;
// npcArray_updateMSG = uMsg;
//}
//void NpcArray_PostUpdateMessage()
//{
// if( !npcArray_updateHWND ) return;
// if( npcArray_updateMSG < WM_USER ) return;
// PostMessage( npcArray_updateHWND, npcArray_updateMSG, 0, 0 );
//}
void NpcArray_DeleteAll()
{
NpcArray_Lock();
int i;
for( i=0; i<NPCA_MAX_NPCS; i++ )
{
if( npc_array[i] ) npc_array[i]->setUnused();
}
//npcArray_count = 0;
NpcArray_Unlock();
}

24
l2detect/NpcArray.h Normal file
View File

@@ -0,0 +1,24 @@
#ifndef H_NPC_ARRAY
#define H_NPC_ARRAY
#define NPCA_MAX_NPCS 512
extern L2Npc *npc_array[NPCA_MAX_NPCS];
void NpcArray_Init();
void NpcArray_Free();
void NpcArray_DeleteAll();
void NpcArray_AddNpcInfo( L2Npc *pNpcInfo );
void NpcArray_DelNPC( unsigned int objectID );
void NpcArray_DelNPCByIdx( int idx );
void NpcArray_Lock();
void NpcArray_Unlock();
int NpcArray_FindNPCByObjectID( unsigned int objectID );
int NpcArray_FindFreeIndex();
//void NpcArray_SetUpdateCommand( HWND hWnd, UINT uMsg );
#endif

347
l2detect/PacketInjector.cpp Normal file
View File

@@ -0,0 +1,347 @@
#include "stdafx.h"
#include "GameClient.h"
#include "PacketInjector.h"
#include "Logger.h"
#include "ConfigIni.h"
extern class GameClient *g_game_client; // in main.cpp
extern class CConfig g_cfg; // in main.cpp
void PGen_Action( unsigned int oid, int x, int y, int z, unsigned char useShift )
{
if( !g_game_client ) return;
L2Game_Action p;
p.create( oid, x, y, z, useShift );
unsigned char bytes[32];
memcpy( bytes, p.getBytesPtr(), p.getPacketSize() );
g_game_client->InjectPacketToServer( bytes, p.getPacketSize(), true );
}
void PGen_AttackRequest( unsigned int oid, int x, int y, int z, unsigned char useShift )
{
L2GamePacket p;
p.setPacketType( 0x01 ); // AttackRequest
p.writeUInt( oid );
p.writeInt( x );
p.writeInt( y );
p.writeInt( z );
p.writeUChar( useShift );
g_game_client->InjectPacketToServer( (unsigned char *)p.getBytesPtr(), p.getPacketSize(), true );
}
void PGen_UseItem( unsigned int oid )
{
if( !g_game_client ) return;
L2Game_UseItem p;
p.create( oid );
unsigned char bytes[32];
memcpy( bytes, p.getBytesPtr(), p.getPacketSize() );
g_game_client->InjectPacketToServer( bytes, p.getPacketSize(), true );
}
void PGen_RequestJoinParty( const wchar_t *invitePlayer, unsigned int lootRules )
{
if( !g_game_client ) return;
L2Game_RequestJoinParty p;
p.create( invitePlayer, lootRules );
g_game_client->InjectPacketToServer( const_cast<unsigned char *>(p.getBytesPtr()), p.getPacketSize(), true );
}
void PGen_RequestOustPartyMember( const wchar_t *dismissPlayer )
{
if( !dismissPlayer ) return;
L2GamePacket p;
p.writeReset();
p.writeUChar( 0x45 );
p.writeUnicodeString( dismissPlayer );
g_game_client->InjectPacketToServer( (unsigned char *)p.getBytesPtr(), p.getPacketSize(), true );
}
void PGen_GameGuardReply_L2J()
{
L2GamePacket pack;
pack.setPacketType( 0xCB ); // GameGuardReply
pack.writeUInt( 0x78F0977F );
pack.writeUInt( 0xD6E63C04 );
pack.writeUInt( 0x89F60C71 );
pack.writeUInt( 0x70069EDD );
g_game_client->InjectPacketToServer( (unsigned char *)pack.getBytesPtr(), pack.getPacketSize(), true );
}
void PGen_RequestTargetCanceld( bool abortCast )
{
L2GamePacket pack;
pack.setPacketType( 0x48 ); // RequestTargetCanceld
pack.writeH( abortCast ? 0x00 : 0x01 ); // abort cast or cancel target
g_game_client->InjectPacketToServer( (unsigned char *)pack.getBytesPtr(), pack.getPacketSize(), true );
}
/* public final static int ALL = 0;
public final static int SHOUT = 1; //!
public final static int TELL = 2;
public final static int PARTY = 3; //#
public final static int CLAN = 4; //@
public final static int GM = 5;
public final static int PETITION_PLAYER = 6; // used for petition
public final static int PETITION_GM = 7; //* used for petition
public final static int TRADE = 8; //+
public final static int ALLIANCE = 9; //$
public final static int ANNOUNCEMENT = 10;
public final static int PARTYROOM_ALL = 16; //(Red)
public final static int PARTYROOM_COMMANDER = 15; //(Yellow)
public final static int HERO_VOICE = 17;
public final static int BATTLEFIELD = 20; */
void PGen_Say2C( unsigned int channelID, const wchar_t *text, const wchar_t *player_to /*= NULL*/ )
{
L2GamePacket pack;
pack.setPacketType( 0x49 ); // Say2
pack.writeS( text ); // <20><><EFBFBD><EFBFBD><EFBFBD>
pack.writeD( channelID ); // <20><><EFBFBD> <20><><EFBFBD><EFBFBD>
// <20><><EFBFBD><EFBFBD> <20><><EFBFBD> <20><><EFBFBD><EFBFBD> = <20><>, <20> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD> <20><><EFBFBD><EFBFBD>, <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20> <20><><EFBFBD> <20> <20><><EFBFBD><EFBFBD><EFBFBD>
if( (channelID == 2 /*TELL*/) && player_to ) pack.writeS( player_to );
g_game_client->InjectPacketToServer( (unsigned char *)pack.getBytesPtr(), pack.getPacketSize(), true );
}
void PGen_MoveBackwardToLocation( int dst_x, int dst_y, int dst_z, int src_x, int src_y, int src_z )
{
L2GamePacket p;
p.setPacketType( 0x0F ); // MoveBackwardToLocation
p.writeD( dst_x );
p.writeD( dst_y );
p.writeD( dst_z );
p.writeD( src_x );
p.writeD( src_y );
p.writeD( src_z );
p.writeD( 0x01 ); // 0x01 = for movement was used mouse
g_game_client->InjectPacketToServer( (unsigned char *)p.getBytesPtr(), p.getPacketSize(), true );
}
void PGen_RequestBypassToserver( const wchar_t *bypassStr )
{
L2GamePacket p;
p.setPacketType( 0x23 ); // RequestBypassToServer
p.writeS( bypassStr );
g_game_client->InjectPacketToServer( (unsigned char *)p.getBytesPtr(), p.getPacketSize(), true );
}
void PGen_RequestLinkHtml( const wchar_t *link )
{
L2GamePacket p;
p.setPacketType( 0x22 ); // RequestLinkHtml
p.writeS( link );
g_game_client->InjectPacketToServer( (unsigned char *)p.getBytesPtr(), p.getPacketSize(), true );
}
void PGen_RequestActionUse( unsigned int actionId, bool ctrlPressed, bool shiftPressed )
{
L2GamePacket p;
p.setPacketType( 0x56 ); // RequestActionUse
p.writeUInt( actionId );
p.writeUInt( ctrlPressed ? 0x01 : 0x00 );
p.writeC( shiftPressed ? 0x01 : 0x00 );
g_game_client->InjectPacketToServer( (unsigned char *)p.getBytesPtr(), p.getPacketSize(), true );
}
void PGen_RequestAutoSoulshot( unsigned int itemID, bool enable )
{
L2GamePacket p;
p.setPacketType( 0xD0 );
p.writeUShort( 0x000D ); // D0:000D RequestAutoSoulshot
p.writeUInt( itemID );
enable ? p.writeUInt( 1 ) : p.writeUInt( 0 );
g_game_client->InjectPacketToServer( (unsigned char *)p.getBytesPtr(), p.getPacketSize(), true );
}
/** Client: Len 13 [RequestDispel]
0D 00
D0 4E 00 // D0:004E RequestDispel D0:004B RequestExDspel (G.Final)
4B 05 00 00 // skillID 1355 (PoWater?)
01 00 00 00 // skillLvl lvl 1 **/
void PGen_RequestDispel( unsigned int skillID )
{
// only since Gracia T2
if( g_cfg.L2_version < (int)L2_VERSION_T2 ) return;
UserBuff buf;
g_game_client->ai.buffs.getBuffnfoBySkillId( skillID, &buf );
if( (buf.skillID == 0) || (buf.skillLvl == 0) ) return; // error, no such buff!
// create packet
L2GamePacket p;
p.setPacketType( 0xD0 );
// opcode is different in Gracia Final
if( g_cfg.L2_version <= (int)L2_VERSION_T22 )
p.writeUShort( 0x004E ); // D0:004E RequestDispel L2 <= T22
else
p.writeUShort( 0x004B ); // D0:004B RequestDispel L2 >= T23 Gracia Final
p.writeUInt( skillID );
p.writeUInt( buf.skillLvl );
g_game_client->InjectPacketToServer( (unsigned char *)p.getBytesPtr(), p.getPacketSize(), true );
}
void PGen_RequestMagicSkillUse( unsigned int skillID, unsigned int ctrlPressed, unsigned char shiftPressed )
{
L2GamePacket p;
p.setPacketType( 0x39 ); // RequestMagicSkillUse
p.writeUInt( skillID );
p.writeUInt( ctrlPressed );
p.writeUChar( shiftPressed );
g_game_client->InjectPacketToServer( (unsigned char *)p.getBytesPtr(), p.getPacketSize(), true );
}
void PGen_RequestWithdrawalParty()
{
L2GamePacket p;
p.setPacketType( 0x44 ); // RequestWithDrawalParty
g_game_client->InjectPacketToServer( (unsigned char *)p.getBytesPtr(), p.getPacketSize(), true );
}
void PGen_RequestChangePartyLeader( const wchar_t *playerName )
{
if( !playerName ) return;
L2GamePacket p;
p.setPacketType( 0xD0 ); // D0:000C RequestChangePartyLeader
p.writeUShort( 0x0000C );
p.writeUnicodeString( playerName );
g_game_client->InjectPacketToServer( (unsigned char *)p.getBytesPtr(), p.getPacketSize(), true );
}
// hack function, do not use!
// input: string consisting of sequence of hex chars, representing packet, starting from packet type
// packet length will be prefixed automatically!
// example: 1F39A400109ACB00003D2BFFFFA9F3FFFF00 - 1F Action packet, without packet len
void PGen_send_hackPacketHex_toServer( const char *szHexStr )
{
if( !szHexStr ) return;
int ll = (int)strlen( szHexStr );
if( ll % 2 ) return;
int nBytes = ll / 2;
int i;
unsigned char *bytebuffer = (unsigned char *)malloc( nBytes );
if( !bytebuffer ) return;
memset( bytebuffer, 0, nBytes );
//log_error_np( LOG_OK, "\ngame_sendPacketHex(): %d bytes\n", nBytes );
for( i=0; i<ll; i+=2 )
{
char c1 = szHexStr[i];
char c2 = szHexStr[i+1];
//log_error_np( LOG_OK, "Parsing byte [%d] %c%c... ", i/2, c1, c2 );
int i1 = 0;
int i2 = 0;
if( (c1>='0') && (c1<='9') ) i1 = 0 + c1 - '0';
if( (c1>='a') && (c1<='f') ) i1 = 10 + c1 - 'a';
if( (c1>='A') && (c1<='F') ) i1 = 10 + c1 - 'A';
if( (c2>='0') && (c2<='9') ) i2 = 0 + c2 - '0';
if( (c2>='a') && (c2<='f') ) i2 = 10 + c2 - 'a';
if( (c2>='A') && (c2<='F') ) i2 = 10 + c2 - 'A';
//log_error_np( LOG_OK, "%d * 16 + %d... ", i1, i2 );
unsigned char b = (unsigned char)( ((i1 << 4) | i2) & 0xFF );
//log_error_np( LOG_OK, "%d (%02X)\n", (int)b, b );
bytebuffer[i/2] = b;
}
L2GamePacket *pack = new L2GamePacket();
pack->writeReset();
pack->writeBytes( bytebuffer, nBytes );
g_game_client->InjectPacketToServer( (unsigned char *)pack->getBytesPtr(), pack->getPacketSize(), true );
delete pack;
pack = NULL;
}
void PGenC_NpcHtmlMessage( unsigned int npcObjectId, const wchar_t *text, unsigned int itemId )
{
L2GamePacket p;
p.setPacketType( 0x19 ); // NpcHtmlMessage
p.writeD( npcObjectId );
p.writeS( text );
p.writeD( itemId );
g_game_client->InjectPacketToClient( (unsigned char *)p.getBytesPtr(), p.getPacketSize() );
}
void PGenC_DeleteObject( unsigned int objectID )
{
L2GamePacket p;
p.setPacketType( 0x08 ); // DeleteObject
p.writeUInt( objectID );
g_game_client->InjectPacketToClient( (unsigned char *)p.getBytesPtr(), p.getPacketSize() );
}
void PGenC_MoveToLocation( unsigned int objectID, int x, int y, int z, int dx, int dy, int dz )
{
L2GamePacket p;
p.setPacketType( 0x2f ); // MoveToLocation
p.writeUInt( objectID );
p.writeD( dx );
p.writeD( dy );
p.writeD( dz );
p.writeD( x );
p.writeD( y );
p.writeD( z );
g_game_client->InjectPacketToClient( (unsigned char *)p.getBytesPtr(), p.getPacketSize() );
}
void PGenC_StopMove( unsigned int objectID, int x, int y, int z, unsigned int heading )
{
L2GamePacket p;
p.setPacketType( 0x47 ); // StopMove
p.writeUInt( objectID );
p.writeD( x );
p.writeD( y );
p.writeD( z );
p.writeUInt( heading );
g_game_client->InjectPacketToClient( (unsigned char *)p.getBytesPtr(), p.getPacketSize() );
}
void PGenC_CreatureSay( unsigned int objectID, unsigned int channelID, const wchar_t *senderName, const wchar_t *text )
{
L2GamePacket p;
p.setPacketType( 0x4A ); // CreatureSay
p.writeD( objectID ); // objectID
p.writeD( channelID ); // channelID (15 - Commander, 17 - Hero)
p.writeS( senderName ); // sender name
p.writeS( text ); // text
g_game_client->InjectPacketToClient( (unsigned char *)p.getBytesPtr(), p.getPacketSize() );
}
void PGenC_StatusUpdate( L2Player *pl )
{
L2GamePacket p;
// first send info about curHp/maxHp
p.setPacketType( 0x18 ); // StatusUpdate
p.writeUInt( pl->objectID );
p.writeUInt( 2 ); // number of attributes
// cur HP
p.writeUInt( 0x09 );
p.writeUInt( (unsigned int)pl->curHp );
// max HP
p.writeUInt( 0x0A );
p.writeUInt( (unsigned int)pl->maxHp );
g_game_client->InjectPacketToClient( (unsigned char *)p.getBytesPtr(), p.getPacketSize() );
// then send info about curMp/maxMp
p.setPacketType( 0x18 ); // StatusUpdate
p.writeUInt( pl->objectID );
p.writeUInt( 2 ); // number of attributes
// cur MP
p.writeUInt( 0x0B );
p.writeUInt( (unsigned int)pl->curHp );
// max MP
p.writeUInt( 0x0C );
p.writeUInt( (unsigned int)pl->maxHp );
g_game_client->InjectPacketToClient( (unsigned char *)p.getBytesPtr(), p.getPacketSize() );
//log_error( LOG_USERAI, "Injected StatusUpdate about [%S]\n", pl->charName );
}
void PGenC_ShowMiniMap( unsigned int mapID /*= 1665*/ )
{
L2GamePacket p;
p.setPacketType( 0xA3 ); // ShowMiniMap
p.writeUInt( mapID );
g_game_client->InjectPacketToClient( (unsigned char *)p.getBytesPtr(), p.getPacketSize() );
}

35
l2detect/PacketInjector.h Normal file
View File

@@ -0,0 +1,35 @@
#ifndef H_PGEN
#define H_PGEN
// to server
void PGen_Action( unsigned int oid, int x, int y, int z, unsigned char useShift );
void PGen_AttackRequest( unsigned int oid, int x, int y, int z, unsigned char useShift );
void PGen_GameGuardReply_L2J();
void PGen_MoveBackwardToLocation( int dst_x, int dst_y, int dst_z, int src_x, int src_y, int src_z );
void PGen_RequestActionUse( unsigned int actionId, bool ctrlPressed, bool shiftPressed );
void PGen_RequestAutoSoulshot( unsigned int itemID, bool enable );
void PGen_RequestBypassToserver( const wchar_t *bypassStr );
void PGen_RequestChangePartyLeader( const wchar_t *playerName );
void PGen_RequestDispel( unsigned int skillID );
void PGen_RequestJoinParty( const wchar_t *invitePlayer, unsigned int lootRules );
void PGen_RequestLinkHtml( const wchar_t *link );
void PGen_RequestMagicSkillUse( unsigned int skillID, unsigned int ctrlPressed, unsigned char shiftPressed );
void PGen_RequestOustPartyMember( const wchar_t *dismissPlayer );
void PGen_RequestTargetCanceld( bool abortCast );
void PGen_RequestWithdrawalParty();
void PGen_Say2C( unsigned int channelID, const wchar_t *text, const wchar_t *player_to = NULL );
void PGen_UseItem( unsigned int oid );
// to client
void PGenC_CreatureSay( unsigned int objectID, unsigned int channelID, const wchar_t *senderName, const wchar_t *text );
void PGenC_DeleteObject( unsigned int objectID );
void PGenC_MoveToLocation( unsigned int objectID, int x, int y, int z, int dx, int dy, int dz );
void PGenC_NpcHtmlMessage( unsigned int npcObjectId, const wchar_t *text, unsigned int itemId = 0 );
void PGenC_StatusUpdate( L2Player *pl );
void PGenC_StopMove( unsigned int objectID, int x, int y, int z, unsigned int heading );
void PGenC_ShowMiniMap( unsigned int mapID = 1665 );
// hack!..
void PGen_send_hackPacketHex_toServer( const char *szHexStr );
#endif

View File

@@ -0,0 +1,7 @@
set out=..\..\out\dist_L2Detect
rem Copy DLL
copy /y %2\%1.dll %2\%out%
rem Copy PDB
rem copy /y %2\%1.pdb %2\%out%

View File

@@ -0,0 +1,882 @@
#include "stdafx.h"
#include "Logger.h"
#include "ConfigIni.h"
#define PCODE_SELLLIST 0x06
#define PCODE_BUYLIST 0x07
#define PCODE_ITEMLIST 0x11
#define PCODE_TRADESTART 0x14
#define PCODE_TRADEOWNADD 0x1A
#define PCODE_TRADEOTHERADD 0x1B
#define PCODE_INVENTORYUPDATE 0x21
#define PCODE_WAREHOUSEDEPOSITLIST 0x41
#define PCODE_WAREHOUSEWITHDRAWLIST 0x42
#define PCODE_PRIVATESTORELISTSELL 0xA1
#define PCODE_PRIVATESTORELISTBUY 0xBE
#define PCODE_RELATIONCHANGED 0xCE
#define PCODE2_EXBUYSELLLITSTPACKET 0x00B7
extern class CConfig g_cfg;
int pconv_was_Init = 0;
int pconv_enabled = 0;
int pconv_epilogue = 0;
int pconv_table[256];
void ProtoConv_Init()
{
memset( pconv_table, 0, sizeof(pconv_table) );
//
pconv_table[ PCODE_SELLLIST ] = 1;
pconv_table[ PCODE_BUYLIST ] = 1;
pconv_table[ PCODE_ITEMLIST ] = 1;
pconv_table[ PCODE_TRADESTART ] = 1;
pconv_table[ PCODE_TRADEOWNADD ] = 1;
pconv_table[ PCODE_TRADEOTHERADD ] = 1;
pconv_table[ PCODE_INVENTORYUPDATE ] = 1;
pconv_table[ PCODE_WAREHOUSEDEPOSITLIST ] = 1;
pconv_table[ PCODE_WAREHOUSEWITHDRAWLIST ] = 1;
pconv_table[ PCODE_PRIVATESTORELISTSELL ] = 1;
pconv_table[ PCODE_PRIVATESTORELISTBUY ] = 1;
pconv_table[ PCODE_RELATIONCHANGED ] = 1;
//
pconv_was_Init = 1;
// disable protocol converter for Hellbound <=> Gracia
// enable conversion only T1/Hellbound => Gracia
//if( (g_cfg.L2_version <= L2_VERSION_T15) && (g_cfg.L2_client_version >= L2_VERSION_T2) )
// pconv_enabled = 1;
//if( (g_cfg.L2_version >= L2_VERSION_T2) && (g_cfg.L2_client_version <= L2_VERSION_T15) )
// pconv_enabled = 1;
// Gracia Epilogue Server:148 -> Client:146 protocol conversion
if( (g_cfg.GraciaEpilogueProtocol_148_hacks) &&
(g_cfg.OverrideGameProtocolVersion == 148) &&
(g_cfg.L2_client_version == L2_VERSION_T24) &&
(g_cfg.L2_version == L2_VERSION_T24) )
{
pconv_enabled = 1;
pconv_epilogue = 1;
}
if( pconv_enabled )
{
log_error( LOG_USERAI, "Enabled protocol converter\n" );
if( pconv_epilogue ) log_error( LOG_USERAI, "Protocol converter: Gracia Epilogue mode!\n" );
}
}
int ProtoConv_IsEnabled()
{
if( !pconv_was_Init ) ProtoConv_Init();
return pconv_enabled;
}
int ProtoConv_ConvExistsForPacket( unsigned char pcode )
{
if( !pconv_was_Init ) ProtoConv_Init();
return pconv_table[ pcode ];
}
bool ProtoConv_ConvertItemList( unsigned char *bytes, unsigned int len,
unsigned char **newBytes, unsigned int *newLen )
{
L2GamePacket ilo; // ItemList old
L2GamePacket iln; // ItemList new
ilo.setBytes( bytes, len );
unsigned char ptype = ilo.getPacketType();
iln.setPacketType( ptype ); // ptype must be == PCODE_ITEMLIST
//
int i = 0;
unsigned short temp_short;
unsigned int temp_int;
unsigned int objectID;
unsigned int itemID;
unsigned int count; // count of one stackable ITEM slot
unsigned long long int count64; // count of one stackable ITEM slot (for protocol >= Final)
unsigned short icount; // count of all used items SLOTS in inventory
//
//writeH(_showWindow ? 0x01 : 0x00);
temp_short = ilo.readUShort();
iln.writeUShort( temp_short );
//writeH(count);
icount = ilo.readUShort();
iln.writeUShort( icount );
//
for( i=0; i<(int)icount; i++ )
{
//writeH(temp.getItem().getType1()); // item type1
temp_short = ilo.readUShort();
iln.writeUShort( temp_short );
//writeD(temp.getObjectId());
objectID = ilo.readUInt();
iln.writeUInt( objectID );
//writeD(temp.getItemId());
itemID = ilo.readUInt();
iln.writeUInt( itemID );
//writeD(temp.getLocationSlot()); // T1
temp_int = ilo.readUInt();
iln.writeUInt( temp_int );
//writeD(temp.getCount());
if( !pconv_epilogue )
{
count = ilo.readUInt();
iln.writeUInt( count );
}
else
{
count64 = ilo.readUInt64();
iln.writeUInt64( count64 );
}
//writeH(temp.getItem().getType2()); // item type2
temp_short = ilo.readUShort();
iln.writeUShort( temp_short );
//writeH(temp.getCustomType1()); // item type3
temp_short = ilo.readUShort();
iln.writeUShort( temp_short );
//writeH(temp.isEquipped() ? 0x01 : 0x00);
temp_short = ilo.readUShort();
iln.writeUShort( temp_short );
//writeD(temp.getItem().getBodyPart());
temp_int = ilo.readUInt();
iln.writeUInt( temp_int );
//writeH(temp.getEnchantLevel()); // enchant level
temp_short = ilo.readUShort();
iln.writeUShort( temp_short );
//race tickets
//writeH(temp.getCustomType2()); // item type3
temp_short = ilo.readUShort();
iln.writeUShort( temp_short );
// writeD(temp.getAugmentation().getAugmentationId());
temp_int = ilo.readUInt();
iln.writeUInt( temp_int );
//writeD(temp.getMana());
temp_int = ilo.readUInt();
iln.writeUInt( temp_int );
// in gracia final elemental attributes are not Ds, they are Hs
if( g_cfg.L2_version <= L2_VERSION_T22 )
{
// T1
//writeD(temp.getAttackElementType());
temp_int = ilo.readUInt();
iln.writeUInt( temp_int );
//writeD(temp.getAttackElementPower());
temp_int = ilo.readUInt();
iln.writeUInt( temp_int );
int ia = 0;
for( ia=0; ia<6; ia++)
{
// element def attr(i)
temp_int = ilo.readUInt(); // 1
iln.writeUInt( temp_int );
}
}
else if( g_cfg.L2_version >= L2_VERSION_T23 )
{
//writeH(temp.getAttackElementType());
temp_short = ilo.readUShort();
iln.writeUShort( temp_short );
//writeH(temp.getAttackElementPower());
temp_short = ilo.readUShort();
iln.writeUShort( temp_short );
int ia = 0;
for( ia=0; ia<6; ia++)
{
// element def attr(i)
temp_short = ilo.readUShort(); // 1
iln.writeUShort( temp_short );
}
}
// isTimeLimitedItem() depends on version!!!!
// read last 4 bytes for each item in inv only if server is >= T2
temp_int = 0x00000000;
if( g_cfg.L2_version >= L2_VERSION_T2 )
{
//writeD(0x00);
temp_int = ilo.readUInt();
}
// write timeLimitedItem for each item in inv only if client is >= T2
if( g_cfg.L2_client_version >= L2_VERSION_T2 )
{
iln.writeUInt( temp_int );
}
// Gracia Epilogue has 3 Hs more
if( pconv_epilogue )
{
// do NOT read 3 enchant effects from original ItemList
// but don't write them to resulting ItemList
iln.writeH( 0 ); // Enchant effect 1
iln.writeH( 0 ); // Enchant effect 2
iln.writeH( 0 ); // Enchant effect 3
}
}
(*newLen) = iln.getPacketSize();
(*newBytes) = (unsigned char *)malloc( (*newLen) );
if( (*newBytes) )
{
memcpy( (*newBytes), iln.getBytesPtr(), (*newLen) );
return true;
}
log_error( LOG_ERROR, "ProtoConv_ItemList: some error after processing, "
"len = %u, newLen = 0x%p, (*newLen) = %u, (*newBytes) = 0x%p\n",
len, newLen, (*newLen), (*newBytes) );
(*newLen) = len;
(*newBytes) = bytes;
return false;
}
bool ProtoConv_ConvertInventoryUpdate( unsigned char *bytes, unsigned int len,
unsigned char **newBytes, unsigned int *newLen )
{
L2GamePacket ilo; // InventoryUpdate old
L2GamePacket iln; // InventoryUpdate new
ilo.setBytes( bytes, len );
unsigned char ptype = ilo.getPacketType();
iln.setPacketType( ptype ); // ptype must be == PCODE_INVENTORYUPDATE
//
int count = ilo.readH(); iln.writeH( (short)count );
// P.S. count <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> = 1 <20><> <20><><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>. <20><> <20><> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>...
int i, ie;
//unsigned short h;
//unsigned int d;
for( i=0; i<count; i++ )
{
iln.writeH( ilo.readH() ); // update type
iln.writeH( ilo.readH() ); // item type 1
iln.writeD( ilo.readD() ); // item object id
iln.writeD( ilo.readD() ); // item item id
iln.writeD( ilo.readD() ); // item location slot
iln.writeQ( ilo.readQ() ); // item count
iln.writeH( ilo.readH() ); // item type 2
iln.writeH( ilo.readH() ); // item custom type 1 (always 0x00)
iln.writeH( ilo.readH() ); // item is equipped
iln.writeD( ilo.readD() ); // item bodypart
iln.writeH( ilo.readH() ); // item enchant level
iln.writeH( ilo.readH() ); // item custom type 2 (pet name related..?)
iln.writeD( ilo.readD() ); // item aug id
iln.writeD( ilo.readD() ); // item mana
// T1 elementals
for( ie=0; ie<8; ie++ ) iln.writeH( ilo.readH() ); // element. attrs
// T2
iln.writeD( ilo.readD() ); // item time
// T24
// write enchant effects to new packet, but don't read them from source
iln.writeH(0x00); iln.writeH(0x00); iln.writeH(0x00);
}
//
(*newLen) = iln.getPacketSize();
(*newBytes) = (unsigned char *)malloc( (*newLen) );
if( (*newBytes) )
{
memcpy( (*newBytes), iln.getBytesPtr(), (*newLen) );
return true;
}
log_error( LOG_ERROR, "ProtoConv_InventoryUpdate: some error after processing, "
"len = %u, newLen = 0x%p, (*newLen) = %u, (*newBytes) = 0x%p\n",
len, newLen, (*newLen), (*newBytes) );
(*newLen) = len;
(*newBytes) = bytes;
return false;
}
bool ProtoConv_ConvertBuyList( unsigned char *bytes, unsigned int len,
unsigned char **newBytes, unsigned int *newLen )
{
L2GamePacket ilo; // BuyList old
L2GamePacket iln; // BuyList new
ilo.setBytes( bytes, len );
unsigned char ptype = ilo.getPacketType();
iln.setPacketType( ptype ); // ptype must be == PCODE_BUYLIST
//
iln.writeQ( ilo.readQ() ); // money
iln.writeD( ilo.readD() ); // buylist ID
int count = ilo.readH(); iln.writeH( (short)count ); // items count
int i, ie;
for( i=0; i<count; i++ )
{
iln.writeH( ilo.readH() ); // item type 1
iln.writeD( ilo.readD() ); // item object id
iln.writeD( ilo.readD() ); // item item id
iln.writeQ( ilo.readQ() ); // item count
iln.writeH( ilo.readH() ); // item type 2
iln.writeH( ilo.readH() ); // item custom type 1 (always 0x00)
iln.writeD( ilo.readD() ); // item bodypart
iln.writeH( ilo.readH() ); // item enchant level
iln.writeH( ilo.readH() ); // 0x00 ...
iln.writeH( ilo.readH() ); // 0x00
iln.writeQ( ilo.readQ() ); // price
// T1 elementals
for( ie=0; ie<8; ie++ ) iln.writeH( ilo.readH() ); // element. attrs
// T24
// write enchant effects to new packet, but don't read them from source
iln.writeH(0x00); iln.writeH(0x00); iln.writeH(0x00);
}
//
(*newLen) = iln.getPacketSize();
(*newBytes) = (unsigned char *)malloc( (*newLen) );
if( (*newBytes) )
{
memcpy( (*newBytes), iln.getBytesPtr(), (*newLen) );
return true;
}
log_error( LOG_ERROR, "ProtoConv_BuyList: some error after processing, "
"len = %u, newLen = 0x%p, (*newLen) = %u, (*newBytes) = 0x%p\n",
len, newLen, (*newLen), (*newBytes) );
(*newLen) = len;
(*newBytes) = bytes;
return false;
}
bool ProtoConv_ConvertSellList( unsigned char *bytes, unsigned int len,
unsigned char **newBytes, unsigned int *newLen )
{
L2GamePacket ilo; // SellList old
L2GamePacket iln; // SellList new
ilo.setBytes( bytes, len );
unsigned char ptype = ilo.getPacketType();
iln.setPacketType( ptype ); // ptype must be == PCODE_SELLLIST
//
iln.writeQ( ilo.readQ() ); // money
iln.writeD( ilo.readD() ); // seller npcID
int count = ilo.readH(); iln.writeH( (short)count ); // items count
int i, ie;
for( i=0; i<count; i++ )
{
iln.writeH( ilo.readH() ); // item type 1
iln.writeD( ilo.readD() ); // item object id
iln.writeD( ilo.readD() ); // item item id
iln.writeQ( ilo.readQ() ); // item count
iln.writeH( ilo.readH() ); // item type 2
iln.writeH( ilo.readH() ); // item custom type 1 (always 0x00)
iln.writeD( ilo.readD() ); // item bodypart
iln.writeH( ilo.readH() ); // item enchant level
iln.writeH( ilo.readH() ); // 0x00 ...
iln.writeH( ilo.readH() ); // item custom type 2
iln.writeQ( ilo.readQ() ); // reference price / 2
// T1 elementals
for( ie=0; ie<8; ie++ ) iln.writeH( ilo.readH() ); // element. attrs
// T24
// write enchant effects to new packet, but don't read them from source
iln.writeH(0x00); iln.writeH(0x00); iln.writeH(0x00);
}
//
(*newLen) = iln.getPacketSize();
(*newBytes) = (unsigned char *)malloc( (*newLen) );
if( (*newBytes) )
{
memcpy( (*newBytes), iln.getBytesPtr(), (*newLen) );
return true;
}
log_error( LOG_ERROR, "ProtoConv_SellList: some error after processing, "
"len = %u, newLen = 0x%p, (*newLen) = %u, (*newBytes) = 0x%p\n",
len, newLen, (*newLen), (*newBytes) );
(*newLen) = len;
(*newBytes) = bytes;
return false;
}
bool ProtoConv_ConvertRelationChanged( unsigned char *bytes, unsigned int len,
unsigned char **newBytes, unsigned int *newLen )
{
L2GamePacket ilo; // old
L2GamePacket iln; // new
ilo.setBytes( bytes, len );
unsigned char ptype = ilo.getPacketType();
iln.setPacketType( ptype ); // ptype must be == PCODE_RELATIONCHANGED
iln.writeD( 0x01 ); // T24 unknown - write to new, but dont read from old
iln.writeD( ilo.readD() ); // objectID
iln.writeD( ilo.readD() ); // relation
iln.writeD( ilo.readD() ); // auto attackable
iln.writeD( ilo.readD() ); // karma
iln.writeD( ilo.readD() ); // pvpFlag
//
(*newLen) = iln.getPacketSize();
(*newBytes) = (unsigned char *)malloc( (*newLen) );
if( (*newBytes) )
{
memcpy( (*newBytes), iln.getBytesPtr(), (*newLen) );
return true;
}
log_error( LOG_ERROR, "ProtoConv_RelationChanged: some error after processing, "
"len = %u, newLen = 0x%p, (*newLen) = %u, (*newBytes) = 0x%p\n",
len, newLen, (*newLen), (*newBytes) );
(*newLen) = len;
(*newBytes) = bytes;
return false;
}
bool ProtoConv_ConvertExBuySellList( unsigned char *bytes, unsigned int len, unsigned char **newBytes, unsigned int *newLen )
{
L2GamePacket ilo; // old
L2GamePacket iln; // new
int count, i, ia;
ilo.setBytes( bytes, len );
//
unsigned char ptype = ilo.getPacketType(); iln.setPacketType( ptype ); // opcode FE
iln.writeH( ilo.readH() ); // ext.opcode 00B7
iln.writeQ( ilo.readQ() ); // money
// first comes BuyList
iln.writeD( ilo.readD() ); // buylist ID
count = ilo.readH(); iln.writeH( (short)count );
for( i=0; i<count; i++ )
{
iln.writeH( ilo.readH() ); // type1
iln.writeD( ilo.readD() ); // oid
iln.writeD( ilo.readD() ); // iid
iln.writeQ( ilo.readQ() ); // count
iln.writeH( ilo.readH() ); // type2
iln.writeH( ilo.readH() ); // 00
iln.writeD( ilo.readD() ); // bodypart
iln.writeH( ilo.readH() ); // enchant level
iln.writeH( ilo.readH() ); // 0x00
iln.writeH( ilo.readH() ); // 0x00 // cust.type3?
iln.writeQ( ilo.readQ() ); // price
// elementals
for( ia=0; ia<8; ia++ ) iln.writeH( ilo.readH() ); // elements
// T24 enchant effects (dont read from old)
iln.writeH(0x00); iln.writeH(0x00); iln.writeH(0x00);
}
// next comes SellList
count = ilo.readH(); iln.writeH( (short)count );
for( i=0; i<count; i++ )
{
iln.writeH( ilo.readH() ); // type1
iln.writeD( ilo.readD() ); // oid
iln.writeD( ilo.readD() ); // iid
iln.writeQ( ilo.readQ() ); // count
iln.writeH( ilo.readH() ); // type2
iln.writeH( ilo.readH() ); // 00
iln.writeD( ilo.readD() ); // bodypart
iln.writeH( ilo.readH() ); // enchant level
iln.writeH( ilo.readH() ); // 0x00
iln.writeH( ilo.readH() ); // 0x00 // cust.type3?
iln.writeQ( ilo.readQ() ); // price
// elementals
for( ia=0; ia<8; ia++ ) iln.writeH( ilo.readH() ); // elements
// T24 enchant effects (dont read from old)
iln.writeH(0x00); iln.writeH(0x00); iln.writeH(0x00);
}
// next comes refund list
count = ilo.readH(); iln.writeH( (short)count );
for( i=0; i<count; i++ )
{
iln.writeD( ilo.readD() ); // refund list item idx
iln.writeD( ilo.readD() ); // iid
iln.writeQ( ilo.readQ() ); // count
iln.writeH( ilo.readH() ); // type2
iln.writeH( ilo.readH() ); // 00
iln.writeH( ilo.readH() ); // enchant level
iln.writeH( ilo.readH() ); // 00
iln.writeQ( ilo.readQ() ); // price
// elementals
for( ia=0; ia<8; ia++ ) iln.writeH( ilo.readH() ); // elements
// T24 enchant effects (dont read from old)
iln.writeH(0x00); iln.writeH(0x00); iln.writeH(0x00);
}
try
{
iln.writeC( ilo.readC() ); // _done
}
catch( L2P_ReadException& e )
{
UNREFERENCED_PARAMETER( e );
iln.writeC( 0x00 ); // :(
}
//
(*newLen) = iln.getPacketSize();
(*newBytes) = (unsigned char *)malloc( (*newLen) );
if( (*newBytes) )
{
memcpy( (*newBytes), iln.getBytesPtr(), (*newLen) );
return true;
}
log_error( LOG_ERROR, "ProtoConv_ExBuySellList: some error after processing, "
"len = %u, newLen = 0x%p, (*newLen) = %u, (*newBytes) = 0x%p\n",
len, newLen, (*newLen), (*newBytes) );
(*newLen) = len;
(*newBytes) = bytes;
return false;
}
bool ProtoConv_ConvertWarehouseDepositList( unsigned char *bytes, unsigned int len, unsigned char **newBytes, unsigned int *newLen )
{
L2GamePacket ilo; // old
L2GamePacket iln; // new
int count, i, ia;
ilo.setBytes( bytes, len );
//
unsigned char ptype = ilo.getPacketType(); iln.setPacketType( ptype ); // opcode FE
iln.writeH( ilo.readH() ); // WH type
iln.writeQ( ilo.readQ() ); // adena
count = ilo.readH(); iln.writeH( (short)count ); // items count
for( i=0; i<count; i++ )
{
iln.writeH( ilo.readH() ); // type1
iln.writeD( ilo.readD() ); // oid
iln.writeD( ilo.readD() ); // iid
iln.writeQ( ilo.readQ() ); // cnt
iln.writeH( ilo.readH() ); // type2
iln.writeH( ilo.readH() ); // cust type1
iln.writeD( ilo.readD() ); // b.part
iln.writeH( ilo.readH() ); // ench
iln.writeH( ilo.readH() ); // 00
iln.writeH( ilo.readH() ); // cust type2
iln.writeD( ilo.readD() ); // oid
iln.writeQ( ilo.readQ() ); // aug.related
for( ia=0; ia<8; ia++ ) iln.writeH( ilo.readH() ); // elementals
iln.writeD( ilo.readD() ); // mana
iln.writeD( ilo.readD() ); // time
// T24 enchant effects
iln.writeH(0x00); iln.writeH(0x00); iln.writeH(0x00);
}
//
(*newLen) = iln.getPacketSize();
(*newBytes) = (unsigned char *)malloc( (*newLen) );
if( (*newBytes) )
{
memcpy( (*newBytes), iln.getBytesPtr(), (*newLen) );
return true;
}
log_error( LOG_ERROR, "ProtoConv_WarehouseDepositList: some error after processing, "
"len = %u, newLen = 0x%p, (*newLen) = %u, (*newBytes) = 0x%p\n",
len, newLen, (*newLen), (*newBytes) );
(*newLen) = len;
(*newBytes) = bytes;
return false;
}
bool ProtoConv_ConvertWarehouseWithdrawList( unsigned char *bytes, unsigned int len, unsigned char **newBytes, unsigned int *newLen )
{
L2GamePacket ilo; // old
L2GamePacket iln; // new
int count, i, ia;
ilo.setBytes( bytes, len );
//
unsigned char ptype = ilo.getPacketType(); iln.setPacketType( ptype ); // opcode FE
iln.writeH( ilo.readH() ); // WH type
iln.writeQ( ilo.readQ() ); // adena
count = ilo.readH(); iln.writeH( (short)count ); // items count
for( i=0; i<count; i++ )
{
iln.writeH( ilo.readH() ); // type1
iln.writeD( ilo.readD() ); // oid
iln.writeD( ilo.readD() ); // iid
iln.writeQ( ilo.readQ() ); // cnt
iln.writeH( ilo.readH() ); // type2
iln.writeH( ilo.readH() ); // cust type1
iln.writeD( ilo.readD() ); // b.part
iln.writeH( ilo.readH() ); // ench
iln.writeH( ilo.readH() ); // 00
iln.writeH( ilo.readH() ); // cust type2
iln.writeD( ilo.readD() ); // oid
iln.writeQ( ilo.readQ() ); // aug.related
for( ia=0; ia<8; ia++ ) iln.writeH( ilo.readH() ); // elementals
iln.writeD( ilo.readD() ); // mana
iln.writeD( ilo.readD() ); // time
// T24 enchant effects
iln.writeH(0x00); iln.writeH(0x00); iln.writeH(0x00);
}
//
(*newLen) = iln.getPacketSize();
(*newBytes) = (unsigned char *)malloc( (*newLen) );
if( (*newBytes) )
{
memcpy( (*newBytes), iln.getBytesPtr(), (*newLen) );
return true;
}
log_error( LOG_ERROR, "ProtoConv_WarehouseWithdrawalList: some error after processing, "
"len = %u, newLen = 0x%p, (*newLen) = %u, (*newBytes) = 0x%p\n",
len, newLen, (*newLen), (*newBytes) );
(*newLen) = len;
(*newBytes) = bytes;
return false;
}
bool ProtoConv_ConvertTradeStart( unsigned char *bytes, unsigned int len,
unsigned char **newBytes, unsigned int *newLen )
{
L2GamePacket ilo; // old
L2GamePacket iln; // new
ilo.setBytes( bytes, len );
unsigned char ptype = ilo.getPacketType(); iln.setPacketType( ptype ); // opcode
iln.writeD( ilo.readD() ); // partner objectId
int count = ilo.readH(); iln.writeH( (short)count ); // items count
int i, ie;
for( i=0; i<count; i++ )
{
iln.writeH( ilo.readH() ); // item type 1
iln.writeD( ilo.readD() ); // item object id
iln.writeD( ilo.readD() ); // item item id
iln.writeQ( ilo.readQ() ); // item count
iln.writeH( ilo.readH() ); // item type 2
iln.writeH( ilo.readH() ); // item custom type 1 (always 0x00)
iln.writeD( ilo.readD() ); // item bodypart
iln.writeH( ilo.readH() ); // item enchant level
iln.writeH( ilo.readH() ); // 00
iln.writeH( ilo.readH() ); // item custom type 2 (pet name related..?)
// T1 elementals
for( ie=0; ie<8; ie++ ) iln.writeH( ilo.readH() ); // element. attrs
// T24 // write enchant effects to new packet, but don't read them from source
iln.writeH(0x00); iln.writeH(0x00); iln.writeH(0x00);
}
//
(*newLen) = iln.getPacketSize();
(*newBytes) = (unsigned char *)malloc( (*newLen) );
if( (*newBytes) )
{
memcpy( (*newBytes), iln.getBytesPtr(), (*newLen) );
return true;
}
log_error( LOG_ERROR, "ProtoConv_TradeStart: some error after processing, "
"len = %u, newLen = 0x%p, (*newLen) = %u, (*newBytes) = 0x%p\n",
len, newLen, (*newLen), (*newBytes) );
(*newLen) = len;
(*newBytes) = bytes;
return false;
}
bool ProtoConv_ConvertTradeOwnAdd( unsigned char *bytes, unsigned int len,
unsigned char **newBytes, unsigned int *newLen )
{
L2GamePacket ilo; // old
L2GamePacket iln; // new
ilo.setBytes( bytes, len );
unsigned char ptype = ilo.getPacketType(); iln.setPacketType( ptype ); // opcode
int count = ilo.readH(); iln.writeH( (short)count ); // items count
int i, ie;
for( i=0; i<count; i++ )
{
iln.writeH( ilo.readH() ); // item type 1
iln.writeD( ilo.readD() ); // item object id
iln.writeD( ilo.readD() ); // item item id
iln.writeQ( ilo.readQ() ); // item count
iln.writeH( ilo.readH() ); // item type 2
iln.writeH( ilo.readH() ); // item custom type 1 (always 0x00)
iln.writeD( ilo.readD() ); // item bodypart
iln.writeH( ilo.readH() ); // item enchant level
iln.writeH( ilo.readH() ); // 00
iln.writeH( ilo.readH() ); // item custom type 2 (pet name related..?)
// T1 elementals
for( ie=0; ie<8; ie++ ) iln.writeH( ilo.readH() ); // element. attrs
// T24 // write enchant effects to new packet, but don't read them from source
iln.writeH(0x00); iln.writeH(0x00); iln.writeH(0x00);
}
//
(*newLen) = iln.getPacketSize();
(*newBytes) = (unsigned char *)malloc( (*newLen) );
if( (*newBytes) )
{
memcpy( (*newBytes), iln.getBytesPtr(), (*newLen) );
return true;
}
log_error( LOG_ERROR, "ProtoConv_TradeOwnAdd: some error after processing, "
"len = %u, newLen = 0x%p, (*newLen) = %u, (*newBytes) = 0x%p\n",
len, newLen, (*newLen), (*newBytes) );
(*newLen) = len;
(*newBytes) = bytes;
return false;
}
bool ProtoConv_ConvertTradeOtherAdd( unsigned char *bytes, unsigned int len,
unsigned char **newBytes, unsigned int *newLen )
{
L2GamePacket ilo; // old
L2GamePacket iln; // new
ilo.setBytes( bytes, len );
unsigned char ptype = ilo.getPacketType(); iln.setPacketType( ptype ); // opcode
int count = ilo.readH(); iln.writeH( (short)count ); // items count
int i, ie;
for( i=0; i<count; i++ )
{
iln.writeH( ilo.readH() ); // item type 1
iln.writeD( ilo.readD() ); // item object id
iln.writeD( ilo.readD() ); // item item id
iln.writeQ( ilo.readQ() ); // item count
iln.writeH( ilo.readH() ); // item type 2
iln.writeH( ilo.readH() ); // item custom type 1 (always 0x00)
iln.writeD( ilo.readD() ); // item bodypart
iln.writeH( ilo.readH() ); // item enchant level
iln.writeH( ilo.readH() ); // 00
iln.writeH( ilo.readH() ); // item custom type 2 (pet name related..?)
// T1 elementals
for( ie=0; ie<8; ie++ ) iln.writeH( ilo.readH() ); // element. attrs
// T24 // write enchant effects to new packet, but don't read them from source
iln.writeH(0x00); iln.writeH(0x00); iln.writeH(0x00);
}
//
(*newLen) = iln.getPacketSize();
(*newBytes) = (unsigned char *)malloc( (*newLen) );
if( (*newBytes) )
{
memcpy( (*newBytes), iln.getBytesPtr(), (*newLen) );
return true;
}
log_error( LOG_ERROR, "ProtoConv_TradeOtherAdd: some error after processing, "
"len = %u, newLen = 0x%p, (*newLen) = %u, (*newBytes) = 0x%p\n",
len, newLen, (*newLen), (*newBytes) );
(*newLen) = len;
(*newBytes) = bytes;
return false;
}
bool ProtoConv_ConvertPrivateStoreListSell( unsigned char *bytes, unsigned int len,
unsigned char **newBytes, unsigned int *newLen )
{
L2GamePacket ilo; // old
L2GamePacket iln; // new
ilo.setBytes( bytes, len );
unsigned char ptype = ilo.getPacketType(); iln.setPacketType( ptype ); // opcode
iln.writeD( ilo.readD() ); // seller obejct ID
iln.writeD( ilo.readD() ); // isPackageSale
iln.writeQ( ilo.readQ() ); // player adena
int count = ilo.readD(); iln.writeD( count ); // items count
int i, ie;
for( i=0; i<count; i++ )
{
iln.writeD( ilo.readD() ); // item type 2
iln.writeD( ilo.readD() ); // item object id
iln.writeD( ilo.readD() ); // item item id
iln.writeQ( ilo.readQ() ); // item count
iln.writeH( ilo.readH() ); // 00
iln.writeH( ilo.readH() ); // ench
iln.writeH( ilo.readH() ); // item custom type 2 (always 0x00)
iln.writeD( ilo.readD() ); // item bodypart
iln.writeQ( ilo.readQ() ); // price
iln.writeQ( ilo.readQ() ); // ref.price
// T1 elementals
for( ie=0; ie<8; ie++ ) iln.writeH( ilo.readH() ); // element. attrs
// T24 // write enchant effects to new packet, but don't read them from source
iln.writeH(0x00); iln.writeH(0x00); iln.writeH(0x00);
}
//
(*newLen) = iln.getPacketSize();
(*newBytes) = (unsigned char *)malloc( (*newLen) );
if( (*newBytes) )
{
memcpy( (*newBytes), iln.getBytesPtr(), (*newLen) );
return true;
}
log_error( LOG_ERROR, "ProtoConv_PrivateStoreListSell: some error after processing, "
"len = %u, newLen = 0x%p, (*newLen) = %u, (*newBytes) = 0x%p\n",
len, newLen, (*newLen), (*newBytes) );
(*newLen) = len;
(*newBytes) = bytes;
return false;
}
bool ProtoConv_ConvertPrivateStoreListBuy( unsigned char *bytes, unsigned int len,
unsigned char **newBytes, unsigned int *newLen )
{
L2GamePacket ilo; // old
L2GamePacket iln; // new
ilo.setBytes( bytes, len );
unsigned char ptype = ilo.getPacketType(); iln.setPacketType( ptype ); // opcode
iln.writeD( ilo.readD() ); // seller object ID
iln.writeQ( ilo.readQ() ); // player adena
int count = ilo.readD(); iln.writeD( count ); // items count
int i, ie;
for( i=0; i<count; i++ )
{
iln.writeD( ilo.readD() ); // item type 2
iln.writeD( ilo.readD() ); // item object id
iln.writeD( ilo.readD() ); // item item id
iln.writeQ( ilo.readQ() ); // item count
iln.writeH( ilo.readH() ); // 00
iln.writeH( ilo.readH() ); // ench
iln.writeH( ilo.readH() ); // item custom type 2 (always 0x00)
iln.writeD( ilo.readD() ); // item bodypart
iln.writeQ( ilo.readQ() ); // price
iln.writeQ( ilo.readQ() ); // ref.price
// T1 elementals
for( ie=0; ie<8; ie++ ) iln.writeH( ilo.readH() ); // element. attrs
// T24 // write enchant effects to new packet, but don't read them from source
iln.writeH(0x00); iln.writeH(0x00); iln.writeH(0x00);
}
//
(*newLen) = iln.getPacketSize();
(*newBytes) = (unsigned char *)malloc( (*newLen) );
if( (*newBytes) )
{
memcpy( (*newBytes), iln.getBytesPtr(), (*newLen) );
return true;
}
log_error( LOG_ERROR, "ProtoConv_PrivateStoreListBuy: some error after processing, "
"len = %u, newLen = 0x%p, (*newLen) = %u, (*newBytes) = 0x%p\n",
len, newLen, (*newLen), (*newBytes) );
(*newLen) = len;
(*newBytes) = bytes;
return false;
}
bool ProtoConv_ConvertPacket( unsigned char *bytes, unsigned int len,
unsigned char **newBytes, unsigned int *newLen )
{
if( !pconv_enabled ) return false;
if( !pconv_was_Init ) ProtoConv_Init();
if( !bytes || (len<3) || !newBytes || !newLen ) return false; // assert
bool bRet = false;
unsigned char pcode = bytes[2];
unsigned short pcode2 = 0;
if( len >= 5 ) pcode2 = bytes[3] | (((unsigned short)bytes[4]) << 8);
try { // C++ exception handler
if( pcode == 0xFE ) // extended server packet
{
switch( pcode2 )
{
case PCODE2_EXBUYSELLLITSTPACKET: bRet = ProtoConv_ConvertExBuySellList( bytes, len, newBytes, newLen ); break;
default: log_error( LOG_ERROR, "ProtoConvert: convert not found for packet FE:%02X\n", (unsigned int)pcode ); break;
}
return bRet;
}
if( pconv_table[ pcode ] == 0 )
{
log_error( LOG_ERROR, "ProtoConvert: convert not found for packet 0x%02X\n", (unsigned int)pcode );
return false;
}
switch( pcode )
{
case PCODE_SELLLIST: bRet = ProtoConv_ConvertSellList( bytes, len, newBytes, newLen ); break;
case PCODE_BUYLIST: bRet = ProtoConv_ConvertBuyList( bytes, len, newBytes, newLen ); break;
case PCODE_ITEMLIST: bRet = ProtoConv_ConvertItemList( bytes, len, newBytes, newLen ); break;
case PCODE_TRADESTART: bRet = ProtoConv_ConvertTradeStart( bytes, len, newBytes, newLen ); break;
case PCODE_TRADEOWNADD: bRet = ProtoConv_ConvertTradeOwnAdd( bytes, len, newBytes, newLen ); break;
case PCODE_TRADEOTHERADD: bRet = ProtoConv_ConvertTradeOtherAdd( bytes, len, newBytes, newLen ); break;
case PCODE_INVENTORYUPDATE: bRet = ProtoConv_ConvertInventoryUpdate( bytes, len, newBytes, newLen ); break;
case PCODE_WAREHOUSEDEPOSITLIST: bRet = ProtoConv_ConvertWarehouseDepositList( bytes, len, newBytes, newLen ); break;
case PCODE_WAREHOUSEWITHDRAWLIST: bRet = ProtoConv_ConvertWarehouseWithdrawList( bytes, len, newBytes, newLen ); break;
case PCODE_PRIVATESTORELISTSELL: bRet = ProtoConv_ConvertPrivateStoreListSell( bytes, len, newBytes, newLen ); break;
case PCODE_PRIVATESTORELISTBUY: bRet = ProtoConv_ConvertPrivateStoreListBuy( bytes, len, newBytes, newLen ); break;
case PCODE_RELATIONCHANGED: bRet = ProtoConv_ConvertRelationChanged( bytes, len, newBytes, newLen ); break;
}
} // try
catch( L2P_Exception& e )
{
log_error( LOG_ERROR, "ProtoConv_ConvertPacket: pcode = 0x%02X, pcode2 = 0x%02X\n"
"L2P_Exception: %s\n", (unsigned int)pcode, (unsigned int)pcode2, e.what() );
// cleanup (<28><> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>!)
if( (*newBytes) != bytes ) free( (*newBytes) );
(*newBytes) = bytes;
(*newLen) = len;
bRet = false;
}
return bRet;
}

View File

@@ -0,0 +1,11 @@
#ifndef H_PROTOCONV
#define H_PROTOCONV
void ProtoConv_Init();
int ProtoConv_IsEnabled();
int ProtoConv_ConvExistsForPacket( unsigned char pcode );
bool ProtoConv_ConvertPacket( unsigned char *bytes, unsigned int len,
unsigned char **newBytes, unsigned int *newLen );
#endif

448
l2detect/RadarDllWnd.cpp Normal file
View File

@@ -0,0 +1,448 @@
#include "stdafx.h"
#include "Resource.h"
#include "ConfigIni.h"
#include "RadarDllWnd.h"
#include "Logger.h"
#include "GameClient.h"
extern class CConfig g_cfg;
extern class GameClient *g_game_client;
#define RADARDLLWND_CLASS TEXT("RadarDllWindow_2.0")
// globals
HINSTANCE g_radardll_hinst = NULL;
DWORD g_radardll_thread_id = 0;
HWND g_hWndL2 = NULL;
DWORD g_l2_thread_id = 0;
HWND g_radardll_hwnd = NULL;
// display globals
int g_radarWnd_drawOnClient = 0;
LPDIRECTDRAW lpdd = NULL;
LPDIRECTDRAW7 lpdd7 = NULL;
LPDIRECTDRAWSURFACE7 lpdds7 = NULL;
// hook procs defs
LRESULT CALLBACK KeyboardProc( int nCode, WPARAM wParam, LPARAM lParam );
LRESULT CALLBACK LowLevelKeyboardProc( int nCode, WPARAM wParam, LPARAM lParam );
void InitDirectDraw( HWND hWnd );
void CleanupDirectDraw();
BOOL RadarDllWindowRegClass( HINSTANCE hInst )
{
g_radardll_hinst = hInst;
WNDCLASSEX wc;
memset( &wc, 0, sizeof(WNDCLASSEX) );
wc.cbSize = sizeof(WNDCLASSEX);
wc.hbrBackground = (HBRUSH)GetStockObject( BLACK_BRUSH );
wc.hCursor = LoadCursor( NULL, IDC_ARROW );
wc.hInstance = hInst;
wc.hIcon = wc.hIconSm = LoadIcon( g_radardll_hinst, MAKEINTRESOURCE(IDI_MFC) );
wc.lpszClassName = RADARDLLWND_CLASS;
wc.style = CS_OWNDC | /*CS_VREDRAW | CS_HREDRAW |*/ CS_DBLCLKS;
wc.lpfnWndProc = RadarDllWindowProc;
if( !RegisterClassEx( &wc ) )
{
MessageBox( 0, TEXT("RegisterClassEx() failed!"), TEXT("Error!"), MB_ICONSTOP );
return FALSE;
}
return TRUE;
}
HWND RadarDllWindowCreate()
{
if( g_radardll_hinst == NULL ) return NULL;
DWORD windowExStyle = WS_EX_LAYERED | WS_EX_TOPMOST; // | WS_EX_TOOLWINDOW /*| WS_EX_NOACTIVATE*/;
DWORD windowStyle = WS_OVERLAPPEDWINDOW;
if( g_cfg.isInGameMode == false )
{
windowExStyle = WS_EX_LAYERED; // NO WS_EX_TOPMOST; // :)
windowStyle |= ( WS_VISIBLE | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX );
}
HWND hWndRadar = NULL;
hWndRadar = CreateWindowEx( windowExStyle, RADARDLLWND_CLASS, TEXT("L2Detect"), windowStyle,
0, 0, 300, 800, NULL, NULL, g_radardll_hinst, NULL );
if( !hWndRadar )
{
log_error( LOG_ERROR, "Radar window creation failed, trying to init common controls...\n" );
MyInitCommonControlsEx();
hWndRadar = CreateWindowEx( windowExStyle, RADARDLLWND_CLASS, TEXT("L2Detect"), windowStyle,
0, 0, 300, 800, NULL, NULL, g_radardll_hinst, NULL );
if( !hWndRadar )
{
log_error( LOG_ERROR, "Radar window creation failed again. Radar will not function!\n" );
return NULL;
}
}
SetLayeredWindowAttributes( hWndRadar, RGB(0,0,0), 255, /*LWA_COLORKEY |*/ LWA_ALPHA );
return hWndRadar;
}
void RadarDllWindowStart( HINSTANCE hInst )
{
RadarDllWindowRegClass( hInst );
HANDLE hThread = NULL;
DWORD dwTID = 0;
hThread = (HANDLE)_beginthreadex( NULL, 0,
(unsigned int (__stdcall *)(void *))RadarDllWindowThread, NULL, 0,
(unsigned int *)&dwTID );
if( hThread == NULL )
{
MessageBox( 0, TEXT("RadarDllWindowThread create error!"), TEXT("Error!"), MB_ICONSTOP );
return;
}
CloseHandle( hThread );
}
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD>-<2D><> <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> EnumWindows
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20> hWnd
BOOL CALLBACK RadarDllWindowThread_EnumWindowsProc( HWND hWnd, LPARAM lParam )
{
UNREFERENCED_PARAMETER(lParam);
DWORD myPid = GetCurrentProcessId(); // pID <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
DWORD dwPid = 0;
DWORD dwTid = GetWindowThreadProcessId( hWnd, &dwPid ); // pID <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>, <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD>
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> 2<> <20><><EFBFBD><EFBFBD> <20>2
if( dwPid == myPid ) // <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD> <20><><EFBFBD> <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>! <20> <20><> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD> <20>2
{
log_error( LOG_DEBUGDUMP, "RadarDllWindowThread_EnumWindowsProc(): got window pid,tid = (%u,%u)\n",
(unsigned int)dwPid, (unsigned int)dwTid );
// window is running in the same process as we are
// check window class or name to check is it is main Lineage II window
bool isL2Window = false;
TCHAR wndTitle[256];
memset( wndTitle, 0, sizeof(wndTitle) );
GetWindowText( hWnd, wndTitle, 255 );
log_error( LOG_DEBUGDUMP, ".. got window title [%S]\n", wndTitle );
if( _tcsicmp( wndTitle, _T("Lineage II") ) == 0 )
{
isL2Window = true;
log_error( LOG_DEBUG, "... found L2 window by title!\n" );
}
// title doesn't match? check window class name!
if( !isL2Window )
{
log_error( LOG_DEBUGDUMP, "... window title doesn't match, trying by class name...\n" );
TCHAR buffer_for_class_name[256] = {0};
if( GetClassName( hWnd, buffer_for_class_name, 255 ) )
{
log_error( LOG_DEBUGDUMP, ".... got window class name = [%S]\n", buffer_for_class_name );
if( _tcsicmp( buffer_for_class_name, _T("l2UnrealWWindowsViewportWindow") ) == 0 )
{
isL2Window = true;
log_error( LOG_DEBUG, ".... found L2 window by class name!\n" );
}
}
else
ErrorLogger_LogLastError( "GetClassName()", GetLastError() );
}
// checks...
if( isL2Window ) // found
{
g_hWndL2 = hWnd; // save in global var
g_l2_thread_id = dwTid;
return FALSE; // stop EnumWindows
}
}
return TRUE;
}
HHOOK WINAPI RadarDllWindowThread_installKeyboardHook()
{
HHOOK hook = NULL;
unsigned int my_process_id = (unsigned int)GetCurrentProcessId();
log_error( LOG_DEBUG, "We're running in process id #%u\n", my_process_id );
g_hWndL2 = NULL; // global handle to L2 Window
g_l2_thread_id = 0;
int tries = 80; // wait 20 seconds for L2 widnow
log_error( LOG_OK, "RadarDllWindowThread_installKeyboardHook(): looking for L2 window ... " );
while( g_hWndL2 == NULL )
{
EnumWindows( RadarDllWindowThread_EnumWindowsProc, 0 );
tries--;
if( g_hWndL2 == NULL )
log_error_np( LOG_OK, "%d, ", tries );
if( tries <= 0 ) break;
Sleep( 250 ); // wait 0.25 seconds, maybe L2 window will appear
}
log_error_np( LOG_OK, "\n" );
// check if window is found
if( g_hWndL2 )
{
hook = SetWindowsHookEx( WH_KEYBOARD, KeyboardProc, g_radardll_hinst, g_l2_thread_id );
if( hook == NULL )
{
DWORD le = GetLastError();
ErrorLogger_LogLastError( "SetWindowsHookEx() failed", le );
}
else
log_error( LOG_OK, "Window keyboard hook installed.\n" );
}
else
{
log_error( LOG_ERROR, "RadarDllWindowThread_installKeyboardHook(): cannot find Lineage II window!!!\n" );
g_hWndL2 = NULL;
}
return hook;
}
DWORD WINAPI RadarDllWindowThread( LPVOID lpParam )
{
UNREFERENCED_PARAMETER(lpParam);
g_radardll_thread_id = GetCurrentThreadId();
// are we in ingame or outgame?
TCHAR tszEvtName[256];
wsprintf( tszEvtName, TEXT("L2Detect Outgame Event_%d"), (unsigned)GetCurrentProcessId() );
HANDLE hEvtDbg = OpenEvent( EVENT_MODIFY_STATE, FALSE, tszEvtName );
HHOOK hook = NULL;
if( hEvtDbg == NULL ) // ingame, wait for L2 Window
{
g_cfg.isInGameMode = true;
Sleep( 5000 );
// install keyboard hook
hook = RadarDllWindowThread_installKeyboardHook();
// wait more till L2 window initialises
Sleep( 4000 );
//MyInitCommonControlsEx();
//InitDirectDraw( hWndL2 );
}
else // outgame. do not wait for anything
{
g_cfg.isInGameMode = false;
}
//
ErrorLogger_FlushLogFile();
//
HWND hWnd = RadarDllWindowCreate();
if( hWnd == NULL )
{
DWORD le = GetLastError();
log_error( LOG_ERROR, "RadarDllWindowCreate() failed! last error %u\n", (unsigned int)le );
ErrorLogger_LogLastError( "RadarDllWindowCreate()", le );
return le;
}
g_radardll_hwnd = hWnd; // save radar window handle in global var
// hide radar window ONLY if is INGAME mode AND Lineage II window is found!
if( (g_cfg.isInGameMode == true) && (g_hWndL2 != NULL) )
ShowWindow( hWnd, SW_HIDE );
// fix: show radar window again in INGAME mode and if Lineage II window was not found
if( (g_cfg.isInGameMode == true) && (g_hWndL2 == NULL) )
ShowWindow( hWnd, SW_SHOWNORMAL );
// radar wnd message loop
MSG msg;
while( GetMessage( &msg, NULL, 0, 0 ) )
{
TranslateMessage( &msg );
DispatchMessage( &msg );
}
//
log_error( LOG_DEBUG, "Window is closed. Cleanup...\n" );
ErrorLogger_FlushLogFile();
// Cleanup
if( g_cfg.isInGameMode )
{
// unhook hook installed in ingame mode
UnhookWindowsHookEx( hook );
CleanupDirectDraw();
}
else
{
// signal EXE in outgame mode to stop
SetEvent( hEvtDbg );
CloseHandle( hEvtDbg );
}
return 0;
}
// local thread's keyboard hook
LRESULT CALLBACK KeyboardProc( int nCode, WPARAM wParam, LPARAM lParam )
{
if( nCode < 0 ) return CallNextHookEx( NULL, nCode, wParam, lParam );
if( nCode == HC_ACTION || nCode == HC_NOREMOVE )
{
//wParam [in] Specifies the virtual-key code of the key that generated the keystroke message.
//lParam [in] Specifies the repeat count, scan code, extended-key flag, context code,
// previous key-state flag, and transition-state flag
//lParam bit 31 is set if key is pressed, and not set if released
bool keyIsPushed = ((lParam & 0x80000000) != 0);
if( keyIsPushed ) // <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>, <20> <20><> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
{
switch( wParam ) // wParam - <20><><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
{
case VK_PAUSE: // <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> Pause/Break?
PostMessage( g_radardll_hwnd, WMMY_WNDSHOWTOGGLE, 0, 0 );
break;
default: // <20><><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
if( g_game_client )
g_game_client->ai.notifyUIKeyUp( (int)wParam );
break;
}
}
}
// [DBG] KeyboardProc( 0, '' 19, 0xC0450001 ) cur thread: 5088 5088: l2 thread
//log_error( LOG_DEBUG, "KeyboardProc( %d, '%c' %d, 0x%08X ) cur thread: %u %u: l2 thread\n",
// nCode, (char)wParam, (int)wParam, (unsigned int)lParam,
// (unsigned int)GetCurrentThreadId(), (unsigned int)g_l2_thread_id );
return CallNextHookEx( NULL, nCode, wParam, lParam );
}
// global keyboard hook
LRESULT CALLBACK LowLevelKeyboardProc( int nCode, WPARAM wParam, LPARAM lParam )
{
if( nCode < 0 ) return CallNextHookEx( NULL, nCode, wParam, lParam );
//
//char szMes[32] = {0};
//switch( wParam )
//{
//case WM_KEYDOWN: strcpy( szMes, "WM_KEYDOWN " ); break;
//case WM_KEYUP: strcpy( szMes, "WM_KEYUP " ); break;
//case WM_SYSKEYDOWN: strcpy( szMes, "WM_SYSKEYDOWN" ); break;
//case WM_SYSKEYUP: strcpy( szMes, "WM_SYSKEYUP " ); break;
//default: sprintf( szMes, "mes_%u", (unsigned int)wParam ); break;
//}
//
KBDLLHOOKSTRUCT *phs = (KBDLLHOOKSTRUCT *)lParam;
if( !phs ) return CallNextHookEx( NULL, nCode, wParam, lParam );
//
//log_error( LOG_DEBUG, "LowLevelKeyboardProc( %d, '%s', '%3c' %4u, %u ) threads (cur/radar/l2): %u/%u/%u\n",
// nCode, szMes, (char)(phs->vkCode), (unsigned int)(phs->vkCode), (unsigned int)phs->scanCode,
// (unsigned int)GetCurrentThreadId(), (unsigned int)g_radardll_thread_id, (unsigned int)g_l2_thread_id );
//
if( wParam == WM_KEYUP )
{
if( phs->vkCode == VK_PAUSE )
PostMessage( g_radardll_hwnd, WMMY_WNDSHOWTOGGLE, 0, 0 );
if( phs->vkCode == VK_NUMLOCK )
{
int new_val = 0;
if( g_radarWnd_drawOnClient == 0 ) new_val = 1;
g_radarWnd_drawOnClient = new_val;
}
}
return CallNextHookEx( NULL, nCode, wParam, lParam );
}
void InitDirectDraw( HWND hWnd )
{
// Window info
if( hWnd != NULL )
{
TCHAR cn[256] = {0};
GetClassName( hWnd, cn, 255 );
log_error( LOG_DEBUG, "Got class name: [%S]\n", cn );
}
// Create DirectDraw object
HRESULT hRes = DirectDrawCreate( NULL, &lpdd, NULL );
if( hRes != S_OK )
{
log_error( LOG_ERROR, "DirectDraw creating failed! HRESULT = %d (%08X), last error %u\n",
hRes, hRes, (unsigned int)GetLastError() );
return;
}
log_error( LOG_DEBUG, "DirectDraw create OK\n" );
// get directdraw7
hRes = lpdd->QueryInterface( IID_IDirectDraw7, (void **)&lpdd7 );
lpdd->Release();
lpdd = NULL;
if( hRes != S_OK )
{
log_error( LOG_ERROR, "IDirectDraw::QueryInterface() failed! err 0x%08x\n", hRes );
return;
}
log_error( LOG_DEBUG, "DirectDraw7 create OK\n" );
// try to set cooperative level (dest HWND)
hRes = lpdd7->SetCooperativeLevel( hWnd, DDSCL_NORMAL /* | DDSCL_MULTITHREADED */ );
if( hRes != S_OK ) log_error( LOG_ERROR, "IDirectDraw7::SetCooperativeLevel() failed! 0x%08X\n", hRes );
else log_error( LOG_DEBUG, "IDirectDraw7::SetCooperativeLevel() OK\n" );
//
/*HDC hdcL2 = GetDC( hWnd );
hRes = lpdd7->GetSurfaceFromDC( hdcL2, &lpdds );
if( hRes != S_OK )
{
log_error( LOG_ERROR, "IDirectDraw7::GetSurfaceFromDC() failed! 0x%08x\n", hRes );
switch( hRes )
{
case DDERR_GENERIC: log_error( LOG_ERROR, "DDERR_GENERIC\n" ); break;
case DDERR_INVALIDPARAMS: log_error( LOG_ERROR, "DDERR_INVALIDPARAMS\n" ); break;
case DDERR_OUTOFMEMORY: log_error( LOG_ERROR, "DDERR_OUTOFMEMORY\n" ); break;
case DDERR_NOTFOUND: log_error( LOG_ERROR, "DDERR_NOTFOUND\n" ); break;
default: log_error( LOG_ERROR, "xz\n" ); break;
}
}
else log_error( LOG_DEBUG, "IDirectDraw7::GetSurfaceFromDC() OK! 0x%08x\n", lpdds );
ReleaseDC( hWnd, hdcL2 );*/
//
/*DDSURFACEDESC2 sd2;
sd2.dwSize = sizeof(sd2);
sd2.ddsCaps.dwCaps;
lpdd7->CreateSurface( &sd2, &lpdds7, NULL );*/
}
void CleanupDirectDraw()
{
if( lpdds7 )
{
log_error( LOG_DEBUG, "Releasing Surface...\n" );
lpdds7->Release();
lpdds7 = NULL;
}
if( lpdd7 )
{
log_error( LOG_DEBUG, "Releasing IDirectDraw7...\n" );
lpdd7->Release();
lpdd7 = NULL;
}
}
// old hook installer code
/*
// find Lineage II Window
HWND hWndL2;
int maxTries = 50;
DWORD l2_pid = 0, l2_tid = 0;
while( maxTries > 0 )
{
maxTries--;
// try to find by name
hWndL2 = FindWindow( NULL, TEXT("Lineage II") );
if( hWndL2 ) log_error( LOG_DEBUG, "Found L2 Window by name 0x%p\n", hWndL2 );
else
{
// or else try to find by class
hWndL2 = FindWindow( TEXT("l2UnrealWWindowsViewportWindow"), NULL );
if( hWndL2 ) log_error( LOG_DEBUG, "Found L2 Window by class 0x%p\n", hWndL2 );
else log_error( LOG_WARNING, "FindWindow() cannot find L2 Window! (triesLeft: %d)\n", maxTries );
}
Sleep( 1000 );
if( hWndL2 != NULL )
{
g_hWndL2 = hWndL2;
l2_tid = GetWindowThreadProcessId( hWndL2, &l2_pid );
g_l2_thread_id = l2_tid;
log_error( LOG_DEBUG, "L2 Window Thread: %d, process ID: %d\n", l2_tid, l2_pid );
break;
}
}
// install keyboard hook only in ingame mode
//hook = SetWindowsHookEx( WH_KEYBOARD_LL, LowLevelKeyboardProc, g_radardll_hinst, 0 );
hook = SetWindowsHookEx( WH_KEYBOARD, KeyboardProc, g_radardll_hinst, g_l2_thread_id );
if( hook == NULL )
{
DWORD le = GetLastError();
ErrorLogger_LogLastError( "SetWindowsHookEx() failed", le );
}
else
log_error( LOG_DEBUG, "SetWindowsHookEx() OK\n" );
*/

56
l2detect/RadarDllWnd.h Normal file
View File

@@ -0,0 +1,56 @@
#ifndef H_RADAR_WND
#define H_RADAR_WND
extern HINSTANCE g_radardll_hinst;
extern HWND g_radardll_hwnd;
extern DWORD g_radardll_thread_id;
extern DWORD g_l2_thread_id;
LRESULT CALLBACK RadarDllWindowProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam );
BOOL RadarDllWindowRegClass( HINSTANCE hInst );
HWND RadarDllWindowCreate();
DWORD WINAPI RadarDllWindowThread( LPVOID lpParam );
void RadarDllWindowStart( HINSTANCE hInst );
#define WMMY_WNDSHOWTOGGLE (WM_USER+100)
#define WMMY_UPDATE_CHARS_LIST (WM_USER+101)
#define WMMY_SET_USER_COORDS (WM_USER+102) // unused
#define WMMY_UPDATE_NPCS_LIST (WM_USER+103)
#define WMMY_TRAYMESSAGE (WM_USER+104)
#define WMMY_GAMECLIENT_NOTIFY (WM_USER+105)
#define WMMY_LOGINCLIENT_NOTIFY (WM_USER+106)
#define WMMY_NOTIFY_TARGET (WM_USER+107)
#define WMMY_UPDATE_CHECKS (WM_USER+108)
#define WMMY_SAVE_WINDOW_SIZE (WM_USER+109)
// new way of lists updating
#define WMMY_ADD_OBJECT (WM_USER+110) // msg
#define WMMY_DEL_OBJECT (WM_USER+111) // msg
#define WMMY_UPDATE_OBJECT (WM_USER+112) // msg
// wParams for these messages
#define MSG_PC 1
#define MSG_NPC 2
// lParams will represent objectId
#define WMMY_FORCE_UPDATE_LIST (WM_USER+113) // msg
#define FORCE_UPDATE_CHARS_LIST 1 // wparam
#define FORCE_UPDATE_NPCS_LIST 2 // wparam
void RadarWnd_NotifyTarget( unsigned int oid_from, unsigned int oid_to, bool selected = true );
// new lists update way
void RadarWnd_AddChar( unsigned int objectId );
void RadarWnd_UpdChar( unsigned int objectId );
void RadarWnd_DelChar( unsigned int objectId );
void RadarWnd_AddNpc( unsigned int objectId );
void RadarWnd_UpdNpc( unsigned int objectId );
void RadarWnd_DelNpc( unsigned int objectId );
void RadarWnd_ForceUpdateCharsList();
void RadarWnd_ForceUpdateNpcsList();
void RadarWnd_UpdateChecksState();
#endif /* H_RADAR_WND */

View File

@@ -0,0 +1,42 @@
#include "stdafx.h"
#include "RadarDllWndCfg.h"
void RadarWndCfg_InitDefault( RADARWNDCFG *pCfg )
{
memset( pCfg, 0, sizeof(RADARWNDCFG) );
pCfg->ui.colors.bgColor = RGB(0,0,0);
pCfg->ui.colors.circleColor = RGB(128,128,128);
pCfg->ui.colors.npcColor = RGB(200,200,0);
pCfg->ui.colors.mobColor = RGB(128,0,0);
pCfg->ui.colors.pcColor = RGB(75,75,255);
pCfg->ui.colors.pcColorDead = RGB(75,75,75);
pCfg->ui.colors.pcColorWar = RGB(255,85,85);
pCfg->ui.colors.pcColorWarDead = RGB(155,65,65);
pCfg->ui.colors.pcColorParty = RGB(60,255,60);
pCfg->ui.colors.pcColorPartyDead = RGB(0,200,0);
}
void RadarWndCfg_LoadConfigFromFile( RADARWNDCFG *pCfg, const char *fileName )
{
if( !pCfg ) return;
char *useFN = (char *)fileName;
if( !useFN ) useFN = "L2Detect_colors.ini";
FILE *f = fopen( useFN, "rb" );
if( !f ) return;
fread( pCfg, 1, sizeof(RADARWNDCFG), f );
fclose( f );
}
void RadarWndCfg_SaveConfigToFile( RADARWNDCFG *pCfg, const char *fileName )
{
if( !pCfg ) return;
char *useFN = (char *)fileName;
if( !useFN ) useFN = "L2Detect_colors.ini";
FILE *f = fopen( useFN, "wb" );
if( !f ) return;
//
fwrite( pCfg, 1, sizeof(RADARWNDCFG), f );
//
fclose( f );
}

29
l2detect/RadarDllWndCfg.h Normal file
View File

@@ -0,0 +1,29 @@
#ifndef H_RADARDLLWND_CFG
#define H_RADARDLLWND_CFG
struct RADARWNDCFG
{
struct st_ui
{
struct st_colors
{
COLORREF bgColor; // = RGB(0,0,0);
COLORREF circleColor; // = RGB(127,128,128);
COLORREF npcColor; // = RGB(200,200,0);
COLORREF mobColor; // = RGB(128,0,0);
COLORREF pcColor; // = RGB(75,75,255);
COLORREF pcColorDead; // = RGB(75,75,75);
COLORREF pcColorWar; // = RGB(255,85,85);
COLORREF pcColorWarDead; // = RGB(155,65,65);
COLORREF pcColorParty; // = RGB(60,255,60);
COLORREF pcColorPartyDead; // = RGB(0,200,0);
} colors;
} ui;
};
void RadarWndCfg_InitDefault( RADARWNDCFG *pCfg );
void RadarWndCfg_LoadConfigFromFile( RADARWNDCFG *pCfg, const char *fileName );
void RadarWndCfg_SaveConfigToFile( RADARWNDCFG *pCfg, const char *fileName );
#endif

View File

@@ -0,0 +1,27 @@
#include "stdafx.h"
#include "Logger.h"
#include "RadarDllWndHWID.h"
#include "HWID.h"
DWORD WINAPI RadarDllWnd_HWID_Check_Thread( LPVOID lpParam )
{
HWND hWnd = (HWND)lpParam;
//log_error( LOG_DEBUG, "RadarDllWnd_HWID_Check_Thread: started, sleeping...\n" );
Sleep( 1000 );
if( !VerifyHWID() )
{
log_error( LOG_ERROR, "RadarDllWnd_HWID_Check_Thread: HWID check failed!\n" );
PostMessage( hWnd, WM_CLOSE, 0, 0 );
}
return 0;
}
void RadarDllWnd_Start_HWID_Check( HWND hWnd )
{
HANDLE hThread = NULL;
unsigned int tid = 0;
hThread = (HANDLE)_beginthreadex( NULL, 0,
(unsigned int (__stdcall *)(void *))RadarDllWnd_HWID_Check_Thread, (void *)hWnd,
0, &tid );
if( hThread ) CloseHandle( hThread );
}

View File

@@ -0,0 +1,6 @@
#ifndef H_RADARDLLWND_HWID
#define H_RADARDLLWND_HWID
void RadarDllWnd_Start_HWID_Check( HWND hWnd );
#endif

1623
l2detect/RadarDllWndProc.cpp Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,54 @@
#include "stdafx.h"
#include "Logger.h"
#include "RadarDllWndSize.h"
void RadarDllWnd_RestoreWindowSize( HWND hWnd )
{
HKEY hKey = NULL;
if( RegOpenKeyEx( HKEY_CURRENT_USER, TEXT("Software\\L2Detect"), 0, KEY_READ, &hKey ) == NO_ERROR )
{
DWORD dwType = REG_DWORD, cb = 4;
int x0 = 0, y0 = 0, w = 0, h = 0;
cb = 4; RegQueryValueEx( hKey, TEXT("x0"), NULL, &dwType, (LPBYTE)&x0, &cb );
cb = 4; RegQueryValueEx( hKey, TEXT("y0"), NULL, &dwType, (LPBYTE)&y0, &cb );
cb = 4; RegQueryValueEx( hKey, TEXT("w"), NULL, &dwType, (LPBYTE)&w, &cb );
cb = 4; RegQueryValueEx( hKey, TEXT("h"), NULL, &dwType, (LPBYTE)&h, &cb );
if( x0 < 0 ) x0 = 1;
if( y0 < 0 ) y0 = 1;
if( x0 > 1200 ) x0 = 1200;
if( y0 > 1000 ) y0 = 1000;
if( w < 50 ) w = 50;
if( h < 100 ) h = 100;
if( x0>0 && y0>0 && w>0 && h>0 )
MoveWindow( hWnd, x0, y0, w, h, TRUE );
}
else
{
DWORD le = GetLastError();
ErrorLogger_LogLastError( "RadarDllWnd_RestoreWindowSize(): RegOpenKeyEx() failed", le );
}
}
void RadarDllWnd_SaveWidowSize( HWND hWnd )
{
RECT r;
GetWindowRect( hWnd, &r );
HKEY hKey = NULL;
DWORD disp = 0;
if( RegCreateKeyEx( HKEY_CURRENT_USER, TEXT("Software\\L2Detect"), 0, NULL,
0, KEY_READ | KEY_WRITE, NULL, &hKey, &disp ) == NO_ERROR )
{
if( disp == REG_CREATED_NEW_KEY )
log_error( LOG_DEBUG, "RadarDllWnd_SaveWidowSize(): created key\n" );
if( disp == REG_OPENED_EXISTING_KEY )
log_error( LOG_DEBUG, "RadarDllWnd_SaveWidowSize(): opened existing key\n" );
RegSetValueEx( hKey, TEXT("x0"), 0, REG_DWORD, (LPCBYTE)&r.left, 4 );
RegSetValueEx( hKey, TEXT("y0"), 0, REG_DWORD, (LPCBYTE)&r.top, 4 );
DWORD dw = r.right - r.left;
RegSetValueEx( hKey, TEXT("w"), 0, REG_DWORD, (LPCBYTE)&dw, 4 );
dw = r.bottom - r.top;
RegSetValueEx( hKey, TEXT("h"), 0, REG_DWORD, (LPCBYTE)&dw, 4 );
RegCloseKey( hKey );
}
else ErrorLogger_LogLastError( "RadarDllWnd_SaveWidowSize(): RegCreateKeyEx() failed", GetLastError() );
}

View File

@@ -0,0 +1,4 @@
#pragma once
void RadarDllWnd_RestoreWindowSize( HWND hWnd );
void RadarDllWnd_SaveWidowSize( HWND hWnd );

View File

@@ -0,0 +1,897 @@
#include "stdafx.h"
#include "Logger.h"
#include "RadarDllWnd.h"
#include "WorldObjectTree.h"
#include "CharArray.h"
#include "NpcArray.h"
#include "utils.h"
#include "GameClient.h"
extern GameClient *g_game_client;
#include "ConfigIni.h"
extern CConfig g_cfg;
#include "windowUtils.h"
void RadarWnd_AddChar( unsigned int objectId ) { PostMessage( g_radardll_hwnd, WMMY_ADD_OBJECT, MSG_PC, (LPARAM)objectId ); }
void RadarWnd_UpdChar( unsigned int objectId ) { PostMessage( g_radardll_hwnd, WMMY_UPDATE_OBJECT, MSG_PC, (LPARAM)objectId ); }
void RadarWnd_DelChar( unsigned int objectId ) { PostMessage( g_radardll_hwnd, WMMY_DEL_OBJECT, MSG_PC, (LPARAM)objectId ); }
void RadarWnd_AddNpc( unsigned int objectId ) { PostMessage( g_radardll_hwnd, WMMY_ADD_OBJECT, MSG_NPC, (LPARAM)objectId ); }
void RadarWnd_UpdNpc( unsigned int objectId ) { PostMessage( g_radardll_hwnd, WMMY_UPDATE_OBJECT, MSG_NPC, (LPARAM)objectId ); }
void RadarWnd_DelNpc( unsigned int objectId ) { PostMessage( g_radardll_hwnd, WMMY_DEL_OBJECT, MSG_NPC, (LPARAM)objectId ); }
// forwards
void RW_DeleteCharFromEnemiesList( unsigned int objectID );
void RW_UpdateCharInEnemiesList( L2Player *cha );
extern HWND g_rw_hWndCL; // chars ListView window
extern HWND g_rw_hWndNPC; // npcs ListView window
extern HWND g_rw_hWndEnemies; // enemies ListView window
extern bool g_radarwnd_npc_displayEnable;
LRESULT RW_OnAddObject( HWND hWnd, WPARAM wParam, LPARAM lParam )
{
UNREFERENCED_PARAMETER(hWnd);
// do not add npc if not displaying
if( wParam == MSG_NPC && !g_radarwnd_npc_displayEnable ) return 0;
unsigned int objectId = (unsigned int)lParam;
L2OBJECT_TYPE objType = L2OT_NONE;
int index = -1;
if( !WorldObjectTree_GetInfoByObjectID( objectId, &objType, &index ) )
{
log_error( LOG_WARNING, "RW_OnAddObject(): cannot get info about object [%u] to add\n", objectId );
return 0;
}
int user_z = g_game_client->ai.usr.z;
switch( wParam )
{
case MSG_PC:
{
if( objType != L2OT_PC )
{
log_error( LOG_WARNING, "RW_OnAddObject(): object [%u]: adding player, but in WOT incorrect type %d\n",
objectId, (int)objType );
return 0;
}
L2Player *cha = chars_array[index];
if( !cha )
{
log_error( LOG_ERROR, "RW_OnAddObject(): player found in WOT, but is NULL in array? O_o\n" );
return 0;
}
if( cha->isUnused() )
{
log_error( LOG_ERROR, "RW_OnAddObject(): player is unused in array! O_o\n" );
return 0;
}
// ok, adding
bool isEnemy = false;
bool is2sidewar = false;
TCHAR colText[128] = {0};
TCHAR szBuf1[128] = {0};
TCHAR szBuf2[128] = {0};
// detect clan war
utils_detectClanWar( cha->relation, &isEnemy, &is2sidewar );
// name
lstrcpy( colText, cha->getName() );
int iImage = -1;
if( isEnemy )
{
iImage = 0;
if( !is2sidewar ) iImage = 3;
}
if( g_game_client->ai.party.isInParty( cha->objectID, NULL ) ) iImage = 1;
if( cha->isAlikeDead ) iImage = 2;
int added_item = -1;
int added_item2 = -1;
added_item = WULV_InsertItem2( g_rw_hWndCL, colText, 999, iImage, (LPARAM)cha->objectID );
if( added_item == -1 ) return 0;
if( isEnemy ) // add enemies also to enemies tab
added_item2 = WULV_InsertItem2( g_rw_hWndEnemies, colText, 999, iImage, (LPARAM)cha->objectID );
// baseClass
szBuf2[0] = szBuf1[0] = 0;
cha->getClassStr( szBuf1 );
if( cha->classID != cha->baseClassID )
{
cha->getBaseClassStr( szBuf2 );
wsprintfW( colText, L"%s / %s", szBuf1, szBuf2 );
}
else wsprintfW( colText, L"%s", szBuf1 );
WULV_SetItem( g_rw_hWndCL, colText, added_item, 1 );
if( isEnemy ) // add enemies info also to enemies tab
WULV_SetItem( g_rw_hWndEnemies, colText, added_item2, 1 );
// clan
ClanList_GetClanNameByID( cha->clanID, colText ); // max 127 chars
WULV_SetItem( g_rw_hWndCL, colText, added_item, 2 );
if( isEnemy ) // add enemies info also to enemies tab
WULV_SetItem( g_rw_hWndEnemies, colText, added_item2, 2 );
// dZ
wsprintf( colText, TEXT("%d"), (user_z - cha->z) );
WULV_SetItem( g_rw_hWndCL, colText, added_item, 3 );
if( isEnemy ) // add enemies info also to enemies tab
WULV_SetItem( g_rw_hWndEnemies, colText, added_item2, 3 );
// clanwar state
colText[0] = 0;
if( isEnemy && !is2sidewar ) lstrcpy( colText, TEXT("<") );
if( isEnemy && is2sidewar ) lstrcpy( colText, TEXT("<>") );
WULV_SetItem( g_rw_hWndCL, colText, added_item, 4 );
if( isEnemy ) // add enemies info also to enemies tab
WULV_SetItem( g_rw_hWndEnemies, colText, added_item2, 4 );
} break;
case MSG_NPC:
{
if( g_radarwnd_npc_displayEnable == 0 ) return 0; // NPC display disabled
if( objType != L2OT_NPC )
{
log_error( LOG_WARNING, "RW_OnAddObject(): object [%u]: adding NPC, but in WOT incorrect type %d\n",
objectId, (int)objType );
return 0;
}
L2Npc *npc = npc_array[index];
if( !npc )
{
log_error( LOG_ERROR, "RW_OnAddObject(): NPC found in WOT, but is NULL in array? O_o\n" );
return 0;
}
if( npc->isUnused() )
{
log_error( LOG_ERROR, "RW_OnAddObject(): NPC is unused in array! O_o\n" );
return 0;
}
TCHAR colText[128] = {0};
wchar_t wName[128] = {0}; char aname[128] = {0};
wchar_t wTitle[128] = {0}; char atitle[128] = {0};
// NPC name
aname[0] = atitle[0] = 0;
wName[0] = wTitle[0] = 0;
lstrcpy( colText, npc->getName() );
if( colText[0] == 0 )
{
if( L2Data_DB_GetNPCNameTitleByID( npc->templateID, aname, atitle ) )
{
MultiByteToWideChar( CP_ACP, 0, aname, -1, wName, 127 );
MultiByteToWideChar( CP_ACP, 0, atitle, -1, wTitle, 127 );
npc->setName( wName );
lstrcpy( colText, wName );
}
}
int iImage = -1;
if( npc->isAlikeDead ) iImage = 2;
int added_item = WULV_InsertItem2( g_rw_hWndNPC, colText, 999, iImage, (LPARAM)npc->objectID );
if( added_item == -1 ) return 0;
// NPC title
wcscpy( colText, npc->getTitle() );
if( (colText[0] == 0) && (wTitle[0]) )
{
lstrcpy( colText, wTitle );
npc->setTitle( wTitle );
}
WULV_SetItem( g_rw_hWndNPC, colText, added_item, 1 );
// NPC dZ
wsprintf( colText, TEXT("%d"), (user_z - npc->z) );
WULV_SetItem( g_rw_hWndNPC, colText, added_item, 2 );
// NPC templateID
wsprintf( colText, TEXT("%d"), npc->templateID );
WULV_SetItem( g_rw_hWndNPC, colText, added_item, 3 );
} break;
}
return 0;
}
LRESULT RW_OnUpdObject( HWND hWnd, WPARAM wParam, LPARAM lParam )
{
UNREFERENCED_PARAMETER(hWnd);
// do not update npc if not displaying
if( wParam == MSG_NPC && !g_radarwnd_npc_displayEnable ) return 0;
unsigned int objectId = (unsigned int)lParam;
L2OBJECT_TYPE objType = L2OT_NONE;
int index = -1;
if( !WorldObjectTree_GetInfoByObjectID( objectId, &objType, &index ) )
{
log_error( LOG_WARNING, "RW_OnUpdObject(): cannot get info about object [%u] to add\n", objectId );
return 0;
}
int user_z = g_game_client->ai.usr.z;
HWND hWndLV = g_rw_hWndCL; // default: from char list
if( wParam == MSG_NPC ) hWndLV = g_rw_hWndNPC;
// find listview itemId to update
int iItem = -1;
LVITEM lvi;
memset( &lvi, 0, sizeof(lvi) );
int idx = -1;
do
{
idx = ListView_GetNextItem( hWndLV, idx, LVNI_ALL );
if( idx == -1 ) break;
lvi.iItem = idx;
lvi.iSubItem = 0;
lvi.mask = LVIF_PARAM;
if( ListView_GetItem( hWndLV, &lvi ) )
{
if( ((unsigned int)lvi.lParam) == objectId )
{
iItem = lvi.iItem;
break;
}
}
} while( idx >= 0 );
if( iItem == -1 )
{
// not found
switch( wParam )
{
case MSG_PC: log_error( LOG_WARNING, "RW_OnUpdObject(): cannot find player objectId [%u] in LV to update\n", objectId ); break;
case MSG_NPC: log_error( LOG_WARNING, "RW_OnUpdObject(): cannot find NPC objectId [%u] in LV to update\n", objectId ); break;
}
return 0;
}
memset( &lvi, 0, sizeof(lvi) );
lvi.iItem = iItem;
lvi.lParam = (LPARAM)objectId;
switch( wParam )
{
case MSG_PC:
{
if( objType != L2OT_PC )
{
log_error( LOG_WARNING, "RW_OnUpdObject(): object [%u]: update player, but in WOT incorrect type %d\n",
objectId, (int)objType );
return 0;
}
L2Player *cha = chars_array[index];
if( !cha )
{
log_error( LOG_ERROR, "RW_OnUpdObject(): player found in WOT, but is NULL in array? O_o\n" );
return 0;
}
if( cha->isUnused() )
{
log_error( LOG_ERROR, "RW_OnUpdObject(): player is unused in array! O_o\n" );
return 0;
}
// ok, adding
bool isEnemy = false;
bool is2sidewar = false;
TCHAR colText[128] = {0};
TCHAR szBuf1[128] = {0};
TCHAR szBuf2[128] = {0};
memset( &lvi, 0, sizeof(lvi) );
lvi.cchTextMax = 128;
lvi.pszText = colText;
// detect clan war
utils_detectClanWar( cha->relation, &isEnemy, &is2sidewar );
// name
lstrcpy( colText, cha->getName() );
lvi.pszText = colText;
lvi.mask = LVIF_TEXT | LVIF_PARAM | LVIF_IMAGE;
lvi.iItem = iItem;
lvi.iSubItem = 0;
lvi.lParam = cha->objectID;
// image
lvi.iImage = -1;
if( isEnemy )
{
lvi.iImage = 0; // RED CIRC
if( !is2sidewar ) lvi.iImage = 3; // HALF RED CIRC
}
if( g_game_client->ai.party.isInParty( cha->objectID, NULL ) ) lvi.iImage = 1;
if( cha->isAlikeDead ) lvi.iImage = 2;
SendMessage( g_rw_hWndCL, LVM_SETITEM, 0, (LPARAM)&lvi );
lvi.iImage = 0;
// baseClass
szBuf2[0] = szBuf1[0] = 0;
cha->getClassStr( szBuf1 );
if( cha->classID != cha->baseClassID )
{
cha->getBaseClassStr( szBuf2 );
wsprintfW( colText, L"%s / %s", szBuf1, szBuf2 );
}
else wsprintfW( colText, L"%s", szBuf1 );
lvi.mask = LVIF_TEXT;
lvi.iItem = iItem;
lvi.iSubItem = 1;
lvi.pszText = colText;
SendMessage( g_rw_hWndCL, LVM_SETITEMTEXT, (WPARAM)iItem, (LPARAM)&lvi );
// clan
ClanList_GetClanNameByID( cha->clanID, colText ); // max 127 chars
lvi.mask = LVIF_TEXT;
lvi.iItem = iItem;
lvi.iSubItem = 2;
lvi.pszText = colText;
SendMessage( g_rw_hWndCL, LVM_SETITEMTEXT, (WPARAM)iItem, (LPARAM)&lvi );
// dZ
wsprintf( colText, TEXT("%d"), (user_z - cha->z) );
lvi.mask = LVIF_TEXT;
lvi.iItem = iItem;
lvi.iSubItem = 3;
lvi.pszText = colText;
SendMessage( g_rw_hWndCL, LVM_SETITEMTEXT, (WPARAM)iItem, (LPARAM)&lvi );
// clanwar state
lvi.mask = LVIF_TEXT;
lvi.iItem = iItem;
lvi.iSubItem = 4;
lvi.pszText = colText;
if( isEnemy )
{
colText[0] = 0;
if( !is2sidewar ) lstrcpy( colText, TEXT("<") );
if( is2sidewar ) lstrcpy( colText, TEXT("<>") );
}
SendMessage( g_rw_hWndCL, LVM_SETITEMTEXT, (WPARAM)iItem, (LPARAM)&lvi );
// update enemies also in enemies list
if( isEnemy ) RW_UpdateCharInEnemiesList( cha );
} break;
case MSG_NPC:
{
L2Npc *npc = npc_array[index];
if( !npc )
{
log_error( LOG_ERROR, "RW_OnUpdObject(): NPC found in WOT, but is NULL in array? O_o\n" );
return 0;
}
if( npc->isUnused() )
{
log_error( LOG_ERROR, "RW_OnUpdObject(): NPC is unused in array! O_o\n" );
return 0;
}
TCHAR colText[128] = {0};
wchar_t wName[128] = {0}; char aname[128] = {0};
wchar_t wTitle[128] = {0}; char atitle[128] = {0};
memset( &lvi, 0, sizeof(lvi) );
lvi.cchTextMax = 128;
lvi.pszText = colText;
// NPC name
aname[0] = atitle[0] = 0;
wName[0] = wTitle[0] = 0;
lstrcpy( colText, npc->getName() );
if( colText[0] == 0 )
{
if( L2Data_DB_GetNPCNameTitleByID( npc->templateID, aname, atitle ) )
{
MultiByteToWideChar( CP_ACP, 0, aname, -1, wName, 127 );
MultiByteToWideChar( CP_ACP, 0, atitle, -1, wTitle, 127 );
npc->setName( wName );
lstrcpy( colText, wName );
}
}
lvi.pszText = colText;
lvi.mask = LVIF_TEXT | LVIF_PARAM | LVIF_IMAGE;
lvi.iItem = iItem;
lvi.iSubItem = 0;
lvi.lParam = npc->objectID;
lvi.iImage = -1;
if( npc->isAlikeDead ) lvi.iImage = 2;
//log_error_np( LOG_OK, "Updating NPC %S, setting iImage = %d\n", npc->charName, lvi.iImage );
SendMessage( g_rw_hWndNPC, LVM_SETITEM, 0, (LPARAM)&lvi );
lvi.iImage = 0;
// NPC title
wcscpy( colText, npc->getTitle() );
if( (colText[0] == 0) && (wTitle[0]) )
{
lstrcpy( colText, wTitle );
npc->setTitle( wTitle );
}
lvi.mask = LVIF_TEXT;
lvi.iItem = iItem;
lvi.iSubItem = 1;
lvi.pszText = colText;
SendMessage( g_rw_hWndNPC, LVM_SETITEMTEXT, (WPARAM)iItem, (LPARAM)&lvi );
// NPC dZ
wsprintf( colText, TEXT("%d"), (user_z - npc->z) );
lvi.mask = LVIF_TEXT;
lvi.iItem = iItem;
lvi.iSubItem = 2;
lvi.pszText = colText;
SendMessage( g_rw_hWndNPC, LVM_SETITEMTEXT, (WPARAM)iItem, (LPARAM)&lvi );
// NPC templateID
wsprintf( colText, TEXT("%d"), npc->templateID );
lvi.mask = LVIF_TEXT;
lvi.iItem = iItem;
lvi.iSubItem = 3;
lvi.pszText = colText;
SendMessage( g_rw_hWndNPC, LVM_SETITEMTEXT, (WPARAM)iItem, (LPARAM)&lvi );
} break;
}
return 0;
}
LRESULT RW_OnDelObject( HWND hWnd, WPARAM wParam, LPARAM lParam )
{
UNREFERENCED_PARAMETER(hWnd);
// do not del npc if do not display
if( wParam == MSG_NPC && !g_radarwnd_npc_displayEnable ) return 0;
bool deleteOK = false;
HWND hWndLV = g_rw_hWndCL; // by default: delete from PC list
if( wParam == MSG_NPC ) hWndLV = g_rw_hWndNPC; // if NPC, delete from NPC list
unsigned int objectId = (unsigned int)lParam;
LVITEM lvi;
memset( &lvi, 0, sizeof(lvi) );
int idx = -1;
do
{
idx = ListView_GetNextItem( hWndLV, idx, LVNI_ALL );
if( idx == -1 ) break;
lvi.iItem = idx;
lvi.iSubItem = 0;
lvi.mask = LVIF_PARAM;
if( ListView_GetItem( hWndLV, &lvi ) )
{
if( ((unsigned int)lvi.lParam) == objectId )
{
ListView_DeleteItem( hWndLV, lvi.iItem );
deleteOK = true;
if( wParam == MSG_NPC ) return 0;
if( wParam == MSG_PC ) break;
}
}
} while( idx >= 0 );
if( deleteOK )
{
// delete also enemies from enemies list (if enemy)
if( wParam == MSG_PC )
{
//log_error( LOG_OK, "RW_OnDelObject(): MSG_PC: deleting PC\n" );
//unsigned int RELATION_MUTUAL_WAR = 0x08000;
//unsigned int RELATION_1SIDED_WAR = 0x10000;
//if( g_cfg.L2_version == L2_VERSION_T23 )
//{
// RELATION_MUTUAL_WAR = 0x04000; // gracia final constants changed
// RELATION_1SIDED_WAR = 0x08000;
//}
//L2OBJECT_TYPE objType = L2OT_NONE;
//int index = -1;
//if( WorldObjectTree_GetInfoByObjectID( objectId, &objType, &index ) )
//{
// int relation = chars_array[index]->relation;
// log_error( LOG_OK, "RW_OnDelObject(): MSG_PC: deleting PC %S relation 0x%08X\n",
// chars_array[index]->charName, chars_array[index]->relation );
// if( (relation & RELATION_1SIDED_WAR) || (relation & RELATION_MUTUAL_WAR) )
RW_DeleteCharFromEnemiesList( objectId );
//}
}
return 0;
}
// if we here, objectId not found
log_error( LOG_WARNING, "RW_OnDelObject(): cannot find oid [%u] in List-View\n", objectId );
return 0;
}
void RW_DeleteCharFromEnemiesList( unsigned int objectID )
{
LVITEM lvi;
memset( &lvi, 0, sizeof(lvi) );
int idx = -1;
do
{
idx = ListView_GetNextItem( g_rw_hWndEnemies, idx, LVNI_ALL );
if( idx == -1 ) break;
lvi.iItem = idx;
lvi.iSubItem = 0;
lvi.mask = LVIF_PARAM;
if( ListView_GetItem( g_rw_hWndEnemies, &lvi ) )
{
if( ((unsigned int)lvi.lParam) == objectID )
{
ListView_DeleteItem( g_rw_hWndEnemies, lvi.iItem );
log_error( LOG_OK, "RW_DeleteCharFromEnemiesList(): oid [%u] del OK\n", objectID );
return;
}
}
} while( idx >= 0 );
// if we here, objectId not found
// this is not error
//log_error( LOG_WARNING, "RW_DeleteCharFromEnemiesList(): cannot find char oid [%u] in List-View\n",
// cha->objectID, cha->charName );
return;
}
void RW_UpdateCharInEnemiesList( L2Player *cha )
{
int user_z = g_game_client->ai.usr.z;
// find listview itemId to update
int iItem = -1;
LVITEM lvi;
memset( &lvi, 0, sizeof(lvi) );
int idx = -1;
do
{
idx = ListView_GetNextItem( g_rw_hWndEnemies, idx, LVNI_ALL );
if( idx == -1 ) break;
lvi.iItem = idx;
lvi.iSubItem = 0;
lvi.mask = LVIF_PARAM;
if( ListView_GetItem( g_rw_hWndEnemies, &lvi ) )
{
if( ((unsigned int)lvi.lParam) == cha->objectID )
{
iItem = lvi.iItem;
break;
}
}
} while( idx >= 0 );
if( iItem == -1 )
{
// not found
log_error( LOG_WARNING, "RW_UpdateCharInEnemiesList(): cannot find objectId [%u] in Enemies LV to update\n",
cha->objectID );
return;
}
memset( &lvi, 0, sizeof(lvi) );
lvi.iItem = iItem;
lvi.lParam = (LPARAM)(cha->objectID);
// ok, adding
bool isEnemy = false;
bool is2sidewar = false;
TCHAR colText[128] = {0};
TCHAR szBuf1[128] = {0};
TCHAR szBuf2[128] = {0};
memset( &lvi, 0, sizeof(lvi) );
lvi.cchTextMax = 128;
lvi.pszText = colText;
// detect clan war
utils_detectClanWar( cha->relation, &isEnemy, &is2sidewar );
// name
lstrcpy( colText, cha->getName() );
lvi.pszText = colText;
lvi.mask = LVIF_TEXT | LVIF_PARAM | LVIF_IMAGE;
lvi.iItem = iItem;
lvi.iSubItem = 0;
lvi.lParam = cha->objectID;
// image
lvi.iImage = -1;
if( isEnemy )
{
lvi.iImage = 0;
if( !is2sidewar ) lvi.iImage = 3;
}
if( g_game_client->ai.party.isInParty( cha->objectID, NULL ) ) lvi.iImage = 1;
if( cha->isAlikeDead ) lvi.iImage = 2;
SendMessage( g_rw_hWndEnemies, LVM_SETITEM, 0, (LPARAM)&lvi );
lvi.iImage = 0;
// baseClass
szBuf2[0] = szBuf1[0] = 0;
cha->getClassStr( szBuf1 );
if( cha->classID != cha->baseClassID )
{
cha->getBaseClassStr( szBuf2 );
wsprintfW( colText, L"%s / %s", szBuf1, szBuf2 );
}
else wsprintfW( colText, L"%s", szBuf1 );
lvi.mask = LVIF_TEXT;
lvi.iItem = iItem;
lvi.iSubItem = 1;
lvi.pszText = colText;
SendMessage( g_rw_hWndEnemies, LVM_SETITEMTEXT, (WPARAM)iItem, (LPARAM)&lvi );
// clan
ClanList_GetClanNameByID( cha->clanID, colText ); // max 127 chars
lvi.mask = LVIF_TEXT;
lvi.iItem = iItem;
lvi.iSubItem = 2;
lvi.pszText = colText;
SendMessage( g_rw_hWndEnemies, LVM_SETITEMTEXT, (WPARAM)iItem, (LPARAM)&lvi );
// dZ
wsprintf( colText, TEXT("%d"), (user_z - cha->z) );
lvi.mask = LVIF_TEXT;
lvi.iItem = iItem;
lvi.iSubItem = 3;
lvi.pszText = colText;
SendMessage( g_rw_hWndEnemies, LVM_SETITEMTEXT, (WPARAM)iItem, (LPARAM)&lvi );
// clanwar state
lvi.mask = LVIF_TEXT;
lvi.iItem = iItem;
lvi.iSubItem = 4;
lvi.pszText = colText;
if( isEnemy )
{
colText[0] = 0;
if( !is2sidewar ) lstrcpy( colText, TEXT("<") );
if( is2sidewar ) lstrcpy( colText, TEXT("<>") );
}
SendMessage( g_rw_hWndEnemies, LVM_SETITEMTEXT, (WPARAM)iItem, (LPARAM)&lvi );
}
void RadarWnd_ForceUpdateCharsList()
{
PostMessage( g_radardll_hwnd, WMMY_FORCE_UPDATE_LIST, FORCE_UPDATE_CHARS_LIST, 0 );
}
void RadarWnd_ForceUpdateNpcsList()
{
PostMessage( g_radardll_hwnd, WMMY_FORCE_UPDATE_LIST, FORCE_UPDATE_NPCS_LIST, 0 );
}
LRESULT RW_OnUpdateCharsList( HWND hWnd )
{
UNREFERENCED_PARAMETER(hWnd);
// window is visible?
//if( bRadarWindowIsVisible == FALSE ) return 0;
// check too fast updates timeout
//DWORD dwCurTickTime = GetTickCount();
//if( dwCurTickTime < (dwRadarDllLastCharListUpdateTime + 1000) ) return 0;
//dwRadarDllLastCharListUpdateTime = dwCurTickTime;
// IN_GAME?
//if( g_game_client->getState() != GCST_IN_GAME ) return 0;
// delete all items from list-view
SendMessage( g_rw_hWndCL, LVM_DELETEALLITEMS, 0, 0 );
// delete all items from enemies list-view
SendMessage( g_rw_hWndEnemies, LVM_DELETEALLITEMS, 0, 0 );
//
int user_z;
user_z = g_game_client->ai.usr.z;
int i;
TCHAR colText[128] = {0};
TCHAR szBuf1[128] = {0};
TCHAR szBuf2[128] = {0};
LVITEM lvi;
memset( &lvi, 0, sizeof(lvi) );
lvi.cchTextMax = 128;
lvi.pszText = colText;
bool isEnemy = false;
bool is2sidewar = false;
for( i=0; i<CHARARRAY_MAX_CHARS; i++ )
{
L2Player *cha = chars_array[i];
if( !cha ) continue;
if( cha->isUnused() ) continue;
isEnemy = false;
is2sidewar = false;
utils_detectClanWar( cha->relation, &isEnemy, &is2sidewar );
// name
lstrcpy( colText, cha->getName() );
lvi.pszText = colText;
lvi.mask = LVIF_TEXT | LVIF_PARAM | LVIF_IMAGE;
lvi.iItem = 999;
lvi.iSubItem = 0;
lvi.lParam = cha->objectID;
// image
lvi.iImage = -1;
if( isEnemy )
{
lvi.iImage = 0;
if( !is2sidewar ) lvi.iImage = 3;
}
if( g_game_client->ai.party.isInParty( cha->objectID, NULL ) ) lvi.iImage = 1;
if( cha->isAlikeDead ) lvi.iImage = 2;
int added_item = -1;
int added_item2 = -1;
added_item = (int)SendMessage( g_rw_hWndCL, LVM_INSERTITEM, 0, (LPARAM)&lvi );
if( added_item == -1 ) continue;
if( isEnemy )
{
// add enemies also to enemies tab
added_item2 = (int)SendMessage( g_rw_hWndEnemies, LVM_INSERTITEM, 0, (LPARAM)&lvi );
}
lvi.iImage = 0;
// baseClass
#ifdef UNICODE
szBuf2[0] = szBuf1[0] = 0;
cha->getClassStr( szBuf1 );
if( cha->classID != cha->baseClassID )
{
cha->getBaseClassStr( szBuf2 );
wsprintfW( colText, L"%s / %s", szBuf1, szBuf2 );
}
else wsprintfW( colText, L"%s", szBuf1 );
#else
//wsprintfA( colText, "%s/%s", cha->classStr(), cha->baseClassStr() );
#endif
lvi.mask = LVIF_TEXT;
lvi.iItem = added_item;
lvi.iSubItem = 1;
lvi.pszText = colText;
SendMessage( g_rw_hWndCL, LVM_SETITEM, 0, (LPARAM)&lvi );
if( isEnemy )
{
// add enemies info also to enemies tab
lvi.iItem = added_item2;
SendMessage( g_rw_hWndEnemies, LVM_SETITEM, 0, (LPARAM)&lvi );
}
// clan
ClanList_GetClanNameByID( cha->clanID, colText ); // max 127 chars
lvi.mask = LVIF_TEXT;
lvi.iItem = added_item;
lvi.iSubItem = 2;
lvi.pszText = colText;
SendMessage( g_rw_hWndCL, LVM_SETITEM, 0, (LPARAM)&lvi );
if( isEnemy )
{
// add enemies info also to enemies tab
lvi.iItem = added_item2;
SendMessage( g_rw_hWndEnemies, LVM_SETITEM, 0, (LPARAM)&lvi );
}
// dZ
wsprintf( colText, TEXT("%d"), (user_z - cha->z) );
lvi.mask = LVIF_TEXT;
lvi.iItem = added_item;
lvi.iSubItem = 3;
lvi.pszText = colText;
SendMessage( g_rw_hWndCL, LVM_SETITEM, 0, (LPARAM)&lvi );
if( isEnemy )
{
// add enemies info also to enemies tab
lvi.iItem = added_item2;
SendMessage( g_rw_hWndEnemies, LVM_SETITEM, 0, (LPARAM)&lvi );
}
// clanwar state
if( isEnemy )
{
lvi.mask = LVIF_TEXT;
lvi.iItem = added_item;
lvi.iSubItem = 4;
lvi.pszText = colText;
colText[0] = 0;
if( isEnemy && !is2sidewar ) lstrcpy( colText, TEXT("<") );
if( isEnemy && is2sidewar ) lstrcpy( colText, TEXT("<>") );
if( colText[0] )
{
SendMessage( g_rw_hWndCL, LVM_SETITEM, 0, (LPARAM)&lvi );
// add enemies info also to enemies tab
lvi.iItem = added_item2;
SendMessage( g_rw_hWndEnemies, LVM_SETITEM, 0, (LPARAM)&lvi );
}
}
}
return 0;
}
LRESULT RW_OnUpdateNpcsList( HWND hWnd )
{
UNREFERENCED_PARAMETER(hWnd);
// in game?
if( g_game_client->getState() != GCST_IN_GAME ) return 0;
// clear ListView
SendMessage( g_rw_hWndNPC, LVM_DELETEALLITEMS, 0, 0 );
if( g_radarwnd_npc_displayEnable == 0 ) return 0;
//
int user_z;
user_z = g_game_client->ai.usr.z;
int i;
TCHAR colText[128] = {0};
wchar_t wName[128] = {0}; char aname[128] = {0};
wchar_t wTitle[128] = {0}; char atitle[128] = {0};
LVITEM lvi;
memset( &lvi, 0, sizeof(lvi) );
lvi.cchTextMax = 128;
lvi.pszText = colText;
for( i=0; i<NPCA_MAX_NPCS; i++ )
{
//
aname[0] = atitle[0] = 0;
wName[0] = wTitle[0] = 0;
//
L2Npc *npc = npc_array[i];
if( !npc ) continue;
if( npc->isUnused() ) continue;
// name
lstrcpy( colText, npc->getName() );
if( colText[0] == 0 )
{
if( L2Data_DB_GetNPCNameTitleByID( npc->templateID, aname, atitle ) )
{
MultiByteToWideChar( CP_ACP, 0, aname, -1, wName, 127 );
MultiByteToWideChar( CP_ACP, 0, atitle, -1, wTitle, 127 );
npc->setName( wName );
//npc->setTitle( wTitle );
lstrcpy( colText, wName );
}
}
lvi.pszText = colText;
lvi.mask = LVIF_TEXT | LVIF_PARAM | LVIF_IMAGE;
lvi.iItem = 999;
lvi.iSubItem = 0;
lvi.lParam = npc->objectID;
lvi.iImage = -1;
if( npc->isAlikeDead ) lvi.iImage = 2;
int added_item = (int)SendMessage( g_rw_hWndNPC, LVM_INSERTITEM, 0, (LPARAM)&lvi );
if( added_item == -1 ) continue;
lvi.iImage = 0;
// title
#ifdef UNICODE
wcscpy( colText, npc->getTitle() );
if( (colText[0] == 0) && (wTitle[0]) )
{
lstrcpy( colText, wTitle );
npc->setTitle( wTitle );
}
#else
wsprintfA( colText, "%S", npc->getTitle() );
#endif
lvi.mask = LVIF_TEXT;
lvi.iItem = added_item;
lvi.iSubItem = 1;
lvi.pszText = colText;
SendMessage( g_rw_hWndNPC, LVM_SETITEM, 0, (LPARAM)&lvi );
// dZ
wsprintf( colText, TEXT("%d"), (user_z - npc->z) );
lvi.mask = LVIF_TEXT;
lvi.iItem = added_item;
lvi.iSubItem = 2;
lvi.pszText = colText;
SendMessage( g_rw_hWndNPC, LVM_SETITEM, 0, (LPARAM)&lvi );
// templateID
wsprintf( colText, TEXT("%d"), npc->templateID );
lvi.mask = LVIF_TEXT;
lvi.iItem = added_item;
lvi.iSubItem = 3;
lvi.pszText = colText;
SendMessage( g_rw_hWndNPC, LVM_SETITEM, 0, (LPARAM)&lvi );
}
return 0;
}

319
l2detect/RadarSetupDlg.cpp Normal file
View File

@@ -0,0 +1,319 @@
#include "stdafx.h"
#include "Resource.h"
#include "ConfigIni.h"
//#include "GameClient.h"
#include "ConfigDlg.h"
#include "Logger.h"
// children
#include "RadarSetupDlg_SelfHeal.h"
#include "RadarSetupDlg_OffpartyBDSWS.h"
#include "RadarSetupDlg_SoundAlerts.h"
#include "RadarSetupDlg_Colors.h"
#include "RadarSetupDlg_InvisGM.h"
#include "RadarSetupDlg_QuickTarget.h"
#include "RadarSetupDlg_LT.h"
#include "RadarSetupDlg_FolAsi.h"
extern HINSTANCE g_radardll_hinst;
extern class CConfig g_cfg;
INT_PTR CALLBACK RadarSetupDlgProc( HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam );
void RadarSetupDlgStart( HWND hWndParent )
{
DialogBoxParam( g_radardll_hinst, MAKEINTRESOURCE(IDD_SETUPRADAR), hWndParent, RadarSetupDlgProc, 0 );
}
HWND rs_hwndTV;
//HTREEITEM
// lParams
#define L_HEAL_USEITEMS 1
#define L_HEAL_USESKILL 2
#define L_QUICK_TARGET 3
#define L_LOCK_TARGET 4
#define L_ASSIST_FOLLOW 5
#define L_OFFPARTY_BDSWS 6
#define L_SOUND_ALERTS 7
#define L_COLORS 8
#define L_INIVIS_GM 9
#define RS_CHILD_COUNT 9
HWND radarSetupDlg_children[ RS_CHILD_COUNT + 1 ];
void RadarSetupDlg_OnInitDialog( HWND hDlg );
void RadarSetupDlg_OnOK( HWND hDlg );
void RadarSetupDlg_OnCancel( HWND hDlg );
void RadarSetupDlg_OnCommand( HWND hDlg, WPARAM wParam, LPARAM lParam );
void RadarSetupDlg_OnNotify( HWND hDlg, WPARAM wParam, LPARAM lParam );
void RadarSetupDlg_OnTreeViewSelChanging( HWND hDlg, LPARAM lParam );
void RadarSetupDlg_OnTreeViewSelChanged( HWND hDlg, LPARAM lParam );
INT_PTR CALLBACK RadarSetupDlgProc( HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam )
{
switch( uMsg )
{
case WM_INITDIALOG: RadarSetupDlg_OnInitDialog( hDlg ); break;
case WM_COMMAND: RadarSetupDlg_OnCommand( hDlg, wParam, lParam ); break;
case WM_NOTIFY: RadarSetupDlg_OnNotify( hDlg, wParam, lParam ); break;
default: return FALSE; break;
}
return true;
}
void RadarSetupDlg_OnInitDialog_InitTreeView( HWND hDlg )
{
rs_hwndTV = GetDlgItem( hDlg, IDC_T_CONFIG );
TCHAR text[256] = {0};
HTREEITEM htiHealing = NULL;
HTREEITEM htiParty = NULL;
HTREEITEM htiTargets = NULL;
HTREEITEM htiLookAndFeel = NULL;
HTREEITEM htiHacks = NULL;
TVINSERTSTRUCT tvis;
// insert at root
tvis.hParent = NULL;
tvis.hInsertAfter = TVI_LAST;
tvis.item.mask = TVIF_CHILDREN | TVIF_PARAM | TVIF_STATE | TVIF_TEXT;
tvis.item.stateMask = TVIS_BOLD | TVIS_EXPANDED;
// insert Healing
tvis.item.lParam = 0;
tvis.item.cChildren = 1;
tvis.item.state = TVIS_BOLD | TVIS_EXPANDED;
tvis.item.pszText = text;
lstrcpy( text, TEXT("Self") );
htiHealing = TreeView_InsertItem( rs_hwndTV, &tvis );
// insert Party
tvis.item.lParam = 0;
tvis.item.cChildren = 1;
tvis.item.state = TVIS_BOLD | TVIS_EXPANDED;
tvis.item.pszText = text;
lstrcpy( text, TEXT("Party") );
htiParty = TreeView_InsertItem( rs_hwndTV, &tvis );
// insert Targeting
tvis.item.lParam = 0;
tvis.item.cChildren = 1;
tvis.item.state = TVIS_BOLD | TVIS_EXPANDED;
tvis.item.pszText = text;
lstrcpy( text, TEXT("PvP settings") );
htiTargets = TreeView_InsertItem( rs_hwndTV, &tvis );
// insert LookAndFeel
tvis.item.lParam = 0;
tvis.item.cChildren = 1;
tvis.item.state = TVIS_BOLD | TVIS_EXPANDED;
tvis.item.pszText = text;
lstrcpy( text, TEXT("Look And Feel") );
htiLookAndFeel = TreeView_InsertItem( rs_hwndTV, &tvis );
// insert hacks
tvis.item.lParam = 0;
tvis.item.cChildren = 1;
tvis.item.state = TVIS_BOLD | TVIS_EXPANDED;
tvis.item.pszText = text;
lstrcpy( text, TEXT("Hacks!") );
htiHacks = TreeView_InsertItem( rs_hwndTV, &tvis );
// insert children
// insert Healing children
tvis.hParent = htiHealing;
tvis.hInsertAfter = TVI_LAST;
//
tvis.item.lParam = L_HEAL_USEITEMS;
tvis.item.cChildren = 0;
tvis.item.state = 0;
tvis.item.pszText = text;
lstrcpy( text, TEXT("Heal Use Items") );
TreeView_InsertItem( rs_hwndTV, &tvis );
//
tvis.item.lParam = L_HEAL_USESKILL;
tvis.item.cChildren = 0;
tvis.item.state = 0;
tvis.item.pszText = text;
lstrcpy( text, TEXT("Heal Use Skills") );
TreeView_InsertItem( rs_hwndTV, &tvis );
//
// insert Party children
tvis.hParent = htiParty;
tvis.hInsertAfter = TVI_LAST;
//
tvis.item.lParam = L_OFFPARTY_BDSWS;
tvis.item.cChildren = 0;
tvis.item.state = 0;
tvis.item.pszText = text;
lstrcpy( text, TEXT("Offparty dance/song") );
TreeView_InsertItem( rs_hwndTV, &tvis );
//
// insert Targets children
tvis.hParent = htiTargets;
tvis.hInsertAfter = TVI_LAST;
//
tvis.item.lParam = L_QUICK_TARGET;
tvis.item.cChildren = 0;
tvis.item.state = 0;
tvis.item.pszText = text;
lstrcpy( text, TEXT("Quick targeting") );
TreeView_InsertItem( rs_hwndTV, &tvis );
//
tvis.item.lParam = L_LOCK_TARGET;
tvis.item.cChildren = 0;
tvis.item.state = 0;
tvis.item.pszText = text;
lstrcpy( text, TEXT("Lock target") );
TreeView_InsertItem( rs_hwndTV, &tvis );
//
tvis.item.lParam = L_ASSIST_FOLLOW;
tvis.item.cChildren = 0;
tvis.item.state = 0;
tvis.item.pszText = text;
lstrcpy( text, TEXT("Assist & follow") );
TreeView_InsertItem( rs_hwndTV, &tvis );
//
// insert LookAndFeel children
tvis.hParent = htiLookAndFeel;
tvis.hInsertAfter = TVI_LAST;
// insert colors
tvis.item.lParam = L_COLORS;
tvis.item.cChildren = 0;
tvis.item.state = 0;
tvis.item.pszText = text;
lstrcpy( text, TEXT("Colors") );
TreeView_InsertItem( rs_hwndTV, &tvis );
// insert Sound Alerts
tvis.item.lParam = L_SOUND_ALERTS;
tvis.item.cChildren = 0;
tvis.item.state = 0;
tvis.item.pszText = text;
lstrcpy( text, TEXT("Sound Alerts") );
TreeView_InsertItem( rs_hwndTV, &tvis );
//
// insert Hacks children
tvis.hParent = htiHacks;
tvis.hInsertAfter = TVI_LAST;
//
tvis.item.lParam = L_INIVIS_GM;
tvis.item.cChildren = 0;
tvis.item.state = 0;
tvis.item.pszText = text;
lstrcpy( text, TEXT("Invisible objects detection") );
TreeView_InsertItem( rs_hwndTV, &tvis );
}
void RadarSetupDlg_OnInitDialog_InitChildren( HWND hDlg )
{
RECT r, rd;
int tree_x = 0;
int tree_w = 0;
int right_w = 0;
int h = 0;
HWND htv = GetDlgItem( hDlg, IDC_T_CONFIG );
GetWindowRect( htv, &r );
GetClientRect( hDlg, &rd );
tree_x = 20;
tree_w = r.right - r.left;
right_w = rd.right - rd.left - tree_w - tree_x - 10;
h = r.bottom - r.top;
int i;
radarSetupDlg_children[0] = 0;
radarSetupDlg_children[L_HEAL_USEITEMS] = RadarSetupDlg_SelfHeal_Create( hDlg );
radarSetupDlg_children[L_HEAL_USESKILL] = NULL; // TODO
radarSetupDlg_children[L_OFFPARTY_BDSWS] = RadarSetupDlg_OFFBDSWS_Create( hDlg );
radarSetupDlg_children[L_QUICK_TARGET] = RadarSetupDlg_QuickTarget_Create( hDlg );
radarSetupDlg_children[L_LOCK_TARGET] = RadarSetupDlg_LockTarget_Create( hDlg );
radarSetupDlg_children[L_ASSIST_FOLLOW] = RadarSetupDlg_FolAsi_Create( hDlg ); // TODO
radarSetupDlg_children[L_SOUND_ALERTS] = RadarSetupDlg_SoundAlerts_Create( hDlg );
radarSetupDlg_children[L_COLORS] = RadarSetupDlg_Colors_Create( hDlg );
radarSetupDlg_children[L_INIVIS_GM] = RadarSetupDlg_InvisGM_Create( hDlg );
// fix windows
//DWORD dwStyle;
for( i=1; i<=RS_CHILD_COUNT; i++ )
{
//dwStyle = GetWindowLongPtr( radarSetupDlg_children[i], GWL_STYLE );
//dwStyle |= WS_CHILD;
//SetWindowLongPtr( radarSetupDlg_children[i], GWL_STYLE, (LONG)dwStyle );
MoveWindow( radarSetupDlg_children[i], tree_x + tree_w + 5, 5, right_w, h, TRUE );
}
}
void RadarSetupDlg_OnInitDialog_DestroyChildren()
{
int i = RS_CHILD_COUNT;
while( i>0 )
{
if( radarSetupDlg_children[i] )
{
SendMessage( radarSetupDlg_children[i], WM_COMMAND, IDC_APPLY, 0 );
DestroyWindow( radarSetupDlg_children[i] );
}
i--;
}
}
void RadarSetupDlg_OnInitDialog( HWND hDlg )
{
RadarSetupDlg_OnInitDialog_InitChildren( hDlg );
RadarSetupDlg_OnInitDialog_InitTreeView( hDlg );
}
void RadarSetupDlg_OnOK( HWND hDlg )
{
RadarSetupDlg_OnInitDialog_DestroyChildren();
EndDialog( hDlg, IDOK );
}
void RadarSetupDlg_OnCancel( HWND hDlg )
{
RadarSetupDlg_OnInitDialog_DestroyChildren();
EndDialog( hDlg, IDOK );
}
void RadarSetupDlg_OnTreeViewSelChanging( HWND hDlg, LPARAM lParam )
{
hDlg;
LPNMTREEVIEW p = (LPNMTREEVIEW)lParam;
int idx = (int)(p->itemOld.lParam);
if( (idx >= 1) && (idx <= RS_CHILD_COUNT) )
{
if( radarSetupDlg_children[idx] )
ShowWindow( radarSetupDlg_children[idx], SW_HIDE );
}
}
void RadarSetupDlg_OnTreeViewSelChanged( HWND hDlg, LPARAM lParam )
{
hDlg;
LPNMTREEVIEW p = (LPNMTREEVIEW)lParam;
int idx = (int)(p->itemNew.lParam);
if( (idx >= 1) && (idx <= RS_CHILD_COUNT) )
{
if( radarSetupDlg_children[idx] )
ShowWindow( radarSetupDlg_children[idx], SW_SHOW );
}
}
void RadarSetupDlg_OnCommand( HWND hDlg, WPARAM wParam, LPARAM lParam )
{
lParam;
switch( LOWORD(wParam) )
{
case IDOK: RadarSetupDlg_OnOK( hDlg ); break;
case IDCANCEL: RadarSetupDlg_OnCancel( hDlg ); break;
case IDC_NPSETUP: ConfigDialogStart( hDlg ); break;
}
}
void RadarSetupDlg_OnNotify( HWND hDlg, WPARAM wParam, LPARAM lParam )
{
wParam;
LPNMHDR pnmh = (LPNMHDR)lParam;
if( pnmh == NULL ) return;
switch( pnmh->code )
{
case TVN_SELCHANGING:
{
if( pnmh->hwndFrom == rs_hwndTV ) RadarSetupDlg_OnTreeViewSelChanging( hDlg, lParam );
} break;
case TVN_SELCHANGED:
{
if( pnmh->hwndFrom == rs_hwndTV ) RadarSetupDlg_OnTreeViewSelChanged( hDlg, lParam );
} break;
}
}

6
l2detect/RadarSetupDlg.h Normal file
View File

@@ -0,0 +1,6 @@
#ifndef H_RADARSETUPDLG
#define H_RADARSETUPDLG
void RadarSetupDlgStart( HWND hWndParent );
#endif

View File

@@ -0,0 +1,140 @@
#include "stdafx.h"
#include "Resource.h"
#include "Logger.h"
#include "GameClient.h"
#include "RadarDllWndCfg.h"
extern HINSTANCE g_radardll_hinst;
extern class GameClient *g_game_client; // in main.cpp
// radar window UI config
extern RADARWNDCFG g_rwCfg; // in RadarDllWndProc.cpp
INT_PTR CALLBACK Colors_DlgProc( HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam );
HWND RadarSetupDlg_Colors_Create( HWND hWndParent )
{
return CreateDialogParam( g_radardll_hinst, MAKEINTRESOURCE(IDD_SR_COLORS),
hWndParent, Colors_DlgProc, 0 );
}
// =========================================================
void Colors_Init( HWND hDlg );
void Colors_OnDestroy( HWND hDlg );
void Colors_OnApply( HWND hDlg );
void Colors_OnPaint( HWND hDlg );
void Colors_OnSelColor( HWND hDlg, int idx );
INT_PTR CALLBACK Colors_DlgProc( HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam )
{
lParam;
switch( uMsg )
{
case WM_INITDIALOG: Colors_Init( hDlg ); break;
case WM_DESTROY: { Colors_OnDestroy( hDlg ); return FALSE; } break;
case WM_COMMAND:
{
switch( LOWORD(wParam) )
{
case IDC_APPLY: Colors_OnApply( hDlg ); break;
// colors
case IDC_B_SELNPCCOLOR: Colors_OnSelColor( hDlg, 0 ); break;
case IDC_B_SELMOBCOLOR: Colors_OnSelColor( hDlg, 1 ); break;
case IDC_B_SELPLAYERCOLOR: Colors_OnSelColor( hDlg, 2 ); break;
case IDC_B_SELDEADPLAYERCOLOR: Colors_OnSelColor( hDlg, 3 ); break;
case IDC_B_SELPARTYPLAYERCOLOR: Colors_OnSelColor( hDlg, 4 ); break;
case IDC_B_SELDEADPARTYPLAYERCOLOR: Colors_OnSelColor( hDlg, 5 ); break;
case IDC_B_SELENEMYPLAYERCOLOR: Colors_OnSelColor( hDlg, 6 ); break;
case IDC_B_SELDEADENEMYPLAYERCOLOR: Colors_OnSelColor( hDlg, 7 ); break;
}
} break;
case WM_PAINT: Colors_OnPaint( hDlg ); break;
default: return FALSE; break;
}
return TRUE;
}
void Colors_Init( HWND hDlg )
{
hDlg;
//log_error( LOG_OK, "Colors_Init\n" );
}
void Colors_OnDestroy( HWND hDlg )
{
hDlg;
//log_error( LOG_OK, "Colors_OnDestroy\n" );
}
void Colors_OnApply( HWND hDlg )
{
hDlg;
//log_error( LOG_OK, "Colors_OnApply\n" );
RadarWndCfg_SaveConfigToFile( &g_rwCfg, NULL );
}
void Colors_OnPaint( HWND hDlg )
{
PAINTSTRUCT ps;
HDC hdc;
hdc = BeginPaint( hDlg, &ps );
HPEN hPenPrev = (HPEN)SelectObject( hdc, GetStockObject( DC_PEN ) );
HBRUSH hBrushPrev = (HBRUSH)SelectObject( hdc, GetStockObject( DC_BRUSH ) );
//
SetDCPenColor( hdc, RGB(0,0,0) );
int i;
for( i=0; i<8; i++ )
{
switch( i )
{
case 0: SetDCBrushColor( hdc, g_rwCfg.ui.colors.npcColor ); break;
case 1: SetDCBrushColor( hdc, g_rwCfg.ui.colors.mobColor ); break;
case 2: SetDCBrushColor( hdc, g_rwCfg.ui.colors.pcColor ); break;
case 3: SetDCBrushColor( hdc, g_rwCfg.ui.colors.pcColorDead ); break;
case 4: SetDCBrushColor( hdc, g_rwCfg.ui.colors.pcColorParty ); break;
case 5: SetDCBrushColor( hdc, g_rwCfg.ui.colors.pcColorPartyDead ); break;
case 6: SetDCBrushColor( hdc, g_rwCfg.ui.colors.pcColorWar ); break;
case 7: SetDCBrushColor( hdc, g_rwCfg.ui.colors.pcColorWarDead ); break;
}
Rectangle( hdc, 240, 5 + i*21, 260, 5 + i*21+15 );
}
//
SelectObject( hdc, (HGDIOBJ)hBrushPrev );
SelectObject( hdc, (HGDIOBJ)hPenPrev );
EndPaint( hDlg, &ps );
}
COLORREF Colors_MyChooseColor( HWND hDlg, COLORREF in )
{
COLORREF init = in;
COLORREF custColors[16] = {0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0};
CHOOSECOLOR cc;
memset( &cc, 0, sizeof(cc) );
cc.lStructSize = sizeof(cc);
cc.hwndOwner = hDlg;
cc.rgbResult = in;
cc.lpCustColors = custColors;
cc.Flags = CC_ANYCOLOR | CC_FULLOPEN | CC_RGBINIT;
if( ChooseColor( &cc ) ) init = cc.rgbResult;
return init;
}
void Colors_OnSelColor( HWND hDlg, int idx )
{
switch( idx )
{
case 0: g_rwCfg.ui.colors.npcColor = Colors_MyChooseColor( hDlg, g_rwCfg.ui.colors.npcColor ); break;
case 1: g_rwCfg.ui.colors.mobColor = Colors_MyChooseColor( hDlg, g_rwCfg.ui.colors.mobColor ); break;
case 2: g_rwCfg.ui.colors.pcColor = Colors_MyChooseColor( hDlg, g_rwCfg.ui.colors.pcColor ); break;
case 3: g_rwCfg.ui.colors.pcColorDead = Colors_MyChooseColor( hDlg, g_rwCfg.ui.colors.pcColorDead ); break;
case 4: g_rwCfg.ui.colors.pcColorParty = Colors_MyChooseColor( hDlg, g_rwCfg.ui.colors.pcColorParty ); break;
case 5: g_rwCfg.ui.colors.pcColorPartyDead = Colors_MyChooseColor( hDlg, g_rwCfg.ui.colors.pcColorPartyDead ); break;
case 6: g_rwCfg.ui.colors.pcColorWar = Colors_MyChooseColor( hDlg, g_rwCfg.ui.colors.pcColorWar ); break;
case 7: g_rwCfg.ui.colors.pcColorWarDead = Colors_MyChooseColor( hDlg, g_rwCfg.ui.colors.pcColorWarDead ); break;
}
RedrawWindow( hDlg, NULL, NULL, RDW_INVALIDATE );
}

View File

@@ -0,0 +1,6 @@
#ifndef H_RadarSetupDlg_Colors
#define H_RadarSetupDlg_Colors
HWND RadarSetupDlg_Colors_Create( HWND hWndParent );
#endif

View File

@@ -0,0 +1,109 @@
#include "stdafx.h"
#include "Resource.h"
#include "Logger.h"
#include "GameClient.h"
#include "DlgPressKey.h"
#include "windowUtils.h"
#include "RadarSetupDlg_FolAsi.h"
extern HINSTANCE g_radardll_hinst;
extern class GameClient *g_game_client; // in main.cpp
INT_PTR CALLBACK RadarSetupDlg_FollowAssist_DlgProc( HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam );
HWND RadarSetupDlg_FolAsi_Create( HWND hWndParent )
{
return CreateDialogParam( g_radardll_hinst, MAKEINTRESOURCE(IDD_SR_FOLLOWASSIST),
hWndParent, RadarSetupDlg_FollowAssist_DlgProc, 0 );
}
// =========================================================
void RadarSetupDlg_FollowAssist_Init( HWND hDlg );
void RadarSetupDlg_FollowAssist_OnDestroy( HWND hDlg );
void RadarSetupDlg_FollowAssist_OnApply( HWND hDlg );
// =====================================
void RadarSetupDlg_FollowAssist_UpdateDisabledWindows( HWND hDlg );
INT_PTR CALLBACK RadarSetupDlg_FollowAssist_DlgProc( HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam )
{
UNREFERENCED_PARAMETER(lParam);
switch( uMsg )
{
case WM_INITDIALOG: RadarSetupDlg_FollowAssist_Init( hDlg ); break;
case WM_DESTROY: { RadarSetupDlg_FollowAssist_OnDestroy( hDlg ); return FALSE; } break;
case WM_COMMAND:
{
switch( LOWORD(wParam) )
{
case IDC_APPLY: RadarSetupDlg_FollowAssist_OnApply( hDlg ); break;
case IDC_C_FOLLOW_ENABLE:
case IDC_C_ASSIST_ENABLE:
RadarSetupDlg_FollowAssist_UpdateDisabledWindows( hDlg );
break;
}
} break;
default: return FALSE; break;
}
return TRUE;
}
void RadarSetupDlg_FollowAssist_Init( HWND hDlg )
{
// force UserAI to reload config file
g_game_client->ai.folAsiCfg.loadFromFile( "L2Detect_folAsi.ini" );
// follow sets
CheckDlgButton( hDlg, IDC_C_FOLLOW_ENABLE, g_game_client->ai.folAsiCfg.m_follow_enable );
SetDlgItemInt( hDlg, IDC_E_FOLLOW_DISTANCE, g_game_client->ai.folAsiCfg.m_follow_dist, FALSE );
SetDlgItemTextW( hDlg, IDC_E_NAME_FOLLOW, g_game_client->ai.folAsiCfg.m_follow_name );
CheckDlgButton( hDlg, IDC_C_FOLLOW_ONLY_IN_PARTY, g_game_client->ai.folAsiCfg.m_follow_only_in_party );
// assist sets
CheckDlgButton( hDlg, IDC_C_ASSIST_ENABLE, g_game_client->ai.folAsiCfg.m_assist_enable );
SetDlgItemTextW( hDlg, IDC_E_NAME_ASSIST, g_game_client->ai.folAsiCfg.m_assist_name );
CheckDlgButton( hDlg, IDC_C_ASSIST_ONLY_IN_PARTY, g_game_client->ai.folAsiCfg.m_assist_only_in_party );
CheckDlgButton( hDlg, IDC_C_DONT_ASSIST_ALLIES, g_game_client->ai.folAsiCfg.m_assist_dont_ally );
//
RadarSetupDlg_FollowAssist_UpdateDisabledWindows( hDlg );
}
void RadarSetupDlg_FollowAssist_OnDestroy( HWND hDlg )
{
UNREFERENCED_PARAMETER(hDlg);
}
void RadarSetupDlg_FollowAssist_OnApply( HWND hDlg )
{
// follow sets
g_game_client->ai.folAsiCfg.m_follow_enable = IsDlgButtonChecked( hDlg, IDC_C_FOLLOW_ENABLE );
g_game_client->ai.folAsiCfg.m_follow_dist = (int)GetDlgItemInt( hDlg, IDC_E_FOLLOW_DISTANCE, NULL, FALSE );
GetDlgItemTextW( hDlg, IDC_E_NAME_FOLLOW, g_game_client->ai.folAsiCfg.m_follow_name, 127 );
g_game_client->ai.folAsiCfg.m_follow_only_in_party = IsDlgButtonChecked( hDlg, IDC_C_FOLLOW_ONLY_IN_PARTY );
// assist sets
g_game_client->ai.folAsiCfg.m_assist_enable = IsDlgButtonChecked( hDlg, IDC_C_ASSIST_ENABLE );
GetDlgItemTextW( hDlg, IDC_E_NAME_ASSIST, g_game_client->ai.folAsiCfg.m_assist_name, 127 );
g_game_client->ai.folAsiCfg.m_assist_only_in_party = IsDlgButtonChecked( hDlg, IDC_C_ASSIST_ONLY_IN_PARTY );
g_game_client->ai.folAsiCfg.m_assist_dont_ally = IsDlgButtonChecked( hDlg, IDC_C_DONT_ASSIST_ALLIES );
// save config to file
g_game_client->ai.folAsiCfg.saveToFile( "L2Detect_folAsi.ini" );
// checks
if( !g_game_client->ai.folAsiCfg.m_follow_enable )
g_game_client->ai.followDisable(); // zero follow objectID
if( !g_game_client->ai.folAsiCfg.m_assist_enable )
g_game_client->ai.assistDisable(); // zero assist objectID
}
void RadarSetupDlg_FollowAssist_UpdateDisabledWindows( HWND hDlg )
{
BOOL b = FALSE;
if( IsDlgButtonChecked( hDlg, IDC_C_FOLLOW_ENABLE ) ) b = TRUE;
EnableWindow( GetDlgItem( hDlg, IDC_E_NAME_FOLLOW ), b );
EnableWindow( GetDlgItem( hDlg, IDC_C_FOLLOW_ONLY_IN_PARTY ), b );
EnableWindow( GetDlgItem( hDlg, IDC_E_FOLLOW_DISTANCE ), b );
b = FALSE;
if( IsDlgButtonChecked( hDlg, IDC_C_ASSIST_ENABLE ) ) b = TRUE;
EnableWindow( GetDlgItem( hDlg, IDC_E_NAME_ASSIST ), b );
EnableWindow( GetDlgItem( hDlg, IDC_C_ASSIST_ONLY_IN_PARTY ), b );
EnableWindow( GetDlgItem( hDlg, IDC_C_DONT_ASSIST_ALLIES ), b );
}

View File

@@ -0,0 +1,6 @@
#ifndef H_RadarSetupDlg_FolAsi
#define H_RadarSetupDlg_FolAsi
HWND RadarSetupDlg_FolAsi_Create( HWND hWndParent );
#endif

View File

@@ -0,0 +1,61 @@
#include "stdafx.h"
#include "Resource.h"
#include "Logger.h"
#include "ConfigIni.h"
extern HINSTANCE g_radardll_hinst;
extern CConfig g_cfg;
INT_PTR CALLBACK RadarSetupDlg_InvisGM_DlgProc( HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam );
HWND RadarSetupDlg_InvisGM_Create( HWND hWndParent )
{
return CreateDialogParam( g_radardll_hinst, MAKEINTRESOURCE(IDD_SR_INVISGM),
hWndParent, RadarSetupDlg_InvisGM_DlgProc, 0 );
}
// =========================================================
void RadarSetupDlg_InvisGM_Init( HWND hDlg );
void RadarSetupDlg_InvisGM_OnDestroy( HWND hDlg );
void RadarSetupDlg_InvisGM_OnApply( HWND hDlg );
INT_PTR CALLBACK RadarSetupDlg_InvisGM_DlgProc( HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam )
{
lParam;
switch( uMsg )
{
case WM_INITDIALOG: RadarSetupDlg_InvisGM_Init( hDlg ); break;
case WM_DESTROY: { RadarSetupDlg_InvisGM_OnDestroy( hDlg ); return FALSE; } break;
case WM_COMMAND:
{
switch( LOWORD(wParam) )
{
case IDC_APPLY: RadarSetupDlg_InvisGM_OnApply( hDlg ); break;
}
} break;
default: return FALSE; break;
}
return TRUE;
}
void RadarSetupDlg_InvisGM_Init( HWND hDlg )
{
CheckDlgButton( hDlg, IDC_C_INVIS_GM_ENABLE, g_cfg.InvisGMTrackEnable );
SetDlgItemInt( hDlg, IDC_E_INVIS_GM_SPEED, g_cfg.InvisGMSpeed, TRUE );
}
void RadarSetupDlg_InvisGM_OnDestroy( HWND hDlg )
{
UNREFERENCED_PARAMETER(hDlg);
}
void RadarSetupDlg_InvisGM_OnApply( HWND hDlg )
{
g_cfg.InvisGMTrackEnable = IsDlgButtonChecked( hDlg, IDC_C_INVIS_GM_ENABLE );
g_cfg.InvisGMSpeed = GetDlgItemInt( hDlg, IDC_E_INVIS_GM_SPEED, NULL, TRUE );
g_cfg.SaveConfig();
}

View File

@@ -0,0 +1,6 @@
#ifndef H_RadarSetupDlg_InvisGM
#define H_RadarSetupDlg_InvisGM
HWND RadarSetupDlg_InvisGM_Create( HWND hWndParent );
#endif

View File

@@ -0,0 +1,63 @@
#include "stdafx.h"
#include "Resource.h"
#include "Logger.h"
#include "GameClient.h"
extern HINSTANCE g_radardll_hinst;
extern class GameClient *g_game_client;
INT_PTR CALLBACK RadarSetupDlg_LockTarget_DlgProc( HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam );
HWND RadarSetupDlg_LockTarget_Create( HWND hWndParent )
{
return CreateDialogParam( g_radardll_hinst, MAKEINTRESOURCE(IDD_SR_LOCKTARGET),
hWndParent, RadarSetupDlg_LockTarget_DlgProc, 0 );
}
// =========================================================
void RadarSetupDlg_LockTarget_Init( HWND hDlg );
void RadarSetupDlg_LockTarget_OnDestroy( HWND hDlg );
void RadarSetupDlg_LockTarget_OnApply( HWND hDlg );
INT_PTR CALLBACK RadarSetupDlg_LockTarget_DlgProc( HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam )
{
lParam;
switch( uMsg )
{
case WM_INITDIALOG: RadarSetupDlg_LockTarget_Init( hDlg ); break;
case WM_DESTROY: { RadarSetupDlg_LockTarget_OnDestroy( hDlg ); return FALSE; } break;
case WM_COMMAND:
{
switch( LOWORD(wParam) )
{
case IDC_APPLY: RadarSetupDlg_LockTarget_OnApply( hDlg ); break;
}
} break;
default: return FALSE; break;
}
return TRUE;
}
void RadarSetupDlg_LockTarget_Init( HWND hDlg )
{
int e = g_game_client->ai.lockTargetMgr.isEnabled() ? 1 : 0;
CheckDlgButton( hDlg, IDC_C_LT_ENABLED, e );
}
void RadarSetupDlg_LockTarget_OnDestroy( HWND hDlg )
{
UNREFERENCED_PARAMETER(hDlg);
}
void RadarSetupDlg_LockTarget_OnApply( HWND hDlg )
{
int e = IsDlgButtonChecked( hDlg, IDC_C_LT_ENABLED );
if( e == 0 )
g_game_client->ai.lockTargetMgr.setEnable( false );
else
g_game_client->ai.lockTargetMgr.setEnable( true );
}

View File

@@ -0,0 +1,6 @@
#ifndef H_RadarSetupDlg_LockTarget
#define H_RadarSetupDlg_LockTarget
HWND RadarSetupDlg_LockTarget_Create( HWND hWndParent );
#endif

View File

@@ -0,0 +1,175 @@
#include "stdafx.h"
#include "Resource.h"
#include "Logger.h"
#include "GameClient.h"
#include "UserAI_OffpartyBDSWS.h"
extern HINSTANCE g_radardll_hinst;
extern class GameClient *g_game_client; // in main.cpp
INT_PTR CALLBACK OFFBDSWS_DlgProc( HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam );
HWND RadarSetupDlg_OFFBDSWS_Create( HWND hWndParent )
{
return CreateDialogParam( g_radardll_hinst, MAKEINTRESOURCE(IDD_SR_OFFPARTYBDSWS),
hWndParent, OFFBDSWS_DlgProc, 0 );
}
// =========================================================
UserAI_OffpartyBDSWS *rsobdsws;
void OFFBDSWS_Init( HWND hDlg );
void OFFBDSWS_OnDestroy( HWND hDlg );
void OFFBDSWS_OnApply( HWND hDlg );
void OFFBDSWS_OnSave( HWND hDlg );
void OFFBDSWS_OnEnable( HWND hDlg );
void OFFBDSWS_On_C_InvBD( HWND hDlg );
void OFFBDSWS_On_C_InvSWS( HWND hDlg );
INT_PTR CALLBACK OFFBDSWS_DlgProc( HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam )
{
lParam;
switch( uMsg )
{
case WM_INITDIALOG: OFFBDSWS_Init( hDlg ); break;
case WM_DESTROY: { OFFBDSWS_OnDestroy( hDlg ); return FALSE; } break;
case WM_COMMAND:
{
switch( LOWORD(wParam) )
{
case IDC_APPLY: OFFBDSWS_OnApply( hDlg ); break;
case IDC_SAVE: OFFBDSWS_OnSave( hDlg ); break;
case IDC_ENABLE: OFFBDSWS_OnEnable( hDlg ); break;
case IDC_C_INVBD: OFFBDSWS_On_C_InvBD( hDlg ); break;
case IDC_C_INVSWS: OFFBDSWS_On_C_InvSWS( hDlg ); break;
}
} break;
default: return FALSE; break;
}
return TRUE;
}
void OFFBDSWS_Init( HWND hDlg )
{
//log_error( LOG_OK, "init\n" );
rsobdsws = new UserAI_OffpartyBDSWS();
rsobdsws->readFromFile( "L2Detect_offp_BDSWS.ini" );
//
HWND h;
h = GetDlgItem( hDlg, IDC_ENABLE );
if( rsobdsws->allEnabled ) SetWindowText( h, TEXT("Disable") );
else SetWindowText( h, TEXT("Enable") );
SetDlgItemText( hDlg, IDC_E_BDNAME, rsobdsws->nameBD );
SetDlgItemText( hDlg, IDC_E_SWSNAME, rsobdsws->nameSWS );
SetDlgItemInt( hDlg, IDC_E_INV_BD_SEC, rsobdsws->inv_bd_secs, TRUE );
SetDlgItemInt( hDlg, IDC_E_INV_SWS_SEC, rsobdsws->inv_sws_secs, TRUE );
SetDlgItemInt( hDlg, IDC_E_DISMISS_BD_SEC, rsobdsws->dismiss_bd_secs, TRUE );
SetDlgItemInt( hDlg, IDC_E_DISMISS_SWS_SEC, rsobdsws->dismiss_sws_secs, TRUE );
if( rsobdsws->inv_bd_enable ) CheckDlgButton( hDlg, IDC_C_INVBD, TRUE );
else CheckDlgButton( hDlg, IDC_C_INVBD, FALSE );
OFFBDSWS_On_C_InvBD( hDlg );
if( rsobdsws->inv_sws_enable ) CheckDlgButton( hDlg, IDC_C_INVSWS, TRUE );
else CheckDlgButton( hDlg, IDC_C_INVSWS, FALSE );
OFFBDSWS_On_C_InvSWS( hDlg );
}
void OFFBDSWS_OnDestroy( HWND hDlg )
{
hDlg;
//log_error( LOG_OK, "close\n" );
delete rsobdsws;
rsobdsws = NULL;
}
void OFFBDSWS_OnApply( HWND hDlg )
{
//log_error( LOG_OK, "OFFBDSWS_OnApply\n" );
int c = IsDlgButtonChecked( hDlg, IDC_C_INVBD );
if( c ) rsobdsws->inv_bd_enable = 1;
else rsobdsws->inv_bd_enable = 0;
c = IsDlgButtonChecked( hDlg, IDC_C_INVSWS );
if( c ) rsobdsws->inv_sws_enable = 1;
else rsobdsws->inv_sws_enable = 0;
//
GetDlgItemTextW( hDlg, IDC_E_BDNAME, rsobdsws->nameBD, 63 );
GetDlgItemTextW( hDlg, IDC_E_SWSNAME, rsobdsws->nameSWS, 63 );
//
rsobdsws->inv_bd_secs = GetDlgItemInt( hDlg, IDC_E_INV_BD_SEC, NULL, TRUE );
rsobdsws->inv_sws_secs = GetDlgItemInt( hDlg, IDC_E_INV_SWS_SEC, NULL, TRUE );
//
rsobdsws->dismiss_bd_secs = GetDlgItemInt( hDlg, IDC_E_DISMISS_BD_SEC, NULL, TRUE );
rsobdsws->dismiss_sws_secs = GetDlgItemInt( hDlg, IDC_E_DISMISS_SWS_SEC, NULL, TRUE );
//
// apply setup immediately
g_game_client->ai.setOffpartyBDSWS_Config( rsobdsws );
//rsobdsws->saveToFile( "L2Detect_offp_BDSWS.ini" );
}
void OFFBDSWS_OnSave( HWND hDlg )
{
hDlg;
rsobdsws->saveToFile( "L2Detect_offp_BDSWS.ini" );
}
// apply enable state immediately
void OFFBDSWS_OnEnable( HWND hDlg )
{
HWND h = GetDlgItem( hDlg, IDC_ENABLE );
if( rsobdsws->allEnabled == 1 )
{
rsobdsws->allEnabled = 0;
rsobdsws->saveToFile( "L2Detect_offp_BDSWS.ini" );
g_game_client->ai.setOffpartyBDSWS_Enable( false );
SetWindowText( h, TEXT("Enable") );
return;
}
else
{
rsobdsws->allEnabled = 1;
rsobdsws->saveToFile( "L2Detect_offp_BDSWS.ini" );
g_game_client->ai.setOffpartyBDSWS_Enable( true );
SetWindowText( h, TEXT("Disable") );
}
}
void OFFBDSWS_On_C_InvBD( HWND hDlg )
{
int c = IsDlgButtonChecked( hDlg, IDC_C_INVBD );
if( c )
{
EnableWindow( GetDlgItem( hDlg, IDC_E_BDNAME ), TRUE );
EnableWindow( GetDlgItem( hDlg, IDC_E_INV_BD_SEC ), TRUE );
EnableWindow( GetDlgItem( hDlg, IDC_E_DISMISS_BD_SEC ), TRUE );
}
else
{
EnableWindow( GetDlgItem( hDlg, IDC_E_BDNAME ), FALSE );
EnableWindow( GetDlgItem( hDlg, IDC_E_INV_BD_SEC ), FALSE );
EnableWindow( GetDlgItem( hDlg, IDC_E_DISMISS_BD_SEC ), FALSE );
}
}
void OFFBDSWS_On_C_InvSWS( HWND hDlg )
{
int c = IsDlgButtonChecked( hDlg, IDC_C_INVSWS );
if( c )
{
EnableWindow( GetDlgItem( hDlg, IDC_E_SWSNAME ), TRUE );
EnableWindow( GetDlgItem( hDlg, IDC_E_INV_SWS_SEC ), TRUE );
EnableWindow( GetDlgItem( hDlg, IDC_E_DISMISS_SWS_SEC ), TRUE );
}
else
{
EnableWindow( GetDlgItem( hDlg, IDC_E_SWSNAME ), FALSE );
EnableWindow( GetDlgItem( hDlg, IDC_E_INV_SWS_SEC ), FALSE );
EnableWindow( GetDlgItem( hDlg, IDC_E_DISMISS_SWS_SEC ), FALSE );
}
}

View File

@@ -0,0 +1,6 @@
#ifndef H_RadarSetupDlg_OffpartyBDSWS
#define H_RadarSetupDlg_OffpartyBDSWS
HWND RadarSetupDlg_OFFBDSWS_Create( HWND hWndParent );
#endif

View File

@@ -0,0 +1,283 @@
#include "stdafx.h"
#include "Resource.h"
#include "Logger.h"
#include "GameClient.h"
#include "DlgPressKey.h"
#include "windowUtils.h"
#include "RadarSetupDlg_QuickTarget_distPri.h"
extern HINSTANCE g_radardll_hinst;
extern class GameClient *g_game_client; // in main.cpp
INT_PTR CALLBACK QuickTarget_DlgProc( HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam );
HWND RadarSetupDlg_QuickTarget_Create( HWND hWndParent )
{
return CreateDialogParam( g_radardll_hinst, MAKEINTRESOURCE(IDD_SR_QUICKTARGET),
hWndParent, QuickTarget_DlgProc, 0 );
}
// =========================================================
void QuickTarget_Init( HWND hDlg );
void QuickTarget_OnDestroy( HWND hDlg );
void QuickTarget_OnApply( HWND hDlg );
void QuickTarget_OnNotify( HWND hDlg, LPARAM lParam );
void QuickTarget_OnLvBeginLabelEdit( HWND hDlg, LPNMHDR pnmh );
void QuickTarget_OnLvEndLabelEdit( HWND hDlg, LPNMHDR pnmh );
void QuickTarget_OnLvDoubleClick( HWND hDlg, LPNMHDR pnmh );
void QuickTarget_OnLvColumnClick( HWND hDlg, LPNMHDR pnmh );
void QuickTarget_FillClassList( HWND hDlg );
void QuickTarget_DisplayKey( HWND hDlg, int vkey );
void QuickTarget_SetKey( HWND hDlg );
INT_PTR CALLBACK QuickTarget_DlgProc( HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam )
{
UNREFERENCED_PARAMETER(lParam);
switch( uMsg )
{
case WM_INITDIALOG: QuickTarget_Init( hDlg ); break;
case WM_DESTROY: { QuickTarget_OnDestroy( hDlg ); return FALSE; } break;
case WM_NOTIFY: QuickTarget_OnNotify( hDlg, lParam ); break;
case WM_COMMAND:
{
switch( LOWORD(wParam) )
{
case IDC_APPLY: QuickTarget_OnApply( hDlg ); break;
case IDC_B_SET_TARGET_KEY: QuickTarget_SetKey( hDlg ); break;
case IDC_B_DISTANCE_SETUP: RadarSetupDlg_QuickTarget_SetupDistancePriorities( hDlg ); break;
}
} break;
default: return FALSE; break;
}
return TRUE;
}
void QuickTarget_Init( HWND hDlg )
{
// force UserAI to reload config file
g_game_client->ai.cfgQuickTarg.loadFromFile( "L2Detect_quickTarg.ini" );
// init class pri list view
HWND hWndClassList = GetDlgItem( hDlg, IDC_CLASSLIST );
WULV_SetExtStyle( hWndClassList, true, true );
WULV_InsertColumn( hWndClassList, TEXT("class"), 120, 0 );
WULV_InsertColumn( hWndClassList, TEXT("pri"), 35, 1 );
// init tab
HWND hwndTab = GetDlgItem( hDlg, IDC_TAB1 );
WUTab_InsertItem( hwndTab, TEXT("PC list"), 0 );
WUTab_InsertItem( hwndTab, TEXT("Enemy list"), 1 );
//
QuickTarget_FillClassList( hDlg );
QuickTarget_DisplayKey( hDlg, g_game_client->ai.cfgQuickTarg.getKey() );
SetDlgItemInt( hDlg, IDC_E_MAXDIST, g_game_client->ai.cfgQuickTarg.getMaxDist(), FALSE );
CheckDlgButton( hDlg, IDC_C_SHOUT_TARGET_IN_PARTY_CHAT, g_game_client->ai.cfgQuickTarg.getAnnounceTargetInPartyChat() );
//CheckDlgButton( hDlg, IDC_C_DONT_TARGET_DEAD, g_game_client->ai.cfgQuickTarg.opt_dontTargetDead() );
//CheckDlgButton( hDlg, IDC_C_DONT_TARGET_PARTY, g_game_client->ai.cfgQuickTarg.opt_dontTargetParty() );
//CheckDlgButton( hDlg, IDC_C_DONT_TARGET_CLAN, g_game_client->ai.cfgQuickTarg.opt_dontTargetClan() );
//CheckDlgButton( hDlg, IDC_C_DONT_TARGET_ALLY, g_game_client->ai.cfgQuickTarg.opt_dontTargetAlly() );
//CheckDlgButton( hDlg, IDC_C_TARGET_ONLY_CW, g_game_client->ai.cfgQuickTarg.opt_targetOnlyCW() );
//CheckDlgButton( hDlg, IDC_C_TARGET_ALSO_PK, g_game_client->ai.cfgQuickTarg.opt_allowTargetPK() );
//CheckDlgButton( hDlg, IDC_C_TARGET_ALSO_FLAGGED, g_game_client->ai.cfgQuickTarg.opt_allowTargetFlagged() );
}
void QuickTarget_OnDestroy( HWND hDlg )
{
UNREFERENCED_PARAMETER(hDlg);
}
void QuickTarget_OnApply( HWND hDlg )
{
HWND hWndClassList = GetDlgItem( hDlg, IDC_CLASSLIST );
// apply class priorities
ClassPriorities *pri = g_game_client->ai.cfgQuickTarg.getClassPriorities();
wchar_t spri[32];
int iItem = -1;
iItem = ListView_GetNextItem( hWndClassList, iItem, LVNI_ALL );
while( iItem != -1 )
{
int classId = WULV_GetItemLPARAM( hWndClassList, iItem );
*((int *)(&spri[0])) = 0;
WULV_GetItemText( hWndClassList, iItem, 1, spri, 31 );
int ipri = 0;
swscanf( spri, L"%d", &ipri );
pri->setPriForClass( classId, ipri );
iItem = ListView_GetNextItem( hWndClassList, iItem, LVNI_ALL );
}
// apply hotkey
int hotkey_vcode = 0;
GetDlgItemText( hDlg, IDC_E_KEY, spri, 31 );
swscanf( spri, L"%d", &hotkey_vcode );
g_game_client->ai.cfgQuickTarg.setKey( hotkey_vcode );
// apply max dist
g_game_client->ai.cfgQuickTarg.setMaxDist( (int)GetDlgItemInt( hDlg, IDC_E_MAXDIST, NULL, FALSE ) );
// apply shout in party
g_game_client->ai.cfgQuickTarg.setAnnounceTargetInPartyChat( (int)GetDlgItemInt( hDlg, IDC_C_SHOUT_TARGET_IN_PARTY_CHAT, NULL, FALSE ) );
// apply "don't" checks
/*g_game_client->ai.cfgQuickTarg.setTargetParams(
IsDlgButtonChecked( hDlg, IDC_C_DONT_TARGET_DEAD ),
IsDlgButtonChecked( hDlg, IDC_C_DONT_TARGET_PARTY ),
IsDlgButtonChecked( hDlg, IDC_C_DONT_TARGET_CLAN ),
IsDlgButtonChecked( hDlg, IDC_C_DONT_TARGET_ALLY ),
IsDlgButtonChecked( hDlg, IDC_C_TARGET_ONLY_CW ),
IsDlgButtonChecked( hDlg, IDC_C_TARGET_ALSO_PK ),
IsDlgButtonChecked( hDlg, IDC_C_TARGET_ALSO_FLAGGED ),
IsDlgButtonChecked( hDlg, IDC_C_SHOUT_TARGET_IN_PARTY_CHAT )
);*/
// save config to file
g_game_client->ai.cfgQuickTarg.saveToFile( "L2Detect_quickTarg.ini" );
}
void QuickTarget_FillClassList( HWND hDlg )
{
HWND hWndClassList = GetDlgItem( hDlg, IDC_CLASSLIST );
SendMessage( hWndClassList, LVM_DELETEALLITEMS, 0, 0 ); // clear LV
ClassPriorities *pri = g_game_client->ai.cfgQuickTarg.getClassPriorities();
int i;
for( i=0; i<L2MaxClasses; i++ )
{
const char *acn = L2Data_getClass( i );
if( acn )
{
wchar_t wcn[128]; wcn[0] = 0;
MultiByteToWideChar( CP_ACP, 0, acn, -1, wcn, 127 );
int ipri = pri->getPriForClass( i );
if( ipri >= 0 )
{
int added_item_index = WULV_InsertItem( hWndClassList, wcn, 999, (LPARAM)i );
swprintf( wcn, 127, L"%d", ipri );
WULV_SetItem( hWndClassList, wcn, added_item_index, 1 );
}
}
}
}
void QuickTarget_DisplayKey( HWND hDlg, int vkey )
{
wchar_t sz[64];
wchar_t szz[32];
swprintf( sz, 63, L"%d ", vkey ); // vkey code
if( ( (vkey>='A') && (vkey<='Z') ) || ( (vkey>='0') && (vkey<='9') ) )
{
swprintf( szz, 31, _T("'%c'"), vkey );
wcscat( sz, szz );
}
else
{
switch( vkey )
{
case VK_ESCAPE: wcscat( sz, L"Esc" ); break;
case VK_OEM_3: wcscat( sz, L"~" ); break;
case VK_SNAPSHOT: wcscat( sz, L"PrtScr" ); break;
case VK_SCROLL: wcscat( sz, L"ScrollLock" ); break;
case VK_PAUSE: wcscat( sz, L"Pause" ); break;
case VK_RETURN: wcscat( sz, L"Enter" ); break;
case VK_SPACE: wcscat( sz, L"Spacebar" ); break;
// TODO: other key codes... <20><><EFBFBD><EFBFBD><EFBFBD>, <20><> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> - <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><> <20><><EFBFBD><EFBFBD><EFBFBD>
}
}
SetDlgItemTextW( hDlg, IDC_E_KEY, sz );
}
void QuickTarget_SetKey( HWND hDlg )
{
int vkey = DlgPressKey_InputPressKey( hDlg );
if( vkey <= 0 ) return;
QuickTarget_DisplayKey( hDlg, vkey );
}
void QuickTarget_OnNotify( HWND hDlg, LPARAM lParam )
{
LPNMHDR pnmh = (LPNMHDR)lParam;
HWND hwndLV = GetDlgItem( hDlg, IDC_CLASSLIST );
if( hwndLV == pnmh->hwndFrom ) // if notification from ClassList ListView
{
switch( pnmh->code )
{
case LVN_BEGINLABELEDIT: QuickTarget_OnLvBeginLabelEdit( hDlg, pnmh ); break;
case LVN_ENDLABELEDIT: QuickTarget_OnLvEndLabelEdit( hDlg, pnmh ); break;
case NM_DBLCLK: QuickTarget_OnLvDoubleClick( hDlg, pnmh ); break;
case LVN_COLUMNCLICK: QuickTarget_OnLvColumnClick( hDlg, pnmh ); break;
}
}
}
void QuickTarget_OnLvBeginLabelEdit( HWND hDlg, LPNMHDR pnmh )
{
HWND hwndLV = GetDlgItem( hDlg, IDC_CLASSLIST );
HWND hwndEdit = (HWND)SendMessage( hwndLV, LVM_GETEDITCONTROL, 0, 0 );
if( !hwndEdit ) return;
NMLVDISPINFO *pnmlvdispinfo = (NMLVDISPINFO *)pnmh;
int iItem = pnmlvdispinfo->item.iItem;
wchar_t pri_text[128] = {0};
WULV_GetItemText( hwndLV, iItem, 1, pri_text, 127 );
DWORD dwOldEditStyle = GetWindowLong( hwndEdit, GWL_STYLE );
SetWindowLong( hwndEdit, GWL_STYLE, dwOldEditStyle | ES_NUMBER ); // allow only number input
SetWindowText( hwndEdit, pri_text );
}
void QuickTarget_OnLvEndLabelEdit( HWND hDlg, LPNMHDR pnmh )
{
HWND hwndLV = GetDlgItem( hDlg, IDC_CLASSLIST );
NMLVDISPINFO *pnmlvdispinfo = (NMLVDISPINFO *)pnmh;
int iItem = pnmlvdispinfo->item.iItem;
wchar_t *newText = pnmlvdispinfo->item.pszText;
if( !newText ) return;
int new_pri = 0;
swscanf( newText, L"%d", &new_pri );
wchar_t ttext[32];
swprintf( ttext, 31, L"%d", new_pri );
WULV_SetItem( hwndLV, ttext, iItem, 1 );
}
void QuickTarget_OnLvDoubleClick( HWND hDlg, LPNMHDR pnmh )
{
UNREFERENCED_PARAMETER(hDlg);
NMITEMACTIVATE *p = (NMITEMACTIVATE *)pnmh;
ListView_EditLabel( pnmh->hwndFrom, p->iItem );
}
int CALLBACK QuickTarget_LVCompareFunc1( LPARAM iItem1, LPARAM iItem2, LPARAM lpHWND );
int CALLBACK QuickTarget_LVCompareFunc2( LPARAM iItem1, LPARAM iItem2, LPARAM lpHWND );
void QuickTarget_OnLvColumnClick( HWND hDlg, LPNMHDR pnmh )
{
UNREFERENCED_PARAMETER(hDlg);
int iCol = ((NMLISTVIEW *)pnmh)->iSubItem;
switch( iCol )
{
case 0: ListView_SortItemsEx( pnmh->hwndFrom, QuickTarget_LVCompareFunc1, (LPARAM)pnmh->hwndFrom ); break;
case 1: ListView_SortItemsEx( pnmh->hwndFrom, QuickTarget_LVCompareFunc2, (LPARAM)pnmh->hwndFrom ); break;
}
}
// sort by class name A -> Z
int CALLBACK QuickTarget_LVCompareFunc1( LPARAM iItem1, LPARAM iItem2, LPARAM lpHWND )
{
HWND hwndLV = (HWND)lpHWND;
TCHAR text1[256], text2[256];
text1[0] = text2[0] = 0;
WULV_GetItemText( hwndLV, iItem1, 0, text1, 255 );
WULV_GetItemText( hwndLV, iItem2, 0, text2, 255 );
return _tcscmp( text1, text2 );
}
// sort by priority 999 -> 0
int CALLBACK QuickTarget_LVCompareFunc2( LPARAM iItem1, LPARAM iItem2, LPARAM lpHWND )
{
HWND hwndLV = (HWND)lpHWND;
TCHAR text1[256], text2[256];
text1[0] = text2[0] = 0;
WULV_GetItemText( hwndLV, iItem1, 1, text1, 255 );
WULV_GetItemText( hwndLV, iItem2, 1, text2, 255 );
int pri1 = 0, pri2 = 0;
_stscanf( text1, _T("%d"), &pri1 );
_stscanf( text2, _T("%d"), &pri2 );
if( pri1 == pri2 ) return 0;
if( pri1 > pri2 ) return -1;
return 1;
}

View File

@@ -0,0 +1,6 @@
#ifndef H_RadarSetupDlg_QuickTarget
#define H_RadarSetupDlg_QuickTarget
HWND RadarSetupDlg_QuickTarget_Create( HWND hWndParent );
#endif

View File

@@ -0,0 +1,199 @@
#include "stdafx.h"
#include "Logger.h"
#include "Resource.h"
#include "windowUtils.h"
#include "GameClient.h"
extern class GameClient *g_game_client;
extern HINSTANCE g_radardll_hinst;
struct rsdqtsdp_RANGE_INFO
{
int min;
int max;
int pri;
};
INT_PTR CALLBACK rsdqtsdp_EditRange_DlgProc( HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam );
bool rsdqtsdp_launch_edit_dlg( HWND hDlg, rsdqtsdp_RANGE_INFO *st )
{
INT_PTR ret = DialogBoxParam( g_radardll_hinst, MAKEINTRESOURCE(IDD_SR_DISTPRI_EDITPRI), hDlg,
rsdqtsdp_EditRange_DlgProc, (LPARAM)st );
if( ret == IDOK ) return true;
return false;
}
void rsdqtsdp_add_range( HWND hDlg )
{
HWND hwndLV = GetDlgItem( hDlg, IDC_LIST1 );
int cur_sel = WULV_GetCurSelItem( hwndLV );
if( cur_sel == -1 ) cur_sel = 999;
rsdqtsdp_RANGE_INFO inf = { 0, 0, 0 };
if( rsdqtsdp_launch_edit_dlg( hDlg, &inf ) )
{
TCHAR txt[32] = {0};
swprintf( txt, 31, L"%d", inf.min );
int added_idx = WULV_InsertItem( hwndLV, txt, cur_sel );
if( added_idx >= 0 )
{
swprintf( txt, 31, L"%d", inf.max );
WULV_SetItem( hwndLV, txt, added_idx, 1 );
swprintf( txt, 31, L"%d", inf.pri );
WULV_SetItem( hwndLV, txt, added_idx, 2 );
}
}
}
void rsdqtsdp_edit_range( HWND hDlg )
{
HWND hwndLV = GetDlgItem( hDlg, IDC_LIST1 );
int cur_sel = WULV_GetCurSelItem( hwndLV );
if( cur_sel == -1 ) return;
rsdqtsdp_RANGE_INFO inf;
TCHAR txt[32] = {0};
WULV_GetItemText( hwndLV, cur_sel, 0, txt, 31 );
swscanf( txt, L"%d", &(inf.min) );
WULV_GetItemText( hwndLV, cur_sel, 1, txt, 31 );
swscanf( txt, L"%d", &(inf.max) );
WULV_GetItemText( hwndLV, cur_sel, 2, txt, 31 );
swscanf( txt, L"%d", &(inf.pri) );
if( rsdqtsdp_launch_edit_dlg( hDlg, &inf ) )
{
swprintf( txt, 31, L"%d", inf.min );
WULV_SetItem( hwndLV, txt, cur_sel, 0 );
swprintf( txt, 31, L"%d", inf.max );
WULV_SetItem( hwndLV, txt, cur_sel, 1 );
swprintf( txt, 31, L"%d", inf.pri );
WULV_SetItem( hwndLV, txt, cur_sel, 2 );
}
}
void rsdqtsdp_del_range( HWND hDlg )
{
HWND hwndLV = GetDlgItem( hDlg, IDC_LIST1 );
int cur_sel = WULV_GetCurSelItem( hwndLV );
if( cur_sel == -1 ) return;
ListView_DeleteItem( hwndLV, cur_sel );
}
void rsdqtsdp_fill_lv( HWND hDlg )
{
HWND hwndLV = GetDlgItem( hDlg, IDC_LIST1 );
SendMessage( hwndLV, LVM_DELETEALLITEMS, 0, 0 );
int i;
DistancePriorities *dpri = g_game_client->ai.cfgQuickTarg.getDistancePriorities();
for( i=0; i<dpri->MAXN; i++ )
{
int min=-1, max=-1, pri=0;
dpri->getRangeInfo( i, &min, &max, &pri );
if( min>=0 && max>=0 )
{
TCHAR txt[32];
swprintf( txt, 31, L"%d", min );
int added_item = WULV_InsertItem( hwndLV, txt, 999 );
if( added_item >= 0 )
{
swprintf( txt, 31, L"%d", max );
WULV_SetItem( hwndLV, txt, added_item, 1 );
swprintf( txt, 31, L"%d", pri );
WULV_SetItem( hwndLV, txt, added_item, 2 );
}
}
}
}
INT_PTR CALLBACK RadarSetupDlg_QuickTarget_SetupDistancePriorities_DlgProc( HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam )
{
switch( uMsg )
{
case WM_INITDIALOG:
{
HWND hwndLV = GetDlgItem( hDlg, IDC_LIST1 );
WULV_SetExtStyle( hwndLV, true, true );
WULV_InsertColumn( hwndLV, TEXT("[min"), 55, 0 );
WULV_InsertColumn( hwndLV, TEXT("max)"), 55, 1 );
WULV_InsertColumn( hwndLV, TEXT("pri_mod"), 60, 2 );
rsdqtsdp_fill_lv( hDlg );
lParam = 0; // fix warn unref. param
} break;
case WM_COMMAND:
switch( LOWORD( wParam ) )
{
case IDC_B_ADD: rsdqtsdp_add_range( hDlg ); break;
case IDC_B_EDIT: rsdqtsdp_edit_range( hDlg ); break;
case IDC_B_DEL: rsdqtsdp_del_range( hDlg ); break;
case IDOK:
{
DistancePriorities *dpri = g_game_client->ai.cfgQuickTarg.getDistancePriorities();
dpri->removeAll();
HWND hwndLV = GetDlgItem( hDlg, IDC_LIST1 );
TCHAR txt[32] = {0};
int min, max, pri;
int iItem = -1;
iItem = ListView_GetNextItem( hwndLV, iItem, LVNI_ALL );
while( iItem >= 0 )
{
WULV_GetItemText( hwndLV, iItem, 0, txt, 31 );
swscanf( txt, L"%d", &min );
WULV_GetItemText( hwndLV, iItem, 1, txt, 31 );
swscanf( txt, L"%d", &max );
WULV_GetItemText( hwndLV, iItem, 2, txt, 31 );
swscanf( txt, L"%d", &pri );
if( dpri->addRangePri( min, max, pri ) < 0 )
log_error( LOG_ERROR, "RadarSetupDlg_QuickTarget_SetupDistancePriorities_DlgProc "
"on OK: failed to add dist pri range [%d-%d,%d]\n", min, max, pri );
iItem = ListView_GetNextItem( hwndLV, iItem, LVNI_ALL );
}
EndDialog( hDlg, IDOK );
} break;
case IDCANCEL: EndDialog( hDlg, IDCANCEL ); break;
}
break;
case WM_CLOSE: EndDialog( hDlg, IDCANCEL ); break;
default: return FALSE; break;
}
return TRUE;
}
void RadarSetupDlg_QuickTarget_SetupDistancePriorities( HWND hWndParent )
{
DialogBoxParam( g_radardll_hinst, MAKEINTRESOURCE(IDD_SR_DISTPRI), hWndParent,
RadarSetupDlg_QuickTarget_SetupDistancePriorities_DlgProc, 0 );
}
INT_PTR CALLBACK rsdqtsdp_EditRange_DlgProc( HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam )
{
switch( uMsg )
{
case WM_INITDIALOG:
{
SetWindowLongPtr( hDlg, GWLP_USERDATA, lParam );
rsdqtsdp_RANGE_INFO *st = (rsdqtsdp_RANGE_INFO *)lParam;
SetDlgItemInt( hDlg, IDC_E_MIN, st->min, TRUE );
SetDlgItemInt( hDlg, IDC_E_MAX, st->max, TRUE );
SetDlgItemInt( hDlg, IDC_E_PRI, st->pri, TRUE );
} break;
case WM_COMMAND:
{
switch( LOWORD( wParam ) )
{
case IDOK:
{
rsdqtsdp_RANGE_INFO *st = (rsdqtsdp_RANGE_INFO *)GetWindowLongPtr( hDlg, GWLP_USERDATA );
st->min = (int)GetDlgItemInt( hDlg, IDC_E_MIN, NULL, TRUE );
st->max = (int)GetDlgItemInt( hDlg, IDC_E_MAX, NULL, TRUE );
st->pri = (int)GetDlgItemInt( hDlg, IDC_E_PRI, NULL, TRUE );
EndDialog( hDlg, IDOK );
} break;
case IDCANCEL: EndDialog( hDlg, IDCANCEL ); break;
default: return FALSE; break;
}
} break;
case WM_CLOSE: EndDialog( hDlg, IDCANCEL ); break;
default: return FALSE; break;
}
return TRUE;
}

View File

@@ -0,0 +1,3 @@
#pragma once
void RadarSetupDlg_QuickTarget_SetupDistancePriorities( HWND hWndParent );

View File

@@ -0,0 +1,408 @@
#include "stdafx.h"
#include "Resource.h"
#include "Logger.h"
#include "HealItemsTable.h"
#include "GameClient.h"
#include "Dlg_FindInDB.h"
extern HINSTANCE g_radardll_hinst;
extern class GameClient *g_game_client; // in main.cpp
INT_PTR CALLBACK SelfHealSetup_DlgProc( HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam );
HWND RadarSetupDlg_SelfHeal_Create( HWND hWndParent )
{
return CreateDialogParam( g_radardll_hinst, MAKEINTRESOURCE(IDD_SR_SELFHEAL),
hWndParent, SelfHealSetup_DlgProc, 0 );
}
HealItemsTable *rssh_hit;
int rssh_cur_sel;
//HWND SelfHealSetup_saveHWND;
void SelfHealSetup_Init( HWND hDlg );
void SelfHealSetup_OnDestroy( HWND hDlg );
void SelfHealSetup_OnCombo1Event( HWND hDlg, WPARAM wParam, LPARAM lParam );
void SelfHealSetup_fillList( HWND hDlg );
void SelfHealSetup_OnApply( HWND hDlg );
void SelfHealSetup_OnAdd( HWND hDlg );
void SelfHealSetup_OnDel( HWND hDlg );
void SelfHealSetup_OnEdit( HWND hDlg );
INT_PTR CALLBACK EditHealItem_DlgProc( HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam );
HealItem *RS_StartHealItemAdd( HWND hWndParent );
BOOL RS_StartHealItemEdit( HWND hWndParent, HealItem *current );
INT_PTR CALLBACK SelfHealSetup_DlgProc( HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam )
{
switch( uMsg )
{
case WM_INITDIALOG: SelfHealSetup_Init( hDlg ); break;
case WM_DESTROY: { SelfHealSetup_OnDestroy( hDlg ); return FALSE; } break;
case WM_COMMAND:
{
switch( LOWORD(wParam) )
{
case IDC_COMBO1: SelfHealSetup_OnCombo1Event( hDlg, wParam, lParam ); break;
case IDC_APPLY: SelfHealSetup_OnApply( hDlg ); break;
case IDC_DEL: SelfHealSetup_OnDel( hDlg ); break;
case IDC_ADD: SelfHealSetup_OnAdd( hDlg ); break;
case IDC_EDIT: SelfHealSetup_OnEdit( hDlg ); break;
}
} break;
default: return FALSE; break;
}
return TRUE;
}
void SelfHealSetup_Init( HWND hDlg )
{
//log_error( LOG_OK, "init\n" );
//SelfHealSetup_saveHWND = hDlg;
//
rssh_hit = new HealItemsTable();
rssh_hit->clear();
rssh_hit->LoadFromFile( "L2Detect_healItems.ini" );
//
HWND h = GetDlgItem( hDlg, IDC_COMBO1 );
SendMessage( h, CB_ADDSTRING, 0, (LPARAM)TEXT("HP Healing") );
SendMessage( h, CB_ADDSTRING, 0, (LPARAM)TEXT("MP Healing") );
SendMessage( h, CB_ADDSTRING, 0, (LPARAM)TEXT("CP Healing") );
SendMessage( h, CB_SETCURSEL, 0, 0 );
rssh_cur_sel = 0;
//
h = GetDlgItem( hDlg, IDC_LISTITEMS );
DWORD dwLvExStyle = LVS_EX_DOUBLEBUFFER | LVS_EX_FULLROWSELECT | LVS_EX_GRIDLINES;
SendMessage( h, LVM_SETEXTENDEDLISTVIEWSTYLE, (WPARAM)dwLvExStyle, (LPARAM)dwLvExStyle );
int i = 0;
TCHAR text[256] = {0};
LVCOLUMN lvc;
lvc.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM;
lvc.cx = 180;
lvc.fmt = LVCFMT_LEFT;
lvc.iSubItem = i;
lvc.pszText = text;
lstrcpy( text, TEXT("Item name") );
SendMessage( h, LVM_INSERTCOLUMN, i++, (LPARAM)&lvc );
lvc.cx = 55;
lvc.iSubItem = i;
lvc.pszText = text;
lstrcpy( text, TEXT("itemID") );
SendMessage( h, LVM_INSERTCOLUMN, i++, (LPARAM)&lvc );
lvc.cx = 40;
lvc.iSubItem = i;
lvc.pszText = text;
lstrcpy( text, TEXT("pri") );
SendMessage( h, LVM_INSERTCOLUMN, i++, (LPARAM)&lvc );
lvc.cx = 50;
lvc.iSubItem = i;
lvc.pszText = text;
lstrcpy( text, TEXT("% use") );
SendMessage( h, LVM_INSERTCOLUMN, i++, (LPARAM)&lvc );
SelfHealSetup_fillList( hDlg );
lvc.cx = 70;
lvc.iSubItem = i;
lvc.pszText = text;
lstrcpy( text, TEXT("delay,ms") );
SendMessage( h, LVM_INSERTCOLUMN, i++, (LPARAM)&lvc );
SelfHealSetup_fillList( hDlg );
}
//void SelfHealSetup_OnOK( HWND hDlg )
//{
// EndDialog( hDlg, IDOK );
//}
//
//void SelfHealSetup_OnCancel( HWND hDlg )
//{
// log_error( LOG_OK, "cancel\n" );
// EndDialog( hDlg, IDCANCEL );
//}
void SelfHealSetup_OnDestroy( HWND hDlg )
{
UNREFERENCED_PARAMETER(hDlg);
rssh_hit->clear();
delete rssh_hit;
rssh_hit = NULL;
//log_error( LOG_OK, "close\n" );
}
void SelfHealSetup_OnCombo1Event( HWND hDlg, WPARAM wParam, LPARAM lParam )
{
UNREFERENCED_PARAMETER(lParam);
HWND h = GetDlgItem( hDlg, IDC_COMBO1 );
int ctrlCode = LOWORD(wParam);
int evt = HIWORD(wParam);
if( (ctrlCode == IDC_COMBO1) && (evt == CBN_SELCHANGE) )
{
rssh_cur_sel = (int)SendMessage( h, CB_GETCURSEL, 0, 0 );
//log_error( LOG_OK, "CBN_SELCHANGE %d\n", rssh_cur_sel );
SelfHealSetup_fillList( hDlg );
}
}
void SelfHealSetup_fillList( HWND hDlg )
{
//CheckDlgButton( hDlg, IDC_C_ENABLED, 0 );
switch( rssh_cur_sel )
{
case 0: CheckDlgButton( hDlg, IDC_C_ENABLED, rssh_hit->enableHealHP ); break;
case 1: CheckDlgButton( hDlg, IDC_C_ENABLED, rssh_hit->enableHealMP ); break;
case 2: CheckDlgButton( hDlg, IDC_C_ENABLED, rssh_hit->enableHealCP ); break;
}
HWND h;
h = GetDlgItem( hDlg, IDC_LISTITEMS );
SendMessage( h, LVM_DELETEALLITEMS, 0, 0 );
HealItem hi;
int i;
bool bLoop = true;
i = 0;
LVITEM lvi;
int added_item;
TCHAR text[256] = {0};
lvi.iItem = 0;
lvi.iSubItem = 0;
lvi.lParam = 0;
lvi.mask = LVIF_TEXT | LVIF_PARAM;
lvi.pszText = text;
while( bLoop )
{
if( rssh_cur_sel == 0 ) bLoop = rssh_hit->getHPItem( i, hi );
if( rssh_cur_sel == 1 ) bLoop = rssh_hit->getMPItem( i, hi );
if( rssh_cur_sel == 2 ) bLoop = rssh_hit->getCPItem( i, hi );
if( !bLoop ) break;
//
#ifdef UNICODE
hi.GetItemNameW( text );
#else
lstrcpy( text, hi.itemName );
#endif
lvi.mask = LVIF_TEXT | LVIF_PARAM;
lvi.pszText = text;
lvi.iItem = 999;
lvi.iSubItem = 0;
lvi.lParam = i;
added_item = (int)SendMessage( h, LVM_INSERTITEM, 0, (LPARAM)&lvi );
//
lvi.mask = LVIF_TEXT;
wsprintf( text, TEXT("%u"), hi.itemID );
lvi.lParam = 0;
lvi.pszText = text;
lvi.iItem = added_item;
lvi.iSubItem = 1;
SendMessage( h, LVM_SETITEM, 0, (LPARAM)&lvi );
//
wsprintf( text, TEXT("%d"), hi.priority );
lvi.pszText = text;
lvi.iItem = added_item;
lvi.iSubItem = 2;
SendMessage( h, LVM_SETITEM, 0, (LPARAM)&lvi );
//
wsprintf( text, TEXT("%d"), hi.percentUse );
lvi.pszText = text;
lvi.iItem = added_item;
lvi.iSubItem = 3;
SendMessage( h, LVM_SETITEM, 0, (LPARAM)&lvi );
//
wsprintf( text, TEXT("%u"), hi.reuseDelayMsec );
lvi.pszText = text;
lvi.iItem = added_item;
lvi.iSubItem = 4;
SendMessage( h, LVM_SETITEM, 0, (LPARAM)&lvi );
//
i++;
}
}
void SelfHealSetup_OnApply( HWND hDlg )
{
//log_error( LOG_OK, "SelfHealSetup_OnApply\n" );
int enabled = IsDlgButtonChecked( hDlg, IDC_C_ENABLED );
switch( rssh_cur_sel )
{
case 0: rssh_hit->enableHealHP = enabled; break;
case 1: rssh_hit->enableHealMP = enabled; break;
case 2: rssh_hit->enableHealCP = enabled; break;
}
switch( rssh_cur_sel )
{
case 0: g_game_client->ai.setEnableHealHP( enabled ); break;
case 1: g_game_client->ai.setEnableHealMP( enabled ); break;
case 2: g_game_client->ai.setEnableHealCP( enabled ); break;
}
rssh_hit->SaveToFile( "L2Detect_healItems.ini" );
g_game_client->ai.setHealItemsTable( rssh_hit );
}
void SelfHealSetup_OnAdd( HWND hDlg )
{
HealItemsTable::HEALITEM_TYPE hi_type;
switch( rssh_cur_sel )
{
case 0: hi_type = HealItemsTable::HIT_HP; break;
case 1: hi_type = HealItemsTable::HIT_MP; break;
case 2: hi_type = HealItemsTable::HIT_CP; break;
default: return; break;
}
HealItem *hi = RS_StartHealItemAdd( hDlg );
if( hi )
{
hi->lastUseTime = GetTickCount() - hi->reuseDelayMsec - 1000; // :)
rssh_hit->addHealItem( hi_type, hi ); // TODO!
SelfHealSetup_fillList( hDlg );
delete hi;
}
}
void SelfHealSetup_OnDel( HWND hDlg )
{
HWND hwndLV = GetDlgItem( hDlg, IDC_LISTITEMS );
int cur_sel = ListView_GetNextItem( hwndLV, -1, LVNI_SELECTED );
if( cur_sel == -1 ) return;
LVITEM lvi;
lvi.iItem = cur_sel;
lvi.iSubItem = 0;
lvi.mask = LVIF_PARAM;
lvi.lParam = 0;
ListView_GetItem( hwndLV, &lvi );
ListView_DeleteItem( hwndLV, cur_sel );
if( rssh_cur_sel == 0 ) rssh_hit->delItemFromTable( HealItemsTable::HIT_HP, lvi.lParam );
if( rssh_cur_sel == 1 ) rssh_hit->delItemFromTable( HealItemsTable::HIT_MP, lvi.lParam );
if( rssh_cur_sel == 2 ) rssh_hit->delItemFromTable( HealItemsTable::HIT_CP, lvi.lParam );
SelfHealSetup_fillList( hDlg );
}
void SelfHealSetup_OnEdit( HWND hDlg )
{
HealItemsTable::HEALITEM_TYPE hi_type;
switch( rssh_cur_sel )
{
case 0: hi_type = HealItemsTable::HIT_HP; break;
case 1: hi_type = HealItemsTable::HIT_MP; break;
case 2: hi_type = HealItemsTable::HIT_CP; break;
default: return; break;
}
HWND hwndLV = GetDlgItem( hDlg, IDC_LISTITEMS );
int cur_sel = ListView_GetNextItem( hwndLV, -1, LVNI_SELECTED );
if( cur_sel == -1 ) return;
LVITEM lvi;
lvi.iItem = cur_sel;
lvi.iSubItem = 0;
lvi.mask = LVIF_PARAM;
lvi.lParam = 0;
ListView_GetItem( hwndLV, &lvi );
int idx = lvi.lParam;
HealItem current;
switch( rssh_cur_sel )
{
case 0: rssh_hit->getHPItem( idx, current ); break;
case 1: rssh_hit->getMPItem( idx, current ); break;
case 2: rssh_hit->getCPItem( idx, current ); break;
}
if( RS_StartHealItemEdit( hDlg, &current ) )
{
rssh_hit->setHealItem( hi_type, idx, &current );
SelfHealSetup_fillList( hDlg );
}
}
struct RS_HealItemEditStruct
{
BOOL edit_mode;
HealItem *toEdit;
};
HealItem *RS_StartHealItemAdd( HWND hWndParent )
{
HealItem *current = new HealItem();
RS_HealItemEditStruct st;
st.edit_mode = FALSE;
st.toEdit = current;
INT_PTR ret = DialogBoxParam( g_radardll_hinst, MAKEINTRESOURCE(IDD_SR_SELFHEAL_EDITOR),
hWndParent, EditHealItem_DlgProc, (LPARAM)&st );
if( ret == IDOK ) return current;
delete current;
return NULL;
}
BOOL RS_StartHealItemEdit( HWND hWndParent, HealItem *current )
{
RS_HealItemEditStruct st;
st.edit_mode = TRUE;
st.toEdit = current;
INT_PTR ret = DialogBoxParam( g_radardll_hinst, MAKEINTRESOURCE(IDD_SR_SELFHEAL_EDITOR),
hWndParent, EditHealItem_DlgProc, (LPARAM)&st );
if( ret == IDOK ) return TRUE;
return FALSE;
}
INT_PTR CALLBACK EditHealItem_DlgProc( HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam )
{
switch( uMsg )
{
case WM_INITDIALOG:
{
SetWindowLongPtr( hDlg, GWLP_USERDATA, (LONG_PTR)lParam );
struct RS_HealItemEditStruct *st = (struct RS_HealItemEditStruct *)lParam;
if( st )
{
if( st->edit_mode )
{
SetWindowText( hDlg, TEXT("Edit item") );
SetDlgItemTextA( hDlg, IDC_E_ITEMNAME, st->toEdit->itemName );
SetDlgItemInt( hDlg, IDC_E_ITEMID, st->toEdit->itemID, FALSE );
SetDlgItemInt( hDlg, IDC_E_ITEMPRI, st->toEdit->priority, TRUE );
SetDlgItemInt( hDlg, IDC_E_PERCENTUSE, st->toEdit->percentUse, TRUE );
SetDlgItemInt( hDlg, IDC_E_REUSEDELAY, st->toEdit->reuseDelayMsec, TRUE );
}
else
{
SetWindowText( hDlg, TEXT("Add item") );
}
}
} break;
case WM_COMMAND:
{
switch( LOWORD( wParam ) )
{
case IDCANCEL: EndDialog( hDlg, IDCANCEL ); break;
case IDOK:
{
struct RS_HealItemEditStruct *st =
(struct RS_HealItemEditStruct *)GetWindowLongPtr( hDlg, GWLP_USERDATA );
if( !st )
{
EndDialog( hDlg, IDCANCEL );
}
else
{
GetDlgItemTextA( hDlg, IDC_E_ITEMNAME, st->toEdit->itemName,
sizeof(st->toEdit->itemName)-1 );
st->toEdit->itemName[sizeof(st->toEdit->itemName)-1] = 0;
st->toEdit->itemID = GetDlgItemInt( hDlg, IDC_E_ITEMID, NULL, FALSE );
st->toEdit->priority = GetDlgItemInt( hDlg, IDC_E_ITEMPRI, NULL, TRUE );
st->toEdit->percentUse = GetDlgItemInt( hDlg, IDC_E_PERCENTUSE, NULL, TRUE );
st->toEdit->reuseDelayMsec = GetDlgItemInt( hDlg, IDC_E_REUSEDELAY, NULL, FALSE );
EndDialog( hDlg, IDOK );
}
} break;
case IDC_FIND:
{
Dlg_FindInDB *dlg = new Dlg_FindInDB( Dlg_FindInDB::MODE_ITEM );
if( dlg->runDialog( hDlg ) )
{
//TCHAR tstr[256];
//wsprintf( tstr, TEXT("%u: %s"), dlg->itemID, dlg->itemNameW );
//MessageBox( hDlg, tstr, TEXT("Result"), 0 );
SetDlgItemTextA( hDlg, IDC_E_ITEMNAME, dlg->itemName );
SetDlgItemInt( hDlg, IDC_E_ITEMID, dlg->itemID, FALSE );
}
delete dlg;
} break;
}
} break;
default: return FALSE; break;
}
return TRUE;
}

View File

@@ -0,0 +1,6 @@
#ifndef H_RadarSetupDlg_SelfHeal
#define H_RadarSetupDlg_SelfHeal
HWND RadarSetupDlg_SelfHeal_Create( HWND hWndParent );
#endif

View File

@@ -0,0 +1,180 @@
#include "stdafx.h"
#include "Resource.h"
#include "Logger.h"
#include "GameClient.h"
extern HINSTANCE g_radardll_hinst;
extern class GameClient *g_game_client; // in main.cpp
INT_PTR CALLBACK SoundAlerts_DlgProc( HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam );
HWND RadarSetupDlg_SoundAlerts_Create( HWND hWndParent )
{
return CreateDialogParam( g_radardll_hinst, MAKEINTRESOURCE(IDD_SR_SOUNDALERTS),
hWndParent, SoundAlerts_DlgProc, 0 );
}
// =========================================================
void SoundAlerts_Init( HWND hDlg );
void SoundAlerts_OnDestroy( HWND hDlg );
void SoundAlerts_OnApply( HWND hDlg );
void SoundAlerts_OnFind( HWND hDlg, int N );
void SoundAlerts_PlayFile( HWND hDlg, int N );
INT_PTR CALLBACK SoundAlerts_DlgProc( HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam )
{
lParam;
switch( uMsg )
{
case WM_INITDIALOG: SoundAlerts_Init( hDlg ); break;
case WM_DESTROY: { SoundAlerts_OnDestroy( hDlg ); return FALSE; } break;
case WM_COMMAND:
{
switch( LOWORD(wParam) )
{
case IDC_APPLY: SoundAlerts_OnApply( hDlg ); break;
case IDC_B_FIND1: SoundAlerts_OnFind( hDlg, 1 ); break;
case IDC_B_FIND2: SoundAlerts_OnFind( hDlg, 2 ); break;
case IDC_B_FIND3: SoundAlerts_OnFind( hDlg, 3 ); break;
case IDC_B_PLAY1: SoundAlerts_PlayFile( hDlg, 1 ); break;
case IDC_B_PLAY2: SoundAlerts_PlayFile( hDlg, 2 ); break;
case IDC_B_PLAY3: SoundAlerts_PlayFile( hDlg, 3 ); break;
}
} break;
default: return FALSE; break;
}
return TRUE;
}
void SoundAlerts_Init( HWND hDlg )
{
// force UserAI to reload config file
g_game_client->ai.loadSoundAlertsCfgFromFile();
//
HWND hwndCB = GetDlgItem( hDlg, IDC_CB_SOUNDTYPECW );
SendMessage( hwndCB, CB_ADDSTRING, 0, (LPARAM)TEXT("Info") );
SendMessage( hwndCB, CB_ADDSTRING, 0, (LPARAM)TEXT("Warning") );
SendMessage( hwndCB, CB_ADDSTRING, 0, (LPARAM)TEXT("Critical") );
hwndCB = GetDlgItem( hDlg, IDC_CB_SOUNDTYPETARGET );
SendMessage( hwndCB, CB_ADDSTRING, 0, (LPARAM)TEXT("Info") );
SendMessage( hwndCB, CB_ADDSTRING, 0, (LPARAM)TEXT("Warning") );
SendMessage( hwndCB, CB_ADDSTRING, 0, (LPARAM)TEXT("Critical") );
hwndCB = GetDlgItem( hDlg, IDC_CB_SOUNDTYPEINVISGM );
SendMessage( hwndCB, CB_ADDSTRING, 0, (LPARAM)TEXT("Info") );
SendMessage( hwndCB, CB_ADDSTRING, 0, (LPARAM)TEXT("Warning") );
SendMessage( hwndCB, CB_ADDSTRING, 0, (LPARAM)TEXT("Critical") );
// set initial CB checks
if( g_game_client->ai.soundAlert_alertOnClanWar > 0 )
{
CheckDlgButton( hDlg, IDC_C_SOUNDENEMYENTER, g_game_client->ai.soundAlert_alertOnClanWar );
hwndCB = GetDlgItem( hDlg, IDC_CB_SOUNDTYPECW );
ComboBox_SetCurSel( hwndCB, g_game_client->ai.soundAlert_alertOnClanWar - 1 );
}
if( g_game_client->ai.soundAlert_alertOnTargeted > 0 )
{
CheckDlgButton( hDlg, IDC_C_SOUNDWHENTARGETED, g_game_client->ai.soundAlert_alertOnTargeted );
hwndCB = GetDlgItem( hDlg, IDC_CB_SOUNDTYPETARGET );
ComboBox_SetCurSel( hwndCB, g_game_client->ai.soundAlert_alertOnTargeted - 1 );
}
if( g_game_client->ai.soundAlert_alertOnInvisGM > 0 )
{
CheckDlgButton( hDlg, IDC_C_SOUNDONINVISGM, g_game_client->ai.soundAlert_alertOnTargeted );
hwndCB = GetDlgItem( hDlg, IDC_CB_SOUNDTYPEINVISGM );
ComboBox_SetCurSel( hwndCB, g_game_client->ai.soundAlert_alertOnInvisGM - 1 );
}
// no clan/party alert, screen message
CheckDlgButton( hDlg, IDC_C_NOPARTYTARGETALERT, g_game_client->ai.soundAlert_noPartyTargetAlert );
CheckDlgButton( hDlg, IDC_C_NOCLANTARGETALERT, g_game_client->ai.soundAlert_noClanTargetAlert );
CheckDlgButton( hDlg, IDC_C_TARGETALERTONSCREEN, g_game_client->ai.soundAlert_screenMessage );
// set file names
SetDlgItemTextA( hDlg, IDC_E_VERYCRITICALFILE, g_game_client->ai.soundAlert_fileNameCritical );
SetDlgItemTextA( hDlg, IDC_E_WARNINGFILE, g_game_client->ai.soundAlert_fileNameWarning );
SetDlgItemTextA( hDlg, IDC_E_INFOFILE, g_game_client->ai.soundAlert_fileNameInfo );
}
void SoundAlerts_OnDestroy( HWND hDlg )
{
hDlg;
//log_error( LOG_OK, "SoundAlerts_OnDestroy\n" );
}
void SoundAlerts_OnApply( HWND hDlg )
{
//log_error( LOG_OK, "SoundAlerts_OnApply\n" );
// apply dialog config to UserAI class
HWND hwndcb = NULL;
if( IsDlgButtonChecked( hDlg, IDC_C_SOUNDENEMYENTER ) )
{
hwndcb = GetDlgItem( hDlg, IDC_CB_SOUNDTYPECW );
g_game_client->ai.soundAlert_alertOnClanWar = 1 + ComboBox_GetCurSel( hwndcb );
}
else g_game_client->ai.soundAlert_alertOnClanWar = 0;
//
if( IsDlgButtonChecked( hDlg, IDC_C_SOUNDWHENTARGETED ) )
{
hwndcb = GetDlgItem( hDlg, IDC_CB_SOUNDTYPETARGET );
g_game_client->ai.soundAlert_alertOnTargeted = 1 + ComboBox_GetCurSel( hwndcb );
}
else g_game_client->ai.soundAlert_alertOnTargeted = 0;
//
if( IsDlgButtonChecked( hDlg, IDC_C_SOUNDONINVISGM ) )
{
hwndcb = GetDlgItem( hDlg, IDC_CB_SOUNDTYPEINVISGM );
g_game_client->ai.soundAlert_alertOnInvisGM = 1 + ComboBox_GetCurSel( hwndcb );
}
else g_game_client->ai.soundAlert_alertOnInvisGM = 0;
// no clan/party alert, screen message
g_game_client->ai.soundAlert_noPartyTargetAlert = IsDlgButtonChecked( hDlg, IDC_C_NOPARTYTARGETALERT );
g_game_client->ai.soundAlert_noClanTargetAlert = IsDlgButtonChecked( hDlg, IDC_C_NOCLANTARGETALERT );
g_game_client->ai.soundAlert_screenMessage = IsDlgButtonChecked( hDlg, IDC_C_TARGETALERTONSCREEN );
// file names
GetDlgItemTextA( hDlg, IDC_E_VERYCRITICALFILE, g_game_client->ai.soundAlert_fileNameCritical, 255 );
GetDlgItemTextA( hDlg, IDC_E_WARNINGFILE, g_game_client->ai.soundAlert_fileNameWarning, 255 );
GetDlgItemTextA( hDlg, IDC_E_INFOFILE, g_game_client->ai.soundAlert_fileNameInfo, 255 );
// save to file
g_game_client->ai.saveSoundAlertsCfgToFile();
}
void SoundAlerts_OnFind( HWND hDlg, int N )
{
TCHAR fileName[256] = {0};
OPENFILENAME ofn;
memset( &ofn, 0, sizeof(ofn) );
ofn.lStructSize = sizeof(ofn);
ofn.Flags = OFN_EXPLORER | OFN_DONTADDTORECENT | OFN_FILEMUSTEXIST | OFN_PATHMUSTEXIST | OFN_NOCHANGEDIR;
ofn.hInstance = g_radardll_hinst;
ofn.hwndOwner = hDlg;
ofn.lpstrFile = fileName;
ofn.lpstrTitle = TEXT("Choose sound file:");
ofn.nMaxFile = 255;
if( GetOpenFileName( &ofn ) )
{
//MessageBox( hDlg, fileName, TEXT("User choosed"), 0 );
switch( N )
{
case 1: SetDlgItemText( hDlg, IDC_E_VERYCRITICALFILE, fileName ); break;
case 2: SetDlgItemText( hDlg, IDC_E_WARNINGFILE, fileName ); break;
case 3: SetDlgItemText( hDlg, IDC_E_INFOFILE, fileName ); break;
}
}
}
void SoundAlerts_PlayFile( HWND hDlg, int N )
{
TCHAR text[256] = {0};
if( N<1 || N>3 ) return;
switch( N )
{
case 1: GetDlgItemText( hDlg, IDC_E_VERYCRITICALFILE, text, 255 ); break;
case 2: GetDlgItemText( hDlg, IDC_E_WARNINGFILE, text, 255 ); break;
case 3: GetDlgItemText( hDlg, IDC_E_INFOFILE, text, 255 ); break;
}
if( !PlaySound( text, NULL, SND_FILENAME | SND_ASYNC ) )
{
ErrorLogger_LogLastError( "PlaySoundW", GetLastError() );
MessageBox( hDlg, TEXT("PlaySound() failed"), text, MB_ICONSTOP );
}
}

View File

@@ -0,0 +1,6 @@
#ifndef H_RadarSetupDlg_SoundAlerts
#define H_RadarSetupDlg_SoundAlerts
HWND RadarSetupDlg_SoundAlerts_Create( HWND hWndParent );
#endif

View File

@@ -0,0 +1,62 @@
#include "stdafx.h"
#include "RemoteServerInfo.h"
RemoteServerInfo::RemoteServerInfo(void)
{
_tcscpy( str_desc, TEXT("[no_desc]") );
strcpy( str_ip, "0.0.0.0" );
memset( m_desc, 0, sizeof(m_desc) );
memset( m_ip, 0, sizeof(m_ip) );
m_port = 0;
}
RemoteServerInfo::RemoteServerInfo( const RemoteServerInfo& other )
{
this->setDesc( other.desc() );
this->setIP( other.ip() );
this->setPort( other.port() );
}
RemoteServerInfo &RemoteServerInfo::operator=( const RemoteServerInfo& other )
{
this->setDesc( other.desc() );
this->setIP( other.ip() );
this->setPort( other.port() );
return (*this);
}
RemoteServerInfo::~RemoteServerInfo(void)
{
m_desc[0] = 0;
m_ip[0] = 0;
m_port = 0;
}
LPCTSTR RemoteServerInfo::desc() const
{
if( m_desc[0] == 0 ) return str_desc;
((RemoteServerInfo *)this)->m_desc[127] = 0; // close string for sure
return m_desc;
}
const char *RemoteServerInfo::ip() const
{
if( m_ip[0] == 0 ) return str_ip;
((RemoteServerInfo *)this)->m_ip[15] = 0; // close string for sure
return m_ip;
}
void RemoteServerInfo::setDesc( LPCTSTR desc )
{
m_desc[0] = 0;
if( !desc ) return;
_tcsncpy( m_desc, desc, 127 );
}
void RemoteServerInfo::setIP( const char *ip )
{
m_ip[0] = 0;
if( !ip ) return;
strncpy( m_ip, ip, 15 );
}

View File

@@ -0,0 +1,28 @@
#ifndef _H_REMOTESERVERINFO
#define _H_REMOTESERVERINFO
class RemoteServerInfo
{
public:
RemoteServerInfo();
RemoteServerInfo( const RemoteServerInfo& other );
RemoteServerInfo &operator=( const RemoteServerInfo& other );
virtual ~RemoteServerInfo();
public:
LPCTSTR desc() const;
const char *ip() const;
unsigned short port() const { return m_port; }
public:
void setDesc( LPCTSTR desc );
void setIP( const char *ip );
void setPort( unsigned short int port ) { m_port = port; }
protected:
TCHAR m_desc[128];
char m_ip[16];
unsigned short int m_port;
protected:
TCHAR str_desc[32];
char str_ip[16];
};
#endif /* _H_REMOTESERVERINFO */

183
l2detect/Resource.h Normal file
View File

@@ -0,0 +1,183 @@
// Used by L2Detect.rc
#define IDM_ABOUTBOX 0x0010
#define IDD_ABOUTBOX 100
#define IDD_CONFIG 129
#define IDD_DEBUG 133
#define IDD_SETUPRADAR 134
#define IDD_SR_SELFHEAL 135
#define IDI_MFC 136
#define IDI_L2_GREEN 137
#define IDI_L2_BLACK 138
#define IDI_L2_PURPLE 139
#define IDD_SR_SELFHEAL_EDITOR 140
#define IDD_SR_FINDINDB 141
#define IDD_SR_OFFPARTYBDSWS 142
#define IDI_L2_BLUE 143
#define IDD_SR_SOUNDALERTS 144
#define IDI_RED_CIRCLE 145
#define IDI_GREEN_CIRCLE 146
#define IDI_CROSS 147
#define IDD_SR_COLORS 148
#define IDI_RED_HALF_CIRCLE 149
#define IDD_SR_INVISGM 150
#define IDD_SR_QUICKTARGET 151
#define IDD_PRESSKEY 152
#define IDD_SR_DISTPRI 153
#define IDD_SR_DISTPRI_EDITPRI 154
#define IDD_SR_FOLLOWASSIST 155
#define IDD_SR_LOCKTARGET 156
#define IDC_ELLSTATUS 1020
#define IDC_EGLSTATUS 1021
#define IDC_STARTLL 1022
#define IDC_STARTGL 1023
#define IDC_STOPLL 1024
#define IDC_STOPGL 1025
#define IDC_FLUSH_LOG 1027
#define IDC_C_ENABLE_MODGT 1028
#define IDC_C_ENABLE_THREADPRI 1029
#define IDC_E_OVERRIDE_GPV 1030
#define IDC_HP 1032
#define IDC_MP 1033
#define IDC_CP 1034
#define IDC_CHARNAME 1035
#define IDC_CB_LOGLEVEL 1036
#define IDC_B_CONENABLE 1037
#define IDC_B_CONDISABLE 1038
#define IDC_C_L2WMOVEFIX 1039
#define IDC_E_FLPORT 1040
#define IDC_E_FGPORT 1041
#define IDC_E_REALIP 1042
#define IDC_E_REALPORT 1043
#define IDC_E_PLAYGSNO 1044
#define IDC_APPLY 1045
#define IDC_C_LOGGAMEP 1046
#define IDC_ENABLE 1046
#define IDC_E_LOGFNPREFIX 1047
#define IDC_APPLY2 1047
#define IDC_SAVE 1047
#define IDC_CB_L2VER 1048
#define IDC_T_CONFIG 1049
#define IDC_CB_L2CVER 1049
#define IDC_C_L2WDROPGMLIST 1050
#define IDC_C_L2WSITFIX 1051
#define IDC_B_LOAD 1052
#define IDC_B_SAVE 1053
#define IDC_C_WARNUNKP 1054
#define IDC_NPSETUP 1055
#define IDC_LISTITEMS 1056
#define IDC_COMBO1 1057
#define IDC_C_ENABLED 1058
#define IDC_ADD 1059
#define IDC_EDIT 1060
#define IDC_DEL 1061
#define IDC_E_ITEMNAME 1063
#define IDC_E_ITEMID 1064
#define IDC_E_ITEMPRI 1065
#define IDC_E_PERCENTUSE 1066
#define IDC_E_REUSEDELAY 1067
#define IDC_EDITNAME 1071
#define IDC_R_STWITH 1072
#define IDC_R_CONTAINS 1073
#define IDC_R_ENWITH 1074
#define IDC_FIND 1077
#define IDC_C_INVBD 1079
#define IDC_E_BDNAME 1080
#define IDC_E_INV_BD_SEC 1081
#define IDC_E_DISMISS_BD_SEC 1082
#define IDC_C_INVSWS 1083
#define IDC_E_SWSNAME 1084
#define IDC_E_INV_SWS_SEC 1085
#define IDC_E_DISMISS_SWS_SEC 1086
#define IDC_E_FORCEGSIP 1087
#define IDC_E_FORCEGSPORT 1088
#define IDC_B_VALIDATEINTERCEPT 1089
#define IDC_B_INTERCEPTCONNECT 1090
#define IDC_B_CHECK_VIRTUALPROTECTEX 1091
#define IDC_C_L2WALKER_INJECTSTATUSUPDATE 1122
#define IDC_B_LOADWALKER 1123
#define IDC_B_UNLOADWALKER 1124
#define IDC_C_GAMEGUARDREPLY 1125
#define IDC_C_EPILOGUE_148_146 1126
#define IDC_B_DUMP_ALL_RELATIONS 1127
#define IDC_B_PRINTADDRTID 1128
// radar sound alerts setup dlg
#define IDC_C_SOUNDENEMYENTER 1089
#define IDC_C_SOUNDWHENTARGETED 1090
#define IDC_CB_SOUNDTYPECW 1091
#define IDC_CB_SOUNDTYPETARGET 1092
#define IDC_B_FIND1 1093
#define IDC_B_FIND2 1094
#define IDC_B_FIND3 1095
#define IDC_E_VERYCRITICALFILE 1096
#define IDC_E_WARNINGFILE 1097
#define IDC_E_INFOFILE 1098
#define IDC_C_NOPARTYTARGETALERT 1099
#define IDC_C_NOCLANTARGETALERT 1100
#define IDC_C_TARGETALERTONSCREEN 1101
#define IDC_CB_SOUNDTYPEINVISGM 1102
#define IDC_C_SOUNDONINVISGM 1103
#define IDC_B_PLAY1 1104
#define IDC_B_PLAY2 1105
#define IDC_B_PLAY3 1106
// radar color setup dlg
#define IDC_B_SELNPCCOLOR 1110
#define IDC_B_SELMOBCOLOR 1111
#define IDC_B_SELPLAYERCOLOR 1112
#define IDC_B_SELDEADPLAYERCOLOR 1113
#define IDC_B_SELPARTYPLAYERCOLOR 1114
#define IDC_B_SELDEADPARTYPLAYERCOLOR 1115
#define IDC_B_SELENEMYPLAYERCOLOR 1116
#define IDC_B_SELDEADENEMYPLAYERCOLOR 1117
// radar invis gm setup dlg
#define IDC_C_INVIS_GM_ENABLE 1120
#define IDC_E_INVIS_GM_SPEED 1121
// radar quicktarget setup dlg
#define IDC_E_KEY 1122
#define IDC_B_SET_TARGET_KEY 1123
//#define IDC_C_DONT_TARGET_DEAD 1124
//#define IDC_C_DONT_TARGET_PARTY 1125
//#define IDC_C_DONT_TARGET_CLAN 1126
//#define IDC_C_DONT_TARGET_ALLY 1127
//#define IDC_B_UP 1128
//#define IDC_B_DOWN 1129
#define IDC_CLASSLIST 1130
#define IDC_E_MAXDIST 1131
//#define IDC_R_TARGET_NEAREST 1132
//#define IDC_R_USE_ONLY_PRIORITY 1133
//#define IDC_R_USE_BOTH 1134
//#define IDC_C_TARGET_ONLY_CW 1135
//#define IDC_C_TARGET_ALSO_PK 1136
//#define IDC_C_TARGET_ALSO_FLAGGED 1137
#define IDC_C_SHOUT_TARGET_IN_PARTY_CHAT 1138
#define IDC_B_DISTANCE_SETUP 1139
#define IDC_TAB1 1140
// distance setup dialog
#define IDC_B_ADD 1140
#define IDC_B_EDIT 1141
#define IDC_B_DEL 1142
#define IDC_LIST1 1143
#define IDC_E_MIN 1144
#define IDC_E_MAX 1145
#define IDC_E_PRI 1146
// follow & assist dialog
#define IDC_C_FOLLOW_ENABLE 1150
#define IDC_C_ASSIST_ENABLE 1151
#define IDC_E_NAME_FOLLOW 1152
#define IDC_E_NAME_ASSIST 1153
#define IDC_C_FOLLOW_ONLY_IN_PARTY 1154
#define IDC_C_ASSIST_ONLY_IN_PARTY 1155
#define IDC_C_DONT_ASSIST_ALLIES 1156
#define IDC_E_FOLLOW_DISTANCE 1157
// lock target setup dialog
#define IDC_C_LT_ENABLED 1200
#define ID_DEBUGDLG 32773

315
l2detect/ScriptEngine.cpp Normal file
View File

@@ -0,0 +1,315 @@
#include "stdafx.h"
#include "Logger.h"
#include "lua/lua.hpp"
#include "GameClient.h"
#include "PacketInjector.h"
#include "se_funcs/SE_funcs.h"
#include "ScriptEngine.h"
extern class GameClient *g_game_client; // in main.cpp
ScriptEngine *ScriptEngine::s_instance = NULL;
int ScriptEngine::s_refCount = 0;
ScriptEngine *ScriptEngine::getInstance()
{
if( ScriptEngine::s_instance == NULL )
{
ScriptEngine::s_instance = new ScriptEngine();
ScriptEngine::s_refCount++;
log_error( LOG_DEBUG, "ScriptEngine: created instance\n" );
}
return ScriptEngine::s_instance;
}
void ScriptEngine::freeInstance()
{
if( ScriptEngine::s_refCount > 0 )
{
ScriptEngine::s_refCount--;
if( ScriptEngine::s_refCount == 0 )
{
delete ScriptEngine::s_instance;
ScriptEngine::s_instance = NULL;
log_error( LOG_DEBUG, "ScriptEngine: freed instance\n" );
}
}
}
ScriptEngine::ScriptEngine()
{
L = NULL;
hThread = NULL;
memset( script_fileName, 0, sizeof(script_fileName) );
should_stop = false;
_isPaused = false;
// handlers
m_onChat_enabled = false;
m_onChat_functionName[0] = 0;
}
ScriptEngine::~ScriptEngine()
{
deinit();
}
void ScriptEngine::init()
{
if( !L )
{
L = luaL_newstate(); // open Lua virtual machine
if( L )
{
luaL_openlibs( L ); // load the Lua libraries: math, io, ..
SE_funcs_register( L ); // register main functions (l2h_*)
}
else log_error( LOG_ERROR, "ScriptEngine::init(): luaL_newstate() returned NULL!\n" );
}
}
void ScriptEngine::deinit()
{
if( L )
{
lua_close( L ); // Destroys all objects in the given Lua state
//(calling the corresponding garbage-collection metamethods, if any)
//and frees all dynamic memory used by this state
L = NULL;
if( hThread ) CloseHandle( hThread );
hThread = NULL;
should_stop = false;
_isPaused = false;
// handlers
m_onChat_enabled = false;
m_onChat_functionName[0] = 0;
}
}
void ScriptEngine::getLastFileName( char *out )
{
if( !out ) return;
out[0] = 0;
if( script_fileName[0] != 0 ) strcpy( out, script_fileName );
}
void ScriptEngine::startScriptThread( const char *filename /*= NULL */ )
{
if( hThread ) return;
DWORD dwThreadID = 0;
if( filename ) strcpy( script_fileName, filename );
hThread = (HANDLE)_beginthreadex( NULL, 0,
(unsigned int (__stdcall *)(void *))scriptEngineThread, (void *)this,
0, (unsigned int *)&dwThreadID );
}
bool ScriptEngine::stopScriptThread( DWORD dwTimeoutMsec, bool bTerminate )
{
if( !hThread ) return true;
this->should_stop = true; // "signal" to stop )
DWORD wait_res = WaitForSingleObject( hThread, dwTimeoutMsec );
if( wait_res != WAIT_OBJECT_0 ) // wait failed :(
{
if( !bTerminate ) return false; // do not do anything, just ret false
TerminateThread( hThread, 0 );
log_error( LOG_ERROR, "ScriptEngine::stopScriptThread(): script thread wait failed, TERMINATED!\n" );
this->deinit();
this->set_onChat_handler( NULL ); // disable onChat() handler
this->init();
if( L ) log_error( LOG_WARNING, "ScriptEngine::stopScriptThread(): re-initialized ScriptEngine, bugs possible ><\n" );
}
if( hThread ) CloseHandle( hThread ); // cleanup
hThread = NULL;
this->should_stop = false; // no more need to stop...
return true;
}
int ScriptEngine::isScriptThreadRunning() const
{
if( hThread == NULL ) return 0;
return 1;
}
int ScriptEngine::isScriptThreadPaused() const
{
if( _isPaused ) return 1;
return 0;
}
bool ScriptEngine::pauseScriptThread( bool bPause /*= true*/ )
{
if( !isScriptThreadRunning() ) return false;
int prev_suspend_count = 0;
if( bPause )
{
prev_suspend_count = (int)SuspendThread( hThread );
if( prev_suspend_count > 0 )
{
log_error( LOG_WARNING, "ScriptEngine::pauseScriptThread(): PAUSE: thread was already suspended, resuming again\n" );
ResumeThread( hThread );
}
_isPaused = true;
return true;
}
else
{
prev_suspend_count = ResumeThread( hThread );
if( prev_suspend_count > 1 )
{
log_error( LOG_WARNING, "ScriptEngine::pauseScriptThread(): UNPAUSE: possible that thread is still suspended!\n" );
}
_isPaused = false;
return true;
}
}
DWORD WINAPI ScriptEngine::scriptEngineThread( LPVOID lpvClass )
{
if( !lpvClass ) return 0;
ScriptEngine *pcls = (ScriptEngine *)lpvClass;
// run a Lua script here
int r = luaL_loadfile( pcls->L, pcls->script_fileName );
if( r == 0 )
{
log_error( LOG_DEBUG, "SE: file [%s] loaded.\n", pcls->script_fileName );
// Call main...
try
{
r = lua_pcall( pcls->L, 0, LUA_MULTRET, 0 );
}
catch(...)
{
log_error( LOG_ERROR, "SE: catched C++ exception after lua_pcall()\n" );
ErrorLogger_FlushLogFile();
}
if( r == 0 ) log_error( LOG_DEBUG, "SE: run OK\n" );
else
{
log_error( LOG_ERROR, "SE: file [%s] lua_pcall() error %d\n", pcls->script_fileName, r );
switch( r )
{
case LUA_ERRRUN: log_error( LOG_ERROR, "SE: LUA_ERRRUN\n" ); break;
case LUA_ERRMEM: log_error( LOG_ERROR, "SE: LUA_ERRMEM\n" ); break;
case LUA_ERRSYNTAX: log_error( LOG_ERROR, "SE: LUA_ERRSYNTAX\n" ); break;
case LUA_ERRERR: log_error( LOG_ERROR, "SE: LUA_ERRERR\n" ); break;
}
int nArgs = lua_gettop( pcls->L );
if( nArgs >= 1 )
{
if( lua_isstring( pcls->L, 1 ) )
log_error( LOG_ERROR, "SE: [%s]\n", lua_tolstring( pcls->L, 1, NULL ) );
}
lua_settop( pcls->L, 0 ); // clear stack
}
}
else
{
log_error( LOG_ERROR, "SE: file [%s] luaL_loadfile() error %d\n", pcls->script_fileName, r );
switch( r )
{
case LUA_ERRRUN: log_error( LOG_ERROR, "SE: LUA_ERRRUN\n" ); break;
case LUA_ERRMEM: log_error( LOG_ERROR, "SE: LUA_ERRMEM\n" ); break;
case LUA_ERRSYNTAX: log_error( LOG_ERROR, "SE: LUA_ERRSYNTAX\n" ); break;
case LUA_ERRERR: log_error( LOG_ERROR, "SE: LUA_ERRERR\n" ); break;
case LUA_ERRFILE: log_error( LOG_ERROR, "SE: LUA_ERRFILE\n" ); break;
}
int nArgs = lua_gettop( pcls->L );
if( nArgs >= 1 )
{
if( lua_isstring( pcls->L, 1 ) )
{
log_error( LOG_ERROR, "SE: [%s]\n", lua_tolstring( pcls->L, 1, NULL ) );
//lua_pop( pcls->L, 1 ); // really?
}
}
lua_settop( pcls->L, 0 ); // clear stack
}
pcls->set_onChat_handler( NULL ); // disable onChat() handler
if( pcls->hThread ) CloseHandle( pcls->hThread ); // cleanup
pcls->hThread = NULL; // mark thread as not running
pcls->should_stop = false;
log_error( LOG_DEBUG, "SE: scriptEngineThread() stopped [%s]\n", pcls->script_fileName );
return 1;
}
// http://www.lua.ru/doc/3.7.html
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD> <20> Lua:
// a = f('how', t.x, 14)
//
//<2F><> <20><> <20> C:
// lua_getfield(L, LUA_GLOBALSINDEX, 'f'); /* function to be called */
// lua_pushstring(L, 'how'); /* 1st argument */
// lua_getfield(L, LUA_GLOBALSINDEX, 't'); /* table to be indexed */
// lua_getfield(L, -1, 'x'); /* push result of t.x (2nd arg) */
// lua_remove(L, -2); /* remove 't' from the stack */
// lua_pushinteger(L, 14); /* 3rd argument */
// lua_call(L, 3, 1); /* call 'f' with 3 arguments and 1 result */
// lua_setfield(L, LUA_GLOBALSINDEX, 'a'); /* set global 'a' */
//
//<2F><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD> <20><><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>: <20> <20><><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>. <20><><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>.
void ScriptEngine::call_onChat( unsigned int senderObjectId, int channelId, const wchar_t *message, const wchar_t *from )
{
if( !m_onChat_enabled ) return;
if( !message ) return;
if( !isScriptThreadRunning() ) return;
if( isScriptThreadPaused() ) return;
//
pauseScriptThread( true ); // pause script thread
//
// convert strings from Unicode to ANSI
char message_ansi[1024];
char from_ansi[128];
message_ansi[0] = from_ansi[0] = 0;
WideCharToMultiByte( CP_ACP, 0, message, -1, message_ansi, sizeof(message_ansi)-1, NULL, NULL );
if( from ) WideCharToMultiByte( CP_ACP, 0, from, -1, from_ansi, sizeof(from_ansi)-1, NULL, NULL );
message_ansi[sizeof(message_ansi)-1] = 0;
from_ansi[sizeof(from_ansi)-1] = 0;
//
lua_getfield( L, LUA_GLOBALSINDEX, m_onChat_functionName ); // function to be called
lua_pushinteger( L, senderObjectId ); // param 1 - sender object ID
lua_pushinteger( L, channelId ); // param 2 - channel ID
lua_pushstring( L, message_ansi ); // param 3 - chat message
lua_pushstring( L, from_ansi ); // param 4 - sender name (only for PM)
// call onChat with 4 arguments and 0 return values: onChat( senderObjectId, channelId, message, from )
int ret = lua_pcall( L, 4, 0, 0 );
if( ret != 0 )
{
log_error( LOG_ERROR, "SE: call_onChat() [%s] error %d\n", script_fileName, ret );
switch( ret )
{
case LUA_ERRRUN: log_error( LOG_ERROR, "SE: LUA_ERRRUN\n" ); break;
case LUA_ERRMEM: log_error( LOG_ERROR, "SE: LUA_ERRMEM\n" ); break;
case LUA_ERRSYNTAX: log_error( LOG_ERROR, "SE: LUA_ERRSYNTAX\n" ); break;
case LUA_ERRERR: log_error( LOG_ERROR, "SE: LUA_ERRERR\n" ); break;
case LUA_ERRFILE: log_error( LOG_ERROR, "SE: LUA_ERRFILE\n" ); break;
}
int nArgs = lua_gettop( L );
if( nArgs >= 1 )
{
if( lua_isstring( L, 1 ) )
log_error( LOG_ERROR, "SE: [%s]\n", lua_tolstring( L, 1, NULL ) );
}
lua_settop( L, 0 ); // clear stack
}
else log_error( LOG_DEBUG, "SE: call_onChat() [%s] OK\n", script_fileName );
//
pauseScriptThread( false ); // resume script thread
//
}
void ScriptEngine::set_onChat_handler( const char *funcName )
{
if( funcName == NULL ) // disable
{
m_onChat_enabled = false;
m_onChat_functionName[0] = 0;
return;
}
m_onChat_enabled = true;
strncpy( m_onChat_functionName, funcName, sizeof(m_onChat_functionName)-1 );
m_onChat_functionName[sizeof(m_onChat_functionName)-1] = 0;
}

Some files were not shown because too many files have changed in this diff Show More