Skip to content

Commit

Permalink
Add support for the game's respawn time overriding
Browse files Browse the repository at this point in the history
  • Loading branch information
nosoop committed Mar 15, 2022
1 parent e99d380 commit f4831b8
Show file tree
Hide file tree
Showing 3 changed files with 89 additions and 1 deletion.
21 changes: 21 additions & 0 deletions gamedata/tf2.utils.nosoop.txt
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,18 @@
"offset" "34"
}
}
"offsetof(CTFPlayer::m_flRespawnTimeOverride)"
{
"signature" "CTFPlayer::IsReadyToSpawn()"
"linux"
{
"offset" "71"
}
"windows"
{
"offset" "127"
}
}
}
"Offsets"
{
Expand Down Expand Up @@ -162,6 +174,15 @@
"library" "server"
"linux" "@_ZNK9CTFPlayer9GetObjectEi"
}
"CTFPlayer::IsReadyToSpawn()"
{
// Windows signature can be found with a bytescan of "83 BE ?? ?? 00 00 03 5E"
// (conditional setter at the end of the function)
// we only use this to get offsetof(CTFPlayer::m_flRespawnTimeOverride)
"library" "server"
"linux" "@_ZN9CTFPlayer14IsReadyToSpawnEv"
"windows" "\x56\x8B\xF1\x80\xBE\x2A\x2A\x00\x00\x00\x74\x04\x32\xC0\x5E\xC3\x8B\x2A\x2A\x2A\x00\x00"
}
"CTFPlayer::RemoveAllObjects()"
{
// contains reference to string "object_removed"
Expand Down
29 changes: 29 additions & 0 deletions scripting/include/tf2utils.inc
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,35 @@ native float TF2Util_GetPlayerBurnDuration(int client);
*/
native void TF2Util_SetPlayerBurnDuration(int client, float duration);

/**
* Returns the player's respawn time override, if any. This is the number of seconds that a
* player will spend waiting to be respawned after their last death (CTFPlayer::m_flDeathTime).
*
* The amount of time remaining can be computed as follows:
*
* flRemainingTime = flDeathTime + flRespawnTimeOverride - GetGameTime();
*
* If the player does not have an override on their respawn time (i.e. they are part of normal
* respawn waves), this will return -1.0.
*
* @error Invalid client.
*/
native float TF2Util_GetPlayerRespawnTimeOverride(int client);

/**
* Changes the player's respawn time override. See `TF2Util_GetPlayerRespawnTimeOverride` above
* for an explanation of the value.
*
* Setting this value to -1.0 will remove any existing respawn time overrides.
*
* When a player dies, the game will set this value to -1.0 or the RespawnTime value of an
* active trigger_player_respawn_override entity that the player died in, if one exists.
* (This happens *after* the `player_death` event is fired.)
*
* @error Invalid client.
*/
native void TF2Util_SetPlayerRespawnTimeOverride(int client, float time);

/**
* Returns the player's shoot position.
*/
Expand Down
40 changes: 39 additions & 1 deletion scripting/tf2utils.sp
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@

#include <stocksoup/memory>

#define PLUGIN_VERSION "0.16.0"
#define PLUGIN_VERSION "0.17.0"
public Plugin myinfo = {
name = "TF2 Utils",
author = "nosoop",
Expand Down Expand Up @@ -44,6 +44,7 @@ Handle g_SDKCallPointInRespawnRoom;
Address offs_ConditionNames;
Address offs_CTFPlayer_aObjects;
Address offs_CTFPlayer_aHealers;
any offs_CTFPlayer_flRespawnTimeOverride;

Address offs_CTFPlayer_hMyWearables;

Expand Down Expand Up @@ -74,6 +75,8 @@ public APLRes AskPluginLoad2(Handle self, bool late, char[] error, int maxlen) {
CreateNative("TF2Util_SetPlayerConditionProvider", Native_SetPlayerConditionProvider);
CreateNative("TF2Util_GetPlayerBurnDuration", Native_GetPlayerBurnDuration);
CreateNative("TF2Util_SetPlayerBurnDuration", Native_SetPlayerBurnDuration);
CreateNative("TF2Util_GetPlayerRespawnTimeOverride", Native_GetPlayerRespawnTimeOverride);
CreateNative("TF2Util_SetPlayerRespawnTimeOverride", Native_SetPlayerRespawnTimeOverride);

CreateNative("TF2Util_GetPlayerObject", Native_GetPlayerObject);
CreateNative("TF2Util_GetPlayerObjectCount", Native_GetPlayerObjectCount);
Expand Down Expand Up @@ -248,6 +251,21 @@ public void OnPluginStart() {

offs_CTFPlayer_aHealers = view_as<Address>(FindSendPropInfo("CTFPlayer", "m_nNumHealers") + 0xC);

Address pOffsPlayerRespawnOverride = GameConfGetAddress(hGameConf,
"offsetof(CTFPlayer::m_flRespawnTimeOverride)");
if (!pOffsPlayerRespawnOverride) {
SetFailState("Could not determine location to read CTFPlayer::m_flRespawnTimeOverride "
... "from.");
}

offs_CTFPlayer_flRespawnTimeOverride =
LoadFromAddress(pOffsPlayerRespawnOverride, NumberType_Int32);
if (offs_CTFPlayer_flRespawnTimeOverride & 0xFFFF0000) {
// high bits are set - bad read?
SetFailState("Could not determine offset of CTFPlayer::m_flRespawnTimeOverride "
... " (received %08x)", offs_CTFPlayer_flRespawnTimeOverride);
}

delete hGameConf;
}

Expand Down Expand Up @@ -650,6 +668,26 @@ any Native_SetPlayerBurnDuration(Handle plugin, int numParams) {
SetEntDataFloat(client, pOffsSharedBurnDuration, duration);
}

// float(int client);
any Native_GetPlayerRespawnTimeOverride(Handle plugin, int numParams) {
int client = GetNativeCell(1);
if (client < 1 || client > MaxClients || !IsClientInGame(client)) {
ThrowNativeError(SP_ERROR_NATIVE, "Client index %d is invalid", client);
}
return GetEntDataFloat(client, offs_CTFPlayer_flRespawnTimeOverride);
}

// void(int client, float time);
any Native_SetPlayerRespawnTimeOverride(Handle plugin, int numParams) {
int client = GetNativeCell(1);
float time = GetNativeCell(2);
if (client < 1 || client > MaxClients || !IsClientInGame(client)) {
ThrowNativeError(SP_ERROR_NATIVE, "Client index %d is invalid", client);
}
SetEntDataFloat(client, offs_CTFPlayer_flRespawnTimeOverride, time);
return;
}

bool IsEntityWeapon(int entity) {
if (!IsValidEntity(entity)) {
ThrowNativeError(SP_ERROR_NATIVE, "Entity %d (%d) is invalid", entity,
Expand Down

0 comments on commit f4831b8

Please sign in to comment.