commit
fcec8b2779
4
.github/workflows/build.yml
vendored
4
.github/workflows/build.yml
vendored
@ -24,7 +24,7 @@ jobs:
|
||||
- Release
|
||||
steps:
|
||||
- name: Check out files
|
||||
uses: actions/checkout@v3.3.0
|
||||
uses: actions/checkout@v3.5.2
|
||||
with:
|
||||
submodules: true
|
||||
fetch-depth: 0
|
||||
@ -72,7 +72,7 @@ jobs:
|
||||
|
||||
# Set up committer info and GPG key
|
||||
- name: Install SSH key
|
||||
uses: shimataro/ssh-key-action@v2.5.0
|
||||
uses: shimataro/ssh-key-action@v2.5.1
|
||||
with:
|
||||
key: ${{ secrets.XLABS_MASTER_SSH_PRIVATE_KEY }}
|
||||
known_hosts: 'just-a-placeholder-so-we-dont-get-errors'
|
||||
|
25
CHANGELOG.md
25
CHANGELOG.md
@ -2,9 +2,26 @@
|
||||
|
||||
All notable changes to this project will be documented in this file.
|
||||
|
||||
The format is based on [Keep a Changelog v0.3.0](http://keepachangelog.com/en/0.3.0/) and this project adheres to [Semantic Versioning](http://semver.org/).
|
||||
The format is based on [Keep a Changelog v0.3.0](http://keepachangelog.com/en/0.3.0/).
|
||||
|
||||
## r4190 - 2023-04-19
|
||||
## r4208 - 2023-04-22
|
||||
|
||||
### Changed
|
||||
|
||||
- `Noclip` GSC method does not require `sv_cheats` to be set to "1" for it to work (#962)
|
||||
- `Ufo` GSC method does not require `sv_cheats` to be set to "1" for it to work (#962)
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fix `InfoString` output (#961)
|
||||
- Fix parsing of the server info (client-side) (#953)
|
||||
- Fix bug in the /info TCP endpoint (#955)
|
||||
|
||||
### Known issues
|
||||
|
||||
- Sound issue fix is experimental as the bug is not fully understood.
|
||||
|
||||
## r4193 - 2023-04-19
|
||||
|
||||
### Added
|
||||
|
||||
@ -14,11 +31,13 @@ The format is based on [Keep a Changelog v0.3.0](http://keepachangelog.com/en/0.
|
||||
|
||||
### Changed
|
||||
|
||||
- `sv_mapRotationCurrent` supports `exec` directive for executing cfg scripts from the `game_settings` folder
|
||||
- `sv_mapRotationCurrent` supports `exec` directive for executing cfg scripts from the `game_settings` folder (#916)
|
||||
- `SetPing` GSC method is now deprecated.
|
||||
|
||||
### Fixed
|
||||
|
||||
- `sv_privatePassword` will work as intended (#908)
|
||||
- Fix crash when loading bots.txt file (#927)
|
||||
|
||||
### Known issues
|
||||
|
||||
|
17
SECURITY.md
Normal file
17
SECURITY.md
Normal file
@ -0,0 +1,17 @@
|
||||
## iw4x-client Security
|
||||
We take security very seriously at XLabsProject. We welcome any peer review of our 100% free software source code to ensure nobody's IW4x clients or servers are ever compromised or hacked.
|
||||
|
||||
### Where should I report security issues?
|
||||
|
||||
In order to give the community time to respond and upgrade we strongly urge you report all security issues privately.
|
||||
Please e-mail MauriceHeumann@gmail.com directly to provide details and repro steps.
|
||||
|
||||
### Other key people
|
||||
|
||||
In the exceptional case that you do not receive a response within a reasonable time frame from our lead developer, please contact any of the following people:
|
||||
- Future/diamante0018: iw4x-sp@proton.me
|
||||
|
||||
We will try respond as soon as possible, but please note:
|
||||
|
||||
### This is an entirely free software project. It is maintained in our spare time.
|
||||
### We cannot guarantee quick responses but we very much appreciate your discretion when reporting security vulnerabilities.
|
42
premake5.lua
42
premake5.lua
@ -17,19 +17,6 @@ function cstrquote(value)
|
||||
return result
|
||||
end
|
||||
|
||||
-- Converts tags in "vX.X.X" format to an array of numbers {X,X,X}.
|
||||
-- In the case where the format does not work fall back to old {4,2,REVISION}.
|
||||
function vertonumarr(value, vernumber)
|
||||
vernum = {}
|
||||
for num in string.gmatch(value, "%d+") do
|
||||
table.insert(vernum, tonumber(num))
|
||||
end
|
||||
if #vernum < 3 then
|
||||
return {4,2,tonumber(vernumber)}
|
||||
end
|
||||
return vernum
|
||||
end
|
||||
|
||||
dependencies = {
|
||||
basePath = "./deps"
|
||||
}
|
||||
@ -108,7 +95,7 @@ newaction {
|
||||
|
||||
newaction {
|
||||
trigger = "generate-buildinfo",
|
||||
description = "Sets up build information file like version.h.",
|
||||
description = "Sets up build information file. Output will be stored in version.h.",
|
||||
onWorkspace = function(wks)
|
||||
-- get revision number via git
|
||||
local proc = assert(io.popen("git rev-list --count HEAD", "r"))
|
||||
@ -129,6 +116,26 @@ newaction {
|
||||
proc = assert(io.popen("git describe --tags --abbrev=0"))
|
||||
local tagName = assert(proc:read('*l'))
|
||||
|
||||
-- get current branch name
|
||||
proc = assert(io.popen("git branch --show-current"))
|
||||
local branchName = proc:read('*l')
|
||||
|
||||
-- branch for ci
|
||||
if branchName == nil or branchName == '' then
|
||||
proc = assert(io.popen("git show -s --pretty=%d HEAD"))
|
||||
local branchInfo = proc:read('*l')
|
||||
m = string.match(branchInfo, ".+,.+, ([^)]+)")
|
||||
if m ~= nil then
|
||||
branchName = m
|
||||
end
|
||||
end
|
||||
|
||||
if branchName == nil then
|
||||
branchName = "develop"
|
||||
end
|
||||
|
||||
print("Detected branch: " .. branchName)
|
||||
|
||||
-- get old version number from version.hpp if any
|
||||
local oldVersion = "(none)"
|
||||
local oldVersionHeader = io.open(wks.location .. "/src/version.h", "r")
|
||||
@ -157,9 +164,16 @@ newaction {
|
||||
versionHeader:write("#define GIT_DESCRIBE " .. gitDescribeOutputQuoted .. "\n")
|
||||
versionHeader:write("#define GIT_DIRTY " .. revDirty .. "\n")
|
||||
versionHeader:write("#define GIT_TAG " .. cstrquote(tagName) .. "\n")
|
||||
versionHeader:write("#define GIT_BRANCH " .. cstrquote(branchName) .. "\n")
|
||||
versionHeader:write("\n")
|
||||
versionHeader:write("// New revision definition. Will be used from now on\n")
|
||||
versionHeader:write("#define REVISION " .. revNumber .. "\n")
|
||||
versionHeader:write("#define REVISION_STR \"r" .. revNumber .. "\"\n")
|
||||
|
||||
if branchName == "develop" then
|
||||
versionHeader:write("#define EXPERIMENTAL_BUILD" .. "\n")
|
||||
end
|
||||
|
||||
versionHeader:write("\n")
|
||||
versionHeader:write("// Alias definitions\n")
|
||||
versionHeader:write("#define VERSION GIT_DESCRIBE\n")
|
||||
|
@ -13,11 +13,11 @@ namespace Components
|
||||
{
|
||||
constexpr std::size_t MAX_NAME_LENGTH = 16;
|
||||
|
||||
std::vector<Bots::botData> Bots::BotNames;
|
||||
|
||||
const Game::dvar_t* Bots::sv_randomBotNames;
|
||||
const Game::dvar_t* Bots::sv_replaceBots;
|
||||
|
||||
std::size_t Bots::botDataIndex;
|
||||
|
||||
struct BotMovementInfo
|
||||
{
|
||||
std::int32_t buttons; // Actions
|
||||
@ -54,27 +54,21 @@ namespace Components
|
||||
{ "activate", Game::CMD_BUTTON_ACTIVATE },
|
||||
};
|
||||
|
||||
void Bots::RandomizeBotNames()
|
||||
std::vector<Bots::botData> Bots::LoadBotNames()
|
||||
{
|
||||
std::random_device rd;
|
||||
std::mt19937 gen(rd());
|
||||
std::ranges::shuffle(BotNames, gen);
|
||||
}
|
||||
std::vector<botData> result;
|
||||
|
||||
void Bots::LoadBotNames()
|
||||
{
|
||||
FileSystem::File bots("bots.txt");
|
||||
|
||||
if (!bots.exists())
|
||||
{
|
||||
return;
|
||||
return result;
|
||||
}
|
||||
|
||||
auto data = Utils::String::Split(bots.getBuffer(), '\n');
|
||||
|
||||
for (auto& entry : data)
|
||||
{
|
||||
// Take into account for CR line endings
|
||||
// Take into account CR line endings
|
||||
Utils::String::Replace(entry, "\r", "");
|
||||
// Remove whitespace
|
||||
Utils::String::Trim(entry);
|
||||
@ -100,38 +94,41 @@ namespace Components
|
||||
|
||||
entry = entry.substr(0, MAX_NAME_LENGTH - 1);
|
||||
|
||||
BotNames.emplace_back(entry, clanAbbrev);
|
||||
result.emplace_back(entry, clanAbbrev);
|
||||
}
|
||||
|
||||
if (sv_randomBotNames->current.enabled)
|
||||
{
|
||||
RandomizeBotNames();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
int Bots::BuildConnectString(char* buffer, const char* connectString, int num, int, int protocol, int checksum, int statVer, int statStuff, int port)
|
||||
{
|
||||
static std::size_t botId = 0; // Loop over the BotNames vector
|
||||
static bool loadedNames = false; // Load file only once
|
||||
std::string botName;
|
||||
std::string clanName;
|
||||
|
||||
if (!loadedNames)
|
||||
static const auto botNames = []() -> std::vector<botData>
|
||||
{
|
||||
loadedNames = true;
|
||||
LoadBotNames();
|
||||
}
|
||||
auto names = LoadBotNames();
|
||||
|
||||
if (!BotNames.empty())
|
||||
if (sv_randomBotNames->current.enabled)
|
||||
{
|
||||
std::random_device rd;
|
||||
std::mt19937 gen(rd());
|
||||
std::ranges::shuffle(names, gen);
|
||||
}
|
||||
|
||||
return names;
|
||||
}();
|
||||
|
||||
if (!botNames.empty())
|
||||
{
|
||||
botId %= BotNames.size();
|
||||
const auto index = botId++;
|
||||
botName = BotNames[index].first;
|
||||
clanName = BotNames[index].second;
|
||||
botDataIndex %= botNames.size();
|
||||
const auto index = botDataIndex++;
|
||||
botName = botNames[index].first;
|
||||
clanName = botNames[index].second;
|
||||
}
|
||||
else
|
||||
{
|
||||
botName = std::format("bot{}", ++botId);
|
||||
botName = std::format("bot{}", num);
|
||||
clanName = "BOT"s;
|
||||
}
|
||||
|
||||
|
@ -11,13 +11,13 @@ namespace Components
|
||||
|
||||
private:
|
||||
using botData = std::pair< std::string, std::string>;
|
||||
static std::vector<botData> BotNames;
|
||||
|
||||
static const Game::dvar_t* sv_randomBotNames;
|
||||
static const Game::dvar_t* sv_replaceBots;
|
||||
|
||||
static void RandomizeBotNames();
|
||||
static void LoadBotNames();
|
||||
static std::size_t botDataIndex;
|
||||
|
||||
static std::vector<botData> LoadBotNames();
|
||||
static int BuildConnectString(char* buffer, const char* connectString, int num, int, int protocol, int checksum, int statVer, int statStuff, int port);
|
||||
|
||||
static void Spawn(unsigned int count);
|
||||
|
@ -40,42 +40,45 @@ namespace Components
|
||||
{
|
||||
Utils::Hook::Call<void(int)>(0x4EFF80)(localClientNum);
|
||||
|
||||
if (Branding::CGDrawVersion.get<bool>())
|
||||
if (CGDrawVersion.get<bool>())
|
||||
{
|
||||
Branding::CG_DrawVersion();
|
||||
CG_DrawVersion();
|
||||
}
|
||||
}
|
||||
|
||||
const char* Branding::GetBuildNumber()
|
||||
{
|
||||
return VERSION " latest " __DATE__ " " __TIME__;
|
||||
#ifdef EXPERIMENTAL_BUILD
|
||||
return REVISION_STR "-develop latest " __DATE__ " " __TIME__;
|
||||
#else
|
||||
return REVISION_STR " latest " __DATE__ " " __TIME__;
|
||||
#endif
|
||||
}
|
||||
|
||||
const char* Branding::GetVersionString()
|
||||
{
|
||||
// IW4x is technically a beta
|
||||
return Utils::String::VA("%s %s build %s %s",
|
||||
BUILD_TYPE, "(Beta)", Branding::GetBuildNumber(), reinterpret_cast<const char*>(0x7170A0));
|
||||
BUILD_TYPE, "(Beta)", GetBuildNumber(), reinterpret_cast<const char*>(0x7170A0));
|
||||
}
|
||||
|
||||
void Branding::Dvar_SetVersionString(const Game::dvar_t* dvar, [[maybe_unused]] const char* value)
|
||||
{
|
||||
const auto* result = Branding::GetVersionString();
|
||||
const auto* result = GetVersionString();
|
||||
Utils::Hook::Call<void(const Game::dvar_t*, const char*)>(0x4A9580)(dvar, result);
|
||||
}
|
||||
|
||||
// Branding this might be a good idea in case this LSP logging ever gets turned on for some reason
|
||||
void Branding::MSG_WriteVersionStringHeader(Game::msg_t* msg, [[maybe_unused]] const char* string)
|
||||
{
|
||||
const auto* result = Branding::GetVersionString();
|
||||
const auto* result = GetVersionString();
|
||||
Utils::Hook::Call<void(Game::msg_t*, const char*)>(0x463820)(msg, result);
|
||||
}
|
||||
|
||||
Game::dvar_t* Branding::Dvar_RegisterUIBuildLocation(const char* dvarName, [[maybe_unused]] float x,
|
||||
[[maybe_unused]] float y, float min, float max, [[maybe_unused]] int flags, const char* description)
|
||||
{
|
||||
return Game::Dvar_RegisterVec2(dvarName, -60.0f,
|
||||
474.0f, min, max, Game::DVAR_ROM, description);
|
||||
return Game::Dvar_RegisterVec2(dvarName, -60.0f, 472.0f, min, max, Game::DVAR_ROM, description);
|
||||
}
|
||||
|
||||
void Branding::RegisterBrandingDvars()
|
||||
@ -95,50 +98,58 @@ namespace Components
|
||||
|
||||
Branding::Branding()
|
||||
{
|
||||
Branding::RegisterBrandingDvars();
|
||||
RegisterBrandingDvars();
|
||||
|
||||
// UI version string
|
||||
Utils::Hook::Set<const char*>(0x43F73B, "IW4x - " GIT_TAG);
|
||||
Utils::Hook::Set<const char*>(0x43F73B, "IW4x - " REVISION_STR);
|
||||
|
||||
// Short version dvar
|
||||
Utils::Hook::Set<const char*>(0x60BD91, GIT_TAG);
|
||||
Utils::Hook::Set<const char*>(0x60BD91, REVISION_STR);
|
||||
|
||||
// Com_Init_Try_Block_Function
|
||||
Utils::Hook::Set<const char*>(0x60BAF4, BUILD_TYPE);
|
||||
Utils::Hook::Set<const char*>(0x60BAEf, GIT_TAG);
|
||||
#ifdef EXPERIMENTAL_BUILD
|
||||
Utils::Hook::Set<const char*>(0x60BAEf, REVISION_STR "-develop");
|
||||
#else
|
||||
Utils::Hook::Set<const char*>(0x60BAEf, REVISION_STR);
|
||||
#endif
|
||||
Utils::Hook::Set<const char*>(0x60BAE5, __DATE__);
|
||||
|
||||
// G_InitGame
|
||||
Utils::Hook::Set<const char*>(0x48EBA1, __DATE__);
|
||||
|
||||
Utils::Hook(0x4B12B0, Branding::GetBuildNumber, HOOK_JUMP).install()->quick();
|
||||
Utils::Hook(0x4B12B0, GetBuildNumber, HOOK_JUMP).install()->quick();
|
||||
|
||||
// Version string color
|
||||
static Game::vec4_t buildLocColor = {1.0f, 1.0f, 1.0f, 0.8f};
|
||||
Utils::Hook::Set<float*>(0x43F710, buildLocColor);
|
||||
|
||||
// Place ui version string to bottom right corner (ui_buildlocation)
|
||||
Utils::Hook(0x6310A0, Branding::Dvar_RegisterUIBuildLocation, HOOK_CALL).install()->quick(); // Dvar_RegisterVec2
|
||||
Utils::Hook(0x6310A0, Dvar_RegisterUIBuildLocation, HOOK_CALL).install()->quick(); // Dvar_RegisterVec2
|
||||
|
||||
Utils::Hook(0x60BD81, Branding::Dvar_SetVersionString, HOOK_CALL).install()->quick();
|
||||
Utils::Hook(0x60BD81, Dvar_SetVersionString, HOOK_CALL).install()->quick();
|
||||
|
||||
Utils::Hook(0x4DA842, Branding::MSG_WriteVersionStringHeader, HOOK_CALL).install()->quick();
|
||||
Utils::Hook(0x4DA842, MSG_WriteVersionStringHeader, HOOK_CALL).install()->quick();
|
||||
|
||||
// Hook CG_DrawFullScreenDebugOverlays so we may render the version when it's appropriate
|
||||
Utils::Hook(0x5AC975, Branding::CG_DrawVersion_Hk, HOOK_CALL).install()->quick();
|
||||
Utils::Hook(0x5AC975, CG_DrawVersion_Hk, HOOK_CALL).install()->quick();
|
||||
|
||||
// Console title
|
||||
if (ZoneBuilder::IsEnabled())
|
||||
{
|
||||
Utils::Hook::Set<const char*>(0x4289E8, "IW4x (" GIT_TAG "): ZoneBuilder");
|
||||
Utils::Hook::Set<const char*>(0x4289E8, "IW4x (" REVISION_STR "): ZoneBuilder");
|
||||
}
|
||||
else if (Dedicated::IsEnabled())
|
||||
{
|
||||
Utils::Hook::Set<const char*>(0x4289E8, "IW4x (" GIT_TAG "): Dedicated");
|
||||
#ifdef EXPERIMENTAL_BUILD
|
||||
Utils::Hook::Set<const char*>(0x4289E8, "IW4x " REVISION_STR "-develop: Dedicated");
|
||||
#else
|
||||
Utils::Hook::Set<const char*>(0x4289E8, "IW4x " REVISION_STR ": Dedicated");
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
Utils::Hook::Set<const char*>(0x4289E8, "IW4x (" GIT_TAG "): Console");
|
||||
Utils::Hook::Set<const char*>(0x4289E8, "IW4x (" REVISION_STR "): Console");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -9,11 +9,23 @@ namespace Components
|
||||
{
|
||||
std::unordered_map<std::string, std::function<void(Game::gentity_s*, const Command::ServerParams*)>> ClientCommand::HandlersSV;
|
||||
|
||||
bool ClientCommand::CheatsEnabled;
|
||||
|
||||
ClientCommand::CheatsScopedLock::CheatsScopedLock()
|
||||
{
|
||||
CheatsEnabled = true;
|
||||
}
|
||||
|
||||
ClientCommand::CheatsScopedLock::~CheatsScopedLock()
|
||||
{
|
||||
CheatsEnabled = false;
|
||||
}
|
||||
|
||||
bool ClientCommand::CheatsOk(const Game::gentity_s* ent)
|
||||
{
|
||||
const auto entNum = ent->s.number;
|
||||
|
||||
if (!(*Game::g_cheats)->current.enabled)
|
||||
if (!(*Game::g_cheats)->current.enabled && !CheatsEnabled)
|
||||
{
|
||||
Logger::Debug("Cheats are disabled!");
|
||||
Game::SV_GameSendServerCommand(entNum, Game::SV_CMD_CAN_IGNORE, VA("%c \"GAME_CHEATSNOTENABLED\"", 0x65));
|
||||
@ -351,12 +363,16 @@ namespace Components
|
||||
GSC::Script::AddMethod("Noclip", [](const Game::scr_entref_t entref) // gsc: self Noclip();
|
||||
{
|
||||
auto* ent = GSC::Script::Scr_GetPlayerEntity(entref);
|
||||
|
||||
CheatsScopedLock cheatsLock;
|
||||
Cmd_Noclip_f(ent, nullptr);
|
||||
});
|
||||
|
||||
GSC::Script::AddMethod("Ufo", [](const Game::scr_entref_t entref) // gsc: self Ufo();
|
||||
{
|
||||
auto* ent = GSC::Script::Scr_GetPlayerEntity(entref);
|
||||
|
||||
CheatsScopedLock cheatsLock;
|
||||
Cmd_UFO_f(ent, nullptr);
|
||||
});
|
||||
}
|
||||
@ -502,6 +518,8 @@ namespace Components
|
||||
// Hook call to ClientCommand in SV_ExecuteClientCommand so we may add custom commands
|
||||
Utils::Hook(0x6259FA, ClientCommandStub, HOOK_CALL).install()->quick();
|
||||
|
||||
CheatsEnabled = false;
|
||||
|
||||
AddCheatCommands();
|
||||
AddScriptFunctions();
|
||||
AddScriptMethods();
|
||||
|
@ -13,6 +13,15 @@ namespace Components
|
||||
private:
|
||||
static std::unordered_map<std::string, std::function<void(Game::gentity_s*, const Command::ServerParams*)>> HandlersSV;
|
||||
|
||||
static bool CheatsEnabled;
|
||||
|
||||
class CheatsScopedLock
|
||||
{
|
||||
public:
|
||||
CheatsScopedLock();
|
||||
~CheatsScopedLock();
|
||||
};
|
||||
|
||||
static void ClientCommandStub(int clientNum);
|
||||
static void AddCheatCommands();
|
||||
static void AddDevelopmentCommands();
|
||||
|
@ -96,14 +96,22 @@ namespace Components
|
||||
}
|
||||
else if (IsWindow(GetWindow()) != FALSE)
|
||||
{
|
||||
SetWindowTextA(GetWindow(), Utils::String::VA("IW4x(" GIT_TAG ") : %s", hostname.data()));
|
||||
#ifdef EXPERIMENTAL_BUILD
|
||||
SetWindowTextA(GetWindow(), Utils::String::Format("IW4x " REVISION_STR "-develop : %s", hostname));
|
||||
#else
|
||||
SetWindowTextA(GetWindow(), Utils::String::Format("IW4x " REVISION_STR " : %s", hostname));
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void Console::ShowPrompt()
|
||||
{
|
||||
wattron(InputWindow, COLOR_PAIR(10) | A_BOLD);
|
||||
wprintw(InputWindow, "%s> ", GIT_TAG);
|
||||
#ifdef EXPERIMENTAL_BUILD
|
||||
wprintw(InputWindow, "%s-develop> ", REVISION_STR);
|
||||
#else
|
||||
wprintw(InputWindow, "%s> ", REVISION_STR);
|
||||
#endif
|
||||
}
|
||||
|
||||
void Console::RefreshOutput()
|
||||
@ -427,38 +435,15 @@ namespace Components
|
||||
RefreshOutput();
|
||||
}
|
||||
|
||||
HFONT CALLBACK Console::ReplaceFont(
|
||||
[[maybe_unused]] int cHeight,
|
||||
int cWidth,
|
||||
int cEscapement,
|
||||
int cOrientation,
|
||||
[[maybe_unused]] int cWeight,
|
||||
DWORD bItalic,
|
||||
DWORD bUnderline,
|
||||
DWORD bStrikeOut,
|
||||
DWORD iCharSet,
|
||||
[[maybe_unused]] DWORD iOutPrecision,
|
||||
DWORD iClipPrecision,
|
||||
[[maybe_unused]] DWORD iQuality,
|
||||
[[maybe_unused]] DWORD iPitchAndFamily,
|
||||
[[maybe_unused]] LPCSTR pszFaceName)
|
||||
HFONT CALLBACK Console::ReplaceFont([[maybe_unused]] int cHeight, int cWidth, int cEscapement, int cOrientation, [[maybe_unused]] int cWeight, DWORD bItalic, DWORD bUnderline,
|
||||
DWORD bStrikeOut, DWORD iCharSet, [[maybe_unused]] DWORD iOutPrecision, DWORD iClipPrecision, [[maybe_unused]] DWORD iQuality,
|
||||
[[maybe_unused]] DWORD iPitchAndFamily, [[maybe_unused]] LPCSTR pszFaceName)
|
||||
{
|
||||
HFONT font = CreateFontA(
|
||||
12,
|
||||
cWidth,
|
||||
cEscapement,
|
||||
cOrientation,
|
||||
700,
|
||||
bItalic,
|
||||
bUnderline,
|
||||
bStrikeOut,
|
||||
iCharSet,
|
||||
OUT_RASTER_PRECIS,
|
||||
iClipPrecision,
|
||||
NONANTIALIASED_QUALITY,
|
||||
0x31,
|
||||
"Terminus (TTF)"
|
||||
); // Terminus (TTF)
|
||||
HFONT font = CreateFontA(12, cWidth, cEscapement, cOrientation, 700, bItalic,
|
||||
bUnderline, bStrikeOut, iCharSet, OUT_RASTER_PRECIS,
|
||||
iClipPrecision, NONANTIALIASED_QUALITY, 0x31,
|
||||
"Terminus (TTF)"
|
||||
);
|
||||
|
||||
return font;
|
||||
}
|
||||
@ -860,7 +845,11 @@ namespace Components
|
||||
AssertOffset(Game::clientUIActive_t, keyCatchers, 0x9B0);
|
||||
|
||||
// Console '%s: %s> ' string
|
||||
Utils::Hook::Set<const char*>(0x5A44B4, "IW4x_MP: " GIT_TAG "> ");
|
||||
#ifdef EXPERIMENTAL_BUILD
|
||||
Utils::Hook::Set<const char*>(0x5A44B4, "IW4x MP: " REVISION_STR "-develop> ");
|
||||
#else
|
||||
Utils::Hook::Set<const char*>(0x5A44B4, "IW4x MP: " REVISION_STR "> ");
|
||||
#endif
|
||||
|
||||
// Patch console color
|
||||
static float consoleColor[] = { 0.70f, 1.00f, 0.00f, 1.00f };
|
||||
|
@ -317,7 +317,7 @@ namespace Components
|
||||
|
||||
void Debug::Com_BugNameInc_f()
|
||||
{
|
||||
char buf[260]{};
|
||||
char buf[512]{};
|
||||
|
||||
if (std::strlen(BugName->current.string) < 4)
|
||||
{
|
||||
|
@ -442,7 +442,7 @@ namespace Components
|
||||
info["status"] = status.to_json();
|
||||
info["host"] = host.to_json();
|
||||
info["map_rotation"] = MapRotation::to_json();
|
||||
info["dedicated"] = Dedicated::com_dedicated->current.value;
|
||||
info["dedicated"] = Dedicated::com_dedicated->current.integer;
|
||||
|
||||
std::vector<nlohmann::json> players;
|
||||
|
||||
|
@ -137,6 +137,7 @@ namespace Components
|
||||
"Dasfonia",
|
||||
"Deity",
|
||||
"Dizzy",
|
||||
"Evan/Eve"
|
||||
"HardNougat",
|
||||
"INeedGames",
|
||||
"JTAG",
|
||||
|
@ -386,7 +386,7 @@ namespace Components
|
||||
info.set("bots", std::to_string(botCount));
|
||||
info.set("sv_maxclients", std::to_string(maxClientCount));
|
||||
info.set("protocol", std::to_string(PROTOCOL));
|
||||
info.set("version", GIT_TAG);
|
||||
info.set("version", REVISION_STR);
|
||||
info.set("checksum", std::to_string(Game::Sys_Milliseconds()));
|
||||
info.set("mapname", Dvar::Var("mapname").get<std::string>());
|
||||
info.set("isPrivate", *password ? "1" : "0");
|
||||
|
@ -58,7 +58,7 @@ namespace Components
|
||||
{
|
||||
Dvar::Var("uiSi_ServerName").set(serverInfo->hostname);
|
||||
Dvar::Var("uiSi_MaxClients").set(serverInfo->clients);
|
||||
Dvar::Var("uiSi_Version").set(serverInfo->shortversion);
|
||||
Dvar::Var("uiSi_Version").set(serverInfo->version);
|
||||
Dvar::Var("uiSi_SecurityLevel").set(serverInfo->securityLevel);
|
||||
Dvar::Var("uiSi_isPrivate").set(serverInfo->password ? "@MENU_YES" : "@MENU_NO");
|
||||
Dvar::Var("uiSi_Hardcore").set(serverInfo->hardcore ? "@MENU_ENABLED" : "@MENU_DISABLED");
|
||||
@ -149,7 +149,7 @@ namespace Components
|
||||
info.set("gamename", "IW4");
|
||||
info.set("sv_maxclients", std::to_string(maxClientCount));
|
||||
info.set("protocol", std::to_string(PROTOCOL));
|
||||
info.set("version", GIT_TAG);
|
||||
info.set("version", REVISION_STR);
|
||||
info.set("version", (*Game::version)->current.string);
|
||||
info.set("mapname", (*Game::sv_mapname)->current.string);
|
||||
info.set("isPrivate", *password ? "1" : "0");
|
||||
@ -261,7 +261,7 @@ namespace Components
|
||||
|
||||
Dvar::Var("uiSi_ServerName").set(info.get("sv_hostname"));
|
||||
Dvar::Var("uiSi_MaxClients").set(info.get("sv_maxclients"));
|
||||
Dvar::Var("uiSi_Version").set(info.get("shortversion"));
|
||||
Dvar::Var("uiSi_Version").set(info.get("version"));
|
||||
Dvar::Var("uiSi_SecurityLevel").set(info.get("sv_securityLevel"));
|
||||
Dvar::Var("uiSi_isPrivate").set(info.get("isPrivate") == "0" ? "@MENU_NO" : "@MENU_YES");
|
||||
Dvar::Var("uiSi_Hardcore").set(info.get("g_hardcore") == "0" ? "@MENU_DISABLED" : "@MENU_ENABLED");
|
||||
|
@ -522,7 +522,7 @@ namespace Components
|
||||
server.hostname = info.get("hostname");
|
||||
server.mapname = info.get("mapname");
|
||||
server.gametype = info.get("gametype");
|
||||
server.shortversion = info.get("shortversion");
|
||||
server.version = info.get("version");
|
||||
server.mod = info.get("fs_game");
|
||||
server.matchType = std::strtol(info.get("matchtype").data(), nullptr, 10);
|
||||
server.clients = std::strtol(info.get("clients").data(), nullptr, 10);
|
||||
|
@ -1,8 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
// This enables version filtering
|
||||
#define VERSION_FILTER
|
||||
|
||||
namespace Components
|
||||
{
|
||||
class ServerList : public Component
|
||||
@ -17,7 +14,7 @@ namespace Components
|
||||
std::string mapname;
|
||||
std::string gametype;
|
||||
std::string mod;
|
||||
std::string shortversion;
|
||||
std::string version;
|
||||
std::size_t hash;
|
||||
int clients;
|
||||
int bots;
|
||||
|
@ -18,7 +18,12 @@ namespace Components
|
||||
if (Flags::HasFlag("version"))
|
||||
{
|
||||
printf("%s", "IW4x " VERSION " (built " __DATE__ " " __TIME__ ")\n");
|
||||
#ifdef EXPERIMENTAL_BUILD
|
||||
printf("Revision: %i - develop\n", REVISION);
|
||||
#else
|
||||
printf("Revision: %i\n", REVISION);
|
||||
#endif
|
||||
|
||||
ExitProcess(EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
|
@ -23,18 +23,18 @@ namespace Components
|
||||
// team switch and intermission.
|
||||
//
|
||||
|
||||
std::mutex SoundMutexFix::SNDMutex;
|
||||
std::mutex SoundMutexFix::CloseStreamMutex;
|
||||
|
||||
void __stdcall SoundMutexFix::LockSoundMutex(int unk)
|
||||
void WINAPI SoundMutexFix::AIL_close_stream_Stub(int h_stream)
|
||||
{
|
||||
std::lock_guard lock(SNDMutex);
|
||||
std::lock_guard lock(CloseStreamMutex);
|
||||
|
||||
DWORD funcPtr = *reinterpret_cast<DWORD*>(0x6D7554); // AIL_close_stream
|
||||
Utils::Hook::Call<void __stdcall(int)>(funcPtr)(unk);
|
||||
const auto ptr = *reinterpret_cast<DWORD*>(0x6D7554); // AIL_close_stream
|
||||
Utils::Hook::Call<void WINAPI(int)>(ptr)(h_stream);
|
||||
}
|
||||
|
||||
SoundMutexFix::SoundMutexFix()
|
||||
{
|
||||
Utils::Hook(0x689EFE, &LockSoundMutex, HOOK_JUMP).install()->quick();
|
||||
Utils::Hook(0x689EFE, &AIL_close_stream_Stub, HOOK_JUMP).install()->quick();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -9,7 +9,7 @@ namespace Components
|
||||
SoundMutexFix();
|
||||
|
||||
private:
|
||||
static std::mutex SNDMutex;
|
||||
static void _stdcall LockSoundMutex(int unk);
|
||||
static std::mutex CloseStreamMutex;
|
||||
static void WINAPI AIL_close_stream_Stub(int h_stream);
|
||||
};
|
||||
}
|
||||
|
@ -978,7 +978,7 @@ namespace Components
|
||||
}
|
||||
|
||||
Logger::Print(" --------------------------------------------------------------------------------\n");
|
||||
Logger::Print(" IW4x ZoneBuilder - {}\n", VERSION);
|
||||
Logger::Print(" IW4x ZoneBuilder - {}\n", REVISION_STR);
|
||||
Logger::Print(" Commands:\n");
|
||||
Logger::Print("\t-buildzone [zone]: builds a zone from a csv located in zone_source\n");
|
||||
Logger::Print("\t-buildall: builds all zones in zone_source\n");
|
||||
|
@ -10,23 +10,22 @@ namespace Game::Engine
|
||||
{
|
||||
Sys_EnterCriticalSection(this->s_);
|
||||
this->hasOwnership_ = true;
|
||||
return;
|
||||
}
|
||||
|
||||
if (type == SCOPED_CRITSECT_TRY)
|
||||
{
|
||||
this->hasOwnership_ = Sys_TryEnterCriticalSection(this->s_);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (type == SCOPED_CRITSECT_TRY)
|
||||
if (type == SCOPED_CRITSECT_RELEASE)
|
||||
{
|
||||
this->hasOwnership_ = Sys_TryEnterCriticalSection(this->s_);
|
||||
Sys_LeaveCriticalSection(this->s_);
|
||||
this->isScopedRelease_ = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (type == SCOPED_CRITSECT_RELEASE)
|
||||
{
|
||||
Sys_LeaveCriticalSection(this->s_);
|
||||
this->isScopedRelease_ = true;
|
||||
}
|
||||
|
||||
this->hasOwnership_ = false;
|
||||
}
|
||||
this->hasOwnership_ = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -69,12 +69,12 @@ BEGIN
|
||||
#else
|
||||
VALUE "FileDescription", "IW4 client modification"
|
||||
#endif
|
||||
VALUE "FileVersion", GIT_TAG
|
||||
VALUE "FileVersion", REVISION_STR
|
||||
VALUE "InternalName", "iw4x"
|
||||
VALUE "LegalCopyright", "Copyright 2023 The XLabsProject Team. All rights reserved."
|
||||
VALUE "OriginalFilename", "iw4x.dll"
|
||||
VALUE "ProductName", "IW4x"
|
||||
VALUE "ProductVersion", GIT_TAG
|
||||
VALUE "ProductVersion", REVISION_STR
|
||||
END
|
||||
END
|
||||
BLOCK "VarFileInfo"
|
||||
|
@ -51,13 +51,9 @@ namespace Utils
|
||||
std::string InfoString::build() const
|
||||
{
|
||||
std::string infoString;
|
||||
|
||||
auto first = true;
|
||||
for (const auto& [key, value] : this->keyValuePairs_)
|
||||
{
|
||||
if (first) first = false;
|
||||
else infoString.append("\\");
|
||||
|
||||
infoString.append("\\");
|
||||
infoString.append(key);
|
||||
infoString.append("\\");
|
||||
infoString.append(value);
|
||||
|
@ -90,10 +90,8 @@ namespace Utils::String
|
||||
[[nodiscard]] const char* Format(std::string_view fmt, Args&&... args)
|
||||
{
|
||||
static thread_local std::string vaBuffer;
|
||||
vaBuffer.clear();
|
||||
|
||||
(SanitizeFormatArgs(args), ...);
|
||||
std::vformat_to(std::back_inserter(vaBuffer), fmt, std::make_format_args(args...));
|
||||
std::vformat(fmt, std::make_format_args(args...)).swap(vaBuffer);
|
||||
return vaBuffer.data();
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user