Raised This Month: $51 Target: $400
 12% 

[TF2] How Fix Infinite loop occurs during array deletion


Post New Thread Reply   
 
Thread Tools Display Modes
Author Message
AzulFlamaWallon
Junior Member
Join Date: Jan 2017
Location: Korea
Old 04-06-2020 , 23:28   [TF2] How Fix Infinite loop occurs during array deletion
Reply With Quote #1

Hello, We've made some minor tweaks to other people's Chain Lightning plugins
to be used by Freak Fortress2 summoners.

Having been fine work well when times of testing.
After that, it was delivered to the live server.

However...

The user who played the summoner using Lightning in the previous round,
If you are hit by the summoner in the next round, or if the user hits the summoner,
the server will shut down.

When I looked at the log from the live server side, an infinite loop occurred somewhere, and a watchdog error occurred, causing the server to burst.

The array is created, the targets that match the conditions are put in the array,
Take targets out of an array of targets, generate lightning and damage.
It is a structure to delete an array.
For some reason, this process was reversed in the middle and the flow was twisted,
causing an infinite loop.

How can I solve it?

TODO : Sorry. I Due to the use of a translator, the sentence flow may be a bit strange.

PHP Code:
#pragma semicolon 1

#define DEBUG

#pragma dynamic 131072 // TODO : Fix Stack Overflow from other plugin's attack. 

/*
    HEADER LINE    
*/
#include <sourcemod>
#include <sdktools>
#include <sdkhooks>
#include <clientprefs>
#include <morecolors>
#include <tf2items>
#include <tf2attributes>
#include <tf2>
#include <tf2_stocks>
#include <freak_fortress_2>
#include <BossUtil>

#pragma newdecls required
/*
    DEFINE LINE
*/

#define SMOKE "sprites/steam1.vmt"
#define LIGHTNING "sprites/lgtning.vmt"
#define SOUND_ZAP "misc/halloween/spell_lightning_ball_impact.wav"

#define BLACK { 0, 0, 0, 255 }
#define GREEN { 0, 255, 0, 255 }
#define YELLOW { 255, 255, 0, 255 }
#define ORANGE { 255, 165, 0, 255 }
#define RED { 255, 0, 0, 255 }
#define NAVY { 0, 0, 128, 255 }
#define BLUE { 0, 0, 255, 255 }
#define PURPLE { 255, 0, 255, 255 }
#define TEAL { 0, 128, 128, 255 }
#define PINK { 255, 192, 203, 255 }
#define AQUAMARINE { 127, 255, 212, 255 }
#define PEACHPUFF { 255, 218, 185, 255}
#define WHITE { 255, 255, 255, 255}

ConVar g_Activatedg_Distanceg_Targetsg_Damageg_Unifyg_Critsg_ColorIdx;

bool g_Enabled[MAXPLAYERS 1];
int g_Color[4];
int g_LightSprite;


public 
void OnPluginStart()
{
    
g_Activated CreateConVar("sm_cl_activate""1""Activate Chain Lightning. ");
    
g_Distance CreateConVar("sm_cl_distance""300""Set Lightning's range");
    
g_Targets CreateConVar("sm_cl_targets""3""Set targets");
    
g_Damage CreateConVar("sm_cl_damage""1.0""Set damage %");
    
g_Unify CreateConVar("sm_cl_unify""1""Set unfity damage");
    
g_Crits CreateConVar("sm_cl_crits""0""Create lightning in only crit");
    
g_ColorIdx CreateConVar("sm_cl_colors""1""Set color");
    
AutoExecConfig(true"Custom_Lightning");
}

public 
void OnMapStart()
{
    
g_Color AQUAMARINE;
    
g_LightSprite PrecacheModel(LIGHTNING);
    
PrecacheSound(SOUND_ZAPtrue);
}

public 
void OnClientPutInServer(int client)
{
    
g_Enabled[client] = g_Activated.BoolValue;
    
    if (
g_Enabled[client])
    {
        
SDKHook(clientSDKHook_OnTakeDamageAliveEvent_OnTakeDamageAlive);
    }
}

public 
void OnClientDisconnect(int client)
{
    if (
g_Enabled[client])
    {
        
SDKUnhook(clientSDKHook_OnTakeDamageAliveEvent_OnTakeDamageAlive);
    }
}

stock void GetLightningColor()
{
    switch (
g_ColorIdx.IntValue)
    {
        case 
1:g_Color BLACK;
        case 
2:g_Color GREEN;
        case 
3:g_Color YELLOW;
        case 
4:g_Color ORANGE;
        case 
5:g_Color RED;
        case 
6:g_Color NAVY;
        case 
7:g_Color BLUE;
        case 
8:g_Color PURPLE;
        case 
9:g_Color TEAL;
        case 
10:g_Color PINK;
        case 
11:g_Color AQUAMARINE;
        case 
12:g_Color PEACHPUFF;
        case 
13:g_Color WHITE;
    }
}

