Gah - a solution with more questions. – EntropicLqd

UE1:UE1PreProcessorCommandlet

From Unreal Wiki, The Unreal Engine Documentation Site
Jump to: navigation, search

About[edit]

This is a preprocessor in the form of a ucc commandlet. Right now it's only available for UT1, but I'm working on a version for Unreal 1. For unknown reasons it gives me lots of errors on Unreal 1 224 sources.

Install[edit]

Copy files in the archive to your <UTdir> folder.

Download[edit]

As always source code is included in zip file.

Unreal Tournament[edit]

link: UEnginePPC v. 0.5.296 for UT(~103kb)

Rune[edit]

link: UEnginePPC v. 0.3.168 for Rune (~633kb)

Unreal[edit]

Preprocessor is already included in patch 227 for Unreal 1.

Usage[edit]

In order to use the preprocessor you have to call ucc with the following parameters:

ucc uengineppc.parse project=[<project_dir>/<project_file>]  [-option...] [-globals...]

Parameters[edit]

  • <project_dir> - relative project directory.
  • <project_file> - file (.upc extension) containing all options. If file is detected, no further modifiers are checked

Options[edit]

option description override by project file
-clean deletes preprocessor directives from .uc file yes
-debug turns on debug mode (prints every operation on parsed .uc file) yes
-printglobals prints all global variables yes
-normalizeeol tries to find \r and \n and change them into \r\n yes
-bIsPackage when defining <project_dir> you may type only the package name. Path will be detected automatically. yes
-bIniVersion macro __UENGINEVERSION__ will return uengine version saved in INI (FirstRun param), if false, it'll return version saved in engine. yes
-deletelog scans UScript source for log functions and deletes it yes
-force forces all source .uc files to be parsed yes

Globals[edit]

All other parameters will be considered to be global variables. If = is not detected, global variable is equal null. Example:

   val1=1 val val2=3 

Directives[edit]

Currently supported directives are:

directive description
`process should be in the first line of .uc file. Tells preprocessor to parse file
`include(file) embed file in the currently opened .uc (do not parse it)
`include(file,false) embed file in the currently opened .uc (do not parse it)
`include(file,true) embed file in the currently opened .uc and parses it
`require(file) embed file in the currently opened .uc (do not parse it). If required file doesn't exist, it stops parsing current file and produce error.
`require(file,false) embed file in the currently opened .uc (do not parse it). If required file doesn't exist, it stops parsing current file and produce error.
`require(file,true) embed file in the currently opened .uc and parses it. If required file doesn't exist, it stops parsing current file and produce error.
`define(name) defines variable name (used in `ifdef and `ifndef directives)
`define(name,value) defines variable name with specified value (used in `if and ternary operation)
`undef(name) removes name from local definitions
`error(name1,true) produces error message and exits commandlet
`error(name1) produces error message and stops parsing current file
`warn(name1) produces warning message
`log(name1) produces message
`ifdef(name) evaluates to true if variable name is defined
`ifndef(name) evaluates to true if variable name is not defined
`if ([expression1] [operator] [expression2]) checks to see if the first condition is true by comparing expression1 to expression2 using the operator.
`else if ([expression1] [operator] [expression2]) checks to see if the first condition is true by comparing expression1 to expression2 using the operator, only if first condition is false..
`else part of conditional statement
`endif ends conditional statement
`write(name) writes defined variable name
`write(name1==name2option1:option2) if statement evaluates to true (variable name1 equals variable name2) writes option1 otherwise writes option 2
`write(name1<>name2?option1:option2) if statement evaluates to true (variable name1 does not match variable name2) writes option1 otherwise writes option 2
`write(name1>name2?option1:option2) if statement evaluates to true (variable name1 is greater then variable name2) writes option1 otherwise writes option 2
`write(name1<name2?option1:option2) if statement evaluates to true (variable name1 is less than variable name2) writes option1 otherwise writes option 2
`write(name1?option1:option2) if statement evaluates to true (variable name1 is defined) writes option1 otherwise writes option 2
`import(directory,extension,type,group,lodset,flags,package) can be used to import textures/sounds from chosen directory
`namespace(name,value) defines namespace name with specified value. It's a combination of `define and `write. If namespace is detected, it'll be replaced by value, without need of using `write
`remove.start everything below this directive will be deleted
`remove.end disables `remove.start

Notice that all variables used in directive `if and ternary operation are parsed in the following order:

  1. Returns value from global variables if correct name is found, otherwise...
  2. Returns value from local variables if correct name is found, otherwise...
  3. Assumes that name is value.

