Enforce Script Syntax – DayZ
Jacob Mango (talk | contribs) m (→Automatic type detection: Missing semi colon in code block) |
(Script Overriding changed to Script Operator Overload) |
||
(27 intermediate revisions by 5 users not shown) | |||
Line 1: | Line 1: | ||
{{ | {{TOC|side}} | ||
'''Enforce Script''' is the language that is used by the Enfusion engine first introduced in [[DayZ]] Standalone. It is a Object-Oriented Scripting Language (OOP) that works with objects and classes and is similar to C# programming language. | '''Enforce Script''' is the language that is used by the [[Enfusion]] engine first introduced in [[:Category:DayZ|DayZ]] Standalone. It is a Object-Oriented Scripting Language (OOP) that works with objects and classes and is similar to C# programming language. | ||
{{Feature|armaR|For {{armaR}}, see {{GameCategory|armaR|Modding|Tutorials|Scripting|link=y|text={{armaR}} Scripting Tutorials}} starting with [[Arma Reforger:From SQF to Enforce Script]].}} | |||
Line 10: | Line 13: | ||
Scope example | Scope example | ||
< | <enforce> | ||
void Hello() | void Hello() | ||
{ | { | ||
Line 20: | Line 23: | ||
int x = 23; // Different x not related to the first one | int x = 23; // Different x not related to the first one | ||
} | } | ||
</ | </enforce> | ||
Nested scope | Nested scope | ||
< | <enforce> | ||
void World() | void World() | ||
{ | { | ||
Line 34: | Line 37: | ||
} | } | ||
} | } | ||
</ | </enforce> | ||
Scope statements | Scope statements | ||
< | <enforce> | ||
void Hello() | void Hello() | ||
{ | { | ||
Line 48: | Line 51: | ||
{ | { | ||
// 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 - while this should change for future | int x = 23; // This will currently throw a multiple declaration error - while this should change for future enforce script iterations, it might stay like this in DayZ. To circumvent this, define the x above the if statement or use different variables. | ||
} | } | ||
} | } | ||
</ | </enforce> | ||
=== Program structure === | === Program structure === | ||
Enforce Script consists of classes and functions. All code must be declared inside a function. | |||
< | <enforce> | ||
class MyClass | class MyClass | ||
{ | { | ||
Line 72: | Line 75: | ||
Print("Hello World"); // this code will be never executed, and should be caught by compiler as unexpected statement | Print("Hello World"); // this code will be never executed, and should be caught by compiler as unexpected statement | ||
</ | </enforce> | ||
=== Variables === | === Variables === | ||
Variables are defined by type and name. | Variables are defined by type and name. | ||
< | <enforce> | ||
void Test() | void Test() | ||
{ | { | ||
Line 89: | Line 92: | ||
int b = 9; | int b = 9; | ||
} | } | ||
</ | </enforce> | ||
=== Functions === | === Functions === | ||
Functions are basic feature of | 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) | * 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) | * 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 | ||
< | <enforce> | ||
void MethodA() // function with no parameters and no return value | void MethodA() // function with no parameters and no return value | ||
{ | { | ||
Line 160: | Line 163: | ||
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 | ||
{ | { | ||
if (!stringArray) | if (!stringArray) // check if stringArray is not null | ||
return; | |||
int count = stringArray.Count(); | int count = stringArray.Count(); | ||
Print(count); | Print(count); | ||
} | } | ||
</ | </enforce> | ||
=== Comments === | === Comments === | ||
< | <enforce> | ||
/* | /* | ||
Multi | Multi | ||
Line 180: | Line 184: | ||
Print("Hello"); // single line comment | Print("Hello"); // single line comment | ||
} | } | ||
</ | </enforce> | ||
=== Constants === | === Constants === | ||
Line 186: | Line 190: | ||
Constants are like variables but read only. They are declared by const keyword. | Constants are like variables but read only. They are declared by const keyword. | ||
< | <enforce> | ||
const int MONTHS_COUNT = 12; | const int MONTHS_COUNT = 12; | ||
Line 194: | Line 198: | ||
MONTHS_COUNT = 7; // err! you cannot change constant! | MONTHS_COUNT = 7; // err! you cannot change constant! | ||
} | } | ||
</ | </enforce> | ||
== Operators == | == Operators == | ||
'''Operator Priority''': Priority of operators is similar to C language, | '''Operator Priority''': Priority of operators is similar to C language, {{Link|https://en.wikipedia.org/wiki/Operators_in_C_and_C%2B%2B#Operator_precedence|more info}}. | ||
=== Arithmetic Operators === | === Arithmetic Operators === | ||
Line 207: | Line 211: | ||
! Operation !! Symbol | ! Operation !! Symbol | ||
|- | |- | ||
| Add || {{ | | Add || {{hl|+}} | ||
|- | |- | ||
| Subtract || {{ | | Subtract || {{hl|-}} | ||
|- | |- | ||
| Multiply || {{ | | Multiply || {{hl|*}} | ||
|- | |- | ||
| Divide || {{ | | Divide || {{hl|/}} | ||
|- | |- | ||
| Modulo || {{ | | Modulo || {{hl|%}} | ||
|} | |} | ||
=== Assignments === | === Assignments === | ||
Line 225: | Line 228: | ||
! Operation !! Symbol | ! Operation !! Symbol | ||
|- | |- | ||
| Assign value to variable || {{ | | Assign value to variable || {{hl|{{=}}}} | ||
|- | |- | ||
| Increment variable by value || {{ | | Increment variable by value || {{hl|+{{=}}}} | ||
|- | |- | ||
| Decrement variable by value || {{ | | Decrement variable by value || {{hl|-{{=}}}} | ||
|- | |- | ||
| Multiply variable by value || {{ | | Multiply variable by value || {{hl|*{{=}}}} | ||
|- | |- | ||
| Divide variable by value || {{ | | Divide variable by value || {{hl|/{{=}}}} | ||
|- | |- | ||
| | | Bitwise-OR by value || {{hl|<nowiki>|</nowiki>{{=}}}} | ||
|- | |- | ||
| Decrement variable by 1 || {{ | | Bitwise-AND by value || {{hl|&{{=}}}} | ||
|- | |||
| Left-shift variable by value || {{hl|<<{{=}}}} | |||
|- | |||
| Right-shift variable by value || {{hl|>>{{=}}}} | |||
|- | |||
| Increment variable by 1 || {{hl|++}} | |||
|- | |||
| Decrement variable by 1 || {{hl|--}} | |||
|} | |} | ||
Line 246: | Line 257: | ||
! Operation !! Symbol | ! Operation !! Symbol | ||
|- | |- | ||
| More than value || {{ | | More than value || {{hl|>}} | ||
|- | |- | ||
| Less than value || {{ | | Less than value || {{hl|<}} | ||
|- | |- | ||
| More or equal to the value || {{ | | More or equal to the value || {{hl|>{{=}}}} | ||
|- | |- | ||
| Less or equal to the value || {{ | | Less or equal to the value || {{hl|<{{=}}}} | ||
|- | |- | ||
| Equal || {{ | | Equal || {{hl|{{=}}{{=}}}} | ||
|- | |- | ||
| Not equal || {{ | | Not equal || {{hl|!{{=}}}} | ||
|} | |} | ||
Line 265: | Line 276: | ||
! Category !! Operator(s) | ! Category !! Operator(s) | ||
|- | |- | ||
| Logical || {{ | | Logical || {{hl|<nowiki>&&</nowiki>}}, {{hl|<nowiki>||</nowiki>}} | ||
|- | |- | ||
| Bitwise || {{ | | Bitwise || {{hl|<nowiki>&</nowiki>}}, {{hl|<nowiki>|</nowiki>}}, {{hl|~}}, {{hl|^}} | ||
|- | |- | ||
| String || {{ | | String || {{hl|+}} | ||
|- | |- | ||
| Shift || {{ | | Shift || {{hl|<<}}, {{hl|>>}} | ||
|- | |- | ||
| Assignment || {{ | | Assignment || {{hl|{{=}}}} | ||
|- | |- | ||
| Indexing || {{ | | Indexing || {{hl|[ ]}} | ||
|- | |- | ||
| Negation || {{ | | Negation || {{hl|!}} | ||
|} | |} | ||
=== Script Operator Overload=== | |||
==== 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. | |||
<enforce> | |||
class IndexOperatorTest | |||
{ | |||
int data[3]; | |||
void Set(int _index, int _value) | |||
{ | |||
data[_index] = _value; | |||
} | |||
int Get(int _index) | |||
{ | |||
return data[_index]; | |||
} | |||
} | |||
auto instance = new IndexOperatorTest(); | |||
instance[1] = 5; | |||
Print(instance[1]); // prints '5' | |||
</enforce> | |||
'''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 336: | Line 374: | ||
|} | |} | ||
=== Other | === Other Keywords === | ||
{| class="wikitable" | {| class="wikitable" | ||
Line 359: | Line 397: | ||
|- | |- | ||
| super || Refers to the base class for the requested variable/function | | super || Refers to the base class for the requested variable/function | ||
|- | |||
| thread || Declared before the function call, runs the function on a new thread | |||
|} | |} | ||
Line 382: | Line 422: | ||
| void || - || - | | void || - || - | ||
|- | |- | ||
| | | Class || - || null | ||
|- | |- | ||
| typename || - || null | | typename || - || null | ||
Line 394: | Line 434: | ||
* Strings can contain standardized escape sequences. These are supported: \n \r \t \\ \" | * Strings can contain standardized escape sequences. These are supported: \n \r \t \\ \" | ||
< | <enforce> | ||
void Method() | void Method() | ||
{ | { | ||
Line 405: | Line 445: | ||
Print(c); // prints "Hello world!" | Print(c); // prints "Hello world!" | ||
} | } | ||
</ | </enforce> | ||
=== Vectors === | === Vectors === | ||
Line 414: | Line 454: | ||
* Vector can be initialized by three numeric values in double quotes e.g. "10 22 13" | * Vector can be initialized by three numeric values in double quotes e.g. "10 22 13" | ||
< | <enforce> | ||
void Method() | void Method() | ||
{ | { | ||
Line 426: | Line 466: | ||
Print(down); // prints <0, -1, 0> | Print(down); // prints <0, -1, 0> | ||
} | } | ||
</ | </enforce> | ||
=== Objects === | === Objects === | ||
Line 434: | Line 474: | ||
* 'autoptr' keyword before object variable declaration ensures that compiler automatically destroys the object when the scope is terminated (e.g. function call ends) | * 'autoptr' keyword before object variable declaration ensures that compiler automatically destroys the object when the scope is terminated (e.g. function call ends) | ||
< | <enforce> | ||
class MyClass | class MyClass | ||
{ | { | ||
Line 441: | Line 481: | ||
Print("Hello world"); | Print("Hello world"); | ||
} | } | ||
} | |||
void MethodA() | |||
{ | |||
MyClass o; // o == null | |||
o = new MyClass; // creates a new instance of MyClass class | |||
o.Say(); // calls Say() function on instance 'o' | |||
delete o; // destroys 'o' instance | |||
} | |||
void | void MethodB() | ||
{ | { | ||
// if you type autoptr into declaration, compiler automatically does "delete o;" when the scope is terminated | |||
autoptr MyClass o; // o == null | |||
o = new MyClass; // creates a new instance of MyClass class | |||
o.Say(); // calls Say() function on instance 'o' | |||
} | } | ||
void MethodC() | |||
{ | |||
MyClass o; | |||
o = new MyClass; | |||
o.Say(); | |||
// This function will delete the object if the reference count of the object is 1 when the function's scope is terminated | |||
} | |||
void MethodC() | |||
{ | |||
} | |||
void UnsafeMethod(MyClass o) // Method not checking for existence of the input argument | void UnsafeMethod(MyClass o) // Method not checking for existence of the input argument | ||
{ | { | ||
o.Say(); | o.Say(); | ||
} | } | ||
void SafeMethod(MyClass o) | |||
{ | { | ||
Print("Hey! Object 'o' is not initialised!"); | if (o) | ||
{ | |||
o.Say(); | |||
} | |||
else | |||
{ | |||
Print("Hey! Object 'o' is not initialised!"); | |||
} | |||
} | } | ||
void MethodD() | void MethodD() | ||
{ | { | ||
autoptr MyClass o; | |||
o = new MyClass; | |||
SafeMethod(o); // ok | |||
UnsafeMethod(o); // ok | |||
SafeMethod(null); // ok | |||
UnsafeMethod(null); // Crash! Object 'o' is not initialised and UnsafeMethod accessed it! | |||
} | |||
} | } | ||
</ | </enforce> | ||
Example of '''this''' & '''super''': | Example of '''this''' & '''super''': | ||
< | <enforce> | ||
class AnimalClass | class AnimalClass | ||
{ | { | ||
Line 522: | Line 562: | ||
} | } | ||
} | } | ||
</ | </enforce> | ||
=== Enums === | === Enums === | ||
Line 533: | Line 573: | ||
* enum name used as type behaves like ordinary int (no enum value checking on assign) | * enum name used as type behaves like ordinary int (no enum value checking on assign) | ||
< | <enforce> | ||
enum MyEnumBase | enum MyEnumBase | ||
{ | { | ||
Line 557: | Line 597: | ||
Print(b); // prints '20' | Print(b); // prints '20' | ||
Print(c); // prints '20' | Print(c); // prints '20' | ||
Print(MyEnum.Alfa); // prints '5' | |||
} | } | ||
</ | </enforce> | ||
=== Templates === | === 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 | * 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 | ||
< | <enforce> | ||
class Item<Class T> | class Item<Class T> | ||
{ | { | ||
Line 597: | Line 639: | ||
int_item.PrintData(); // prints "m_data = 72" | int_item.PrintData(); // prints "m_data = 72" | ||
} | } | ||
</ | </enforce> | ||
=== Arrays === | === Arrays === | ||
Line 608: | Line 650: | ||
* Elements are accessible by array access operator [ ] | * Elements are accessible by array access operator [ ] | ||
< | <enforce> | ||
void MethodA() | void MethodA() | ||
{ | { | ||
Line 638: | Line 680: | ||
int numbersArray[size]; // err! size static array cannot be declared by variable! | int numbersArray[size]; // err! size static array cannot be declared by variable! | ||
} | } | ||
</ | </enforce> | ||
==== Dynamic Arrays ==== | ==== Dynamic Arrays ==== | ||
Line 653: | Line 695: | ||
** array<vector> = TVectorArray | ** array<vector> = TVectorArray | ||
< | <enforce> | ||
void Method() | void Method() | ||
{ | { | ||
Line 673: | Line 715: | ||
Print(nameCount); // prints "nameCount = 2" | Print(nameCount); // prints "nameCount = 2" | ||
} | } | ||
</ | </enforce> | ||
=== Automatic type detection === | === Automatic type detection === | ||
Line 679: | Line 721: | ||
The variable type will be detected automatically at compile time when the keyword '''auto''' is used as placeholder. | The variable type will be detected automatically at compile time when the keyword '''auto''' is used as placeholder. | ||
< | <enforce> | ||
class MyCustomClass(){} | class MyCustomClass(){} | ||
Line 688: | Line 730: | ||
auto variableInst = new MyCustomClass(); // variableInst will be of type MyCustomClass | auto variableInst = new MyCustomClass(); // variableInst will be of type MyCustomClass | ||
} | } | ||
</ | </enforce> | ||
== Control Structures == | == Control Structures == | ||
Line 697: | Line 740: | ||
==== If statement ==== | ==== If statement ==== | ||
< | <enforce> | ||
void Method() | void Method() | ||
{ | { | ||
Line 736: | Line 779: | ||
} | } | ||
} | } | ||
</ | </enforce> | ||
==== Switch statement ==== | ==== Switch statement ==== | ||
Switch statement supports switching by numbers, constants and strings. | Switch statement supports switching by numbers, constants and strings. | ||
< | <enforce> | ||
void Method() | void Method() | ||
{ | { | ||
Line 799: | Line 842: | ||
} | } | ||
} | } | ||
</ | </enforce> | ||
=== Iteration structures === | === Iteration structures === | ||
Line 805: | Line 848: | ||
==== For ==== | ==== For ==== | ||
The for loop consists of three parts: declaration, condition and increment. | The for loop consists of three parts: declaration, condition and increment. | ||
< | <enforce> | ||
void Method() | void Method() | ||
{ | { | ||
Line 821: | Line 864: | ||
void ListArray(TStringArray a) | void ListArray(TStringArray a) | ||
{ | { | ||
if (a == null) | if (a == null) // check if "a" is not null | ||
return; | |||
int i = 0; | int i = 0; | ||
Line 832: | Line 876: | ||
} | } | ||
} | } | ||
</ | </enforce> | ||
==== Foreach ==== | ==== Foreach ==== | ||
Simpler and more comfortable version of for loop. | Simpler and more comfortable version of for loop. | ||
< | <enforce> | ||
void TestFn() | void TestFn() | ||
{ | { | ||
Line 871: | Line 915: | ||
} | } | ||
} | } | ||
</ | </enforce> | ||
==== While ==== | ==== While ==== | ||
< | <enforce> | ||
void Method() | void Method() | ||
{ | { | ||
Line 890: | Line 934: | ||
} | } | ||
} | } | ||
</ | </enforce> | ||
Line 896: | Line 940: | ||
* All member functions and variables are public by default. You can use 'private' or 'protected' keyword to control access | * 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 | * Class member functions are virtual and can be overridden by child class | ||
* 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' | ||
Line 904: | Line 948: | ||
=== Inheritance === | === Inheritance === | ||
< | <enforce> | ||
class AnimalClass | class AnimalClass | ||
{ | { | ||
Line 957: | Line 1,001: | ||
LetAnimalMakeSound(pluto); // prints "Wof! Wof!" | LetAnimalMakeSound(pluto); // prints "Wof! Wof!" | ||
} | } | ||
</ | </enforce> | ||
=== Constructor & Destructor === | === Constructor & Destructor === | ||
Line 971: | Line 1,015: | ||
* When constructor doesn't have any parameters omit brackets while using 'new' operator | * When constructor doesn't have any parameters omit brackets while using 'new' operator | ||
< | <enforce> | ||
class MyClassA | class MyClassA | ||
{ | { | ||
Line 1,008: | Line 1,052: | ||
delete b; // prints "Instance of MyClassB is destroyed!" | delete b; // prints "Instance of MyClassB is destroyed!" | ||
} // here at the end of scope ARC feature automatically destroys 'a' object and it prints "Instance of MyClassA is destroyed!" | } // here at the end of scope ARC feature automatically destroys 'a' object and it prints "Instance of MyClassA is destroyed!" | ||
</ | </enforce> | ||
=== Managed class & pointer safety === | === Managed class & pointer safety === | ||
Line 1,016: | Line 1,060: | ||
* All objects available in game module should be Managed, so they should be using soft links by default (they all inherits from Managed class) | * All objects available in game module should be Managed, so they should be using soft links by default (they all inherits from Managed class) | ||
< | <enforce> | ||
// without Managed | // without Managed | ||
class A | class A | ||
Line 1,059: | Line 1,103: | ||
if (a2) a2.Hello(); // nothing happens because a2 is also NULL, thus this code will always be safe | if (a2) a2.Hello(); // nothing happens because a2 is also NULL, thus this code will always be safe | ||
} | } | ||
</ | </enforce> | ||
=== Automatic Reference Counting === | === Automatic Reference Counting === | ||
Line 1,078: | Line 1,122: | ||
* weak reference just pointing to an object, but doesn't increase reference count | * weak reference just pointing to an object, but doesn't increase reference count | ||
< | <enforce> | ||
class Parent | class Parent | ||
{ | { | ||
Line 1,098: | Line 1,142: | ||
// local variables 'a', 'b' are released (reference count is decreased by 1) | // local variables 'a', 'b' are released (reference count is decreased by 1) | ||
} | } | ||
</ | </enforce> | ||
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. | 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. | ||
Line 1,118: | Line 1,162: | ||
Examples: | Examples: | ||
< | <enforce> | ||
class MyClassA | class MyClassA | ||
{ | { | ||
Line 1,218: | Line 1,262: | ||
ref MyClassA m_e[10]; | ref MyClassA m_e[10]; | ||
}; | }; | ||
</ | </enforce> | ||
Line 1,231: | Line 1,275: | ||
* 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 | ||
< | <enforce> | ||
// original | // original | ||
class ModMe | class ModMe | ||
Line 1,266: | Line 1,310: | ||
a.Say(); // prints 'Hello modded Two' , 'Hello modded One' and 'Hello original' | a.Say(); // prints 'Hello modded Two' , 'Hello modded One' and 'Hello original' | ||
} | } | ||
</ | </enforce> | ||
=== Modded constants === | === Modded constants === | ||
Line 1,273: | Line 1,317: | ||
* Allows multiple mods to change different constants in a single class | * Allows multiple mods to change different constants in a single class | ||
< | <enforce> | ||
class BaseTest | class BaseTest | ||
{ | { | ||
Line 1,297: | Line 1,341: | ||
Print(TestConst.CONST_MOD); // 3 | Print(TestConst.CONST_MOD); // 3 | ||
} | } | ||
</ | </enforce> | ||
=== Modded private members === | === Modded private members === | ||
Line 1,303: | Line 1,347: | ||
* Even though modded class behaves similar to an inherited one, it can still access private members of the vanilla class | * Even though modded class behaves similar to an inherited one, it can still access private members of the vanilla class | ||
< | <enforce> | ||
// original | // original | ||
class VanillaClass | class VanillaClass | ||
Line 1,332: | Line 1,376: | ||
} | } | ||
} | } | ||
</ | </enforce> | ||
[[Category:Syntax]] | [[Category:Syntax]] | ||
{{GameCategory|dayz|Scripting}} | |||
Latest revision as of 17:48, 14 November 2024
Enforce Script is the language that is used by the Enfusion engine first introduced in DayZ Standalone. It is a Object-Oriented Scripting Language (OOP) that works with objects and classes and is similar to 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 | - | "" (empty string) |
vector | see float | (0.0,0.0,0.0) |
void | - | - |
Class | - | null |
typename | - | null |
Strings
- Strings are passed by value, like primitive types
- Can be concatenated by + operator
- Strings are initialized and destroyed automatically
- Strings can contain standardized 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 initialized and destroyed automatically
- Vector can be initialized 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 & 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 initialized 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 don't 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 initialized and destroyed automatically, use 'new' and 'delete' (or 'autoptr' feature)
- Class variables are cleared to default values upon creation
Inheritance
Constructor & 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 instanced instead of 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
Modded private members
- Even though modded class behaves similar to an inherited one, it can still access private members of the vanilla class