Community-Tutorials (Source)

Networkvars

Hi leute, heute soll es um so gennante "NetworkVars" gehen.

Doch was sind diese NetworkVars und wozu werden sie benötigt.

Eigentlich ist alles ganz einfach, wir haben im HL2 einmal den Client und den Server.

Der Client ist verantwortlich für zum Besispiel Hudelemente, die Grafik und die Physik.
Der Server für die Spielmodi und die allgemeine Spielelogik (das was Server eben so machen).

Es erscheint logisch das zwischen den beiden Daten (Variablen --> Engl: Vars) austauschen müssen. (ZB Aktuelle Positionen der Spieler).
Das ganze geschieht auch logischerweise über das Netzwerk (Eng: Network).

Und da haben wir auch schon das Wort NetworkVars raus. So nun aber genug gelabert, ich will euch nun zeigen wie das
von statten geht.

Wir gehen von folgendem Beispiel aus:

Wenn wir im Server in einen Trigger laufen bekommt der Spieler Punkte (Server).
Diese Punkte wollen wir nun in einem HudElement anzeigen (Client) und aus diesem Grund müssen wir die Variable mit unseren Punkten vom Server zum Client schicken.

Also los, pratkisch brauchen wir nur 4 Dateien öffnen.

Im Client:
c_baseplayer.cpp
c_baseplayer.h

Im Server:
player.cpp
player.h

Jeder Spieler soll so eine Variable in seiner Klasse haben, deswegen ist es eben wichtig das wir sie in den Dateien des Spielers deklarieren.

Also Springen wir mal in die erste Datei die wir bearbeiten:

c_baseplayer.h

Deklariert nun in der Playerklasse eine Variable namens "Punkte". Achtet darauf das ihr sie im Public Bereich deklariert, damit ihr später darauf zugreifen könnt.

Ich zum Beispiel habe sie in der Zeile 67 deklariert.
Anmerkung: Wenn ihr schnell zu einer Zeile Springen wollt, drückt Strg + g.

int Points;

Ihr wundert euch sicher warum wir diese Variable im Client deklarieren, aber macht es einfach so, die Makros die valve geschrieben hat kommen mit im Server deklarierten Sachen nicht so gut klar.

Nun gehen wir wieder in die Serverdateien zurück, zu player.h.

Dort sagen wir nun HL2 das wir eine Variable haben die Netzwerkfähig sein soll.

In der Klasse CBasePlayer im public bereich (bei mir zb Zeile 648) schreibt ihr folgendes:

CNetworkVar(int, Punkte);

Der erste Parameter gibt an um welchen Datentyp es sich handelt, der Zweite gibt den Namen an.

Damit wäre unsere Arbeit in den Headerdateien vollbracht.

Nun gehen wir in die Datei player.cpp direkt zur Zeile 7011.

Was wir da sehen ist eine Tabelle. In dieser Tabelle werden die Dinge reingeschrieben (zb unsere eben deklarierte Networkvar),
die an den Client gesendet werden.

In diese Tabelle schreiben wir jetzt nach dem Schema unsere Variable ein:

IMPLEMENT_SERVERCLASS_ST( CBasePlayer, DT_BasePlayer )

SendPropDataTable(SENDINFO_DT(pl), &REFERENCE_SEND_TABLE(DT_PlayerState), SendProxy_DataTableToDataTable),
SendPropEHandle(SENDINFO(m_hVehicle)),
SendPropEHandle(SENDINFO(m_hUseEntity)),
SendPropInt (SENDINFO(m_iHealth), 10 ),
SendPropInt (SENDINFO(Punkte), 10 ),
SendPropInt (SENDINFO(m_lifeState), 3, SPROP_UNSIGNED ),
SendPropFloat (SENDINFO(m_flMaxspeed), 12, SPROP_ROUNDDOWN, 0.0f, 2048.0f ), // CL
SendPropInt (SENDINFO(m_fFlags), PLAYER_FLAG_BITS, SPROP_UNSIGNED|SPROP_CHANGES_OFTEN, SendProxy_CropFlagsToPlayerFlagBitsLength ),
SendPropInt (SENDINFO(m_iObserverMode), 3, SPROP_UNSIGNED ),
SendPropEHandle (SENDINFO(m_hObserverTarget) ),
SendPropInt (SENDINFO(m_iFOV), 8, SPROP_UNSIGNED ),
SendPropInt (SENDINFO(m_iDefaultFOV), 8, SPROP_UNSIGNED ),
SendPropArray ( SendPropEHandle( SENDINFO_ARRAY( m_hViewModel ) ), m_hViewModel ),
SendPropString (SENDINFO(m_szLastPlaceName) ),

