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

news2024/11/19 9:26:41

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

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

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

上一个内容: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;
};


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

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

相关文章

vue3组件传值---vue组件通过属性,事件和provide,inject进行传值

通过属性传值&#xff08;父传子&#xff09; vue的组件具有props自建属性&#xff08;自定义名称&#xff0c;类似于class&#xff0c;id的属性&#xff09;&#xff0c;通过这个属性&#xff0c;父组件可以向子组件传递参数&#xff0c;从而实现组件之间的信息传递&#xff0…

【深度学习】【机器学习】支持向量机,网络入侵检测,KDD数据集

文章目录 环境加载数据归一化数据训练模型用测试数据集给出评估指标准确率召回率预测某个输入数据随便取一行数据加载训练好的SVM支持向量机模型并预测 全部数据和代码下载 环境 之前介绍过用深度学习做入侵检测&#xff0c;这篇用向量机。 环境Python3.10 requirements.txt…

深度解析:短剧市场的发展趋势

一、 短剧视频的兴起 小程序短剧视频是近年来在社交媒体平台上崭露头角的一种内容形式&#xff0c;其独特的表达方式吸引了大量用户的关注&#xff0c;这种类型的视频通常以小幅度、短时长的剧情为主&#xff0c;具有轻松幽默的风格&#xff0c;适合在碎片化的时间作为娱乐消遣…

OpenFeign --学习笔记

什么是OpenFeign&#xff1f; OpenFeign可以想象成一座连接客户端&#xff08;服务器&#xff09;和服务器之间的桥梁。在微服务架构中&#xff0c;各个服务之间像小岛屿一样分布在网络上&#xff0c;它们需要相互通信才能协同工作。但是&#xff0c;这些岛屿之间并没有现成的…

el-dialog给弹框标题后加图标,鼠标悬停显示详细内容

效果&#xff1a; 代码&#xff1a; <div slot"title" class"el-dialog__title">标题<el-tooltip effect"dark" placement"right"><div slot"content">鼠标悬停显示</div><i class"el-icon…

AI绘画入门教程(非常详细)从零基础入门到精通,看完这一篇就够了

AI绘画的出现&#xff0c;让越来越多的人可以轻松画出美丽的插画作品。在本篇文章中&#xff0c;我们将会使用AI绘画软件&#xff1a;触站&#xff0c;轻松创建属于自己的作品。从零开始学AI绘画&#xff01; 从零开始学AI绘画关键步骤&#xff1a; 第一步&#xff1a;下载软…

MatrixOne→MatrixOS:矩阵起源的创业史即将用“AI Infra”和“AI Platform”书写新章程

在数字化浪潮的推动下&#xff0c;MatrixOne的故事就像一部科技界的创业史诗&#xff0c;它始于一个简单而宏伟的梦想——构建一个能够支撑起新一代数字世界的操作系统。想象一下&#xff0c;在AIGC时代&#xff0c;数据流动如同“血液”&#xff0c;算法运转如同“心跳”&…

<microros> 如何自定义uROS2数据类型

如何自定义数据类型 在microros中&#xff0c;我们可以看到&#xff0c;官方给我们提供了很多数据类型。 如果我们在实际使用的时候&#xff0c;这些类型无法满足我们的传输要求怎么办呢&#xff1f; 官方也提供了自定义数据类型的办法。 参考&#xff1a; https://github…

深度学习的实用性探究:虚幻还是现实?

深度学习的实用性探究&#xff1a;虚幻还是现实&#xff1f; 深度学习作为人工智能领域的一个热点&#xff0c;已经在学术和工业界引起了广泛的关注。尽管深度学习技术显示出惊人的性能和潜力&#xff0c;但有时它们给人的感觉是“虚”的&#xff0c;或许是因为它们的抽象性和…

MySQL进阶——索引使用规则

在上篇文章我们学习了MySQL进阶——索引&#xff0c;这篇文章学习MySQL进阶——索引使用规则。 索引使用规则 在使用索引时&#xff0c;需要遵守一些使用规则&#xff0c;否则索引会部分失效或全部失效。 最左前缀法则 最左前缀法则是查询从索引的最左列开始&#xff0c;并…

