[INC] HintTimer, прошу помощи в написании

Dragon_Knight

Участник
Сообщения
5
Реакции
0
Всем привет
С языком знаком хорошо, но вот решил заняться сервером CSS. Вики и доки по SM написаны ужасно, без примеров и без сопутствующего материала. Отсюда и много вопросов...

Итак, понадобился какой-нить наглядный таймер, который было-бы крайне просто использовать. Ничего готово не нашёл, и решил написать свой. Собственно написал такой инклуд:
PHP:
new Handle:Timer_Countdown[MAXPLAYERS+1] = {INVALID_HANDLE, ...};
new CountdownCounts[MAXPLAYERS+1] = {0, ...};

forward OnCountdownHintTimerEnd(client, time, id);

public CountdownHintTimerCreate(client, time, String:text[], id)
{
	if(Timer_Countdown[client] == INVALID_HANDLE)
	{
		new Handle:pack = CreateDataPack();
		WritePackCell(pack, client);
		WritePackCell(pack, time);
		WritePackString(pack, text);
		WritePackCell(pack, id);
		
		CountdownHintTimer(Handle:0, pack); // Мегатопор
		Timer_Countdown[client] = CreateTimer(1.0, CountdownHintTimer, pack, TIMER_REPEAT);
	}
	else
	{
		CPrintToChat(client, "{gold}[CountdownHintTimer]: {red}Ошибка создания таймера для Вас, таймер уже создан!");
	}
}

public Action:CountdownHintTimer(Handle:timer, Handle:pack)
{
	new client, time, String:text[64], id;
	
	ResetPack(pack);
	client = ReadPackCell(pack);
	time = ReadPackCell(pack);
	ReadPackString(Handle:pack, text, sizeof(text));
	id = ReadPackCell(pack);
	
	if(CountdownCounts[client] < time)
	{
		PrintHintText(client, text, (time - CountdownCounts[client]));
		CountdownCounts[client]++;
	}
	else
	{
		ClearTimer(Timer_Countdown[client]);
		CountdownHintTimerReset(client);
		CloseHandle(pack);
		PrintHintText(client, "");
		
		new result;
		Call_StartFunction(INVALID_HANDLE, OnCountdownHintTimerEnd);
		Call_PushCell(client);
		Call_PushCell(time);
		Call_PushCell(id);
		Call_Finish(result);
	}
}

public CountdownHintTimerReset(client)
{
	Timer_Countdown[client] = INVALID_HANDLE;
	CountdownCounts[client] = 0;
}
Работать с ним так: CountdownHintTimerCreate(pid, 25, "Таймер. осталось %d сек.", 0);

Нареканий по работе нету, однако есть много мест, которые сделаны откровенно ... плохо, в частности:
* CountdownHintTimerCreate > CountdownHintTimer(Handle:0, pack); - как более грамотно избавиться от этого топора, что-бы таймер начинал работать сразу.
* Как сделать полноценный колбэк OnCountdownHintTimerEnd(client, time, id) ?
* И что в целом можно сделать в коде, что-бы привести к более адекватному виду?
 

R1KO

fuck society
Сообщения
9,457
Реакции
7,786
  • Команда форума
  • #2
PHP:
new Handle:Timer_Countdown[MAXPLAYERS+1] = {INVALID_HANDLE, ...}; 
new CountdownCounts[MAXPLAYERS+1] = {0, ...}; 

forward OnCountdownHintTimerEnd(client, time, id); 

public CountdownHintTimerCreate(client, time, String:text[], id) 
{ 
	if(Timer_Countdown[client] == INVALID_HANDLE) 
	{ 
		new Handle:pack = CreateDataPack(); 
		WritePackCell(pack, client); 
		WritePackCell(pack, time); 
		WritePackString(pack, text); 
		WritePackCell(pack, id); 
		 
		CountdownHintPrint(client, time, text, id);
		Timer_Countdown[client] = CreateTimer(1.0, CountdownHintTimer, pack, TIMER_REPEAT); 
	} 
	else 
	{ 
		CPrintToChat(client, "{gold}[CountdownHintTimer]: {red}Ошибка создания таймера для Вас, таймер уже создан!"); 
	} 
} 

