106.网络游戏逆向分析与漏洞攻防-装备系统数据分析-在UI中显示装备与技能信息

免责声明:内容仅供学习参考,请合法利用知识,禁止进行违法犯罪活动!

如果看不懂、不知道现在做的什么,那就跟着做完看效果,代码看不懂是正常的,只要会抄就行,抄着抄着就能懂了

内容参考于:易道云信息技术研究院

上一个内容:105.处理装备与技能数据的创建

码云版本号:a715264dcde99ef2789e15577a69513e4574255d

代码下载地址,在 titan 目录下,文件名为:titan-在UI中显示装备与技能信息.zip

链接:https://pan.baidu.com/s/1W-JpUcGOWbSJmMdmtMzYZg

提取码:q9n5

--来自百度网盘超级会员V4的分享

HOOK引擎,文件名为:黑兔sdk升级版.zip

链接:https://pan.baidu.com/s/1IB-Zs6hi3yU8LC2f-8hIEw

提取码:78h8

--来自百度网盘超级会员V4的分享

以 105.处理装备与技能数据的创建 它的代码为基础进行修改

效果图:

装备

物品

坐骑

扩展包

技能

上一个内容里,把装备、技能相关的结构体、数据包拦截函数(NetClient.h里面的OnSvrGameBaseReset函数)都已经搞好了,本次就是要把这些信息在ui界面中显示出来

上一个内容中的代码有一个问题

下图中15 03 00 05 00,也就是18 03数据包最大有5个,但是18 03这个数据包的序号是从1开始,这就会导致超出数组长度访问一个不确定的内存导致程序崩溃,所以数组长度我们要进行加1

新加一个Dialog

它的属性

添加一个类

类名,如果点了确定出现 COM组件的调用返回了错误HRESULT E_FAIL 98节里有解决方式,由中文目录引起的

给控件添加变量

控件的属性

变量名、变量类型

上方是物品相关的界面,下方是技能相关的界面

新加Dialog

Dialog属性

用到的控件

控件的属性

新加类

类名,CWndSkill

List控件添加变量

变量名,lstSkill

新加CWndSkill.cpp文件,技能窗口类

// CWndSkill.cpp: 实现文件
//#include "pch.h"
#include "CWndSkill.h"
#include "resource.h"
#include "CUI.h"
#include "extern_all.h"// CWndSkill 对话框IMPLEMENT_DYNAMIC(CWndSkill, CDialogEx)CWndSkill::CWndSkill(CWnd* pParent /*=nullptr*/): CDialogEx(IDD_PAGE_4, pParent)
{}CWndSkill::~CWndSkill()
{
}void CWndSkill::DoDataExchange(CDataExchange* pDX)
{CDialogEx::DoDataExchange(pDX);DDX_Control(pDX, IDC_LIST1, lstSkill);
}BOOL CWndSkill::OnInitDialog()
{CDialogEx::OnInitDialog();CUI* ui = (CUI*)Client;ui->SetListView(&lstSkill);lstSkill.InsertColumn(0, L"名称", 0, 100);lstSkill.InsertColumn(1, L"冷却时间", 0, 100);return TRUE;
}BEGIN_MESSAGE_MAP(CWndSkill, CDialogEx)ON_BN_CLICKED(IDC_BUTTON1, &CWndSkill::OnBnClickedButton1)
END_MESSAGE_MAP()// CWndSkill 消息处理程序void CWndSkill::OnBnClickedButton1()
{lstSkill.DeleteAllItems();CString txt;float coolDown;int index = 0;for (int i = 0; i < Client->SkillMax; i++){if (!Client->Skill[i].Isfree) {coolDown = Client->Skill[i].CoolDownTime / 1000;lstSkill.InsertItem(index, Client->Skill[i].Name);txt.Format(L"%.2f秒", coolDown);lstSkill.SetItemText(index++, 1, txt);}}
}

新加CWndSkill.h文件,技能窗口类

#pragma once
#include "afxdialogex.h"// CWndSkill 对话框class CWndSkill : public CDialogEx
{DECLARE_DYNAMIC(CWndSkill)public:CWndSkill(CWnd* pParent = nullptr);   // 标准构造函数virtual ~CWndSkill();// 对话框数据
#ifdef AFX_DESIGN_TIMEenum { IDD = IDD_PAGE_4 };
#endifprotected:virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV 支持virtual BOOL OnInitDialog();DECLARE_MESSAGE_MAP()
public:CListCtrl lstSkill;afx_msg void OnBnClickedButton1();
};

新加CWndItem.cpp文件,物品窗口类