C语言字符、数组指针变量

目录 一、字符指针变量 二、数组指针变量 a.数组指针变量是什么 b.数组指针变量的书写格式 c.数组指针变量如何初始化 d.二维数组传参的本质 一、字符指针变量 在指针的类型中我们知道有一种指针类型为字符指针 char* 。 其一般使用&#xff1a; int main() {char ch w…

解决:Navicat导入sql脚本时报2006

目录 问题复现原因分析解决办法问题小结 1) MySQL 服务宕了 2) mysql连接超时 3) mysql请求链接进程被主动kill 4) Your SQL statement was too large. 问题复现 今天在用Navicat 16.0.6导入.sql文件时&#xff0c;运行一半就报错了。错误如下&#xff1a; [E…

机器学习实验----支持向量机(SVM)实现二分类

目录 一、介绍 (1)解释算法 (2)数据集解释 二、算法实现和代码介绍 1.超平面 2.分类判别模型 3.点到超平面的距离 4.margin 间隔 5.拉格朗日乘数法KKT不等式 (1)介绍 (2)对偶问题 (3)惩罚参数 (4)求解 6.核函数解决非线性问题 7.SMO (1)更新w (2)更新b 三、代…

【机器学习数据挖掘】基于ARIMA 自回归积分滑动平均模型的销售价格库存分析报告 附完整python代码

资源地址&#xff1a;Python数据分析大作业 4000字 图文分析文档 销售分析 完整python代码 ​ 完整代码分析 同时销售量后1000的sku品类占比中&#xff08;不畅销产品&#xff09;如上&#xff0c;精品类产品占比第一&#xff0c;达到66.7%&#xff0c;其次是香化类产品&#…

别人状告你怎么办?你知道还可反告吗?

别人状告你怎么办&#xff1f;你知道还可反告吗&#xff1f; --李秘书讲写作&#xff1a;关于反诉状的写作技巧与策略 反诉状是民事诉讼中的一种重要法律文书&#xff0c;它允许被告在原告提起诉讼后&#xff0c;对原告提起反诉&#xff0c;以抵消原告的诉讼请求。李秘书这节…

视频会议开发:为什么必须使用显卡GPU解码渲染视频?

现在&#xff0c;使用视频会议系统远程协同办公、沟通交流&#xff0c;已经非常普遍了。如果我们要开发自己的视频会议系统&#xff0c;那么&#xff0c;GPU解码渲染技术是不可缺少的。 在视频会议系统中&#xff0c;经常需要同时观看会议中多个参会人员的视频图像&#xff0c;…

Ant Design Pro

一&#xff1a;Ant Design pro是什么&#xff1a; Ant Design Pro 是基于 Ant Design 和 umi 的封装的一整套企业级中后台前端/设计解决方案&#xff0c;致力于在设计规范和基础组件的基础上&#xff0c;继续向上构建&#xff0c;提炼出典型模板/业务组件/配套设计资源&#x…

【js】input设置focus()不生效

实现功能&#xff1a;点击添加文章标签的时候&#xff0c;输入框聚焦。 页面上&#xff0c;input输入框默认不显示&#xff0c;是display:none; 点击添加按钮后&#xff0c;input输入框才显示。 在js里面直接获取元素进行设置聚焦不成功 。 ∵ focus方法比show方法先执行。j…

【MySQL】MySQL Connect -- 详解

一、Connector / C 使用 要使用 C 语言连接 MySQL&#xff0c;需要使用 MySQL 官网提供的库&#xff0c;可以去官网进行下载&#xff1a;MySQL :: MySQL Community Downloads 我们使用 C 接口库来进行连接&#xff0c;要正确使用&#xff0c;还需要做一些准备工作&#xff1a…

从军事角度理解“战略与战术”

战略与战术&#xff0c;均源于军事术语。 战略&#xff08;Strategy&#xff09;&#xff0c;源自希腊语词汇“strategos&#xff08;将军&#xff09;”和“strategia&#xff08;军事指挥部&#xff0c;即将军的办公室和技能&#xff09;”。指的是指挥全局性作战规划的谋略…