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_TIME
	enum { IDD = IDD_PAGE_4 };
#endif

protected:
	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_TIME
	enum { IDD = IDD_PAGE_3 };
#endif

protected:
	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 0x200

class 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: // 消息处理函数-SEND
	bool OnClientlogin(char*& buff, unsigned& len); // 登录数据包的处理 I_LOGIN
	bool OnClientStartCreateRole(char*& buff, unsigned& len);  // 申请进入创建角色界面 I_CREATEROLE_START
	bool OnClientDelRole(char*& buff, unsigned& len);
	bool OnClientSendCustom(char*& buff, unsigned& len);
	bool OnClientCreateRole(char*& buff, unsigned& len);
	bool OnClientSelectRole(char*& buff, unsigned& len);
protected: // 消息处理函数-RECV
	bool 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_TIME
	enum { IDD = IDD_MAIN };
#endif

protected:
	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;
};


  • 8
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值