// CWndItem.cpp: 实现文件
//#include "pch.h"
#include "CWndItem.h"
#include "resource.h"
#include "extern_all.h"
#include "CUI.h"// CWndItem 对话框IMPLEMENT_DYNAMIC(CWndItem, CDialogEx)CWndItem::CWndItem(CWnd* pParent /*=nullptr*/): CDialogEx(IDD_PAGE_3, pParent)
{}CWndItem::~CWndItem()
{
}void CWndItem::DoDataExchange(CDataExchange* pDX)
{CDialogEx::DoDataExchange(pDX);DDX_Control(pDX, IDC_LIST1, lstItem);
}BOOL CWndItem::OnInitDialog()
{CDialogEx::OnInitDialog();CUI* ui = (CUI*)Client;ui->SetListView(&lstItem);lstItem.InsertColumn(0, L"名称",0, 100);lstItem.InsertColumn(1, L"数量",0, 100);return TRUE;
}BEGIN_MESSAGE_MAP(CWndItem, CDialogEx)ON_BN_CLICKED(IDC_BUTTON1, &CWndItem::OnBnClickedButton1)ON_BN_CLICKED(IDC_BUTTON4, &CWndItem::OnBnClickedButton4)ON_BN_CLICKED(IDC_BUTTON5, &CWndItem::OnBnClickedButton5)ON_BN_CLICKED(IDC_BUTTON6, &CWndItem::OnBnClickedButton6)
END_MESSAGE_MAP()// CWndItem 消息处理程序void CWndItem::OnBnClickedButton1()
{lstItem.DeleteAllItems();CString txt;int index = 0;for (int i = 0; i < Client->EquipMax; i++){if (!Client->Equip[i].Isfree) {lstItem.InsertItem(index, Client->Equip[i].Name);txt.Format(L"%d/%d", Client->Equip[i].Amount, Client->Equip[i].MaxAmount);lstItem.SetItemText(index++, 1, txt);}}
}void CWndItem::OnBnClickedButton4()
{lstItem.DeleteAllItems();CString txt;int index = 0;for (int i = 0; i < Client->ItemMax; i++){if (!Client->ItemBag[i].Isfree) {lstItem.InsertItem(index, Client->ItemBag[i].Name);txt.Format(L"%d/%d", Client->ItemBag[i].Amount, Client->ItemBag[i].MaxAmount);lstItem.SetItemText(index++, 1, txt);}}
}void CWndItem::OnBnClickedButton5()
{lstItem.DeleteAllItems();CString txt;int index = 0;for (int i = 0; i < Client->MountMax; i++){if (!Client->MountBag[i].Isfree) {lstItem.InsertItem(index, Client->MountBag[i].Name);txt.Format(L"%d/%d", Client->MountBag[i].Amount, Client->MountBag[i].MaxAmount);lstItem.SetItemText(index++, 1, txt);}}
}void CWndItem::OnBnClickedButton6()
{lstItem.DeleteAllItems();CString txt;int index = 0;for (int i = 0; i < Client->ItemExMax; i++){if (!Client->ItemEx[i].Isfree) {lstItem.InsertItem(index, Client->ItemEx[i].Name);txt.Format(L"%d/%d", Client->ItemEx[i].Amount, Client->ItemEx[i].MaxAmount);lstItem.SetItemText(index++, 1, txt);}}
}

新加CWndItem.h文件,物品窗口类

#pragma once
#include "afxdialogex.h"// CWndItem 对话框class CWndItem : public CDialogEx
{DECLARE_DYNAMIC(CWndItem)public:CWndItem(CWnd* pParent = nullptr);   // 标准构造函数virtual ~CWndItem();// 对话框数据
#ifdef AFX_DESIGN_TIMEenum { IDD = IDD_PAGE_3 };
#endifprotected:virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV 支持virtual BOOL OnInitDialog();DECLARE_MESSAGE_MAP()
public:CListCtrl lstItem;afx_msg void OnBnClickedButton1();afx_msg void OnBnClickedButton4();afx_msg void OnBnClickedButton5();afx_msg void OnBnClickedButton6();
};

SKILL.cpp文件的修改:修改了 SetConfigID函数

#include "pch.h"
#include "SKILL.h"
#include "extern_all.h"void SKILL::SetConfigID(char*& buffStart)
{GAMEOBJECT::SetConfigID(buffStart);CStringA txt;txt.Format("desc_%s_1", ConfigID);Name = txtManger->ReadTextById(txt.GetBuffer());if (Name.IsEmpty()) {Name = ConfigID;}
}

NetClient.h文件的修改:新加 EquipMax变量、MountMax变量、ItemMax变量、SkillMax变量