public 
Action Event_OnTakeDamageAlive(int victimint &attackerint &inflictorfloat &damageint &damagetypeint &weaponfloat damageForce[3], float damagePosition[3])
{
    if (
BU_IsValidUser(attackertrue)) // TODO : "return ->ClientInGame()&IsPlayerAlive()" 
    
{    
        if (!(
damagetype DMG_CRIT) && g_Crits.BoolValue)
        {
            return 
Plugin_Continue;
        }
        
        if (
g_Unify.BoolValue)
        {
            
damage damage g_Damage.FloatValue;
            return 
Plugin_Changed;
        }
        
        if (
IsActiveFunction(attackervictim)) // Check Valied Users.
        
{
            if (
IsActiveWeapon(attacker))
            {
                
ArrayList targets = new ArrayList();

                
float tPos[3]; // Target Position
                
                
for (int target 1target <= MaxClientstarget++) // Push Valid Targets Loop.
                
{
                    if (
IsValidTarget(targetvictimattackerTFTeam_Red))
                    {
                        
GetClientAbsOrigin(targettPos);
                        
tPos[2] = damagePosition[2];
                        
float dist GetVectorDistance(damagePositiontPos);
                        if (
RoundToFloor(dist) <= g_Distance.IntValue)
                        {
                            
targets.Push(target);
                        }
                    }
                }
                
                
int total_targets = !g_Targets GetRandomInt(15) : g_Targets.IntValue;
                
int array_length targets.Length;
                
                if (
total_targets array_length)
                { 
                    
total_targets array_length
                }
                
                if (
total_targets
                {                    
                    
//Stops the sound so it doesn't overlap over each other and cause a loud pitch sound
                    
EmitAmbientSound(SOUND_ZAPdamagePositionvictim_SND_STOPLOOPING___);
                    
EmitAmbientSound(SOUND_ZAPdamagePositionvictimSNDLEVEL_GUNFIRESND_NOFLAGS1.0SNDPITCH_HIGH0.0);
                }
                
                while (
total_targets// FIXME : WatchDogError in this section.
                
{
                    
int i GetRandomInt(0array_length 1);
                    
int target targets.Get(i);    
                    
GetClientAbsOrigin(targettPos);
                    
tPos[2] = damagePosition[2];
                    
                    
GetLightningColor();
                    
TE_SetupBeamPoints(damagePositiontPosg_LightSprite0000.210.01.01010.0g_Color1);
                    
TE_SendToAll();

                    
SDKHooks_TakeDamage(target0attackerg_Unify.BoolValue damage g_Damage.FloatValue damage g_Damage.FloatValueDMG_DISSOLVE);

                    
targets.Erase(i);
                    
array_length--;
                    
total_targets--;
                }
                
                
delete targets;

                return 
Plugin_Continue;
            }
        }
        
    }
    return 
Plugin_Continue;
}

stock bool IsActiveFunction(int _Attackerint _Victim)
{
    if (
g_Activated.IntValue || g_Enabled[_Attacker])
    {
        if (
BU_IsValidUser(_Victimtrue))
        {
            if (
_Attacker != _Victim)
            {
                return 
true;
            }
        }
    }
    return 
false;
}

stock bool IsValidTarget(int _Targetint _Victimint _AttackerTFTeam _Team)
{
    if (
BU_IsValidUser(_Targettrue))
    {
        if (
TF2_GetClientTeam(_Target) == _Team && _Target != _Attacker)
        {
            return 
true;
        }        
    }
    return 
false;
}

stock bool IsActiveWeapon(int _Attacker)
{
    if (
TF2_GetClientTeam(_Attacker) == TFTeam_Blue)
    {    
        if (
IsValidEntity(GetEntPropEnt(_AttackerProp_Send"m_hActiveWeapon")))
        {            
            if (
BU_IsCorrectWeapon(_Attacker30667trueTFClass_Sniper))
            {    
                return 
true;
            }
        }
    }
    return 
false;


Last edited by AzulFlamaWallon; 04-07-2020 at 05:43.
AzulFlamaWallon is offline
Bacardi
Veteran Member
Join Date: Jan 2010
Location: mom's basement
Old 04-08-2020 , 03:59   Re: [TF2] How Fix Infinite loop occurs during array deletion
Reply With Quote #2

- You not need SDKUnhook on player disconnect, it will do it automatically.

- When you loop all client indexs (1 to MaxClients), you should first check IsClientInGame(?), before checking team or else things. Or you get errors.

- You maybe get errors in code and ArrayList are not get deleted, then later those leaked handles could give you bugs. I just assumed.


I maybe do it like this way, I'm not trust while loops.
Code:
		
	if (IsActiveWeapon(attacker))
	{
		ArrayList targets = new ArrayList();

		float tPos[3]; // Target Position
		
		for (int target = 1; target <= MaxClients; target++) // Push Valid Targets Loop.
		{
			// Client is in game or empty slot
			if(!IsClientInGame(target)) continue;
			

			if (IsValidTarget(target, victim, attacker, TFTeam_Red))
			{
				GetClientAbsOrigin(target, tPos);
				tPos[2] = damagePosition[2];
				float dist = GetVectorDistance(damagePosition, tPos);
				if (RoundToFloor(dist) <= g_Distance.IntValue)
				{
					targets.Push(target);
				}
			}
		}
		
		// no min. bound on ConVar, you could set as -1 ?
		int total_targets = !g_Targets ? GetRandomInt(1, 5) : g_Targets.IntValue;
		//int array_length = targets.Length; // Doesn't hurt if we use Length


		// check is Array empty, then don't do extra work
		// What if Cvar sm_cl_targets have set -1 ? Re-check variable total_targets
		if(targets.Length <= 0 || total_targets <= 0)
		{
			// Remember delete ArrayList;
			delete targets;

			return Plugin_Continue;
		}


		if (total_targets > targets.Length)
		{ 
			total_targets = targets.Length; 
		}
		
		if (total_targets) 
		{                    
			//Stops the sound so it doesn't overlap over each other and cause a loud pitch sound
			EmitAmbientSound(SOUND_ZAP, damagePosition, victim, _, SND_STOPLOOPING, _, _, _);
			EmitAmbientSound(SOUND_ZAP, damagePosition, victim, SNDLEVEL_GUNFIRE, SND_NOFLAGS, 1.0, SNDPITCH_HIGH, 0.0);
		}
		
		for(int x = 0; x < total_targets; x++) // FIXME : WatchDogError in this section.
		{
		
			// ERROR ? Array empty
			if(targets.Length <= 0) continue;
		
			int i = GetRandomInt(0, targets.Length - 1);

			int target = targets.Get(i);    
			GetClientAbsOrigin(target, tPos);
			tPos[2] = damagePosition[2];
			
			GetLightningColor();
			TE_SetupBeamPoints(damagePosition, tPos, g_LightSprite, 0, 0, 0, 0.2, 10.0, 1.0, 10, 10.0, g_Color, 1);
			TE_SendToAll();

			SDKHooks_TakeDamage(target, 0, attacker, g_Unify.BoolValue ? damage * g_Damage.FloatValue : damage * g_Damage.FloatValue, DMG_DISSOLVE);

			targets.Erase(i);
			//array_length--; // we use targets.Length
			//total_targets--; we use for loop
		}
		
		delete targets;

		return Plugin_Continue;
	}
}
__________________
Do not Private Message @me
Bacardi is offline
AzulFlamaWallon
Junior Member
Join Date: Jan 2017
Location: Korea
Old 04-10-2020 , 12:28   Re: [TF2] How Fix Infinite loop occurs during array deletion
Reply With Quote #3

Quote:
Originally Posted by Bacardi View Post
- You not need SDKUnhook on player disconnect, it will do it automatically.

- When you loop all client indexs (1 to MaxClients), you should first check IsClientInGame(?), before checking team or else things. Or you get errors.

- You maybe get errors in code and ArrayList are not get deleted, then later those leaked handles could give you bugs. I just assumed.


I maybe do it like this way, I'm not trust while loops.
Code:
		
	if (IsActiveWeapon(attacker))
	{
		ArrayList targets = new ArrayList();

		float tPos[3]; // Target Position
		
		for (int target = 1; target <= MaxClients; target++) // Push Valid Targets Loop.
		{
			// Client is in game or empty slot
			if(!IsClientInGame(target)) continue;
			

			if (IsValidTarget(target, victim, attacker, TFTeam_Red))
			{
				GetClientAbsOrigin(target, tPos);
				tPos[2] = damagePosition[2];
				float dist = GetVectorDistance(damagePosition, tPos);
				if (RoundToFloor(dist) <= g_Distance.IntValue)
				{
					targets.Push(target);
				}
			}
		}
		
		// no min. bound on ConVar, you could set as -1 ?
		int total_targets = !g_Targets ? GetRandomInt(1, 5) : g_Targets.IntValue;
		//int array_length = targets.Length; // Doesn't hurt if we use Length


		// check is Array empty, then don't do extra work
		// What if Cvar sm_cl_targets have set -1 ? Re-check variable total_targets
		if(targets.Length <= 0 || total_targets <= 0)
		{
			// Remember delete ArrayList;
			delete targets;

			return Plugin_Continue;
		}


		if (total_targets > targets.Length)
		{ 
			total_targets = targets.Length; 
		}
		
		if (total_targets) 
		{                    
			//Stops the sound so it doesn't overlap over each other and cause a loud pitch sound
			EmitAmbientSound(SOUND_ZAP, damagePosition, victim, _, SND_STOPLOOPING, _, _, _);
			EmitAmbientSound(SOUND_ZAP, damagePosition, victim, SNDLEVEL_GUNFIRE, SND_NOFLAGS, 1.0, SNDPITCH_HIGH, 0.0);
		}
		
		for(int x = 0; x < total_targets; x++) // FIXME : WatchDogError in this section.
		{
		
			// ERROR ? Array empty
			if(targets.Length <= 0) continue;
		
			int i = GetRandomInt(0, targets.Length - 1);

			int target = targets.Get(i);    
			GetClientAbsOrigin(target, tPos);
			tPos[2] = damagePosition[2];
			
			GetLightningColor();
			TE_SetupBeamPoints(damagePosition, tPos, g_LightSprite, 0, 0, 0, 0.2, 10.0, 1.0, 10, 10.0, g_Color, 1);
			TE_SendToAll();

			SDKHooks_TakeDamage(target, 0, attacker, g_Unify.BoolValue ? damage * g_Damage.FloatValue : damage * g_Damage.FloatValue, DMG_DISSOLVE);

			targets.Erase(i);
			//array_length--; // we use targets.Length
			//total_targets--; we use for loop
		}
		
		delete targets;

		return Plugin_Continue;
	}
}
I tried to correct it as you said, but server is down.
The crash error came out like this.
It seems that the array is not deleted again somewhere.

Error was like below.

PHP Code:
This crash was caused by the server taking too long to process a frame.
Host_ErrorWatchdogHandler called server exiting.??
This crash signature is unique.

    Function
0    engine_srv.so!Sys_Error_Internal(boolchar const*, char*) + 0x1a1
1    engine_srv
.so!Sys_Error(char const*, ...) + 0x20
2    engine_srv
.so!Host_Error(char const*, ...) + 0xcc
3    engine_srv
.so!WatchDogHandler() + 0x12
4    linux
-gate.so 0xb80
5    engine_srv
.so!KeyValues::GetSymbolForStringClassic(char const*, bool) + 0x25
6    engine_srv
.so!KeyValues::FindKey(char const*, bool) + 0xcf
7    engine_srv
.so!KeyValues::GetInt(char const*, int) + 0x24
8    sourcemod.2
.tf2.so!sm_GetEventInt [smn_events.cpp:279 0xe
9    0xd40acd0
10    sourcepawn
.jit.x86.so!sp::Environment::Invoke [environment.cpp:296 0xe
11    sourcepawn.jit.x86.so!sp::Environment::Invoke [environment.cpp:299 0x8
12    0xf6ddd668
13    sourcemod.2
.tf2.so!EventManager::OnFireEvent [EventManager.cpp:424 0x18
14    sourcemod.2.tf2.so!__SourceHook_FHCls_IGameEventManager2FireEvent0::CMyDelegateImpl::Call [FastDelegate.h:1079 0x10
15    sourcemod.2.tf2.so!__SourceHook_FHCls_IGameEventManager2FireEvent0::Func [EventManager.cpp:41 0x28
16    engine_srv.so 0x1076c0
17    engine_srv
.so 0x105ff0
18    server_srv
.so!CTFPlayer::OnTakeDamage_Alive(CTakeDamageInfo const&) + 0x81a
19    sdkhooks
.ext.2.tf2.so!__SourceHook_MFHCls_OnTakeDamage_Alive::Func [extension.cpp:174 0x9
20    server_srv.so 0xeeedb0
21    server_srv
.so!CBaseCombatCharacter::OnTakeDamage(CTakeDamageInfo const&) + 0x8f
22    server_srv
.so!CTFPlayer::OnTakeDamage(CTakeDamageInfo const&) + 0xee2
23    sdkhooks
.ext.2.tf2.so!__SourceHook_MFHCls_OnTakeDamage::Func [extension.cpp:173 0x9
24    sourcemod.2.tf2.so!CHalfLife2::ReferenceToEntity [HalfLife2.cpp:969 0x8
25    sdktools.ext.2.tf2.so 0x22a40
26    sdkhooks
.ext.2.tf2.so!CTakeDamageInfoHack::CTakeDamageInfoHack [basehandle.h:166 0x8
27    server_srv.so 0xf05fd0
28    sdkhooks
.ext.2.tf2.so!Native_TakeDamage [sourcehook.h:5573 0x9
29    sdkhooks.ext.2.tf2.so 0x1f7f0
30    sourcemod.2
.tf2.so!sm_SetConVarNum [smn_console.cpp:357 0x7
31    sourcepawn.jit.x86.so!sp::Environment::Invoke [environment.cpp:296 0xe
32    sourcepawn.jit.x86.so!sp::PluginContext::Invoke [plugin-context.cpp:454 0x18
33    sourcepawn.jit.x86.so!sp::ScriptedInvoker::Invoke [scripted-invoker.cpp:301 0x21
34    sourcepawn.jit.x86.so!sp::ScriptedInvoker::Execute [scripted-invoker.cpp:190 0xc
35    0xd430c18
36    sdkhooks
.ext.2.tf2.so!SDKHooks::HandleOnTakeDamageHook [extension.cpp:1118 0x10
37    sdkhooks.ext.2.tf2.so!SDKHooks::Hook_OnTakeDamage_Alive [extension.cpp:1225 0x11
38    sdkhooks.ext.2.tf2.so!__SourceHook_MFHCls_OnTakeDamage_Alive::CMyDelegateImpl::Call [FastDelegate.h:994 0x9
39    sdkhooks.ext.2.tf2.so!__SourceHook_MFHCls_OnTakeDamage_Alive::Func [extension.cpp:174 0x14
40    server_srv.so 0xeeedb0
41    server_srv
.so!CBaseCombatCharacter::OnTakeDamage(CTakeDamageInfo const&) + 0x8f
42    server_srv
.so!CTFPlayer::OnTakeDamage(CTakeDamageInfo const&) + 0xee2
43    sdkhooks
.ext.2.tf2.so!__SourceHook_MFHCls_OnTakeDamage::Func [extension.cpp:173 0x9
44    sourcemod.2.tf2.so!CHalfLife2::ReferenceToEntity [HalfLife2.cpp:969 0x8
45    sdktools.ext.2.tf2.so 0x22a40
46    sdkhooks
.ext.2.tf2.so!CTakeDamageInfoHack::CTakeDamageInfoHack [basehandle.h:166 0x8
47    server_srv.so 0xf05fd0
48    sdkhooks
.ext.2.tf2.so!Native_TakeDamage [sourcehook.h:5573 0x9
49    sdkhooks.ext.2.tf2.so 0x1f7f0
50    sourcemod.2
.tf2.so!sm_SetConVarNum [smn_console.cpp:357 0x7
51    sourcepawn.jit.x86.so!sp::Environment::Invoke [environment.cpp:296 0xe
52    server_srv.so!CUtlSymbol::CUtlSymbol(char const*) + 0x3f 
AzulFlamaWallon is offline
Bacardi
Veteran Member
Join Date: Jan 2010
Location: mom's basement
Old 04-10-2020 , 12:32   Re: [TF2] How Fix Infinite loop occurs during array deletion
Reply With Quote #4

Could you show your "updated" code ?


Try follow dump file for open handles etc. etc.

sm_dump_handles handles1.txt

And if server have run a while, check again.

sm_dump_handles handles2.txt

Compare those two files.
__________________
Do not Private Message @me

Last edited by Bacardi; 04-10-2020 at 12:52.
Bacardi is offline
AzulFlamaWallon
Junior Member
Join Date: Jan 2017
Location: Korea
Old 04-11-2020 , 03:06   Re: [TF2] How Fix Infinite loop occurs during array deletion
Reply With Quote #5

Quote:
Originally Posted by Bacardi View Post
Could you show your "updated" code ?


Try follow dump file for open handles etc. etc.

sm_dump_handles handles1.txt

And if server have run a while, check again.

sm_dump_handles handles2.txt

Compare those two files.
This is the native function I used in addition to this plugin.

PHP Code:

bool CheckInPlayer
(int client)
{
    if (
client && client <= MaxClients)
    {
        if (
IsClientInGame(client) == true)
        {
            return 
true;
        }
        else
        {
            return 
false;
        }
    }
    else
    {
        return 
false;
    }
}

public 
int Native_CheckWeapon(Handle _Pluginint _NumParams// This Func is BU_IsCorrectWeapon(int _Attacker, int _WeaponIDX, bool _ChkClass, TFClassType _ClassType)
{
    
int atker GetNativeCell(1);
    
int idx GetNativeCell(2);
    
bool checkClass GetNativeCell(3);
    
TFClassType classType GetNativeCell(4);
    
    if (
CheckInPlayer(atker))
    {
        
int weaponID GetEntPropEnt(atkerProp_Send"m_hActiveWeapon");
        
int weaponName GetEntProp(weaponIDProp_Send"m_iItemDefinitionIndex");
        
        if (
checkClass)
        {
            if (
TF2_GetPlayerClass(atker) == classType)
            {
                if (
weaponName == idx)
                {
                    return 
true;
                }
            }
        }
        else
        {
            if (
weaponName == idx)
            {
                return 
true;
            }
        }
    }
    
    return 
false;
}

public 
int Native_CheckUser(Handle _Pluginint _NumParams// This Func is BU_IsValidUser(int _Entity, bool _IsAlive = false);
{
    
int entity GetNativeCell(1);
    
bool isAlive GetNativeCell(2);
    
    if (
entity <= || entity MaxClients)
    {
        return 
false;
    }
    if (
isAlive)
    {
        return 
IsClientInGame(entity) && IsPlayerAlive(entity);
    }
    return 
IsClientInGame(entity);

and Updated Codes.

PHP Code:
#pragma semicolon 1

#define DEBUG
#pragma dynamic 131072 

#include <sourcemod>
#include <sdktools>
#include <sdkhooks>
#include <clientprefs>
#include <morecolors>
#include <tf2items>
#include <tf2attributes>
#include <tf2>
#include <tf2_stocks>
#include <freak_fortress_2>
#include <BossUtil>

#pragma newdecls required


#define SMOKE "sprites/steam1.vmt"
#define LIGHTNING "sprites/lgtning.vmt"
#define SOUND_ZAP "misc/halloween/spell_lightning_ball_impact.wav"


#define BLACK { 0, 0, 0, 255 }
#define GREEN { 0, 255, 0, 255 }
#define YELLOW { 255, 255, 0, 255 }
#define ORANGE { 255, 165, 0, 255 }
#define RED { 255, 0, 0, 255 }
#define NAVY { 0, 0, 128, 255 }
#define BLUE { 0, 0, 255, 255 }
#define PURPLE { 255, 0, 255, 255 }
#define TEAL { 0, 128, 128, 255 }
#define PINK { 255, 192, 203, 255 }
#define AQUAMARINE { 127, 255, 212, 255 }
#define PEACHPUFF { 255, 218, 185, 255}
#define WHITE { 255, 255, 255, 255}

ConVar g_Activatedg_Distanceg_Targetsg_Damageg_Unifyg_Critsg_ColorIdx;

bool g_Enabled[MAXPLAYERS 1];
int g_Color[4];
int g_LightSprite// Sprite


public void OnPluginStart()
{
    
g_Activated CreateConVar("sm_cl_activate""1""Activate Chain Lightning");
    
g_Distance CreateConVar("sm_cl_distance""300""Chain's Distance");
    
g_Targets CreateConVar("sm_cl_targets""3""Set Targets");
    
g_Damage CreateConVar("sm_cl_damage""1.0""Set Damage Multifly");
    
g_Unify CreateConVar("sm_cl_unify""1""Set Equal Damage");
    
g_Crits CreateConVar("sm_cl_crits""0""Is Only Activate the Crits");
    
g_ColorIdx CreateConVar("sm_cl_colors""1""Set Chain's Colors");
    
AutoExecConfig(true"Custom_Lightning");
}

public 
void OnMapStart()
{
    
g_Color AQUAMARINE;
    
g_LightSprite PrecacheModel(LIGHTNING);
    
PrecacheSound(SOUND_ZAPtrue);
}

public 
void OnClientPutInServer(int client)
{
    
g_Enabled[client] = g_Activated.BoolValue;
    
    if (
g_Enabled[client])
    {
        
SDKHook(clientSDKHook_OnTakeDamageAliveEvent_OnTakeDamageAlive);
    }
}

/*
public void OnClientDisconnect(int client)
{
    if (g_Enabled[client])
    {
        SDKUnhook(client, SDKHook_OnTakeDamageAlive, Event_OnTakeDamageAlive);
    }
}*/

stock void GetLightningColor()
{
    switch (
g_ColorIdx.IntValue)
    {
        case 
1:g_Color BLACK;
        case 
2:g_Color GREEN;
        case 
3:g_Color YELLOW;
        case 
4:g_Color ORANGE;
        case 
5:g_Color RED;
        case 
6:g_Color NAVY;
        case 
7:g_Color BLUE;
        case 
8:g_Color PURPLE;
        case 
9:g_Color TEAL;
        case 
10:g_Color PINK;
        case 
11:g_Color AQUAMARINE;
        case 
12:g_Color PEACHPUFF;
        case 
13:g_Color WHITE;
    }
}

public 
Action Event_OnTakeDamageAlive(int victimint &attackerint &inflictorfloat &damageint &damagetypeint &weaponfloat damageForce[3], float damagePosition[3])
{
    if (
BU_IsValidUser(attackertrue))
    {
        if (!(
damagetype DMG_CRIT) && g_Crits.BoolValue)
        {
            return 
Plugin_Continue;
        }
        
        if (
g_Unify.BoolValue)
        {
            
damage damage g_Damage.FloatValue;
            return 
Plugin_Changed;
        }
        
        if (
IsActiveFunction(attackervictim))
        {
            if (
IsActiveWeapon(attacker))
            {
                
ArrayList targets = new ArrayList();
                
                
float tPos[3]; // Target Position
                
                
for (int target 1target <= MaxClientstarget++) // Push Valid Targets Loop.
                
{
                    
// Client is in game or empty slot
                    
if (!IsClientInGame(target))continue;
                    
                    
                    if (
IsValidTarget(targetvictimattackerTFTeam_Red))
                    {
                        
GetClientAbsOrigin(targettPos);
                        
tPos[2] = damagePosition[2];
                        
float dist GetVectorDistance(damagePositiontPos);
                        if (
RoundToFloor(dist) <= g_Distance.IntValue)
                        {
                            
targets.Push(target);
                        }
                    }
                }
                
                
// no min. bound on ConVar, you could set as -1 ?
                
int total_targets = !g_Targets GetRandomInt(15) : g_Targets.IntValue;
                
//int array_length = targets.Length; // Doesn't hurt if we use Length
                
                
                // check is Array empty, then don't do extra work
                // What if Cvar sm_cl_targets have set -1 ? Re-check variable total_targets
                
if (targets.Length <= || total_targets <= 0)
                {
                    
// Remember delete ArrayList;
                    
delete targets;
                    
                    return 
Plugin_Continue;
                }
                
                
                if (
total_targets targets.Length)
                {
                    
total_targets targets.Length;
                }
                
                if (
total_targets)
                {
                    
//Stops the sound so it doesn't overlap over each other and cause a loud pitch sound
                    
EmitAmbientSound(SOUND_ZAPdamagePositionvictim_SND_STOPLOOPING___);
                    
EmitAmbientSound(SOUND_ZAPdamagePositionvictimSNDLEVEL_GUNFIRESND_NOFLAGS1.0SNDPITCH_HIGH0.0);
                }
                
                for (
int x 0total_targetsx++) // FIXME : WatchDogError in this section.
                
{                
                    
// ERROR ? Array empty
                    
if (targets.Length <= 0)continue;
                    
                    
int i GetRandomInt(0targets.Length 1);
                    
                    
int target targets.Get(i);
                    
GetClientAbsOrigin(targettPos);
                    
tPos[2] = damagePosition[2];
                    
                    
GetLightningColor();
                    
TE_SetupBeamPoints(damagePositiontPosg_LightSprite0000.210.01.01010.0g_Color1);
                    
TE_SendToAll();
                    
                    
SDKHooks_TakeDamage(target0attackerg_Unify.BoolValue damage g_Damage.FloatValue damage g_Damage.FloatValueDMG_DISSOLVE);
                    
                    
targets.Erase(i);
                    
//array_length--; // we use targets.Length
                    //total_targets--; we use for loop
                
}
                
                
delete targets;
                
                return 
Plugin_Continue;
            }
        }
        
    }
    return 
Plugin_Continue;
}

stock bool IsActiveFunction(int _Attackerint _Victim)
{
    if (
g_Activated.IntValue || g_Enabled[_Attacker])
    {
        if (
BU_IsValidUser(_Victimtrue))
        {
            if (
_Attacker != _Victim)
            {
                return 
true;
            }
        }
    }
    return 
false;
}

stock bool IsValidTarget(int _Targetint _Victimint _AttackerTFTeam _Team)
{
    if (
BU_IsValidUser(_Targettrue))
    {
        if (
TF2_GetClientTeam(_Target) == _Team && _Target != _Attacker)
        {
            return 
true;
        }
    }
    return 
false;
}

stock bool IsActiveWeapon(int _Attacker)
{
    if (
TF2_GetClientTeam(_Attacker) == TFTeam_Blue)
    {
        if (
IsValidEntity(GetEntPropEnt(_AttackerProp_Send"m_hActiveWeapon")))
        {
            if (
BU_IsCorrectWeapon(_Attacker30667trueTFClass_Sniper))
            {
                return 
true;
            }
        }
    }
    return 
false;

This time, the error occurred when a summoner using the plug-in was damage in the first round.
I will ask the server owner to get the dump file as soon as possible.

TODO : Summoner Plug-in in use
We're using "clone attack" from "Freak Fortress 2" and there's a problem with the two types of Summoners not available, so the server is using a plug-in that replicates them.
AzulFlamaWallon is offline
Bacardi
Veteran Member
Join Date: Jan 2010
Location: mom's basement
Old 04-11-2020 , 13:00   Re: [TF2] How Fix Infinite loop occurs during array deletion
Reply With Quote #6

Hooold on... When using SDKHooks_TakeDamage, could this trigger also SDKHook SDKHook_OnTakeDamageAlive ?

I have to check.
Bacardi is offline
AzulFlamaWallon
Junior Member
Join Date: Jan 2017
Location: Korea
Old 04-13-2020 , 08:58   Re: [TF2] How Fix Infinite loop occurs during array deletion
Reply With Quote #7

Quote:
Originally Posted by Bacardi View Post
Hooold on... When using SDKHooks_TakeDamage, could this trigger also SDKHook SDKHook_OnTakeDamageAlive ?

I have to check.
I don't know about that.
Alive was next to TakeDamage, so I thought I'd hit only the living persons.
AzulFlamaWallon is offline
Bacardi
Veteran Member
Join Date: Jan 2010
Location: mom's basement
Old 04-13-2020 , 10:10   Re: [TF2] How Fix Infinite loop occurs during array deletion
Reply With Quote #8

damage type DMG_DISSOLVE did not trigger SDKHook_OnTakeDamageAlive, I tested... (I maybe test again) So problem is not that.

Can you see SourceMod error logs ?
You maybe get errors in code which again stop code to process end of code block. Maybe.

And what about those dump handles files ?

*edit

You could try fix this part. It collect also dead players at that g_Distance.IntValue range.

PHP Code:
        if (IsActiveFunction(attackervictim))
        {
            if (
IsActiveWeapon(attacker))
            {
                
ArrayList targets = new ArrayList();
                
                
float tPos[3]; // Target Position
                
                
for (int target 1target <= MaxClientstarget++) // Push Valid Targets Loop.
                
{
                    
// Client is in game or empty slot
                    
if (!IsClientInGame(target))continue;
                    
                    
                    if (
IsValidTarget(targetvictimattackerTFTeam_Red))
                    {
                        
GetClientAbsOrigin(targettPos);
                        
tPos[2] = damagePosition[2];
                        
float dist GetVectorDistance(damagePositiontPos);
                        if (
RoundToFloor(dist) <= g_Distance.IntValue)
                        {
                            
targets.Push(target);
                        }
                    }
                } 

Last edited by Bacardi; 04-13-2020 at 15:31.
Bacardi is offline
AzulFlamaWallon
Junior Member
Join Date: Jan 2017
Location: Korea
Old 04-19-2020 , 08:49   Re: [TF2] How Fix Infinite loop occurs during array deletion
Reply With Quote #9

Quote:
Originally Posted by Bacardi View Post
damage type DMG_DISSOLVE did not trigger SDKHook_OnTakeDamageAlive, I tested... (I maybe test again) So problem is not that.

Can you see SourceMod error logs ?
You maybe get errors in code which again stop code to process end of code block. Maybe.

And what about those dump handles files ?

*edit

You could try fix this part. It collect also dead players at that g_Distance.IntValue range.

PHP Code:
        if (IsActiveFunction(attackervictim))
        {
            if (
IsActiveWeapon(attacker))
            {
                
ArrayList targets = new ArrayList();
                
                
float tPos[3]; // Target Position
                
                
for (int target 1target <= MaxClientstarget++) // Push Valid Targets Loop.
                
{
                    
// Client is in game or empty slot
                    
if (!IsClientInGame(target))continue;
                    
                    
                    if (
IsValidTarget(targetvictimattackerTFTeam_Red))
                    {
                        
GetClientAbsOrigin(targettPos);
                        
tPos[2] = damagePosition[2];
                        
float dist GetVectorDistance(damagePositiontPos);
                        if (
RoundToFloor(dist) <= g_Distance.IntValue)
                        {
                            
targets.Push(target);
                        }
                    }
                } 
I modified it and sent it back,
The server owner is not answering.
The server owner did not receive the current file.
We can't even test it.
If the file comes, I will mention it again. I'm sorry.
AzulFlamaWallon is offline
Bacardi
Veteran Member
Join Date: Jan 2010
Location: mom's basement
Old 04-19-2020 , 09:28   Re: [TF2] How Fix Infinite loop occurs during array deletion
Reply With Quote #10

I have doubt, that crash could cause Freak Fortress.

I tested code without FF and it worked fine.
Bacardi is offline
Reply



Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off

Forum Jump


All times are GMT -4. The time now is 20:10.


Powered by vBulletin®
Copyright ©2000 - 2024, vBulletin Solutions, Inc.
Theme made by Freecode