save cps on disconnect. fix ->spec->rejoin->lose pos. merged savestate stuff into persistent_data_t stuff

This commit is contained in:
rtldg 2021-03-02 18:17:10 +00:00
parent 62862ec2b5
commit a186e25b4e

View File

@ -49,6 +49,7 @@ enum struct persistent_data_t
float fDisconnectTime; float fDisconnectTime;
float fPosition[3]; float fPosition[3];
float fAngles[3]; float fAngles[3];
float fVelocity[3];
MoveType iMoveType; MoveType iMoveType;
float fGravity; float fGravity;
float fSpeed; float fSpeed;
@ -59,13 +60,9 @@ enum struct persistent_data_t
int iPreFrames; int iPreFrames;
int iTimerPreFrames; int iTimerPreFrames;
bool bPractice; bool bPractice;
} int iTimesTeleported;
ArrayList aCheckpoints;
enum struct savestate_t int iCurrentCheckpoint;
{
float Angles[3];
float Origin[3];
float Velocity[3];
} }
typedef StopTimerCallback = function void (int data); typedef StopTimerCallback = function void (int data);
@ -98,15 +95,9 @@ ArrayList gA_Targetnames = null;
ArrayList gA_Classnames = null; ArrayList gA_Classnames = null;
// save states // save states
bool gB_SaveStatesSegmented[MAXPLAYERS+1]; bool gB_SaveStates[MAXPLAYERS+1]; // whether we have data for when player rejoins from spec
savestate_t gA_SaveStateData[MAXPLAYERS+1];
timer_snapshot_t gA_SaveStates[MAXPLAYERS+1];
bool gB_SaveStates[MAXPLAYERS+1];
char gS_SaveStateTargetname[MAXPLAYERS+1][32];
ArrayList gA_SaveFrames[MAXPLAYERS+1];
ArrayList gA_PersistentData = null; ArrayList gA_PersistentData = null;
int gI_SavePreFrames[MAXPLAYERS+1]; float gF_PauseEyeAngles[MAXPLAYERS+1][3];
int gI_TimerFrames[MAXPLAYERS+1];
// cookies // cookies
Handle gH_HideCookie = null; Handle gH_HideCookie = null;
@ -676,7 +667,7 @@ public Action Command_Jointeam(int client, const char[] command, int args)
if(!gB_SaveStates[client]) if(!gB_SaveStates[client])
{ {
SaveState(client); PersistData(client, false);
} }
char arg1[8]; char arg1[8];
@ -815,6 +806,8 @@ public Action Timer_Cron(Handle Timer)
if(fTime - aData.fDisconnectTime >= gCV_PersistData.FloatValue) if(fTime - aData.fDisconnectTime >= gCV_PersistData.FloatValue)
{ {
DeletePersistentData(i, aData); DeletePersistentData(i, aData);
ResetCheckpointsInner(aData.aCheckpoints);
delete aData.aCheckpoints;
} }
} }
@ -1155,8 +1148,6 @@ public void OnClientPutInServer(int client)
} }
gB_SaveStates[client] = false; gB_SaveStates[client] = false;
delete gA_SaveFrames[client];
gB_ClosedKZCP[client] = false; gB_ClosedKZCP[client] = false;
} }
@ -1180,26 +1171,31 @@ public void OnClientDisconnect(int client)
return; return;
} }
PersistData(client, true);
// if data wasn't persisted, then we have checkpoints to reset...
ResetCheckpoints(client); ResetCheckpoints(client);
delete gA_Checkpoints[client]; delete gA_Checkpoints[client];
gB_SaveStates[client] = false;
delete gA_SaveFrames[client];
PersistData(client);
} }
void PersistData(int client) void FillPersistentData(int client, persistent_data_t aData, bool disconnected)
{ {
persistent_data_t aData; aData.iSteamID = GetSteamAccountID(client);
aData.fDisconnectTime = GetEngineTime();
if(!IsClientInGame(client) || if (disconnected)
!IsPlayerAlive(client) ||
(aData.iSteamID = GetSteamAccountID((client))) == 0 ||
Shavit_GetTimerStatus(client) == Timer_Stopped ||
gCV_PersistData.IntValue == 0)
{ {
return; aData.iCurrentCheckpoint = gI_CurrentCheckpoint[client];
if (gA_Checkpoints[client] != null)
{
aData.aCheckpoints = view_as<ArrayList>(CloneHandle(gA_Checkpoints[client]));
delete gA_Checkpoints[client];
}
if (gB_SaveStates[client])
{
return;
}
} }
if(gB_Replay) if(gB_Replay)
@ -1209,23 +1205,16 @@ void PersistData(int client)
aData.iTimerPreFrames = Shavit_GetPlayerTimerFrame(client); aData.iTimerPreFrames = Shavit_GetPlayerTimerFrame(client);
} }
aData.fDisconnectTime = GetEngineTime();
aData.iMoveType = GetEntityMoveType(client); aData.iMoveType = GetEntityMoveType(client);
aData.fGravity = GetEntityGravity(client); aData.fGravity = GetEntityGravity(client);
aData.fSpeed = GetEntPropFloat(client, Prop_Send, "m_flLaggedMovementValue"); aData.fSpeed = GetEntPropFloat(client, Prop_Send, "m_flLaggedMovementValue");
aData.bPractice = Shavit_IsPracticeMode(client); aData.bPractice = Shavit_IsPracticeMode(client);
aData.iTimesTeleported = gI_TimesTeleported[client];
float fPosition[3]; GetClientAbsOrigin(client, aData.fPosition);
GetClientAbsOrigin(client, fPosition); GetClientEyeAngles(client, aData.fAngles);
CopyArray(fPosition, aData.fPosition, 3); GetEntPropVector(client, Prop_Data, "m_vecAbsVelocity", aData.fVelocity);
Shavit_SaveSnapshot(client, aData.aSnapshot);
float fAngles[3];
GetClientEyeAngles(client, fAngles);
CopyArray(fAngles, aData.fAngles, 3);
timer_snapshot_t aSnapshot;
Shavit_SaveSnapshot(client, aSnapshot);
CopyArray(aSnapshot, aData.aSnapshot, sizeof(timer_snapshot_t));
char sTargetname[64]; char sTargetname[64];
GetEntPropString(client, Prop_Data, "m_iName", sTargetname, 64); GetEntPropString(client, Prop_Data, "m_iName", sTargetname, 64);
@ -1246,8 +1235,63 @@ void PersistData(int client)
{ {
aData.iClassname = gA_Classnames.PushString(sClassname); aData.iClassname = gA_Classnames.PushString(sClassname);
} }
}
gA_PersistentData.PushArray(aData); int FindPersistentData(int client, persistent_data_t aData)
{
int iSteamID;
if(client == 0 || (iSteamID = GetSteamAccountID(client)) == 0)
{
return -1;
}
for(int i = 0; i < gA_PersistentData.Length; i++)
{
gA_PersistentData.GetArray(i, aData);
if(iSteamID == aData.iSteamID)
{
return i;
}
}
return -1;
}
void PersistData(int client, bool disconnected)
{
if(!IsClientInGame(client) ||
(!IsPlayerAlive(client) && !disconnected) ||
GetSteamAccountID(client) == 0 ||
//Shavit_GetTimerStatus(client) == Timer_Stopped ||
(!gCV_RestoreStates.BoolValue && !disconnected) ||
(gCV_PersistData.IntValue == 0 && disconnected))
{
return;
}
persistent_data_t aData;
int iIndex = FindPersistentData(client, aData);
FillPersistentData(client, aData, disconnected);
if (disconnected)
{
gB_SaveStates[client] = false;
}
else
{
gB_SaveStates[client] = true;
}
if (iIndex == -1)
{
gA_PersistentData.PushArray(aData);
}
else
{
gA_PersistentData.SetArray(iIndex, aData, sizeof(aData));
}
} }
void DeletePersistentData(int index, persistent_data_t data) void DeletePersistentData(int index, persistent_data_t data)
@ -1256,61 +1300,47 @@ void DeletePersistentData(int index, persistent_data_t data)
gA_PersistentData.Erase(index); gA_PersistentData.Erase(index);
} }
public Action Timer_LoadPersistentData(Handle Timer, any data) Action Timer_LoadPersistentData(Handle Timer, any data)
{ {
int iSteamID = 0; LoadPersistentData(data);
int client = GetClientFromSerial(data); return Plugin_Stop;
}
void LoadPersistentData(int serial)
{
int client = GetClientFromSerial(serial);
if(client == 0 || if(client == 0 ||
(iSteamID = GetSteamAccountID(client)) == 0 || GetSteamAccountID(client) == 0 ||
GetClientTeam(client) < 2 || GetClientTeam(client) < 2 ||
!IsPlayerAlive(client)) !IsPlayerAlive(client))
{ {
return Plugin_Stop; return;
} }
persistent_data_t aData; persistent_data_t aData;
int iIndex = -1; int iIndex = FindPersistentData(client, aData);
int iLength = gA_PersistentData.Length;
for(int i = 0; i < iLength; i++) if (iIndex == -1)
{ {
gA_PersistentData.GetArray(i, aData); return;
if(iSteamID == aData.iSteamID)
{
iIndex = i;
break;
}
}
if(iIndex == -1)
{
return Plugin_Stop;
} }
Shavit_StopTimer(client); Shavit_StopTimer(client);
float fPosition[3];
CopyArray(aData.fPosition, fPosition, 3);
float fAngles[3];
CopyArray(aData.fAngles, fAngles, 3);
SetEntityMoveType(client, aData.iMoveType); SetEntityMoveType(client, aData.iMoveType);
SetEntityGravity(client, aData.fGravity); SetEntityGravity(client, aData.fGravity);
SetEntPropFloat(client, Prop_Send, "m_flLaggedMovementValue", aData.fSpeed); SetEntPropFloat(client, Prop_Send, "m_flLaggedMovementValue", aData.fSpeed);
timer_snapshot_t aSnapshot; Shavit_LoadSnapshot(client, aData.aSnapshot);
CopyArray(aData.aSnapshot, aSnapshot, sizeof(timer_snapshot_t));
Shavit_LoadSnapshot(client, aSnapshot);
if(aData.iTargetname != -1) if(aData.iTargetname != -1)
{ {
char sTargetname[64]; char sTargetname[64];
gA_Targetnames.GetString(aData.iTargetname, sTargetname, 64); gA_Targetnames.GetString(aData.iTargetname, sTargetname, 64);
// TODO: ?????????????? is it supposed to be targetname??????
//DispatchKeyValue(client, "targetname", gS_SaveStateTargetname[client]);
SetEntPropString(client, Prop_Data, "m_iName", sTargetname); SetEntPropString(client, Prop_Data, "m_iName", sTargetname);
} }
@ -1322,7 +1352,7 @@ public Action Timer_LoadPersistentData(Handle Timer, any data)
SetEntPropString(client, Prop_Data, "m_iClassname", sClassname); SetEntPropString(client, Prop_Data, "m_iClassname", sClassname);
} }
TeleportEntity(client, fPosition, fAngles, view_as<float>({ 0.0, 0.0, 0.0 })); TeleportEntity(client, aData.fPosition, aData.fAngles, aData.fVelocity);
if(gB_Replay && aData.aFrames != null) if(gB_Replay && aData.aFrames != null)
{ {
@ -1336,10 +1366,16 @@ public Action Timer_LoadPersistentData(Handle Timer, any data)
Shavit_SetPracticeMode(client, true, false); Shavit_SetPracticeMode(client, true, false);
} }
delete aData.aFrames; gI_TimesTeleported[client] = aData.iTimesTeleported;
gA_PersistentData.Erase(iIndex);
return Plugin_Stop; if (aData.aCheckpoints != null)
{
gI_CurrentCheckpoint[client] = aData.iCurrentCheckpoint;
gA_Checkpoints[client] = view_as<ArrayList>(CloneHandle(aData.aCheckpoints));
}
gB_SaveStates[client] = false;
DeletePersistentData(iIndex, aData);
} }
void RemoveWeapon(any data) void RemoveWeapon(any data)
@ -1350,18 +1386,22 @@ void RemoveWeapon(any data)
} }
} }
void ResetCheckpoints(int client) void ResetCheckpointsInner(ArrayList cps)
{ {
if(gA_Checkpoints[client]) if (cps)
{ {
for(int i = 0; i < gA_Checkpoints[client].Length; i++) for(int i = 0; i < cps.Length; i++)
{ {
delete view_as<ArrayList>(gA_Checkpoints[client].Get(i, cp_cache_t::aFrames)); delete view_as<ArrayList>(cps.Get(i, cp_cache_t::aFrames));
} }
gA_Checkpoints[client].Clear(); cps.Clear();
} }
}
void ResetCheckpoints(int client)
{
ResetCheckpointsInner(gA_Checkpoints[client]);
gI_CurrentCheckpoint[client] = 0; gI_CurrentCheckpoint[client] = 0;
} }
@ -2276,19 +2316,11 @@ bool SaveCheckpoint(int client, int index, bool overflow = false)
gI_CurrentCheckpoint[client] = index; gI_CurrentCheckpoint[client] = index;
cp_cache_t cpcache; cp_cache_t cpcache;
float temp[3];
GetClientAbsOrigin(target, temp); GetClientAbsOrigin(target, cpcache.fPosition);
CopyArray(temp, cpcache.fPosition, 3); GetClientEyeAngles(target, cpcache.fAngles);
GetEntPropVector(target, Prop_Data, "m_vecVelocity", cpcache.fVelocity);
GetClientEyeAngles(target, temp); GetEntPropVector(target, Prop_Data, "m_vecBaseVelocity", cpcache.fBaseVelocity);
CopyArray(temp, cpcache.fAngles, 3);
GetEntPropVector(target, Prop_Data, "m_vecVelocity", temp);
CopyArray(temp, cpcache.fVelocity, 3);
GetEntPropVector(target, Prop_Data, "m_vecBaseVelocity", temp);
CopyArray(temp, cpcache.fBaseVelocity, 3);
char sTargetname[64]; char sTargetname[64];
GetEntPropString(target, Prop_Data, "m_iName", sTargetname, 64); GetEntPropString(target, Prop_Data, "m_iName", sTargetname, 64);
@ -2387,7 +2419,7 @@ bool SaveCheckpoint(int client, int index, bool overflow = false)
Shavit_SaveSnapshot(target, snapshot); Shavit_SaveSnapshot(target, snapshot);
} }
CopyArray(snapshot, cpcache.aSnapshot, sizeof(timer_snapshot_t)); cpcache.aSnapshot = snapshot;
if(CanSegment(target)) if(CanSegment(target))
{ {
@ -2457,20 +2489,14 @@ void TeleportToCheckpoint(int client, int index, bool suppressMessage)
gA_Checkpoints[client].GetArray(index - 1, cpcache, sizeof(cp_cache_t)); gA_Checkpoints[client].GetArray(index - 1, cpcache, sizeof(cp_cache_t));
timer_snapshot_t snapshot; if(Shavit_GetStyleSettingInt(gI_Style[client], "kzcheckpoints") != Shavit_GetStyleSettingInt(cpcache.aSnapshot.bsStyle, "kzcheckpoints"))
CopyArray(cpcache.aSnapshot, snapshot, sizeof(timer_snapshot_t));
if(Shavit_GetStyleSettingInt(gI_Style[client], "kzcheckpoints") != Shavit_GetStyleSettingInt(snapshot.bsStyle, "kzcheckpoints"))
{ {
Shavit_PrintToChat(client, "%T", "CommandTeleCPInvalid", client); Shavit_PrintToChat(client, "%T", "CommandTeleCPInvalid", client);
return; return;
} }
float pos[3]; if(IsNullVector(cpcache.fPosition))
CopyArray(cpcache.fPosition, pos, 3);
if(IsNullVector(pos))
{ {
return; return;
} }
@ -2529,31 +2555,23 @@ void TeleportToCheckpoint(int client, int index, bool suppressMessage)
SetEntPropFloat(client, Prop_Send, "m_flDuckSpeed", cpcache.fDuckSpeed); SetEntPropFloat(client, Prop_Send, "m_flDuckSpeed", cpcache.fDuckSpeed);
} }
float ang[3];
CopyArray(cpcache.fAngles, ang, 3);
// this is basically the same as normal checkpoints except much less data is used // this is basically the same as normal checkpoints except much less data is used
if(Shavit_GetStyleSettingInt(gI_Style[client], "kzcheckpoints")) if(Shavit_GetStyleSettingInt(gI_Style[client], "kzcheckpoints"))
{ {
TeleportEntity(client, pos, ang, view_as<float>({ 0.0, 0.0, 0.0 })); TeleportEntity(client, cpcache.fPosition, cpcache.fAngles, view_as<float>({ 0.0, 0.0, 0.0 }));
return; return;
} }
Shavit_LoadSnapshot(client, snapshot); Shavit_LoadSnapshot(client, cpcache.aSnapshot);
Shavit_ResumeTimer(client); Shavit_ResumeTimer(client);
float vel[3]; float vel[3];
if((gI_CheckpointsSettings[client] & CP_VELOCITY) > 0 || cpcache.bSegmented) if((gI_CheckpointsSettings[client] & CP_VELOCITY) > 0 || cpcache.bSegmented)
{ {
float basevel[3]; AddVectors(cpcache.fVelocity, cpcache.fBaseVelocity, vel);
CopyArray(cpcache.fVelocity, vel, 3);
CopyArray(cpcache.fBaseVelocity, basevel, 3);
AddVectors(vel, basevel, vel);
} }
else else
{ {
vel = NULL_VECTOR; vel = NULL_VECTOR;
@ -2575,8 +2593,8 @@ void TeleportToCheckpoint(int client, int index, bool suppressMessage)
SetEntPropString(client, Prop_Data, "m_iClassname", sClassname); SetEntPropString(client, Prop_Data, "m_iClassname", sClassname);
} }
TeleportEntity(client, pos, TeleportEntity(client, cpcache.fPosition,
((gI_CheckpointsSettings[client] & CP_ANGLES) > 0 || cpcache.bSegmented)? ang:NULL_VECTOR, ((gI_CheckpointsSettings[client] & CP_ANGLES) > 0 || cpcache.bSegmented)? cpcache.fAngles:NULL_VECTOR,
vel); vel);
if(cpcache.bPractice || !cpcache.bSegmented || GetClientSerial(client) != cpcache.iSerial) if(cpcache.bPractice || !cpcache.bSegmented || GetClientSerial(client) != cpcache.iSerial)
@ -3029,15 +3047,9 @@ public void Player_Spawn(Event event, const char[] name, bool dontBroadcast)
{ {
if(gCV_RestoreStates.BoolValue) if(gCV_RestoreStates.BoolValue)
{ {
RequestFrame(RestoreState, serial); RequestFrame(LoadPersistentData, serial);
}
else
{
gB_SaveStates[client] = false;
} }
} }
else else
{ {
CreateTimer(0.10, Timer_LoadPersistentData, GetClientSerial(client), TIMER_FLAG_NO_MAPCHANGE); CreateTimer(0.10, Timer_LoadPersistentData, GetClientSerial(client), TIMER_FLAG_NO_MAPCHANGE);
@ -3097,26 +3109,6 @@ void RemoveRadar(any data)
RemoveRadarBase(client); RemoveRadarBase(client);
} }
void RestoreState(any data)
{
int client = GetClientFromSerial(data);
if(client == 0 || !IsPlayerAlive(client))
{
return;
}
if(gA_SaveStates[client].bsStyle != Shavit_GetBhopStyle(client) ||
gA_SaveStates[client].iTimerTrack != Shavit_GetClientTrack(client))
{
gB_SaveStates[client] = false;
return;
}
LoadState(client);
}
public Action Player_Notifications(Event event, const char[] name, bool dontBroadcast) public Action Player_Notifications(Event event, const char[] name, bool dontBroadcast)
{ {
if(gCV_HideTeamChanges.BoolValue) if(gCV_HideTeamChanges.BoolValue)
@ -3130,7 +3122,7 @@ public Action Player_Notifications(Event event, const char[] name, bool dontBroa
{ {
if(!gB_SaveStates[client]) if(!gB_SaveStates[client])
{ {
SaveState(client); PersistData(client, false);
} }
if(gCV_AutoRespawn.FloatValue > 0.0 && StrEqual(name, "player_death")) if(gCV_AutoRespawn.FloatValue > 0.0 && StrEqual(name, "player_death"))
@ -3407,17 +3399,17 @@ public void Shavit_OnFinish(int client)
public void Shavit_OnPause(int client, int track) public void Shavit_OnPause(int client, int track)
{ {
if(!GetClientEyeAngles(client, gA_SaveStateData[client].Angles)) if(!GetClientEyeAngles(client, gF_PauseEyeAngles[client]))
{ {
gA_SaveStateData[client].Angles = NULL_VECTOR; gF_PauseEyeAngles[client] = NULL_VECTOR;
} }
} }
public void Shavit_OnResume(int client, int track) public void Shavit_OnResume(int client, int track)
{ {
if(!IsNullVector(gA_SaveStateData[client].Angles)) if(!IsNullVector(gF_PauseEyeAngles[client]))
{ {
TeleportEntity(client, NULL_VECTOR, gA_SaveStateData[client].Angles, NULL_VECTOR); TeleportEntity(client, NULL_VECTOR, gF_PauseEyeAngles[client], NULL_VECTOR);
} }
} }
@ -3438,60 +3430,6 @@ public Action Command_Drop(int client, const char[] command, int argc)
return Plugin_Handled; return Plugin_Handled;
} }
void LoadState(int client)
{
TeleportEntity(client, gA_SaveStateData[client].Origin, gA_SaveStateData[client].Angles, gA_SaveStateData[client].Velocity);
DispatchKeyValue(client, "targetname", gS_SaveStateTargetname[client]);
Shavit_LoadSnapshot(client, gA_SaveStates[client]);
Shavit_SetPracticeMode(client, gB_SaveStatesSegmented[client], false);
if(gB_Replay && gA_SaveFrames[client] != null)
{
Shavit_SetReplayData(client, gA_SaveFrames[client]);
Shavit_SetPlayerPreFrame(client, gI_SavePreFrames[client]);
Shavit_SetPlayerTimerFrame(client, gI_TimerFrames[client]);
}
delete gA_SaveFrames[client];
gB_SaveStates[client] = false;
}
void SaveState(int client)
{
if(Shavit_GetTimerStatus(client) == Timer_Stopped)
{
return;
}
GetClientAbsOrigin(client, gA_SaveStateData[client].Origin);
GetClientEyeAngles(client, gA_SaveStateData[client].Angles);
GetEntPropVector(client, Prop_Data, "m_vecAbsVelocity", gA_SaveStateData[client].Velocity);
GetEntPropString(client, Prop_Data, "m_iName", gS_SaveStateTargetname[client], 32);
Shavit_SaveSnapshot(client, gA_SaveStates[client]);
gB_SaveStatesSegmented[client] = Shavit_IsPracticeMode(client);
if(gB_Replay)
{
delete gA_SaveFrames[client];
gA_SaveFrames[client] = Shavit_GetReplayData(client);
gI_SavePreFrames[client] = Shavit_GetPlayerPreFrame(client);
gI_TimerFrames[client] = Shavit_GetPlayerTimerFrame(client);
}
gB_SaveStates[client] = true;
}
void CopyArray(const any[] from, any[] to, int size)
{
for(int i = 0; i < size; i++)
{
to[i] = from[i];
}
}
bool CanSegment(int client) bool CanSegment(int client)
{ {
return StrContains(gS_StyleStrings[gI_Style[client]].sSpecialString, "segments") != -1; return StrContains(gS_StyleStrings[gI_Style[client]].sSpecialString, "segments") != -1;