#pragma once
#include "NetClass.h"
#include "GameWinSock.h"
#include "AIM.h"
#include "ITEM.h"
#include "SKILL.h"#define CAMP_NAME_QH "xuanrenQH"
#define CAMP_NAME_ZE "xuanrenZQ"#define MAX_AIM 0x200class NetClient // 监视客户端每一个操作
{typedef bool (NetClient::* DATAPROC)(char*&, unsigned&);
public:AIM Player; // 玩家角色/* 怪物列表,最好排序,使用lId排序,然后使用二分查找实现快速查询结构用链表或者数组都可以怪物或附近玩家这种东西不可能会很多如果太多电脑处理不过来,所以数组设置为0x100大小差不多够用*/PAIM Aimlst[MAX_AIM]{};// 用来控制飞天bool HideMode;/*18 01 是装备18 02 是角色背包18 03 是扩展背包18 08 是坐骑背包18 31 是攻击技能18 28 是移动类型技能*/PITEM Equip = nullptr; // 装备栏,18 01 是装备PITEM MountBag = nullptr; // 坐骑栏,18 08 是坐骑背包PITEM ItemBag = nullptr; // 物品栏,18 02 是角色背包PITEM ItemEx = nullptr; // 扩展栏,18 03 是扩展背包PSKILL Skill = nullptr;  // 技能栏,18 28 是技能信息short EquipMax = 0; // 装备栏数据个数short MountMax = 0; // 坐骑栏数据个数short ItemMax = 0; // 物品栏数据个数short ItemExMax = 0; // 扩展栏数据个数short SkillMax = 0; // 技能栏数据个数protected:PSTRUCT_DESC StructTable = nullptr;char* StructTxt = nullptr;POBJ_DESC ObjectTable = nullptr;// 游戏的数据类型表char* ObjectTxt = nullptr;DATAPROC SendProc[0x100];DATAPROC RecvProc[0x100];bool DefaultProc(char*&, unsigned&);
protected: // 消息处理函数-SENDbool OnClientlogin(char*& buff, unsigned& len); // 登录数据包的处理 I_LOGINbool OnClientStartCreateRole(char*& buff, unsigned& len);  // 申请进入创建角色界面 I_CREATEROLE_STARTbool OnClientDelRole(char*& buff, unsigned& len);bool OnClientSendCustom(char*& buff, unsigned& len);bool OnClientCreateRole(char*& buff, unsigned& len);bool OnClientSelectRole(char*& buff, unsigned& len);
protected: // 消息处理函数-RECVbool OnSvrTips(char*& buff, unsigned& len);bool OnSvrloginOk(char*& buff, unsigned& len);bool OnSvrStartCreateRole(char*& buff, unsigned& len);bool OnSverNotice(char*& buff, unsigned& len);bool OnSverObject(char*& buff, unsigned& len);bool OnSverStruct(char*& buff, unsigned& len);bool OnSvrObjectInit(char*& buff, unsigned& len);bool OnSvrObjectInitEx(char*& buff, unsigned& len);bool OnSvrUpdateCord(char*& buff, unsigned& len);bool OnSvrUpdateProperty(char*& buff, unsigned& len);bool OnSvrUpdatePropertyMu(char*& buff, unsigned& len);bool OnSvrRemoveObjectMu(char*& buff, unsigned& len);bool OnSvrUpdateCordEx(char*& buff, unsigned& len);bool OnSvrGameBase(char*& buff, unsigned& len);bool OnSvrGameBaseReset(char*& buff, unsigned& len);
public:PROLEDATA roles;unsigned rolecount;bool logined = false;
private:GameWinSock* WinSock;bool DelRole(const wchar_t* rolename, unsigned _len);PAIM GetAimById(long long lId);PAIM CreateAim(long long lId);void RemoveAimById(long long lId);POBJECTBASE GetGameOBJECT(short MainIndex, short Index);// 获取一个物品或技能void ReSetGameOBJECT(short MainIndex, short max);
public:// 通过角色名获取附近角色的信息PAIM GetAimByName(const wchar_t* name);// 获取面向float GetFace(float x, float y, float targetX, float targetY);// 通过附近角色名获取它的信息,然后通过它的信息里的坐标,再通过我们角色坐标计算面向,效果就是面向 GetAimByName(name); 这个角色void FaceTo(const wchar_t* name);
public:void virtual Init(GameWinSock * _winSock);// 模拟接收的数据包bool SetCoord(long long lId, float x, float h, float y, float face);bool SetProperty(long long lId, int ProType, void* value);/*模拟登陆的方法Id是账号Pass是密码它要基于发送的方法实现,因为我们没有连接socket的操作*/bool login(const char* Id, const char* Pass);bool DelRole(const wchar_t* rolename);bool StartCreateRole();// 用于创建角色bool SelectCamp(const char* _campname);// 选择阵营/*性别 0 男 1 女阵营 1 艾森赫特 2 格兰蒂尔种族 1 布冯特人 3 格洛玛人 4 尤恩图人 6 喀什人职业 1 仲裁者 3秘法师 6 猎魔人 8 元素法师脸型 0 1 2 3*/bool CreateRole(wchar_t* name,double sex, double camp, double face, double occu, const char* photo, const char*infos, const char* txt, double faceShape);// 角色创建// 选择角色并且登录进游戏bool SelectRole(const wchar_t* rolename);// 坠落bool Fall();// 瞬移void Teleport(float x, float h, float y, float face);// 模拟停止bool MoveStop(float x, float h, float y, float face);// 原地跳bool MoveJump(float x, float h, float y, float face, float oldy, float xNext, float yNext);// 移动开始bool MoveWalk(float x, float h, float y, float face, float oldy, float xNext, float yNext);// 应该是移动时跳跃bool MoveWJump(float x, float h, float y, float face, float oldy, float xNext, float yNext);// 使用技能bool UseSkill(const char* _skillName, float x, float h, float y, float face, float xTarget = 0, float hTarget = 0, float yTarget = 0, int rInt1 = 0, int rInt2 = 0, int rInt3 = 0);// 根据角色名字获取一个登录成功数据包(选择角色列表里的一个数据)PROLEDATA GetRoleByName(const wchar_t* rolename);bool Talk(wchar_t* txt, int PdId = 1, double un = 0.0);bool TalkTo(wchar_t* name, wchar_t* txt, double un = 0.0);bool HeartBeep();// 心跳数据包(5秒)bool HeartLoop();// 延迟心跳数据包(20秒)bool Backtoroles(); // 返回到选择角色界面
public:// 用于拦截游戏删除角色功能bool virtual OnDelRole(wchar_t* rolename, unsigned _len);// 用于拦截游戏登录功能void virtual Onlogin(const char* Id, const char*Pass);// 用于拦截游戏创建角色功能bool virtual OnStartCreateRole(int code);// 拦截创建角色bool virtual OnCreateRole(PNS_CREATEROLE _header, PCREATE_ROLE_DATAS _body);// opcode意思是操作码,count意思是数量,buffStart意思是解码的内容开始,buffend意思是解码的内容结束,buffer是原始的数据,len是原始数据的长度// char& buffer, int& len这俩参数带&的原因是,在 OnSendCustom 里进行修改之后,通过&的方式传递回去bool virtual OnSendCustom(PNET_SEND_CHEAD _coder, char*& buffer, unsigned& len);// 拦截0xA开头发送的数据包bool virtual OnSelectRole(wchar_t* rolename);
public:// 针对SendCustom的单独处理bool virtual OnChooseCamp(PNS_CHOOSECAMP _coder);bool virtual OnChat(PCHAT_DATA _coder);bool virtual OnChatPublic(PCHAT_PUB _coder);bool virtual OnChatPrivate(PCHAT_PRV _coder);bool virtual OnHeartBeep(PHEART_BEEP _coder);bool virtual OnHeartLoop(PHEART_LOOP _coder);// 分发移动处理函数bool virtual OnMove(PMOVE_DATA _coder);// 移动中处理函数bool virtual OnMoveWalk(PMOVE_DATA_WALK _coder);// 停止移动处理函数bool virtual OnMoveStop(PMOVE_DATA_STOP _coder);// 跳跃处理函数bool virtual OnMoveJump(PMOVE_DATA_JUMP _coder);// 移动时跳跃bool virtual OnMoveWJump(PMOVE_DATA_WJUMP _coder);//  分发坠落函数bool virtual OnFall(PFALL_DATA_START _coder);// 针对Notice的单独处理bool virtual OnSvrChat(PCHAT_PRV _coder);bool virtual OnUseSkill(PUSESKILL _coder);bool virtual OnInited(); // 发送完了964数据包,表示角色上线public:// 处理失败,参数是错误码bool virtual Tips(int code);void virtual loginok(ROLE_DATA* _roles, int count);bool virtual OnScrStartCreateRole(short code,wchar_t* _txt);bool virtual OnSvrNotice(PNET_SEND_CHEAD _coder, int count, char*& buffer, unsigned& len);
public:bool virtual OnRecvData(char*& buff, unsigned& len);bool virtual OnSendData(char*& buff, unsigned& len);bool virtual OnConnect(char*& ip, unsigned& port);};

