|

提醒:若下载的软件是收费的"请不要付款",可能是骗子,请立即联系本站举报,执意要付款被骗后本站概不负责。(任何交易请走第三方中介,请勿直接付款交易以免被骗!切记).
做的是任务挂,用LUA做功能的,挂中提供接口函数。
由于内挂大部分是HOOK游戏处理封包位置来做相应功能的,所以转脱机算是很方便。因为LUA脚本来做功能的,其实脱机也就是把接口写好就行了。
其实脱机可以抛弃不少封包处理,有很多不明白的封包,只要不和封号有关,不和功能需求有关,直接PASS。
先说点大局, 脱机要做单文档,也就是象游戏一样,一个程序一个客户端,方便管理,也方便写作,为什么呢,全局变量可以随便扔。-
游戏登陆部分,一般是一个帐号验证服务器,一个游戏服务器,然后靠KEY来相互关联,我的逻辑块是:
UINT CGameRobotDlg::MainThreadCyc(LPVOID pVoid)
{//这是一个线程,外部还有个定时器再不停的检测,如果该线程退出了,再继续启动
//这样做可以让帐号退出或者什么意外的,再继续登陆注意上
//注意CreateEvent所创建的句柄,可以控制连接的断开
if (g_pMainDlg->m_bThreaFlag)//线程还在进行中
return 1;
//获得启动信息
CGameRobotDlg* pThis = (CGameRobotDlg*)pVoid;
int nSel = pThis->m_cServerList.GetCurSel();//选择的服务器
if (nSel == LB_ERR)
return 1;
g_pMainDlg->m_bThreaFlag = TRUE;
strcpy(pThis->m_LoginConnectIP, g_ServerList[nSel].Address);
if (szLineServer[0] == 0)
strcpy(szLineServer, g_ServerList[nSel].Title);
pThis->GetDlgItem(IDC_EDIT_USER)->GetWindowText(pThis->m_LoginName, 0x20);
pThis->GetDlgItem(IDC_EDIT_PASS)->GetWindowText(pThis->m_LoginPass, 0x30);
pThis->GetDlgItem(IDC_Btn_BeginGame)->EnableWindow(FALSE);
MD5_CTX md5;
BYTE outmd5[16] = {0};
md5.MD5Update((BYTE*)pThis->m_LoginPass, strlen(pThis->m_LoginPass));
md5.MD5Final(outmd5);
char temp[10];
ZeroMemory(pThis->m_LoginPass, 0x30);
ZeroMemory(pThis->m_SelectRole, 0x20);
for (int i=0; i<16; i++)
{
wsprintf(temp, "%02X", outmd5);
strcat(pThis->m_LoginPass, temp);
}
//////////////////////////////////////////////////////////////////////////
//登陆部分
pThis->m_hLoginTimeHandle = CreateEvent(NULL, TRUE, FALSE, NULL);
pThis->m_GamePacket.m_bIsLoginGetKey = FALSE;
pThis->m_GamePacket.m_bIsGameGetKey = FALSE;
pThis->m_LoginSocket.UnInit();
if (pThis->m_LoginSocket.Init(ProcessLoginRecvData, pThis->m_LoginConnectIP, GAME_CONNECT_PORT))
{//连接登陆服务器
pThis->m_bCheckLogin = TRUE;
pThis->m_2CheckLogin = 0;
pThis->KillTimer(CGameRobotDlg::B_CHECK_FADAI);//检测发呆状态,包括想象得到的无响应状态
pThis->SetTimer(CGameRobotDlg::B_CHECK_FADAI, 1000, NULL);
pThis->KillTimer(CGameRobotDlg::B_CHECK_LOGIN);//有时候登陆没有返回角色信息
pThis->SetTimer(CGameRobotDlg::B_CHECK_LOGIN, 1000, NULL);
pThis->m_GamePacket.InitGame();
ZeroMemory(pThis->m_GamePacket.m_RoleName, 30);
::WaitForSingleObject(pThis->m_hLoginTimeHandle, INFINITE);
g_pMainDlg->AddInfo(C_RED, "登陆连接已经断开!");
pThis->m_LoginSocket.UnInit();
if (g_AccountUseing)
{//帐号使用中,等待10秒
ResetEvent(pThis->m_hLoginTimeHandle);
::WaitForSingleObject(pThis->m_hLoginTimeHandle, 10*1000);
}
}
else
{
pThis->AddInfo(C_RED, "连接登陆服务器失败!");
pThis->m_bCheckLogin = FALSE;
if (pThis->m_3CheckLogin++ > 20)//有时候怎么连都连不上的
{//网络环境问题的话,关闭游戏
CloseHandle(pThis->m_hLoginTimeHandle);
pThis->m_hLoginTimeHandle = NULL;
g_pMainDlg->m_bThreaFlag = TRUE;
g_pMainDlg->KillTimer(CGameRobotDlg::BEGIN_LOOP);
g_pMainDlg->CloseGame();
return 2;
}
}
CloseHandle(pThis->m_hLoginTimeHandle);
pThis->m_hLoginTimeHandle = NULL;
//////////////////////////////////////////////////////////////////////////
//游戏部分
if (pThis->m_enumState == CGameRobotDlg::R_OK)
{
int nIndex = 0;
pThis->m_hGameTimeHandle = CreateEvent(NULL, TRUE, FALSE, NULL);
pThis->m_2CheckGame = 0;
pThis->KillTimer(CGameRobotDlg::B_CHECK_GAME);//又是些检测
pThis->SetTimer(CGameRobotDlg::B_CHECK_GAME, 1000, NULL);
do {
pThis->m_bChangeMap = FALSE;
pThis->m_GameSocket.UnInit();
g_pMainDlg->AddInfo(C_GREEN, "正在连接游戏服务器中...");
if ((pThis->m_ConnectPort != 0) && pThis->m_GameSocket.Init(ProcessGameRecvData, pThis->m_ConnectIP, pThis->m_ConnectPort))
{
nIndex = 0;
g_pMainDlg->AddInfo(C_GREEN, "连接游戏服务器成功,进入游戏循环");
::WaitForSingleObject(pThis->m_hGameTimeHandle, INFINITE);
ResetEvent(pThis->m_hGameTimeHandle);
g_pMainDlg->AddInfo(C_RED, "游戏连接已经断开!");
pThis->m_GameSocket.UnInit();
}
else
{
pThis->AddInfo(C_RED, "连接游戏服务器失败!");
if (pThis->m_ConnectIP[0] != 0)
pThis->m_bChangeMap = TRUE;
if (nIndex++ > 5) {
pThis->m_bChangeMap = FALSE;
}
}
} while(pThis->m_bChangeMap);//m_bChangeMap 是切换地图的标志,切换地图情况下需要再次进行网络连接
pThis->m_2CheckGame = 0;
pThis->KillTimer(CGameRobotDlg::B_CHECK_GAME);
CloseHandle(pThis->m_hGameTimeHandle);
pThis->m_hGameTimeHandle = NULL;
//////////////////////////////////////////////////////////////////////////
pThis->GetDlgItem(IDC_Btn_BeginGame)->EnableWindow(TRUE);
pThis->m_bThreaFlag = FALSE;
return 0;
}
else if (pThis->m_enumState == CGameRobotDlg::R_PASS_GAME
|| pThis->m_enumState == CGameRobotDlg::R_LOGIN_RETURN)
{
pThis->GetDlgItem(IDC_Btn_BeginGame)->EnableWindow(TRUE);
pThis->m_bThreaFlag = FALSE;
}
return 1;
}
void __stdcall ProcessLoginRecvData(char *pData, DWORD DataLength)
{//处理登陆连接
if (g_pMainDlg == NULL || DataLength == 0)
{
g_pMainDlg->SetMainState(TRUE, CGameRobotDlg::R_LOGIN_RETURN);
return;
}
if (g_pMainDlg->m_GamePacket.m_bIsLoginGetKey == FALSE)
{//获得登陆KEY
if (*(PBYTE)pData == 0x20)
{
g_pMainDlg->m_GamePacket.GetLoginKey(pData, DataLength);
g_pMainDlg->m_GamePacket.m_bIsLoginGetKey = TRUE;//标志
return;
}
}
g_pMainDlg->m_GamePacket.LoginDeCrypt(pData, DataLength);//解密
switch(*(PBYTE)pData) {
case 1: break;
//这里依据封包命令字做相应处理
default:
g_pMainDlg->AddInfo(C_RED, "缺省封包: %X == %X", *(PWORD)(pData), DataLength);
break;
}
}
void __stdcall ProcessGameRecvData(char *pData, DWORD DataLength)
{//处理游戏连接
if (g_pMainDlg == NULL || DataLength == 0)
{
g_AttackObjectID = 0; //攻击对象去掉
g_pMainDlg->m_bStartAttack = FALSE;//停止攻击
bDoScript_State = FALSE;//把脚本停掉
g_pMainDlg->AddInfo(C_RED, "无封包了.");
g_pMainDlg->SetMainState(FALSE, CGameRobotDlg::R_OK);
return;
}
g_pMainDlg->m_2CheckGame = 0;
if (g_pMainDlg->m_GamePacket.m_bIsGameGetKey == FALSE)
{
if (*(PBYTE)pData == 0x20)
{
//换游戏加密KEY了
g_pMainDlg->m_GamePacket.GetGameKey(pData, DataLength);
g_pMainDlg->m_GamePacket.m_bIsGameGetKey = TRUE;//标志
g_pMainDlg->m_GamePacket.m_bCanLoop = FALSE;
bD0Flag = FALSE;
return;
}
}
g_pMainDlg->m_GamePacket.LoginDeCrypt(pData, DataLength);//解密
ProcessGameRecvPack(pData, DataLength);//具体的封包处理了
}
给出些数据结构,可以从中看出,脱机中想做什么功能,只要相关数据就行了,有些不必了解
typedef struct {//自己的装备
DWORD ItemUseKeyID;
BYTE at_pos; //0 是身上, 2是包袱
BYTE x;
BYTE y;
BYTE CurCount; //数量
BYTE IsBind; //是否绑定
BYTE Needlevel;//装备需求, 穿装备的功能需要
char name[30];
BYTE type1; //物品的分类
WORD type2;
WORD type3;
BYTE type4;
}TMyItemData, *PTMyItemData;
typedef struct {//玩家,怪物,NPC
DWORD ID;
char name[22];
DWORD x;
DWORD y;
int type; //3是NPC
DWORD CurHP;
DWORD MaxHP;
DWORD CurMP;
DWORD MaxMP;
BYTE MenPai;
BYTE IsCaptainFlag; //是否是队长
BOOL IsDead; //是否死亡
DWORD GroupID; //供组队的ID
char npcClassName[50];
}Object, *PObject;
map<DWORD, Object> m_AroundObject;//周围对象(NPC,怪物,玩家)
★在这里注意下说一下★, 我们的对象链表,当他们死亡时,最好不要做删除链表操作,只要将他们的ID设置为0就好了。
一些游戏在刷怪时,包括NPC,他们的ID是比较固定的
struct GroupItem {//地面上物品
DWORD ID;
char name[22];
DWORD x;
DWORD y;
};
struct MemberInfo {//大小0x54
DWORD MemberID; //成员ID,注意这个ID不是角色ID
char name[0x20];//+34成员的名称
};
typedef struct {
DWORD GroupID; //队伍ID
MemberInfo pMI[6];//最多有6个成员, 其中第一个是队长
}TGroupMgr, *PTGroupMgr;
就这些差不多了,技能好像处理不是很多,就是需要个技能ID就差不多了
case 0xD9://已经学习的技能
//R(0x0015): D9 14 00 00 00 5B 00 00 00 08 00 00 00 00 00 00 00 00 00 00 00
// =========== =========== 技能ID以及已经学习的等级
{//extern map<DWORD, int> g_AlreadyStudySkill
DWORD skillid = *(PDWORD)(GameCurPack+5);
int skilllevel= *(PDWORD)(GameCurPack+5+4);
g_AlreadyStudySkill[skillid] = skilllevel;
}
break;
联系我时,请说是在 挂海论坛 上看到的,谢谢! |
上一篇: 写点东西,菜鸟也玩保护...下一篇: 一个剥离GPK版的DragonNest.exe
免责声明:
1、本主题所有言论和图片纯属会员个人意见,与本论坛立场无关。一切关于该内容及资源商业行为与www.52ghai.com无关。
2、本站提供的一切资源内容信息仅限用于学习和研究目的;不得将上述内容用于商业或者非法用途,否则,一切后果请用户自负。
3、本站信息来自第三方用户,非本站自制,版权归原作者享有,版权争议与本站无关。您必须在下载后的24个小时之内,从您的电脑或手机中彻底删除上述内容。
4、如果您喜欢该程序,请支持正版,购买注册,得到更好的正版服务。如有侵犯你版权的,请邮件与我们联系删除(邮箱:xhzlw@foxmail.com),本站将立即改正。
|