[Guide] DayZ Standalone Scripting - Enforce Scripting

  • Einführung

    Ich teile hier mal alles was ich bisher über Enforce, die Script Sprache auf der die DayZ Standalone und womöglich spätere Bohemia Titel basieren werden, herausgefunden habe.

    Das ganze richtet sich an bereits erfahrene Programmierer, die die Grundkonzepte moderner Hochsprachen verstehen. Also falls ihr euch mit C#, C++ oder auch Java auskennt solltet ihr klarkommen. Falls nicht wird das ganze hier euch nicht wirklich weiterhelfen.

    Ich kann nicht versichern das alles was ich hier schreibe zu 100% richtig ist, da es auf meinen eigenen getesteten Theorien basiert sowie auf Aussagen von Nutzern der DayZ Modding Discords.

    Also falls jemand mehr weiß oder einen Fehler entdeckt kann er es ja posten.

    Ich empfehle die DayZ Tools auf Steam unter Tools. In den DayZ Tools gibt es unter Workbench->Editors->Script Editor einen Script Editor mit Code highlighting und Codevorschlägen. Zum einrichten der Workbench für tatsächliche Mods (nicht nur modifizierte Missionfiles) diesen Guide verwenden.

    Am Anfang empfiehlt es sich allerdings die dayZOffline.ChernarusPlus Mission im DayZ Verzeichnis->missions->init.c zu Editieren (vorher Backup machen!). Zum Starten von DayZ im offline mode braucht ihr eine batch Datei im Missionverzeichnis in der steht:

    Code
    @echo off
    
    taskkill /F /IM DayZ_x64.exe /T
    
    RD /s /q "storage_-1" > nul 2>&1
    
    cd ../../
    
    start DayZ_x64.exe -mission=.\Missions\dayzOffline.ChernarusPlus -scrAllowFileWrite -nosplash -noPause -noBenchmark -name MyName -scriptDebug=true -filePatching -doLogs

    (Batchdatei von Arkensor aus der CommunityOfflineMode)


    Ganz wichtig dabei auch: DayZ SA windowed starten (einfach im Optionsmenü einstellen) so kann man bei Fehlern einfach Wiederholen drücken.

    Wenn alles Funktioniert müsst ihr das Spiel auch nicht komplett neustarten um Änderungen in der Missionfile wirksam zu machen. Einfach dafür im Menü Neustarten drücken (manchmal ist trotzdem ein kompletter Neustart erforderlich z.B. beim bearbeiten von Dateien die mit #include eingebunden sind.).

    Hilfreiche Links

    Enforce Script - Grundlegende Konzepte

    Enforce Script ist eine Scriptsprache die für die Enforce Engine entwickelt wurde.

    Alles Scripts, auch die der grundlegenden Spiellogik sind in der scripts.pbo im dta Ordner des DayZSA verzeichnisses offen einsehbar und sind hilfreich um herauszufinden wie gewisse Sachen funktionieren (bis endlich eine ordentliche API referenz herauskommt).

    Wichtige Eigenschaften:

    • Objektorientiert
    • Anweisungen werden mit einem ; (Semikolon) beendet.
    • Funktionskörper/Kontrollstrukturenkörper in {} (Geschweiften Klammern)
    • C Sprachen ähnlich
    • Erstes Array Element ist 0
    • Keine Mehrfachdeklarationen/Definitionen auf einer Zeile (z.B. int a,b;)
    • Case sensitive (Groß und Kleinschreibung ist wichtig!)
    • Big-endian (ggf. Systemabhängig)
    • Für manches gibt es mehr als einen Syntax z.B. extends
    • Nach Kontrollstrukturen können {} weggelassen werden wenn nur eine Anweisung kommt.
    • Deklaration und Definition von Klassen und Funktionen immer gleichzeitig nie seperat (soweit ich weiß).
    • Alles wird wie ein Objekt behandelt.
    • Auf nicht initialisierte Objekte kann mit if(!e) geprüft werden.
    • Klassen und Funktionen können auch verwendet werden vor der Zeile in der sie definiert werden.

    Keywords

    Liste ggf. unvollständig.


    Keyword
    Beschreibung Beispiel
    native Von der Engine Implementierte Funktion kann nicht überschrieben werden.
    Im Quellcode der Engine sind solche Funktionen mit Offset vermerkt.
    Keyword derzeit für Modder belanglos.
    proto native UIScriptedMenu GetMenu();
    proto Funktionsprototyp (In C++ pure virtual function) ist nicht definiert und muss überschrieben werden. Nur für native Funktionen.
    proto int GetID();
    ref
    Referenz auf Typ. Bei Basistypen crashed das Spiel. Verwendung bei Instanzen von Klassen empfohlen.
    ref array<int> iarr;
    reference Für DayZ Tools (Material Editor) wird als parameter in material benutzt. Unklar.
    out In Funktionsdeklaration Parameter das von Funktion modifiziert wird.
    void GetList(out array<int> _arr){}
    inout In Funktionsdeklarartion Parameter das von Funktion benutzt und dann modifiziert wird.
    proto int strrep(inout string s, string sample, string replace);
    static In Klasse: static member Variable/Funktion gibt es nur einmal für alle Instanzen(nützlich für Variable die Anzahl der Instanzen zählt). Wie in C++ In Funktionen: static Variable die auch nach Funktionsende bestehen bleibt (wie in C++).
    static int a;
    local Als Variable / Funktionsparameter: Ist lokale Variable die nicht zu problemen führt bei mehrfachaufrufen der Funktion zur gleichen Zeit wie z.B. bei threads und Rekursion.
    local int a;
    for Zählschleife wie in C++.
    for(int i=0;i<5;++i) {}
    while While Schleife wie in C++.
    while(var) {}
    if, else
    Alternative wie in C++.
    if(a) {}else if(b) {}else {}
    class Zum Definieren einer Klasse.
    class A{};
    override Zum überschreiben von Memberfunktionen einer parent-Klasse oder gemoddeter Klasse.
    override int GetId() {}
    private Private Membervariable/funktion. Zugriff nur von Member der Klasse.
    private int m_a;
    protected Protected Membervariable/funktion. Zugriff nur von Member der Klassenhierarchie.
    protected int m_b;
    modded Modifizierte Gamelogik-Klasse. Zugriff auf Original mit super Keyword.
    modded class PlayerBase {}
    foreach foreach Schleife.
    foreach(int a: iarr) {}
    true, false
    Boolsche Werte: Wahr, Falsch.
    bool a=true;
    null, NULL
    Wert einer nicht initialisierten Variable
    ref array<int> arr=null;
    new Operator zum erstellen einer Instanz.
    ref array<int> arr=new array<int>;
    delete Operator zum zerstören einer Instanz. (Wird vlt. selber aufgerufen wie garbage collector in Java?)
    delete arr;
    switch, case, default
    Switch wie in C++. Funktionalität muss ich noch genauer prüfen.
    switch(a){case 1:break;default:}
    continue Wie in C++. In Schleifen: Derzeitigen Durchlauf abbrechen und mit nächsten anfangen.
    while(a) { if(b) continue; }
    break Wie in C++. In Schleifen: Schleife abbrechen.
    while(a) { if(b) break; }
    enum Aufzählung definieren. (Zuweisungen Optional)
    enum Keys {ESC=0,A=1,B=2};
    super Variable zum Zugriff auf Parent Klasse Funktionalität oder Zugriff auf die Originalklasse für modded Klassen.
    super.GetId();
    return In Funktion Rückgabe des Funktionswertes.
    return false;
    external
    Belanglos für Modder Funktion. Unklar.
    proto native external owned string GetName();
    owned Rückgabe wert darf nicht "released" werden. Unklar.
    proto native owned string ClassName(class ent);
    typedef Type alias wie in C++.
    typedef array<string> TStringArray;
    extends Alternative Schreibweise beim erben von Klassen.
    class A extends B {} //=class A : B {}
    volatile Compiler Info ist Interne Funktion die wieder auf Script zurückgreift. Für Modding irrelevant.
    proto volatile Class Spawn();
    this In Klassen: Zugriff auf sich selbst.
    this.GetId();
    const Deklaration einer Konstanten oder als Parameter eines konstanten Parameters.
    const int a=0;
    goto
    Goto wie in C++. Sollte vlt. nicht genutzt werde. Noch nicht getestet.
    goto a;
    event Info für DayZ Tools, dass diese Funktion entity Script event ist.
    event private void EOnTouch(IEntity other, int extra)
    notnull Parameter darf nicht null sein.
    void InsertAll(notnull array<T> from)

    Datentypen

    Basistypen

    Typ
    Beschreibung Beispiel
    bool Boolscher Wert
    bool b=true;
    int 32 Bit Integer
    int i=10;
    float Fließkommazahl float f=0.5;
    string Zeichenkette.
    In Zeichenketten wird der \ (Backslash) als Kontrollzeichen verwendet wie in C Sprachen.
    "\\" währe z.B. ein \ und "\n" ein Zeilenumbruch.
    string str="Test";
    vector 3xfloat Vektor vector vec="0.5 0 3"
    typ[]
    Einfaches Array vom Typ typ. Anzahl elemente Optional. Nutzung des Fortgeschrittenene Typs empfohlen.
    int a[3]={1,2,3};

    Fortgeschrittene

    Typ
    Beschreibung Beispiel
    array<typ>, TTypArray
    Fortgeschrittener Array typ. TTypArray nur bei Basistypen wobei Typ der Basistype ist (sind typedefs). array<int> arr;
    map<typ1,typ2>, TTyp1Typ2Map
    Map Typ lässt sich indezieren mit typ1 und speichert Wert vom Typ typ2. TTyp1Typ2Map nur bei Basistypen wobei Typ der Basistype ist (sind typedefs).
    map<int,string> m;
    set<typ>, TTypSet
    Set Typ. TTypSet nur bei Basistypen wobei Typ der Basistype ist (sind typedefs).
    set<int> s;

    Sonstige

    Typ Beschreibung Beispiel
    void Leerer Typ bei Funktionen die nichts zurückgeben.
    void foo() {}
    auto Typ der selbst den typ der zurückgegebenen Variable bestimmt.
    auto a=1; //a ist int
    typename Typ eines types. Stichwort RTTI.
    typename t = int;
    func Typ einer Funktion.
    void foo() {}func f=foo;
    Class Typ für alle Klassen der basis funktionalität bietet. Class a = A;
    autoptr Ist im Prinzip eine auto ref. Sollte eigentlich autoref heißen aber das ist von Bohemia Interactive.
    autoptr map<string, float> m_values;


    Alle Standardtypen sind auch als Klassen definiert.

    Für die von der Engine definierten Memberfunktionen und Variablen Dateien EnScript.c, EnString.c und EnConvert.c in Verzeichnis scripts.pbo->1_Core->proto durchlesen.

    Operatoren

    Logik

    Operator Beschreibung Beispiel
    <, > Kleiner als, größer als.
    1<2 //true
    ==, != Gleich, ungleich.
    1==2 //false
    <=, >=
    Kleiner gleich, größer gleich.
    1<=1 //true
    ! Nicht. !true //false
    &&, || Und, oder.
    true && false //falsetrue || false //true

    Arithmetisch

    Operator Beschreibung Beispiel
    +, -
    Plus, Minus
    1+2 //=3
    *, /, %
    Multiplikation, Division, Divisionsrest (nicht Modulus!).
    3*2 //=6
    ++, --
    Inkrement, Dekrement
    int a=1;a++ //=1!!!++a //=3

    Bitwise

    Operator Beschreibung Beispiel
    &, |
    Und, Oder
    1 | 2 //=31 | 3 //=1
    ~ Nicht ~0 //=-1
    <<, >>
    Linksbitshift, Rechtsbitshift
    1<<1 //=2

    Sonstige

    Operator Beschreibung Beispiel
    = Zuweisungsoperator a=1
    [] Index Operator (bei Arrays).
    int a[]={2,4,6};a[1] //=4
    +=, -=, *=, /=, %=
    Kombinierte Operatoren.
    a+=1 //Entspricht: a=a+1
    . Zugriff auf Member in Klasse/Enum
    a.b


    Kommentare

    Art Beschreibung Beispiel
    // Einzeilliger Kommentar
    //Kommentar
    /* */
    Mehrzeilliger Kommentar
    /*KommentarKommentar*/


    Kontollstrukturen

    Alternativen

    if, else

    switch

    Schleifen

    while

    Code
    while(true)
    {
        //Endlosschleife
    }

    for

    Code
    for(int i=0;i<5;i++)
    {
        //Code wird 5 mal ausgeführt i dabei von 0 bis 4
    }

    foreach

    Code
    foreach(int a : arr) //arr vom typ array<int>
    {
        //a geht all member von arr durch
    }
    foreach(int a, string b : m) //m vom typ map<int,string>
    {
        //geht alle map Elemente durch. a ist der int teil und b der string Teil.
    }

    break, continue

    Code
    while(true)
    {
        if(a) break; //führt solang code durch bis a true (das gleiche wie while(!a))
    }
    for(int i=1;i<=10;i++)
    {
        //Code wird bei jedem durchlauf durchgeführt.
        if(i>=5) continue;
        //Code wird nur bei Durchlauf 1 bis 4 durchgeführt.
    }

    Goto

    Code
    a:
    //Endlosschleife
    goto a;

    Funktionen

    Klassen

    Klassen in Enforce Script stammen alle von der Klasse "Class" ab und haben damit immer die folgenden Memberfunktionen, die nicht überschrieben werden können:

    Memberfunktion Beschreibung
    bool IsInherited(typename type)
    Wahr wenn Klasse gleicher Typ wie type oder davon vererbter Typ.
    string ClassName() Gibt Name der Klasse als String zurück.
    typename Type() Gibt Typ zurück.
    string ToString() Gibt Inhalt als string zurück.
    Class Cast(Class from) Typecast von Klassen zwischen parent<->child
    bool CastTo(out Class to, Class from) from wird zu Typ von to getypecasted und to zugewiesen. Wahr wenn erfolgreich.
    bool SafeCastType(Class type, out Class to, Class from) Interne Funktion nicht für Modding relevant?


    Alle relevanten Arten von memberfunktionen/variablen sind im Beispiel. Am ende der Klassendefinition ist immer ein ; (Semikolon).

    Beispiel:


    Ref

    Ref sorgt dafür, das eine Klasse als Referenz übergeben wird allerdings nicht immer.

    Hier erläuterung von einem anderem Discord user (Jacob_Mango):

    Anzumerken ist auch das Instanzen die vom Typ Object erben und dieser Typ selbst immer als Referenz übergeben werden da Sie direkt mit dem Objekt in der Spielwelt zusammenhängen.

    Generell ist aber zu empfehlen alles als Referenz zu übergeben es sei denn eine Kopie ist erwünscht.

    Bei Basis typen scheint das Keyword nicht zu funktionieren und crashed das Spiel!

    Typecasts

    Code
    Man man;
    Object obj;
    man=Man.Cast(obj); //Kann fehlschlagen da man von Objekt erbt
    Class.CastTo(man,obj); //selbes wie Oben gibt true zurück wenn erfolgreich
    man=(Object)obj; //wieder selbes anscheinend Funktionieren C Casts auch

    Typecasts funktionieren nur zwischen Objekten die kompatibel sind. Etwas wie childclass->parentclass funktioniert immer parentclass->childclass aber nur wenn die Instanz auch tatsächlich eine childclass ist. So kann ein Spieler (Instanz von PlayerBase) nicht in eine Pflanze (PlantBase) umgewandelt werden auch wenn es der Spielstil mancher Spieler vermuten lässt.

    Templates

    Muss noch getestet werden geht vlt. auch mit Funktionen.

    Code
    class A<typename T>
    {
        T var;
    }
    //A<int> ist Klasse wo T im Body mit int ersetzt wurde.

    Nomenklatur der API

    Das scheint die Nomenklatur zu sein (meist):

    Art Beschreibung Beispiel
    Nicht öffentliche Membervariablen Mit m_ beginnend. m_player
    Funktionen Jedes Wort mit Großbuchstaben beginnend. GetGame
    Konstante Alles Groß zwischen wörtern _ (Unterstrich) COLOR_RED
    Klassenname Jedes Wort mit Großbuchstaben beginned. PlayerBase
    Variablen Mit Kleinbuchstaben beginnend danach jedes Wort mit Großbuchstaben beginnend. countPlayers

    Attribute

    Anscheinend gibt es sowas wie spezielle Attribute wie NonSerialized() diese werden in [] geschrieben siehe scripts.pbo->1_Core->proto->Serializer.c für ein Beispiel.

    Präprozessor

    Präprozessor Anweisungen werden vor der Script ausgeführt wird geprüft und sind u.a. dazu da Scriptdateien dynamisch zu verändern z.B. je nach Platform. Sie Starten immer mit einer # (Raute) und sind im Grunde identisch zu C/C++.

    Anweisung Beschreibung Beispiel
    #include Bindet andere Script dateien ein (werden einfach eingefügt an dieser Stelle).
    Mit $CurrentDir: kann der Pfad der Spielinstallation eingefügt werden. Wichtig ist das der \ (Backslash) hier ein Kontrollzeichen im String ist und \\ dafür verwendet werden muss.
    #include "$CurrentDir:Missions\\dayzOffline.ChernarusPlus\\ref.c"
    #ifdef Zweig für ist Definiert.
    #ifdef PLATFORM_CONSOLE
    #ifndef Zweig für ist nicht Definiert.
    #ifndef PLATFORM_WINDOWS
    #else Else zweig.
    #else
    #endif Ende des Zweiges.
    #endif

    Defines (unvollständig)

    Name Zweck
    PLATFORM_WINDOWS Spiel läuft auf Windows.
    GAME_TEMPLATE Unklar.
    PLATFORM_CONSOLE Läuft auf Konsole.
    PLATFORM_XBOX Läuft auf XBOX
    PLATFORM_PS4 Läuft auf PS4
    NO_GUI Unklar.
    DEVELOPER Wahrscheinlich debug modus.
    SERVER_FOR_CONSOLE Läuft auf Konsolenserver.
    BOT Unklar.
    DAYZ_CREATURE_DEBUG_SHADOW Unklar.
    BULDOZER Wahrscheinlich in Buldozer gestartet.
    NEW_UI Unklar.
    DOXYGEN Wahrscheinlich Info für Doxygen.


    In API zurechtfinden


    Die API ist nicht Dokumentiert und meist muss man selbst die Scripts durchsuchen. Dafür empfiehlt es sich die scripts.pbo im Dayz Verzeichnis->dta mit dem PBO Manager zu entpacken. Diesen Ordner kann dann mit Notepad++ über Suchen->In Datein Suchen durchsuchen. Das ist ganz hilfreich um Beispiele zur Anwendung verschiedener Klassen/Funktionen zu finden. Lystics API Referenz ist auch hilfreich um Informationen zu finden. Dafür einfach im Suchfeld ungefähr eingeben was man will und meist findet man dann auch was man sucht.

    Mods von anderen Moddern können auch mit dem PBO Manager entpackt werden und deren Quelltext damit eingesehen.

    Der oben genannte DayZ Modder Discord kann auch nach Stichworten durchsucht werden und im Notfall kann man dort auch mal fragen meist findet man dort was man will.

    16 Mal editiert, zuletzt von smpk () aus folgendem Grund: Korrekturen credits

  • smpk

    Hat den Titel des Themas von „DayZ Standalone Scripting - Enforce Scripting“ zu „[Guide] DayZ Standalone Scripting - Enforce Scripting“ geändert.