[Release] HP Bar Source 99.6XT (Main 1.00.13)
Hello,
I finally found some spare time to finish this small project. As i promised i'm releasing it after it's finished. The release includes source code without compiled binaries, everyone who wanna use it can compile it, so i leave this part to you guys.
Client Side
HealthBar.h
Code:
#pragma once
#include "stdafx.h"
#include <gl\GL.h>
#pragma comment(lib,"Opengl32.lib")
#define MAX_MAIN_VIEWPORT 400
struct NEW_HEALTH_BAR
{
WORD index;
BYTE type;
BYTE rate;
};
struct VAngle
{
float X;
float Y;
float Z;
};
void ClearNewHealthBar();
void InsertNewHealthBar(WORD index, BYTE type, BYTE rate);
NEW_HEALTH_BAR* GetNewHealthBar(WORD index, BYTE type);
void DrawNewHealthBar();
#define pCursorX *(DWORD *)0x7CBAF14
#define pCursorY *(DWORD *)0x7CBAF10
#define pProtocolCall 0x004CDA7D
#define pGLSwitch ((void(*)()) 0x005F10B0)
#define pDrawBarForm ((void(*)(float PosX, float PosY, float Width, float Height)) 0x005F21D0)
#define pGetPosFromAngle ((void(*)(int a1, int a2, int a3)) 0x005F0CE0)
#define pSetBlend ((char(*)(BYTE Mode)) 0x005F1130)
#define pDrawText ((int(*)(int posX, int posY, LPCSTR lpString, int a4, char a5, int a6)) 0x00534350 )
#define DrawText ((char(*)(int a1, int a2, LPCSTR lpString))0x005343A0)
#define DrawText2 ((int(*)(int a1, int a2, LPCSTR lpString, int a4, char a5, int a6))0x005342A0)
#define pSetTextColor ((void(__thiscall*)(HDC hdc, COLORREF h)) 0x00661030) // OK
#define MU_CDC_GET_THIS_POINTER 0x00643470 //99.6XT
#define MU_CDC_TABBEDTEXTOUT 0x00454500 //99.6XT
HealthBar.cpp
Code:
#include "stdafx.h"
NEW_HEALTH_BAR gNewHealthBar[MAX_MAIN_VIEWPORT];
void ClearNewHealthBar() // OK
{
for (int n = 0; n < MAX_MAIN_VIEWPORT; n++)
{
gNewHealthBar[n].index = 0xFFFF;
gNewHealthBar[n].type = 0;
gNewHealthBar[n].rate = 0;
}
}
void InsertNewHealthBar(WORD index, BYTE type, BYTE rate) // OK
{
for (int n = 0; n < MAX_MAIN_VIEWPORT; n++)
{
if (gNewHealthBar[n].index == 0xFFFF)
{
gNewHealthBar[n].index = index;
gNewHealthBar[n].type = type;
gNewHealthBar[n].rate = rate;
return;
}
}
}
NEW_HEALTH_BAR* GetNewHealthBar(WORD index, BYTE type) // OK
{
for (int n = 0; n < MAX_MAIN_VIEWPORT; n++)
{
if (gNewHealthBar[n].index != 0xFFFF)
{
if (gNewHealthBar[n].index == index && gNewHealthBar[n].type == type)
{
return &gNewHealthBar[n];
}
}
}
return 0;
}
void DrawNewHealthBar() // OK
{
((void(*)())0x00581D30)();
int PosX, PosY, LifeProgress;
float LifeBarWidth = 38.0f;
char LifeDisplay[20];
VAngle Angle;
for (int n = 0; n < MAX_MAIN_VIEWPORT; n++)
{
int ViewportAddress = *(DWORD*)(0x73C8174) + 1068 * n;
int mIndex = *(WORD*)(ViewportAddress + 492);
int MonsterType = *(BYTE*)(ViewportAddress + 132);
if (!ViewportAddress)
{
continue;
}
NEW_HEALTH_BAR* lpNewHealthBar = GetNewHealthBar(mIndex, MonsterType);
if (lpNewHealthBar == 0)
{
continue;
}
int LifePercent = lpNewHealthBar->rate / 10;
Angle.X = *(float*)(ViewportAddress + 0x10);
Angle.Y = *(float*)(ViewportAddress + 0x14);
Angle.Z = *(float *)(ViewportAddress + 308) + *(float *)(ViewportAddress + 24) + 100.0f;
pGetPosFromAngle((int)&Angle, (int)&PosX, (int)&PosY);
PosX -= (int)floor(LifeBarWidth / (double)2.0);
if ((pCursorX >= PosX) && ((float)pCursorX <= (float)PosX + LifeBarWidth) && (pCursorY >= PosY - 2) && (pCursorY < PosY + 6))
{
sprintf_s(LifeDisplay, "HP : %d0%%", LifePercent);
pDrawText(PosX, PosY - 6, LifeDisplay, 0, 0, 1);
}
pSetBlend(true);
glColor4f(0.0, 0.0, 0.0, 0.5);
pDrawBarForm((float)(PosX + 1), (float)(PosY + 1), LifeBarWidth + 4.0f, 5.0f);
pSetBlend(true);
glColor3f(0.2f, 0.0, 0.0);
pDrawBarForm((float)PosX, (float)PosY, LifeBarWidth + 4.0f, 5.0f);
glColor3f(0.19607843f, 0.039215688f, 0.0);
pDrawBarForm((float)(PosX + 2), (float)(PosY + 2), LifeBarWidth, 1.0f);
if (LifePercent > 10)
{
LifeProgress = 10;
}
else
{
LifeProgress = LifePercent;
}
glColor3f(0.98039216f, 0.039215688f, 0.0);
for (int i = 0; i < LifeProgress; i++)
{
pDrawBarForm((float)(i * 4 + PosX + 2), (float)(PosY + 2), 3.0, 2.0);
}
pGLSwitch();
}
pGLSwitch();
glColor3f(1.0, 1.0, 1.0);
}
Protocol.h
Code:
#ifndef _Protocol_H
#define _Protocol_H
#include "StdAfx.h"
#include "Packets.h"
#define ProtocolCore ((BOOL(*)(DWORD,BYTE*,DWORD,DWORD))0x004CDB60)
extern DWORD *GameIndex;
int cMU_ProtocolCore(int index, PBYTE lpMsg, int len, int flags);
void GCNewHealthBarRecv(PMSG_NEW_HEALTH_BAR_RECV* lpMsg);
#endif
Protocol.cpp
Code:
#include "StdAfx.h"
DWORD *GameIndex = (DWORD*)0x78305B4;
int cMU_ProtocolCore(int index, PBYTE lpMsg, int len, int flags)
{
switch (index)
{
case 0xF3:
{
switch(((lpMsg[0]==0xC1)?lpMsg[3]:lpMsg[4]))
{
case 0xE2:
GCNewHealthBarRecv((PMSG_NEW_HEALTH_BAR_RECV*)lpMsg);
return 1;
}
break;
}
}
return ProtocolCore(index, lpMsg, len, flags);
}
void GCNewHealthBarRecv(PMSG_NEW_HEALTH_BAR_RECV* lpMsg) // OK
{
ClearNewHealthBar();
for (int n = 0; n < lpMsg->count; n++)
{
PMSG_NEW_HEALTH_RECV* lpInfo = (PMSG_NEW_HEALTH_RECV*)(((BYTE*)lpMsg) + sizeof(PMSG_NEW_HEALTH_BAR_RECV) + (sizeof(PMSG_NEW_HEALTH_RECV)*n));
InsertNewHealthBar(lpInfo->index, lpInfo->type, lpInfo->rate);
}
}
dllmain.cpp
Code:
#include "stdafx.h"
BOOL APIENTRY DllMain(HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}
extern "C" _declspec(dllexport) void TheLast()
{
DWORD OldProtect;
if (VirtualProtect(LPVOID(0x401000), 2490366, PAGE_EXECUTE_READWRITE, &OldProtect))
{
ToolKit.SetCompleteHook(0xFF, MU_PROTOCOL_CORE, &cMU_ProtocolCore);
ToolKit.SetCompleteHook(0xE8, 0x00580806, &DrawNewHealthBar);
}
}
GameServer Side
Health packet info worker
Code:
void Start(){
_beginthread(TimerWorker, 0, NULL);
}
void TimerWorker(void * ignored) {
while (true)
{
for (int n = 0; n < OBJECT_MAX; n++)
{
LPOBJ lpObj = gObj(n);
if (lpObj->Type == OBJECT_USER && lpObj->Connected == 3)
{
GCNewHealthBarSend(lpObj);
}
}
Sleep(500);
}
}
void __cdecl GCNewHealthBarSend(LPOBJ lpObj) // OK
{
BYTE send[4096];
PMSG_NEW_HEALTH_BAR_SEND pMsg;
pMsg.header.set(0xF3, 0xE2, 0);
int size = sizeof(pMsg);
pMsg.count = 0;
PMSG_NEW_HEALTH_BAR info;
for (int n = 0; n < MAX_VIEWPORT; n++)
{
if (lpObj->VpPlayer[n].state != VIEWPORT_SEND && lpObj->VpPlayer[n].state != VIEWPORT_WAIT)
{
continue;
}
if (lpObj->VpPlayer[n].type != OBJECT_MONSTER)
{
continue;
}
if (OBJECT_RANGE(lpObj->VpPlayer[n].index) == 0)
{
continue;
}
LPOBJ lpTarget = gObj(lpObj->VpPlayer[n].index);
if (lpTarget->Live == 0)
{
continue;
}
info.index = lpTarget->m_Index;
info.type = (BYTE)lpTarget->Type;
info.rate = (BYTE)((lpTarget->Life * 100) / (lpTarget->MaxLife + lpTarget->AddLife));
memcpy(&send[size], &info, sizeof(info));
size += sizeof(info);
pMsg.count++;
}
pMsg.header.size[0] = SET_NUMBERHB(size);
pMsg.header.size[1] = SET_NUMBERLB(size);
memcpy(send, &pMsg, sizeof(pMsg));
DataSend(lpObj->m_Index, send, size);
}
Packet.h
Code:
struct PSWMSG_HEAD
{
void set(BYTE head, BYTE subh, WORD size) // OK
{
this->type = 0xC2;
this->size[0] = HIBYTE(size);
this->size[1] = LOBYTE(size);
this->head = head;
this->subh = subh;
}
void setE(BYTE head, BYTE subh, WORD size) // OK
{
this->type = 0xC4;
this->size[0] = HIBYTE(size);
this->size[1] = LOBYTE(size);
this->head = head;
this->subh = subh;
}
BYTE type;
BYTE size[2];
BYTE head;
BYTE subh;
};
struct PMSG_NEW_HEALTH_BAR_RECV
{
PSWMSG_HEAD header; // C2:F3:E2
BYTE count;
};
struct PMSG_NEW_HEALTH_RECV
{
WORD index;
BYTE type;
BYTE rate;
};
Misc
Code:
#define MU_PROTOCOL_CORE 0x004CDA7D
enum eViewportState
{
VIEWPORT_NONE = 0,
VIEWPORT_SEND = 1,
VIEWPORT_WAIT = 2,
VIEWPORT_DESTROY = 3,
};
#define OBJECT_RANGE(x) (((x)<0)?0:((x)>=OBJECT_MAX)?0:1)
#define OBJECT_MONSTER_RANGE(x) (((x)<0)?0:((x)>=OBJ_MAXMONSTER)?0:1)
#define SET_NUMBERHB(x) ((BYTE)((DWORD)(x)>>(DWORD)8))
#define SET_NUMBERLB(x) ((BYTE)((DWORD)(x)&0xFF))
#define SET_NUMBERHW(x) ((WORD)((DWORD)(x)>>(DWORD)16))
#define SET_NUMBERLW(x) ((WORD)((DWORD)(x)&0xFFFF))
#define SET_NUMBERHDW(x) ((DWORD)((QWORD)(x)>>(QWORD)32))
#define SET_NUMBERLDW(x) ((DWORD)((QWORD)(x)&0xFFFFFFFF))
Code:
void ToolKitEx::SetCompleteHook(BYTE head, DWORD offset, ...) // OK
{
DWORD OldProtect;
VirtualProtect((void*)offset, 5, PAGE_EXECUTE_READWRITE, &OldProtect);
if (head != 0xFF)
{
*(BYTE*)(offset) = head;
}
DWORD* function = &offset + 1;
*(DWORD*)(offset + 1) = (*function) - (offset + 5);
VirtualProtect((void*)offset, 5, OldProtect, &OldProtect);
}
Main.exe Link :
Download (MEGA)
https://i.imgur.com/pz7QKTp.jpg
re: [Release] HP Bar Source 99.6XT (Main 1.00.13)
You can build a dll file , Thank you for your interest
re: [Release] HP Bar Source 99.6XT (Main 1.00.13)
you can post full surce plz ?
re: [Release] HP Bar Source 99.6XT (Main 1.00.13)
for (int n = 0; n < OBJECT_MAX; n++)
Good luck with cpu usage, since you sending packets to players from players/monsters that will never be on player viewport of target.
re: [Release] HP Bar Source 99.6XT (Main 1.00.13)
Mmm ya but down below it checks does the Monsters are in the view port so it just need to be checked are there any visible at the moment. So the packet must not be sent if no monsters are in the viewport currently. We must simply avoid sending when no monsters are in viewport or hook the ViewportAdd func and send packet per monster. There are tons of ways to implement this, the source code is just a bare example of what can be done and how, that's why is not released as compiled .dll (everyone is free to use/change do whatever he want). To goal was to find the offsets and render the bars, i won't focus on the server side because this isn't a server side project, ofc you are right about the CPU usage.
re: [Release] HP Bar Source 99.6XT (Main 1.00.13)
The problem is not really send or not, but the loop itself.
If this gameservers is look a bit of mine (Even if you use dll), did you will have a game loop that already do this, you need only to send at this loop;
i recommend to do call GCNewHealthBarSend(lpObj); at void MonsterAndMsgProc() function, before
Code:
if ( lpObj->Type == OBJ_USER )
{
gDarkSpirit[n].Run();
}
check, since MonsterAndMsgProc is already done for this type of loop on viewport.
Also you need to verify if life is -1 (Or simple if it is above of maxlife of monster), since can bug in some situations.
Ps. I will try to put my code here to help when i go to home
This function is like a muemu function :P
re: [Release] HP Bar Source 99.6XT (Main 1.00.13)
Ya good call about MonsterAndMsgProc().
As i don't have time to implement it right now will share some dummy code.
Code:
SetCompleteHook(0xE9, 0x004C4869, &TimerTick); // Hook at CDarkSpirit::Run((CDarkSpirit *)&gDarkSpirit + n); position
__declspec(naked) void TimerTick(){
_asm {
push EAX //lpObj instance
call &GCNewHealthBarSend
MOV ECX, DWORD PTR SS : [EBP - 0x8]
IMUL ECX, ECX, 0x28
ADD ECX, 0x3A77ED8 //CDarkSpirit class
CALL 00402478 // CDarkSpirit::Run func
}
}
That's the code of the original MonsterAndMsgProc() function
Code:
for ( n = 0; n < 4000; ++n )
{
lpObj = &gObj + n;
if ( *(&gObj.Connected + 1379 * n) == 3 )
{
if ( lpObj->Type != 2 && lpObj->Type != 3 )
{
gObjSkillUseProcTime500(lpObj);
gObjMsgProc(lpObj);
CreateFrustrum(lpObj->X, lpObj->Y, n);
}
else
{
gObjMonsterProcess(lpObj);
}
if ( lpObj->Type == 1 )
CDarkSpirit::Run((CDarkSpirit *)&gDarkSpirit + n);
}
else if ( lpObj->Connected >= 2 && lpObj->Type == 1 )
{
gObjMsgProc(lpObj);
if ( lpObj->Connected == 3 )
CreateFrustrum(lpObj->X, lpObj->Y, n);
}
}
And the ASM of the 'if'
Code:
004C4864 83F9 01 CMP ECX,0x1
004C4867 75 11 JNZ SHORT 004C487A ; 004C487A
004C4869 8B4D F8 MOV ECX,DWORD PTR SS:[EBP-0x8]
004C486C 6BC9 28 IMUL ECX,ECX,0x28
004C486F 81C1 D87EA703 ADD ECX,0x3A77ED8
004C4875 E8 FEDBF3FF CALL 00402478 ; 00402478
re: [Release] HP Bar Source 99.6XT (Main 1.00.13)
you can post fixed ?
+ packet.h ?
or full source plz in visual ?
re: [Release] HP Bar Source 99.6XT (Main 1.00.13)
Quote:
Originally Posted by
PlugS
you can post fixed ?
+ packet.h ?
or full source plz in visual ?
Sorry i missed that...
Packet.h
Code:
struct PSWMSG_HEAD
{
void set(BYTE head, BYTE subh, WORD size) // OK
{
this->type = 0xC2;
this->size[0] = HIBYTE(size);
this->size[1] = LOBYTE(size);
this->head = head;
this->subh = subh;
}
void setE(BYTE head, BYTE subh, WORD size) // OK
{
this->type = 0xC4;
this->size[0] = HIBYTE(size);
this->size[1] = LOBYTE(size);
this->head = head;
this->subh = subh;
}
BYTE type;
BYTE size[2];
BYTE head;
BYTE subh;
};
struct PMSG_NEW_HEALTH_BAR_RECV
{
PSWMSG_HEAD header; // C2:F3:E2
BYTE count;
};
struct PMSG_NEW_HEALTH_RECV
{
WORD index;
BYTE type;
BYTE rate;
};
re: [Release] HP Bar Source 99.6XT (Main 1.00.13)
in this
ToolKit.SetCompleteHook(0xFF, MU_PROTOCOL_CORE, &cMU_ProtocolCore);
MU_PROTOCOL_CORE is missing define, what is MU_PROTOCOL_CORE ?
re: [Release] HP Bar Source 99.6XT (Main 1.00.13)
Quote:
Originally Posted by
vankyy26
Sorry i missed that...
Packet.h
Code:
struct PSWMSG_HEAD
{
void set(BYTE head, BYTE subh, WORD size) // OK
{
this->type = 0xC2;
this->size[0] = HIBYTE(size);
this->size[1] = LOBYTE(size);
this->head = head;
this->subh = subh;
}
void setE(BYTE head, BYTE subh, WORD size) // OK
{
this->type = 0xC4;
this->size[0] = HIBYTE(size);
this->size[1] = LOBYTE(size);
this->head = head;
this->subh = subh;
}
BYTE type;
BYTE size[2];
BYTE head;
BYTE subh;
};
struct PMSG_NEW_HEALTH_BAR_RECV
{
PSWMSG_HEAD header; // C2:F3:E2
BYTE count;
};
struct PMSG_NEW_HEALTH_RECV
{
WORD index;
BYTE type;
BYTE rate;
};
ToolKit.SetCompleteHook(0xFF, MU_PROTOCOL_CORE, &cMU_ProtocolCore); ToolKit.SetCompleteHook(0xE8, 0x00580806, &DrawNewHealthBar);
You can give me
code : ToolKit
and MU_PROTOCOL_CORE?
re: [Release] HP Bar Source 99.6XT (Main 1.00.13)
you can change ToolKit.SetCompleteHook -> HookOffset
and I think 0x004CDB60 = MU_PROTOCOL_CORE
void HookOffset(DWORD my, DWORD tohook, BYTE type)
{
*(BYTE*)tohook = type;
*(DWORD*)(tohook+1) = my - (tohook+5);
};
vankyy26 I said true or false ?...... :wink:
re: [Release] HP Bar Source 99.6XT (Main 1.00.13)
PMSG_NEW_HEALTH_BAR_SEND = code ?
PMSG_NEW_HEALTH_BAR = code ?
VIEWPORT_SEND = ?
VIEWPORT_WAIT = ?
OBJECT_RANGE = ?
SET_NUMBERHB = ?
SET_NUMBERLB = ?
re: [Release] HP Bar Source 99.6XT (Main 1.00.13)
re: [Release] HP Bar Source 99.6XT (Main 1.00.13)
Code:
#define MU_PROTOCOL_CORE 0x004CDA7D
enum eViewportState
{
VIEWPORT_NONE = 0,
VIEWPORT_SEND = 1,
VIEWPORT_WAIT = 2,
VIEWPORT_DESTROY = 3,
};
#define OBJECT_RANGE(x) (((x)<0)?0:((x)>=OBJECT_MAX)?0:1)
#define OBJECT_MONSTER_RANGE(x) (((x)<0)?0:((x)>=OBJ_MAXMONSTER)?0:1)
#define SET_NUMBERHB(x) ((BYTE)((DWORD)(x)>>(DWORD)8))
#define SET_NUMBERLB(x) ((BYTE)((DWORD)(x)&0xFF))
#define SET_NUMBERHW(x) ((WORD)((DWORD)(x)>>(DWORD)16))
#define SET_NUMBERLW(x) ((WORD)((DWORD)(x)&0xFFFF))
#define SET_NUMBERHDW(x) ((DWORD)((QWORD)(x)>>(QWORD)32))
#define SET_NUMBERLDW(x) ((DWORD)((QWORD)(x)&0xFFFFFFFF))
Code:
void ToolKitEx::SetCompleteHook(BYTE head, DWORD offset, ...) // OK
{
DWORD OldProtect;
VirtualProtect((void*)offset, 5, PAGE_EXECUTE_READWRITE, &OldProtect);
if (head != 0xFF)
{
*(BYTE*)(offset) = head;
}
DWORD* function = &offset + 1;
*(DWORD*)(offset + 1) = (*function) - (offset + 5);
VirtualProtect((void*)offset, 5, OldProtect, &OldProtect);
}