Enforce Script Syntax – DayZ
Lou Montana (talk | contribs) m (Fix link) |
Lou Montana (talk | contribs) m (Some wiki formatting) |
||
| (One intermediate revision by the same user not shown) | |||
| Line 1: | Line 1: | ||
{{TOC|side}} | {{TOC|side}} | ||
'''Enforce Script''' is the language that is used by the [[Enfusion]] engine first introduced in [[:Category:DayZ|DayZ]] Standalone. It is | '''Enforce Script''' is the language that is used by the [[Enfusion]] engine first introduced in [[:Category:DayZ|DayZ]] Standalone. | ||
It is an Object-Oriented Scripting Language that works with objects and classes and is similar to the C# programming language. | |||
{{Feature|armaR|For {{armaR}}, see {{GameCategory|armaR|Modding|Scripting|Tutorials| | {{Feature|armaR|For {{armaR}}, see {{GameCategory|armaR|Modding|Scripting|Tutorials||text={{armaR}} Scripting Tutorials}} starting with {{Link|Arma Reforger:From SQF to Enforce Script}}.}} | ||
| Line 12: | Line 13: | ||
Code block is bordered by curly brackets and defines a scope. Variables defined inside scope are accessible only from inside of it. | Code block is bordered by curly brackets and defines a scope. Variables defined inside scope are accessible only from inside of it. | ||
Scope example | Scope example: | ||
<enforce> | <enforce> | ||
void Hello() | void Hello() | ||
| Line 25: | Line 26: | ||
</enforce> | </enforce> | ||
Nested scope | Nested scope: | ||
<enforce> | <enforce> | ||
void World() | void World() | ||
| Line 39: | Line 40: | ||
</enforce> | </enforce> | ||
Scope statements | Scope statements: | ||
<enforce> | <enforce> | ||
void Hello() | void Hello() | ||
| Line 51: | Line 52: | ||
{ | { | ||
// This is code block for the else branch | // This is code block for the else branch | ||
int x = 23; // This will currently throw a multiple declaration error | int x = 23; // This will currently throw a multiple declaration error | ||
// while this behaviour changed for later titles (e.g {{armaR}}), it might stay like this in DayZ. | |||
// To circumvent this, define the x above the if statement or use different variables. | |||
} | } | ||
} | } | ||
| Line 89: | Line 92: | ||
a = 5; | a = 5; | ||
// | // initialise | ||
int b = 9; | int b = 9; | ||
} | } | ||
| Line 159: | Line 162: | ||
return a + b; | return a + b; | ||
} | } | ||
void PrintCount(TStringArray stringArray) // function with one "TStringArray" object parameter which returns no value | void PrintCount(TStringArray stringArray) // function with one "TStringArray" object parameter which returns no value | ||
| Line 175: | Line 177: | ||
<enforce> | <enforce> | ||
/* | /* | ||
Multi | Multi | ||
line | line | ||
comment | comment | ||
*/ | */ | ||
| Line 195: | Line 197: | ||
void Test() | void Test() | ||
{ | { | ||
int a = MONTHS_COUNT; // ok | int a = MONTHS_COUNT; // ok | ||
MONTHS_COUNT = 7; // err! you cannot change constant! | MONTHS_COUNT = 7; // err! you cannot change a '''constant'''! | ||
} | } | ||
</enforce> | </enforce> | ||
| Line 208: | Line 210: | ||
{| class="wikitable" | {| class="wikitable" | ||
! Operation !! Symbol | ! Operation !! Symbol | ||
|- | |- | ||
| Line 225: | Line 226: | ||
{| class="wikitable" | {| class="wikitable" | ||
! Operation !! Symbol | ! Operation !! Symbol | ||
|- | |- | ||
| Line 254: | Line 254: | ||
{| class="wikitable" | {| class="wikitable" | ||
! Operation !! Symbol | ! Operation !! Symbol | ||
|- | |- | ||
| Line 273: | Line 272: | ||
{| class="wikitable" | {| class="wikitable" | ||
! Category !! Operator(s) | ! Category !! Operator(s) | ||
|- | |- | ||
| Line 294: | Line 292: | ||
==== Index Operator ==== | ==== Index Operator ==== | ||
Overloading the index operator can be achieved through the {{hl|Set}} and {{hl|Get}} methods. You can have any number of overloads as long as there is no ambiguity with the types. | Overloading the index operator can be achieved through the {{hl|Set}} and {{hl|Get}} methods. | ||
You can have any number of overloads as long as there is no ambiguity with the types. | |||
<enforce> | <enforce> | ||
| Line 318: | Line 317: | ||
'''Note:''' If you want to assign a pre-parsed vector with <enforce inline>instance[index] = "1 1 1"</enforce> the setter needs to accept a {{hl|string}} as {{hl|_value}} parameter and convert it explicitly using <enforce inline>_value.ToVector()</enforce> before an assignment. | '''Note:''' If you want to assign a pre-parsed vector with <enforce inline>instance[index] = "1 1 1"</enforce> the setter needs to accept a {{hl|string}} as {{hl|_value}} parameter and convert it explicitly using <enforce inline>_value.ToVector()</enforce> before an assignment. | ||
== Keywords == | == Keywords == | ||
| Line 324: | Line 324: | ||
{| class="wikitable" | {| class="wikitable" | ||
! Keyword !! Description | ! Keyword !! Description | ||
|- | |- | ||
| Line 343: | Line 342: | ||
{| class="wikitable" | {| class="wikitable" | ||
! Keyword !! Description | ! Keyword !! Description | ||
|- | |- | ||
| Line 368: | Line 366: | ||
{| class="wikitable" | {| class="wikitable" | ||
! Keyword !! Description | ! Keyword !! Description | ||
|- | |- | ||
| Line 377: | Line 374: | ||
{| class="wikitable" | {| class="wikitable" | ||
! Keyword !! Description | ! Keyword !! Description | ||
|- | |- | ||
| Line 407: | Line 403: | ||
{| class="wikitable" | {| class="wikitable" | ||
! Type name !! Range !! Default Value | ! Type name !! Range !! Default Value | ||
|- | |- | ||
| Line 416: | Line 411: | ||
| bool || true or false || false | | bool || true or false || false | ||
|- | |- | ||
| string || | | string || {{n/a}} || "" (empty string) | ||
|- | |- | ||
| vector || see float || | | vector || see float || { 0.0, 0.0, 0.0 } | ||
|- | |- | ||
| void || | | void || {{n/a}} || {{n/a}} | ||
|- | |- | ||
| Class || | | Class || {{n/a}} || null | ||
|- | |- | ||
| typename || | | typename || {{n/a}} || null | ||
|} | |} | ||
| Line 431: | Line 426: | ||
* Strings are passed by value, like primitive types | * Strings are passed by value, like primitive types | ||
* Can be concatenated by + operator | * Can be concatenated by + operator | ||
* Strings are | * Strings are initialised and destroyed automatically | ||
* Strings can contain | * Strings can contain standardised escape sequences; these are supported: {{hl|\n}} {{hl|\r}} {{hl|\t}} {{hl|\\}} {{hl|\"}} | ||
<enforce> | <enforce> | ||
| Line 450: | Line 445: | ||
* Vectors are passed by value, like primitive types | * Vectors are passed by value, like primitive types | ||
* Vector values are accessible by [ | * Vector values are accessible by {{hl|[]}} operator, like static arrays | ||
* Vectors are | * Vectors are initialised and destroyed automatically | ||
* Vector can be | * Vector can be initialised by three numeric values in double quotes e.g. "10 22 13" | ||
<enforce> | <enforce> | ||
void Method() | void Method() | ||
{ | { | ||
vector up = "0 1 0"; // | vector up = "0 1 0"; // initialised by values <0, 1, 0> | ||
vector down; // vector "down" has now default value <0, 0, 0> | vector down; // vector "down" has now default value <0, 0, 0> | ||
down = up; | down = up; | ||
down[1] = -1; // change Y value of vector "down" | down[1] = -1; // change Y value of vector "down" | ||
Print(up); // prints <0, 1, 0> | Print(up); // prints <0, 1, 0> | ||
Print(down); // prints <0, -1, 0> | Print(down); // prints <0, -1, 0> | ||
} | } | ||
</enforce> | </enforce> | ||
| Line 481: | Line 476: | ||
Print("Hello world"); | Print("Hello world"); | ||
} | } | ||
void MethodA() | void MethodA() | ||
{ | { | ||
MyClass o; // o == null | MyClass o; // o == null | ||
o = new MyClass; // creates a new instance of MyClass class | o = new MyClass; // creates a new instance of MyClass class | ||
o.Say(); // calls Say() function on instance 'o' | o.Say(); // calls Say() function on instance 'o' | ||
delete o; // destroys 'o' instance | delete o; // destroys 'o' instance | ||
} | } | ||
| Line 493: | Line 488: | ||
{ | { | ||
// if you type autoptr into declaration, compiler automatically does "delete o;" when the scope is terminated | // if you type autoptr into declaration, compiler automatically does "delete o;" when the scope is terminated | ||
autoptr MyClass o; // o == null | autoptr MyClass o; // o == null | ||
o = new MyClass; // creates a new instance of MyClass class | o = new MyClass; // creates a new instance of MyClass class | ||
o.Say(); // calls Say() function on instance 'o' | o.Say(); // calls Say() function on instance 'o' | ||
} | } | ||
| Line 528: | Line 523: | ||
o = new MyClass; | o = new MyClass; | ||
SafeMethod(o); // ok | SafeMethod(o); // ok | ||
UnsafeMethod(o); // ok | UnsafeMethod(o); // ok | ||
SafeMethod(null); // ok | SafeMethod(null); // ok | ||
UnsafeMethod(null); // Crash! Object 'o' is not initialised and UnsafeMethod accessed it! | UnsafeMethod(null); // Crash! Object 'o' is not initialised and UnsafeMethod accessed it! | ||
} | } | ||
} | } | ||
</enforce> | </enforce> | ||
Example of '''this''' | Example of '''this''' and '''super''': | ||
<enforce> | <enforce> | ||
| Line 546: | Line 541: | ||
Print("AnimalClass.Hello()"); | Print("AnimalClass.Hello()"); | ||
} | } | ||
} | } | ||
class HoneyBadger: AnimalClass | class HoneyBadger: AnimalClass | ||
| Line 579: | Line 574: | ||
Beta, // has value 6 | Beta, // has value 6 | ||
Gamma // has value 7 | Gamma // has value 7 | ||
} | } | ||
enum MyEnum: MyEnumBase | enum MyEnum: MyEnumBase | ||
{ | { | ||
| Line 586: | Line 582: | ||
Green = 20, // has value 20 | Green = 20, // has value 20 | ||
Orange // has value 21 | Orange // has value 21 | ||
} | } | ||
void Test() | void Test() | ||
| Line 612: | Line 608: | ||
class Item<Class T> | class Item<Class T> | ||
{ | { | ||
T | T m_Data; | ||
void Item(T data) | void Item(T data) | ||
{ | { | ||
m_Data = data; | |||
} | } | ||
void SetData(T data) | void SetData(T data) | ||
{ | { | ||
m_Data = data; | |||
} | } | ||
T GetData() | T GetData() | ||
{ | { | ||
return | return m_Data; | ||
} | } | ||
void PrintData() | void PrintData() | ||
{ | { | ||
Print( | Print(m_Data); | ||
} | } | ||
} | } | ||
void Method() | void Method() | ||
| Line 636: | Line 632: | ||
Item<int> int_item = new Item<int>(72); // template class Item declared with type "int". In Item<int> class, all "T"s are substituted with 'int' | Item<int> int_item = new Item<int>(72); // template class Item declared with type "int". In Item<int> class, all "T"s are substituted with 'int' | ||
string_item.PrintData(); // prints " | string_item.PrintData(); // prints "m_Data = 'Hello!'" | ||
int_item.PrintData(); // prints " | int_item.PrintData(); // prints "m_Data = 72" | ||
} | } | ||
</enforce> | </enforce> | ||
| Line 646: | Line 642: | ||
* Arrays are indexed from 0 | * Arrays are indexed from 0 | ||
* Arrays are passed by reference, like objects | * Arrays are passed by reference, like objects | ||
* Static arrays are | * Static arrays are initialised and destroyed automatically | ||
* Size of static arrays can be set only during compilation time | * Size of static arrays can be set only during compilation time | ||
* Elements are accessible by array access operator [ ] | * Elements are accessible by array access operator {{hl|[]}} | ||
<enforce> | <enforce> | ||
| Line 686: | Line 682: | ||
* Dynamic arrays are provided through 'array' template class | * Dynamic arrays are provided through 'array' template class | ||
* Dynamic arrays are passed by reference | * Dynamic arrays are passed by reference | ||
* Dynamic Arrays are objects and therefore they must be created and destroyed like objects, so | * Dynamic Arrays are objects and therefore they must be created and destroyed like objects, so do not forget to use "autoptr" or delete operator! | ||
* Elements are accessible by "Get" function or by array access operator [ ] | * Elements are accessible by "Get" function or by array access operator {{hl|[]}} | ||
* There are already defined typedefs for primitive type arrays: | * There are already defined typedefs for primitive type arrays: | ||
** array<string> = TStringArray | ** array<string> = TStringArray | ||
| Line 705: | Line 701: | ||
string name; | string name; | ||
name = nameArray.Get(1); // gets second element of array "nameArray" | name = nameArray.Get(1); // gets second element of array "nameArray" | ||
Print(name); // prints "name = 'Michal'" | Print(name); // prints "name = 'Michal'" | ||
nameArray.Remove(1); // second element is removed | nameArray.Remove(1); // second element is removed | ||
name = nameArray.Get(1); // gets second element of array "nameArray" | name = nameArray.Get(1); // gets second element of array "nameArray" | ||
Print(name); // prints "name = 'David'" | Print(name); // prints "name = 'David'" | ||
int nameCount = nameArray.Count(); // gets elements count of array "nameArray" | int nameCount = nameArray.Count(); // gets elements count of array "nameArray" | ||
Print(nameCount); // prints "nameCount = 2" | Print(nameCount); // prints "nameCount = 2" | ||
} | } | ||
</enforce> | </enforce> | ||
| Line 726: | Line 722: | ||
void Method() | void Method() | ||
{ | { | ||
auto variableName = 1; // variableName will be of type | auto variable1 = 1; // variableName will be of type integer | ||
auto variablePi = 3.14; // variablePi will be of type float | auto variable2 = 1.0; // variableName will be of type float | ||
auto variablePi = 3.14; // variablePi will be of type float | |||
auto variableInst = new MyCustomClass(); // variableInst will be of type MyCustomClass | auto variableInst = new MyCustomClass(); // variableInst will be of type MyCustomClass | ||
} | } | ||
| Line 788: | Line 785: | ||
int a = 2; | int a = 2; | ||
switch(a) | switch (a) | ||
{ | { | ||
case 1: | case 1: | ||
| Line 809: | Line 806: | ||
int quality = MEDIUM; | int quality = MEDIUM; | ||
switch(quality) | switch (quality) | ||
{ | { | ||
case LOW: | case LOW: | ||
| Line 827: | Line 824: | ||
// using switch with strings | // using switch with strings | ||
string name = "peter"; | string name = "peter"; | ||
switch(name) | switch (name) | ||
{ | { | ||
case "john": | case "john": | ||
| Line 884: | Line 881: | ||
void TestFn() | void TestFn() | ||
{ | { | ||
int pole1[] = {7,3,6,8}; | int pole1[] = { 7, 3, 6, 8 }; | ||
array<string> pole2 = {"a", "b", "c"}; | array<string> pole2 = { "a", "b", "c" }; | ||
auto mapa = new map<string, int>(); | auto mapa = new map<string, int>(); | ||
mapa["jan"] = 1; | mapa["jan"] = 1; | ||
| Line 892: | Line 889: | ||
// simple foreach iteration | // simple foreach iteration | ||
foreach(int v: pole1) // prints: '7', '3', '6', '8' | foreach (int v: pole1) // prints: '7', '3', '6', '8' | ||
{ | { | ||
Print(v); | Print(v); | ||
| Line 898: | Line 895: | ||
// foreach iteration with key (if you iterate trough array, key is filled with array index) | // foreach iteration with key (if you iterate trough array, key is filled with array index) | ||
foreach(int i, string j: pole2) // prints: 'pole[0] = a', 'pole[1] = b', 'pole[2] = c' | foreach (int i, string j : pole2) // prints: 'pole[0] = a', 'pole[1] = b', 'pole[2] = c' | ||
{ | { | ||
Print("pole[" + i + "] = " + j); | Print("pole[" + i + "] = " + j); | ||
| Line 904: | Line 901: | ||
// map iteration, with key and value | // map iteration, with key and value | ||
foreach(auto k, auto a: mapa) // prints: 'mapa[jan] = 1', 'mapa[feb] = 2', 'mapa[mar] = 3' | foreach (auto k, auto a : mapa) // prints: 'mapa[jan] = 1', 'mapa[feb] = 2', 'mapa[mar] = 3' | ||
{ | { | ||
Print("mapa[" + k + "] = " + a); | Print("mapa[" + k + "] = " + a); | ||
| Line 910: | Line 907: | ||
// map iteration with just value | // map iteration with just value | ||
foreach(auto b: mapa) // prints: '1', '2', '3' | foreach (auto b : mapa) // prints: '1', '2', '3' | ||
{ | { | ||
Print(b); | Print(b); | ||
| Line 943: | Line 940: | ||
* Use override keyword for overriding base class methods(to avoid accidental overriding) | * Use override keyword for overriding base class methods(to avoid accidental overriding) | ||
* Class can inherit from one parent class using keyword 'extends' | * Class can inherit from one parent class using keyword 'extends' | ||
* Objects are not | * Objects are not initialised and destroyed automatically, use 'new' and 'delete' (or 'autoptr' feature) | ||
* Class variables are cleared to default values upon creation | * Class variables are cleared to default values upon creation | ||
| Line 954: | Line 951: | ||
{ | { | ||
} | } | ||
} | } | ||
class Dog: AnimalClass | class Dog: AnimalClass | ||
| Line 967: | Line 964: | ||
// do something | // do something | ||
} | } | ||
} | } | ||
class Cat: AnimalClass | class Cat: AnimalClass | ||
| Line 980: | Line 977: | ||
// do something | // do something | ||
} | } | ||
} | } | ||
void LetAnimalMakeSound(AnimalClass pet) | void LetAnimalMakeSound(AnimalClass pet) | ||
| Line 995: | Line 992: | ||
Dog pluto = new Dog; | Dog pluto = new Dog; | ||
nyan.MakeSound(); // prints "Meow!" | nyan.MakeSound(); // prints "Meow!" | ||
pluto.MakeSound(); // prints "Wof! Wof!" | pluto.MakeSound(); // prints "Wof! Wof!" | ||
LetAnimalMakeSound(nyan); // prints "Meow!" | LetAnimalMakeSound(nyan); // prints "Meow!" | ||
LetAnimalMakeSound(pluto); // prints "Wof! Wof!" | LetAnimalMakeSound(pluto); // prints "Wof! Wof!" | ||
} | } | ||
</enforce> | </enforce> | ||
=== Constructor | === Constructor and Destructor === | ||
Constructor and destructor are special member functions | Constructor and destructor are special member functions | ||
* Every class can have one constructor and one destructor | * Every class can have one constructor and one destructor | ||
* Constructor is function called when object is created(by 'new') and has same name as class ( e.g. 'void ClassName()' ) | * Constructor is function called when object is created (by 'new') and has same name as class (e.g. 'void ClassName()') | ||
* Destructor is called when object is going to be destroyed (by 'delete'/'autoptr') and has same name as class with tilde character at beginning ( e.g. 'void ~ClassName()' ) | * Destructor is called when object is going to be destroyed (by 'delete'/'autoptr') and has same name as class with tilde character at beginning (e.g. 'void ~ClassName()') | ||
* Constructor can have initialization parameters, destructor cannot have any parameters | * Constructor can have initialization parameters, destructor cannot have any parameters | ||
* Both constructor and destructor do not return any value (returns void) | * Both constructor and destructor do not return any value (returns void) | ||
| Line 1,027: | Line 1,024: | ||
Print("Instance of MyClassA is destroyed!"); | Print("Instance of MyClassA is destroyed!"); | ||
} | } | ||
} | } | ||
class MyClassB | class MyClassB | ||
| Line 1,043: | Line 1,040: | ||
Print("Instance of MyClassB is destroyed!"); | Print("Instance of MyClassB is destroyed!"); | ||
} | } | ||
} | } | ||
void Method() | void Method() | ||
| Line 1,082: | Line 1,079: | ||
if (a2) a2.Hello(); // a2 is still pointing to deleted instance of A so condition pass. This line cause crash! | if (a2) a2.Hello(); // a2 is still pointing to deleted instance of A so condition pass. This line cause crash! | ||
} | } | ||
// with Managed | // with Managed | ||
class B: Managed | class B: Managed | ||
| Line 1,126: | Line 1,124: | ||
{ | { | ||
ref Child m_child; // putting 'ref' keyword, we give a hint to compiler, that this is strong reference. | ref Child m_child; // putting 'ref' keyword, we give a hint to compiler, that this is strong reference. | ||
} | } | ||
class Child | class Child | ||
{ | { | ||
Parent m_parent; // this reference is weak reference (there is no 'ref') | Parent m_parent; // this reference is weak reference (there is no 'ref') | ||
} | } | ||
void main() | void main() | ||
| Line 1,165: | Line 1,163: | ||
class MyClassA | class MyClassA | ||
{ | { | ||
void MyClassA() { Print("MyClassA()"); } // constructor | void MyClassA() { Print("MyClassA()"); } // constructor | ||
void ~MyClassA() { Print("~MyClassA()"); } // destructor | void ~MyClassA() { Print("~MyClassA()"); } // destructor | ||
} | } | ||
void function1() | void function1() | ||
| Line 1,221: | Line 1,219: | ||
{ | { | ||
MyClassA a = CreateMyObj(); // object is created inside CreateMyObj function 'MyClassA()' | MyClassA a = CreateMyObj(); // object is created inside CreateMyObj function 'MyClassA()' | ||
// any code here | // any code here | ||
| Line 1,248: | Line 1,247: | ||
{ | { | ||
//! weak reference to object | //! weak reference to object | ||
MyClassA | MyClassA m_A; | ||
//! strong reference to object | //! strong reference to object | ||
ref MyClassA | ref MyClassA m_B; | ||
//! strong reference to dynami array(dynamic array is object itself) of weak references | //! strong reference to dynami array(dynamic array is object itself) of weak references | ||
ref array<MyClassA> | ref array<MyClassA> m_C; | ||
//! strong reference to dynamic array of strong references | //! strong reference to dynamic array of strong references | ||
ref array<ref MyClassA> | ref array<ref MyClassA> m_D; | ||
//! static array of strong references | //! static array of strong references | ||
ref MyClassA | ref MyClassA m_E[10]; | ||
} | } | ||
</enforce> | </enforce> | ||
| Line 1,272: | Line 1,271: | ||
* Modded class behaves like class inherited from original class (you can use super to access original class) | * Modded class behaves like class inherited from original class (you can use super to access original class) | ||
* When modded class is declared, it will be | * When modded class is declared, it will be instanciated instead of the original class everywhere in the script | ||
* When several modded classes are modding the same vanilla class, the next modded class will instead inherit of the latest modded class, which enables mod compatibility | * When several modded classes are modding the same vanilla class, the next modded class will instead inherit of the latest modded class, which enables mod compatibility | ||
| Line 1,283: | Line 1,282: | ||
Print("Hello original"); | Print("Hello original"); | ||
} | } | ||
} | } | ||
// First mod | // First mod | ||
| Line 1,293: | Line 1,292: | ||
super.Say(); | super.Say(); | ||
} | } | ||
} | } | ||
// Second mod | // Second mod | ||
| Line 1,303: | Line 1,302: | ||
super.Say(); | super.Say(); | ||
} | } | ||
} | } | ||
void Test() | void Test() | ||
{ | { | ||
ModMe a = new ModMe(); // modded class ModMe is | ModMe a = new ModMe(); // modded class ModMe is instantiated | ||
a.Say(); // prints | a.Say(); // prints "Hello modded Two", "Hello modded One" and "Hello original" | ||
} | } | ||
</enforce> | </enforce> | ||
| Line 1,337: | Line 1,336: | ||
void TestPrint() | void TestPrint() | ||
{ | { | ||
Print(TestConst.CONST_BASE); // 1 | Print(TestConst.CONST_BASE); // 1 | ||
Print(TestConst.CONST_TEST); // 2 | Print(TestConst.CONST_TEST); // 2 | ||
Print(TestConst.CONST_MOD); | Print(TestConst.CONST_MOD); // 3 | ||
} | } | ||
</enforce> | </enforce> | ||
| Line 1,345: | Line 1,344: | ||
=== Modded private members === | === Modded private members === | ||
{{Feature|informative|Even though modded class behaves similar to an inherited one, it can still access private members of the vanilla class.}} | |||
<enforce> | <enforce> | ||
| Line 1,351: | Line 1,350: | ||
class VanillaClass | class VanillaClass | ||
{ | { | ||
private bool imPrivate = | private bool imPrivate = false; | ||
private void DoSomething() | private void DoSomething() | ||
| Line 1,358: | Line 1,357: | ||
} | } | ||
} | } | ||
// accesss | // accesss | ||
modded class VanillaClass | modded class VanillaClass | ||
{ | { | ||
void AccessPvt() | void AccessPvt() | ||
{ | { | ||
Print(imPrivate); | Print(imPrivate); | ||
DoSomething(); | DoSomething(); | ||
} | } | ||
} | } | ||
// override | // override | ||
modded class VanillaClass | modded class VanillaClass | ||
Latest revision as of 16:33, 25 October 2025
Enforce Script is the language that is used by the Enfusion engine first introduced in DayZ Standalone. It is an Object-Oriented Scripting Language that works with objects and classes and is similar to the C# programming language.
Basics
Code blocks
Code block is bordered by curly brackets and defines a scope. Variables defined inside scope are accessible only from inside of it.
Scope example:
Nested scope:
Scope statements:
Program structure
Enforce Script consists of classes and functions. All code must be declared inside a function.
Variables
Variables are defined by type and name.
Functions
Functions are basic feature of Enforce Script. Function declaration consist of return value type, function name and list of parameters.
- Functions can be declared in global scope or inside class declaration
- Function parameters are fixed and typed (cannot be changed during run-time, no variadic parameters)
- Functions can be overloaded
- Keyword 'out' before parameter declaration ensures, that the parameter is passed by reference (you can pass more than one value from a function this way, can be used only in native functions)
- Enforce Script supports default parameter
Comments
Constants
Constants are like variables but read only. They are declared by const keyword.
Operators
Operator Priority: Priority of operators is similar to C language, more info.
Arithmetic Operators
| Operation | Symbol |
|---|---|
| Add | + |
| Subtract | - |
| Multiply | * |
| Divide | |
| Modulo | % |
Assignments
| Operation | Symbol |
|---|---|
| Assign value to variable | = |
| Increment variable by value | += |
| Decrement variable by value | -= |
| Multiply variable by value | *= |
| Divide variable by value | |
| Bitwise-OR by value | |= |
| Bitwise-AND by value | &= |
| Left-shift variable by value | <<= |
| Right-shift variable by value | >>= |
| Increment variable by 1 | ++ |
| Decrement variable by 1 | -- |
Relational (conditional)
| Operation | Symbol |
|---|---|
| More than value | > |
| Less than value | < |
| More or equal to the value | >= |
| Less or equal to the value | <= |
| Equal | == |
| Not equal | != |
Others
| Category | Operator(s) |
|---|---|
| Logical | &&, || |
| Bitwise | &, |, ~, ^ |
| String | + |
| Shift | <<, >> |
| Assignment | = |
| Indexing | [ ] |
| Negation | ! |
Script Operator Overload
Index Operator
Overloading the index operator can be achieved through the Set and Get methods. You can have any number of overloads as long as there is no ambiguity with the types.
Note: If you want to assign a pre-parsed vector with instance[index] = "1 1 1" the setter needs to accept a string as _value parameter and convert it explicitly using _value.ToVector() before an assignment.
Keywords
Function/method modifiers
| Keyword | Description |
|---|---|
| private | The method can be called only from inside of the same class method |
| protected | The method can be called only from inside of class method or methods of its extended classes |
| static | The method can be called without object pointer, just by className.methodName() , only static members of the same class can be accessed from inside of static method |
| override | Compiler checks if is method present in base class and if method signature match |
| proto | Prototyping of internal function (C++ side) |
| native | Native call convention of internal function (C++ side) |
Variable modifiers
| Keyword | Description |
|---|---|
| private | Variable can be accessed only from inside of class methods. Mutually exclusive with "protected" |
| protected | Variable can be accessed only from inside of class methods or methods of its extended classes. Mutually exclusive with "private" |
| static | Variable can be accessed without object pointer, using className.variable |
| autoptr | Modifier for variables of class pointer type. Pointer target will be automatically destroyed upon end of variable lifetime (end of scope or deletion of class which contains it) |
| proto | Prototyping of internal function (C++ side) |
| ref | Variable is a strong reference |
| const | Constant, cannot be modified |
| out | Modifier for function parameters, variable will be changed by a function call |
| inout | Modifier for function parameters, variable will be used and then changed by a function call |
Class modifiers
| Keyword | Description |
|---|---|
| modded | Inheritance-like behaviour for modding |
Other Keywords
| Keyword | Description |
|---|---|
| new | Create new object instance |
| delete | Destroy object instance |
| class | Class declaration |
| extends | Class inheritence |
| typedef | Type definition |
| return | Terminates function & returns value (if specified) |
| null | null value |
| this | Address of the object, on which the member function is being called |
| super | Refers to the base class for the requested variable/function |
| thread | Declared before the function call, runs the function on a new thread |
Types
Primitive Types
| Type name | Range | Default Value |
|---|---|---|
| int | from −2,147,483,648 to +2,147,483,647 | 0 |
| float | from ±1.401298E−45 to ±3.402823E+38 | 0.0 |
| bool | true or false | false |
| string | N/A | "" (empty string) |
| vector | see float | { 0.0, 0.0, 0.0 } |
| void | N/A | N/A |
| Class | N/A | null |
| typename | N/A | null |
Strings
- Strings are passed by value, like primitive types
- Can be concatenated by + operator
- Strings are initialised and destroyed automatically
- Strings can contain standardised escape sequences; these are supported:
\n \r \t \ \ \"
Vectors
- Vectors are passed by value, like primitive types
- Vector values are accessible by [] operator, like static arrays
- Vectors are initialised and destroyed automatically
- Vector can be initialised by three numeric values in double quotes e.g. "10 22 13"
Objects
- Objects in enforce script are references and are passed by reference
- All member functions and variables are public by default. Use 'private' keyword to make them private
- 'autoptr' keyword before object variable declaration ensures that compiler automatically destroys the object when the scope is terminated (e.g. function call ends)
Example of this and super:
Enums
Enumerators are set of named constant identifiers.
- enums have int type
- enum item value can be assigned in definition, otherwise it is computed automatically (previous item value plus one)
- enum can inherit from another enum (item value continues from last parent item value)
- enum name used as type behaves like ordinary int (no enum value checking on assign)
Templates
Enforce Script has template feature similar to C++ Templates, which allows classes to operate with generic types.
- Generic type declaration is placed inside <, > (e.g. "class TemplateClass<class GenericType>" )operators after template class name identifier
- Enforce Script supports any number of generic types per template class
Arrays
Static Arrays
- Arrays are indexed from 0
- Arrays are passed by reference, like objects
- Static arrays are initialised and destroyed automatically
- Size of static arrays can be set only during compilation time
- Elements are accessible by array access operator []
Dynamic Arrays
- Dynamic arrays support change of size at runtime by inserting/removing array items
- Dynamic arrays are provided through 'array' template class
- Dynamic arrays are passed by reference
- Dynamic Arrays are objects and therefore they must be created and destroyed like objects, so do not forget to use "autoptr" or delete operator!
- Elements are accessible by "Get" function or by array access operator []
- There are already defined typedefs for primitive type arrays:
- array<string> = TStringArray
- array<float> = TFloatArray
- array<int> = TIntArray
- array<class> = TClassArray
- array<vector> = TVectorArray
Automatic type detection
The variable type will be detected automatically at compile time when the keyword auto is used as placeholder.
Control Structures
Control structures work very similar to C# or C/C++ languages.
Conditional structures
If statement
Switch statement
Switch statement supports switching by numbers, constants and strings.
Iteration structures
For
The for loop consists of three parts: declaration, condition and increment.
Foreach
Simpler and more comfortable version of for loop.
While
Object-oriented programming specifics
- All member functions and variables are public by default. You can use 'private' or 'protected' keyword to control access
- Class member functions are virtual and can be overridden by child class
- Use override keyword for overriding base class methods(to avoid accidental overriding)
- Class can inherit from one parent class using keyword 'extends'
- Objects are not initialised and destroyed automatically, use 'new' and 'delete' (or 'autoptr' feature)
- Class variables are cleared to default values upon creation
Inheritance
Constructor and Destructor
Constructor and destructor are special member functions
- Every class can have one constructor and one destructor
- Constructor is function called when object is created (by 'new') and has same name as class (e.g. 'void ClassName()')
- Destructor is called when object is going to be destroyed (by 'delete'/'autoptr') and has same name as class with tilde character at beginning (e.g. 'void ~ClassName()')
- Constructor can have initialization parameters, destructor cannot have any parameters
- Both constructor and destructor do not return any value (returns void)
- Constructor and destructor are called even when object is created or destroyed from C++
- When constructor doesn't have any parameters omit brackets while using 'new' operator
Managed class & pointer safety
- Since script does not do garbage collecting automatically, all plain pointers are considered unsafe
- All classes inherited from Managed class work soft links instead of plain pointers. Soft link is weak reference that does not keep the object alive and is zeroed upon their destruction so they are never invalid
- All objects available in game module should be Managed, so they should be using soft links by default (they all inherits from Managed class)
Automatic Reference Counting
Enforce Script has support of automatic reference counting. In a spirit of flexibility, you can choose if your class should or shouldn't be managed, by choosing to inherit from Managed class.
Simple "C++" like classes remains an option for high performance, but less secure scripts
- objects referenced by plain C pointers
- no automatic memory management, owner must delete them
For common gameplay scripts/mods/etc there are managed objects, which are
- slightly slower (due indirect weak pointer object accessing)
- internally ref-counted and automatically deleted when not needed
- objects referenced by weak pointers (pointer is always valid or NULL, never points to deleted memory etc.)
Strong and weak references
- strong reference increases reference count - holds object alive
- weak reference just pointing to an object, but doesn't increase reference count
In the code above at the end of function main, object 'a' has zero strong references thus is deleted, destructor releases m_child, and so the object 'b' also has zero strong references and it is deleted.
Usage of ref keyword
In the Enforce script by default all variables are weak references, ref keyword is marking that variable is strong reference. In some special cases, variables are strong references by default
- local variables inside functions
- function arguments
- function return value
and are released after their scope ends.
While an object is stored in at least one strong reference, it's being kept alive. When the last strong reference is destroyed or overwritten, the object is destroyed and all other (only weak refs left) references are set to NULL. When an object is deleted manually by delete command (e.g., 'delete a;'), it is deleted immediately ignoring reference count, and all references (weak and strong) are set to NULL.
Optimal usage of references in Enforce script is to have exactly one strong reference per object, placed in "owner" object who creates it. This way of usage ensures
- no cyclic references
- proper order of object destruction - object is destroyed when its "creator" is destroyed
Examples:
Modding
Modded class
Modded class is used to inject inherited class into class hierarchy without modifying other scripts, which is required for proper modding:
- Modded class behaves like class inherited from original class (you can use super to access original class)
- When modded class is declared, it will be instanciated instead of the original class everywhere in the script
- When several modded classes are modding the same vanilla class, the next modded class will instead inherit of the latest modded class, which enables mod compatibility
Modded constants
- Constants can be overridden on compilation by the the last loaded mod (be mindful of the mod load order)
- Allows multiple mods to change different constants in a single class