Phase 1 of the AWS migration has been completed. If you encounter any issues, please report them through our support portal. Thank you for your patience.

Language Overview

From SC2Mapster Wiki
Jump to: navigation, search

Language Overview

StarCraft II uses a scripting language called "Galaxy" for providing customizable logic to game state progression. All maps no mater how simple use at least some Galaxy script which can be either generated automatically from GUI or hand written. Hand written Galaxy script can do some jobs that GUI cannot which is the main reason to learn the scripting language.

The language itself is JIT compiled on map load into virtual machine code which is interpreted by the StarCraft II's Galaxy virtual machine component during runtime. The virtual machine itself uses a Harvard architecture providing separate memory spaces for code and the global heap. The Galaxy virtual machine does support multiple threads of execution and has a strict memory model allowing only a single thread to execute at any time which will execute until its root method returns or blocks. When testing maps from the editor in windowed mode a combined debugger and profiler can be attached to the virtual machine to aid with script development.

Syntactically Galaxy is based on the original specification of C. Some features such as pointers are supported by the virtual machine but are disabled for security reasons. Many features like multi-line comments are also not supported probably due to development resource constraints. Features like type casting were never attempted due to security reasons however might still be performed by the virtual machine internally. To mitigate the lack of pointers a later patch added limited {{{C++}}} like reference support in the form of template-like types. Several standard C types are also missing such as a 16 bit integer, unsigned integers of any length and floating point numbers. Instead of using standard C libraries Blizzard provides a list of natives which map directly to internal function calls inside the game engine. Arrays are also implemented as types as opposed to variable modifiers.

Many people criticize the language due to its lack of the C features such as the standard libraries and pointers. The natives used lack many key features of the standard C library such as the ability to dynamically allocate memory (malloc) and many string manipulation functions. The "byte" type 8 bit integer appears to have incomplete support with implicit type casting to int not occurring in some use cases such as an array index. Many people also view the Harvard style memory system as imposing limits on code complexity which is insufficient for some maps however in practice such limits are seldom and issue. A common problem with using the language is due to inexperience with original C style programming as many features such as declaring local variables anywhere is not supported by the original C specification.

List of SC2 natives

Galaxy vs JASS2

Warcraft III used a scripting language called JASS2 (usually just JASS) similar to how StarCraft II uses Galaxy. Although the JASS2 syntax is completely different from Galaxy they share many of the basic features. Galaxy also supports many new or improved features to take advantage of. It also imposes some restrictions which were not present in JASS2.

Features which are similar between JASS2 and Galaxy.

  • List of natives as a standard library.
  • All locals must be declared immediately after opening a function.
  • Use of a JIT compiler and virtual machine for execution.
  • Support of 32bit long fields.

Features which are new or were improved upon in Galaxy.

  • All variables are statically linked by the JIT compiler instead of runtime name resolution. This greatly improves execution performance.
  • Non-argument local references automatically decrement object reference counters at function return. JASS2 suffered from a bug causing possible object handle leaks.
  • Many common complex object types are automatically garbage collected. JASS2 required manual object deallocation which result in a common issue of object leaks.
  • Strings are garbage collected. In JASS2 unique strings persisted until end of session.
  • Functions can be declared before being defined allowing definitions to be in any order. JASS2 required that all called functions be defined above the call site.
  • Non 32 bit long types are supported. JASS2 only supported 32bit long types.
  • The range of integer operators was expanded to include bitwise operators. JASS2 did not support any bitwise operations natively.
  • It is possible to declare global variables anywhere outside a function. JASS2 required that global variables be declared inside a special "global" block which only one could exist.
  • A fixed point type is supported. JASS2 lacked any such type.

Restrictions which are new to Galaxy.

  • Arrays now require a size argument. JASS2 used dynamic arrays which automatically resized up to size 8192.
  • There is a memory resource limit which applies separately to both code and global variables. JASS2 had no practical limit on code and global allocation.
  • There is no support for floating point types. JASS2 supported platform dependent 32 bit single precision floats in the form of the "real" type.

Language Features

The language is largely based on the original C specification. As such many basic tutorials for C are appropriate for learning Galaxy. Alternativly experience using Galaxy will make learning the more advanced aspects of C easier.

Flow Control Statements

