Skocz do zawartości
Master

[Rozwiązane] Problem z timerem (Invalid timer handle)

Rekomendowane odpowiedzi

Witam!

 

Poniższy error strasznie spami mi logi. Analizuje kod już 10 raz i nie potrafię znaleźć przyczyny. Proszę o pomoc.

 

Error

Spoiler

L 09/22/2018 - 00:00:12: [SM] Exception reported: Invalid timer handle a58d46b7 (error 1)
L 09/22/2018 - 00:00:12: [SM] Blaming: arena/multi1v1_drug_rounds.smx
L 09/22/2018 - 00:00:12: [SM] Call stack trace:
L 09/22/2018 - 00:00:12: [SM]   [0] KillTimer
L 09/22/2018 - 00:00:12: [SM]   [1] Line 102, C:\Users\Admin\Desktop\New Arena\multi1v1_drug_rounds.sp::KillDrugTimer
L 09/22/2018 - 00:00:12: [SM]   [2] Line 45, C:\Users\Admin\Desktop\New Arena\multi1v1_drug_rounds.sp::Event_RoundEnd
L 09/22/2018 - 00:00:12: [SM]   [4] CS_TerminateRound
L 09/22/2018 - 00:00:12: [SM]   [5] Line 1171, ./scripting/multi1v1.sp::Timer_CheckRoundComplete
L 09/22/2018 - 00:00:34: [SM] Exception reported: Invalid timer handle a58d46b7 (error 1)
L 09/22/2018 - 00:00:34: [SM] Blaming: arena/multi1v1_drug_rounds.smx
L 09/22/2018 - 00:00:34: [SM] Call stack trace:
L 09/22/2018 - 00:00:34: [SM]   [0] KillTimer
L 09/22/2018 - 00:00:34: [SM]   [1] Line 102, C:\Users\Admin\Desktop\New Arena\multi1v1_drug_rounds.sp::KillDrugTimer
L 09/22/2018 - 00:00:34: [SM]   [2] Line 45, C:\Users\Admin\Desktop\New Arena\multi1v1_drug_rounds.sp::Event_RoundEnd
L 09/22/2018 - 00:00:34: [SM]   [4] CS_TerminateRound
L 09/22/2018 - 00:00:34: [SM]   [5] Line 1171, ./scripting/multi1v1.sp::Timer_CheckRoundComplete

 

 

Kod

Spoiler

#pragma semicolon 1

#include <clientprefs>
#include <sdktools>
#include <multi1v1>

#include "multi1v1/generic.sp"

#pragma newdecls required

#define TAG " [\x0FArena\x01]"

bool g_bDrug[MAXPLAYERS + 1];
Handle g_hDrugCookie = INVALID_HANDLE;

Handle g_DrugTimers[MAXPLAYERS + 1];
float g_DrugAngles[20] = {0.0, 5.0, 10.0, 15.0, 20.0, 25.0, 20.0, 15.0, 10.0, 5.0, 0.0, -5.0, -10.0, -15.0, -20.0, -25.0, -20.0, -15.0, -10.0, -5.0};
UserMsg g_FadeUserMsgId;

public void OnPluginStart() 
{
	g_FadeUserMsgId = GetUserMessageId("Fade");
	g_hDrugCookie = RegClientCookie("multi1v1_drug", "", CookieAccess_Protected);
	HookEvent("round_end", Event_RoundEnd, EventHookMode_PostNoCopy);
	LoadTranslations("multi1v1.phrases");
}

public void OnMapEnd()
{
	for(int client = 1; client <= MaxClients; client++)
	{
		if(isValidClient(client))
		{
			KillDrugTimer(client);
		}
	}
}

public Action Event_RoundEnd(Event event, char[] name, bool dontBroadcast)
{
	for(int client = 1; client <= MaxClients; client++)
	{
		if(isValidClient(client))
		{
			KillDrugTimer(client);
		}
	}
}

public void OnClientConnected(int client) 
{
	g_bDrug[client] = false;
}

public void Multi1v1_OnGunsMenuCreated(int client, Menu menu)
{
	char sEnabledString[32];
	GetEnabledString(sEnabledString, sizeof(sEnabledString), g_bDrug[client], client);
	AddMenuOption(menu, "drug", "Na Haju: %s", sEnabledString);
}

public void Multi1v1_GunsMenuCallback(Menu menu, MenuAction action, int client, int param2)
{
	if(action == MenuAction_Select)
	{
		char buffer[64];
		menu.GetItem(param2, buffer, sizeof(buffer));
		if(StrEqual(buffer, "drug")) 
		{
			g_bDrug[client] = !g_bDrug[client];
			SetCookieBool(client, g_hDrugCookie, g_bDrug[client]);
			Multi1v1_GiveWeaponsMenu(client, GetMenuSelectionPosition());
		}
	}
}

