Ru:Events (SourceMod Scripting)

From AlliedModders Wiki
Revision as of 23:16, 24 December 2010 by V1KT0P (talk | contribs) (Hooking Events)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to: navigation, search
Для просмотра всех событий, нажмите здесь.

События это короткие сообщения с именем, посылаемые сервером. Хотя они используются для внутренней передачи сообщений, они также посылаются клиентам.

Все нативные события можно найти в plugins/include/events.inc.

Введение

События описаны в .res файлах мода в папке resource. "Стандартные" события находятся в hl2/resource/gameevents.res и hl2/resource/serverevents.res. Мод может расширить эти события с помощью расширений.

Для примера посмотрим на player_death из hl2/resource/gameevents.res:

"player_death"
{
	"userid"	"short"   	// user ID убитого				
	"attacker"	"short"	 	// user ID убийцы
}

Counter-Strike:Source расширяет это описание в cstrike/resource/modevents.res:

"player_death"
{
	"userid"	"short"   	// user ID убитого				
	"attacker"	"short"	 	// user ID убийцы
	"weapon"	"string" 	// название оружие, которым убил убийца 
	"headshot"	"bool"		// сигнал попадания в голову
}

Обратите внимание, что событие состоит в следующем формате:

"name"
{
	"key1"	"valueType1"
	"key2"	"valueType2"
	...
}

Посылка сообщений

Послать сообщенмя очень просто. Например мы хотим послать сообщение смерти используя событие player_death описанное выше. Для Counter-Strike:Source, это будет иметь вид:

SendDeathMessage(attacker, victim, const String:weapon[], bool:headshot)
{
	new Handle:event = CreateEvent("player_death")
	if (event == INVALID_HANDLE)
	{
		return
	}
 
	SetEventInt(event, "userid", GetClientUserId(victim))
	SetEventInt(event, "attacker", GetClientUserId(attacker))
	SetEventString(event, "weapon", weapon)
	SetEventBool(event, "headshot", headshot)
	FireEvent(event)
}

Примечания:

  • Вы не должны вызывать CloseHandle(), FireEvent() сделает это за вас.
  • Даже если "userid" и "attacker" являются shorts, мы отсылаем их в качестве ints. Термин "short" используется только для того, чтобы сказать движку сколько байт числа необходимо для отправки.
  • Событие может и не создастся; это происходит если событие не существует или никто не перехватывает его. Поэтому вы должны убедиться, что вызов CreateEvent возвращает правильный Handle.
  • Большинство событий используют userids вместо индекса.
  • По умолчанию, FireEvent() посылает сообщения к клиенту. Это можно отключить установив dontBroadcast в true.

Перехват Событий

Существует три режима перехвата событий:

  • Pre - Перехват события до выполнения.
  • Post - Перехват события после выполнения.
  • Post_NoCopy - Перехват события, но не сохраняется любая информация об этом событии (специальная оптимизация).

Перехват событий обычно делается для одной из этих целей. Для того, чтоб понять какой режим использовать, смотрите ниже список целей:

  • Блокировка события (предотвращение выполнения)
    • Всегда Pre
  • Изменение события (изменение параметров)
    • Всегда Pre
  • Выполнить после события (сделать что-то после того как событие произошло)
    • Pre если ваши действия должны произойти перед выполнением мода.
    • Post если ваши действия должны произойти после выполнением мода.
    • PostNoCopy если подходит Post и требуется только имя события.

Как всегда вы не должны убирать перехват события, когда происходит выгрузка плагина. Они удаляются автоматически.

Блокировка Событий

Блокировку событий сделать очень просто. Например мы хотим заблокировать событие смерти если смерть произошла от попадания в голову:

public OnPluginStart()
{
	HookEvent("player_death", Event_PlayerDeath, EventHookMode_Pre)
}
 
public Action:Event_PlayerDeath(Handle:event, const String:name[], bool:dontBroadcast)
{
	if (GetEventBool(event, "headshot"))
	{
		return Plugin_Handled
	}
	return Plugin_Continue
}

Изменение Событий

Измененить событий тоже очень просто -- события могут быть изменены в режиме перед выполнением события. Например мы хотим убрать попадание в голову со всех событий:

public OnPluginStart()
{
	HookEvent("player_death", Event_PlayerDeath, EventHookMode_Pre)
}
 
public Action:Event_PlayerDeath(Handle:event, const String:name[], bool:dontBroadcast)
{
	SetEventBool(event, "headshot", false)
	return Plugin_Continue
}

Post Перехват

По умолчанию используется перехват после события и как правило наиболее используемый. Например мы хотим послать сообщение всем игрокам, которые умерли:

public OnPluginStart()
{
	HookEvent("player_death", Event_PlayerDeath)
}
 
public Event_PlayerDeath(Handle:event, const String:name[], bool:dontBroadcast)
{
	decl String:weapon[64]
	new victimId = GetEventInt(event, "userid")
	new attackerId = GetEventInt(event, "attacker")
	new bool:headshot = GetEventBool(event, "headshot")
	GetEventString(event, "weapon", weapon, sizeof(weapon))
 
	decl String:name[64]
	new victim = GetClientOfUserId(victimId)
	new attacker = GetClientOfUserId(attackerId)
	GetClientName(attacker, name, sizeof(name))
 
	PrintToConsole(victim,
		"You were killed by \"%s\" (weapon \"%s\") (headshot \"%d\")",
		name,
		weapon,
		headshot)
}

Это будет писать игроку в консоли кто его убил, с каким оружием и было ли попадание в голову.

Обратите внимание, что возвращение значений с перехвата после события игнорируется, поэтому тег Action ненужен.

PostNoCopy Перехват

Наконец есть перехваты где требуется только имя события. PostNoCopy специальная оптимизация для этого. При переходе от Pre к Post, SourceMod должен дублировать событие и все значения. PostNoCopy предотвращает это.

Например мы хотим найти когда происходят определенные события.

public OnPluginStart()
{
	HookEvent("game_newmap", GameEvents, EventHookMode_PostNoCopy)
	HookEvent("game_start", GameEvents, EventHookMode_PostNoCopy)
	HookEvent("game_end", GameEvents, EventHookMode_PostNoCopy)
	HookEvent("game_message", GameEvents, EventHookMode_PostNoCopy)
}
 
public GameEvents(Handle:event, const String:name[], bool:dontBroadcast)
{
	PrintToServer("Event has been fired (event \"%s\") (nobcast \"%d\")", name, dontBroadcast)
}

Обратите внимание, что как и обычный Post перехват, он не требует возврата значений. Однако, параметр event для PostNoCopy всегда должен быть равным INVALID_HANDLE. Таким образом параметр name должен использоваться вместо GetEventName.