`import details:[edit]

As type you can use only TEXTURE and SOUND. If the extension is uax or utx the preprocessor will create #exec obj load instead of #exec type import. For example code below:

`import(tex,pcx,TEXTURE,HUD)

will make the preprocessor iterate through all files in folder <UT>/<Project>/tex in search for all *.pcx files. When a file with extension pcx is found, the preprocessor will create a UScript #exec directive to import texture into group HUD. Group, LodStet, Flags and Package parameters are optional. Result will look like:

#exec TEXTURE IMPORT NAME=Tex001 FILE="tex/Tex001.pcx"
#exec TEXTURE IMPORT NAME=Tex002 FILE="tex/Tex002.pcx"
#exec TEXTURE IMPORT NAME=Tex003 FILE="tex/Tex003.pcx"

`namespace details:[edit]

Namespace can be useful to replace large parts of text, without need of use `write and `define directives. For example if you write directive:

`namespace(__SOMECLASS__,class'SomeClass'.static)

and use it in code:

__SOMECLASS__.SomeFunction();

parsed code will change to:

class'SomeClass'.static.SomeFunction();

You can also use macros:

`namespace(__SOMECLASS__,class'__SELF__.SomeClass'.static)

assuming that your package is MyPackege this directive means:

`namespace(__SOMECLASS__,class'MyPackege.SomeClass'.static)

Namespace works also in `require and `include directive.

Operators in conditional statement and write directive[edit]

operator description type
== equal string, float, integer, bool
<> not equal string, float, integer, bool
>= greater or equal float, integer
<= less or equal float, integer
< less float, integer
> greater float, integer
! negation, works as `ifndef

Unreal Engine version[edit]

Since 0.2.106 UE1PreProcessorCommandlet can check the Unreal Engine version. This will be useful once the preprocessor is stable and compiled to U1.

`if(__UENGINEVERSION__==436)
//some UT436 specific code
`endif

Macros[edit]

Macros are in fact hardcoded constants. Each macro will write something in the currently parsed .uc file. Currently supported macros are:

  • __FILE__ - will write name of currently parsed file, usable in conditional statements
  • __CLASS__ - will write name of currently parsed class, usable in conditional statements
  • __DATE__ - will write time
  • __SELF__ - will write current package, usable in conditional statements
  • __UENGINEVERSION__ - will write Unreal Engine version, usable in conditional statements
  • __NUMERATE_CPP__ - replaces itself with a number and increments a counter (used in native functions). It's value depends on native_offset
  • __LINE__ - will write current line (parsed output)
  • __RELATIVE_LINE__ - will write current line (unparsed input)

Functions[edit]

You can also define functions in new section of project file, eg.:

[functions]
`log($value)=log($value,'ResidualDecay')

Now when you call in code:

`log("Log message");

the parser will change it to:

log("Log message",'ResidualDecay');

Tips:

  • Avoid using functions with similar names - eg.: `log and `logx will screw up result code.
  • Avoid using parameters with similar names in one function - eg.: `log($value1, $value2); will not work too good :).
  • Functions can only be defined in project file.

Eventually all bugs listed above will be eliminated (current implementation was written in ~5-10 minutes).

Project file[edit]

Project file must have upc extension, and 'path' must be relative to ucc.exe location. Default location for files with preprocessor Unreal Script files is:

<project_folder>/classes/preprocessor

parsed .uc files will be stored in:

<project_folder>/classes

Here's all commands for project file.

