Difference between revisions of "Ru:Events (SourceMod Scripting)"

From AlliedModders Wiki
Jump to: navigation, search
(Посылка сообщений)
Line 53: Line 53:
 
*Вы не должны вызывать <tt>CloseHandle()</tt>, <tt>FireEvent()</tt> сделает это за вас.
 
*Вы не должны вызывать <tt>CloseHandle()</tt>, <tt>FireEvent()</tt> сделает это за вас.
 
*Даже если "userid" и "attacker" являются shorts, мы отсылаем их в качестве ints.  Термин "short" используется только для того, чтобы сказать движку сколько байт числа необходимо для отправки.
 
*Даже если "userid" и "attacker" являются shorts, мы отсылаем их в качестве ints.  Термин "short" используется только для того, чтобы сказать движку сколько байт числа необходимо для отправки.
*It is possible for event creation to fail; this can happen if the event does not exist, or nothing is hooking the eventThus, you should always make sure <tt>CreateEvent</tt> calls return a valid Handle.
+
*Событие может и не создастся; это происходит если событие не существует или никто не перехватывает егоПоэтому вы должны убедиться, что вызов <tt>CreateEvent</tt> возвращает правильный Handle.
*Most events use client userids instead of client indexes.
+
*Большинство событий используют userids вместо индекса.
*By default, <tt>FireEvent()</tt> broadcasts messages to clientsThis can be prevented by passing <tt>dontBroadcast</tt> as true.
+
*По умолчанию, <tt>FireEvent()</tt> посылает сообщения к клиентуЭто можно отключить установив <tt>dontBroadcast</tt> в true.
  
 
=Hooking Events=
 
=Hooking Events=

Revision as of 22:49, 24 December 2010

Для просмотра всех событий, нажмите здесь.

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

Все нативные события можно найти в 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.

Hooking Events

When hooking an event, there are three modes to choose from:

  • Pre - Hook the event before it is fired.
  • Post - Hook the event after it is fired.
  • Post_NoCopy - Hook the event, but do not save any of its information (special optimization).

Hooking an event is usually done for one of the following goals. To get an idea of which mode to use, see the list below each goal:

  • Blocking the event (preventing it from being fired)
    • Always Pre
  • Rewriting the event (changing its parameters)
    • Always Pre
  • Acting upon the event (doing something once the event is completed)
    • Pre if your action must come before the mod's action.
    • Post if your action must come after the mod's action.
    • PostNoCopy if your action is Post and only requires the event name.

As always, you do not need to unhook events when your plugin unloads. They are automatically removed.

Blocking Events

Blocking events is the easiest thing to do. Let's say we want to block death events that are headshots:

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
}

Rewriting Events

Rewriting events is just as easy -- events can be modified in pre hooks. For example, say we want to remove headshots from all events:

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 Hooks

Post hooks are default, and will usually be the most common usage. For example, say we want to print a message to every client that dies:

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)
}

This will print a message to a player's console telling them who killed them, with what weapon, and whether it was a headshot or not.

Note that the return value for post hooks is ignored, so the Action tag is not needed.

PostNoCopy Hooks

Lastly, there are some hooks where the only piece of information needed is the name of the event. PostNoCopy is a special optimization for this case. When transitioning from Pre to Post, SourceMod must duplicate the event and all of its key/value pairs. PostNoCopy prevents that sequence from happening.

For example, let's say we want to find when a certain sequence of events is called.

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)
}

Note that like normal Post hooks, there is no return value needed. However, the event parameter for PostNoCopy will always be equal to INVALID_HANDLE. Thus, the name parameter must be used instead of GetEventName.