Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add bxt_enable_big_map #500

Merged
merged 10 commits into from
Feb 8, 2024
76 changes: 76 additions & 0 deletions BunnymodXT/modules/HwDLL.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -872,6 +872,8 @@ void HwDLL::Clear()

tas_studio_norefresh_override = 0;

g_sv_delta = nullptr;

if (resetState == ResetState::NORMAL) {
input.Clear();
ResetTASPlaybackState();
Expand Down Expand Up @@ -1314,6 +1316,12 @@ void HwDLL::FindStuff()
} else {
EngineDevWarning("[hw dll] Could not find R_SetFrustum.\n");
}

g_sv_delta = reinterpret_cast<void**>(MemUtils::GetSymbolAddress(m_Handle, "g_sv_delta"));
if (g_sv_delta)
EngineDevMsg("[hw dll] Found g_sv_delta at %p.\n", g_sv_delta);
else
EngineDevWarning("[hw dll] Could not find g_sv_delta.\n");
}
else
{
Expand Down Expand Up @@ -2017,6 +2025,20 @@ void HwDLL::FindStuff()
}
});

void *SV_LookupDelta;
auto fSV_LookupDelta = FindAsync(
SV_LookupDelta,
patterns::engine::SV_LookupDelta,
[&](auto pattern) {
switch (pattern - patterns::engine::SV_LookupDelta.cbegin())
{
default:
case 0: // HL-SteamPipe.
g_sv_delta = *reinterpret_cast<void***>(reinterpret_cast<uintptr_t>(SV_LookupDelta) + 6);
break;
}
});

{
auto pattern = fClientDLL_CheckStudioInterface.get();
if (ClientDLL_CheckStudioInterface) {
Expand Down Expand Up @@ -2293,6 +2315,17 @@ void HwDLL::FindStuff()
}
}

{
auto pattern = fSV_LookupDelta.get();
if (SV_LookupDelta) {
EngineDevMsg("[hw dll] Found SV_LookupDelta at %p (using the %s pattern).\n", SV_LookupDelta, pattern->name());
EngineDevMsg("[hw dll] Found g_sv_delta at %p.\n", g_sv_delta);
} else {
EngineDevWarning("[hw dll] Could not find SV_LookupDelta.\n");
EngineWarning("[hw dll] Loading big maps on the fly is not available.\n");
}
}

#define GET_FUTURE(future_name) \
{ \
auto pattern = f##future_name.get(); \
Expand Down Expand Up @@ -5205,6 +5238,43 @@ struct HwDLL::Cmd_BXT_Skybox_Reload
}
};

void ChangeDeltaForBigMap(delta_s *delta)
{
for (int i = 0; i < delta->fieldCount; ++i) {
delta_description_s *curr_description = delta->pdd + i;
// "origin[0]", "origin[1]", ... so comparing "origin" is enough
if (!strncmp(curr_description->fieldName, "origin", 6)) {
auto curr_map_size = (1 << curr_description->significant_bits) / curr_description->premultiply;
if (curr_map_size < BIG_MAP_SIZE) {
curr_description->significant_bits = (int) std::ceil(std::log(BIG_MAP_SIZE * 2.0f * curr_description->premultiply) / std::log(2));
}
}
}
}

struct HwDLL::Cmd_BXT_Enable_Big_Map
{
USAGE("\
Usage: bxt_enable_big_map\n\n\
After entering this command in main menu, you can load maps beyond +-4096 limit.\n\
Due to shortcomings of the implementation, you must restart your game in order to revert the effect.\n\
Can be called in command line option when start up the game.\n");
khanghugo marked this conversation as resolved.
Show resolved Hide resolved

static void handler()
{
auto &hw = HwDLL::GetInstance();

if (hw.g_sv_delta == NULL)
Copy link
Owner

Choose a reason for hiding this comment

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

Should this also check for IsInWorld?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Would that make it not work until a server is started because the pointer is yet found? This big map works by changing deltas before starting the server. Delta (delta.lst) is loaded upon starting the game, not the server.

The IsInWorld function is auxiliary compared to delta change, it is more for a select few entities to behave in big map.

Copy link
Owner

Choose a reason for hiding this comment

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

I see

hw.ORIG_Con_Printf("Feature is not supported.\n");
else {
hw.ORIG_Con_Printf("Big map support enabled.\nCurrent maximum map size is +-%d\n", BIG_MAP_SIZE);
hw.is_big_map = true;
for (delta_info_s *curr_delta = *reinterpret_cast<delta_info_s**>(hw.g_sv_delta); curr_delta != NULL && curr_delta->delta != NULL; curr_delta = curr_delta->next)
ChangeDeltaForBigMap(curr_delta->delta);
}
}
};

