Merge pull request #130 from Laupetin/feature/fonticons
Fonticons for 2D text rendering
This commit is contained in:
commit
5e52289b03
@ -47,7 +47,6 @@ namespace Components
|
||||
Loader::Register(new Toast());
|
||||
Loader::Register(new Party());
|
||||
Loader::Register(new Zones());
|
||||
Loader::Register(new Colors());
|
||||
Loader::Register(new D3D9Ex());
|
||||
#if (!defined(VLD_RPTHOOK_INSTALL) || defined(VLDEnable)) && defined(COMPILE_IW4MVM) // IW4MVM uses detours which produces memory leaks, but those are not really relevant
|
||||
Loader::Register(new IW4MVM());
|
||||
@ -103,6 +102,8 @@ namespace Components
|
||||
Loader::Register(new StartupMessages());
|
||||
Loader::Register(new SoundMutexFix());
|
||||
Loader::Register(new Gamepad());
|
||||
Loader::Register(new Chat());
|
||||
Loader::Register(new TextRenderer());
|
||||
|
||||
Loader::Register(new Client());
|
||||
|
||||
|
@ -73,7 +73,6 @@ namespace Components
|
||||
#include "Modules/Menus.hpp"
|
||||
#include "Modules/Toast.hpp"
|
||||
#include "Modules/Zones.hpp"
|
||||
#include "Modules/Colors.hpp"
|
||||
#include "Modules/D3D9Ex.hpp"
|
||||
#include "Modules/Script.hpp"
|
||||
#include "Modules/Weapon.hpp"
|
||||
@ -131,6 +130,8 @@ namespace Components
|
||||
#include "Modules/StartupMessages.hpp"
|
||||
#include "Modules/Stats.hpp"
|
||||
#include "Modules/SoundMutexFix.hpp"
|
||||
#include "Modules/Chat.hpp"
|
||||
#include "Modules/TextRenderer.hpp"
|
||||
|
||||
#include "Modules/Gamepad.hpp"
|
||||
#include "Modules/Client.hpp"
|
||||
|
209
src/Components/Modules/Chat.cpp
Normal file
209
src/Components/Modules/Chat.cpp
Normal file
@ -0,0 +1,209 @@
|
||||
#include "STDInclude.hpp"
|
||||
|
||||
namespace Components
|
||||
{
|
||||
Game::dvar_t** Chat::cg_chatHeight = reinterpret_cast<Game::dvar_t**>(0x7ED398);
|
||||
Dvar::Var Chat::cg_chatWidth;
|
||||
Game::dvar_t** Chat::cg_chatTime = reinterpret_cast<Game::dvar_t**>(0x9F5DE8);
|
||||
|
||||
bool Chat::SendChat;
|
||||
|
||||
const char* Chat::EvaluateSay(char* text, Game::gentity_t* player)
|
||||
{
|
||||
SendChat = true;
|
||||
|
||||
if (text[1] == '/')
|
||||
{
|
||||
SendChat = false;
|
||||
text[1] = text[0];
|
||||
++text;
|
||||
}
|
||||
|
||||
TextRenderer::StripMaterialTextIcons(text, text, strlen(text) + 1);
|
||||
|
||||
Game::Scr_AddEntity(player);
|
||||
Game::Scr_AddString(text + 1);
|
||||
Game::Scr_NotifyLevel(Game::SL_GetString("say", 0), 2);
|
||||
|
||||
return text;
|
||||
}
|
||||
|
||||
__declspec(naked) void Chat::PreSayStub()
|
||||
{
|
||||
__asm
|
||||
{
|
||||
mov eax, [esp + 100h + 10h]
|
||||
|
||||
push eax
|
||||
pushad
|
||||
|
||||
push[esp + 100h + 28h]
|
||||
push eax
|
||||
call Chat::EvaluateSay
|
||||
add esp, 8h
|
||||
|
||||
mov[esp + 20h], eax
|
||||
popad
|
||||
pop eax
|
||||
|
||||
mov[esp + 100h + 10h], eax
|
||||
|
||||
jmp PlayerName::CleanStrStub
|
||||
}
|
||||
}
|
||||
|
||||
__declspec(naked) void Chat::PostSayStub()
|
||||
{
|
||||
__asm
|
||||
{
|
||||
// eax is used by the callee
|
||||
push eax
|
||||
|
||||
xor eax, eax
|
||||
mov al, Chat::SendChat
|
||||
|
||||
test al, al
|
||||
jnz return
|
||||
|
||||
// Don't send the chat
|
||||
pop eax
|
||||
retn
|
||||
|
||||
return:
|
||||
pop eax
|
||||
|
||||
// Jump to the target
|
||||
push 5DF620h
|
||||
retn
|
||||
}
|
||||
}
|
||||
|
||||
void Chat::CheckChatLineEnd(const char*& inputBuffer, char*& lineBuffer, float& len, const int chatHeight, const float chatWidth, char*& lastSpacePos, char*& lastFontIconPos, const int lastColor)
|
||||
{
|
||||
if (len > chatWidth)
|
||||
{
|
||||
if (lastSpacePos && lastSpacePos > lastFontIconPos)
|
||||
{
|
||||
inputBuffer += lastSpacePos - lineBuffer + 1;
|
||||
lineBuffer = lastSpacePos;
|
||||
}
|
||||
else if (lastFontIconPos)
|
||||
{
|
||||
inputBuffer += lastFontIconPos - lineBuffer;
|
||||
lineBuffer = lastFontIconPos;
|
||||
}
|
||||
*lineBuffer = 0;
|
||||
len = 0.0f;
|
||||
Game::cgsArray[0].teamChatMsgTimes[Game::cgsArray[0].teamChatPos % chatHeight] = Game::cgArray[0].time;
|
||||
|
||||
Game::cgsArray[0].teamChatPos++;
|
||||
lineBuffer = Game::cgsArray[0].teamChatMsgs[Game::cgsArray[0].teamChatPos % chatHeight];
|
||||
lineBuffer[0] = '^';
|
||||
lineBuffer[1] = CharForColorIndex(lastColor);
|
||||
lineBuffer += 2;
|
||||
lastSpacePos = nullptr;
|
||||
lastFontIconPos = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void Chat::CG_AddToTeamChat(const char* text)
|
||||
{
|
||||
// Text can only be 150 characters maximum. This is bigger than the teamChatMsgs buffers with 160 characters
|
||||
// Therefore it is not needed to check for buffer lengths
|
||||
|
||||
const auto chatHeight = (*cg_chatHeight)->current.integer;
|
||||
const auto chatWidth = static_cast<float>(cg_chatWidth.get<int>());
|
||||
const auto chatTime = (*cg_chatTime)->current.integer;
|
||||
if (chatHeight < 0 || static_cast<unsigned>(chatHeight) > std::extent_v<decltype(Game::cgs_t::teamChatMsgs)> || chatWidth <= 0 || chatTime <= 0)
|
||||
{
|
||||
Game::cgsArray[0].teamLastChatPos = 0;
|
||||
Game::cgsArray[0].teamChatPos = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
TextRenderer::FontIconInfo fontIconInfo{};
|
||||
auto len = 0.0f;
|
||||
auto lastColor = static_cast<int>(TEXT_COLOR_DEFAULT);
|
||||
char* lastSpace = nullptr;
|
||||
char* lastFontIcon = nullptr;
|
||||
char* p = Game::cgsArray[0].teamChatMsgs[Game::cgsArray[0].teamChatPos % chatHeight];
|
||||
p[0] = '\0';
|
||||
|
||||
while (*text)
|
||||
{
|
||||
CheckChatLineEnd(text, p, len, chatHeight, chatWidth, lastSpace, lastFontIcon, lastColor);
|
||||
|
||||
const char* fontIconEndPos = &text[1];
|
||||
if(text[0] == TextRenderer::FONT_ICON_SEPARATOR_CHARACTER && TextRenderer::IsFontIcon(fontIconEndPos, fontIconInfo))
|
||||
{
|
||||
// The game calculates width on a per character base. Since the width of a font icon is calculated based on the height of the font
|
||||
// which is roughly double as much as the average width of a character without an additional multiplier the calculated len of the font icon
|
||||
// would be less than it most likely would be rendered. Therefore apply a guessed 2.0f multiplier at this location which makes
|
||||
// the calculated width of a font icon roughly comparable to the width of an average character of the font.
|
||||
const auto normalizedFontIconWidth = TextRenderer::GetNormalizedFontIconWidth(fontIconInfo);
|
||||
const auto fontIconWidth = normalizedFontIconWidth * FONT_ICON_CHAT_WIDTH_CALCULATION_MULTIPLIER;
|
||||
len += fontIconWidth;
|
||||
|
||||
lastFontIcon = p;
|
||||
for(; text < fontIconEndPos; text++)
|
||||
{
|
||||
p[0] = text[0];
|
||||
p++;
|
||||
}
|
||||
|
||||
CheckChatLineEnd(text, p, len, chatHeight, chatWidth, lastSpace, lastFontIcon, lastColor);
|
||||
}
|
||||
else if (text[0] == '^' && text[1] != 0 && text[1] >= TextRenderer::COLOR_FIRST_CHAR && text[1] <= TextRenderer::COLOR_LAST_CHAR)
|
||||
{
|
||||
p[0] = '^';
|
||||
p[1] = text[1];
|
||||
lastColor = ColorIndexForChar(text[1]);
|
||||
p += 2;
|
||||
text += 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (text[0] == ' ')
|
||||
lastSpace = p;
|
||||
*p++ = *text++;
|
||||
len += 1.0f;
|
||||
}
|
||||
}
|
||||
|
||||
*p = 0;
|
||||
|
||||
Game::cgsArray[0].teamChatMsgTimes[Game::cgsArray[0].teamChatPos % chatHeight] = Game::cgArray[0].time;
|
||||
|
||||
Game::cgsArray[0].teamChatPos++;
|
||||
if (Game::cgsArray[0].teamChatPos - Game::cgsArray[0].teamLastChatPos > chatHeight)
|
||||
Game::cgsArray[0].teamLastChatPos = Game::cgsArray[0].teamChatPos + 1 - chatHeight;
|
||||
}
|
||||
|
||||
__declspec(naked) void Chat::CG_AddToTeamChat_Stub()
|
||||
{
|
||||
__asm
|
||||
{
|
||||
pushad
|
||||
|
||||
push ecx
|
||||
call CG_AddToTeamChat
|
||||
add esp, 4h
|
||||
|
||||
popad
|
||||
ret
|
||||
}
|
||||
}
|
||||
|
||||
Chat::Chat()
|
||||
{
|
||||
cg_chatWidth = Dvar::Register<int>("cg_chatWidth", 52, 1, INT_MAX, Game::DVAR_FLAG_SAVED, "The normalized maximum width of a chat message");
|
||||
|
||||
// Intercept chat sending
|
||||
Utils::Hook(0x4D000B, PreSayStub, HOOK_CALL).install()->quick();
|
||||
Utils::Hook(0x4D00D4, PostSayStub, HOOK_CALL).install()->quick();
|
||||
Utils::Hook(0x4D0110, PostSayStub, HOOK_CALL).install()->quick();
|
||||
|
||||
// Change logic that does word splitting with new lines for chat messages to support fonticons
|
||||
Utils::Hook(0x592E10, CG_AddToTeamChat_Stub, HOOK_JUMP).install()->quick();
|
||||
}
|
||||
}
|
27
src/Components/Modules/Chat.hpp
Normal file
27
src/Components/Modules/Chat.hpp
Normal file
@ -0,0 +1,27 @@
|
||||
#pragma once
|
||||
|
||||
namespace Components
|
||||
{
|
||||
class Chat : public Component
|
||||
{
|
||||
static constexpr auto FONT_ICON_CHAT_WIDTH_CALCULATION_MULTIPLIER = 2.0f;
|
||||
public:
|
||||
Chat();
|
||||
|
||||
private:
|
||||
static Game::dvar_t** cg_chatHeight;
|
||||
static Dvar::Var cg_chatWidth;
|
||||
static Game::dvar_t** cg_chatTime;
|
||||
|
||||
static bool SendChat;
|
||||
|
||||
static const char* EvaluateSay(char* text, Game::gentity_t* player);
|
||||
|
||||
static void PreSayStub();
|
||||
static void PostSayStub();
|
||||
|
||||
static void CheckChatLineEnd(const char*& inputBuffer, char*& lineBuffer, float& len, int chatHeight, float chatWidth, char*& lastSpacePos, char*& lastFontIconPos, int lastColor);
|
||||
static void CG_AddToTeamChat(const char* text);
|
||||
static void CG_AddToTeamChat_Stub();
|
||||
};
|
||||
}
|
@ -1,337 +0,0 @@
|
||||
#include "STDInclude.hpp"
|
||||
|
||||
namespace Components
|
||||
{
|
||||
char Colors::LastColorIndex;
|
||||
Dvar::Var Colors::NewColors;
|
||||
Dvar::Var Colors::ColorBlind;
|
||||
Game::dvar_t* Colors::ColorAllyColorBlind;
|
||||
Game::dvar_t* Colors::ColorEnemyColorBlind;
|
||||
|
||||
std::vector<DWORD> Colors::ColorTable;
|
||||
|
||||
DWORD Colors::HsvToRgb(Colors::HsvColor hsv)
|
||||
{
|
||||
DWORD rgb;
|
||||
unsigned char region, p, q, t;
|
||||
unsigned int h, s, v, remainder;
|
||||
|
||||
if (hsv.s == 0)
|
||||
{
|
||||
rgb = RGB(hsv.v, hsv.v, hsv.v);
|
||||
return rgb;
|
||||
}
|
||||
|
||||
// converting to 16 bit to prevent overflow
|
||||
h = hsv.h;
|
||||
s = hsv.s;
|
||||
v = hsv.v;
|
||||
|
||||
region = static_cast<uint8_t>(h / 43);
|
||||
remainder = (h - (region * 43)) * 6;
|
||||
|
||||
p = static_cast<uint8_t>((v * (255 - s)) >> 8);
|
||||
q = static_cast<uint8_t>((v * (255 - ((s * remainder) >> 8))) >> 8);
|
||||
t = static_cast<uint8_t>((v * (255 - ((s * (255 - remainder)) >> 8))) >> 8);
|
||||
|
||||
switch (region)
|
||||
{
|
||||
case 0:
|
||||
rgb = RGB(v, t, p);
|
||||
break;
|
||||
case 1:
|
||||
rgb = RGB(q, v, p);
|
||||
break;
|
||||
case 2:
|
||||
rgb = RGB(p, v, t);
|
||||
break;
|
||||
case 3:
|
||||
rgb = RGB(p, q, v);
|
||||
break;
|
||||
case 4:
|
||||
rgb = RGB(t, p, v);
|
||||
break;
|
||||
default:
|
||||
rgb = RGB(v, p, q);
|
||||
break;
|
||||
}
|
||||
|
||||
return rgb;
|
||||
}
|
||||
|
||||
void Colors::Strip(const char* in, char* out, int max)
|
||||
{
|
||||
if (!in || !out) return;
|
||||
|
||||
max--;
|
||||
int current = 0;
|
||||
while (*in != 0 && current < max)
|
||||
{
|
||||
char index = *(in + 1);
|
||||
if (*in == '^' && (Colors::ColorIndex(index) != 7 || index == '7'))
|
||||
{
|
||||
++in;
|
||||
}
|
||||
else
|
||||
{
|
||||
*out = *in;
|
||||
++out;
|
||||
++current;
|
||||
}
|
||||
|
||||
++in;
|
||||
}
|
||||
*out = '\0';
|
||||
}
|
||||
|
||||
std::string Colors::Strip(const std::string& in)
|
||||
{
|
||||
char buffer[1000] = { 0 }; // Should be more than enough
|
||||
Colors::Strip(in.data(), buffer, sizeof(buffer));
|
||||
return std::string(buffer);
|
||||
}
|
||||
|
||||
void Colors::UserInfoCopy(char* buffer, const char* name, size_t size)
|
||||
{
|
||||
Utils::Memory::Allocator allocator;
|
||||
|
||||
if (!Dvar::Var("sv_allowColoredNames").get<bool>())
|
||||
{
|
||||
Colors::Strip(name, buffer, size);
|
||||
}
|
||||
else
|
||||
{
|
||||
strncpy_s(buffer, size, name, _TRUNCATE);
|
||||
}
|
||||
}
|
||||
|
||||
__declspec(naked) void Colors::ClientUserinfoChanged()
|
||||
{
|
||||
__asm
|
||||
{
|
||||
mov eax, [esp + 4h] // length
|
||||
//sub eax, 1
|
||||
push eax
|
||||
|
||||
push ecx // name
|
||||
push edx // buffer
|
||||
|
||||
call Colors::UserInfoCopy
|
||||
|
||||
add esp, 0Ch
|
||||
retn
|
||||
}
|
||||
}
|
||||
|
||||
char* Colors::GetClientName(int localClientNum, int index, char *buf, size_t size)
|
||||
{
|
||||
Game::CL_GetClientName(localClientNum, index, buf, size);
|
||||
|
||||
// Append clantag to username & remove the colors
|
||||
strncpy_s(buf, size, Colors::Strip(ClanTags::GetUserClantag(index, buf)).data(), size);
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
void Colors::PatchColorLimit(char limit)
|
||||
{
|
||||
Utils::Hook::Set<char>(0x535629, limit); // DrawText2d
|
||||
Utils::Hook::Set<char>(0x4C1BE4, limit); // No idea :P
|
||||
Utils::Hook::Set<char>(0x4863DD, limit); // No idea :P
|
||||
Utils::Hook::Set<char>(0x486429, limit); // No idea :P
|
||||
Utils::Hook::Set<char>(0x49A5A8, limit); // No idea :P
|
||||
Utils::Hook::Set<char>(0x505721, limit); // R_TextWidth
|
||||
Utils::Hook::Set<char>(0x505801, limit); // No idea :P
|
||||
Utils::Hook::Set<char>(0x50597F, limit); // No idea :P
|
||||
Utils::Hook::Set<char>(0x5815DB, limit); // No idea :P
|
||||
Utils::Hook::Set<char>(0x592ED0, limit); // No idea :P
|
||||
Utils::Hook::Set<char>(0x5A2E2E, limit); // No idea :P
|
||||
|
||||
Utils::Hook::Set<char>(0x5A2733, limit - '0'); // No idea :P
|
||||
|
||||
LastColorIndex = limit;
|
||||
}
|
||||
|
||||
char Colors::Add(uint8_t r, uint8_t g, uint8_t b)
|
||||
{
|
||||
char index = '0' + static_cast<char>(Colors::ColorTable.size());
|
||||
Colors::ColorTable.push_back(RGB(r, g, b));
|
||||
Colors::PatchColorLimit(index);
|
||||
return index;
|
||||
}
|
||||
|
||||
unsigned int Colors::ColorIndex(char index)
|
||||
{
|
||||
char result = index - '0';
|
||||
if (static_cast<unsigned int>(result) >= Colors::ColorTable.size() || result < 0) result = 7;
|
||||
return result;
|
||||
}
|
||||
|
||||
void Colors::LookupColor(DWORD* color, char index)
|
||||
{
|
||||
*color = RGB(255, 255, 255);
|
||||
|
||||
if (index == '8') // Color 8
|
||||
{
|
||||
*color = *reinterpret_cast<DWORD*>(0x66E5F70);
|
||||
}
|
||||
else if (index == '9') // Color 9
|
||||
{
|
||||
*color = *reinterpret_cast<DWORD*>(0x66E5F74);
|
||||
}
|
||||
else if (index == ':')
|
||||
{
|
||||
*color = Colors::HsvToRgb({ static_cast<uint8_t>((Game::Sys_Milliseconds() / 200) % 256), 255,255 });
|
||||
}
|
||||
else if (index == ';')
|
||||
{
|
||||
float fltColor[4];
|
||||
Game::Dvar_GetUnpackedColorByName("sv_customTextColor", fltColor);
|
||||
*color = RGB(fltColor[0] * 255, fltColor[1] * 255, fltColor[2] * 255);
|
||||
}
|
||||
else
|
||||
{
|
||||
int clrIndex = Colors::ColorIndex(index);
|
||||
|
||||
// Use native colors
|
||||
if (clrIndex <= 7 && !Colors::NewColors.get<bool>())
|
||||
{
|
||||
*color = reinterpret_cast<DWORD*>(0x78DC70)[index - 48];
|
||||
}
|
||||
else
|
||||
{
|
||||
*color = Colors::ColorTable[clrIndex];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
char* Colors::CleanStrStub(char* string)
|
||||
{
|
||||
Colors::Strip(string, string, strlen(string) + 1);
|
||||
return string;
|
||||
}
|
||||
|
||||
__declspec(naked) void Colors::LookupColorStub()
|
||||
{
|
||||
__asm
|
||||
{
|
||||
pushad
|
||||
push [esp + 24h] // Index
|
||||
push esi // Color ref
|
||||
call Colors::LookupColor
|
||||
add esp, 8h
|
||||
popad
|
||||
retn
|
||||
}
|
||||
}
|
||||
|
||||
// Patches team overhead normally
|
||||
bool Colors::Dvar_GetUnpackedColorByName(const char* name, float* expandedColor)
|
||||
{
|
||||
if (Colors::ColorBlind.get<bool>())
|
||||
{
|
||||
const auto str = std::string(name);
|
||||
if (str == "g_TeamColor_EnemyTeam")
|
||||
{
|
||||
// Dvar_GetUnpackedColor
|
||||
auto* colorblindEnemy = Colors::ColorEnemyColorBlind->current.color;
|
||||
expandedColor[0] = static_cast<float>(colorblindEnemy[0]) / 255.0f;
|
||||
expandedColor[1] = static_cast<float>(colorblindEnemy[1]) / 255.0f;
|
||||
expandedColor[2] = static_cast<float>(colorblindEnemy[2]) / 255.0f;
|
||||
expandedColor[3] = static_cast<float>(colorblindEnemy[3]) / 255.0f;
|
||||
return false;
|
||||
}
|
||||
else if (str == "g_TeamColor_MyTeam")
|
||||
{
|
||||
// Dvar_GetUnpackedColor
|
||||
auto* colorblindAlly = Colors::ColorAllyColorBlind->current.color;
|
||||
expandedColor[0] = static_cast<float>(colorblindAlly[0]) / 255.0f;
|
||||
expandedColor[1] = static_cast<float>(colorblindAlly[1]) / 255.0f;
|
||||
expandedColor[2] = static_cast<float>(colorblindAlly[2]) / 255.0f;
|
||||
expandedColor[3] = static_cast<float>(colorblindAlly[3]) / 255.0f;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
__declspec(naked) void Colors::GetUnpackedColorByNameStub()
|
||||
{
|
||||
__asm
|
||||
{
|
||||
push [esp + 8h]
|
||||
push [esp + 8h]
|
||||
call Colors::Dvar_GetUnpackedColorByName
|
||||
add esp, 8h
|
||||
|
||||
test al, al
|
||||
jnz continue
|
||||
|
||||
retn
|
||||
|
||||
continue:
|
||||
push edi
|
||||
mov edi, [esp + 8h]
|
||||
push 406535h
|
||||
retn
|
||||
}
|
||||
}
|
||||
|
||||
Colors::Colors()
|
||||
{
|
||||
// Add a colorblind mode for team colors
|
||||
Colors::ColorBlind = Dvar::Register<bool>("r_colorBlindTeams", false, Game::dvar_flag::DVAR_FLAG_SAVED, "Use color-blindness-friendly colors for ingame team names");
|
||||
// A dark red
|
||||
Colors::ColorEnemyColorBlind = Game::Dvar_RegisterColor("g_ColorBlind_EnemyTeam", 0.659f, 0.088f, 0.145f, 1, Game::dvar_flag::DVAR_FLAG_SAVED, "Enemy team color for colorblind mode");
|
||||
// A bright yellow
|
||||
Colors::ColorAllyColorBlind = Game::Dvar_RegisterColor("g_ColorBlind_MyTeam", 1, 0.859f, 0.125f, 1, Game::dvar_flag::DVAR_FLAG_SAVED, "Ally team color for colorblind mode");
|
||||
Utils::Hook(0x406530, Colors::GetUnpackedColorByNameStub, HOOK_JUMP).install()->quick();
|
||||
|
||||
// Disable SV_UpdateUserinfo_f, to block changing the name ingame
|
||||
Utils::Hook::Set<BYTE>(0x6258D0, 0xC3);
|
||||
|
||||
// Allow colored names ingame
|
||||
Utils::Hook(0x5D8B40, Colors::ClientUserinfoChanged, HOOK_JUMP).install()->quick();
|
||||
|
||||
// Though, don't apply that to overhead names.
|
||||
Utils::Hook(0x581932, Colors::GetClientName, HOOK_CALL).install()->quick();
|
||||
|
||||
// Patch RB_LookupColor
|
||||
Utils::Hook(0x534CD0, Colors::LookupColorStub, HOOK_JUMP).install()->quick();
|
||||
|
||||
// Patch ColorIndex
|
||||
Utils::Hook(0x417770, Colors::ColorIndex, HOOK_JUMP).install()->quick();
|
||||
|
||||
// Patch I_CleanStr
|
||||
Utils::Hook(0x4AD470, Colors::CleanStrStub, HOOK_JUMP).install()->quick();
|
||||
|
||||
// Register dvar
|
||||
Colors::NewColors = Dvar::Register<bool>("cg_newColors", true, Game::dvar_flag::DVAR_FLAG_SAVED, "Use Warfare 2 color code style.");
|
||||
Game::Dvar_RegisterColor("sv_customTextColor", 1, 0.7f, 0, 1, Game::dvar_flag::DVAR_FLAG_REPLICATED, "Color for the extended color code.");
|
||||
Dvar::Register<bool>("sv_allowColoredNames", true, Game::dvar_flag::DVAR_FLAG_NONE, "Allow colored names on the server");
|
||||
|
||||
// Add our colors
|
||||
Colors::Add(0, 0, 0); // 0 - Black
|
||||
Colors::Add(255, 49, 49); // 1 - Red
|
||||
Colors::Add(134, 192, 0); // 2 - Green
|
||||
Colors::Add(255, 173, 34); // 3 - Yellow
|
||||
Colors::Add(0, 135, 193); // 4 - Blue
|
||||
Colors::Add(32, 197, 255); // 5 - Light Blue
|
||||
Colors::Add(151, 80, 221); // 6 - Pink
|
||||
|
||||
Colors::Add(255, 255, 255); // 7 - White
|
||||
|
||||
Colors::Add(0, 0, 0); // 8 - Team color (axis?)
|
||||
Colors::Add(0, 0, 0); // 9 - Team color (allies?)
|
||||
|
||||
// Custom colors
|
||||
Colors::Add(0, 0, 0); // 10 - Rainbow (:)
|
||||
Colors::Add(0, 0, 0); // 11 - Server color (;) - using that color in infostrings (e.g. your name) fails, ';' is an illegal character!
|
||||
}
|
||||
|
||||
Colors::~Colors()
|
||||
{
|
||||
Colors::ColorTable.clear();
|
||||
}
|
||||
}
|
@ -1,47 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
namespace Components
|
||||
{
|
||||
class Colors : public Component
|
||||
{
|
||||
public:
|
||||
static char LastColorIndex;
|
||||
|
||||
Colors();
|
||||
~Colors();
|
||||
|
||||
static void Strip(const char* in, char* out, int max);
|
||||
static std::string Strip(const std::string& in);
|
||||
|
||||
static char Add(uint8_t r, uint8_t g, uint8_t b);
|
||||
|
||||
private:
|
||||
struct HsvColor
|
||||
{
|
||||
unsigned char h;
|
||||
unsigned char s;
|
||||
unsigned char v;
|
||||
};
|
||||
|
||||
static Dvar::Var NewColors;
|
||||
static Dvar::Var ColorBlind;
|
||||
static Game::dvar_t* ColorAllyColorBlind;
|
||||
static Game::dvar_t* ColorEnemyColorBlind;
|
||||
|
||||
static DWORD HsvToRgb(HsvColor hsv);
|
||||
|
||||
static void UserInfoCopy(char* buffer, const char* name, size_t size);
|
||||
|
||||
static void ClientUserinfoChanged();
|
||||
static char* GetClientName(int localClientNum, int index, char *buf, size_t size);
|
||||
static void PatchColorLimit(char limit);
|
||||
|
||||
static unsigned int ColorIndex(char index);
|
||||
static void LookupColor(DWORD* color, char index);
|
||||
static void LookupColorStub();
|
||||
static char* CleanStrStub(char* string);
|
||||
static bool Dvar_GetUnpackedColorByName(const char* name, float* expandedColor);
|
||||
static void GetUnpackedColorByNameStub();
|
||||
static std::vector<DWORD> ColorTable;
|
||||
};
|
||||
}
|
@ -45,7 +45,7 @@ namespace Components
|
||||
void Console::RefreshStatus()
|
||||
{
|
||||
std::string mapname = Dvar::Var("mapname").get<const char*>();
|
||||
std::string hostname = Colors::Strip(Dvar::Var("sv_hostname").get<const char*>());
|
||||
std::string hostname = TextRenderer::StripColors(Dvar::Var("sv_hostname").get<const char*>());
|
||||
|
||||
if (Console::HasConsole)
|
||||
{
|
||||
|
@ -4,8 +4,6 @@ namespace Components
|
||||
{
|
||||
SteamID Dedicated::PlayerGuids[18][2];
|
||||
|
||||
bool Dedicated::SendChat;
|
||||
|
||||
bool Dedicated::IsEnabled()
|
||||
{
|
||||
static std::optional<bool> flag;
|
||||
@ -76,99 +74,6 @@ namespace Components
|
||||
}
|
||||
}
|
||||
|
||||
void Dedicated::StripMaterialTextIcons(char* text)
|
||||
{
|
||||
char* currentChar = text;
|
||||
bool isEscaped = false;
|
||||
while (*currentChar)
|
||||
{
|
||||
if (*currentChar == '^')
|
||||
{
|
||||
isEscaped = true;
|
||||
}
|
||||
else if(isEscaped == true && (*currentChar == '\x01' || *currentChar == '\x02'))
|
||||
{
|
||||
*currentChar = ' ';
|
||||
}
|
||||
else
|
||||
{
|
||||
isEscaped = false;
|
||||
}
|
||||
|
||||
currentChar++;
|
||||
}
|
||||
}
|
||||
|
||||
const char* Dedicated::EvaluateSay(char* text, Game::gentity_t* player)
|
||||
{
|
||||
Dedicated::SendChat = true;
|
||||
|
||||
if (text[1] == '/')
|
||||
{
|
||||
Dedicated::SendChat = false;
|
||||
text[1] = text[0];
|
||||
++text;
|
||||
}
|
||||
|
||||
StripMaterialTextIcons(text);
|
||||
|
||||
Game::Scr_AddEntity(player);
|
||||
Game::Scr_AddString(text + 1);
|
||||
Game::Scr_NotifyLevel(Game::SL_GetString("say", 0), 2);
|
||||
|
||||
return text;
|
||||
}
|
||||
|
||||
__declspec(naked) void Dedicated::PreSayStub()
|
||||
{
|
||||
__asm
|
||||
{
|
||||
mov eax, [esp + 100h + 10h]
|
||||
|
||||
push eax
|
||||
pushad
|
||||
|
||||
push [esp + 100h + 28h]
|
||||
push eax
|
||||
call Dedicated::EvaluateSay
|
||||
add esp, 8h
|
||||
|
||||
mov [esp + 20h], eax
|
||||
popad
|
||||
pop eax
|
||||
|
||||
mov [esp + 100h + 10h], eax
|
||||
|
||||
jmp Colors::CleanStrStub
|
||||
}
|
||||
}
|
||||
|
||||
__declspec(naked) void Dedicated::PostSayStub()
|
||||
{
|
||||
__asm
|
||||
{
|
||||
// eax is used by the callee
|
||||
push eax
|
||||
|
||||
xor eax, eax
|
||||
mov al, Dedicated::SendChat
|
||||
|
||||
test al, al
|
||||
jnz return
|
||||
|
||||
// Don't send the chat
|
||||
pop eax
|
||||
retn
|
||||
|
||||
return:
|
||||
pop eax
|
||||
|
||||
// Jump to the target
|
||||
push 5DF620h
|
||||
retn
|
||||
}
|
||||
}
|
||||
|
||||
void Dedicated::TransmitGuids()
|
||||
{
|
||||
std::string list = Utils::String::VA("%c", 20);
|
||||
@ -329,11 +234,6 @@ namespace Components
|
||||
Dvar::Register<bool>("sv_dontrotate", false, Game::dvar_flag::DVAR_FLAG_CHEAT, "");
|
||||
Dvar::Register<bool>("com_logFilter", true, Game::dvar_flag::DVAR_FLAG_LATCHED, "Removes ~95% of unneeded lines from the log");
|
||||
|
||||
// Intercept chat sending
|
||||
Utils::Hook(0x4D000B, Dedicated::PreSayStub, HOOK_CALL).install()->quick();
|
||||
Utils::Hook(0x4D00D4, Dedicated::PostSayStub, HOOK_CALL).install()->quick();
|
||||
Utils::Hook(0x4D0110, Dedicated::PostSayStub, HOOK_CALL).install()->quick();
|
||||
|
||||
if (Dedicated::IsEnabled() || ZoneBuilder::IsEnabled())
|
||||
{
|
||||
// Make sure all callbacks are handled
|
||||
|
@ -14,22 +14,13 @@ namespace Components
|
||||
|
||||
static void Heartbeat();
|
||||
|
||||
static void StripMaterialTextIcons(char* text);
|
||||
|
||||
private:
|
||||
static bool SendChat;
|
||||
|
||||
static void MapRotate();
|
||||
static void InitDedicatedServer();
|
||||
|
||||
static void PostInitialization();
|
||||
static void PostInitializationStub();
|
||||
|
||||
static const char* EvaluateSay(char* text, Game::gentity_t* player);
|
||||
|
||||
static void PreSayStub();
|
||||
static void PostSayStub();
|
||||
|
||||
static void FrameStub();
|
||||
|
||||
static void TransmitGuids();
|
||||
|
@ -203,7 +203,7 @@ namespace Components
|
||||
// Don't perform any checks if name didn't change
|
||||
if (name == lastValidName) return;
|
||||
|
||||
std::string saneName = Colors::Strip(Utils::String::Trim(name));
|
||||
std::string saneName = TextRenderer::StripAllTextIcons(TextRenderer::StripColors(Utils::String::Trim(name)));
|
||||
if (saneName.size() < 3 || (saneName[0] == '[' && saneName[1] == '{'))
|
||||
{
|
||||
Logger::Print("Username '%s' is invalid. It must at least be 3 characters long and not appear empty!\n", name.data());
|
||||
|
@ -71,7 +71,7 @@ namespace Components
|
||||
|
||||
entry->name = Steam::Proxy::SteamFriends->GetFriendPersonaName(user);
|
||||
entry->online = Steam::Proxy::SteamFriends->GetFriendPersonaState(user) != 0;
|
||||
entry->cleanName = Utils::String::ToLower(Colors::Strip(entry->name));
|
||||
entry->cleanName = Utils::String::ToLower(TextRenderer::StripColors(entry->name));
|
||||
|
||||
std::string guid = Friends::GetPresence(user, "iw4x_guid");
|
||||
std::string name = Friends::GetPresence(user, "iw4x_name");
|
||||
|
@ -2,7 +2,6 @@
|
||||
|
||||
namespace Components
|
||||
{
|
||||
int Materials::ImageNameLength;
|
||||
Utils::Hook Materials::ImageVersionCheckHook;
|
||||
|
||||
std::vector<Game::GfxImage*> Materials::ImageTable;
|
||||
@ -151,66 +150,6 @@ namespace Components
|
||||
}
|
||||
}
|
||||
|
||||
Game::Material* Materials::ResolveMaterial(const char* stringPtr)
|
||||
{
|
||||
const char* imagePtr = stringPtr + 4;
|
||||
unsigned int length = static_cast<unsigned int>(stringPtr[3] & 0xFF);
|
||||
|
||||
if (strlen(imagePtr) >= length)
|
||||
{
|
||||
Materials::ImageNameLength = 4 + length;
|
||||
std::string image(imagePtr, length);
|
||||
|
||||
auto* material = Game::DB_FindXAssetHeader(Game::XAssetType::ASSET_TYPE_MATERIAL, image.data()).material;
|
||||
|
||||
if(material == nullptr || material->techniqueSet == nullptr || material->techniqueSet->name == nullptr || strcmp(material->techniqueSet->name, "2d") != 0)
|
||||
return Game::DB_FindXAssetHeader(Game::XAssetType::ASSET_TYPE_MATERIAL, "default").material;
|
||||
|
||||
return material;
|
||||
}
|
||||
|
||||
Materials::ImageNameLength = 4;
|
||||
return Game::DB_FindXAssetHeader(Game::XAssetType::ASSET_TYPE_MATERIAL, "default").material;
|
||||
}
|
||||
|
||||
__declspec(naked) void Materials::PostDrawMaterialStub()
|
||||
{
|
||||
__asm
|
||||
{
|
||||
mov eax, Materials::ImageNameLength
|
||||
add [esp + 30h], eax
|
||||
|
||||
mov eax, 5358FFh
|
||||
jmp eax
|
||||
}
|
||||
}
|
||||
|
||||
__declspec(naked) void Materials::DrawMaterialStub()
|
||||
{
|
||||
__asm
|
||||
{
|
||||
push eax
|
||||
pushad
|
||||
|
||||
push ecx
|
||||
call Materials::ResolveMaterial
|
||||
add esp, 4h
|
||||
|
||||
mov [esp + 20h], eax
|
||||
|
||||
// Make all material text icons have white tint
|
||||
mov eax,[esp + 0x50]
|
||||
or eax,0x00FFFFFF
|
||||
mov [esp + 0x50],eax
|
||||
|
||||
popad
|
||||
pop eax
|
||||
|
||||
push 5310F0h
|
||||
retn
|
||||
}
|
||||
}
|
||||
|
||||
int Materials::WriteDeathMessageIcon(char* string, int offset, Game::Material* material)
|
||||
{
|
||||
if (!material)
|
||||
@ -291,77 +230,11 @@ namespace Components
|
||||
|
||||
#endif
|
||||
|
||||
int Materials::R_TextWidth_Hk(const char* text, int maxChars, Game::Font_s* font)
|
||||
{
|
||||
auto lineWidth = 0;
|
||||
auto maxWidth = 0;
|
||||
|
||||
if (maxChars <= 0)
|
||||
maxChars = 0x7FFFFFFF;
|
||||
|
||||
if (text == nullptr)
|
||||
return 0;
|
||||
|
||||
auto count = 0;
|
||||
while (text && *text && count < maxChars)
|
||||
{
|
||||
const auto letter = Game::SEH_ReadCharFromString(&text, nullptr);
|
||||
if (letter == '\r' || letter == '\n')
|
||||
{
|
||||
lineWidth = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (letter == '^' && text)
|
||||
{
|
||||
if (*text >= '0' && *text <= Colors::LastColorIndex)
|
||||
{
|
||||
text++;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (*text >= '\x01' && *text <= '\x02' && text[1] != '\0' && text[2] != '\0' && text[3] != '\0')
|
||||
{
|
||||
const auto width = text[1];
|
||||
const auto materialNameLength = text[3];
|
||||
|
||||
// This is how the game calculates width and height. Probably some 1 byte floating point number.
|
||||
auto v9 = font->pixelHeight * (width - 16) + 16;
|
||||
auto w = ((((v9 >> 24) & 0x1F) + v9) >> 5);
|
||||
|
||||
lineWidth += w;
|
||||
|
||||
text += 4;
|
||||
for (auto currentLength = 0; currentLength < materialNameLength && *text; currentLength++)
|
||||
text++;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
lineWidth += R_GetCharacterGlyph(font, letter)->dx;
|
||||
if (lineWidth > maxWidth)
|
||||
maxWidth = lineWidth;
|
||||
count++;
|
||||
}
|
||||
}
|
||||
|
||||
return maxWidth;
|
||||
}
|
||||
|
||||
Materials::Materials()
|
||||
{
|
||||
Materials::ImageNameLength = 7;
|
||||
|
||||
// Allow codo images
|
||||
Materials::ImageVersionCheckHook.initialize(0x53A456, Materials::ImageVersionCheck, HOOK_CALL)->install();
|
||||
|
||||
// Fix material pointer exploit
|
||||
// Also make all material text icons have white tint
|
||||
Utils::Hook(0x534E0C, Materials::DrawMaterialStub, HOOK_CALL).install()->quick();
|
||||
|
||||
// Increment string pointer accordingly
|
||||
Utils::Hook(0x5358FA, Materials::PostDrawMaterialStub, HOOK_JUMP).install()->quick();
|
||||
|
||||
// Adapt death message to IW5 material format
|
||||
Utils::Hook(0x5A30D9, Materials::DeathMessageStub, HOOK_JUMP).install()->quick();
|
||||
|
||||
@ -371,9 +244,6 @@ namespace Components
|
||||
// Debug material comparison
|
||||
Utils::Hook::Set<void*>(0x523894, Materials::MaterialComparePrint);
|
||||
|
||||
// Consider material text icons when calculating text width
|
||||
Utils::Hook(0x5056C0, Materials::R_TextWidth_Hk, HOOK_JUMP).install()->quick();
|
||||
|
||||
#ifdef DEBUG
|
||||
if (Flags::HasFlag("dump"))
|
||||
{
|
||||
|
@ -21,20 +21,13 @@ namespace Components
|
||||
private:
|
||||
static std::vector<Game::GfxImage*> ImageTable;
|
||||
static std::vector<Game::Material*> MaterialTable;
|
||||
static int ImageNameLength;
|
||||
|
||||
static Utils::Hook ImageVersionCheckHook;
|
||||
static void ImageVersionCheck();
|
||||
|
||||
static Game::Material* ResolveMaterial(const char* stringPtr);
|
||||
static void DrawMaterialStub();
|
||||
static void PostDrawMaterialStub();
|
||||
|
||||
static int WriteDeathMessageIcon(char* string, int offset, Game::Material* material);
|
||||
static void DeathMessageStub();
|
||||
|
||||
static int R_TextWidth_Hk(const char* text, int maxChars, Game::Font_s* font);
|
||||
|
||||
#ifdef DEBUG
|
||||
static void DumpImageCfg(int, const char*, const char* material);
|
||||
static void DumpImageCfgPath(int, const char*, const char* material);
|
||||
|
@ -2,37 +2,77 @@
|
||||
|
||||
namespace Components
|
||||
{
|
||||
std::string PlayerName::PlayerNames[18];
|
||||
Dvar::Var PlayerName::sv_allowColoredNames;
|
||||
|
||||
int PlayerName::GetClientName(int /*localClientNum*/, int index, char *buf, int size)
|
||||
void PlayerName::UserInfoCopy(char* buffer, const char* name, const size_t size)
|
||||
{
|
||||
if (!sv_allowColoredNames.get<bool>())
|
||||
{
|
||||
char nameBuffer[64] = { 0 };
|
||||
TextRenderer::StripColors(name, nameBuffer, sizeof(nameBuffer));
|
||||
TextRenderer::StripAllTextIcons(nameBuffer, buffer, size);
|
||||
}
|
||||
else
|
||||
{
|
||||
TextRenderer::StripAllTextIcons(name, buffer, size);
|
||||
}
|
||||
|
||||
std::string readablePlayerName(buffer);
|
||||
readablePlayerName = Utils::String::Trim(readablePlayerName);
|
||||
|
||||
if (readablePlayerName.size() < 3)
|
||||
{
|
||||
strncpy(buffer, "Unknown Soldier", size);
|
||||
}
|
||||
}
|
||||
|
||||
__declspec(naked) void PlayerName::ClientUserinfoChanged()
|
||||
{
|
||||
__asm
|
||||
{
|
||||
mov eax, [esp + 4h] // length
|
||||
//sub eax, 1
|
||||
push eax
|
||||
|
||||
push ecx // name
|
||||
push edx // buffer
|
||||
|
||||
call UserInfoCopy
|
||||
|
||||
add esp, 0Ch
|
||||
retn
|
||||
}
|
||||
}
|
||||
|
||||
char* PlayerName::GetClientName(int localClientNum, int index, char* buf, size_t size)
|
||||
{
|
||||
Game::CL_GetClientName(localClientNum, index, buf, size);
|
||||
|
||||
// Append clantag to username & remove the colors
|
||||
strncpy_s(buf, size, TextRenderer::StripColors(ClanTags::GetUserClantag(index, buf)).data(), size);
|
||||
|
||||
return buf;
|
||||
}
|
||||
char* PlayerName::CleanStrStub(char* string)
|
||||
{
|
||||
if (index < 0 || index >= 18) return 0;
|
||||
return strncpy_s(buf, size, PlayerName::PlayerNames[index].data(), PlayerName::PlayerNames[index].size()) == 0;
|
||||
TextRenderer::StripColors(string, string, strlen(string) + 1);
|
||||
return string;
|
||||
}
|
||||
|
||||
PlayerName::PlayerName()
|
||||
{
|
||||
#if(0) // Disabled for now
|
||||
{
|
||||
for (int i = 0; i < ARRAYSIZE(PlayerName::PlayerNames); ++i)
|
||||
{
|
||||
PlayerName::PlayerNames[i] = "mumu";
|
||||
}
|
||||
sv_allowColoredNames = Dvar::Register<bool>("sv_allowColoredNames", true, Game::dvar_flag::DVAR_FLAG_NONE, "Allow colored names on the server");
|
||||
|
||||
Utils::Hook(Game::CL_GetClientName, PlayerName::GetClientName, HOOK_JUMP).install()->quick();
|
||||
}
|
||||
#endif
|
||||
// Disable SV_UpdateUserinfo_f, to block changing the name ingame
|
||||
Utils::Hook::Set<BYTE>(0x6258D0, 0xC3);
|
||||
|
||||
//const char* clanname = "ZOB";
|
||||
//Utils::Hook::Set<const char*>(0x497656, clanname);
|
||||
//Utils::Hook::Set<const char*>(0x497679, clanname);
|
||||
}
|
||||
// Allow colored names ingame
|
||||
Utils::Hook(0x5D8B40, ClientUserinfoChanged, HOOK_JUMP).install()->quick();
|
||||
|
||||
PlayerName::~PlayerName()
|
||||
{
|
||||
for (int i = 0; i < ARRAYSIZE(PlayerName::PlayerNames); ++i)
|
||||
{
|
||||
PlayerName::PlayerNames[i].clear();
|
||||
}
|
||||
// Though, don't apply that to overhead names.
|
||||
Utils::Hook(0x581932, GetClientName, HOOK_CALL).install()->quick();
|
||||
|
||||
// Patch I_CleanStr
|
||||
Utils::Hook(0x4AD470, CleanStrStub, HOOK_JUMP).install()->quick();
|
||||
}
|
||||
}
|
||||
|
@ -6,11 +6,14 @@ namespace Components
|
||||
{
|
||||
public:
|
||||
PlayerName();
|
||||
~PlayerName();
|
||||
|
||||
static void UserInfoCopy(char* buffer, const char* name, size_t size);
|
||||
|
||||
private:
|
||||
static std::string PlayerNames[18];
|
||||
static Dvar::Var sv_allowColoredNames;
|
||||
|
||||
static int GetClientName(int localClientNum, int index, char *buf, int size);
|
||||
static char* CleanStrStub(char* string);
|
||||
static void ClientUserinfoChanged();
|
||||
static char* GetClientName(int localClientNum, int index, char* buf, size_t size);
|
||||
};
|
||||
}
|
||||
|
@ -407,6 +407,32 @@ namespace Components
|
||||
// Passthrough to the game's own IsDynClassname
|
||||
return Utils::Hook::Call<BOOL(char*)>(0x444810)(a1);
|
||||
}
|
||||
|
||||
void QuickPatch::CL_KeyEvent_OnEscape()
|
||||
{
|
||||
if (Game::Con_CancelAutoComplete())
|
||||
return;
|
||||
|
||||
if (TextRenderer::HandleFontIconAutocompleteKey(0, TextRenderer::FONT_ICON_ACI_CONSOLE, Game::K_ESCAPE))
|
||||
return;
|
||||
|
||||
// Close console
|
||||
Game::Key_RemoveCatcher(0, ~Game::KEYCATCH_CONSOLE);
|
||||
}
|
||||
|
||||
__declspec(naked) void QuickPatch::CL_KeyEvent_ConsoleEscape_Stub()
|
||||
{
|
||||
__asm
|
||||
{
|
||||
pushad
|
||||
call CL_KeyEvent_OnEscape
|
||||
popad
|
||||
|
||||
// Exit CL_KeyEvent function
|
||||
mov ebx, 0x4F66F2
|
||||
jmp ebx
|
||||
}
|
||||
}
|
||||
|
||||
QuickPatch::QuickPatch()
|
||||
{
|
||||
@ -428,6 +454,9 @@ namespace Components
|
||||
// Filtering any mapents that is intended for Spec:Ops gamemode (CODO) and prevent them from spawning
|
||||
Utils::Hook(0x5FBD6E, QuickPatch::IsDynClassnameStub, HOOK_CALL).install()->quick();
|
||||
|
||||
// Hook escape handling on open console to change behaviour to close the console instead of only canceling autocomplete
|
||||
Utils::Hook(0x4F66A3, CL_KeyEvent_ConsoleEscape_Stub, HOOK_JUMP).install()->quick();
|
||||
|
||||
// bounce dvar
|
||||
sv_enableBounces = Game::Dvar_RegisterBool("sv_enableBounces", false, Game::DVAR_FLAG_REPLICATED, "Enables bouncing on the server");
|
||||
Utils::Hook(0x4B1B2D, QuickPatch::BounceStub, HOOK_JUMP).install()->quick();
|
||||
|
@ -48,5 +48,8 @@ namespace Components
|
||||
static Game::dvar_t* g_playerEjection;
|
||||
static void PlayerEjectionStub();
|
||||
static BOOL IsDynClassnameStub(char* a1);
|
||||
|
||||
static void CL_KeyEvent_OnEscape();
|
||||
static void CL_KeyEvent_ConsoleEscape_Stub();
|
||||
};
|
||||
}
|
||||
|
@ -71,10 +71,10 @@ namespace Components
|
||||
}
|
||||
}
|
||||
|
||||
void ServerInfo::DrawScoreboardInfo(void* a1)
|
||||
void ServerInfo::DrawScoreboardInfo(int localClientNum)
|
||||
{
|
||||
Game::Font_s* font = Game::R_RegisterFont("fonts/bigfont", 0);
|
||||
void* cxt = Game::UI_GetContext(a1);
|
||||
void* cxt = Game::ScrPlace_GetActivePlacement(localClientNum);
|
||||
|
||||
std::string addressText = Network::Address(*Game::connectedHost).getString();
|
||||
if (addressText == "0.0.0.0:0" || addressText == "loopback") addressText = "Listen Server";
|
||||
|
@ -36,7 +36,7 @@ namespace Components
|
||||
static const char* GetPlayerText(unsigned int index, int column);
|
||||
static void SelectPlayer(unsigned int index);
|
||||
|
||||
static void DrawScoreboardInfo(void* a1);
|
||||
static void DrawScoreboardInfo(int localClientNum);
|
||||
static void DrawScoreboardStub();
|
||||
};
|
||||
}
|
||||
|
@ -469,10 +469,10 @@ namespace Components
|
||||
server.ping = (Game::Sys_Milliseconds() - i->sendTime);
|
||||
server.addr = address;
|
||||
|
||||
Dedicated::StripMaterialTextIcons(server.hostname.data());
|
||||
Dedicated::StripMaterialTextIcons(server.mapname.data());
|
||||
Dedicated::StripMaterialTextIcons(server.gametype.data());
|
||||
Dedicated::StripMaterialTextIcons(server.mod.data());
|
||||
server.hostname = TextRenderer::StripMaterialTextIcons(server.hostname);
|
||||
server.mapname = TextRenderer::StripMaterialTextIcons(server.mapname);
|
||||
server.gametype = TextRenderer::StripMaterialTextIcons(server.gametype);
|
||||
server.mod = TextRenderer::StripMaterialTextIcons(server.mod);
|
||||
|
||||
// Remove server from queue
|
||||
i = ServerList::RefreshContainer.servers.erase(i);
|
||||
@ -592,8 +592,8 @@ namespace Components
|
||||
return info1->clients < info2->clients;
|
||||
}
|
||||
|
||||
std::string text1 = Utils::String::ToLower(Colors::Strip(ServerList::GetServerInfoText(info1, ServerList::SortKey, true)));
|
||||
std::string text2 = Utils::String::ToLower(Colors::Strip(ServerList::GetServerInfoText(info2, ServerList::SortKey, true)));
|
||||
std::string text1 = Utils::String::ToLower(TextRenderer::StripColors(ServerList::GetServerInfoText(info1, ServerList::SortKey, true)));
|
||||
std::string text2 = Utils::String::ToLower(TextRenderer::StripColors(ServerList::GetServerInfoText(info2, ServerList::SortKey, true)));
|
||||
|
||||
// ASCII-based comparison
|
||||
return text1.compare(text2) < 0;
|
||||
|
1645
src/Components/Modules/TextRenderer.cpp
Normal file
1645
src/Components/Modules/TextRenderer.cpp
Normal file
File diff suppressed because it is too large
Load Diff
262
src/Components/Modules/TextRenderer.hpp
Normal file
262
src/Components/Modules/TextRenderer.hpp
Normal file
@ -0,0 +1,262 @@
|
||||
#pragma once
|
||||
|
||||
namespace Components
|
||||
{
|
||||
enum TextColor
|
||||
{
|
||||
TEXT_COLOR_BLACK = 0,
|
||||
TEXT_COLOR_RED = 1,
|
||||
TEXT_COLOR_GREEN = 2,
|
||||
TEXT_COLOR_YELLOW = 3,
|
||||
TEXT_COLOR_BLUE = 4,
|
||||
TEXT_COLOR_LIGHT_BLUE = 5,
|
||||
TEXT_COLOR_PINK = 6,
|
||||
TEXT_COLOR_DEFAULT = 7,
|
||||
TEXT_COLOR_AXIS = 8,
|
||||
TEXT_COLOR_ALLIES = 9,
|
||||
TEXT_COLOR_RAINBOW = 10,
|
||||
TEXT_COLOR_SERVER = 11, // using that color in infostrings (e.g. your name) fails, ';' is an illegal character!
|
||||
|
||||
TEXT_COLOR_COUNT
|
||||
};
|
||||
|
||||
constexpr unsigned int ColorRgba(const uint8_t r, const uint8_t g, const uint8_t b, const uint8_t a)
|
||||
{
|
||||
return (r) | (g << 8) | (b << 16) | (a << 24);
|
||||
}
|
||||
|
||||
constexpr unsigned int ColorRgb(const uint8_t r, const uint8_t g, const uint8_t b)
|
||||
{
|
||||
return ColorRgba(r, g, b, 0xFF);
|
||||
}
|
||||
|
||||
constexpr char CharForColorIndex(const int colorIndex)
|
||||
{
|
||||
return static_cast<char>('0' + colorIndex);
|
||||
}
|
||||
|
||||
constexpr int ColorIndexForChar(const char colorChar)
|
||||
{
|
||||
return colorChar - '0';
|
||||
}
|
||||
|
||||
class TextRenderer : public Component
|
||||
{
|
||||
static constexpr auto STRING_BUFFER_SIZE_BIG = 1024;
|
||||
static constexpr auto STRING_BUFFER_SIZE_SMALL = 128;
|
||||
|
||||
static constexpr auto REFERENCE_SEARCH_START_WITH = "FONT_ICON_SEARCH_START_WITH";
|
||||
static constexpr auto REFERENCE_HINT_AUTO_COMPLETE = "FONT_ICON_HINT_AUTO_COMPLETE";
|
||||
static constexpr auto REFERENCE_HINT_MODIFIER = "FONT_ICON_HINT_MODIFIER";
|
||||
static constexpr auto REFERENCE_MODIFIER_LIST_HEADER = "FONT_ICON_MODIFIER_LIST_HEADER";
|
||||
static constexpr auto REFERENCE_MODIFIER_LIST_FLIP_HORIZONTAL = "FONT_ICON_MODIFIER_LIST_FLIP_HORIZONTAL";
|
||||
static constexpr auto REFERENCE_MODIFIER_LIST_FLIP_VERTICAL = "FONT_ICON_MODIFIER_LIST_FLIP_VERTICAL";
|
||||
static constexpr auto REFERENCE_MODIFIER_LIST_BIG = "FONT_ICON_MODIFIER_LIST_BIG";
|
||||
|
||||
static constexpr unsigned MY_ALTCOLOR_TWO = 0x0DCE6FFE6;
|
||||
static constexpr unsigned COLOR_MAP_HASH = 0xA0AB1041;
|
||||
static constexpr auto FONT_ICON_AUTOCOMPLETE_BOX_PADDING = 6.0f;
|
||||
static constexpr auto FONT_ICON_AUTOCOMPLETE_BOX_BORDER = 2.0f;
|
||||
static constexpr auto FONT_ICON_AUTOCOMPLETE_COL_SPACING = 12.0f;
|
||||
static constexpr auto FONT_ICON_AUTOCOMPLETE_ARROW_SIZE = 12.0f;
|
||||
static constexpr float MY_OFFSETS[4][2]
|
||||
{
|
||||
{-1.0f, -1.0f},
|
||||
{-1.0f, 1.0f},
|
||||
{1.0f, -1.0f},
|
||||
{1.0f, 1.0f},
|
||||
};
|
||||
static constexpr float WHITE_COLOR[4]
|
||||
{
|
||||
1.0f,
|
||||
1.0f,
|
||||
1.0f,
|
||||
1.0f
|
||||
};
|
||||
static constexpr float TEXT_COLOR[4]
|
||||
{
|
||||
1.0f,
|
||||
1.0f,
|
||||
0.8f,
|
||||
1.0f
|
||||
};
|
||||
static constexpr float HINT_COLOR[4]
|
||||
{
|
||||
0.6f,
|
||||
0.6f,
|
||||
0.6f,
|
||||
1.0f
|
||||
};
|
||||
|
||||
public:
|
||||
static constexpr char FONT_ICON_SEPARATOR_CHARACTER = ':';
|
||||
static constexpr char FONT_ICON_MODIFIER_SEPARATOR_CHARACTER = '+';
|
||||
static constexpr char FONT_ICON_MODIFIER_FLIP_HORIZONTALLY = 'h';
|
||||
static constexpr char FONT_ICON_MODIFIER_FLIP_VERTICALLY = 'v';
|
||||
static constexpr char FONT_ICON_MODIFIER_BIG = 'b';
|
||||
|
||||
static constexpr char COLOR_FIRST_CHAR = '0';
|
||||
static constexpr char COLOR_LAST_CHAR = CharForColorIndex(TEXT_COLOR_COUNT - 1);
|
||||
|
||||
enum FontIconAutocompleteInstance : unsigned
|
||||
{
|
||||
FONT_ICON_ACI_CONSOLE,
|
||||
FONT_ICON_ACI_CHAT,
|
||||
|
||||
FONT_ICON_ACI_COUNT
|
||||
};
|
||||
|
||||
struct FontIconInfo
|
||||
{
|
||||
Game::Material* material;
|
||||
bool flipHorizontal;
|
||||
bool flipVertical;
|
||||
bool big;
|
||||
};
|
||||
|
||||
private:
|
||||
struct FontIconTableEntry
|
||||
{
|
||||
std::string iconName;
|
||||
std::string materialName;
|
||||
Game::Material* material;
|
||||
};
|
||||
|
||||
struct HsvColor
|
||||
{
|
||||
unsigned char h;
|
||||
unsigned char s;
|
||||
unsigned char v;
|
||||
};
|
||||
|
||||
class FontIconAutocompleteResult
|
||||
{
|
||||
public:
|
||||
std::string fontIconName;
|
||||
std::string materialName;
|
||||
};
|
||||
|
||||
class BufferedLocalizedString
|
||||
{
|
||||
public:
|
||||
BufferedLocalizedString(const char* reference, size_t bufferSize);
|
||||
void Cache();
|
||||
const char* Format(const char* value);
|
||||
const char* GetString() const;
|
||||
int GetWidth(FontIconAutocompleteInstance autocompleteInstance, Game::Font_s* font);
|
||||
|
||||
private:
|
||||
const char* stringReference;
|
||||
std::unique_ptr<char[]> stringBuffer;
|
||||
size_t stringBufferSize;
|
||||
int stringWidth[FONT_ICON_ACI_COUNT];
|
||||
};
|
||||
|
||||
class FontIconAutocompleteContext
|
||||
{
|
||||
public:
|
||||
static constexpr auto MAX_RESULTS = 10;
|
||||
|
||||
bool autocompleteActive;
|
||||
bool inModifiers;
|
||||
bool userClosed;
|
||||
unsigned int lastHash;
|
||||
std::string lastQuery;
|
||||
FontIconAutocompleteResult results[MAX_RESULTS];
|
||||
size_t resultCount;
|
||||
bool hasMoreResults;
|
||||
size_t resultOffset;
|
||||
size_t lastResultOffset;
|
||||
size_t selectedOffset;
|
||||
float maxFontIconWidth;
|
||||
float maxMaterialNameWidth;
|
||||
BufferedLocalizedString stringSearchStartWith;
|
||||
|
||||
FontIconAutocompleteContext();
|
||||
};
|
||||
|
||||
static unsigned colorTableDefault[TEXT_COLOR_COUNT];
|
||||
static unsigned colorTableNew[TEXT_COLOR_COUNT];
|
||||
static unsigned(*currentColorTable)[TEXT_COLOR_COUNT];
|
||||
static FontIconAutocompleteContext autocompleteContextArray[FONT_ICON_ACI_COUNT];
|
||||
static std::map<std::string, FontIconTableEntry> fontIconLookup;
|
||||
static std::vector<FontIconTableEntry> fontIconList;
|
||||
|
||||
static BufferedLocalizedString stringHintAutoComplete;
|
||||
static BufferedLocalizedString stringHintModifier;
|
||||
static BufferedLocalizedString stringListHeader;
|
||||
static BufferedLocalizedString stringListFlipHorizontal;
|
||||
static BufferedLocalizedString stringListFlipVertical;
|
||||
static BufferedLocalizedString stringListBig;
|
||||
|
||||
static Dvar::Var cg_newColors;
|
||||
static Dvar::Var cg_fontIconAutocomplete;
|
||||
static Dvar::Var cg_fontIconAutocompleteHint;
|
||||
static Game::dvar_t* sv_customTextColor;
|
||||
static Dvar::Var r_colorBlind;
|
||||
static Game::dvar_t* g_ColorBlind_MyTeam;
|
||||
static Game::dvar_t* g_ColorBlind_EnemyTeam;
|
||||
static Game::dvar_t** con_inputBoxColor;
|
||||
|
||||
public:
|
||||
static void DrawText2D(const char* text, float x, float y, Game::Font_s* font, float xScale, float yScale, float sinAngle, float cosAngle, Game::GfxColor color, int maxLength, int renderFlags, int cursorPos, char cursorLetter, float padding, Game::GfxColor glowForcedColor, int fxBirthTime, int fxLetterTime, int fxDecayStartTime, int fxDecayDuration, Game::Material* fxMaterial, Game::Material* fxMaterialGlow);
|
||||
static int R_TextWidth_Hk(const char* text, int maxChars, Game::Font_s* font);
|
||||
static unsigned int ColorIndex(char index);
|
||||
static void StripColors(const char* in, char* out, size_t max);
|
||||
static std::string StripColors(const std::string& in);
|
||||
static void StripMaterialTextIcons(const char* in, char* out, size_t max);
|
||||
static std::string StripMaterialTextIcons(const std::string& in);
|
||||
static void StripAllTextIcons(const char* in, char* out, size_t max);
|
||||
static std::string StripAllTextIcons(const std::string& in);
|
||||
|
||||
static bool IsFontIcon(const char*& text, FontIconInfo& fontIcon);
|
||||
static float GetNormalizedFontIconWidth(const FontIconInfo& fontIcon);
|
||||
static float GetFontIconWidth(const FontIconInfo& fontIcon, const Game::Font_s* font, float xScale);
|
||||
|
||||
static bool HandleFontIconAutocompleteKey(int localClientNum, FontIconAutocompleteInstance autocompleteInstance, int key);
|
||||
|
||||
TextRenderer();
|
||||
|
||||
private:
|
||||
static unsigned HsvToRgb(HsvColor hsv);
|
||||
|
||||
static void DrawAutocompleteBox(const FontIconAutocompleteContext& context, float x, float y, float w, float h, const float* color);
|
||||
static void DrawAutocompleteModifiers(FontIconAutocompleteInstance instance, float x, float y, Game::Font_s* font, float textXScale, float textYScale);
|
||||
static void DrawAutocompleteResults(FontIconAutocompleteInstance instance, float x, float y, Game::Font_s* font, float textXScale, float textYScale);
|
||||
static void DrawAutocomplete(FontIconAutocompleteInstance instance, float x, float y, Game::Font_s* font, float textXScale, float textYScale);
|
||||
static void UpdateAutocompleteContextResults(FontIconAutocompleteContext& context, Game::Font_s* font, float textXScale);
|
||||
static void UpdateAutocompleteContext(FontIconAutocompleteContext& context, const Game::field_t* edit, Game::Font_s* font, const float textXScale);
|
||||
static void Field_Draw_Say(int localClientNum, Game::field_t* edit, int x, int y, int horzAlign, int vertAlign);
|
||||
static void Con_DrawInput_Hk(int localClientNum);
|
||||
|
||||
static void AutocompleteUp(FontIconAutocompleteContext& context);
|
||||
static void AutocompleteDown(FontIconAutocompleteContext& context);
|
||||
static void AutocompleteFill(const FontIconAutocompleteContext& context, Game::ScreenPlacement* scrPlace, Game::field_t* edit, bool closeFontIcon);
|
||||
static bool AutocompleteHandleKeyDown(FontIconAutocompleteContext& context, int key, Game::ScreenPlacement* scrPlace, Game::field_t* edit);
|
||||
static void Console_Key_Hk(int localClientNum, int key);
|
||||
static bool ChatHandleKeyDown(int localClientNum, int key);
|
||||
static void Message_Key_Stub();
|
||||
|
||||
static int SEH_PrintStrlenWithCursor(const char* string, const Game::field_t* field);
|
||||
static void Field_AdjustScroll_PrintLen_Stub();
|
||||
|
||||
static void PatchColorLimit(char limit);
|
||||
static bool Dvar_GetUnpackedColorByName(const char* name, float* expandedColor);
|
||||
static void GetUnpackedColorByNameStub();
|
||||
|
||||
static Game::GfxImage* GetFontIconColorMap(const Game::Material* fontIconMaterial);
|
||||
static float DrawFontIcon(const FontIconInfo& fontIcon, float x, float y, float sinAngle, float cosAngle, const Game::Font_s* font, float xScale, float yScale, unsigned color);
|
||||
|
||||
static float GetMonospaceWidth(Game::Font_s* font, int rendererFlags);
|
||||
static void GlowColor(Game::GfxColor* result, Game::GfxColor baseColor, Game::GfxColor forcedGlowColor, int renderFlags);
|
||||
static unsigned R_FontGetRandomLetter(int seed);
|
||||
static void DrawTextFxExtraCharacter(Game::Material* material, int charIndex, float x, float y, float w, float h, float sinAngle, float cosAngle, unsigned color);
|
||||
static float DrawHudIcon(const char*& text, float x, float y, float sinAngle, float cosAngle, const Game::Font_s* font, float xScale, float yScale, unsigned color);
|
||||
static void RotateXY(float cosAngle, float sinAngle, float pivotX, float pivotY, float x, float y, float* outX, float* outY);
|
||||
static void UpdateColorTable();
|
||||
|
||||
static void InitFontIconStrings();
|
||||
static void InitFontIcons();
|
||||
static void UI_Init_Hk(int localClientNum);
|
||||
};
|
||||
}
|
@ -75,6 +75,7 @@ namespace Game
|
||||
|
||||
Con_DrawMiniConsole_t Con_DrawMiniConsole = Con_DrawMiniConsole_t(0x464F30);
|
||||
Con_DrawSolidConsole_t Con_DrawSolidConsole = Con_DrawSolidConsole_t(0x5A5040);
|
||||
Con_CancelAutoComplete_t Con_CancelAutoComplete = Con_CancelAutoComplete_t(0x435580);
|
||||
|
||||
DB_AllocStreamPos_t DB_AllocStreamPos = DB_AllocStreamPos_t(0x418380);
|
||||
DB_PushStreamPos_t DB_PushStreamPos = DB_PushStreamPos_t(0x458A20);
|
||||
@ -155,6 +156,7 @@ namespace Game
|
||||
Info_ValueForKey_t Info_ValueForKey = Info_ValueForKey_t(0x47C820);
|
||||
|
||||
Key_SetCatcher_t Key_SetCatcher = Key_SetCatcher_t(0x43BD00);
|
||||
Key_RemoveCatcher_t Key_RemoveCatcher = Key_RemoveCatcher_t(0x408260);
|
||||
Key_IsKeyCatcherActive_t Key_IsKeyCatcherActive = Key_IsKeyCatcherActive_t(0x4DA010);
|
||||
|
||||
LargeLocalInit_t LargeLocalInit = LargeLocalInit_t(0x4A62A0);
|
||||
@ -340,10 +342,14 @@ namespace Game
|
||||
UI_UpdateArenas_t UI_UpdateArenas = UI_UpdateArenas_t(0x4A95B0);
|
||||
UI_SortArenas_t UI_SortArenas = UI_SortArenas_t(0x630AE0);
|
||||
UI_DrawHandlePic_t UI_DrawHandlePic = UI_DrawHandlePic_t(0x4D0EA0);
|
||||
UI_GetContext_t UI_GetContext = UI_GetContext_t(0x4F8940);
|
||||
ScrPlace_GetActivePlacement_t ScrPlace_GetActivePlacement = ScrPlace_GetActivePlacement_t(0x4F8940);
|
||||
UI_TextWidth_t UI_TextWidth = UI_TextWidth_t(0x6315C0);
|
||||
UI_DrawText_t UI_DrawText = UI_DrawText_t(0x49C0D0);
|
||||
UI_GetFontHandle_t UI_GetFontHandle = UI_GetFontHandle_t(0x4AEA60);
|
||||
ScrPlace_ApplyRect_t ScrPlace_ApplyRect = ScrPlace_ApplyRect_t(0x454E20);
|
||||
UI_KeyEvent_t UI_KeyEvent = UI_KeyEvent_t(0x4970F0);
|
||||
UI_SafeTranslateString_t UI_SafeTranslateString = UI_SafeTranslateString_t(0x4F1700);
|
||||
UI_ReplaceConversions_t UI_ReplaceConversions = UI_ReplaceConversions_t(0x4E9740);
|
||||
|
||||
Win_GetLanguage_t Win_GetLanguage = Win_GetLanguage_t(0x45CBA0);
|
||||
|
||||
@ -353,6 +359,18 @@ namespace Game
|
||||
|
||||
unzClose_t unzClose = unzClose_t(0x41BF20);
|
||||
|
||||
RB_DrawCursor_t RB_DrawCursor = RB_DrawCursor_t(0x534EA0);
|
||||
|
||||
R_NormalizedTextScale_t R_NormalizedTextScale = R_NormalizedTextScale_t(0x5056A0);
|
||||
|
||||
Material_Process2DTextureCoordsForAtlasing_t Material_Process2DTextureCoordsForAtlasing = Material_Process2DTextureCoordsForAtlasing_t(0x506090);
|
||||
|
||||
Byte4PackRgba_t Byte4PackRgba = Byte4PackRgba_t(0x4FE910);
|
||||
RandWithSeed_t RandWithSeed = RandWithSeed_t(0x495580);
|
||||
GetDecayingLetterInfo_t GetDecayingLetterInfo = GetDecayingLetterInfo_t(0x5351C0);
|
||||
|
||||
Field_Draw_t Field_Draw = Field_Draw_t(0x4F5B40);
|
||||
Field_AdjustScroll_t Field_AdjustScroll = Field_AdjustScroll_t(0x488C10);
|
||||
AimAssist_ApplyAutoMelee_t AimAssist_ApplyAutoMelee = AimAssist_ApplyAutoMelee_t(0x56A360);
|
||||
|
||||
XAssetHeader* DB_XAssetPool = reinterpret_cast<XAssetHeader*>(0x7998A8);
|
||||
@ -448,11 +466,19 @@ namespace Game
|
||||
|
||||
GfxScene* scene = reinterpret_cast<GfxScene*>(0x6944914);
|
||||
|
||||
clientActive_t* clients = reinterpret_cast<clientActive_t*>(0xB2C698);
|
||||
ConDrawInputGlob* conDrawInputGlob = reinterpret_cast<ConDrawInputGlob*>(0x9FD6F8);
|
||||
field_t* g_consoleField = reinterpret_cast<field_t*>(0xA1B6B0);
|
||||
|
||||
clientStatic_t* cls = reinterpret_cast<clientStatic_t*>(0xA7FE90);
|
||||
|
||||
sharedUiInfo_t* sharedUiInfo = reinterpret_cast<sharedUiInfo_t*>(0x62E4B78);
|
||||
ScreenPlacement* scrPlaceFull = reinterpret_cast<ScreenPlacement*>(0x10843F0);
|
||||
ScreenPlacement* scrPlaceView = reinterpret_cast<ScreenPlacement*>(0x1084378);
|
||||
|
||||
clientActive_t* clients = reinterpret_cast<clientActive_t*>(0xB2C698);
|
||||
|
||||
cg_s* cgArray = reinterpret_cast<cg_s*>(0x7F0F78);
|
||||
cgs_t* cgsArray = reinterpret_cast<cgs_t*>(0x7ED3B8);
|
||||
|
||||
PlayerKeyState* playerKeys = reinterpret_cast<PlayerKeyState*>(0xA1B7D0);
|
||||
kbutton_t* playersKb = reinterpret_cast<kbutton_t*>(0xA1A9A8);
|
||||
@ -584,37 +610,32 @@ namespace Game
|
||||
|
||||
while (lock && *reinterpret_cast<volatile long*>(0x16B8A58)) std::this_thread::sleep_for(1ms);
|
||||
|
||||
unsigned int index = 0;
|
||||
do
|
||||
const auto pool = Components::Maps::GetAssetEntryPool();
|
||||
for(auto hash = 0; hash < 37000; hash++)
|
||||
{
|
||||
unsigned short hashIndex = db_hashTable[index];
|
||||
if (hashIndex)
|
||||
auto hashIndex = db_hashTable[hash];
|
||||
while(hashIndex)
|
||||
{
|
||||
do
|
||||
auto* assetEntry = &pool[hashIndex];
|
||||
|
||||
if(assetEntry->asset.type == type)
|
||||
{
|
||||
XAssetEntry* asset = &Components::Maps::GetAssetEntryPool()[hashIndex];
|
||||
hashIndex = asset->nextHash;
|
||||
if (asset->asset.type == type)
|
||||
callback(assetEntry);
|
||||
if (overrides)
|
||||
{
|
||||
callback(asset);
|
||||
if (overrides)
|
||||
auto overrideIndex = assetEntry->nextOverride;
|
||||
while (overrideIndex)
|
||||
{
|
||||
unsigned short overrideIndex = asset->nextOverride;
|
||||
if (asset->nextOverride)
|
||||
{
|
||||
do
|
||||
{
|
||||
asset = &Components::Maps::GetAssetEntryPool()[overrideIndex];
|
||||
callback(asset);
|
||||
overrideIndex = asset->nextOverride;
|
||||
} while (overrideIndex);
|
||||
}
|
||||
auto* overrideEntry = &pool[overrideIndex];
|
||||
callback(overrideEntry);
|
||||
overrideIndex = overrideEntry->nextOverride;
|
||||
}
|
||||
}
|
||||
} while (hashIndex);
|
||||
}
|
||||
|
||||
hashIndex = assetEntry->nextHash;
|
||||
}
|
||||
++index;
|
||||
} while (index < 74000);
|
||||
}
|
||||
|
||||
if(lock) InterlockedDecrement(lockVar);
|
||||
}
|
||||
@ -643,6 +664,20 @@ namespace Game
|
||||
return hash;
|
||||
}
|
||||
|
||||
unsigned int R_HashString(const char* string, size_t maxLen)
|
||||
{
|
||||
unsigned int hash = 0;
|
||||
|
||||
while (*string && maxLen > 0)
|
||||
{
|
||||
hash = (*string | 0x20) ^ (33 * hash);
|
||||
++string;
|
||||
maxLen--;
|
||||
}
|
||||
|
||||
return hash;
|
||||
}
|
||||
|
||||
void SV_KickClientError(client_t* client, const std::string& reason)
|
||||
{
|
||||
if (client->state < 5)
|
||||
@ -1315,22 +1350,123 @@ namespace Game
|
||||
}
|
||||
}
|
||||
|
||||
__declspec(naked) Glyph* R_GetCharacterGlyph(Font_s* /*font */, unsigned int /*letter*/)
|
||||
__declspec(naked) Glyph* R_GetCharacterGlyph(Font_s* /*font*/, unsigned int /*letter*/)
|
||||
{
|
||||
__asm
|
||||
__asm
|
||||
{
|
||||
push eax
|
||||
pushad
|
||||
mov edi, [esp + 0x28 + 4]
|
||||
push [esp + 0x24 + 4]
|
||||
|
||||
mov edi, [esp + 0x8 + 0x24] // letter
|
||||
push [esp + 0x4 + 0x24] // font
|
||||
mov eax, 0x5055C0
|
||||
call eax
|
||||
add esp,0x4
|
||||
add esp, 4
|
||||
mov [esp + 0x20], eax
|
||||
|
||||
popad
|
||||
pop eax
|
||||
ret
|
||||
}
|
||||
}
|
||||
|
||||
__declspec(naked) bool SetupPulseFXVars(const char* /*text*/, int /*maxLength*/, int /*fxBirthTime*/, int /*fxLetterTime*/, int /*fxDecayStartTime*/, int /*fxDecayDuration*/, bool* /*resultDrawRandChar*/, int* /*resultRandSeed*/, int* /*resultMaxLength*/, bool* /*resultDecaying*/, int* /*resultDecayTimeElapsed*/)
|
||||
{
|
||||
__asm
|
||||
{
|
||||
push eax
|
||||
pushad
|
||||
|
||||
mov eax, [esp + 0x08 + 0x24] // maxLength
|
||||
push [esp + 0x2C + 0x24] // resultDecayTimeElapsed
|
||||
push [esp + 0x2C + 0x24] // resultDecaying
|
||||
push [esp + 0x2C + 0x24] // resultMaxLength
|
||||
push [esp + 0x2C + 0x24] // resultRandSeed
|
||||
push [esp + 0x2C + 0x24] // resultDrawRandChar
|
||||
push [esp + 0x2C + 0x24] // fxDecayDuration
|
||||
push [esp + 0x2C + 0x24] // fxDecayStartTime
|
||||
push [esp + 0x2C + 0x24] // fxLetterTime
|
||||
push [esp + 0x2C + 0x24] // fxBirthTime
|
||||
push [esp + 0x28 + 0x24] // text
|
||||
mov ebx, 0x535050
|
||||
call ebx
|
||||
add esp, 0x28
|
||||
mov [esp + 0x20],eax
|
||||
|
||||
popad
|
||||
pop eax
|
||||
retn
|
||||
ret
|
||||
}
|
||||
}
|
||||
|
||||
__declspec(naked) void RB_DrawChar(Material* /*material*/, float /*x*/, float /*y*/, float /*w*/, float /*h*/, float /*sinAngle*/, float /*cosAngle*/, Glyph* /*glyph*/, unsigned int /*color*/)
|
||||
{
|
||||
__asm
|
||||
{
|
||||
pushad
|
||||
|
||||
mov eax, [esp + 0x4 + 0x20] // material
|
||||
mov edx, [esp + 0x20 + 0x20] // glyph
|
||||
push [esp + 0x24 + 0x20] // color
|
||||
push [esp + 0x20 + 0x20] // cosAngle
|
||||
push [esp + 0x20 + 0x20] // sinAngle
|
||||
push [esp + 0x20 + 0x20] // h
|
||||
push [esp + 0x20 + 0x20] // w
|
||||
push [esp + 0x20 + 0x20] // y
|
||||
push [esp + 0x20 + 0x20] // x
|
||||
|
||||
mov ecx, 0x534E20
|
||||
call ecx
|
||||
add esp, 0x1C
|
||||
|
||||
popad
|
||||
ret
|
||||
}
|
||||
}
|
||||
|
||||
__declspec(naked) void RB_DrawStretchPicRotate(Material* /*material*/, float /*x*/, float /*y*/, float /*w*/, float /*h*/, float /*s0*/, float /*t0*/, float /*s1*/, float /*t1*/, float /*sinAngle*/, float /*cosAngle*/, unsigned int /*color*/)
|
||||
{
|
||||
__asm
|
||||
{
|
||||
pushad
|
||||
|
||||
mov eax, [esp + 0x4 + 0x20] // material
|
||||
push [esp + 0x30 + 0x20] // color
|
||||
push [esp + 0x30 + 0x20] // cosAngle
|
||||
push [esp + 0x30 + 0x20] // sinAngle
|
||||
push [esp + 0x30 + 0x20] // t1
|
||||
push [esp + 0x30 + 0x20] // s1
|
||||
push [esp + 0x30 + 0x20] // t0
|
||||
push [esp + 0x30 + 0x20] // s0
|
||||
push [esp + 0x30 + 0x20] // h
|
||||
push [esp + 0x30 + 0x20] // w
|
||||
push [esp + 0x30 + 0x20] // y
|
||||
push [esp + 0x30 + 0x20] // x
|
||||
mov ebx, 0x5310F0
|
||||
call ebx
|
||||
add esp, 0x2C
|
||||
|
||||
popad
|
||||
ret
|
||||
}
|
||||
}
|
||||
|
||||
__declspec(naked) char ModulateByteColors(char /*colorA*/, char /*colorB*/)
|
||||
{
|
||||
__asm
|
||||
{
|
||||
push eax
|
||||
pushad
|
||||
|
||||
mov eax, [esp + 0x4 + 0x24] // colorA
|
||||
mov ecx, [esp + 0x8 + 0x24] // colorB
|
||||
mov ebx, 0x5353C0
|
||||
call ebx
|
||||
mov [esp + 0x20], eax
|
||||
|
||||
popad
|
||||
pop eax
|
||||
ret
|
||||
}
|
||||
}
|
||||
|
||||
@ -1356,6 +1492,5 @@ namespace Game
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#pragma optimize("", on)
|
||||
}
|
||||
|
@ -157,6 +157,9 @@ namespace Game
|
||||
typedef void (__cdecl * Con_DrawSolidConsole_t)();
|
||||
extern Con_DrawSolidConsole_t Con_DrawSolidConsole;
|
||||
|
||||
typedef bool(__cdecl * Con_CancelAutoComplete_t)();
|
||||
extern Con_CancelAutoComplete_t Con_CancelAutoComplete;
|
||||
|
||||
typedef char *(__cdecl *DB_AllocStreamPos_t)(int alignment);
|
||||
extern DB_AllocStreamPos_t DB_AllocStreamPos;
|
||||
|
||||
@ -375,6 +378,9 @@ namespace Game
|
||||
typedef void(__cdecl * Key_SetCatcher_t)(int localClientNum, int catcher);
|
||||
extern Key_SetCatcher_t Key_SetCatcher;
|
||||
|
||||
typedef void(__cdecl * Key_RemoveCatcher_t)(int localClientNum, int andMask);
|
||||
extern Key_RemoveCatcher_t Key_RemoveCatcher;
|
||||
|
||||
typedef bool(__cdecl * Key_IsKeyCatcherActive_t)(int localClientNum, int catcher);
|
||||
extern Key_IsKeyCatcherActive_t Key_IsKeyCatcherActive;
|
||||
|
||||
@ -459,6 +465,12 @@ namespace Game
|
||||
typedef bool(__cdecl * UI_KeyEvent_t)(int clientNum, int key, int down);
|
||||
extern UI_KeyEvent_t UI_KeyEvent;
|
||||
|
||||
typedef const char* (__cdecl * UI_SafeTranslateString_t)(const char* reference);
|
||||
extern UI_SafeTranslateString_t UI_SafeTranslateString;
|
||||
|
||||
typedef void(__cdecl * UI_ReplaceConversions_t)(const char* sourceString, ConversionArguments* arguments, char* outputString, size_t outputStringSize);
|
||||
extern UI_ReplaceConversions_t UI_ReplaceConversions;
|
||||
|
||||
typedef void(__cdecl * MSG_Init_t)(msg_t *buf, char *data, int length);
|
||||
extern MSG_Init_t MSG_Init;
|
||||
|
||||
@ -696,7 +708,7 @@ namespace Game
|
||||
typedef char* (__cdecl * SEH_StringEd_GetString_t)(const char* string);
|
||||
extern SEH_StringEd_GetString_t SEH_StringEd_GetString;
|
||||
|
||||
typedef int (__cdecl * SEH_ReadCharFromString_t)(const char** text, int* isTrailingPunctuation);
|
||||
typedef unsigned int(__cdecl* SEH_ReadCharFromString_t)(const char** text, int* isTrailingPunctuation);
|
||||
extern SEH_ReadCharFromString_t SEH_ReadCharFromString;
|
||||
|
||||
typedef char* (__cdecl * SL_ConvertToString_t)(unsigned short stringValue);
|
||||
@ -813,14 +825,20 @@ namespace Game
|
||||
typedef void(__cdecl * UI_DrawHandlePic_t)(/*ScreenPlacement*/void *scrPlace, float x, float y, float w, float h, int horzAlign, int vertAlign, const float *color, Material *material);
|
||||
extern UI_DrawHandlePic_t UI_DrawHandlePic;
|
||||
|
||||
typedef void* (__cdecl * UI_GetContext_t)(void*);
|
||||
extern UI_GetContext_t UI_GetContext;
|
||||
typedef ScreenPlacement* (__cdecl * ScrPlace_GetActivePlacement_t)(int localClientNum);
|
||||
extern ScrPlace_GetActivePlacement_t ScrPlace_GetActivePlacement;
|
||||
|
||||
typedef int(__cdecl * UI_TextWidth_t)(const char *text, int maxChars, Font_s *font, float scale);
|
||||
extern UI_TextWidth_t UI_TextWidth;
|
||||
|
||||
typedef void(__cdecl * UI_DrawText_t)(void* scrPlace, const char *text, int maxChars, Font_s *font, float x, float y, int horzAlign, int vertAlign, float scale, const float *color, int style);
|
||||
extern UI_DrawText_t UI_DrawText;
|
||||
|
||||
typedef Font_s* (__cdecl* UI_GetFontHandle_t)(ScreenPlacement* scrPlace, int fontEnum, float scale);
|
||||
extern UI_GetFontHandle_t UI_GetFontHandle;
|
||||
|
||||
typedef void(__cdecl* ScrPlace_ApplyRect_t)(ScreenPlacement* a1, float* x, float* y, float* w, float* h, int horzAlign, int vertAlign);
|
||||
extern ScrPlace_ApplyRect_t ScrPlace_ApplyRect;
|
||||
|
||||
typedef const char * (__cdecl * Win_GetLanguage_t)();
|
||||
extern Win_GetLanguage_t Win_GetLanguage;
|
||||
@ -836,6 +854,30 @@ namespace Game
|
||||
|
||||
typedef void(__cdecl * unzClose_t)(void* handle);
|
||||
extern unzClose_t unzClose;
|
||||
|
||||
typedef void(__cdecl* RB_DrawCursor_t)(Material* material, char cursor, float x, float y, float sinAngle, float cosAngle, Font_s* font, float xScale, float yScale, unsigned int color);
|
||||
extern RB_DrawCursor_t RB_DrawCursor;
|
||||
|
||||
typedef float(__cdecl* R_NormalizedTextScale_t)(Font_s* font, float scale);
|
||||
extern R_NormalizedTextScale_t R_NormalizedTextScale;
|
||||
|
||||
typedef void(__cdecl * Material_Process2DTextureCoordsForAtlasing_t)(const Material* material, float* s0, float* s1, float* t0, float* t1);
|
||||
extern Material_Process2DTextureCoordsForAtlasing_t Material_Process2DTextureCoordsForAtlasing;
|
||||
|
||||
typedef void(__cdecl* Byte4PackRgba_t)(const float* from, char* to);
|
||||
extern Byte4PackRgba_t Byte4PackRgba;
|
||||
|
||||
typedef int(__cdecl* RandWithSeed_t)(int* seed);
|
||||
extern RandWithSeed_t RandWithSeed;
|
||||
|
||||
typedef void(__cdecl* GetDecayingLetterInfo_t)(unsigned int letter, int* randSeed, int decayTimeElapsed, int fxBirthTime, int fxDecayDuration, unsigned __int8 alpha, bool* resultSkipDrawing, char* resultAlpha, unsigned int* resultLetter, bool* resultDrawExtraFxChar);
|
||||
extern GetDecayingLetterInfo_t GetDecayingLetterInfo;
|
||||
|
||||
typedef void(__cdecl * Field_Draw_t)(int localClientNum, field_t* edit, int x, int y, int horzAlign, int vertAlign);
|
||||
extern Field_Draw_t Field_Draw;
|
||||
|
||||
typedef void(__cdecl * Field_AdjustScroll_t)(ScreenPlacement* scrPlace, field_t* edit);
|
||||
extern Field_AdjustScroll_t Field_AdjustScroll;
|
||||
|
||||
typedef void(__cdecl * AimAssist_ApplyAutoMelee_t)(const AimInput* input, AimOutput* output);
|
||||
extern AimAssist_ApplyAutoMelee_t AimAssist_ApplyAutoMelee;
|
||||
@ -932,11 +974,19 @@ namespace Game
|
||||
|
||||
extern GfxScene* scene;
|
||||
|
||||
extern clientActive_t* clients;
|
||||
extern ConDrawInputGlob* conDrawInputGlob;
|
||||
extern field_t* g_consoleField;
|
||||
|
||||
extern clientStatic_t* cls;
|
||||
|
||||
extern sharedUiInfo_t* sharedUiInfo;
|
||||
extern ScreenPlacement* scrPlaceFull;
|
||||
extern ScreenPlacement* scrPlaceView;
|
||||
|
||||
extern clientActive_t* clients;
|
||||
|
||||
extern cg_s* cgArray;
|
||||
extern cgs_t* cgsArray;
|
||||
|
||||
extern PlayerKeyState* playerKeys;
|
||||
extern kbutton_t* playersKb;
|
||||
@ -974,6 +1024,7 @@ namespace Game
|
||||
void ShowMessageBox(const std::string& message, const std::string& title);
|
||||
|
||||
unsigned int R_HashString(const char* string);
|
||||
unsigned int R_HashString(const char* string, size_t maxLen);
|
||||
void R_LoadSunThroughDvars(const char* mapname, sunflare_t* sun);
|
||||
void R_SetSunFromDvars(sunflare_t* sun);
|
||||
|
||||
@ -1012,11 +1063,15 @@ namespace Game
|
||||
void R_AddDebugBounds(float* color, Bounds* b);
|
||||
void R_AddDebugBounds(float* color, Bounds* b, const float(*quat)[4]);
|
||||
|
||||
Glyph* R_GetCharacterGlyph(Font_s* font, unsigned int letter);
|
||||
bool SetupPulseFXVars(const char* text, int maxLength, int fxBirthTime, int fxLetterTime, int fxDecayStartTime, int fxDecayDuration, bool* resultDrawRandChar, int* resultRandSeed, int* resultMaxLength, bool* resultDecaying, int* resultDecayTimeElapsed);
|
||||
void RB_DrawChar(Material* material, float x, float y, float w, float h, float sinAngle, float cosAngle, Glyph* glyph, unsigned int color);
|
||||
void RB_DrawStretchPicRotate(Material* material, float x, float y, float w, float h, float s0, float t0, float s1, float t1, float sinAngle, float cosAngle, unsigned int color);
|
||||
char ModulateByteColors(char colorA, char colorB);
|
||||
|
||||
float GraphGetValueFromFraction(int knotCount, const float(*knots)[2], float fraction);
|
||||
float GraphFloat_GetValue(const GraphFloat* graph, const float fraction);
|
||||
|
||||
Glyph* R_GetCharacterGlyph(Font_s* font, unsigned int letter);
|
||||
|
||||
void AimAssist_UpdateTweakables(int localClientNum);
|
||||
void AimAssist_UpdateAdsLerp(const AimInput* input);
|
||||
}
|
||||
|
@ -702,8 +702,8 @@ namespace Game
|
||||
const char *name;
|
||||
char gameFlags;
|
||||
char sortKey;
|
||||
char textureAtlasRowCount;
|
||||
char textureAtlasColumnCount;
|
||||
unsigned char textureAtlasRowCount;
|
||||
unsigned char textureAtlasColumnCount;
|
||||
GfxDrawSurf drawSurf;
|
||||
unsigned int surfaceTypeBits;
|
||||
unsigned __int16 hashIndex;
|
||||
@ -1566,9 +1566,9 @@ namespace Game
|
||||
{
|
||||
MaterialInfo info;
|
||||
char stateBitsEntry[48];
|
||||
char textureCount;
|
||||
char constantCount;
|
||||
char stateBitsCount;
|
||||
unsigned char textureCount;
|
||||
unsigned char constantCount;
|
||||
unsigned char stateBitsCount;
|
||||
char stateFlags;
|
||||
char cameraRegion;
|
||||
MaterialTechniqueSet *techniqueSet;
|
||||
@ -4539,10 +4539,10 @@ namespace Game
|
||||
{
|
||||
XAsset asset;
|
||||
char zoneIndex;
|
||||
volatile char inuse;
|
||||
volatile char inuseMask;
|
||||
bool printedMissingAsset;
|
||||
unsigned __int16 nextHash;
|
||||
unsigned __int16 nextOverride;
|
||||
unsigned __int16 usageFrame;
|
||||
};
|
||||
|
||||
enum XFileLanguage : unsigned char
|
||||
@ -6042,6 +6042,30 @@ namespace Game
|
||||
int updateSound;
|
||||
int allowAddDObj;
|
||||
};
|
||||
|
||||
enum TextRenderFlags
|
||||
{
|
||||
TEXT_RENDERFLAG_FORCEMONOSPACE = 0x1,
|
||||
TEXT_RENDERFLAG_CURSOR = 0x2,
|
||||
TEXT_RENDERFLAG_DROPSHADOW = 0x4,
|
||||
TEXT_RENDERFLAG_DROPSHADOW_EXTRA = 0x8,
|
||||
TEXT_RENDERFLAG_GLOW = 0x10,
|
||||
TEXT_RENDERFLAG_GLOW_FORCE_COLOR = 0x20,
|
||||
TEXT_RENDERFLAG_FX_DECODE = 0x40,
|
||||
TEXT_RENDERFLAG_PADDING = 0x80,
|
||||
TEXT_RENDERFLAG_SUBTITLETEXT = 0x100,
|
||||
TEXT_RENDERFLAG_CINEMATIC = 0x200,
|
||||
TEXT_RENDERFLAG_OUTLINE = 0x400,
|
||||
TEXT_RENDERFLAG_OUTLINE_EXTRA = 0x800,
|
||||
};
|
||||
|
||||
enum FontPassType
|
||||
{
|
||||
FONTPASS_NORMAL = 0x0,
|
||||
FONTPASS_GLOW = 0x1,
|
||||
FONTPASS_OUTLINE = 0x2,
|
||||
FONTPASS_COUNT = 0x3,
|
||||
};
|
||||
|
||||
struct AimInput
|
||||
{
|
||||
@ -6183,6 +6207,175 @@ namespace Game
|
||||
entityState_s noDeltaEntities[1024];
|
||||
};
|
||||
|
||||
struct ConDrawInputGlob
|
||||
{
|
||||
char autoCompleteChoice[64];
|
||||
int matchIndex;
|
||||
int matchCount;
|
||||
const char* inputText;
|
||||
int inputTextLen;
|
||||
bool hasExactMatch;
|
||||
bool mayAutoComplete;
|
||||
float x;
|
||||
float y;
|
||||
float leftX;
|
||||
float fontHeight;
|
||||
};
|
||||
|
||||
struct ScreenPlacement
|
||||
{
|
||||
float scaleVirtualToReal[2];
|
||||
float scaleVirtualToFull[2];
|
||||
float scaleRealToVirtual[2];
|
||||
float realViewportPosition[2];
|
||||
float realViewportSize[2];
|
||||
float virtualViewableMin[2];
|
||||
float virtualViewableMax[2];
|
||||
float realViewableMin[2];
|
||||
float realViewableMax[2];
|
||||
float virtualAdjustableMin[2];
|
||||
float virtualAdjustableMax[2];
|
||||
float realAdjustableMin[2];
|
||||
float realAdjustableMax[2];
|
||||
float subScreenLeft;
|
||||
};
|
||||
|
||||
struct serverStatusInfo_t
|
||||
{
|
||||
char address[64];
|
||||
const char* lines[128][4];
|
||||
char text[1024];
|
||||
char pings[54];
|
||||
int numLines;
|
||||
};
|
||||
|
||||
struct pendingServer_t
|
||||
{
|
||||
char adrstr[64];
|
||||
char name[64];
|
||||
int startTime;
|
||||
int serverNum;
|
||||
int valid;
|
||||
};
|
||||
|
||||
struct pendingServerStatus_t
|
||||
{
|
||||
int num;
|
||||
pendingServer_t server[16];
|
||||
};
|
||||
|
||||
struct pinglist_t
|
||||
{
|
||||
char adrstr[64];
|
||||
int start;
|
||||
};
|
||||
|
||||
struct serverStatus_s
|
||||
{
|
||||
pinglist_t pingList[16];
|
||||
int numqueriedservers;
|
||||
int currentping;
|
||||
int nextpingtime;
|
||||
int maxservers;
|
||||
int refreshtime;
|
||||
int numServers;
|
||||
int sortKey;
|
||||
int sortDir;
|
||||
int lastCount;
|
||||
int refreshActive;
|
||||
int currentServer;
|
||||
int displayServers[20000];
|
||||
int numDisplayServers;
|
||||
int serverCount;
|
||||
int numPlayersOnServers;
|
||||
int nextDisplayRefresh;
|
||||
int nextSortTime;
|
||||
int motdLen;
|
||||
int motdWidth;
|
||||
int motdPaintX;
|
||||
int motdPaintX2;
|
||||
int motdOffset;
|
||||
int motdTime;
|
||||
char motd[1024];
|
||||
};
|
||||
|
||||
struct mapInfo
|
||||
{
|
||||
char mapName[32];
|
||||
char mapLoadName[16];
|
||||
char mapDescription[32];
|
||||
char mapLoadImage[32];
|
||||
char mapCustomKey[32][16];
|
||||
char mapCustomValue[32][64];
|
||||
int mapCustomCount;
|
||||
int teamMembers;
|
||||
int typeBits;
|
||||
int timeToBeat[32];
|
||||
int active;
|
||||
};
|
||||
|
||||
struct gameTypeInfo
|
||||
{
|
||||
char gameType[12];
|
||||
char gameTypeName[32];
|
||||
};
|
||||
|
||||
struct CachedAssets_t
|
||||
{
|
||||
Material* scrollBarArrowUp;
|
||||
Material* scrollBarArrowDown;
|
||||
Material* scrollBarArrowLeft;
|
||||
Material* scrollBarArrowRight;
|
||||
Material* scrollBar;
|
||||
Material* scrollBarThumb;
|
||||
Material* sliderBar;
|
||||
Material* sliderThumb;
|
||||
Material* whiteMaterial;
|
||||
Material* cursor;
|
||||
Material* textDecodeCharacters;
|
||||
Material* textDecodeCharactersGlow;
|
||||
Font_s* bigFont;
|
||||
Font_s* smallFont;
|
||||
Font_s* consoleFont;
|
||||
Font_s* boldFont;
|
||||
Font_s* textFont;
|
||||
Font_s* extraBigFont;
|
||||
Font_s* objectiveFont;
|
||||
Font_s* hudBigFont;
|
||||
Font_s* hudSmallFont;
|
||||
snd_alias_list_t* itemFocusSound;
|
||||
};
|
||||
|
||||
struct sharedUiInfo_t
|
||||
{
|
||||
CachedAssets_t assets;
|
||||
int playerCount;
|
||||
char playerNames[18][32];
|
||||
char teamNames[18][32];
|
||||
int playerClientNums[18];
|
||||
volatile int updateGameTypeList;
|
||||
int numGameTypes;
|
||||
gameTypeInfo gameTypes[32];
|
||||
int numCustomGameTypes;
|
||||
gameTypeInfo customGameTypes[32];
|
||||
char customGameTypeCancelState[2048];
|
||||
int numJoinGameTypes;
|
||||
gameTypeInfo joinGameTypes[32];
|
||||
volatile int updateArenas;
|
||||
int mapCount;
|
||||
mapInfo mapList[128];
|
||||
int mapIndexSorted[128];
|
||||
bool mapsAreSorted;
|
||||
Material* serverHardwareIconList[9];
|
||||
unsigned __int64 partyMemberXuid;
|
||||
Material* talkingIcons[2];
|
||||
serverStatus_s serverStatus;
|
||||
char serverStatusAddress[64];
|
||||
serverStatusInfo_t serverStatusInfo;
|
||||
int nextServerStatusRefresh;
|
||||
pendingServerStatus_t pendingServerStatus;
|
||||
};
|
||||
|
||||
struct GraphFloat
|
||||
{
|
||||
char name[64];
|
||||
@ -6199,7 +6392,10 @@ namespace Game
|
||||
void* nextSnap;
|
||||
char _pad1[0x673DC];
|
||||
int frametime; // + 0x6A754
|
||||
char _pad2[0x960C]; // + 0x6A758
|
||||
int time;
|
||||
int oldTime;
|
||||
int physicalsTime;
|
||||
char _pad2[0x9600]; // + 0x6A758
|
||||
float compassMapWorldSize[2]; // + 0x73D64
|
||||
char _pad3[0x74]; // + 0x73D6C
|
||||
float selectedLocation[2]; // + 0x73DE0
|
||||
@ -6210,6 +6406,8 @@ namespace Game
|
||||
char _pad4[0x89740];
|
||||
};
|
||||
|
||||
static_assert(sizeof(cg_s) == 0xFD540);
|
||||
|
||||
static constexpr auto MAX_GAMEPADS = 1;
|
||||
|
||||
static constexpr auto GPAD_VALUE_MASK = 0xFFFFFFFu;
|
||||
@ -6448,6 +6646,236 @@ namespace Game
|
||||
};
|
||||
#pragma warning(pop)
|
||||
|
||||
enum ShockViewTypes
|
||||
{
|
||||
SHELLSHOCK_VIEWTYPE_BLURRED = 0x0,
|
||||
SHELLSHOCK_VIEWTYPE_FLASHED = 0x1,
|
||||
SHELLSHOCK_VIEWTYPE_NONE = 0x2,
|
||||
};
|
||||
|
||||
struct shellshock_parms_t
|
||||
{
|
||||
struct
|
||||
{
|
||||
int blurredFadeTime;
|
||||
int blurredEffectTime;
|
||||
int flashWhiteFadeTime;
|
||||
int flashShotFadeTime;
|
||||
ShockViewTypes type;
|
||||
} screenBlend;
|
||||
|
||||
struct
|
||||
{
|
||||
int fadeTime;
|
||||
float kickRate;
|
||||
float kickRadius;
|
||||
} view;
|
||||
|
||||
struct
|
||||
{
|
||||
bool affect;
|
||||
char loop[64];
|
||||
char loopSilent[64];
|
||||
char end[64];
|
||||
char endAbort[64];
|
||||
int fadeInTime;
|
||||
int fadeOutTime;
|
||||
float drylevel;
|
||||
float wetlevel;
|
||||
char roomtype[16];
|
||||
float channelvolume[64];
|
||||
int modEndDelay;
|
||||
int loopFadeTime;
|
||||
int loopEndDelay;
|
||||
} sound;
|
||||
|
||||
struct
|
||||
{
|
||||
bool affect;
|
||||
int fadeTime;
|
||||
float mouseSensitivity;
|
||||
float maxPitchSpeed;
|
||||
float maxYawSpeed;
|
||||
} lookControl;
|
||||
|
||||
struct
|
||||
{
|
||||
bool affect;
|
||||
} movement;
|
||||
};
|
||||
|
||||
struct XAnimParent
|
||||
{
|
||||
unsigned short flags;
|
||||
unsigned short children;
|
||||
};
|
||||
|
||||
struct XAnimEntry
|
||||
{
|
||||
unsigned short numAnims;
|
||||
unsigned short parent;
|
||||
|
||||
union
|
||||
{
|
||||
XAnimParts* parts;
|
||||
XAnimParent animParent;
|
||||
};
|
||||
};
|
||||
|
||||
struct XAnim_s
|
||||
{
|
||||
unsigned int size;
|
||||
const char* debugName;
|
||||
const char** debugAnimNames;
|
||||
XAnimEntry entries[1];
|
||||
};
|
||||
|
||||
struct animation_s
|
||||
{
|
||||
char name[64];
|
||||
int initialLerp;
|
||||
float moveSpeed;
|
||||
int duration;
|
||||
int nameHash;
|
||||
int flags;
|
||||
int64_t movetype;
|
||||
int noteType;
|
||||
};
|
||||
|
||||
struct lerpFrame_t
|
||||
{
|
||||
float yawAngle;
|
||||
int yawing;
|
||||
float pitchAngle;
|
||||
int pitching;
|
||||
int animationNumber;
|
||||
animation_s* animation;
|
||||
int animationTime;
|
||||
float oldFramePos[3];
|
||||
float animSpeedScale;
|
||||
int oldFrameSnapshotTime;
|
||||
};
|
||||
|
||||
struct clientControllers_t
|
||||
{
|
||||
float angles[4][3];
|
||||
float tag_origin_angles[3];
|
||||
float tag_origin_offset[3];
|
||||
};
|
||||
|
||||
struct __declspec(align(4)) XAnimTree_s
|
||||
{
|
||||
XAnim_s* anims;
|
||||
int info_usage;
|
||||
volatile int calcRefCount;
|
||||
volatile int modifyRefCount;
|
||||
unsigned __int16 children;
|
||||
};
|
||||
|
||||
enum PlayerDiveState
|
||||
{
|
||||
DIVE_NONE = 0x0,
|
||||
DIVE_FORWARD = 0x1,
|
||||
DIVE_FORWARDLEFT = 0x2,
|
||||
DIVE_LEFT = 0x3,
|
||||
DIVE_BACKLEFT = 0x4,
|
||||
DIVE_BACK = 0x5,
|
||||
DIVE_BACKRIGHT = 0x6,
|
||||
DIVE_RIGHT = 0x7,
|
||||
DIVE_FORWARDRIGHT = 0x8,
|
||||
};
|
||||
|
||||
struct clientInfo_t
|
||||
{
|
||||
int infoValid;
|
||||
int nextValid;
|
||||
int clientNum;
|
||||
char name[16];
|
||||
team_t team;
|
||||
team_t oldteam;
|
||||
int rank;
|
||||
int prestige;
|
||||
unsigned int perks[2];
|
||||
int score;
|
||||
int location;
|
||||
int health;
|
||||
char model[64];
|
||||
char attachModelNames[6][64];
|
||||
char attachTagNames[6][64];
|
||||
unsigned int partBits[6];
|
||||
lerpFrame_t legs;
|
||||
lerpFrame_t torso;
|
||||
float lerpMoveDir;
|
||||
float lerpLean;
|
||||
float playerAngles[3];
|
||||
int legsAnim;
|
||||
int torsoAnim;
|
||||
float fTorsoPitch;
|
||||
float fWaistPitch;
|
||||
int leftHandGun;
|
||||
int dobjDirty;
|
||||
clientControllers_t control;
|
||||
unsigned int clientConditions[18][2];
|
||||
XAnimTree_s* pXAnimTree;
|
||||
int iDObjWeapon;
|
||||
char weaponModel;
|
||||
int stanceTransitionTime;
|
||||
int turnAnimEndTime;
|
||||
char turnAnimType;
|
||||
bool hideWeapon;
|
||||
bool usingKnife;
|
||||
int dualWielding;
|
||||
PlayerDiveState diveState;
|
||||
int riotShieldNext;
|
||||
unsigned int playerCardIcon;
|
||||
unsigned int playerCardTitle;
|
||||
unsigned int playerCardNameplate;
|
||||
};
|
||||
|
||||
struct cgs_t
|
||||
{
|
||||
int viewX;
|
||||
int viewY;
|
||||
int viewWidth;
|
||||
int viewHeight;
|
||||
float viewAspect;
|
||||
int serverCommandSequence;
|
||||
int processedSnapshotNum;
|
||||
int localServer;
|
||||
char gametype[32];
|
||||
char szHostName[256];
|
||||
bool hardcore;
|
||||
int maxclients;
|
||||
int privateClients;
|
||||
char mapname[64];
|
||||
int gameEndTime;
|
||||
int voteTime;
|
||||
int voteYes;
|
||||
int voteNo;
|
||||
char voteString[256];
|
||||
XModel* gameModels[512];
|
||||
FxEffectDef* smokeGrenadeFx;
|
||||
shellshock_parms_t holdBreathParams;
|
||||
char teamChatMsgs[8][160];
|
||||
int teamChatMsgTimes[8];
|
||||
int teamChatPos;
|
||||
int teamLastChatPos;
|
||||
float compassWidth;
|
||||
float compassHeight;
|
||||
float compassY;
|
||||
clientInfo_t corpseinfo[8];
|
||||
bool entUpdateToggleContextKey;
|
||||
XAnim_s* helicopterAnims;
|
||||
};
|
||||
|
||||
static_assert(sizeof(cgs_t) == 0x3BA4);
|
||||
|
||||
struct ConversionArguments
|
||||
{
|
||||
int argCount;
|
||||
const char* args[9];
|
||||
};
|
||||
|
||||
#pragma endregion
|
||||
|
||||
#ifndef IDA
|
||||
|
Loading…
x
Reference in New Issue
Block a user