Worst-case scenario: the UEd Goblin wipes the map and burns down your house.
Legacy:Preprocessor
Using the UT3 PreProcessor
Contents
Introduction
The UT3 PreProcessor is functional and while it seems to be lacking in documentation (at least that is available to the mod community) it works ok as a basic pp.
There are other preprocessors of course. I believe I've seen several UnrealScript specific ones and there are always things like filepp which is just totally awesome. You could use a C preprocessor as well, or something like perl's Template Toolkit.
However, should you choose to use the inbuilt preprocessor, here is a guide to what has been discovered so far.
features
* Basic if/else/elsif/endif directives * Include capability * Define preprocessor symbols * Simple "literal" macro replacement * Macros that can take arguments * Multi-line Macros * Some integration with Editor.Make * ??? There must be more - please contribute your knowledge!
usage
The usage is simple and rather straight forward. All directives are initiated with the backtick ( ` ) symbol.
Defining Macros...
Here are some examples of defining macros and symbols:
`define MyVersion "1.3.20" `define MyClass class'MyPackage.MyClass' `define LogError(txt) LogInternal( GetFuncName()$":"$ `txt , 'Error') `define LogDebug(txt) LogInternal( GetFuncName()$":"$ `txt , 'Debug') `define MyAssert(condition) if( `condition ) { `LogError("Assert failed: `condition"); } `define NameOf(var) ( ( `var == `var ) ? '`var' : '`var' )
Conditional...
Standard if/elsif/else/endif clauses can be used. At the moment, the conditions that can be evaluated by these clauses seem to be somewhat limited to the following:
`notdefined( SYMBOL ) `isdefined( SYMBOL )
There must be other preprocessor functions that can be used as well - but those are all you need to accomplish quite a bit:
`define MyVersion "1.3.20" `define MyClass class'MyPackage.MyClass' `define LogError(txt) LogInternal( GetFuncName()$":"$ `txt , 'Error') `define MyAssert(condition) if( `condition ) { `LogError("Assert failed: `condition"); } `if(`isdefined(DEBUG)) `define LogDebug(txt) LogInternal( GetFuncName()$":"$ `txt , 'Debug') `define NameOf(var) ( ( `var == `var ) ? '`var' : '`var' ) `else `define LogDebug(txt) `define NameOf(var) '`var' `endif
Including Source...
You may use the include directive to incorporate content. The convention for "header files" seems to be to use the extension: .uci
class MyMutator extends Mutator; `include( MyPackage/Classes/MyStdInc.uci ) function PostBeginPlay() { `MyDbg("MyCoolMutator, Version: " $ `MyVersion ); // whatever.... }
Things to investigate
The '#' symbol seems to be recognized:
// Not sure what this is - it may be for positional arguments or number of arguments supplied to macros. More investigation is needed. `#()
Enclosing symbols in '{' and '}' seems to have some purpose, not sure what it is but, I think it may mean "evaluate to empty string and do not produce an error if the symbol/macro is not defined." like so:
`if(`isdefined(MY_UNIT_TEST)) `define FuncScope public `endif `{FuncScope} MyCoolFunction() { // whatever... }
Line Continuation and Multi Line Macros
You may wish to continue long lines or create multi-line macros. You can continue lines with a backslash. If you want your macros to be "multi-line" then you can place a "\n" at the end of the line.
Example source:
var int SwapTmp; `define SwapInt(a,b) SwapTmp = `a; \ `a = `b; \ `b = SwapTmp var array<string> Messages; `define DefaultMessages \ Messages(0)="Hello World" \n \ Messages(1)="Headshot!!!" \n class MyClass extends Info; function PostBeginPlay() { Swap(MyKills,MyHealth); } defaultproperties { `DefaultMessages }
The above would result in something like:
var int SwapTmp; class MyClass extends Info; function PostBeginPlay() { SwapTmp = MyKills; MyKills = MyHealth; MyHealth = SwapTmp; } defaultproperties { Messages(0)="Hello World" Messages(1)="Headshot!!!" }
Caveats
Line Numbers in warning/error output
Unless you use the `include() directive, you should not have a problem with this. If however, you choose to
use the `include() directive then when your code has a warning or error it is quite likely that the line
number reported by the compiler will be inaccurate.
_[BIA]DarthMushak_ : I have written a perl script that will launch "ut3 make" and parse the resulting output before displaying it, adjusting line numbers as necessary. If anyone is interested, let me know.
white space
- Caution* you must be aware of how the UT3 preprocessor interprets whitespace! If there is no whitespace between the end of your macro definition and the newline, then when the preprocessor inserts the result, it will *eat all the whitespace on its RHS* - so:
1: `define MyType int\n 2: \n 3: var `MyType Foo;\n 4: \n 5: `define MyOtherType string \n 6: \n 7: var `MyOtherType Bar;\n
Assuming that the "\n" chars in the code above are the newlines, the above code would effectively produce the following:
1: 2: 3: var intFoo; 4: 5: 6: 7: var string Bar;
So, be careful with the whitespace!
Integration with Editor.Make ( ut3 make ... )
While you are free to define symbols such as DEBUG and FINAL_RELEASE via preprocessor directives it is probably best if you leverage the inbuilt support for these two via command line switches to the "make" Commandlet.
Here is an example snippet of a class file that will be used to clarify the following examples:
DEBUG
By supplying the switch *-debug* to make, the symbol "DEBUG" will be defined globally in all classes during the parsing phase.
ut3 make -debug
FINAL_RELEASE
By supplying the switch *-final_release* to make, the symbol "FINAL_RELEASE" will be defined globally in all classes during parsing phase.
RELEASE
If you supply neither *-final_release* or *-debug* then the code will be built for "release".
More to come
Stay tuned! If you learn more, please update this page. Thanks!