extern "C" DLLEXPORT void bxt_tas_load_script_from_string(const char *script)
{
auto& hw = HwDLL::GetInstance();
Expand Down Expand Up @@ -5600,6 +5670,7 @@ void HwDLL::RegisterCVarsAndCommandsIfNeeded()
wrapper::Add<Cmd_BXT_Splits_Track_Z, Handler<int>, Handler<const char*, int>>("bxt_splits_track_z");
wrapper::Add<Cmd_BXT_Splits_Place_Down, Handler<>, Handler<const char*>>("+bxt_splits_place");
wrapper::Add<Cmd_BXT_Splits_Place_Up, Handler<>, Handler<const char*>>("-bxt_splits_place");
wrapper::Add<Cmd_BXT_Enable_Big_Map, Handler<>>("bxt_enable_big_map");
}

void HwDLL::InsertCommands()
Expand Down Expand Up @@ -7201,6 +7272,11 @@ HOOK_DEF_1(HwDLL, int, __cdecl, Host_FilterTime, float, passedTime)
RuntimeData::Add(RuntimeData::PlayerHealth{playerhealth});

lastRecordedHealth = playerhealth;

int bxt_flags = 0;
if (is_big_map)
bxt_flags |= BXT_FLAGS_BIG_MAP;
RuntimeData::Add(RuntimeData::Flags{bxt_flags});
}

if (runningFrames) {
Expand Down
8 changes: 8 additions & 0 deletions BunnymodXT/modules/HwDLL.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#include "../cvars.hpp"
#include "taslogger/writer.hpp"
#include "../input_editor.hpp"
#include "../shared.hpp"

enum class TASEditorMode {
DISABLED,
Expand Down Expand Up @@ -534,6 +535,7 @@ class HwDLL : public IHookableNameFilterOrdered
struct Cmd_Minus_BXT_CH_Hook;
struct Cmd_BXT_CH_CheckPoint_Create;
struct Cmd_BXT_CH_CheckPoint_GoTo;
struct Cmd_BXT_Enable_Big_Map;

void RegisterCVarsAndCommandsIfNeeded();
void InsertCommands();
Expand Down Expand Up @@ -783,4 +785,10 @@ class HwDLL : public IHookableNameFilterOrdered
Vector ch_checkpoint_vel;
Vector ch_checkpoint_viewangles;
bool ch_checkpoint_is_duck;

public:
bool is_big_map = false;

protected:
void **g_sv_delta;
};
78 changes: 76 additions & 2 deletions BunnymodXT/modules/ServerDLL.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
#include "../runtime_data.hpp"
#include "../custom_triggers.hpp"
#include "../splits.hpp"
#include "../shared.hpp"

// Linux hooks.
#ifndef _WIN32
Expand Down Expand Up @@ -90,6 +91,11 @@ extern "C" Vector __cdecl _ZN11CBaseEntity17FireBulletsPlayerEj6VectorS0_S0_fiii
{
return ServerDLL::HOOKED_CBaseEntity__FireBulletsPlayer_Linux(thisptr, cShots, vecSrc, vecDirShooting, vecSpread, flDistance, iBulletType, iTracerFreq, iDamage, pevAttacker, shared_rand);
}

extern "C" int __cdecl _ZN11CBaseEntity9IsInWorldEv(void *thisptr)
{
return ServerDLL::HOOKED_CBaseEntity__IsInWorld_Linux(thisptr);
}
#endif

void ServerDLL::Hook(const std::wstring& moduleName, void* moduleHandle, void* moduleBase, size_t moduleLength, bool needToIntercept)
Expand Down Expand Up @@ -150,7 +156,9 @@ void ServerDLL::Hook(const std::wstring& moduleName, void* moduleHandle, void* m
ORIG_CTriggerEndSection__EndSectionTouch, HOOKED_CTriggerEndSection__EndSectionTouch,
ORIG_ShiftMonsters, HOOKED_ShiftMonsters,
ORIG_PM_Duck, HOOKED_PM_Duck,
ORIG_PM_UnDuck, HOOKED_PM_UnDuck);
ORIG_PM_UnDuck, HOOKED_PM_UnDuck,
ORIG_CBaseEntity__IsInWorld, HOOKED_CBaseEntity__IsInWorld,
ORIG_CBaseEntity__IsInWorld_Linux, HOOKED_CBaseEntity__IsInWorld_Linux);
}
}

Expand Down Expand Up @@ -201,7 +209,9 @@ void ServerDLL::Unhook()
ORIG_CTriggerEndSection__EndSectionTouch,
ORIG_ShiftMonsters,
ORIG_PM_Duck,
ORIG_PM_UnDuck);
ORIG_PM_UnDuck,
ORIG_CBaseEntity__IsInWorld,
ORIG_CBaseEntity__IsInWorld_Linux);
}

