Skip to content

Commit

Permalink
feat(game/five): introduce sv_replaceExeToSwitchBuilds feature flag
Browse files Browse the repository at this point in the history
When set to false, this flag indicates that instead of loading the old
game build executable and corresponding files - we should use the latest
stable game build executable and only replace certain parts of
update.rpf. By default the flag is set to true which corresponds to the
default behavior as it was before this commit.

Also introduce sv_enforceGameBuild 1, which corresponds to the game
version without any DLC content. If build 1 is set - the game will run
as if sv_replaceExeToSwitchBuilds is set to false.

In the future this will allow to deprecate old executables while
still allowing servers to control set of content/dlcs that they want to
have. Deprecating old executables will significatly simplify our
codebase and speed up development.
  • Loading branch information
Nobelium-cfx committed Oct 21, 2024
1 parent 20656b6 commit df68640
Show file tree
Hide file tree
Showing 23 changed files with 1,205 additions and 503 deletions.
1,222 changes: 777 additions & 445 deletions code/client/launcher/GameCache.cpp

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion code/client/shared/CfxSubProcess.h
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ inline const wchar_t* MakeCfxSubProcess(const std::wstring& processType, const s
if ((origin.find(L"game") == 0 && origin != L"game_mtl") || processType == L"DumpServer")
{
#if defined(GTA_FIVE) || defined(IS_RDR3)
auto buildNumber = xbr::GetGameBuild();
auto buildNumber = xbr::GetRequestedGameBuild();

if (buildNumber != 1604 && buildNumber != 1311)
{
Expand Down
67 changes: 62 additions & 5 deletions code/client/shared/CrossBuildRuntime.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,20 @@ namespace xbr
// When there's no entry for a specific major game build, revision "0" will be assumed in the relevant code.
//

// TODO: Replace with the default game build once we use latest game build as default instead of the 1604 one.
inline unsigned int GetLatestStableGameBuild()
{
#if defined(IS_RDR3)
return 1491;
#elif defined(GTA_FIVE)
return 3258;
#elif defined(GTA_NY)
return 43;
#else
return 0;
#endif
}

struct GameBuildUniquifier
{
int m_minor;
Expand Down Expand Up @@ -59,23 +73,66 @@ inline std::pair<int, int> ParseGameBuildFromString(const std::string& buildStr)
#ifndef XBR_BUILDS_ONLY
namespace xbr
{
int GetGameBuildInit();
int GetRequestedGameBuildInit();
bool GetReplaceExecutableInit();

#ifdef IS_FXSERVER
inline int GetGameBuild()
{
#ifndef IS_FXSERVER
return 0;
}

inline int GetRequestedGameBuild()
{
return 0;
}

inline bool GetReplaceExecutable()
{
return false;
}

#else

inline int GetRequestedGameBuild()
{
static int buildNumber = -1;

if (buildNumber == -1)
{
buildNumber = GetGameBuildInit();
buildNumber = GetRequestedGameBuildInit();
}

return buildNumber;
#else
return 0;
}

inline bool GetReplaceExecutable()
{
// Special build 1 with all DLCs turned off can not be achieved by replacing the executable.
static bool replaceExecutable = GetReplaceExecutableInit() && GetRequestedGameBuild() != 1;
return replaceExecutable;
}

inline int GetGameBuild()
{
// For GTA5 we may want to ignore the CLI build request and use the latest build.
// In this case the requested build behavior will be achieved by partially loading old update.rpf files in UpdateRpfOverrideMount.cpp.
#ifdef GTA_FIVE
if (!GetReplaceExecutable() && GetRequestedGameBuild() < GetLatestStableGameBuild())
{
static int buildNumber = -1;

if (buildNumber == -1)
{
buildNumber = GetLatestStableGameBuild();
}

return buildNumber;
}
#endif
return GetRequestedGameBuild();
}
#endif

#ifndef IS_FXSERVER
inline std::string_view GetCurrentGameBuildString()
Expand Down
19 changes: 17 additions & 2 deletions code/client/shared/XBRInit.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

namespace xbr
{
int GetGameBuildInit()
int GetRequestedGameBuildInit()
{
constexpr const std::pair<std::wstring_view, int> buildNumbers[] = {
#define EXPAND(_, __, x) \
Expand All @@ -21,7 +21,8 @@ int GetGameBuildInit()

auto sharedData = CfxState::Get();
std::wstring_view cli = (sharedData->initCommandLine[0]) ? sharedData->initCommandLine : GetCommandLineW();
auto buildNumber = std::get<1>(buildNumbers[0]);
// TODO: replace with default game build defined in CrossBuildRuntime.h.
auto buildNumber = 1604;

for (auto [build, number] : buildNumbers)
{
Expand All @@ -34,5 +35,19 @@ int GetGameBuildInit()

return buildNumber;
}

bool GetReplaceExecutableInit()
{
bool replaceExecutable = true;

std::wstring fpath = MakeRelativeCitPath(L"CitizenFX.ini");
if (GetFileAttributes(fpath.c_str()) != INVALID_FILE_ATTRIBUTES)
{
replaceExecutable = (GetPrivateProfileInt(L"Game", L"ReplaceExecutable", 1, fpath.c_str()) != 0);
}

return replaceExecutable;
}

}
#endif
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@

static inline auto GetGameBuild()
{
return xbr::GetGameBuild();
return xbr::GetRequestedGameBuild();
}
#else
static inline auto GetGameBuild()
Expand Down
1 change: 1 addition & 0 deletions code/components/citizen-server-impl/include/GameServer.h
Original file line number Diff line number Diff line change
Expand Up @@ -371,6 +371,7 @@ namespace fx
SVIMP_EXPORT void SetOneSyncPopulation(bool population);
SVIMP_EXPORT std::string_view GetEnforcedGameBuild();
SVIMP_EXPORT int GetEnforcedGameBuildNumber();
SVIMP_EXPORT bool GetReplaceExecutable();
}

DECLARE_INSTANCE_TYPE(fx::GameServer);
Expand Down
26 changes: 15 additions & 11 deletions code/components/citizen-server-impl/include/state/ServerGameState.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ static constexpr const size_t kGamePlayerCap =

#include <Client.h>
#include <GameServer.h>
#include <CrossBuildRuntime.h>

#include <ServerInstanceBase.h>
#include <ServerTime.h>
Expand Down Expand Up @@ -50,11 +51,14 @@ static constexpr const size_t kGamePlayerCap =
#include <net/NetObjEntityType.h>

#ifdef STATE_FIVE
// For GTA5, if the feature flag for new build system is set, we use the latest stable build executable even if lower version is enforced.
// The different sv_enforceGameBuild behaviors is achieved on the client side by loading different DLC sets with IsDlcIncludedInBuild.

inline bool Is2060()
{
static bool value = ([]()
{
return fx::GetEnforcedGameBuildNumber() >= 2060;
return (!fx::GetReplaceExecutable() && xbr::GetLatestStableGameBuild() >= 2060) || fx::GetEnforcedGameBuildNumber() >= 2060;
})();

return value;
Expand All @@ -64,7 +68,7 @@ inline bool Is2189()
{
static bool value = ([]()
{
return fx::GetEnforcedGameBuildNumber() >= 2189;
return (!fx::GetReplaceExecutable() && xbr::GetLatestStableGameBuild() >= 2189) || fx::GetEnforcedGameBuildNumber() >= 2189;
})();

return value;
Expand All @@ -74,7 +78,7 @@ inline bool Is2372()
{
static bool value = ([]()
{
return fx::GetEnforcedGameBuildNumber() >= 2372;
return (!fx::GetReplaceExecutable() && xbr::GetLatestStableGameBuild() >= 2372) || fx::GetEnforcedGameBuildNumber() >= 2372;
})();

return value;
Expand All @@ -84,7 +88,7 @@ inline bool Is2545()
{
static bool value = ([]()
{
return fx::GetEnforcedGameBuildNumber() >= 2545;
return (!fx::GetReplaceExecutable() && xbr::GetLatestStableGameBuild() >= 2545) || fx::GetEnforcedGameBuildNumber() >= 2545;
})();

return value;
Expand All @@ -94,7 +98,7 @@ inline bool Is2612()
{
static bool value = ([]()
{
return fx::GetEnforcedGameBuildNumber() >= 2612;
return (!fx::GetReplaceExecutable() && xbr::GetLatestStableGameBuild() >= 2612) || fx::GetEnforcedGameBuildNumber() >= 2612;
})();

return value;
Expand All @@ -104,7 +108,7 @@ inline bool Is2699()
{
static bool value = ([]()
{
return fx::GetEnforcedGameBuildNumber() >= 2699;
return (!fx::GetReplaceExecutable() && xbr::GetLatestStableGameBuild() >= 2699) || fx::GetEnforcedGameBuildNumber() >= 2699;
})();

return value;
Expand All @@ -114,7 +118,7 @@ inline bool Is2802()
{
static bool value = ([]()
{
return fx::GetEnforcedGameBuildNumber() >= 2802;
return (!fx::GetReplaceExecutable() && xbr::GetLatestStableGameBuild() >= 2802) || fx::GetEnforcedGameBuildNumber() >= 2802;
})();

return value;
Expand All @@ -124,7 +128,7 @@ inline bool Is2944()
{
static bool value = ([]()
{
return fx::GetEnforcedGameBuildNumber() >= 2944;
return (!fx::GetReplaceExecutable() && xbr::GetLatestStableGameBuild() >= 2944) || fx::GetEnforcedGameBuildNumber() >= 2944;
})();

return value;
Expand All @@ -134,7 +138,7 @@ inline bool Is3095()
{
static bool value = ([]()
{
return fx::GetEnforcedGameBuildNumber() >= 3095;
return (!fx::GetReplaceExecutable() && xbr::GetLatestStableGameBuild() >= 3095) || fx::GetEnforcedGameBuildNumber() >= 3095;
})();

return value;
Expand All @@ -144,7 +148,7 @@ inline bool Is3258()
{
static bool value = ([]()
{
return fx::GetEnforcedGameBuildNumber() >= 3258;
return (!fx::GetReplaceExecutable() && xbr::GetLatestStableGameBuild() >= 3258) || fx::GetEnforcedGameBuildNumber() >= 3258;
})();

return value;
Expand All @@ -154,7 +158,7 @@ inline bool Is3323()
{
static bool value = ([]()
{
return fx::GetEnforcedGameBuildNumber() >= 3323;
return (!fx::GetReplaceExecutable() && xbr::GetLatestStableGameBuild() >= 3323) || fx::GetEnforcedGameBuildNumber() >= 3323;
})();

return value;
Expand Down
6 changes: 6 additions & 0 deletions code/components/citizen-server-impl/src/GameStateExports.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ static bool g_oneSyncPopulation;
static bool(*g_onesync)();

extern fx::GameBuild g_enforcedGameBuild;
extern bool g_replaceExecutable;

namespace fx
{
Expand Down Expand Up @@ -67,4 +68,9 @@ int GetEnforcedGameBuildNumber()

return build;
}

bool GetReplaceExecutable()
{
return g_replaceExecutable;
}
}
7 changes: 7 additions & 0 deletions code/components/citizen-server-impl/src/InitConnectMethod.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -379,6 +379,7 @@ std::optional<TicketData> VerifyTicketEx(const std::string& ticket, const Botan:

extern std::shared_ptr<ConVar<bool>> g_oneSyncVar;
fx::GameBuild g_enforcedGameBuild;
bool g_replaceExecutable;

static InitFunction initFunction([]()
{
Expand All @@ -402,6 +403,9 @@ static InitFunction initFunction([]()
g_enforcedGameBuild = "1604";
auto enforceGameBuildVar = instance->AddVariable<fx::GameBuild>("sv_enforceGameBuild", ConVar_ReadOnly | ConVar_ServerInfo, "1604", &g_enforcedGameBuild);

g_replaceExecutable = true;
auto replaceExecutableVar = instance->AddVariable<bool>("sv_replaceExeToSwitchBuilds", ConVar_ReadOnly | ConVar_ServerInfo, true, &g_replaceExecutable);

auto poolSizesIncrease = std::make_shared<std::unordered_map<std::string, uint32_t>>();
auto poolSizesIncreaseVar = instance->AddVariable<std::string>("sv_poolSizesIncrease", ConVar_ServerInfo | ConVar_Internal, "");
auto poolSizesIncreaseCmd = instance->AddCommand("increase_pool_size", [instance, poolSizesIncreaseVar, poolSizesIncrease](const std::string& poolName, int sizeIncrease)
Expand Down Expand Up @@ -739,6 +743,9 @@ static InitFunction initFunction([]()
trace("Something went wrong. Pool sizes increase may not be set.");
}

// Capture replaceExecutableVar just to prolong it's lifetime until connection is initialized.
(void)replaceExecutableVar;

{
auto oldClient = clientRegistry->GetClientByGuid(guid);

Expand Down
1 change: 1 addition & 0 deletions code/components/citizen-server-main/src/ServerInstance.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ static std::set<std::string, console::IgnoreCaseLess> setList =
"onesync_enableBeyond",
"gamename",
"sv_enforceGameBuild",
"sv_replaceExeToSwitchBuilds",
"sv_licenseKey",
"resources_useSystemChat",
};
Expand Down
22 changes: 11 additions & 11 deletions code/components/font-renderer/src/GtaGameInterface.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@
#include <CoreConsole.h>
#include <CrossBuildRuntime.h>
#include <utf8.h>
#include <Hooking.h>
#include <CL2LaunchMode.h>
#include <Hooking.h>
#include <CL2LaunchMode.h>
#include <CfxReleaseInfo.h>

#include "memdbgon.h"
Expand Down Expand Up @@ -277,15 +277,15 @@ FontRendererGameInterface* CreateGameInterface()
return &g_gtaGameInterface;
}

#include <random>

#include <random>

static std::wstring GetUpdateChannel()
{
wchar_t resultPath[1024];

static std::wstring fpath = MakeRelativeCitPath(L"CitizenFX.ini");
GetPrivateProfileString(L"Game", L"UpdateChannel", L"production", resultPath, std::size(resultPath), fpath.c_str());

GetPrivateProfileString(L"Game", L"UpdateChannel", L"production", resultPath, std::size(resultPath), fpath.c_str());

return resultPath;
}

Expand Down Expand Up @@ -435,7 +435,7 @@ static InitFunction initFunction([] ()
brandName += L"*";
}

brandName += fmt::sprintf(L" (b%d)", xbr::GetGameBuild());
brandName += fmt::sprintf(L" (b%d)", xbr::GetRequestedGameBuild());

if (launch::IsSDKGuest())
{
Expand Down Expand Up @@ -466,14 +466,14 @@ static InitFunction initFunction([] ()
})();

brandName = fmt::sprintf(L"Ver. %d%s", version, updateChannelTag);
}

}

enum class AnchorPos
{
TopRight = 0,
BottomRight = 1,
TopLeft = 2,
BottomLeft = 3,
BottomLeft = 3,
};

static auto anchorPosBase = ([]()
Expand All @@ -493,7 +493,7 @@ static InitFunction initFunction([] ()
})();

auto anchorPos = anchorPosBase;


// in the menu, we want it to always be on the bottom right
if (!inGame)
{
Expand Down
Loading

1 comment on commit df68640

@taoletsgo
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the future this will allow to deprecate old executables while
still allowing servers to control set of content/dlcs that they want to
have. Deprecating old executables will significatly simplify our
codebase and speed up development.

I don't know if you can see this comment. I searched through the commit history and found it. In the future, a true option should also be provided. For details, please refer to here:
#3024

Thx!!!

Please sign in to comment.