CUI.cpp文件的修改:修改了 OnInitDialog函数

// CUI.cpp: 实现文件
//#include "pch.h"
#include "htdMfcDll.h"
#include "CUI.h"
#include "afxdialogex.h"
#include "extern_all.h"
// CUI 对话框IMPLEMENT_DYNAMIC(CUI, CDialogEx)CUI::CUI(CWnd* pParent /*=nullptr*/): CDialogEx(IDD_MAIN, pParent), txtDetails(_T("")), txtChat(_T("")), txtChatName(_T(""))
{}CUI::~CUI()
{
}void CUI::SetListView(CListCtrl* lst)
{auto lStyle = GetWindowLongPtr(lst->m_hWnd, GWL_STYLE); // 获取窗口样式lStyle |= LVS_REPORT; // 设置为报表模式SetWindowLongPtr(lst->m_hWnd, GWL_STYLE, lStyle);// 给窗口设置样式auto dStyle = lst->GetExtendedStyle(); // 获取扩展样式dStyle |= LVS_EX_FULLROWSELECT; // 设置选择时选择一行dStyle |= LVS_EX_GRIDLINES; // 画网格线lst->SetExtendedStyle(dStyle); // 设置扩展样式
}void CUI::DoDataExchange(CDataExchange* pDX)
{CDialogEx::DoDataExchange(pDX);DDX_Control(pDX, IDC_TAB1, mTab);DDX_Control(pDX, IDC_LIST1, lstlog);DDX_Text(pDX, IDC_EDIT1, txtDetails);DDX_Text(pDX, IDC_EDIT3, txtChat);DDX_Text(pDX, IDC_EDIT2, txtChatName);DDX_Control(pDX, IDC_COMBO2, cmbChat);
}BOOL CUI::OnInitDialog()
{CDialogEx::OnInitDialog();SetListView(&lstlog);InstallPage(new CUIWnd_0(this), IDD_PAGE_0, L"角色", TRUE);InstallPage(new CUIWnd_1(this), IDD_PAGE_1, L"周围");InstallPage(new CWndSet(), IDD_PAGE_2, L"设置");InstallPage(new CWndItem(), IDD_PAGE_3, L"装备");InstallPage(new CWndSkill(), IDD_PAGE_4, L"技能");lstlog.InsertColumn(0, L"消息", 0, 70);lstlog.InsertColumn(1, L"内容", 0, 700);lstlog.InsertColumn(2, L"时间", 0, 200);//PageINJ.Init(wAppPath);//PageRAN.SetAppPath(wAppPath);for (CString & txt : ChatPdName){cmbChat.AddString(txt);}cmbChat.SetCurSel(0);return TRUE;
}bool CUI::InstallPage(CDialogEx* wnd, int IDD_WND, CString&& _Name, BOOL IsShow)
{if (CurPage >= (sizeof(WNDS) / sizeof(CDialogEx*))) return false;Pages[CurPage] = wnd;Pages[CurPage]->Create(IDD_WND, this);//Pages[CurPage]->SetParent(this);Pages[CurPage]->ShowWindow(IsShow);CRect rect;mTab.GetClientRect(&rect);rect.top += 32;rect.left += 5;rect.bottom -= 4;rect.right -= 5;Pages[CurPage]->MoveWindow(&rect);mTab.InsertItem(CurPage, _Name);CurPage++;return true;
}BEGIN_MESSAGE_MAP(CUI, CDialogEx)ON_NOTIFY(TCN_SELCHANGE, IDC_TAB1, &CUI::OnTcnSelchangeTab1)ON_WM_TIMER()ON_BN_CLICKED(IDC_BUTTON1, &CUI::OnBnClickedButton1)
END_MESSAGE_MAP()// CUI 消息处理程序void CUI::OnTcnSelchangeTab1(NMHDR* pNMHDR, LRESULT* pResult)
{// TODO: 在此添加控件通知处理程序代码*pResult = 0;int n = mTab.GetCurSel();for (int i = 0; i < CurPage; i++){Pages[i]->ShowWindow(i == n);}
}PTextManger CUI::getTxtManger()
{if (!txtManger)txtManger = new TextManger("F:\\语言包.txt");return txtManger;
}void CUI::loginok(ROLE_DATA* _roles, int count)
{PushLog(LOGTYPE::SYS, L"账号登录成功");NetClient::loginok(_roles, count);wnds.wndRole->lstRole.DeleteAllItems();CString txtInfos;for (int i = 0; i < count; i++){txtInfos = _roles[i].infos.value();txtInfos = txtInfos + L";";CString txtIndex, txtSex, txtMap, txtJob, txtCamp, txtRace, txtLv;CStringA stxtMap, stxtJob, stxtCamp, stxtRace;txtSex = ReadValue(txtInfos, L"1,", L";");txtMap = ReadValue(txtInfos, L"56,", L";");txtJob = L"job_" + ReadValue(txtInfos, L"37,", L";");txtCamp = L"camp_" + ReadValue(txtInfos, L"35,", L";");txtRace = L"race_" + ReadValue(txtInfos, L"36,", L";");txtLv = ReadValue(txtInfos, L"38,", L";");txtIndex.Format(L"%d", _roles[i].index.value());stxtMap = txtMap;stxtJob = txtJob;stxtCamp = txtCamp;stxtRace = txtRace;txtSex = SexName[txtSex == L"1"];wnds.wndRole->lstRole.InsertItem(0, txtIndex);wnds.wndRole->lstRole.SetItemText(0, 1, _roles[i].name);wnds.wndRole->lstRole.SetItemText(0, 2, txtLv);wnds.wndRole->lstRole.SetItemText(0, 3, txtSex);wnds.wndRole->lstRole.SetItemText(0, 4, getTxtManger()->ReadTextById(stxtCamp.GetBuffer()));wnds.wndRole->lstRole.SetItemText(0, 5, getTxtManger()->ReadTextById(stxtMap.GetBuffer()));wnds.wndRole->lstRole.SetItemText(0, 6, getTxtManger()->ReadTextById(stxtRace.GetBuffer()));wnds.wndRole->lstRole.SetItemText(0, 7, getTxtManger()->ReadTextById(stxtJob.GetBuffer()));}
}bool CUI::Tips(int code)
{CString logName;logName.Format(L"服务器提示:%d", code);PushLog(LOGTYPE::TIPS, logName.GetBuffer());// NetClient::Tips(code);return true;
}bool CUI::OnInited()
{SetTimer(0x10001, 50, NULL);return true;
}bool CUI::OnSvrChat(PCHAT_PRV _coder)
{CString txt;CString txtPd;CString txtName = _coder->name;CString txtInfo = _coder->txt;txt.Format(L"%d", _coder->ChartId.value());AfxMessageBox(txt);switch (_coder->ChartId){case 1:// 附近频道txtPd = L"附近";break;case 2:// 区域频道txtPd = L"区域";break;case 3:// 私聊txtPd = L"接收的私聊";// return OnChatPrivate((PCHAT_PRV)_coder);break;case 6:// 公会频道txtPd = L"公会";break;case 9:// 阵营频道txtPd = L"阵营";break;case 21:// 喊话频道txtPd = L"喊话";// return OnChatPublic((PCHAT_PUB)_coder);break;case 103:// 喊话频道txtPd = L"发送的私信";// return OnChatPublic((PCHAT_PUB)_coder);break;}txt.Format(L"[%s][%s][%s]", txtPd, txtInfo, txtName);PushLog(LOGTYPE::CHAT, txt.GetBuffer());return true;
}bool CUI::OnFall(PFALL_DATA_START _coder)
{NetClient::OnFall(_coder);return !wnds.wndSet->setValue[(unsigned)SETNAME::NeverFall];
}bool CUI::OnMoveWalk(PMOVE_DATA_WALK _coder)
{if (wnds.wndSet->setValue[(unsigned)SETNAME::AddSpeed]){float* MoveSpeed = (float*)_coder->MoveSpeed.oldPointer;MoveSpeed[0] = wnds.wndSet->OldSpeed;}return true;
}bool CUI::OnMoveJump(PMOVE_DATA_JUMP _coder)
{if (wnds.wndSet->setValue[(unsigned)SETNAME::AddSpeed]){float* MoveSpeed = (float*)_coder->MoveSpeed.oldPointer;MoveSpeed[0] = wnds.wndSet->OldSpeed;}return true;
}bool CUI::OnMoveWJump(PMOVE_DATA_WJUMP _coder)
{if (wnds.wndSet->setValue[(unsigned)SETNAME::AddSpeed]){float* MoveSpeed = (float*)_coder->MoveSpeed.oldPointer;MoveSpeed[0] = wnds.wndSet->OldSpeed;}return true;
}CString CUI::ReadValue(CString& txt, wchar_t* key, wchar_t* endStr)
{CString result = L"";int iStart = txt.Find(key);if (iStart > -1) {iStart = iStart + wcslen(key);int iend = txt.Find(endStr, iStart);if (iend > -1)result = txt.Mid(iStart, iend - iStart);}return result;
}void CUI::PushLog(LOGTYPE type, wchar_t* txt)
{struct tm newtiem {};time_t t;time(&t);localtime_s(&newtiem, &t); // 获取时间CString logName;logName.Format(L"%.4d-%.2d-%.2d %.2d:%.2d:%.2d", newtiem.tm_year + 1900, newtiem.tm_mon + 1, newtiem.tm_mday, newtiem.tm_hour, newtiem.tm_min, newtiem.tm_sec);lstlog.InsertItem(0, MsgName[(int)type]);lstlog.SetItemText(0, 1, txt);lstlog.SetItemText(0, 2, logName);
}void CUI::OnTimer(UINT_PTR nIDEvent)
{// wnds.wndAIM->UI();CStringA tmp;tmp.Format("%d", Player.CurArea);txtDetails.Format(L"lv.%d.%s 生命值[%d/%d] 经验值[%d/%d] 当前所在场景[%s](%.2f|%.2f|%.2f)", Player.Level, Player.Name,  Player.HP, Player.MaxHP + Player.MaxHPAdd, Player.PlayerExp, Player.PlayerUpgradeExp, getTxtManger()->ReadTextById(tmp.GetBuffer()), Player.x, Player.h, Player.y);SetDlgItemText(IDC_EDIT1, txtDetails.GetBuffer());// UpdateData(FALSE);__super::OnTimer(nIDEvent);
}void CUI::OnBnClickedButton1()
{int nsel = cmbChat.GetCurSel();UpdateData(TRUE);if (nsel > -1) {if (ChatPdId[nsel] != -1) {Talk(txtChat.GetBuffer(), ChatPdId[nsel]);}else {TalkTo(txtChatName.GetBuffer(), txtChat.GetBuffer());}txtChat = L"";}SetDlgItemText(IDC_EDIT3, txtChat.GetBuffer());}

CUI.h文件的修改:新加 CWndItem.h头文件、CWndSkill.h头文件,修改了 WNDS结构体

#pragma once
#include "afxdialogex.h"
#include "NetClient.h"
#include "TextManger.h"
//增加页面头文件
#include "CUIWnd_0.h"
#include "CUIWnd_1.h"
#include "CWndSet.h"
#include "CWndItem.h"
#include "CWndSkill.h"
//游戏辅助UI类
// CUI 对话框enum class LOGTYPE {TIPS = 0,SYS = 1,CHAT = 2,MAX
};typedef struct WNDS {CUIWnd_0* wndRole;CUIWnd_1* wndAIM;CWndSet* wndSet;CWndItem* wndItem;CWndSkill* wndSkill;
}*PWNDS;// #define MAX_PAGE_MAIN 3// 这里用了多重继承,这回有一个问题,函数名一样的会发生冲突
// 所以在继承的时候要注意函数名
class CUI : public CDialogEx,public NetClient
{DECLARE_DYNAMIC(CUI)public:CUI(CWnd* pParent = nullptr);   // 标准构造函数virtual ~CUI();// 对话框数据
#ifdef AFX_DESIGN_TIMEenum { IDD = IDD_MAIN };
#endifprotected:virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV 支持DECLARE_MESSAGE_MAP()union {CDialogEx* Pages[sizeof(WNDS)/sizeof(CDialogEx*)];WNDS wnds;};short      CurPage = 0;
public:CTabCtrl mTab;virtual BOOL OnInitDialog();bool    InstallPage(CDialogEx* wnd, int IDD_WND, CString&& _Name, BOOL IsShow=FALSE);afx_msg void OnTcnSelchangeTab1(NMHDR* pNMHDR, LRESULT* pResult);
public:void SetListView(CListCtrl* lst);PTextManger getTxtManger();CListCtrl lstlog;
protected:CString MsgName[(unsigned int)LOGTYPE::MAX]{L"错误",L"系统",L"聊天"};CString SexName[2]{L"男",L"女"};CString ChatPdName[6]{L"附近",L"区域",L"公会",L"阵营",L"喊话",L"私信"};int ChatPdId[6]{1, 2, 6, 9, 21, -1};void PushLog(LOGTYPE type, wchar_t* txt);
protected:void virtual loginok(ROLE_DATA* _roles, int count);bool virtual Tips(int code);bool virtual OnInited();bool virtual OnSvrChat(PCHAT_PRV _coder);//  分发坠落函数bool virtual OnFall(PFALL_DATA_START _coder);// 移动中处理函数bool virtual OnMoveWalk(PMOVE_DATA_WALK _coder);// 跳跃处理函数bool virtual OnMoveJump(PMOVE_DATA_JUMP _coder);// 移动时跳跃bool virtual OnMoveWJump(PMOVE_DATA_WJUMP _coder);// 解析角色的信息,性别、种族、阵营等CString ReadValue(CString&txt, wchar_t* key, wchar_t* endStr);
public:CString txtDetails;afx_msg void OnTimer(UINT_PTR nIDEvent);CString txtChat;CString txtChatName;afx_msg void OnBnClickedButton1();CComboBox cmbChat;
};

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/24167.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