Clear();
Expand Down Expand Up @@ -272,6 +282,8 @@ void ServerDLL::Clear()
ORIG_ShiftMonsters = nullptr;
ORIG_PM_Duck = nullptr;
ORIG_PM_UnDuck = nullptr;
ORIG_CBaseEntity__IsInWorld = nullptr;
ORIG_CBaseEntity__IsInWorld_Linux = nullptr;
ppmove = nullptr;
offPlayerIndex = 0;
offOldbuttons = 0;
Expand Down Expand Up @@ -809,6 +821,7 @@ void ServerDLL::FindStuff()
auto fCBasePlayer__ViewPunch = FindAsync(ORIG_CBasePlayer__ViewPunch, patterns::server::CBasePlayer__ViewPunch);
auto fCBasePlayer__Jump = FindAsync(ORIG_CBasePlayer__Jump, patterns::server::CBasePlayer__Jump);
auto fCBaseDoor__DoorActivate = FindAsync(ORIG_CBaseDoor__DoorActivate, patterns::server::CBaseDoor__DoorActivate);
auto fCBaseEntity__IsInWorld = FindAsync(ORIG_CBaseEntity__IsInWorld, patterns::server::CBaseEntity__IsInWorld);

uintptr_t pDispatchRestore;
auto fDispatchRestore = FindAsync(
Expand Down Expand Up @@ -1566,6 +1579,19 @@ void ServerDLL::FindStuff()
}
}

{
auto pattern = fCBaseEntity__IsInWorld.get();
if (ORIG_CBaseEntity__IsInWorld) {
EngineDevMsg("[server dll] Found CBaseEntity::IsInWorld at %p (using the %s pattern).\n", ORIG_CBaseEntity__IsInWorld, pattern->name());
} else {
ORIG_CBaseEntity__IsInWorld_Linux = reinterpret_cast<_CBaseEntity__IsInWorld_Linux>(MemUtils::GetSymbolAddress(m_Handle, "_ZN11CBaseEntity9IsInWorldEv"));
if (ORIG_CBaseEntity__IsInWorld_Linux)
EngineDevMsg("[server dll] Found CBaseEntity::IsInWorld [Linux] at %p.\n", ORIG_CBaseEntity__IsInWorld_Linux);
else
EngineDevWarning("[server dll] Could not find CBaseEntity::IsInWorlds.\n");
khanghugo marked this conversation as resolved.
Show resolved Hide resolved
}
}

if (!pEngfuncs)
{
pEngfuncs = reinterpret_cast<enginefuncs_t*>(MemUtils::GetSymbolAddress(m_Handle, "g_engfuncs"));
Expand Down Expand Up @@ -3247,3 +3273,51 @@ HOOK_DEF_1(ServerDLL, void, __fastcall, CBasePlayer__Jump, void*, thisptr)
ORIG_CBasePlayer__Jump(thisptr);
insideCBasePlayerJump = false;
}

int ServerDLL::IsInWorld(Vector origin, Vector velocity, int map_size) // https://github.com/ValveSoftware/halflife/blob/c7240b965743a53a29491dd49320c88eecf6257b/dlls/cbase.cpp#L706
{
// Copy pasted from HLSDK, but origin value is changed
// Maybe in the future we should also make velocity check to use sv_maxvelocity value,
// but I don't see any side effect when going beyond it ever

// position
if (origin.x >= map_size) return 0;
if (origin.y >= map_size) return 0;
if (origin.z >= map_size) return 0;
if (origin.x <= -map_size) return 0;
if (origin.y <= -map_size) return 0;
if (origin.z <= -map_size) return 0;
// speed
if (velocity.x >= 2000) return 0;
if (velocity.y >= 2000) return 0;
if (velocity.z >= 2000) return 0;
if (velocity.x <= -2000) return 0;
if (velocity.y <= -2000) return 0;
if (velocity.z <= -2000) return 0;

return 1;
}

HOOK_DEF_1(ServerDLL, int, __fastcall, CBaseEntity__IsInWorld, void*, thisptr)
{
if (HwDLL::GetInstance().is_big_map)
{
entvars_t *pev = *reinterpret_cast<entvars_t**>(reinterpret_cast<uintptr_t>(thisptr) + 4);
if (pev)
return IsInWorld(pev->origin, pev->velocity, BIG_MAP_SIZE);
}

return ORIG_CBaseEntity__IsInWorld(thisptr);
}

