Closed lunatixxx closed 2 years ago
Could you provide with steps on how to repro it on a clean server setup?
I don't think there is a specific stepto reproduce that, the jockey teleport is something that happen on official too randomly. But your plugin really broke the game and started to teleport players without even a jockey alive, install it on a server of the said version with the jockey unteleport plugin and launch a versus game.
#include <sourcemod>
#include <sdkhooks>
#include <sdktools>
#include <colors>
#include <left4dhooks>
#include <smac>
#include <smac_stocks>
char path[256];
#define debug 0
#define VICTIM_SAVE_INTERVAL 1.2
#define VICTIM_CHECK_INTERVAL 2.0
enum L4D2Team
{
L4D2Team_None = 0,
L4D2Team_Spectator,
L4D2Team_Survivor,
L4D2Team_Infected
}
Handle g_hJockeyRideCheck_Timer;
Handle g_hSaveVictimPosition_Timer;
new Handle:hDisableJockeyUnteleportMaps;
int g_iJockeyVictim;
int g_iJockey;
float g_fVictimPrevPos[3];
float g_fMapCenter[3];
bool g_bIsEnabled;
public Plugin:myinfo =
{
name = "Jockey Unteleport",
author = "larrybrains",
description = "Teleports a survivor back into the map if they are randomly teleported outside of the map while jockeyed.",
version = "1.0",
url = "https://larrymod.com"
};
public OnPluginStart()
{
HookEvent("jockey_ride", Event_JockeyRide);
HookEvent("jockey_ride_end", Event_JockeyRideEnd);
HookEvent("jockey_killed", Event_JockeyDeath);
HookEvent("player_death", Event_PlayerDeath, EventHookMode_Pre);
HookEvent("player_disconnect", Event_PlayerDisconnect, EventHookMode_Pre);
hDisableJockeyUnteleportMaps = CreateTrie();
RegServerCmd("jockey_unteleport_disabled", DisableJockeyUnteleport);
BuildPath(Path_SM, path, 256, "logs/jockeybug.txt");
}
public Action:DisableJockeyUnteleport(args)
{
decl String:mapname[64];
GetCmdArg(1, mapname, sizeof(mapname));
SetTrieValue(hDisableJockeyUnteleportMaps, mapname, true);
}
public void OnMapStart()
{
g_hJockeyRideCheck_Timer = null;
g_hSaveVictimPosition_Timer = null;
g_fMapCenter[0] = 0.0;
g_fMapCenter[1] = 0.0;
g_fMapCenter[2] = 0.0;
decl String:mapname[64];
GetCurrentMap(mapname, sizeof(mapname));
decl dummy;
if (GetTrieValue(hDisableJockeyUnteleportMaps, mapname, dummy))
{
g_bIsEnabled = false;
#if debug
CPrintToChatAll("{blue}[Jockey UnTeleport]{default} is disabled.");
#endif
}
else
{
g_bIsEnabled = true;
#if debug
CPrintToChatAll("{blue}[Jockey UnTeleport]{default} is enabled.");
#endif
}
}
public Action Event_JockeyDeath(Event h_Event, const char[] s_Name, bool b_DontBroadcast)
{
if (!g_bIsEnabled)
return Plugin_Handled;
delete g_hJockeyRideCheck_Timer;
delete g_hSaveVictimPosition_Timer;
g_iJockeyVictim = -1;
g_iJockey = -1;
#if debug
CPrintToChatAll("{blue}[Jockey UnTeleport]{default} Jockey killed.");
#endif
return Plugin_Continue;
}
public Action Event_JockeyRideEnd(Event hEvent, const char[] s_Name, bool b_DontBroadcast)
{
if (!g_bIsEnabled)
return Plugin_Handled;
delete g_hJockeyRideCheck_Timer;
delete g_hSaveVictimPosition_Timer;
g_iJockeyVictim = -1;
g_iJockey = -1;
#if debug
CPrintToChatAll("{blue}[Jockey UnTeleport]{default} Jockey ride ended.");
#endif
return Plugin_Continue;
}
public Action Event_JockeyRide(Event event, const char[] name, bool dontBroadcast)
{
if (!g_bIsEnabled)
return Plugin_Handled;
new jockey = GetClientOfUserId(GetEventInt(event, "userid"));
new victim = GetClientOfUserId(GetEventInt(event, "victim"));
static float startVictimPos[3];
if (IsClientInGame(jockey))
{
if (IsPlayerAlive(jockey))
{
g_iJockey = jockey;
}
}
if (IsClientInGame(victim))
{
if (IsPlayerAlive(victim))
{
GetClientAbsOrigin(victim, startVictimPos);
g_fVictimPrevPos = startVictimPos;
#if debug
CPrintToChatAll("{blue}[Jockey UnTeleport]{default} initial victim position saved. Origin: %.1f, %.1f, %.1f", g_fVictimPrevPos[0], g_fVictimPrevPos[1], g_fVictimPrevPos[2] );
#endif
g_iJockeyVictim = victim;
if (g_hJockeyRideCheck_Timer == null)
{
g_hJockeyRideCheck_Timer = CreateTimer(VICTIM_CHECK_INTERVAL, JockeyRideCheck_Timer, victim, TIMER_REPEAT);
}
if (g_hSaveVictimPosition_Timer == null)
{
g_hSaveVictimPosition_Timer = CreateTimer(VICTIM_SAVE_INTERVAL, SaveVictimPosition_Timer, victim, TIMER_REPEAT);
}
}
}
return Plugin_Continue;
}
public void Event_PlayerDeath(Event hEvent, const char[] name, bool dontBroadcast)
{
if (!g_bIsEnabled)
return;
static int client;
client = GetClientOfUserId(hEvent.GetInt("userid"));
if (client != 0) {
if (client == g_iJockeyVictim || client == g_iJockey) {
g_iJockeyVictim = -1;
g_iJockey = -1;
delete g_hJockeyRideCheck_Timer;
delete g_hSaveVictimPosition_Timer;
}
}
}
public void Event_PlayerDisconnect(Event hEvent, const char[] name, bool dontBroadcast)
{
if (!g_bIsEnabled)
return;
static int client;
client = GetClientOfUserId(hEvent.GetInt("userid"));
if (client != 0) {
if (client == g_iJockeyVictim || client == g_iJockey ) {
g_iJockeyVictim = -1;
g_iJockey = -1;
delete g_hJockeyRideCheck_Timer;
delete g_hSaveVictimPosition_Timer;
}
}
}
public Action SaveVictimPosition_Timer(Handle timer, any victim)
{
if (!g_bIsEnabled)
return Plugin_Stop;
static float prevVictimPos[3];
static bool isOutsideWorld;
if (IsClientInGame(victim))
{
if (IsPlayerAlive(victim))
{
GetClientAbsOrigin(victim, prevVictimPos);
isOutsideWorld = TR_PointOutsideWorld(prevVictimPos);
float distanceToCenter = GetVectorDistance(prevVictimPos, g_fMapCenter);
if ( !isOutsideWorld && distanceToCenter >= 150)
{
g_fVictimPrevPos = prevVictimPos;
#if debug
CPrintToChatAll("{blue}[Jockey UnTeleport]{default} victim position saved. Origin: %.1f, %.1f, %.1f", g_fVictimPrevPos[0], g_fVictimPrevPos[1], g_fVictimPrevPos[2] );
#endif
}
}
}
return Plugin_Continue;
}
public Action JockeyRideCheck_Timer(Handle timer, any victim)
{
if (!g_bIsEnabled)
return Plugin_Stop;
static float newVictimPos[3];
static bool isOutsideWorld;
if(IsClientInGame(victim))
{
if (IsPlayerAlive(victim))
{
GetClientAbsOrigin(victim, newVictimPos);
isOutsideWorld = TR_PointOutsideWorld(newVictimPos);
float distance = GetVectorDistance(newVictimPos, g_fVictimPrevPos);
float distanceToCenter = GetVectorDistance(newVictimPos, g_fMapCenter);
if ( isOutsideWorld || distance >= 750 || distanceToCenter < 150 )
{
TeleportToPrevPos(victim);
SMAC_PrintAdminNotice("Attempting to fix position of %N after jockey teleportation bug.", victim, g_iJockey);
LogAction(-1, -1, "[Jockey UnTeleport] Survivor %N teleported by Jockey %N, origin: %.1f, %.1f, %.1f distance: %.1f distance to center: %.1f world:(%s)", victim, g_iJockey, newVictimPos[0], newVictimPos[1], newVictimPos[2], distance, distanceToCenter, isOutsideWorld ? "OutsideWorld" : "InsideWorld");
LogToFile(path, "[Jockey UnTeleport] Survivor %N teleported by Jockey %N, origin: %.1f, %.1f, %.1f distance: %.1f distance to center: %.1f world:(%s)", victim, g_iJockey, newVictimPos[0], newVictimPos[1], newVictimPos[2], distance, distanceToCenter, isOutsideWorld ? "OutsideWorld" : "InsideWorld");
}
}
}
return Plugin_Continue;
}
void TeleportToPrevPos(int victim)
{
if(IsClientInGame(victim))
{
if (IsPlayerAlive(victim))
{
TeleportEntity(victim, g_fVictimPrevPos, NULL_VECTOR, NULL_VECTOR);
#if debug
CPrintToChatAll("{blue}[Jockey UnTeleport]{default} trying to teleport survivor.");
#endif
}
}
}
If you install plugin A, then install plugin B, and it misbehaves, would you automatically assume plugin B is a culprit?
My plugin couples tight with game logic by unlinking triggers from player on every team change event. Its behavior is easier to predict than combination of many individual plugins in linked repository.
Known problems could cause nested player_team
events (including ones from death events), which can usually be patched up by a delayed team change (in case of plugins), or an additional condition in my plugin, example:
https://github.com/shqke/sp_public/blob/b3da30154d4a137d7193923ab7446a56f82b6510/remove_touch_links/scripting/remove_touch_links.sp#L18-L21
I'd need more information, if you want me to help with your case.
What will be your conclusion if you had no problem before, install a plugin and sunddenly everyone teleport, then remove it and no more problems for the next games ?
Jockey anti teleport does nothing on his own, the player have to be jockeyed and teleported. The fact that you are removing touch_link seems to cause a problem that's all i know.
You've spotted a false pattern and made abrupt conclusions, but you can't claim that you know which modification is the culprit, before figuring out what exactly is happening on your server. You shouldn't debug a problem by historical activation order of server mods. I'm also not going to modify it just to support intrusive behavior of mods you have installed.
Specifics of the entry point and bug itself also disallow me to do much about nested consequences of player_team
event invocation, other than placing additional condition just to support a clean server installation. My plugin mimicks natural game behavior and avoids any internal stateful logic.
If you can't be bothered to locate a problem, then simply don't use my plugin. But, if you're determined to find the issue, then I'll need more information.
The moment i installed your plugin it teleported 4 players in less than one minute in versus. I was alerted by the jockey unteleport plugin, it even teleported special infecteds.
"[!] Attempting to fix position of Hunter after jockey teleportation bug."
Uninstalled it and nothing happen anymore.
Server Ubuntu versions newer than 18, i think what this plugin modify could give us a lead on what cause this jockey teleportation bug.
https://github.com/SirPlease/L4D2-Competitive-Rework/issues/482