public Action:CountdownHintTimer(Handle:timer, any:pack) 
{ 
	decl client, time, String:text[64], id; 
	ResetPack(pack); 
	client = ReadPackCell(pack); 
	time = ReadPackCell(pack); 
	ReadPackString(pack, text, sizeof(text)); 
	id = ReadPackCell(pack);
	CloseHandle(pack);
	CountdownHintPrint(client, time, text, id);
}

stock CountdownHintPrint(client, time, text, id)
{
	if(CountdownCounts[client] < time) 
	{ 
		PrintHintText(client, text, (time - CountdownCounts[client])); 
		CountdownCounts[client]++; 
	} 
	else 
	{ 
		ClearTimer(Timer_Countdown[client]); 
		CountdownHintTimerReset(client); 
		PrintHintText(client, ""); 
		 
		new result; 
		Call_StartFunction(INVALID_HANDLE, OnCountdownHintTimerEnd); 
		Call_PushCell(client); 
		Call_PushCell(time); 
		Call_PushCell(id); 
		Call_Finish(result); 
	} 
} 

public CountdownHintTimerReset(client) 
{ 
	Timer_Countdown[client] = INVALID_HANDLE; 
	CountdownCounts[client] = 0; 
}
 

Dragon_Knight

Участник
Сообщения
5
Реакции
0
Спасибо за ответ, но этот код гарантированно работать не будет.

CreateTimer(1.0, CountdownHintTimer, pack, TIMER_REPEAT); - вызываем CountdownHintTimer и передаём ссылку на пак туда.
CountdownHintTimer > CloseHandle(pack); - убиваем ссылку и уничтожаем сам пак. Следующий вызов таймера будет с pack = INVALID_HANDLE.

Второй момент, public Action:CountdownHintTimer(Handle:timer, any:pack)
почему "any:pack", когда туда конкретно передаётся только ссылка?
 

R1KO

fuck society
Сообщения
9,457
Реакции
7,786
  • Команда форума
  • #4
CreateTimer(1.0, CountdownHintTimer, pack, TIMER_REPEAT); - вызываем CountdownHintTimer и передаём ссылку на пак туда.
CountdownHintTimer > CloseHandle(pack); - убиваем ссылку и уничтожаем сам пак. Следующий вызов таймера будет с pack = INVALID_HANDLE.
Согласен. Затупил.

Второй момент, public Action:CountdownHintTimer(Handle:timer, any:pack)
почему "any:pack", когда туда конкретно передаётся только ссылка?
Если бы было CreateDataTimer - то Handle:pack, а в твоем случае CreateTimer, поэтому any:pack
 

Dragon_Knight

Участник
Сообщения
5
Реакции
0
R1KO, эм...
PHP:
stock Handle:CreateDataTimer(Float:interval, Timer:func, &Handle:datapack, flags=0)
{
	datapack = CreateDataPack();
	flags |= TIMER_DATA_HNDL_CLOSE;
	return CreateTimer(interval, func, datapack, flags);
}
Разница тока в том, что CreateDataTimer это сток, который в себе создаёт пак и кладёт его в обычный таймер. Ну и ещё возвращает ссылку на пак, но только для удобства.
Отсюда ровно нету разницы, что сначала создать пак и передать ссылку на него в CreateTimer, или использовать CreateDataTimer. Отсюда не понимаю, почемы Вы их так явно разделили...

Ну а если число логически, то CreateDataTimer вообще какой-то не логичный сток. По логике сначала формируем данные а потом их передаём, а не надеемся что данные будут сформированы ДО того как вызовется таймер..
 

R1KO

fuck society
Сообщения
9,457
Реакции
7,786
  • Команда форума
  • #6
Dragon_Knight, по сути без разницы что там будет, Hanle задает конкретный тип данных, а any сообщает что он может быть любым.
 

Dragon_Knight

Участник
Сообщения
5
Реакции
0
R1KO, именно это я и хотел уточнить.
Я люблю писать кокретно и не двусмысленно. Если передаём ссылку, то и тип входной переменной тлько ссылка... Я даже проверки типа if(ValidPlayer(pid)) не признаю, пишу исключительно так: if(ValidPlayer(pid) == true).
 
Последнее редактирование:

Dragon_Knight

Участник
Сообщения
5
Реакции
0
Как более грамотно написать коллбек, который будет вызываться при завершении таймера. И что-бы его наличие в коде было не обязательно.. Т.е. в данном случае если не писать в коде : public OnCountdownHintTimerEnd(client, time, id); будет ошибка о том, что функция не найдена.
 
Сверху Снизу