新媒体暴力起号必备因素!沈阳新媒体运营培训学校

1周涨粉10w&#xff1f;这对普通人来说可以说是天文数字&#xff0c;但只要掌握方式方法&#xff0c;普通人也能做到&#xff01; 面试经验丰富的人都深知&#xff0c;给面试官留下的第一印象相当重要&#xff0c;几乎决定了80%的面试机会。标题也是如此&#xff0c;在完成一篇…

[经验] 蝉联一词的含义是什么 #知识分享#职场发展

蝉联一词的含义是什么 蝉联这个词起源于古代中国&#xff0c;最初是指天子连续两年以上的年号相同。后来&#xff0c;这个词被用于形容某个人或某个团体连续多次获得某种荣誉或奖项的情况。在现代生活中&#xff0c;我们常常听到某个体育运动员蝉联冠军、某个企业蝉联业绩排行榜…

基于拓扑漏洞分析的网络安全态势感知模型

漏洞态势分析是指通过获取网络系统中的漏洞信息、拓扑信息、攻击信息等&#xff0c;分析网络资产可能遭受的安全威胁以及预测攻击者利用漏洞可能发动的攻击&#xff0c;构建拓扑漏洞图&#xff0c;展示网络中可能存在的薄弱环节&#xff0c;以此来评估网络安全状态。 在网络安…

