Merge branch 'develop_official' into feature/xinput
This commit is contained in:
commit
ea926dfe67
17
.github/workflows/discord-notify.yml
vendored
Normal file
17
.github/workflows/discord-notify.yml
vendored
Normal file
@ -0,0 +1,17 @@
|
||||
name: Notify Discord
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- "*"
|
||||
issues:
|
||||
|
||||
jobs:
|
||||
notify:
|
||||
runs-on: ubuntu-latest
|
||||
if: github.repository_owner == 'XLabsProject'
|
||||
steps:
|
||||
- name: Send notification to Discord
|
||||
uses: Ilshidur/action-discord@master
|
||||
env:
|
||||
DISCORD_WEBHOOK: ${{ secrets.DISCORD_CI_BOT_WEBHOOK }}
|
23
README.md
23
README.md
@ -40,6 +40,29 @@
|
||||
| `--disable-bitmessage` | Disable use of BitMessage completely. |
|
||||
| `--disable-base128` | Disable base128 encoding for minidumps. |
|
||||
| `--no-new-structure` | Do not use new virtual path structure (separating headers and source files). |
|
||||
| `--iw4x-zones` | Zonebuilder generates iw4x zones that cannot be loaded without IW4x specific patches. |
|
||||
|
||||
## Command line arguments
|
||||
|
||||
| Argument | Description |
|
||||
|:----------------------------|:-----------------------------------------------|
|
||||
| `-tests` | Perform unit tests. |
|
||||
| `-entries` | Prints fast file info to the console. |
|
||||
| `-stdout` | Redirect stdout to the external console. |
|
||||
| `-console` | Enables external console. |
|
||||
| `-dedicated` | Dedicated server. |
|
||||
| `-scriptablehttp` | Adds HTTP console commands. |
|
||||
| `-bigdumps` | Enables dumps. |
|
||||
| `-reallybigdumps` | Unused. |
|
||||
| `-bigminidumps` | Mini dumps. |
|
||||
| `-reallybigminidumps` | Big mini dumps. |
|
||||
| `-dump` | Prints asset info to a .ents file. |
|
||||
| `-monitor` | Enables monitor. |
|
||||
| `-nointro` | Skips game's intro. |
|
||||
| `-version` | Prints IW4X version. |
|
||||
| `-zonebuilder` | Enables zone builder. |
|
||||
| `-nosteam` | Disables Steam features. |
|
||||
|
||||
|
||||
## Disclaimer
|
||||
|
||||
|
5011
lib/include/stb_truetype.h
Normal file
5011
lib/include/stb_truetype.h
Normal file
File diff suppressed because it is too large
Load Diff
@ -74,6 +74,11 @@ newoption {
|
||||
description = "Upload minidumps even for Debug builds."
|
||||
}
|
||||
|
||||
newoption {
|
||||
trigger = "iw4x-zones",
|
||||
description = "Zonebuilder generates iw4x zones that cannot be loaded without IW4x specific patches."
|
||||
}
|
||||
|
||||
newaction {
|
||||
trigger = "version",
|
||||
description = "Returns the version string for the current commit of the source code.",
|
||||
@ -324,6 +329,9 @@ workspace "iw4x"
|
||||
if _OPTIONS["force-exception-handler"] then
|
||||
defines { "FORCE_EXCEPTION_HANDLER" }
|
||||
end
|
||||
if _OPTIONS["iw4x-zones"] then
|
||||
defines { "GENERATE_IW4X_SPECIFIC_ZONES" }
|
||||
end
|
||||
|
||||
-- Pre-compiled header
|
||||
pchheader "STDInclude.hpp" -- must be exactly same as used in #include directives
|
||||
|
@ -286,7 +286,7 @@ namespace Components
|
||||
push [esp + 2Ch]
|
||||
push [esp + 2Ch]
|
||||
call AssetHandler::IsAssetEligible
|
||||
add esp, 08h
|
||||
add esp, 8h
|
||||
|
||||
mov [esp + 20h], eax
|
||||
popad
|
||||
@ -295,13 +295,13 @@ namespace Components
|
||||
test al, al
|
||||
jz doNotLoad
|
||||
|
||||
mov eax, [esp + 8]
|
||||
mov eax, [esp + 8h]
|
||||
sub esp, 14h
|
||||
mov ecx, 5BB657h
|
||||
jmp ecx
|
||||
|
||||
doNotLoad:
|
||||
mov eax, [esp + 8]
|
||||
mov eax, [esp + 8h]
|
||||
retn
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,82 @@
|
||||
#include "STDInclude.hpp"
|
||||
|
||||
#define STB_TRUETYPE_IMPLEMENTATION
|
||||
#include <stb_truetype.h>
|
||||
|
||||
namespace Assets
|
||||
{
|
||||
namespace
|
||||
{
|
||||
int PackFonts(const uint8_t* data, std::vector<uint16_t>& charset, Game::Glyph* glyphs, float pixel_height, unsigned char* pixels, int pw, int ph, int yOffset)
|
||||
{
|
||||
stbtt_fontinfo f;
|
||||
f.userdata = NULL;
|
||||
|
||||
if (!stbtt_InitFont(&f, data, 0))
|
||||
return -1;
|
||||
|
||||
std::memset(pixels, 0, pw * ph);
|
||||
|
||||
int x = 1, y = 1, bottom_y = 1;
|
||||
|
||||
float scale = stbtt_ScaleForPixelHeight(&f, pixel_height);
|
||||
|
||||
int i = 0;
|
||||
|
||||
for (auto& ch : charset)
|
||||
{
|
||||
int advance, lsb, x0, y0, x1, y1, gw, gh;
|
||||
|
||||
int g = stbtt_FindGlyphIndex(&f, ch);
|
||||
|
||||
stbtt_GetGlyphHMetrics(&f, g, &advance, &lsb);
|
||||
stbtt_GetGlyphBitmapBox(&f, g, scale, scale, &x0, &y0, &x1, &y1);
|
||||
|
||||
gw = x1 - x0;
|
||||
gh = y1 - y0;
|
||||
|
||||
if (x + gw + 1 >= pw)
|
||||
{
|
||||
// Advance to next row
|
||||
y = bottom_y;
|
||||
x = 1;
|
||||
}
|
||||
|
||||
if (y + gh + 1 >= ph)
|
||||
{
|
||||
// Check if we have ran out of the room
|
||||
return -i;
|
||||
}
|
||||
|
||||
stbtt_MakeGlyphBitmap(&f, pixels + x + y * pw, gw, gh, pw, scale, scale, g);
|
||||
|
||||
auto& glyph = glyphs[i++];
|
||||
|
||||
glyph.letter = ch;
|
||||
glyph.s0 = x / static_cast<float>(pw);
|
||||
glyph.s1 = (x + gw) / static_cast<float>(pw);
|
||||
glyph.t0 = y / static_cast<float>(ph);
|
||||
glyph.t1 = (y + gh) / static_cast<float>(ph);
|
||||
glyph.pixelWidth = static_cast<char>(gw);
|
||||
glyph.pixelHeight = static_cast<char>(gh);
|
||||
glyph.x0 = static_cast<char>(x0);
|
||||
glyph.y0 = static_cast<char>(y0 + yOffset);
|
||||
glyph.dx = static_cast<char>(roundf(scale * advance));
|
||||
|
||||
// Advance to next col
|
||||
x = x + gw + 1;
|
||||
|
||||
// Expand bottom of current row if current glyph is bigger
|
||||
if (y + gh + 1 > bottom_y)
|
||||
{
|
||||
bottom_y = y + gh + 1;
|
||||
}
|
||||
}
|
||||
|
||||
return bottom_y;
|
||||
}
|
||||
}
|
||||
|
||||
void IFont_s::mark(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder)
|
||||
{
|
||||
Game::Font_s *asset = header.font;
|
||||
@ -17,6 +92,157 @@ namespace Assets
|
||||
}
|
||||
}
|
||||
|
||||
void IFont_s::load(Game::XAssetHeader* header, const std::string& name, Components::ZoneBuilder::Zone*)
|
||||
{
|
||||
Components::FileSystem::File fontDefFile(Utils::String::VA("%s.json", name.data()));
|
||||
Components::FileSystem::File fontFile(Utils::String::VA("%s.ttf", name.data()));
|
||||
|
||||
if (fontDefFile.exists() && fontFile.exists())
|
||||
{
|
||||
std::string errors;
|
||||
auto fontDef = json11::Json::parse(fontDefFile.getBuffer(), errors);
|
||||
|
||||
if (!errors.empty())
|
||||
{
|
||||
Components::Logger::Error("Font define %s is broken: %s.", name.data(), errors.data());
|
||||
}
|
||||
|
||||
if (!fontDef.is_object())
|
||||
{
|
||||
Components::Logger::Error("Font define %s is invaild.", name.data(), errors.data());
|
||||
}
|
||||
|
||||
int w = fontDef["textureWidth"].int_value();
|
||||
int h = fontDef["textureHeight"].int_value();
|
||||
|
||||
int size = fontDef["size"].int_value();
|
||||
int yOffset = fontDef["yOffset"].int_value();
|
||||
|
||||
uint8_t* pixels = Utils::Memory::AllocateArray<uint8_t>(w * h);
|
||||
|
||||
// Setup assets
|
||||
auto* texName = Utils::Memory::DuplicateString(Utils::String::VA("if_%s", name.data() + 6 /* skip "fonts/" */));
|
||||
auto* fontName = Utils::Memory::DuplicateString(name.data());
|
||||
auto* glowMaterialName = Utils::Memory::DuplicateString(Utils::String::VA("%s_glow", name.data()));
|
||||
|
||||
auto* image = Utils::Memory::Duplicate(Game::DB_FindXAssetHeader(Game::ASSET_TYPE_IMAGE, "gamefonts_pc").image);
|
||||
image->name = texName;
|
||||
|
||||
auto* material = Utils::Memory::Duplicate(Game::DB_FindXAssetHeader(Game::ASSET_TYPE_MATERIAL, "fonts/gamefonts_pc").material);
|
||||
material->textureTable = Utils::Memory::Duplicate(material->textureTable);
|
||||
material->textureTable->u.image = image;
|
||||
material->info.name = fontName;
|
||||
|
||||
auto* glowMaterial = Utils::Memory::Duplicate(Game::DB_FindXAssetHeader(Game::ASSET_TYPE_MATERIAL, "fonts/gamefonts_pc_glow").material);
|
||||
glowMaterial->textureTable = material->textureTable;
|
||||
glowMaterial->info.name = glowMaterialName;
|
||||
|
||||
std::vector<uint16_t> charset;
|
||||
|
||||
if (fontDef["charset"].is_array())
|
||||
{
|
||||
for (auto& ch : fontDef["charset"].array_items())
|
||||
charset.push_back(static_cast<uint16_t>(ch.int_value()));
|
||||
|
||||
// order matters
|
||||
std::sort(charset.begin(), charset.end());
|
||||
|
||||
for (uint16_t i = 32; i < 128; i++)
|
||||
{
|
||||
if (std::find(charset.begin(), charset.end(), i) == charset.end())
|
||||
{
|
||||
Components::Logger::Error("Font %s missing codepoint %d.", name.data(), i);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (uint16_t i = 32; i < 128; i++)
|
||||
charset.push_back(i);
|
||||
}
|
||||
|
||||
auto* font = Utils::Memory::Allocate<Game::Font_s>();
|
||||
|
||||
font->fontName = fontName;
|
||||
font->pixelHeight = size;
|
||||
font->material = material;
|
||||
font->glowMaterial = glowMaterial;
|
||||
font->glyphCount = charset.size();
|
||||
font->glyphs = Utils::Memory::AllocateArray<Game::Glyph>(charset.size());
|
||||
|
||||
// Generate glyph data
|
||||
int result = PackFonts(reinterpret_cast<const uint8_t*>(fontFile.getBuffer().data()), charset, font->glyphs, static_cast<float>(size), pixels, w, h, yOffset);
|
||||
|
||||
if (result == -1)
|
||||
{
|
||||
Components::Logger::Error("Truetype font %s is broken.", name.data());
|
||||
}
|
||||
else if (result < 0)
|
||||
{
|
||||
Components::Logger::Error("Texture size of font %s is not enough.", name.data());
|
||||
}
|
||||
else if(h - result > size)
|
||||
{
|
||||
Components::Logger::Print("Warn: Texture of font %s have too much left over space: %d\n", name.data(), h - result);
|
||||
}
|
||||
|
||||
header->font = font;
|
||||
|
||||
// Save generated materials
|
||||
Game::XAssetHeader tmpHeader;
|
||||
|
||||
tmpHeader.image = image;
|
||||
Components::AssetHandler::StoreTemporaryAsset(Game::ASSET_TYPE_IMAGE, tmpHeader);
|
||||
|
||||
tmpHeader.material = material;
|
||||
Components::AssetHandler::StoreTemporaryAsset(Game::ASSET_TYPE_MATERIAL, tmpHeader);
|
||||
|
||||
tmpHeader.material = glowMaterial;
|
||||
Components::AssetHandler::StoreTemporaryAsset(Game::ASSET_TYPE_MATERIAL, tmpHeader);
|
||||
|
||||
// Save generated image
|
||||
Utils::IO::CreateDir("userraw\\images");
|
||||
|
||||
int fileSize = w * h * 4;
|
||||
int iwiHeaderSize = static_cast<int>(sizeof(Game::GfxImageFileHeader));
|
||||
|
||||
Game::GfxImageFileHeader iwiHeader =
|
||||
{
|
||||
{ 'I', 'W', 'i' },
|
||||
/* version */
|
||||
8,
|
||||
/* flags */
|
||||
2,
|
||||
/* format */
|
||||
Game::IMG_FORMAT_BITMAP_RGBA,
|
||||
0,
|
||||
/* dimensions(x, y, z) */
|
||||
{ static_cast<short>(w), static_cast<short>(h), 1 },
|
||||
/* fileSizeForPicmip (mipSize in bytes + sizeof(GfxImageFileHeader)) */
|
||||
{ fileSize + iwiHeaderSize, fileSize, fileSize, fileSize }
|
||||
};
|
||||
|
||||
std::string outIwi;
|
||||
outIwi.resize(fileSize + sizeof(Game::GfxImageFileHeader));
|
||||
|
||||
std::memcpy(outIwi.data(), &iwiHeader, sizeof(Game::GfxImageFileHeader));
|
||||
|
||||
// Generate RGBA data
|
||||
auto* rgbaPixels = outIwi.data() + sizeof(Game::GfxImageFileHeader);
|
||||
|
||||
for (int i = 0; i < w * h * 4; i += 4)
|
||||
{
|
||||
rgbaPixels[i + 0] = static_cast<char>(255);
|
||||
rgbaPixels[i + 1] = static_cast<char>(255);
|
||||
rgbaPixels[i + 2] = static_cast<char>(255);
|
||||
rgbaPixels[i + 3] = static_cast<char>(pixels[i / 4]);
|
||||
}
|
||||
|
||||
Utils::IO::WriteFile(Utils::String::VA("userraw\\images\\%s.iwi", texName), outIwi);
|
||||
Utils::Memory::Free(pixels);
|
||||
}
|
||||
}
|
||||
|
||||
void IFont_s::save(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder)
|
||||
{
|
||||
AssertSize(Game::Font_s, 24);
|
||||
|
@ -9,6 +9,6 @@ namespace Assets
|
||||
|
||||
virtual void save(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder) override;
|
||||
virtual void mark(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder) override;
|
||||
// virtual void load(Game::XAssetHeader* header, std::string name, Components::ZoneBuilder::Zone* builder) override;
|
||||
virtual void load(Game::XAssetHeader* header, const std::string& name, Components::ZoneBuilder::Zone* builder) override;
|
||||
};
|
||||
}
|
||||
|
@ -36,12 +36,13 @@ namespace Assets
|
||||
{"effect_zfeather", "effect_zfeather_blend"},
|
||||
|
||||
{"wc_unlit_add", "wc_unlit_add_lin"},
|
||||
{"wc_unlit_distfalloff", "wc_unlit_distfalloff_replace"},
|
||||
{"wc_unlit_multiply", "wc_unlit_multiply_lin"},
|
||||
{"wc_unlit_falloff_add", "wc_unlit_falloff_add_lin_ua"},
|
||||
{"wc_unlit", "wc_unlit_add_lin"},
|
||||
{"wc_unlit_alphatest", "wc_unlit_blend_lin_ua"},
|
||||
{"wc_unlit", "wc_unlit_replace_lin"},
|
||||
{"wc_unlit_alphatest", "wc_unlit_blend_lin"},
|
||||
{"wc_unlit_multiply_lin", "wc_unlit_multiply_lin"},
|
||||
{"wc_unlit_blend", "wc_unlit_blend_lin"},
|
||||
{"wc_unlit_blend", "wc_unlit_blend_lin_ua"},
|
||||
{"wc_unlit_replace", "wc_unlit_replace_lin"},
|
||||
|
||||
{"mc_unlit_replace", "mc_unlit_replace_lin"},
|
||||
@ -83,38 +84,41 @@ namespace Assets
|
||||
|
||||
if (asset->techniqueSet)
|
||||
{
|
||||
std::string techset = reader.readString();
|
||||
if (!techset.empty() && techset.front() == ',') techset.erase(techset.begin());
|
||||
asset->techniqueSet = Components::AssetHandler::FindAssetForZone(Game::XAssetType::ASSET_TYPE_TECHNIQUE_SET, techset.data(), builder).techniqueSet;
|
||||
std::string techsetName = reader.readString();
|
||||
if (!techsetName.empty() && techsetName.front() == ',') techsetName.erase(techsetName.begin());
|
||||
asset->techniqueSet = Components::AssetHandler::FindAssetForZone(Game::XAssetType::ASSET_TYPE_TECHNIQUE_SET, techsetName.data(), builder).techniqueSet;
|
||||
|
||||
if (!asset->techniqueSet)
|
||||
{
|
||||
// Workaround for effect techsets having _nofog suffix
|
||||
std::string suffix;
|
||||
if (Utils::String::StartsWith(techset, "effect_") && Utils::String::EndsWith(techset, "_nofog"))
|
||||
if (Utils::String::StartsWith(techsetName, "effect_") && Utils::String::EndsWith(techsetName, "_nofog"))
|
||||
{
|
||||
suffix = "_nofog";
|
||||
Utils::String::Replace(techset, suffix, "");
|
||||
Utils::String::Replace(techsetName, suffix, "");
|
||||
}
|
||||
|
||||
for (int i = 0; i < ARRAYSIZE(techsetSuffix); ++i)
|
||||
{
|
||||
Game::MaterialTechniqueSet* techsetPtr = Components::AssetHandler::FindAssetForZone(Game::XAssetType::ASSET_TYPE_TECHNIQUE_SET, (techset + techsetSuffix[i] + suffix).data(), builder).techniqueSet;
|
||||
Game::MaterialTechniqueSet* techsetPtr = Components::AssetHandler::FindAssetForZone(Game::XAssetType::ASSET_TYPE_TECHNIQUE_SET, (techsetName + techsetSuffix[i] + suffix).data(), builder).techniqueSet;
|
||||
|
||||
if (techsetPtr)
|
||||
{
|
||||
asset->techniqueSet = techsetPtr;
|
||||
|
||||
if (asset->techniqueSet->name[0] == ',') continue; // Try to find a better one
|
||||
Components::Logger::Print("Techset '%s' has been mapped to '%s'\n", techset.data(), asset->techniqueSet->name);
|
||||
Components::Logger::Print("Techset '%s' has been mapped to '%s'\n", techsetName.data(), asset->techniqueSet->name);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
Components::Logger::Print("Techset %s exists with the same name in iw4, and was mapped 1:1 with %s\n", techsetName.data(), asset->techniqueSet->name);
|
||||
}
|
||||
|
||||
if (!asset->techniqueSet)
|
||||
{
|
||||
Components::Logger::Error("Missing techset: '%s' not found", techset.data());
|
||||
Components::Logger::Error("Missing techset: '%s' not found", techsetName.data());
|
||||
}
|
||||
}
|
||||
|
||||
@ -254,7 +258,7 @@ namespace Assets
|
||||
|
||||
if (header.material->techniqueSet == iw4TechSet->asset.header.techniqueSet)
|
||||
{
|
||||
Components::Logger::Print("Material %s with techset %s has been mapped to %s (last chance!)\n", asset->info.name, asset->techniqueSet->name, header.material->techniqueSet->name);
|
||||
Components::Logger::Print("Material %s with techset %s has been mapped to %s (last chance!), taking the sort key of material %s\n", asset->info.name, asset->techniqueSet->name, header.material->techniqueSet->name, header.material->info.name);
|
||||
asset->info.sortKey = header.material->info.sortKey;
|
||||
asset->techniqueSet = iw4TechSet->asset.header.techniqueSet;
|
||||
|
||||
|
@ -3,6 +3,10 @@
|
||||
namespace Components
|
||||
{
|
||||
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)
|
||||
@ -218,8 +222,69 @@ namespace Components
|
||||
}
|
||||
}
|
||||
|
||||
// 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);
|
||||
|
||||
@ -239,7 +304,7 @@ namespace Components
|
||||
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˛ color code style.");
|
||||
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");
|
||||
|
||||
|
@ -22,6 +22,9 @@ namespace Components
|
||||
};
|
||||
|
||||
static Dvar::Var NewColors;
|
||||
static Dvar::Var ColorBlind;
|
||||
static Game::dvar_t* ColorAllyColorBlind;
|
||||
static Game::dvar_t* ColorEnemyColorBlind;
|
||||
|
||||
static DWORD HsvToRgb(HsvColor hsv);
|
||||
|
||||
@ -35,6 +38,8 @@ namespace Components
|
||||
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;
|
||||
};
|
||||
}
|
||||
|
@ -193,6 +193,7 @@ namespace Components
|
||||
"Killera",
|
||||
"Lithium",
|
||||
"Louvenarde",
|
||||
"FutureRave",
|
||||
"OneFourOne",
|
||||
"quaK",
|
||||
"RaidMax",
|
||||
|
@ -60,7 +60,7 @@ namespace Components
|
||||
UIScript::Add("visitWiki", [](UIScript::Token)
|
||||
{
|
||||
//Utils::OpenUrl(Utils::Cache::GetStaticUrl("/wiki/"));
|
||||
Utils::OpenUrl("https://github.com/Jawesome99/IW4x/wiki");
|
||||
Utils::OpenUrl("https://github.com/Emosewaj/IW4x/wiki");
|
||||
});
|
||||
|
||||
UIScript::Add("visitDiscord", [](UIScript::Token)
|
||||
|
@ -341,9 +341,6 @@ namespace Components
|
||||
|
||||
// original code
|
||||
mov eax, dword ptr[esp + 0xa0];
|
||||
jmp collide;
|
||||
|
||||
collide:
|
||||
push 0x00478376;
|
||||
retn;
|
||||
|
||||
@ -374,11 +371,6 @@ namespace Components
|
||||
// dont eject if g_playerEjection is set to 0
|
||||
je donteject;
|
||||
|
||||
// original code
|
||||
cmp dword ptr[ebx + 19ch], edi;
|
||||
jle eject;
|
||||
|
||||
eject:
|
||||
push 0x005d8152;
|
||||
retn;
|
||||
|
||||
@ -388,12 +380,32 @@ namespace Components
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T> std::function < T > ImportFunction(const std::string& dll, const std::string& function)
|
||||
BOOL QuickPatch::IsDynClassnameStub(char* a1)
|
||||
{
|
||||
auto dllHandle = GetModuleHandleA(&dll[0]);
|
||||
auto procAddr = GetProcAddress(dllHandle, &function[0]);
|
||||
auto version = Zones::GetEntitiesZoneVersion();
|
||||
|
||||
return std::function < T >(reinterpret_cast<T*>(procAddr));
|
||||
if (version >= VERSION_LATEST_CODO)
|
||||
{
|
||||
for (auto i = 0; i < Game::spawnVars->numSpawnVars; i++)
|
||||
{
|
||||
char** kvPair = Game::spawnVars->spawnVars[i];
|
||||
auto key = kvPair[0];
|
||||
auto val = kvPair[1];
|
||||
|
||||
bool isSpecOps = strncmp(key, "script_specialops", 17) == 0;
|
||||
bool isSpecOpsOnly = val[0] == '1' && val[1] == '\0';
|
||||
|
||||
if (isSpecOps && isSpecOpsOnly)
|
||||
{
|
||||
// This will prevent spawning of any entity that contains "script_specialops: '1'"
|
||||
// It removes extra hitboxes / meshes on 461+ CODO multiplayer maps
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Passthrough to the game's own IsDynClassname
|
||||
return Utils::Hook::Call<BOOL(char*)>(0x444810)(a1);
|
||||
}
|
||||
|
||||
QuickPatch::QuickPatch()
|
||||
@ -407,38 +419,15 @@ namespace Components
|
||||
// quit_hard
|
||||
Command::Add("quit_hard", [](Command::Params*)
|
||||
{
|
||||
typedef enum _HARDERROR_RESPONSE_OPTION {
|
||||
OptionAbortRetryIgnore,
|
||||
OptionOk,
|
||||
OptionOkCancel,
|
||||
OptionRetryCancel,
|
||||
OptionYesNo,
|
||||
OptionYesNoCancel,
|
||||
OptionShutdownSystem
|
||||
} HARDERROR_RESPONSE_OPTION, *PHARDERROR_RESPONSE_OPTION;
|
||||
|
||||
typedef enum _HARDERROR_RESPONSE {
|
||||
ResponseReturnToCaller,
|
||||
ResponseNotHandled,
|
||||
ResponseAbort,
|
||||
ResponseCancel,
|
||||
ResponseIgnore,
|
||||
ResponseNo,
|
||||
ResponseOk,
|
||||
ResponseRetry,
|
||||
ResponseYes
|
||||
} HARDERROR_RESPONSE, *PHARDERROR_RESPONSE;
|
||||
|
||||
BOOLEAN hasPerms;
|
||||
HARDERROR_RESPONSE response;
|
||||
|
||||
auto result = ImportFunction<NTSTATUS __stdcall(ULONG, BOOLEAN, BOOLEAN, PBOOLEAN)>("ntdll.dll", "RtlAdjustPrivilege")
|
||||
(19, true, false, &hasPerms);
|
||||
|
||||
result = ImportFunction<NTSTATUS __stdcall(NTSTATUS, ULONG, LPCSTR, PVOID, HARDERROR_RESPONSE_OPTION, PHARDERROR_RESPONSE)>("ntdll.dll", "NtRaiseHardError")
|
||||
(0xC000007B /*0x0000000A*/, 0, nullptr, nullptr, OptionShutdownSystem, &response);
|
||||
int data = false;
|
||||
const Utils::Library ntdll("ntdll.dll");
|
||||
ntdll.InvokePascal<void>("RtlAdjustPrivilege", 19, true, false, &data);
|
||||
ntdll.InvokePascal<void>("NtRaiseHardError", 0xC000007B, 0, nullptr, nullptr, 6, &data);
|
||||
});
|
||||
|
||||
// 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();
|
||||
|
||||
// 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();
|
||||
|
@ -47,5 +47,6 @@ namespace Components
|
||||
static void PlayerCollisionStub();
|
||||
static Game::dvar_t* g_playerEjection;
|
||||
static void PlayerEjectionStub();
|
||||
static BOOL IsDynClassnameStub(char* a1);
|
||||
};
|
||||
}
|
||||
|
@ -25,9 +25,14 @@ namespace Components
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!RCon::Password.empty() && *reinterpret_cast<int*>(0xB2C540) >= 5) // Get our state
|
||||
auto addr = reinterpret_cast<Game::netadr_t*>(0xA5EA44);
|
||||
if (!RCon::Password.empty())
|
||||
{
|
||||
Network::Address target(reinterpret_cast<Game::netadr_t*>(0xA5EA44));
|
||||
Network::Address target(addr);
|
||||
if (!target.isValid() || target.getIP().full == 0)
|
||||
{
|
||||
target = Party::Target();
|
||||
}
|
||||
|
||||
if (target.isValid())
|
||||
{
|
||||
@ -71,6 +76,7 @@ namespace Components
|
||||
Dvar::OnInit([]()
|
||||
{
|
||||
Dvar::Register<const char*>("rcon_password", "", Game::dvar_flag::DVAR_FLAG_NONE, "The password for rcon");
|
||||
Dvar::Register<bool>("log_rcon_requests", false, Game::dvar_flag::DVAR_FLAG_NONE, "Print remote commands in the output log");
|
||||
});
|
||||
|
||||
Network::Handle("rcon", [](Network::Address address, const std::string& _data)
|
||||
@ -107,9 +113,12 @@ namespace Components
|
||||
static std::string outputBuffer;
|
||||
outputBuffer.clear();
|
||||
|
||||
#ifdef DEBUG
|
||||
Logger::Print("Executing RCon request from %s: %s\n", address.getCString(), command.data());
|
||||
#ifndef DEBUG
|
||||
if (Dvar::Var("log_rcon_requests").get<bool>())
|
||||
#endif
|
||||
{
|
||||
Logger::Print("Executing RCon request from %s: %s\n", address.getCString(), command.data());
|
||||
}
|
||||
|
||||
Logger::PipeOutput([](const std::string& output)
|
||||
{
|
||||
|
@ -378,7 +378,7 @@ namespace Components
|
||||
|
||||
Game::XFileHeader header =
|
||||
{
|
||||
#ifdef DEBUG
|
||||
#ifndef GENERATE_IW4X_SPECIFIC_ZONES
|
||||
XFILE_MAGIC_UNSIGNED,
|
||||
#else
|
||||
XFILE_HEADER_IW4X | (static_cast<unsigned __int64>(XFILE_VERSION_IW4X) << 32),
|
||||
@ -394,7 +394,7 @@ namespace Components
|
||||
|
||||
std::string zoneBuffer = this->buffer.toBuffer();
|
||||
|
||||
#ifndef DEBUG
|
||||
#ifdef GENERATE_IW4X_SPECIFIC_ZONES
|
||||
// Insert a random byte, this will destroy the whole alignment and result in a crash, if not handled
|
||||
zoneBuffer.insert(zoneBuffer.begin(), static_cast<char>(Utils::Cryptography::Rand::GenerateInt()));
|
||||
|
||||
@ -844,7 +844,7 @@ namespace Components
|
||||
|
||||
Command::Add("quit", [](Command::Params*)
|
||||
{
|
||||
ZoneBuilder::Quit();
|
||||
Game::Com_Quitf_t();
|
||||
});
|
||||
|
||||
Command::Add("error", [](Command::Params*)
|
||||
@ -921,12 +921,6 @@ namespace Components
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ZoneBuilder::Quit()
|
||||
{
|
||||
//TerminateProcess(GetCurrentProcess(), 0);
|
||||
ExitProcess(0);
|
||||
}
|
||||
|
||||
void ZoneBuilder::HandleError(int level, const char* format, ...)
|
||||
{
|
||||
char buffer[256] = { 0 };
|
||||
@ -1088,9 +1082,6 @@ namespace Components
|
||||
// set new entry point
|
||||
Utils::Hook(0x4513DA, ZoneBuilder::EntryPoint, HOOK_JUMP).install()->quick();
|
||||
|
||||
// set quit handler
|
||||
Utils::Hook(0x4D4000, ZoneBuilder::Quit, HOOK_JUMP).install()->quick();
|
||||
|
||||
// handle com_error calls
|
||||
Utils::Hook(0x4B22D0, ZoneBuilder::HandleError, HOOK_JUMP).install()->quick();
|
||||
|
||||
|
@ -138,7 +138,6 @@ namespace Components
|
||||
static std::string FindMaterialByTechnique(const std::string& name);
|
||||
|
||||
static int __stdcall EntryPoint(HINSTANCE /*hInstance*/, HINSTANCE /*hPrevInstance*/, LPSTR /*lpCmdLine*/, int /*nShowCmd*/);
|
||||
static void Quit();
|
||||
static void HandleError(int level, const char* format, ...);
|
||||
static void SoftErrorAssetOverflow();
|
||||
|
||||
|
@ -4,10 +4,63 @@
|
||||
namespace Components
|
||||
{
|
||||
int Zones::ZoneVersion;
|
||||
int Zones::EntitiesVersion;
|
||||
|
||||
int Zones::FxEffectIndex;
|
||||
char* Zones::FxEffectStrings[64];
|
||||
|
||||
static std::unordered_map<std::string, std::string> shellshock_replace_list = {
|
||||
{ "66","bg_shock_screenType" },
|
||||
{ "67","bg_shock_screenBlurBlendTime"},
|
||||
{ "68","bg_shock_screenBlurBlendFadeTime"},
|
||||
{ "69","bg_shock_screenFlashWhiteFadeTime"},
|
||||
{ "70","bg_shock_screenFlashShotFadeTime"},
|
||||
{ "71","bg_shock_viewKickPeriod"},
|
||||
{ "72","bg_shock_viewKickRadius"},
|
||||
{ "73","bg_shock_viewKickFadeTime"},
|
||||
{ "78","bg_shock_sound"},
|
||||
{ "74","bg_shock_soundLoop"},
|
||||
{ "75","bg_shock_soundLoopSilent"},
|
||||
{ "76","bg_shock_soundEnd"},
|
||||
{ "77","bg_shock_soundEndAbort"},
|
||||
{ "79","bg_shock_soundFadeInTime"},
|
||||
{ "80","bg_shock_soundFadeOutTime"},
|
||||
{ "81","bg_shock_soundLoopFadeTime"},
|
||||
{ "82","bg_shock_soundLoopEndDelay"},
|
||||
{ "83","bg_shock_soundRoomType"},
|
||||
{ "84","bg_shock_soundDryLevel"},
|
||||
{ "85","bg_shock_soundWetLevel"},
|
||||
{ "86","bg_shock_soundModEndDelay"},
|
||||
|
||||
// guessed, not sure
|
||||
{ "87","bg_shock_lookControl"},
|
||||
{ "88","bg_shock_lookControl_maxpitchspeed"},
|
||||
{ "89","bg_shock_lookControl_maxyawspeed"},
|
||||
{ "90","bg_shock_lookControl_mousesensitivityscale"},
|
||||
{ "91","bg_shock_lookControl_fadeTime"},
|
||||
{ "92","bg_shock_movement"}
|
||||
};
|
||||
|
||||
static std::unordered_map<std::string, std::string> vision_replace_list = {
|
||||
{ "511","r_glow" },
|
||||
{ "516","r_glowRadius0" },
|
||||
{ "512","r_glowBloomCutoff" },
|
||||
{ "513","r_glowBloomDesaturation" },
|
||||
{ "514","r_glowBloomIntensity0" },
|
||||
{ "520","r_filmEnable" },
|
||||
{ "522","r_filmContrast" },
|
||||
{ "521","r_filmBrightness" },
|
||||
{ "523","r_filmDesaturation" },
|
||||
{ "524","r_filmDesaturationDark" },
|
||||
{ "525","r_filmInvert" },
|
||||
{ "526","r_filmLightTint" },
|
||||
{ "527","r_filmMediumTint" },
|
||||
{ "528","r_filmDarkTint" },
|
||||
{ "529","r_primaryLightUseTweaks" },
|
||||
{ "530","r_primaryLightTweakDiffuseStrength" },
|
||||
{ "531","r_primaryLightTweakSpecularStrength" },
|
||||
};
|
||||
|
||||
Game::XAssetType currentAssetType = Game::XAssetType::ASSET_TYPE_INVALID;
|
||||
Game::XAssetType previousAssetType = Game::XAssetType::ASSET_TYPE_INVALID;
|
||||
|
||||
@ -223,30 +276,20 @@ namespace Components
|
||||
|
||||
int size = 3112;
|
||||
|
||||
if (Zones::ZoneVersion >= 318)
|
||||
{
|
||||
if (Zones::ZoneVersion >= 461)
|
||||
size = 4124;
|
||||
else if (Zones::ZoneVersion >= 460)
|
||||
size = 4120;
|
||||
else if (Zones::ZoneVersion >= 365)
|
||||
size = 3124;
|
||||
else if (Zones::ZoneVersion >= 359)
|
||||
size = 3120;
|
||||
else if (Zones::ZoneVersion >= 332)
|
||||
size = 3068;
|
||||
else if (Zones::ZoneVersion >= 318)
|
||||
size = 3156;
|
||||
|
||||
if (Zones::ZoneVersion >= 332)
|
||||
{
|
||||
size = 3068; // We didn't adapt that, but who the fuck cares!
|
||||
|
||||
if (Zones::ZoneVersion >= 359)
|
||||
{
|
||||
size = 3120;
|
||||
|
||||
if (Zones::ZoneVersion >= 365)
|
||||
{
|
||||
size = 3124;
|
||||
|
||||
if (Zones::ZoneVersion >= 460)
|
||||
{
|
||||
size = 4120;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
int offsetShift = (Zones::ZoneVersion >= 461) ? 4 : 0;
|
||||
|
||||
// and do the stuff
|
||||
Game::Load_Stream(true, varWeaponCompleteDef, size);
|
||||
@ -270,7 +313,7 @@ namespace Components
|
||||
|
||||
if (Zones::ZoneVersion >= 359)
|
||||
{
|
||||
auto count = (Zones::Version() == 460) ? 52 : 56;
|
||||
auto count = (Zones::Version() >= 460) ? 52 : 56;
|
||||
for (int offset = 20; offset <= count; offset += 4)
|
||||
{
|
||||
*Game::varXModelPtr = reinterpret_cast<Game::XModel**>(varWeaponCompleteDef + offset);
|
||||
@ -299,7 +342,7 @@ namespace Components
|
||||
|
||||
if (Zones::ZoneVersion >= 359)
|
||||
{
|
||||
auto stringCount = (Zones::Version() == 460) ? 62 : 52;
|
||||
auto stringCount = (Zones::Version() >= 460) ? 62 : 52;
|
||||
auto arraySize = stringCount * 4;
|
||||
|
||||
// 236
|
||||
@ -395,8 +438,8 @@ namespace Components
|
||||
// 980
|
||||
if (Zones::ZoneVersion >= 359)
|
||||
{
|
||||
auto offset = (Zones::Version() == 460) ? 1476 : 916;
|
||||
auto count = (Zones::Version() == 460) ? 57 : 52;
|
||||
auto offset = (Zones::Version() >= 460) ? 1476 : 916;
|
||||
auto count = (Zones::Version() >= 461) ? 58 : (Zones::Version() >= 460) ? 57 : 52;
|
||||
|
||||
// 53 soundalias name references; up to and including 1124
|
||||
for (int i = 0; i < count; ++i, offset += 4)
|
||||
@ -809,7 +852,7 @@ namespace Components
|
||||
void* vec2 = Game::DB_AllocStreamPos(3);
|
||||
*reinterpret_cast<void**>(varWeaponCompleteDef + 3204) = vec2;
|
||||
|
||||
Game::Load_Stream(true, vec2, 8 * *reinterpret_cast<short*>(varWeaponCompleteDef + 3776));
|
||||
Game::Load_Stream(true, vec2, 8 * *reinterpret_cast<short*>(varWeaponCompleteDef + 3776 + offsetShift));
|
||||
}
|
||||
|
||||
*Game::varXString = reinterpret_cast<char**>(varWeaponCompleteDef + 3200);
|
||||
@ -820,7 +863,7 @@ namespace Components
|
||||
void* vec2 = Game::DB_AllocStreamPos(3);
|
||||
*reinterpret_cast<void**>(varWeaponCompleteDef + 3208) = vec2;
|
||||
|
||||
Game::Load_Stream(true, vec2, 8 * *reinterpret_cast<short*>(varWeaponCompleteDef + 3778));
|
||||
Game::Load_Stream(true, vec2, 8 * *reinterpret_cast<short*>(varWeaponCompleteDef + 3778 + offsetShift));
|
||||
}
|
||||
}
|
||||
else if (Zones::ZoneVersion >= 359)
|
||||
@ -868,22 +911,22 @@ namespace Components
|
||||
|
||||
if (Zones::Version() >= 460)
|
||||
{
|
||||
*Game::varXString = reinterpret_cast<char**>(varWeaponCompleteDef + 3288);
|
||||
*Game::varXString = reinterpret_cast<char**>(varWeaponCompleteDef + 3288 + offsetShift);
|
||||
Game::Load_XString(false);
|
||||
|
||||
*Game::varXString = reinterpret_cast<char**>(varWeaponCompleteDef + 3292);
|
||||
*Game::varXString = reinterpret_cast<char**>(varWeaponCompleteDef + 3292 + offsetShift);
|
||||
Game::Load_XString(false);
|
||||
|
||||
*Game::varXString = reinterpret_cast<char**>(varWeaponCompleteDef + 3324);
|
||||
*Game::varXString = reinterpret_cast<char**>(varWeaponCompleteDef + 3324 + offsetShift);
|
||||
Game::Load_XString(false);
|
||||
|
||||
*Game::varXString = reinterpret_cast<char**>(varWeaponCompleteDef + 3328);
|
||||
*Game::varXString = reinterpret_cast<char**>(varWeaponCompleteDef + 3328 + offsetShift);
|
||||
Game::Load_XString(false);
|
||||
|
||||
*Game::varXString = reinterpret_cast<char**>(varWeaponCompleteDef + 3484);
|
||||
*Game::varXString = reinterpret_cast<char**>(varWeaponCompleteDef + 3484 + offsetShift);
|
||||
Game::Load_XString(false);
|
||||
|
||||
*Game::varXString = reinterpret_cast<char**>(varWeaponCompleteDef + 3488);
|
||||
*Game::varXString = reinterpret_cast<char**>(varWeaponCompleteDef + 3488 + offsetShift);
|
||||
Game::Load_XString(false);
|
||||
}
|
||||
else if (Zones::ZoneVersion >= 359)
|
||||
@ -929,37 +972,37 @@ namespace Components
|
||||
|
||||
if (Zones::Version() >= 460)
|
||||
{
|
||||
*Game::varTracerDefPtr = reinterpret_cast<Game::TracerDef * *>(varWeaponCompleteDef + 3492);
|
||||
*Game::varTracerDefPtr = reinterpret_cast<Game::TracerDef * *>(varWeaponCompleteDef + 3492 + offsetShift);
|
||||
Game::Load_TracerDefPtr(false);
|
||||
|
||||
*Game::varTracerDefPtr = reinterpret_cast<Game::TracerDef * *>(varWeaponCompleteDef + 3496);
|
||||
*Game::varTracerDefPtr = reinterpret_cast<Game::TracerDef * *>(varWeaponCompleteDef + 3496 + offsetShift);
|
||||
Game::Load_TracerDefPtr(false);
|
||||
|
||||
*Game::varTracerDefPtr = reinterpret_cast<Game::TracerDef * *>(varWeaponCompleteDef + 3500);
|
||||
*Game::varTracerDefPtr = reinterpret_cast<Game::TracerDef * *>(varWeaponCompleteDef + 3500 + offsetShift);
|
||||
Game::Load_TracerDefPtr(false);
|
||||
|
||||
*Game::varsnd_alias_list_name = reinterpret_cast<Game::snd_alias_list_t * *>(varWeaponCompleteDef + 3528);
|
||||
*Game::varsnd_alias_list_name = reinterpret_cast<Game::snd_alias_list_t * *>(varWeaponCompleteDef + 3528 + offsetShift);
|
||||
Game::Load_SndAliasCustom(*Game::varsnd_alias_list_name); // 2848
|
||||
|
||||
*Game::varFxEffectDefHandle = reinterpret_cast<Game::FxEffectDef * *>(varWeaponCompleteDef + 3532);
|
||||
*Game::varFxEffectDefHandle = reinterpret_cast<Game::FxEffectDef * *>(varWeaponCompleteDef + 3532 + offsetShift);
|
||||
Game::Load_FxEffectDefHandle(false);
|
||||
|
||||
*Game::varXString = reinterpret_cast<char**>(varWeaponCompleteDef + 3536);
|
||||
*Game::varXString = reinterpret_cast<char**>(varWeaponCompleteDef + 3536 + offsetShift);
|
||||
Game::Load_XString(false);
|
||||
|
||||
*Game::varsnd_alias_list_name = reinterpret_cast<Game::snd_alias_list_t * *>(varWeaponCompleteDef + 3552);
|
||||
*Game::varsnd_alias_list_name = reinterpret_cast<Game::snd_alias_list_t * *>(varWeaponCompleteDef + 3552 + offsetShift);
|
||||
Game::Load_SndAliasCustom(*Game::varsnd_alias_list_name);
|
||||
|
||||
*Game::varsnd_alias_list_name = reinterpret_cast<Game::snd_alias_list_t * *>(varWeaponCompleteDef + 3556);
|
||||
*Game::varsnd_alias_list_name = reinterpret_cast<Game::snd_alias_list_t * *>(varWeaponCompleteDef + 3556 + offsetShift);
|
||||
Game::Load_snd_alias_list_nameArray(false, 4);
|
||||
|
||||
*Game::varsnd_alias_list_name = reinterpret_cast<Game::snd_alias_list_t * *>(varWeaponCompleteDef + 3572);
|
||||
*Game::varsnd_alias_list_name = reinterpret_cast<Game::snd_alias_list_t * *>(varWeaponCompleteDef + 3572 + offsetShift);
|
||||
Game::Load_snd_alias_list_nameArray(false, 4);
|
||||
|
||||
*Game::varsnd_alias_list_name = reinterpret_cast<Game::snd_alias_list_t * *>(varWeaponCompleteDef + 3588);
|
||||
*Game::varsnd_alias_list_name = reinterpret_cast<Game::snd_alias_list_t * *>(varWeaponCompleteDef + 3588 + offsetShift);
|
||||
Game::Load_SndAliasCustom(*Game::varsnd_alias_list_name);
|
||||
|
||||
*Game::varsnd_alias_list_name = reinterpret_cast<Game::snd_alias_list_t * *>(varWeaponCompleteDef + 3592);
|
||||
*Game::varsnd_alias_list_name = reinterpret_cast<Game::snd_alias_list_t * *>(varWeaponCompleteDef + 3592 + offsetShift);
|
||||
Game::Load_SndAliasCustom(*Game::varsnd_alias_list_name);
|
||||
}
|
||||
else if (Zones::ZoneVersion >= 359)
|
||||
@ -1023,7 +1066,7 @@ namespace Components
|
||||
|
||||
if (Zones::Version() >= 460)
|
||||
{
|
||||
for (int i = 0, offset = 3660; i < 6; ++i, offset += 4)
|
||||
for (int i = 0, offset = 3660 + offsetShift; i < 6; ++i, offset += 4)
|
||||
{
|
||||
*Game::varsnd_alias_list_name = reinterpret_cast<Game::snd_alias_list_t * *>(varWeaponCompleteDef + offset);
|
||||
Game::Load_SndAliasCustom(*Game::varsnd_alias_list_name);
|
||||
@ -1058,25 +1101,25 @@ namespace Components
|
||||
|
||||
if (Zones::Version() >= 460)
|
||||
{
|
||||
*Game::varXString = reinterpret_cast<char**>(varWeaponCompleteDef + 3712);
|
||||
*Game::varXString = reinterpret_cast<char**>(varWeaponCompleteDef + 3712 + offsetShift);
|
||||
Game::Load_XString(false);
|
||||
|
||||
*Game::varXString = reinterpret_cast<char**>(varWeaponCompleteDef + 3728);
|
||||
*Game::varXString = reinterpret_cast<char**>(varWeaponCompleteDef + 3728 + offsetShift);
|
||||
Game::Load_XString(false);
|
||||
|
||||
*Game::varXString = reinterpret_cast<char**>(varWeaponCompleteDef + 3732);
|
||||
*Game::varXString = reinterpret_cast<char**>(varWeaponCompleteDef + 3732 + offsetShift);
|
||||
Game::Load_XString(false);
|
||||
|
||||
*Game::varMaterialHandle = reinterpret_cast<Game::Material * *>(varWeaponCompleteDef + 3740);
|
||||
*Game::varMaterialHandle = reinterpret_cast<Game::Material * *>(varWeaponCompleteDef + 3740 + offsetShift);
|
||||
Game::Load_MaterialHandle(false);
|
||||
|
||||
*Game::varMaterialHandle = reinterpret_cast<Game::Material * *>(varWeaponCompleteDef + 3744);
|
||||
*Game::varMaterialHandle = reinterpret_cast<Game::Material * *>(varWeaponCompleteDef + 3744 + offsetShift);
|
||||
Game::Load_MaterialHandle(false);
|
||||
|
||||
*Game::varMaterialHandle = reinterpret_cast<Game::Material * *>(varWeaponCompleteDef + 3748);
|
||||
*Game::varMaterialHandle = reinterpret_cast<Game::Material * *>(varWeaponCompleteDef + 3748 + offsetShift);
|
||||
Game::Load_MaterialHandle(false);
|
||||
|
||||
*Game::varMaterialHandle = reinterpret_cast<Game::Material * *>(varWeaponCompleteDef + 3752);
|
||||
*Game::varMaterialHandle = reinterpret_cast<Game::Material * *>(varWeaponCompleteDef + 3752 + offsetShift);
|
||||
Game::Load_MaterialHandle(false);
|
||||
}
|
||||
else if (Zones::ZoneVersion >= 359)
|
||||
@ -1127,35 +1170,35 @@ namespace Components
|
||||
|
||||
if (Zones::Version() >= 460)
|
||||
{
|
||||
if (*reinterpret_cast<DWORD*>(varWeaponCompleteDef + 3780) == -1)
|
||||
if (*reinterpret_cast<DWORD*>(varWeaponCompleteDef + 3780 + offsetShift) == -1)
|
||||
{
|
||||
void* vec2 = Game::DB_AllocStreamPos(3);
|
||||
*reinterpret_cast<void**>(varWeaponCompleteDef + 3780) = vec2;
|
||||
*reinterpret_cast<void**>(varWeaponCompleteDef + 3780 + offsetShift) = vec2;
|
||||
|
||||
Game::Load_Stream(true, vec2, 8 * *reinterpret_cast<short*>(varWeaponCompleteDef + 3776));
|
||||
Game::Load_Stream(true, vec2, 8 * *reinterpret_cast<short*>(varWeaponCompleteDef + 3776 + offsetShift));
|
||||
}
|
||||
|
||||
if (*reinterpret_cast<DWORD*>(varWeaponCompleteDef + 3784) == -1)
|
||||
if (*reinterpret_cast<DWORD*>(varWeaponCompleteDef + 3784 + offsetShift) == -1)
|
||||
{
|
||||
void* vec2 = Game::DB_AllocStreamPos(3);
|
||||
*reinterpret_cast<void**>(varWeaponCompleteDef + 3784) = vec2;
|
||||
*reinterpret_cast<void**>(varWeaponCompleteDef + 3784 + offsetShift) = vec2;
|
||||
|
||||
Game::Load_Stream(true, vec2, 8 * *reinterpret_cast<short*>(varWeaponCompleteDef + 3778));
|
||||
Game::Load_Stream(true, vec2, 8 * *reinterpret_cast<short*>(varWeaponCompleteDef + 3778 + offsetShift));
|
||||
}
|
||||
|
||||
*Game::varXString = reinterpret_cast<char**>(varWeaponCompleteDef + 3876);
|
||||
*Game::varXString = reinterpret_cast<char**>(varWeaponCompleteDef + 3876 + offsetShift);
|
||||
Game::Load_XString(false);
|
||||
|
||||
*Game::varXString = reinterpret_cast<char**>(varWeaponCompleteDef + 3880);
|
||||
*Game::varXString = reinterpret_cast<char**>(varWeaponCompleteDef + 3880 + offsetShift);
|
||||
Game::Load_XString(false);
|
||||
|
||||
*Game::varXString = reinterpret_cast<char**>(varWeaponCompleteDef + 3884);
|
||||
*Game::varXString = reinterpret_cast<char**>(varWeaponCompleteDef + 3884 + offsetShift);
|
||||
Game::Load_XString(false);
|
||||
|
||||
*Game::varXString = reinterpret_cast<char**>(varWeaponCompleteDef + 3996);
|
||||
*Game::varXString = reinterpret_cast<char**>(varWeaponCompleteDef + 3996 + offsetShift);
|
||||
Game::Load_XString(false);
|
||||
|
||||
*Game::varXString = reinterpret_cast<char**>(varWeaponCompleteDef + 4012);
|
||||
*Game::varXString = reinterpret_cast<char**>(varWeaponCompleteDef + 4012 + offsetShift);
|
||||
Game::Load_XString(false);
|
||||
}
|
||||
else if (Zones::ZoneVersion >= 359)
|
||||
@ -1381,7 +1424,7 @@ namespace Components
|
||||
char* varWeaponAttach = *reinterpret_cast<char**>(0x112ADE0); // varAddonMapEnts
|
||||
|
||||
// and do the stuff
|
||||
if (Zones::Version() >= 448)
|
||||
if (Zones::Version() >= 446)
|
||||
{
|
||||
Game::Load_Stream(true, varWeaponAttach, 20);
|
||||
|
||||
@ -1426,7 +1469,7 @@ namespace Components
|
||||
|
||||
bool Zones::LoadMaterialShaderArgumentArray(bool atStreamStart, Game::MaterialShaderArgument* argument, int size)
|
||||
{
|
||||
// if (Zones::ZoneVersion >= 448 && currentAssetType == Game::XAssetType::ASSET_TYPE_FX) __debugbreak();
|
||||
// if (Zones::ZoneVersion >= 446 && currentAssetType == Game::XAssetType::ASSET_TYPE_FX) __debugbreak();
|
||||
bool result = Game::Load_Stream(atStreamStart, argument, size);
|
||||
|
||||
Game::MaterialPass* curPass = *Game::varMaterialPass;
|
||||
@ -1436,13 +1479,13 @@ namespace Components
|
||||
{
|
||||
Game::MaterialShaderArgument* arg = &argument[i];
|
||||
|
||||
if (Zones::Version() < 448)
|
||||
{
|
||||
if (arg->type != D3DSHADER_PARAM_REGISTER_TYPE::D3DSPR_TEXTURE && arg->type != D3DSHADER_PARAM_REGISTER_TYPE::D3DSPR_ATTROUT)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (Zones::Version() < 446)
|
||||
{
|
||||
// should be min 68 currently
|
||||
// >= 58 fixes foliage without bad side effects
|
||||
// >= 53 still has broken shadow mapping
|
||||
@ -1489,7 +1532,100 @@ namespace Components
|
||||
{
|
||||
if (arg->type == 3 || arg->type == 5)
|
||||
{
|
||||
if (Zones::Version() == 460 /*|| Zones::Version() == 448*/) // 448 is no longer compatible, needs correct mappings
|
||||
// 446 is from a special client version that had lot of
|
||||
// unrelased/unfinished maps, is just enough for explore,
|
||||
// trees had issue with it
|
||||
if (Zones::Version() == 446)
|
||||
{
|
||||
static std::unordered_map<std::uint16_t, std::uint16_t> mapped_constants = {
|
||||
{ 33, 31 },
|
||||
{ 34, 32 },
|
||||
{ 36, 34 },
|
||||
{ 39, 37 },
|
||||
{ 40, 38 },
|
||||
{ 42, 40 },
|
||||
{ 43, 41 },
|
||||
{ 45, 43 },
|
||||
{ 62, 52 },
|
||||
{ 63, 53 },
|
||||
{ 199, 58 },
|
||||
{ 259, 86 },
|
||||
{ 263, 90 },
|
||||
{ 271, 98 },
|
||||
{ 279, 106 },
|
||||
};
|
||||
|
||||
const auto itr = mapped_constants.find(arg->u.codeConst.index);
|
||||
if (itr != mapped_constants.end())
|
||||
{
|
||||
arg->u.codeConst.index = itr->second;
|
||||
}
|
||||
}
|
||||
else if (Zones::Version() == 461)
|
||||
{
|
||||
static std::unordered_map<std::uint16_t, std::uint16_t> mapped_constants =
|
||||
{
|
||||
// mp_raid
|
||||
{ 33, 31 },
|
||||
{ 34, 32 },
|
||||
{ 36, 34 },
|
||||
{ 39, 37 },
|
||||
{ 40, 38 },
|
||||
{ 42, 40 },
|
||||
{ 43, 41 },
|
||||
{ 45, 43 },
|
||||
{ 62, 52 },
|
||||
{ 63, 53 },
|
||||
{ 197, 58 },
|
||||
{ 202, 63 },
|
||||
{ 203, 64 },
|
||||
{ 261, 90 },
|
||||
{ 265, 94 },
|
||||
{ 269, 98 },
|
||||
{ 277, 106 },
|
||||
|
||||
// mp_dome
|
||||
{ 38, 36 },
|
||||
{ 40, 38 },
|
||||
{ 118, 86 },
|
||||
};
|
||||
|
||||
const auto itr = mapped_constants.find(arg->u.codeConst.index);
|
||||
if (itr != mapped_constants.end())
|
||||
{
|
||||
arg->u.codeConst.index = itr->second;
|
||||
}
|
||||
if (arg->u.codeConst.index == 257)
|
||||
{
|
||||
auto techsetName = (*reinterpret_cast<Game::MaterialTechniqueSet**>(0x112AE8C))->name;
|
||||
|
||||
// dont know if this applies to 460 too, but I dont have 460 files to test
|
||||
if (!strncmp(techsetName, "wc_unlit_add", 12) ||
|
||||
!strncmp(techsetName, "wc_unlit_multiply", 17) )
|
||||
{
|
||||
// fixes glass and water
|
||||
arg->u.codeConst.index = 116;
|
||||
}
|
||||
else
|
||||
{
|
||||
// anything else
|
||||
arg->u.codeConst.index = 86;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// copy-paste from 460
|
||||
if (arg->u.codeConst.index >= 259)
|
||||
{
|
||||
arg->u.codeConst.index -= 171;
|
||||
}
|
||||
else if (arg->u.codeConst.index >= 197)
|
||||
{
|
||||
arg->u.codeConst.index -= 139;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (Zones::Version() == 460 /*|| Zones::Version() == 446*/) // 446 is no longer compatible, needs correct mappings
|
||||
{
|
||||
static std::unordered_map<std::uint16_t, std::uint16_t> mapped_constants = {
|
||||
{ 22, 21 },
|
||||
@ -1741,8 +1877,8 @@ namespace Components
|
||||
{
|
||||
// 359 and above adds an extra remapped techset ptr
|
||||
if (Zones::ZoneVersion >= 359) size += 4;
|
||||
// 448 amd above adds an additional technique
|
||||
if (Zones::ZoneVersion >= 448) size += 4;
|
||||
// 446 amd above adds an additional technique
|
||||
if (Zones::ZoneVersion >= 446) size += 4;
|
||||
|
||||
bool result = Game::Load_Stream(atStreamStart, buffer, size);
|
||||
|
||||
@ -1754,22 +1890,22 @@ namespace Components
|
||||
// As MW2 flags are only 1 byte large, this won't be possible anyways
|
||||
int shiftTest = 4;
|
||||
|
||||
std::memmove(buffer + 8 + shiftTest, buffer + 12 + shiftTest, (Zones::Version() >= 448) ? 200 : 196 - shiftTest);
|
||||
AssetHandler::Relocate(buffer + 12 + shiftTest, buffer + 8 + shiftTest, (Zones::Version() >= 448) ? 200 : 196 - shiftTest);
|
||||
std::memmove(buffer + 8 + shiftTest, buffer + 12 + shiftTest, (Zones::Version() >= 446) ? 200 : 196 - shiftTest);
|
||||
AssetHandler::Relocate(buffer + 12 + shiftTest, buffer + 8 + shiftTest, (Zones::Version() >= 446) ? 200 : 196 - shiftTest);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
int Zones::LoadMaterialTechniqueArray(bool atStreamStart, int count)
|
||||
{
|
||||
if (Zones::Version() >= 448)
|
||||
if (Zones::Version() >= 446)
|
||||
{
|
||||
count += 1;
|
||||
}
|
||||
|
||||
auto retval = Utils::Hook::Call<int(bool, int)>(0x497020)(atStreamStart, count);
|
||||
|
||||
if (Zones::Version() >= 448)
|
||||
if (Zones::Version() >= 446)
|
||||
{
|
||||
auto lastTechnique = **reinterpret_cast<Game::MaterialTechnique * **>(0x112AEDC);
|
||||
auto varMaterialTechniqueSet = **reinterpret_cast<Game::MaterialTechniqueSet * **>(0x112B070);
|
||||
@ -1783,11 +1919,11 @@ namespace Components
|
||||
|
||||
bool Zones::LoadMaterial(bool atStreamStart, char* buffer, int size)
|
||||
{
|
||||
// if (Zones::ZoneVersion >= 448 && currentAssetType == Game::ASSET_TYPE_XMODEL) __debugbreak();
|
||||
// if (Zones::ZoneVersion >= 446 && currentAssetType == Game::ASSET_TYPE_XMODEL) __debugbreak();
|
||||
|
||||
bool result = Game::Load_Stream(atStreamStart, buffer, (Zones::Version() >= 448) ? 104 : size);
|
||||
bool result = Game::Load_Stream(atStreamStart, buffer, (Zones::Version() >= 446) ? 104 : size);
|
||||
|
||||
if (Zones::Version() >= 448)
|
||||
if (Zones::Version() >= 446)
|
||||
{
|
||||
char codol_material[104];
|
||||
memcpy(codol_material, buffer, 104);
|
||||
@ -1990,7 +2126,7 @@ namespace Components
|
||||
void Zones::LoadImpactFx(bool atStreamStart, char* buffer, int size)
|
||||
{
|
||||
if (Zones::Version() >= 460) size = 0xB94;
|
||||
else if (Zones::Version() >= 448) size = 0xA64;
|
||||
else if (Zones::Version() >= 446) size = 0xA64;
|
||||
else if (Zones::Version() >= VERSION_ALPHA2) size = 0x8C0;
|
||||
|
||||
Game::Load_Stream(atStreamStart, buffer, size);
|
||||
@ -2007,7 +2143,7 @@ namespace Components
|
||||
|
||||
int Zones::ImpactFxArrayCount()
|
||||
{
|
||||
if (Zones::Version() >= 448)
|
||||
if (Zones::Version() >= 446)
|
||||
{
|
||||
return 19;
|
||||
}
|
||||
@ -2170,7 +2306,7 @@ namespace Components
|
||||
int Zones::LoadRandomFxGarbage(bool atStreamStart, char* buffer, int size)
|
||||
{
|
||||
int count = 0;
|
||||
if (Zones::Version() >= 448)
|
||||
if (Zones::Version() >= 446)
|
||||
{
|
||||
size /= 48;
|
||||
count = size;
|
||||
@ -2179,7 +2315,7 @@ namespace Components
|
||||
|
||||
const auto retval = Game::Load_Stream(atStreamStart, buffer, size);
|
||||
|
||||
if (Zones::Version() >= 448)
|
||||
if (Zones::Version() >= 446)
|
||||
{
|
||||
for (auto i = 0; i < count; i++)
|
||||
{
|
||||
@ -2258,7 +2394,7 @@ namespace Components
|
||||
{
|
||||
int count = 0;
|
||||
|
||||
if (Zones::Version() >= 448)
|
||||
if (Zones::Version() >= 446)
|
||||
{
|
||||
size /= 12;
|
||||
count = size;
|
||||
@ -2267,7 +2403,7 @@ namespace Components
|
||||
|
||||
auto retval = Game::Load_Stream(atStreamStart, buffer, size);
|
||||
|
||||
if (Zones::Version() >= 448)
|
||||
if (Zones::Version() >= 446)
|
||||
{
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
@ -2332,8 +2468,8 @@ namespace Components
|
||||
cmp dword ptr[eax], 0xFFFFFFFF;
|
||||
je loadAssetData;
|
||||
|
||||
// check if FF is below 448, still load data in that case
|
||||
cmp Zones::ZoneVersion, 448;
|
||||
// check if FF is below 446, still load data in that case
|
||||
cmp Zones::ZoneVersion, 446;
|
||||
jl loadAssetData;
|
||||
|
||||
// offset to pointer magic
|
||||
@ -2426,7 +2562,9 @@ namespace Components
|
||||
|
||||
int Zones::LoadMapEnts(bool atStreamStart, Game::MapEnts* buffer, int size)
|
||||
{
|
||||
if (Zones::Version() >= 448)
|
||||
EntitiesVersion = Zones::Version();
|
||||
|
||||
if (Zones::Version() >= 446)
|
||||
{
|
||||
size /= 44;
|
||||
size *= 36;
|
||||
@ -2583,7 +2721,7 @@ namespace Components
|
||||
|
||||
int Zones::LoadClipMap(bool atStreamStart)
|
||||
{
|
||||
if (Zones::Version() >= 448)
|
||||
if (Zones::Version() >= 446)
|
||||
{
|
||||
AssertOffset(codolClipMap_t, pInfo, 72);
|
||||
|
||||
@ -3139,8 +3277,8 @@ namespace Components
|
||||
cmp dword ptr[edx + 4], 0xFFFFFFFF;
|
||||
je loadAssetData;
|
||||
|
||||
// check if FF is below 448, still load data in that case
|
||||
cmp Zones::ZoneVersion, 448;
|
||||
// check if FF is below 446, still load data in that case
|
||||
cmp Zones::ZoneVersion, 446;
|
||||
jl loadAssetData;
|
||||
|
||||
// offset to pointer magic
|
||||
@ -3171,8 +3309,8 @@ namespace Components
|
||||
cmp dword ptr[eax + 0Ch], 0xFFFFFFFF;
|
||||
je loadAssetData;
|
||||
|
||||
// check if FF is below 448, still load data in that case
|
||||
cmp Zones::ZoneVersion, 448;
|
||||
// check if FF is below 446, still load data in that case
|
||||
cmp Zones::ZoneVersion, 446;
|
||||
jl loadAssetData;
|
||||
|
||||
// offset to pointer magic
|
||||
@ -3203,8 +3341,8 @@ namespace Components
|
||||
cmp dword ptr[eax + 14h], 0xFFFFFFFF;
|
||||
je loadAssetData;
|
||||
|
||||
// check if FF is below 448, still load data in that case
|
||||
cmp Zones::ZoneVersion, 448;
|
||||
// check if FF is below 446, still load data in that case
|
||||
cmp Zones::ZoneVersion, 446;
|
||||
jl loadAssetData;
|
||||
|
||||
// offset to pointer magic
|
||||
@ -3273,11 +3411,11 @@ namespace Components
|
||||
|
||||
void Zones::LoadXModelAsset(Game::XModel** asset)
|
||||
{
|
||||
if (Zones::Version() >= 448)
|
||||
if (Zones::Version() >= 446)
|
||||
{
|
||||
for (int i = 0; i < (*asset)->numLods; i++)
|
||||
{
|
||||
if ((*asset)->lodInfo[i].surfs == nullptr && Zones::Version() >= 448)
|
||||
if ((*asset)->lodInfo[i].surfs == nullptr && Zones::Version() >= 446)
|
||||
{
|
||||
const auto name = (*asset)->name;
|
||||
const auto fx_model = Game::DB_FindXAssetHeader(Game::XAssetType::ASSET_TYPE_XMODEL, "void").model;
|
||||
@ -3303,7 +3441,7 @@ namespace Components
|
||||
|
||||
void Zones::LoadMaterialAsset(Game::Material** asset)
|
||||
{
|
||||
if (asset && *asset && Zones::Version() >= 448)
|
||||
if (asset && *asset && Zones::Version() >= 446)
|
||||
{
|
||||
static std::vector<std::string> broken_materials = {
|
||||
"gfx_fxt_debris_wind_ash_z10",
|
||||
@ -3353,6 +3491,29 @@ namespace Components
|
||||
Game::DB_PopStreamPos();
|
||||
}
|
||||
|
||||
char* Zones::ParseVision_Stub(const char** data_p)
|
||||
{
|
||||
auto token = Game::Com_Parse(data_p);
|
||||
|
||||
if (vision_replace_list.find(token) != vision_replace_list.end())
|
||||
{
|
||||
return vision_replace_list[token].data();
|
||||
}
|
||||
|
||||
return token;
|
||||
}
|
||||
|
||||
char* Zones::ParseShellShock_Stub(const char** data_p)
|
||||
{
|
||||
auto token = Game::Com_Parse(data_p);
|
||||
if (shellshock_replace_list.find(token) != shellshock_replace_list.end())
|
||||
{
|
||||
return shellshock_replace_list[token].data();
|
||||
}
|
||||
return token;
|
||||
}
|
||||
|
||||
|
||||
Zones::Zones()
|
||||
{
|
||||
Zones::ZoneVersion = 0;
|
||||
@ -3499,6 +3660,9 @@ namespace Components
|
||||
Utils::Hook(0x418998, Zones::GameMapSpPatchStub, HOOK_JUMP).install()->quick();
|
||||
Utils::Hook(0x427A1B, Zones::LoadPathDataTail, HOOK_JUMP).install()->quick();
|
||||
|
||||
Utils::Hook(0x4B4EA1, Zones::ParseShellShock_Stub, HOOK_CALL).install()->quick();
|
||||
Utils::Hook(0x4B4F0C, Zones::ParseShellShock_Stub, HOOK_CALL).install()->quick();
|
||||
|
||||
Utils::Hook(0x4F4D3B, [] ()
|
||||
{
|
||||
if (Zones::ZoneVersion >= VERSION_ALPHA3)
|
||||
@ -3521,6 +3685,10 @@ namespace Components
|
||||
Utils::Hook(0x4597DD, Zones::LoadStatement, HOOK_CALL).install()->quick();
|
||||
Utils::Hook(0x471A39, Zones::LoadWindowImage, HOOK_JUMP).install()->quick();
|
||||
|
||||
// Fix newer vision file
|
||||
Utils::Hook(0x59A849, ParseVision_Stub, HOOK_CALL).install()->quick();
|
||||
Utils::Hook(0x59A8AD, ParseVision_Stub, HOOK_CALL).install()->quick();
|
||||
|
||||
#ifdef DEBUG
|
||||
// Easy dirty disk debugging
|
||||
Utils::Hook::Set<WORD>(0x4CF7F0, 0xC3CC);
|
||||
|
@ -3,6 +3,7 @@
|
||||
#define VERSION_ALPHA2 316
|
||||
#define VERSION_ALPHA3 318//319
|
||||
#define VERSION_ALPHA3_DEC 319
|
||||
#define VERSION_LATEST_CODO 461
|
||||
|
||||
namespace Components
|
||||
{
|
||||
@ -23,9 +24,12 @@ namespace Components
|
||||
|
||||
static int Version() { return Zones::ZoneVersion; };
|
||||
|
||||
static int GetEntitiesZoneVersion() { return Zones::EntitiesVersion; };
|
||||
|
||||
private:
|
||||
|
||||
static int ZoneVersion;
|
||||
static int EntitiesVersion;
|
||||
|
||||
static int FxEffectIndex;
|
||||
static char* FxEffectStrings[64];
|
||||
@ -101,5 +105,7 @@ namespace Components
|
||||
static void LoadTracerDef(bool atStreamStart, Game::TracerDef* tracer, int size);
|
||||
static void LoadTracerDefFxEffect();
|
||||
static void FixImageCategory(Game::GfxImage* image);
|
||||
static char* ParseShellShock_Stub(const char** data_p);
|
||||
static char* ParseVision_Stub(const char** data_p);
|
||||
};
|
||||
}
|
||||
|
@ -66,6 +66,7 @@ namespace Game
|
||||
Com_Parse_t Com_Parse = Com_Parse_t(0x474D60);
|
||||
Com_MatchToken_t Com_MatchToken = Com_MatchToken_t(0x447130);
|
||||
Com_SetSlowMotion_t Com_SetSlowMotion = Com_SetSlowMotion_t(0x446E20);
|
||||
Com_Quitf_t Com_Quit_f = Com_Quitf_t(0x4D4000);
|
||||
|
||||
Con_DrawMiniConsole_t Con_DrawMiniConsole = Con_DrawMiniConsole_t(0x464F30);
|
||||
Con_DrawSolidConsole_t Con_DrawSolidConsole = Con_DrawSolidConsole_t(0x5A5040);
|
||||
@ -99,11 +100,11 @@ namespace Game
|
||||
Dvar_RegisterFloat_t Dvar_RegisterFloat = Dvar_RegisterFloat_t(0x648440);
|
||||
Dvar_RegisterVec2_t Dvar_RegisterVec2 = Dvar_RegisterVec2_t(0x4F6070);
|
||||
Dvar_RegisterVec3_t Dvar_RegisterVec3 = Dvar_RegisterVec3_t(0x4EF8E0);
|
||||
Dvar_RegisterVec4_t Dvar_RegisterVec4 = Dvar_RegisterVec4_t(0x4F28E0);
|
||||
Dvar_RegisterVec4_t Dvar_RegisterVec4 = Dvar_RegisterVec4_t(0x471500);
|
||||
Dvar_RegisterInt_t Dvar_RegisterInt = Dvar_RegisterInt_t(0x479830);
|
||||
Dvar_RegisterEnum_t Dvar_RegisterEnum = Dvar_RegisterEnum_t(0x412E40);
|
||||
Dvar_RegisterString_t Dvar_RegisterString = Dvar_RegisterString_t(0x4FC7E0);
|
||||
Dvar_RegisterColor_t Dvar_RegisterColor = Dvar_RegisterColor_t(0x4F28E0);//0x471500;
|
||||
Dvar_RegisterColor_t Dvar_RegisterColor = Dvar_RegisterColor_t(0x4F28E0);
|
||||
|
||||
Dvar_GetUnpackedColorByName_t Dvar_GetUnpackedColorByName = Dvar_GetUnpackedColorByName_t(0x406530);
|
||||
Dvar_FindVar_t Dvar_FindVar = Dvar_FindVar_t(0x4D5390);
|
||||
|
@ -133,6 +133,9 @@ namespace Game
|
||||
typedef void(__cdecl * Com_SetSlowMotion_t)(float start, float end, int duration);
|
||||
extern Com_SetSlowMotion_t Com_SetSlowMotion;
|
||||
|
||||
typedef void(__cdecl * Com_Quitf_t)();
|
||||
extern Com_Quitf_t Com_Quit_f;
|
||||
|
||||
typedef char* (__cdecl * Con_DrawMiniConsole_t)(int localClientNum, int xPos, int yPos, float alpha);
|
||||
extern Con_DrawMiniConsole_t Con_DrawMiniConsole;
|
||||
|
||||
|
@ -3049,7 +3049,7 @@ namespace Game
|
||||
float value;
|
||||
float vector[4];
|
||||
const char *string;
|
||||
char color[4];
|
||||
unsigned char color[4];
|
||||
};
|
||||
|
||||
struct $BFBB53559BEAC4289F32B924847E59CB
|
||||
|
@ -59,7 +59,7 @@ template <size_t S> class Sizer { };
|
||||
#define Offset_Of(x, y, z) BindNum(offsetof(x, y), z)
|
||||
|
||||
// Submodules
|
||||
// Ignore the warnings, it's no our code!
|
||||
// Ignore the warnings, it's not our code!
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable: 4005)
|
||||
#pragma warning(disable: 4091)
|
||||
@ -152,6 +152,7 @@ template <size_t S> class Sizer { };
|
||||
#pragma comment(lib, "Advapi32.lib")
|
||||
#pragma comment(lib, "rpcrt4.lib")
|
||||
#pragma comment(lib, "dbghelp.lib")
|
||||
#pragma comment(lib, "ntdll.lib")
|
||||
|
||||
// Enable additional literals
|
||||
using namespace std::literals;
|
||||
|
@ -384,25 +384,25 @@ namespace Steam
|
||||
Proxy::LaunchWatchGuard();
|
||||
|
||||
Proxy::Overlay = ::Utils::Library(GAMEOVERLAY_LIB, false);
|
||||
if (!Proxy::Overlay.valid()) return false;
|
||||
if (!Proxy::Overlay.IsValid()) return false;
|
||||
}
|
||||
|
||||
Proxy::Client = ::Utils::Library(STEAMCLIENT_LIB, false);
|
||||
if (!Proxy::Client.valid()) return false;
|
||||
if (!Proxy::Client.IsValid()) return false;
|
||||
|
||||
Proxy::SteamClient = Proxy::Client.get<ISteamClient008*(const char*, int*)>("CreateInterface")("SteamClient008", nullptr);
|
||||
Proxy::SteamClient = Proxy::Client.Get<ISteamClient008*(const char*, int*)>("CreateInterface")("SteamClient008", nullptr);
|
||||
if(!Proxy::SteamClient) return false;
|
||||
|
||||
Proxy::SteamBGetCallback = Proxy::Client.get<Proxy::SteamBGetCallbackFn>("Steam_BGetCallback");
|
||||
Proxy::SteamBGetCallback = Proxy::Client.Get<Proxy::SteamBGetCallbackFn>("Steam_BGetCallback");
|
||||
if (!Proxy::SteamBGetCallback) return false;
|
||||
|
||||
Proxy::SteamFreeLastCallback = Proxy::Client.get<Proxy::SteamFreeLastCallbackFn>("Steam_FreeLastCallback");
|
||||
Proxy::SteamFreeLastCallback = Proxy::Client.Get<Proxy::SteamFreeLastCallbackFn>("Steam_FreeLastCallback");
|
||||
if (!Proxy::SteamFreeLastCallback) return false;
|
||||
|
||||
Proxy::SteamGetAPICallResult = Proxy::Client.get<Proxy::SteamGetAPICallResultFn>("Steam_GetAPICallResult");
|
||||
Proxy::SteamGetAPICallResult = Proxy::Client.Get<Proxy::SteamGetAPICallResultFn>("Steam_GetAPICallResult");
|
||||
if (!Proxy::SteamGetAPICallResult) return false;
|
||||
|
||||
Proxy::SteamClient = Proxy::Client.get<ISteamClient008*(const char*, int*)>("CreateInterface")("SteamClient008", nullptr);
|
||||
Proxy::SteamClient = Proxy::Client.Get<ISteamClient008*(const char*, int*)>("CreateInterface")("SteamClient008", nullptr);
|
||||
if (!Proxy::SteamClient) return false;
|
||||
|
||||
Proxy::SteamPipe = Proxy::SteamClient->CreateSteamPipe();
|
||||
@ -411,7 +411,7 @@ namespace Steam
|
||||
Proxy::SteamUser = Proxy::SteamClient->ConnectToGlobalUser(Proxy::SteamPipe);
|
||||
if (!Proxy::SteamUser) return false;
|
||||
|
||||
Proxy::ClientEngine = Proxy::Client.get<IClientEngine*(const char*, int*)>("CreateInterface")("CLIENTENGINE_INTERFACE_VERSION005", nullptr);
|
||||
Proxy::ClientEngine = Proxy::Client.Get<IClientEngine*(const char*, int*)>("CreateInterface")("CLIENTENGINE_INTERFACE_VERSION005", nullptr);
|
||||
if (!Proxy::ClientEngine) return false;
|
||||
|
||||
Proxy::ClientUser = Proxy::ClientEngine->GetIClientUser(Proxy::SteamUser, Proxy::SteamPipe);
|
||||
@ -526,17 +526,17 @@ namespace Steam
|
||||
|
||||
void Proxy::SetOverlayNotificationPosition(uint32_t eNotificationPosition)
|
||||
{
|
||||
if (Proxy::Overlay.valid())
|
||||
if (Proxy::Overlay.IsValid())
|
||||
{
|
||||
Proxy::Overlay.get<void(uint32_t)>("SetNotificationPosition")(eNotificationPosition);
|
||||
Proxy::Overlay.Get<void(uint32_t)>("SetNotificationPosition")(eNotificationPosition);
|
||||
}
|
||||
}
|
||||
|
||||
bool Proxy::IsOverlayEnabled()
|
||||
{
|
||||
if (Proxy::Overlay.valid())
|
||||
if (Proxy::Overlay.IsValid())
|
||||
{
|
||||
return Proxy::Overlay.get<bool()>("IsOverlayEnabled")();
|
||||
return Proxy::Overlay.Get<bool()>("IsOverlayEnabled")();
|
||||
}
|
||||
|
||||
return false;
|
||||
@ -544,9 +544,9 @@ namespace Steam
|
||||
|
||||
bool Proxy::BOverlayNeedsPresent()
|
||||
{
|
||||
if (Proxy::Overlay.valid())
|
||||
if (Proxy::Overlay.IsValid())
|
||||
{
|
||||
return Proxy::Overlay.get<bool()>("BOverlayNeedsPresent")();
|
||||
return Proxy::Overlay.Get<bool()>("BOverlayNeedsPresent")();
|
||||
}
|
||||
|
||||
return false;
|
||||
|
@ -2,34 +2,63 @@
|
||||
|
||||
namespace Utils
|
||||
{
|
||||
Library Library::Load(const std::string& name)
|
||||
{
|
||||
return Library(LoadLibraryA(name.data()));
|
||||
}
|
||||
|
||||
Library Library::Load(const std::filesystem::path& path)
|
||||
{
|
||||
return Library::Load(path.generic_string());
|
||||
}
|
||||
|
||||
Library Library::GetByAddress(void* address)
|
||||
{
|
||||
HMODULE handle = nullptr;
|
||||
GetModuleHandleExA(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, static_cast<LPCSTR>(address), &handle);
|
||||
return Library(handle);
|
||||
}
|
||||
|
||||
Library::Library(const std::string& buffer, bool _freeOnDestroy) : _module(nullptr), freeOnDestroy(_freeOnDestroy)
|
||||
{
|
||||
this->_module = LoadLibraryExA(buffer.data(), nullptr, 0);
|
||||
}
|
||||
|
||||
Library::Library(const std::string& buffer)
|
||||
{
|
||||
this->_module = GetModuleHandleA(buffer.data());
|
||||
this->freeOnDestroy = true;
|
||||
}
|
||||
|
||||
Library::Library(const HMODULE handle)
|
||||
{
|
||||
this->_module = handle;
|
||||
this->freeOnDestroy = true;
|
||||
}
|
||||
|
||||
Library::~Library()
|
||||
{
|
||||
if (this->freeOnDestroy)
|
||||
{
|
||||
this->free();
|
||||
this->Free();
|
||||
}
|
||||
}
|
||||
|
||||
bool Library::valid()
|
||||
bool Library::IsValid() const
|
||||
{
|
||||
return (this->getModule() != nullptr);
|
||||
return this->_module != nullptr;
|
||||
}
|
||||
|
||||
HMODULE Library::getModule()
|
||||
HMODULE Library::GetModule()
|
||||
{
|
||||
return this->_module;
|
||||
}
|
||||
|
||||
void Library::free()
|
||||
void Library::Free()
|
||||
{
|
||||
if (this->valid())
|
||||
if (this->IsValid())
|
||||
{
|
||||
FreeLibrary(this->getModule());
|
||||
FreeLibrary(this->_module);
|
||||
}
|
||||
|
||||
this->_module = nullptr;
|
||||
|
@ -5,25 +5,58 @@ namespace Utils
|
||||
class Library
|
||||
{
|
||||
public:
|
||||
static Library Load(const std::string& name);
|
||||
static Library Load(const std::filesystem::path& path);
|
||||
static Library GetByAddress(void* address);
|
||||
|
||||
Library() : _module(nullptr), freeOnDestroy(false) {};
|
||||
Library(const std::string& buffer, bool freeOnDestroy = true);
|
||||
Library(const std::string& buffer, bool freeOnDestroy);
|
||||
explicit Library(const std::string& name);
|
||||
explicit Library(HMODULE handle);
|
||||
~Library();
|
||||
|
||||
bool valid();
|
||||
HMODULE getModule();
|
||||
bool IsValid() const;
|
||||
HMODULE GetModule();
|
||||
|
||||
template <typename T>
|
||||
std::function<T> get(const std::string& process)
|
||||
T GetProc(const std::string& process) const
|
||||
{
|
||||
if (!this->valid())
|
||||
{
|
||||
throw std::runtime_error("Library not loaded!");
|
||||
if (!this->IsValid()) T{};
|
||||
return reinterpret_cast<T>(GetProcAddress(this->_module, process.data()));
|
||||
}
|
||||
|
||||
return reinterpret_cast<T*>(GetProcAddress(this->getModule(), process.data()));
|
||||
template <typename T>
|
||||
std::function<T> Get(const std::string& process) const
|
||||
{
|
||||
if (!this->IsValid()) return std::function<T>();
|
||||
return static_cast<T*>(this->GetProc<void*>(process));
|
||||
}
|
||||
|
||||
void free();
|
||||
template <typename T, typename... Args>
|
||||
T Invoke(const std::string& process, Args ... args) const
|
||||
{
|
||||
auto method = this->Get<T(__cdecl)(Args ...)>(process);
|
||||
if (method) return method(args...);
|
||||
return T();
|
||||
}
|
||||
|
||||
template <typename T, typename... Args>
|
||||
T InvokePascal(const std::string& process, Args ... args) const
|
||||
{
|
||||
auto method = this->Get<T(__stdcall)(Args ...)>(process);
|
||||
if (method) return method(args...);
|
||||
return T();
|
||||
}
|
||||
|
||||
template <typename T, typename... Args>
|
||||
T InvokeThis(const std::string& process, void* this_ptr, Args ... args) const
|
||||
{
|
||||
auto method = this->Get<T(__thiscall)(void*, Args ...)>(this_ptr, process);
|
||||
if (method) return method(args...);
|
||||
return T();
|
||||
}
|
||||
|
||||
void Free();
|
||||
|
||||
private:
|
||||
HMODULE _module;
|
||||
|
@ -142,6 +142,13 @@ namespace Utils
|
||||
return static_cast<T*>(Allocate(count * sizeof(T)));
|
||||
}
|
||||
|
||||
template <typename T> static inline T* Duplicate(T* original)
|
||||
{
|
||||
T* data = Memory::Allocate<T>();
|
||||
std::memcpy(data, original, sizeof(T));
|
||||
return data;
|
||||
}
|
||||
|
||||
static char* DuplicateString(const std::string& string);
|
||||
|
||||
static void Free(void* data);
|
||||
|
Loading…
Reference in New Issue
Block a user