Flow control statements are any statement which changes the sequence of execution. Normally programs will execute sequentially evaluating every statement in order of declaration. By using flow control it is possible to alter this order by making the code executed depend on the evaluation of certain tests.

Conditional Selection Statement (if)

Galaxy supports conditional selection statements in the form of the usual "if" statement. Unlike C conditional statements the jump is made based on a bool type (instead of int) and always requires a code block (no inlined code).

Conditional statements are commonly used when scripting as they allow the conversion of a logical test (a bool value) into a branch in the executed code. Multiple conditional branches and even a failure branch can be defined greatly improving the dynamic nature of your code. For example when a player earns a point one might test the number of points he has against a constant and if the test passes then end the game otherwise play some voiceover to everyone.

The syntax of the conditional selection statement is defined as...

if ( bool runblock )
 { code block }
 optional repeatable else if ( bool ''runblock'' )
 { ''code block'' }
 ''optional'' '''else'''
 { ''code block'' }
 ''end''


The functionality is such that if runblock is true then run the following code block otherwise advance to next else if statement if any and repeat until no more "else if" statements remain. If none of the checked statements pass then run the code block following the else statement if any. After running a code block or if the no suitable code block was found then resume program execution from end. When a block is executed any following else if statements will not have their runblock value evaluated.

The conditional selection statement can be used like...

 // Single selection for random chance.
 if ( Random(1, 5) <= 1 ) {
     // Code has a 1 in 5 chance to execute.
 }
 
 // Multiple selection for common choice and less common choices.
 if ( Random(1, 5) <= 4 ) {
     // Code has a 4 in 5 chance to execute.
 } else if ( Random(1, 5) <= 4 ) {
     // Code has a 4 in 25 chance to execute.
 } else if ( Random(1, 5) <= 4 ) {
     // Code has a 4 in 125 chance to execute.
 }
 
 // Multiple selection with failure case for rare choices and failure result.
 if ( Random(1, 64) <= 1 ) {
     // Code has a 1 in 64 chance to execute.
 }else if ( Random(1, 8) <= 1 ) {
     // Code has a 63 in 512 chance to execute.
 }else
     // Code has a 441 in 512 chance to execute.
 }

Some hints for using the conditional selection statement...

  • If you are testing the same value for multiple specific cases a case statement should rather be used. Case statements might compile to perform decision making more efficiently than multiple selection.
  • If you are testing multiple mutually exclusive events then it is recommended to test the one most likely to occur first. On average it will result in fewer tests being performed and so execute faster.
  • The if and else if statements expect a bool value. Although this is usually the result of a comparison operation it can also come from a function return value or from evaluating a bool type variable. This is a subtle feature unavailable in the standard StarCraft II Editor GUI which forces you to always use a comparison.

Conditional Repetition Statement (while)

Galaxy supports conditional repetition statements in the form of the usual "while" statement. Unlike C conditional statements the loop is run based on a bool type (instead of int) and always requires a code block (no inlined code).

Conditional repetition is used to repeat jobs a number of times until the condition is failed. The condition used is usually influenced by the code block such that after a finite number of iterations it will fail and execution will continue after the loop. It is possible to escape from a loop by executing the break statement.

The syntax of the conditional repetition statement is defined as...

 '''while''' ( bool ''runblock'' )
 { ''code block'' }
 ''end''

The functionality is such that runblock is evaluated and if true the following code block is executed and the sequence repeated. If either runblock evaluates false or a break is used inside the code block then execution resumes from end.

The conditional repetition statement can be used like...

 // A loop which never runs its block.
 while ( false ) {
     // This never runs!
 }
 
 // A loop that never stops running its block.
 while ( true ) {
     // This never stops running! An infinite loop.
 }
 
 // A simple loop that runs 5 times.
 // Variable i is of type int.
 i = 0;
 while ( i < 5 ) {
     // Code here will run 5 times.
     i+= 1;
 }
 // The variable i has the value of 5.
 
 // Using an infinite loop with a test performed inside the code block.
 i = 0;
 while ( true ) {
     i+= 1;
     // Code here will be repeated 6 times.
     // End when i is greater than 10.
     if ( i > 10 ) { break; }
     // Code here will be repeated 5 times.
     i+= 1;
 }
 // The variable i has the value of 11.