科普|大数据风险检测对申贷人有哪些好处?

大数据风险检测可以极大地提高金融机构在用户肖像、反欺诈和信用评级等方面的效率和风险控制能力&#xff0c;这是金融企业发展过程中必须结合的一种科技技术。大数据风险检测覆盖信贷领域的所有流程&#xff0c;从客户获取到身份验证&#xff0c;再到信贷中和信贷后。因此&…

电赛报告书写

一、总体要求 &#xff08;1&#xff09;摘要&#xff1a;一页&#xff0c;小于300字 &#xff08;2&#xff09;正文&#xff1a;不超过8页 &#xff08;3&#xff09;附录&#xff1a;可以没有&#xff0c;但是不能超过2页 二、摘要书写 摘要要小于等于300字&#xff0c…

实现飞书机器人推送消息到指定群组或者用户

实现飞书机器人推送消息到指定群组或者用户 1 简介2 创建飞书应用2.1 注册登录2.2 创建应用2.3 添加应用能力2.4 权限管理3 发布应用4 代码示例4.1 获取应用ID与token4.2 使用Python SDK4.3 简单示例4.4 获取用户或机器人所在的群列表4.5 通过手机号或邮箱获取用户 ID4.6 给群组…

生活使用英语口语柯桥外语学校成人英语学习