public void Multi1v1_AfterPlayerSetup(int client)
{
	if(!IsActivePlayer(client))
		return;

	int iArena = Multi1v1_GetArenaNumber(client);
	int iPlayer1 = Multi1v1_GetArenaPlayer1(iArena);
	int iPlayer2 = Multi1v1_GetArenaPlayer2(iArena);

	if(iPlayer1 >= 0 && iPlayer2 >= 0 && g_bDrug[iPlayer1] && g_bDrug[iPlayer2])
	{
        PrintToChat(client, "%s \x0FR\x02u\x03n\x04d\x05a \x06n\x07a \x08H\x09a\x0Aj\x0Bu\x10!", TAG);
        CreateDrug(client);
	}
}

void CreateDrug(int client)
{
	g_DrugTimers[client] = CreateTimer(1.0, Timer_Drug, client, TIMER_REPEAT);	
}

void KillDrugTimer(int client)
{
	if(g_DrugTimers[client] != INVALID_HANDLE)
	{
		KillTimer(g_DrugTimers[client]);
	}

	g_DrugTimers[client] = INVALID_HANDLE;
}

public Action Timer_Drug(Handle timer, any client)
{
	if(!IsClientInGame(client) || g_DrugTimers[client] != timer)
	{
		KillTimer(timer);
		return Plugin_Handled;
	}

	if(!IsPlayerAlive(client))
	{
		return Plugin_Handled;
	}

	float angs[3];
	GetClientEyeAngles(client, angs);
	
	angs[2] = g_DrugAngles[GetRandomInt(0,19)];
	
	TeleportEntity(client, NULL_VECTOR, angs, NULL_VECTOR);

	int clients[2];
	clients[0] = client;	

	int duration = 255;
	int holdtime = 255;
	int flags = 0x0002;
	int color[4] = { 0, 0, 0, 128 };
	color[0] = GetRandomInt(0,255);
	color[1] = GetRandomInt(0,255);
	color[2] = GetRandomInt(0,255);

	Handle message = StartMessageEx(g_FadeUserMsgId, clients, 1);

	if(GetUserMessageType() == UM_Protobuf)
	{
		Protobuf pb = UserMessageToProtobuf(message);
		pb.SetInt("duration", duration);
		pb.SetInt("hold_time", holdtime);
		pb.SetInt("flags", flags);
		pb.SetColor("clr", color);
	}
	else
	{
		BfWriteShort(message, duration);
		BfWriteShort(message, holdtime);
		BfWriteShort(message, flags);
		BfWriteByte(message, color[0]);
		BfWriteByte(message, color[1]);
		BfWriteByte(message, color[2]);
		BfWriteByte(message, color[3]);
	}

	EndMessage();

	return Plugin_Handled;
}

public void OnClientCookiesCached(int client) 
{
	if(IsFakeClient(client))
		return;

	g_bDrug[client] = GetCookieBool(client, g_hDrugCookie);
}

bool isValidClient(int client)
{
	return (1 <= client <= MaxClients && IsClientInGame(client));
}

 

 

Przez MAGNET,

Plus za ładnie dodany kod w spoilerach ^^

Udostępnij tę odpowiedź


Odnośnik do odpowiedzi
Udostępnij na innych stronach

Funkcja jest przestarzała i pokazuje ostrzeżenie przy kompilacji, oczywiście można skompilować, ale chyba nie ma sensu używać przestarzałych funkcji.

 

SHU_1537636975234-1805.png.29a488e58399094bf6384ba301849b2f.png

Edytowane przez Master

Udostępnij tę odpowiedź


Odnośnik do odpowiedzi
Udostępnij na innych stronach

Hmm no tak, ma to sens...

 

przejrzałem na szybko kod i strzelam, że błąd mógłby występować tutaj:

public Action Timer_Drug(Handle timer, any client)
{
	if(!IsClientInGame(client) || g_DrugTimers[client] != timer)
....

Nie jestem do końca przekonany, czy przy zastosowaniu flagi REPEAT id uchwytu pozostaje takie samo, przez co timer 'killuje' się wcześniej

Spróbuj usunąć tę drugą część warunku.

 

 

Ponadto, nie powinieneś przekazywać w timerze client'a, ponieważ w trakcie tej sekundy gracz mógł się rozłączyć i na jego miejsce wskoczyć nowy.

Aby wykonać to poprawnie, powinieneś przekazywać UserId, który jest unikalnym numerem dla każdego gracza - działa on mniej więcej tak, że po zmianie mapy (albo restarcie serwera, nieważne) playerowi przypisywana jest wartość zmiennej, która inkrementuje się za każdym razem, gdy łączy się nowy gracz. A zatem, będąc jako pierwszy na serwerze dostaniesz UserId = 1, kolejny gracz 2 itd..., a gdybyś wykonał reconnect, uzyskałbyś już UserId= 3

 

Na podstawie UserId można bezproblemowo uzyskać id clienta - jeśli będzie miało ono wartość 0, oznacza to że dany gracz się rozłączył

Uzyskiwanie UserId: https://go-code.pl/dokumentacja-sourcemod/client/GetClientUserId
Hej! Skorzystałeś z linku lub pobrałeś załącznik? Uhonoruj naszą pracę poprzez rejestrację na forum i rośnij razem z nami!

Uzyskiwanie id clienta na podstawie UserId: https://go-code.pl/dokumentacja-sourcemod/client/GetClientOfUserId
Hej! Skorzystałeś z linku lub pobrałeś załącznik? Uhonoruj naszą pracę poprzez rejestrację na forum i rośnij razem z nami!

 

Po zastosowaniu powyższej metody, Twój kod powinien wyglądać mniej więcej tak:

 

void CreateDrug(int client)
{
	g_DrugTimers[client] = CreateTimer(1.0, Timer_Drug, GetClientUserId(client), TIMER_REPEAT);	
}


public Action Timer_Drug(Handle timer, any clientUserId)
{
	int client = GetClientOfUserId(clientUserId);
	if(!client)
	{
		KillTimer(timer);	
		return Plugin_Handled;
	}

....

 

Udostępnij tę odpowiedź


Odnośnik do odpowiedzi
Udostępnij na innych stronach

Niestety problem nadal występuje. Dodam, że error występuje w bardzo dużej częstotliwości. 

 

Spoiler

 

SHU_zpNegKd.thumb.png.5b42e6abdc4b821b976aa159bb736225.png

Aktualny kod

 

Spoiler

#pragma semicolon 1

#include <clientprefs>
#include <sdktools>
#include <multi1v1>

#include "multi1v1/generic.sp"

#pragma newdecls required

#define TAG " [\x0FArena\x01]"

bool g_bDrug[MAXPLAYERS + 1];
Handle g_hDrugCookie = INVALID_HANDLE;

Handle g_DrugTimers[MAXPLAYERS + 1];
float g_DrugAngles[20] = {0.0, 5.0, 10.0, 15.0, 20.0, 25.0, 20.0, 15.0, 10.0, 5.0, 0.0, -5.0, -10.0, -15.0, -20.0, -25.0, -20.0, -15.0, -10.0, -5.0};
UserMsg g_FadeUserMsgId;

public void OnPluginStart() 
{
	g_FadeUserMsgId = GetUserMessageId("Fade");
	g_hDrugCookie = RegClientCookie("multi1v1_drug", "", CookieAccess_Protected);
	HookEvent("round_end", Event_RoundEnd, EventHookMode_PostNoCopy);
	LoadTranslations("multi1v1.phrases");
}

public void OnMapEnd()
{
	for(int client = 1; client <= MaxClients; client++)
	{
		if(isValidClient(client))
		{
			KillDrugTimer(client);
		}
	}
}

public Action Event_RoundEnd(Event event, char[] name, bool dontBroadcast)
{
	for(int client = 1; client <= MaxClients; client++)
	{
		if(isValidClient(client))
		{
			KillDrugTimer(client);
		}
	}
}

public void OnClientConnected(int client) 
{
	g_bDrug[client] = false;
}

public void Multi1v1_OnGunsMenuCreated(int client, Menu menu)
{
	char sEnabledString[32];
	GetEnabledString(sEnabledString, sizeof(sEnabledString), g_bDrug[client], client);
	AddMenuOption(menu, "drug", "Na Haju: %s", sEnabledString);
}

public void Multi1v1_GunsMenuCallback(Menu menu, MenuAction action, int client, int param2)
{
	if(action == MenuAction_Select)
	{
		char buffer[64];
		menu.GetItem(param2, buffer, sizeof(buffer));
		if(StrEqual(buffer, "drug")) 
		{
			g_bDrug[client] = !g_bDrug[client];
			SetCookieBool(client, g_hDrugCookie, g_bDrug[client]);
			Multi1v1_GiveWeaponsMenu(client, GetMenuSelectionPosition());
		}
	}
}

public void Multi1v1_AfterPlayerSetup(int client)
{
	if(!IsActivePlayer(client))
		return;

	int iArena = Multi1v1_GetArenaNumber(client);
	int iPlayer1 = Multi1v1_GetArenaPlayer1(iArena);
	int iPlayer2 = Multi1v1_GetArenaPlayer2(iArena);

	if(iPlayer1 >= 0 && iPlayer2 >= 0 && g_bDrug[iPlayer1] && g_bDrug[iPlayer2])
	{
        PrintToChat(client, "%s \x0FR\x02u\x03n\x04d\x05a \x06n\x07a \x08H\x09a\x0Aj\x0Bu\x10!", TAG);
        CreateDrug(client);
	}
}

void CreateDrug(int client)
{
	g_DrugTimers[client] = CreateTimer(1.0, Timer_Drug, GetClientUserId(client), TIMER_REPEAT);
}

void KillDrugTimer(int client)
{
	if(g_DrugTimers[client] != INVALID_HANDLE)
	{
		KillTimer(g_DrugTimers[client]);
	}

	g_DrugTimers[client] = INVALID_HANDLE;
}

public Action Timer_Drug(Handle timer, any clientUserId)
{
	int client = GetClientOfUserId(clientUserId);

	if(!client || !IsPlayerAlive(client))
	{
		KillTimer(timer);
		return Plugin_Handled;
	}

	float angs[3];
	GetClientEyeAngles(client, angs);
	
	angs[2] = g_DrugAngles[GetRandomInt(0,19)];
	
	TeleportEntity(client, NULL_VECTOR, angs, NULL_VECTOR);

	int clients[2];
	clients[0] = client;	

	int duration = 255;
	int holdtime = 255;
	int flags = 0x0002;
	int color[4] = { 0, 0, 0, 128 };
	color[0] = GetRandomInt(0,255);
	color[1] = GetRandomInt(0,255);
	color[2] = GetRandomInt(0,255);

	Handle message = StartMessageEx(g_FadeUserMsgId, clients, 1);

	if(GetUserMessageType() == UM_Protobuf)
	{
		Protobuf pb = UserMessageToProtobuf(message);
		pb.SetInt("duration", duration);
		pb.SetInt("hold_time", holdtime);
		pb.SetInt("flags", flags);
		pb.SetColor("clr", color);
	}
	else
	{
		BfWriteShort(message, duration);
		BfWriteShort(message, holdtime);
		BfWriteShort(message, flags);
		BfWriteByte(message, color[0]);
		BfWriteByte(message, color[1]);
		BfWriteByte(message, color[2]);
		BfWriteByte(message, color[3]);
	}

	EndMessage();

	return Plugin_Handled;
}

public void OnClientCookiesCached(int client) 
{
	if(IsFakeClient(client))
		return;

	g_bDrug[client] = GetCookieBool(client, g_hDrugCookie);
}

bool isValidClient(int client)
{
	return (1 <= client <= MaxClients && IsClientInGame(client));
}

 

 

Udostępnij tę odpowiedź


Odnośnik do odpowiedzi
Udostępnij na innych stronach

Na te chwile jedyna sensowna możliwość do rozpatrzenia to dodanie g_DrugTimers[client] = INVALID_HANDLE;

public Action Timer_Drug(Handle timer, any clientUserId)
{
	int client = GetClientOfUserId(clientUserId);

	if(!client || !IsPlayerAlive(client))
	{
		KillTimer(timer);
		g_DrugTimers[client] = INVALID_HANDLE;
		return Plugin_Handled;
	}

 

Udostępnij tę odpowiedź


Odnośnik do odpowiedzi
Udostępnij na innych stronach
1 godzinę temu, MAGNET napisał:

Na te chwile jedyna sensowna możliwość do rozpatrzenia to dodanie g_DrugTimers[client] = INVALID_HANDLE;


public Action Timer_Drug(Handle timer, any clientUserId)
{
	int client = GetClientOfUserId(clientUserId);

	if(!client || !IsPlayerAlive(client))
	{
		KillTimer(timer);
		g_DrugTimers[client] = INVALID_HANDLE;
		return Plugin_Handled;
	}

 

Według referencji z timers.inc powyższe działanie jest zbędne. Funkcja KillTimer jest używana do zatrzymania Timera spoza obszaru funkcji typu CallBack tego Timera. Natomiast jeżeli samopowtarzający się Timer jest zatrzymywany w jego własnym CallBack`u, to wystarczy ustawić wartość zmiennej g_DrugTimers jako INVALID_HANDLE i zwrócić Plugin_Stop. Nie twierdzę, że sposób z KillTimer nie zadziała, tylko że istnieje pewniejsze rozwiązanie.

 

źródło: https://go-code.pl/dokumentacja-sourcemod/timers/Timer
Hej! Skorzystałeś z linku lub pobrałeś załącznik? Uhonoruj naszą pracę poprzez rejestrację na forum i rośnij razem z nami!

kod:

public Action Timer_Drug(Handle timer, any clientUserId)
{
	int client = GetClientOfUserId(clientUserId);

	if(!client || !IsPlayerAlive(client))
	{
		g_DrugTimers[client] = INVALID_HANDLE;
		return Plugin_Stop;
	}

 

Przez MAGNET,

dzięki za poprawienie :)

Udostępnij tę odpowiedź


Odnośnik do odpowiedzi
Udostępnij na innych stronach
Gość
Ten temat został zamknięty. Brak możliwości dodania odpowiedzi.

×
×
  • Dodaj nową pozycję...