Some hints for using the conditional repetition statement...

  • Computers have finite computational resources so cannot execute infinite loops. An infinite loop will either cause an operation limit thread crash or make the game become unresponsive.
  • Even a simple code block can cause performance problems if repeated enough. Such blocks are prime targets for optimization.
  • You can use a break statement inside the code block to end the loop at any time. You can use this to end the code block pre-maturely.
  • With an infinite loop and an if statement the break statement can be used to move the test expression inside the code block. Useful if you need the code block to always run at least partly.

Conditional Repetition Statement (for)

int i = 0;
for(; i < 10;i+=1)
{  
   UIDisplayMessage(PlayerGroupAll(), c_messageAreaDebug, StringToText("Integer: "+IntToString(i)));
 }

Variables

  • Always declare the variables at the beginning of function or script.
  • Never declare them after function calls or logical operations.
int a; // variable declaration
int b = 1; // variable declaration & definition
const int c = 2; // variable that cannot be changed
// Variable must be declared at the top of the function

See: List of Variable Types

Array

const int array_count = 5; // It must be const
int i = 0;
int[array_count] t; // The [] are next to the type. This is different from C
while (i < array_count)
{
  t[i] = i;
  i = i + 1;
}

See: Arrays for more details.

Struct

struct point2d
{
  int x;
  int y;
}; // Do not forget the ;

point2d A; // Create a variable A of type point2d
A.x = 2;
A.y = 3;
print(A.x);
point2d* B = &A; // Take a pointer of A
Print(B->x);

See Structs for more details.

Function

int plus(int i, int j)
{
  int result = i + j; // Local variable initialized with arguments
  return result; // Return a result
}

static void private()
{
  // This function can only be called inside the file (because of "static")
}

// Function prototype
native int AIGetRawGasNumSpots (int player, int town);

Include

The only C style macro supported by the Galaxy virtual machine compiler is the include statement. What this does is physically insert the given script file into the compilation unit at the current position equivalently making the file appear as if it was part of the script. This feature is mostly used internally or when using external script libraries as generally all map specific scripts get placed into a single enormous file, the map script file.

include "Folder/File"; // Include the file "Folder/File.galaxy"

Types

  • Galaxy features many primitive types to choose from. All primitive types are hardcoded into the virtual machine and some have special overloaded operators.
  • It is also possible to declare custom types in C style. These inherit the same behaviour of the base type when evaluated. It is not possible to operator overload custom types.
// Declare type "flag_t" which acts like an int.
typedef int flag_t; 
// Declare type storage_t which acts like an int array of size 50.
typedef int[50] storage_t;
// Declare type dostuff_t which acts like a function pointer to
// functions of prototype stuff_t.
void stuff_t();
typedef funcref<stuff_t> dostuff_t;
// Declare type anothertype_t from the custom type flag_t.
typedef flag_t anothertype_t;

Language Lacks

  • No dynamic allocation: There is no new or malloc. We wonder what would be the use of pointers without this.
  • No pointer: Since patch 9, pointer were all removed. With the above lack of new or malloc, pointer were quite limited to begin with.
  • Bulk Copy Not Supported: That with the lack of pointer, array and struct can't be passed to and from functions. It's also impossible to :copy them from one variable to another. This with the 2 above render struct and array almost completely useless.
  • Weak Compiler Debugging Output: The only error it is able to say is "Syntax Error" and the line where the error happened is not :available.
  • No /* ... */ Comments: Maybe it's too hard to code ...
  • Single Pass Declaration Scanning: You have to write the prototype of functions if it is declared after in the file.
  • /=, *= Not Working Properly For Fixed:
  • Language Being Based On C: C is an old static language. We expected a dynamic language like Lua. However, this isn't even on par with C... :(
  • Line Cannot Be > 2048 Characters: Wth ...
  • No Trigonometric Functions: There are sine, cosine, tangent, arcsine, arccosine arctangent form delta and arctangent from value in the :Build-In Lib
  • No Vectorial Functions: The functions support around "point" is extremly limited. You got Distance and Angle.
  • No Direct Accessor To Propriety Of Native Classes: You have to use native function like PointGetX(), PointGetY()
  • No Quaternion and No Matrix Support: Seriously, ever tried doing spatial rotation by hand?