Multiplayer Editing in ArmA 3

  • Um mal ein wenig auf das Multiplayerscripting einzugehen, versuch ich hier mal das ganze ein wenig zu erläutern.


    Grundlagen:
    Nachfolgend mal grundlegende Befehle um etwas zu synchronisieren.


    Senden
    publicVariable
    Funktion: Sendet den Inhalt einer Variable an alle (Server + Client).


    Syntax: publicVariable "Variable";
    Wichtig: Die Variable muß in "" gesetzt werden als String
    Hinweis: Löst den publicVariableEventHandler nicht auf dem Rechner aus, der diesen Befehl aufruft !


    publicVariableClient
    Funktion: Sendet den Inhalt einer Variable an eine bestimmten Client (nur auf dem Server ausführbar)


    Syntax: clientID publicVariableClient "Variable";
    Wichtig: Die Variable muß in "" gesetzt werden als String
    Hinweis: Löst den publicVariableEventHandler nicht auf dem Rechner aus, der diesen Befehl aufruft !


    clientID: Gibt die einzigartige ID des Besitzers eines Objektes auf dem Server zurück (lokal und global-Thematik) und läßt sich mit dem Befehl owner ermitteln
    Syntax: _clientID = owner <object>;


    Wenn man den Befehl (Serverseitig) auf den Charachter eines Spielers anwendet, gibt der Befehl die clientID des Spielers zurück (Zahl).
    Funktioniert auch bei Objekten die auf einem Client gespawnt wurden, da sie dort lokal sind.(Was sich allerdings auch wieder ändern kann. (Siehe lokal/global)

    <object>
    kann hierbei alles sein was als Objekt definiert ist wie z.B. Fahrzeuge, Einheiten, etc.



    publicVariableServer
    Funktion: Sendet den Inhalt einer Variable nur an den Server. (macht nur auf einem Client Sinn).


    Syntax: publicVariableServer "Variable";
    Wichtig: Die Variable muß in "" gesetzt werden als String
    Hinweis: Löst den publicVariableEventHandler nicht auf dem Rechner aus, der diesen Befehl aufruft !


    Gleiches Prinzip wie bei der Client-Variante, jedoch vom Client in Richtung Server.



    Zusammenfassung: mit den Public-Befehlen lassen sich grundsätzlich Variablen übermitteln und mit der Client- bzw. Server-Variante gar gezielt, was den Bandbreitenverbrauch etwas schont.
    Mit der Nachfolgenden Funktion habt ihr noch die Möglichkeit "Aktionen" auf dem Client/Sevrer ausführen zu lassen.



    Empfang

    addPublicVariableEventHandler
    Funktion: Der <Code> wird ausgeführt sobald sich die Variable ändert und per publicVariable-Befehl gesendet wurde.


    Syntax: "Variable" addPublicVariableEventHandler { <Code> };
    Wichtig: Die Variable muß in "" gesetzt werden als String


    Mit diesem Befehl lassen sich z.B. Wetter, Tageszeiten, usw. recht gut im MP synchronisieren.


    Funktionen
    Funktionen sind äußerst nützlich um die Bandbreite zu reduzieren, die man mit den publicVariable-Befehlen benutzt und reduziert somit den lag bei exzessiver Benutzung.


    Wie man eine Funktion erstellt/definiert ist im Grunde recht simpel.


    Beispiel globale Funktion (d.h. läßt sich immer wieder aufrufen):

    Code
    1. funktionsname = { };


    In die {} Klammern schreibt ihr dann die Funktion.


    Beispiel lokale Funktion (d.h. läßt sich nur innerhalb eines Scripts aufrufen und ist nach dem Ende des Scripts nicht mehr aufrufbar):

    Code
    1. _funktionsname = { };


    In die {} Klammern schreibt ihr dann die Funktion.


    - Lokale Funktionen und Variablen fangen immer mit einem Unterstrich an und lassen sich nur innerhalb eines Scripts verwenden.
    - Funktionen lassen sich mit call oder spawn aufrufen.
    - call kann Werte zurück geben. Ruft man in einem Sctipt per call eine Funktion auf, so wartet die das Script bis die Funktion beendet ist.
    - spawn ist quasi ein fire&forget-Aufruf. Script wartet nicht auf das Ende der Funktion

    Nu mal zum praktischen Teil:


    Beispiel: Tageszeit auf allen Clients mit dem Server synchronisieren:


    initPlayerLocal.sqf

    Code
    1. GT_fnc_syncDate = { _syncDate = _this; setDate _syncDate;};"GT_syncDate" addPublicVariableEventHandler { (_this select 1) call GT_fnc_syncDate; };


    Diese Script wird auf jedem Client ausgeführt wenn er dem Server beitritt.
    Hier wird 1. die Funktion GT_fnc_syncDate definiert und 2. ein EventHandler für die Variable GT_syncDate zugewiesen, d.h. jedes mal wenn die Variable per publicVariable-Befehl gesendet wird ruft der Client die Funktion GT_fnc_syncDate auf.
    (_this select 0) -> Übergibt den Namen der Variable(wird hier aber nicht gebraucht)
    (_this select 1) -> Übergibt den Inhalt der Variable und wird in der Funktion mit _this abgerufen.


    initServer.sqf

    Code
    1. execVM "server_cycle.sqf";


    Dieses Script wird beim Missionsstart nur vom Server ausgeführt und startet die Datei server_cycle.sqf.


    server_cycle.sqf

    Code
    1. while{true} DO { sleep (60*10);GT_syncDate = date;publicVariable "GT_syncDate";};


    while(true) DO {... - erstellt eine Endlos-Schleife
    sleep (60*10); - Wartet 10 Minuten bevor es weiter geht.
    GT_syncDate = date; - setzt die Variable auf das aktuelle Datum
    publicVariable "GT_syncDate"; - publiziert die Variable an alle Clients



    An dieser Stelle funktioniert es schon mal grundsätzlich die Zeit alle 10 Minuten zu synchronisieren, jedoch wenn ein Spieler dem laufenden Spiel (Join In Progress) beitritt, wird bei ihm erst die Zeit synchronisiert, wenn der Server cycle von 10 Minuten durch ist, was dazu führen kann dass er bis zu 10 Minuten nicht zur gleichen Tageszeit spielt. Um das zu umgehen erstellen wir noch ein weiteres Script, was die JIP-Spieler zusätzlich synchronisiert:


    initPlayerServer.sqf

    Code
    1. _playerObj = _this select 0; //mit select 0 erhaltet ihr bei diesem Script die Spielerfigur
    2. waituntil{alive _playerObj}; //wartet bis der Spieler gespawnt ist
    3. _clientID owner _playerObj; //ermittelt die client ID
    4. GT_syncDate = date;
    5. _clientID publicVariableClient "GT_syncDate"; //Der JIP-Spieler wird jetzt synchronisiert


    initServer.sqf
    intiPlayerLocal.sqf
    und initServer.sqf sind sogenannte Event-Scripts, welche Variablen, Objekte, etc. über _this abrufbar sind könnt ihr hier nachlesen.

  • Inspiriert durch die TWT TVR Mission vom Sonntag hab ich mich mal auf die Suche begeben, wie man die Thermal Bildgebung deactivieren kann und es gibt tatsächlich eine BI Funktion [vehicle] disableTIEquipment true/false; [deaktiviert/aktiviert] mit welcher man ein Fahrzeug Land/See/Luft initialisieren oder später ändern kann. Bei Infantry Units gibt es zwar keinen Fehler, aber es funktioniert auch nicht (-> Siehe Laser Designator und Thermal Visiere). Das müsste man nochmal testen.


    Großes Manko ist, dass bei dieser Funtkion auch die Nachtsicht ausgeschaltet wird, allerdings gibt es da bereits ein Ticket bei BI, um dieses zu unterscheiden.