[project]                 - project information
path=path                 - path to project
debug=true                - turns on debug mode (prints every operation on parsed .uc)
make=true                 - if true, ucc commandlet will run make after parsing all files
make_ini=make.ini         - ini used in ucc make commandlet
clean=true                - if true, will delete preprocessor directives
output=folder             - override default output folder where parsed .uc files are written
input=folder              - override default input folder where parsed .uc files are stored
bIsPackage=true           - when defining path you may type only name of package. Path will be detected automatically.
bIniVersion=true          - if true, macro __UENGINEVERSION__ will return uengine version saved in INI (FirstRun param), if false, it'll return version saved in engine.
bDeleteLog=true           - scans UScript source for log functions and deletes it
native_offset             - offset for __NUMERATE_CPP__ macro (starting number)
bForce=true               - if true forces all source .uc files to be parsed
printnamespace=true       - will print global namespace if true
bClearOutput=true         - will delete all output files before parsing input
printmacros=true          - will print all global macros if true
native_offset=1600        - offset when using __NUMERATE_CPP__ macro
 
[globals]                 - group containing global variables for whole project
someglobal=somevalue      - global variable (sample)
 
[namespace]
some_namespace=some_value - declares namespace 'some_namespace' with value equal 'some_value' (for usage see `namespace details)
 
[functions]
`some_function($some_value)=log($some_value,'ResidualDecay') - declares function `some_function

example:

[project]
path=../MyProject/
debug=true
make=true
make_ini=make.ini
clean=true
output=classes
input=classes/preprocessor
bIsPackage=false
 
[globals]
global_value1=test1
global_value2=test2

Example[edit]

Let's say you have project file in <UDir>/system called REmitter.upc with content:

[project]
path=../REmitter/
debug=true
make=false
make_ini=make.ini
clean=true
output=classes
input=classes/preprocessor
printglobals=true
 
[globals]
__NUM_NATIVES__=1

and classes:

REmitterBase.uc

`process
`include(classes/includes/default_header.uc,true)
// Base class for emitter related actors.
// Quaternion implementation originally written by UsAaR33.
class REmitterBase extends Actor native;
 
struct Quat
{
	var() config float W, X, Y, Z;
};
//converts rotator to quaternion
native`write(__NUM_NATIVES__==1?(2330):) static final function Quat RotationToQuat( rotator R, bool bHighPrecision);

default_header.uc

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Copyright 2005-2008 Dead Cow Studios. All Rights Reserved.
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Coder: Raven
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Last revision: __DATE__
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

You run preprocessor and:

  1. directive `process is found, so preprocessor knows that this class has to be parsed.
  2. directive `include is found. Preprocessor embeds file default_header.uc and parses it
  3. macro __DATE__ is found and current date is inserted at its place
  4. directive `write is found. Because expression evaluates to true, first value - (2330) - is inserted at it's place

output .uc file will look like this:

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Copyright 2005-2008 Dead Cow Studios. All Rights Reserved.
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Coder: Raven
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Last revision: 21-9-2008 20:1
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Base class for emitter related actors.
// Quaternion implementation originally written by UsAaR33.
class REmitterBase extends Actor native;
 
struct Quat
{
	var() config float W, X, Y, Z;
};
//converts rotator to quaternion
native(2330) static final function Quat RotationToQuat( rotator R, bool bHighPrecision);

Changelog[edit]

  • v 0.5.296
    • Added two new macros
  • v 0.5.262
    • Added new advanced functions to define in new section of project file
  • v 0.4.194
    • Added new `remove.start and `remove.end directives to remove larger parts of code
    • Namespaces are now usable in `include and `require directives
  • v 0.4.194
    • Added new global namespace
  • v 0.3.185
    • Added new __NUMERATE_CPP__ macro
    • Added new commadline option -force
    • Added new project option bForce
    • Various updates and fixes
  • v 0.3.168
    • Fixed bug in GetVariable function. Variable search is aborted if name is NULL.
  • v 0.3.150
    • added option to delete log calls out of UScript source
  • v 0.3.144
    • added bIniVersion to commandline and project file (changes the way macro __UENGINEVERSION__ works)
  • v 0.2.123
    • new directive `else if
  • v 0.2.106
    • new directive `namespace
    • new macro __UENGINEVERSION__
    • new macro __SELF__
    • macros can be used in conditional statements
  • v 0.2.56
    • new directive `import used to create #exec directive for large number of textures/sounds
  • v 0.1.35
    • fixed directive `write bug (now it doesn't ignore defined variables)
  • v 0.1.5
    • added new option bIsPackage
  • v 0.1.4
    • fixed bug with inline `write directive
  • v 0.1.1
    • initial release