// Data that only gets sent to the local player.
SendPropDataTable( "localdata", 0, &REFERENCE_SEND_TABLE(DT_LocalPlayerExclusive), SendProxy_SendLocalDataTable ),

END_SEND_TABLE()

So dann schauen wir uns das Schlammasel mal an:

SendPropInt (SENDINFO(Punkte), 10 )

1. Das erste gibt den zu sendenden Datentyp an, wir wollen "int" wegschicken (deswegen "SendPropInt"), aber wie wir schon anhand der tabelle sehen gibt es noch mehr Datentypen.
(ZB "SendPropArray", "SendPropString", "SendPropFloat").

2. Das SENDINFO ist ein Makro wo einfach nur unsere Variable als Parameter benötigt wird,

3. Die Zahl dahinter gibt an wie lang (in Bit) unsere zahl ist. Wenn wir dort -1 hinschreiben kann die Zahl beliebig lang sein. DAS SOLLTET IHR ABER AUF KEINEN FALL AUS FAULHEIT TUN, DAS ERFORDET MEHR BANDBREITE UND KANN IM GROßEN STIL BETRIEBEN LAGS VERURSACHEN!

Ja das war es ja dann auch schon, die Zahl kann so gesendet werden.

Nun sind unsere Arbeiten am Server beendet.

Als letzten Schritt wenden wir uns der c_baseplayer.cpp zu.

Wenn wir Sendetabellen haben, haben wir logischerweise auch Empfangstabellen. Die Empfangstabelle die zu unserer Sendetabelle passt finden wir auf Zeile 215.

Man sieht schon am Kopf der Tabelle das die beiden zusammengehören.

Im Server: IMPLEMENT_SERVERCLASS_ST( CBasePlayer, DT_BasePlayer )
Im Client: IMPLEMENT_CLIENTCLASS_DT(C_BasePlayer, DT_BasePlayer, CBasePlayer)

(Das DT steht für DataTable und gibt also den Namen der Sende - und Empfangstabelle an).

Also steht da nachdem wir es nach dem gleichen Schema wie im Server eingefügt haben:

IMPLEMENT_CLIENTCLASS_DT(C_BasePlayer, DT_BasePlayer, CBasePlayer)

RecvPropDataTable( "localdata", 0, 0, &REFERENCE_RECV_TABLE(DT_LocalPlayerExclusive) ),

RecvPropDataTable(RECVINFO_DT(pl), 0, &REFERENCE_RECV_TABLE(DT_PlayerState), DataTableRecvProxy_StaticDataTable),

RecvPropInt (RECVINFO(m_iFOV), 0, RecvProxy_FOV),
RecvPropInt (RECVINFO(m_iDefaultFOV), 0, RecvProxy_DefaultFOV),

RecvPropEHandle( RECVINFO(m_hVehicle) ),
RecvPropEHandle( RECVINFO(m_hUseEntity) ),

RecvPropInt (RECVINFO(m_iHealth)),
RecvPropInt (RECVINFO(Punkte)),
RecvPropInt (RECVINFO(m_lifeState)),

RecvPropFloat (RECVINFO(m_flMaxspeed)),
RecvPropInt (RECVINFO(m_fFlags)),

RecvPropInt (RECVINFO(m_iObserverMode) ),
RecvPropEHandle (RECVINFO(m_hObserverTarget), RecvProxy_ObserverTarget ),
RecvPropArray ( RecvPropEHandle( RECVINFO( m_hViewModel[0] ) ), m_hViewModel ),

RecvPropString( RECVINFO(m_szLastPlaceName) ),

END_RECV_TABLE()

RecvPropInt (RECVINFO(Punkte))

Das erkläre ich jetzt hier nicht nochmal, sollte logisch sein (auch hier wieder verschiedene Datentypen beim Empfangen beachten).

Tja und das war es dann auch schon, wir können die Variable im Server verändern und dann im Client beliebig darauf zugreifen.

Das schöne ist auch das das MS IntelliSense das sogar gemerkt hat:

kyle015.jpg

Hoffe es war halbwegs verständlich.

Kyle :ugly: (der muss noch)

Achja falls ihr ein talentierter Modeler seid und arbeit bei einer MOD sucht, meldet euch bei mir, bzw klickt auf den Link in meine Signatur.