Server Plugins:de

From Valve Developer Community
Jump to: navigation, search
English Español Русский

Serverpluginssind C++ Codebibliotheken, die das Verhalten eines dedizierten Servers verändern. Sie werden verwendet, um alles von Wartungstools bis zu zusätzlichen spieltypen zu liefern.

Installation

Source lädt automatisch Plugins, die in Dateien definiert werden, die mit <game>\addons\*.vdf* übereinstimmen. diese Dateien sollten wie folgt formatiert sein:

Plugin
{
    file <path to plugin>
}

der Pfad ist relativ zum gameinfo.txt-Verzeichnis.

Verwaltung

Die folgenden Konsolenbefehle werden geboten:

  • plugin_print (liefert IDs für die Benutzung mit anderen Befehlen)
  • plugin_load
  • plugin_unload
  • plugin_pause (die Engine hört auf, Callbacks an das Plugin zu liefern)
  • plugin_unpause
  • plugin_pause_all
  • plugin_unpause_all

Programmierung

Ein Beispielplugin-Projekt kann unter src\utils\serverplugin_sample\ gefunden werden. Die Orange Box Version ist gut für Source 2007 und 2009.

Plugins arbeiten über das veröffentlichen eines Objekts zur Engine, welches von IServerPluginCallbacks und IGameEventListener2 erbt. Source wird Funktionsaufrufe an das Plugin zu verschiedenen Zeiten senden, hard-coded und/oder belauschte, und das Plugin kann auf jedes dieser Events durch das ausführen eigenen codes reagieren. In manchen Fällen (z. B. Spielerverbindungen) ist auch das Ändern der ursprünglichen Ergebnisse der originalen Funktion möglich.

Der wichtigste Vorbehalt ist, dass man auf keine Serverklassen zugreifen kann. Jedes Plugin ist eine diskrete Bibliothek, die nur auf die Teile des Servers zugreifen kann, die über Sources verschiedene Schnittstellen veröffentlicht werden. Schnittstellen, wie CBaseEntity, sind nicht verfügbar; Entities werden stattdessen mit edict_t repräsentiert. Bestätigung: Auf Entities ohne edicts kann nicht zugegriffen werden.

Achtung:
Wenn es Quellcode für eine Klassendeklaration gibt, ist es möglich, diese einzubinden und Zugriff zu gewinnen, aber dies zu machen ist gefählrich. Sollte die Klasse im Server sich jemals ändern, wird das Plugin ungültige Pointer besitzen.
Tipp:Ein Plugin wird bei der Initialisierung fehlschlagen (nicht mit einem Callstack abstürzen), wenn Exceptions während des Ladens auftreten. Das kann passieren, wenn versucht wird, eine Schnittstelle zu benutzen, bevor diese durch IServerPluginCallbacks::Load() initialisiert wurde (z. B. einen Pointer aus cvar->FindVar() zwischenspeichern). Man kann Dinge deklarieren, aber bis Load() kann ihnen nichts zugewiesen werden.

Kompilierung

Windows
Baue das zur Verfügung gestellte Visual Studio Projekt ; siehe Kompilieren unter VS2008 oder Kompilieren unter VS2010 für Hilfe beim Upgraden
Linux
Navigiere nach src/linux_sdk/, bearbeite Makefile.plugin, um deine Dateien einzubinden und führe dann make plugin aus.
Wenn du für Source 2009 kompilierst, musst du den Namen mancher Valve-Bibliotheken in Makefile und Makefile.vpcm ändern:
Tipp:Es ist wahrscheinlich am Besten, eine Kopie des linux_sdk-Verzeichnisses zu machen, bevor man dies tut, sodass die Source 2007 Kompilierung nicht zerstört wird.
  • tier0_i486 > libtier0
  • vstdlib_i486 > libvstdlib
  • steam_api_i486 > libsteam_api
Benutze ldd -d <plugin.so> um auf Abhängigkeiten zu prüfen. Es wird nicht die Bibliotheken finden; kümme dich darum, wie sie heißen.
Mac
Bisher nicht möglich

Um ein Plugin zu debuggen, muss der Server mit -allowdebug gestartet werden.

Auf Events hören

Die Schnittstelle IGameEventManager2 (IGameEventManager wurde vorher verwender) erlaubt einem Plugin, auf Spielevents zu reagiren. Spielevents werden von einer Modifikation gefeuert, wenn Dinge von Interesse passieren, wie das Sterben eines Spielers oder das Platzieren einer Bombe. IGameEventManager2::AddListener Sollte aufgerufen werden, um auf ein bestimmtes Spielevent zu horchen. Es muss für jedes Event aufgerufen werden, über welche der Listener informiert werden will. FireGameEvent wird dann im Plugin aufgerufen, wenn eins der belauschten Events auftritt. Die in jedem Event enthaltenen Daten werden durch Event-Konfigurationsdateien beschrieben, insbesonder:

  • hl2/resource/serverevents.res
  • hl2/resource/GameEvents.res
  • <mod dir>/resource/ModEvents.res

ConVars und Commands erstellen

ConVars lassen einen Variablen spezifizieren, die der Benutzer benutzen kann, um das Verhalten des Plugins einzustellen. ConCommands erlauben die Erzeugen von Befehlen, die das Plugin leifert. Die Erzeugung ist einfach und selbstbeinhaltend. Der Codeschnipsel unten erzeugt den neuen Befehl empty_version und die neue Variable plugin_empty. Der Befehl kann vom Server oder vom Client aus ausgeführt werden. Um die Quelle des Befehls zu bestimmen, sollte der durch SetCommandClient gelieferte Index verwendet werden.

CON_COMMAND( empty_version, "Liefert die Version des leeren Plugins" )
{
        Msg( "Version:1.0.0.0\n" );
}

static ConVar empty_cvar("plugin_empty", "0", 0, "Beispielplugin-cvar");

Andere Tricks

Spielerentities erhalten:

static CGlobalVars *gpGlobals;
static IVEngineServer *engine;

CON_COMMAND( list_players, "Prints the name of each connected player" )
{
	for (int i=1;i<gpGlobals->maxClients;i++) // EntIndex 0 ist Weltspawn, nach dem die Spieler kommen
	{
		// Beachte, dass das nur funktioniert, wenn der Spieler aktivi st; Spieler, die sich gerade noch verbinden, werden nicht aufgeführt
		IPlayerInfo *playerinfo = playerinfomanager->GetPlayerInfo(engine->PEntityOfEntIndex(i));
		if (playerinfo)
		{
			Msg(playerinfo->GetName());
			Msg("\n");
		}
	}
}

Hinzufügen und Entfernen eines Servertags:

#include <string>

void AddTag(char* MyTag)
{
	static ConVar* sv_tags = cvar->FindVar("sv_tags");
	std::string tag_string;

	tag_string.assign(sv_tags->GetString());	

	if (tag_string.find(MyTag) == -1)
	{
		if (tag_string.length() && tag_string.at(tag_string.length()) != ',')
			tag_string.append(",");

		tag_string.append(MyTag);

		sv_tags->SetValue(tag_string.c_str());
	}
}

void RemoveTag(char* MyTag)
{
	static ConVar* sv_tags = cvar->FindVar("sv_tags");
	std::string tag_string;

	tag_string.assign(sv_tags->GetString());	

	size_t start = tag_string.find(MyTag);
	if (start != -1)
	{
		tag_string.erase( start, tag_string.find(start,',') );
		sv_tags->SetValue(tag_string.c_str());
	}
}

Siehe auch