● “自来水”英语怎么说&#xff1f; ● “自来水”的英语表达是&#xff1a;Running water或者Tap water. 例句&#xff1a; There are hot and cold running water in all the bedrooms. 所有的卧室里都有冷热自来水。 ● “热水”英文怎么水&#xff1f; ● 我们不管…

C++设计模式——Adapter适配器模式

一&#xff0c;适配器模式简介 适配器模式是一种结构型设计模式&#xff0c;用于将已有接口转换为调用者所期望的另一种接口。 适配器模式让特定的API接口可以适配多种场景。例如&#xff0c;现有一个名为"Reader()"的API接口只能解析txt格式的文件&#xff0c;给这…

【css3】png图片实现动态动画

.border_style {width: 400px;height: 400px;background-color: black;margin: auto;}keyframes sprite-animation {0% {background-position: 0 0;}100% {background-position: 0 -2064px;/* 假设每个图像的宽度为100px */}}.wrj_box {width: 86px;height: 86px;background-im…

STL中stack和queue模拟实现+容器适配器

目录 容器适配器 STL标准库中stack和queue的底层结构 deque的简单介绍 deque的缺陷 为什么选择deque作为stack和queue的底层默认容器 stack的模拟实现 queue的模拟实现 容器适配器 适配器是一种设计模式&#xff08;设计模式是一套被反复使用的&#xff0c;多数人知晓…

OpenAI模型规范概览

这是OpenAI对外分享的模型规范文档&#xff08;Model Spec&#xff09;&#xff0c;它定义了OpenAI希望在API接口和ChatGPT&#xff08;含GPT系列产品&#xff09;中模型的行为方式&#xff0c;这也是OpenAI超级对齐团队奉行的行为准则&#xff0c;希望能对国内做RLHF的同学有帮…

阿里云对象存储OSS简单使用

文章目录 概念基本概念Bucket 准备工作控制台操作对象存储OSSJava客户端操作对象存储OSS参考来源 概念 基本概念 阿里云对象存储 OSS是一款海量、安全、低成本、高可靠的云存储服务&#xff0c;提供最高可达 99.995 % 的服务可用性。而且提供了多种存储类型&#xff0c;降低我…

SemiDrive X9H 平台 QT 静态编译

一、 前言 芯驰 X9H 芯片&#xff0c;搭载多个操作系统协同运行&#xff0c;系统实现了仪表、空调、中控、副驾多媒体的四屏驱动控制&#xff0c;在人车智能交互上可以通过显示屏、屏幕触摸控制、语音控制、物理按键控制、车身协议的完美融合&#xff0c;使汽车更智能。让车主…

算法:94. 二叉树的中序遍历

给定一个二叉树的根节点 root &#xff0c;返回 它的 中序 遍历 。 示例 1&#xff1a; 输入&#xff1a;root [1,null,2,3] 输出&#xff1a;[1,3,2]示例 2&#xff1a; 输入&#xff1a;root [] 输出&#xff1a;[]示例 3&#xff1a; 输入&#xff1a;root [1] 输出&am…

静态IP代理服务对比:哪些提供商值得信赖?静态ip代理哪家好用?

当涉及选择静态IP代理时&#xff0c;许多人可能会感到困惑&#xff0c;因为市场上存在着各种各样的选项。本文旨在为您提供一些关键指导&#xff0c;帮助您确定哪种静态IP代理是最适合您需求的。在这个过程中&#xff0c;我们将介绍一个备受推崇的解决方案——太阳HTTP。 1.高速…

拥抱生态农业,享受绿色生活

随着人们对健康生活的追求日益增强&#xff0c;生态农业逐渐成为人们关注的焦点。我们深知生态农业对于保护生态环境、提高农产品品质的重要性&#xff0c;因此&#xff0c;我们积极推广生态农业理念&#xff0c;让更多的人了解并参与到生态农业的实践中来。 生态农业的蓝总说&…

ADASIS V2 协议-1

ADAS V2协议-1 1 简介2 版本控制3 ADASIS v23.1 ADASIS v2 Horizon &#xff08;地平线&#xff09;3.2 ADASIS v2的构建3.3 ADASIS v2 Horizon Provider &#xff08;ADAS V2地平线提供者&#xff09;3.4 paths and offsets &#xff08;路径和偏移量&#xff09;3.5 Path Pro…

YOLOv8---seg实例分割(制作数据集,训练模型,预测结果)

YOLOv8----seg实例分割&#xff08;制作数据集&#xff0c;训练模型&#xff0c;预测结果&#xff09; 内容如下&#xff1a;【需要软件及工具&#xff1a;pycharm、labelme、anaconda、云主机&#xff08;跑训练&#xff09;】 1.制作自己的数据集 2.在yolo的预训练模型的基础…

Prompt 提示词强大方法论和框架2

自从ChatGPT Chat Generative Pre-trained Transformer于2022年11月30日发布以来&#xff0c;一个新兴的行业突然兴起&#xff0c; 那就是提示工程Prompt engineering&#xff0c;可谓如日冲天。 从简单的文章扩写到RAG&#xff0c;ChatGPT展现了前所未有的惊人能力。 在上一…

90后机器人创业者再获10亿元融资,为精密传动行业注入新动力!

据了解&#xff0c;一位90后机器人创业者再次获得近10亿元人民币的融资&#xff0c;这一消息在精密传动行业引起了广泛关注。 杭州宇树科技有限公司&#xff08;简称“宇树”&#xff09;&#xff0c;2024年春节前完成了B2轮融资&#xff0c;融资近10亿元人民币&#xff0c;本轮…