HOOK_DEF_1(ServerDLL, int, __cdecl, CBaseEntity__IsInWorld_Linux, void*, thisptr)
{
if (HwDLL::GetInstance().is_big_map)
{
entvars_t *pev = *reinterpret_cast<entvars_t**>(reinterpret_cast<uintptr_t>(thisptr) + 4);
if (pev)
return IsInWorld(pev->origin, pev->velocity, BIG_MAP_SIZE);
}

return ORIG_CBaseEntity__IsInWorld_Linux(thisptr);
}
4 changes: 4 additions & 0 deletions BunnymodXT/modules/ServerDLL.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,8 @@ class ServerDLL : public IHookableDirFilter
HOOK_DECL(void, __fastcall, CBasePlayer__ViewPunch, void* thisptr, int edx, float p, float y, float r)
HOOK_DECL(void, __fastcall, CBasePlayer__Jump, void* thisptr)
HOOK_DECL(void, __fastcall, CTriggerCamera__FollowTarget, void* thisptr)
HOOK_DECL(int, __fastcall, CBaseEntity__IsInWorld, void* thisptr)
HOOK_DECL(int, __cdecl, CBaseEntity__IsInWorld_Linux, void* thisptr)

public:
static ServerDLL& GetInstance()
Expand Down Expand Up @@ -106,6 +108,8 @@ class ServerDLL : public IHookableDirFilter

void SetStamina(bool makeItZero);

int IsInWorld(Vector origin, Vector velocity, int map_size);

bool is_cof = false; // Cry of Fear-specific
ptrdiff_t offm_fStamina; // Cry of Fear-specific

Expand Down
9 changes: 9 additions & 0 deletions BunnymodXT/patterns.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -792,6 +792,10 @@ namespace patterns
"CoF-5936",
"55 8B EC A1 ?? ?? ?? ?? 3B 05 ?? ?? ?? ?? 75 ?? EB ?? 8B 0D ?? ?? ?? ?? 89 0D ?? ?? ?? ?? E8"
);

PATTERNS(SV_LookupDelta,
"HL-SteamPipe",
"55 8B EC 56 8B 35 ?? ?? ?? ?? 57 8B 7D ?? 85 F6 74 ?? 8B 46 ?? 50 57 E8 ?? ?? ?? ?? 83 C4 08 85 C0 74 ?? 8B 36 85 F6 75 ?? 57")
}

namespace server
Expand Down Expand Up @@ -1158,6 +1162,11 @@ namespace patterns
"CoF-5936",
"55 8B EC 83 EC 0C 56 8B F1 8B 0D"
);

PATTERNS(CBaseEntity__IsInWorld,
"HL-SteamPipe",
"8B 49 04 D9 41 08 D8 1D ?? ?? ?? ?? DF E0"
);
}

namespace client
Expand Down
14 changes: 14 additions & 0 deletions BunnymodXT/runtime_data.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ namespace RuntimeData
EDICTS,
PLAYERHEALTH,
SPLIT_MARKER,
FLAGS,
};

// Encrypting filter.
Expand Down Expand Up @@ -358,6 +359,12 @@ namespace RuntimeData
archive(m.map_name);
}

void operator()(const Flags& f) const {
archive(RuntimeDataType::FLAGS);

archive(f.flags);
}

private:
Archive& archive;
};
Expand Down Expand Up @@ -474,6 +481,12 @@ namespace RuntimeData
data = m;
break;
}
case RuntimeDataType::FLAGS: {
Flags f;
archive(f.flags);
data = f;
break;
}
default: {
EngineDevWarning("Read unknown RuntimeDataType %d\n", data_type);
break;
Expand Down Expand Up @@ -538,6 +551,7 @@ namespace RuntimeData
void operator()(const RuntimeData::CustomTriggerCommand& c) const {}
void operator()(const RuntimeData::Edicts& e) const {}
void operator()(const RuntimeData::SplitMarker& m) const {}
void operator()(const RuntimeData::Flags& f) const {}

private:
// bxt commands that should be executed when found during demo playback
Expand Down
7 changes: 6 additions & 1 deletion BunnymodXT/runtime_data.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,10 @@ namespace RuntimeData
std::string map_name;
};

struct Flags {
int flags;
};

using Data = boost::variant<VersionInfo,
CVarValues,
Time,
Expand All @@ -75,7 +79,8 @@ namespace RuntimeData
CustomTriggerCommand,
Edicts,
PlayerHealth,
SplitMarker>;
SplitMarker,
Flags>;

void Add(Data data);
void Clear();
Expand Down
4 changes: 4 additions & 0 deletions BunnymodXT/shared.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,7 @@ enum class EventType : unsigned char {

#define MQ_NAME "BunnymodXT-TASView"
#define BUNNYSPLIT_PIPE_NAME "BunnymodXT-BunnySplit"

#define BIG_MAP_SIZE 32768 // +-BIG_MAP_SIZE so 64k x 64k map should have value of 32k

#define BXT_FLAGS_BIG_MAP (1<<0)
Loading
Loading