User Tools

Site Tools


hpl3:engine:script

Link to this comparison view

Both sides previous revision Previous revision
Next revision
Previous revision
Last revision Both sides next revision
hpl3:engine:script [2012/04/17 12:32]
thomas [Array]
hpl3:engine:script [2014/02/18 07:24]
thomas [Comments]
Line 22: Line 22:
 ||m|| a member variable || class cMyClass {\\ int mlMember;\\ } || ||m|| a member variable || class cMyClass {\\ int mlMember;\\ } ||
 ||g|| a global variable, defined outside of a class or function.|| int glMyGlobal; \\ class cMyClass {} || ||g|| a global variable, defined outside of a class or function.|| int glMyGlobal; \\ class cMyClass {} ||
 +||id|| this is for tID type.|| tID m_idEntity ||
  
 a variable name always starts with a lower case letter, so anything of type not specified must start with a lower case word. Example: a variable name always starts with a lower case letter, so anything of type not specified must start with a lower case word. Example:
Line 36: Line 37:
  
 **Function/​Class comment** \\  **Function/​Class comment** \\ 
-Use comment blocks for the main comment for each class/​function,​ this so that the parser can show the correct info for code compleition/​hints.+Use comment blocks for the main comment for each class/​function,​ this so that the parser can show the correct info for code compleition/​hints. Only for helpers and similar type of base functions where the information is needed.
  
  
Line 61: Line 62:
 cMonster@ pMonster = CurrentHit();​ cMonster@ pMonster = CurrentHit();​
 float fDamage = RandomDamage();​ float fDamage = RandomDamage();​
-fDamage -= pMonster->Defense();+fDamage -= pMonster.Defense();
 if(fDamage<​0) fDamage =0; if(fDamage<​0) fDamage =0;
 fDamage *= mfHitMultiplier;​ fDamage *= mfHitMultiplier;​
-pMonster->DecHealth(fDamage);​+pMonster.DecHealth(fDamage);​
 </​code>​ </​code>​
  
Line 75: Line 76:
 float fDistSqr = vDiff.x*vDiff.x +vDiff.y*vDiff.y;​ float fDistSqr = vDiff.x*vDiff.x +vDiff.y*vDiff.y;​
 </​code>​ </​code>​
 +
 +Only do this in rare cases when it is really hard to figure what the code means. Normally, simply using section comments is enough. If you split the code into nice sections and name them well, that should be more than enough for other people to figure out what it is about.
  
  
Line 109: Line 112:
 <code c>void insertAt(uint,​ const T&in) <code c>void insertAt(uint,​ const T&in)
 void removeAt(uint) void removeAt(uint)
-void insertLast(const T&in), void push_back(const T&in) +void insertLast(const T&in) 
-void insertBack(const T&in), void push_front(const T&in) +void insertBack(const T&in) 
-void removeFirst(), void pop_front() +void removeFirst() 
-void removeLast(), void pop_back() +void removeLast() 
-uint length() const, uint size() const+uint length() const
 void resize(uint) void resize(uint)
  
Line 129: Line 132:
 void pop_front() void pop_front()
 uint size() const</​code>​ uint size() const</​code>​
 +
 +===== Included files =====
 +
 +File can be included using the //#​include//​ key word. This will look in all folders that have been declared in resources.cfg.
 +
 +An important thing to think about is that any enums, classes, interfaces, etc that are meant to be shared, needs to be declared with the //shared// keyword. Example:
 +<code c++> shared enum eMyEnum {
 +shard interface iMyInterface { </​code>​
 +If this is not done, then the data types will be declared as different types in all files that include the files, which will lead to exceptions, or worse crashes.
 +
 +
 ===== User Classes ===== ===== User Classes =====
  
Line 149: Line 163:
  
 ==== Handles ==== ==== Handles ====
-For any script that is to be saved (which means all scripts pretty much), handles to script classes can NOT be member variables. So a script file like:\\ + 
-<code c++>​class cMyClass {+ 
 +For any script that is to be saved (which means all scripts pretty much), handles to script classes can NOT be member variables. So a script file like: 
 + 
 + 
 +<code c++> 
 +class cMyClass {
  ...  ...
 } }
Line 156: Line 175:
  ...  ...
  ​cMyClass@ mpMyClass;  ​cMyClass@ mpMyClass;
-}</​code>​+} 
 +</​code>​ 
 + 
 is NOT supported. The reason for this is that when a script is destroyed any handle to these classes are destroyed too and cannot be retrieved again! is NOT supported. The reason for this is that when a script is destroyed any handle to these classes are destroyed too and cannot be retrieved again!
 +
  
 It is however okay to to pass handles as arguments: It is however okay to to pass handles as arguments:
 +
 +
 <code c++>void MyFunc(cMyClass@ apArg) { <code c++>void MyFunc(cMyClass@ apArg) {
 ... ...
-}</​code>​ +} 
-or use them as local or global variables. ​+</​code>​ 
 + 
 + 
 +or use them as local or global variables. 
 + 
 <code c++> <code c++>
 cMyClass@ gpGlobalVar cMyClass@ gpGlobalVar
 void MyFunc() { void MyFunc() {
 </​code>​ </​code>​
-<code c++> + 
-void MyFunc() {+ 
 +<code c++>void MyFunc() {
  ​cMyClass@ pLocalVar  ​cMyClass@ pLocalVar
  ...  ...
 } }
 </​code>​ </​code>​
-It is only when they are to be saved that problems arise! 
  
-Finally, having handles ​to engine types, ie + 
-<code c++>​class cMyClass {+Its only when they are to be saved that problems arise. 
 + 
 + 
 +==== ID Handles ==== 
 + 
 + 
 +When working with engine types it is recommended to use ID handles instead of class pointers. 
 + 
 + 
 +<code c++> 
 +class cMyClass {
  ​iPhyiscsBody@ mpBody  ​iPhyiscsBody@ mpBody
-}</​code>​  +} 
-is okay!+</​code>​ 
 + 
 + 
 +Using class handler directly like this works but it is unsafe and does not support saving. Instead the handle can be saved like this. 
 + 
 + 
 +<​code>​ 
 +class cMyClass { 
 + tID mBody; 
 +
 +</​code>​ 
 + 
 + 
 +This saves a unqiue identifier to the body. The ID of a object can be retrived by calling GetID() function. There are script functions for converting the ID to a class handle. 
 + 
 + 
 +<​code>​ 
 +void MyFunc() { 
 + 
 + ​iPhysicsBody@ pBody = cLux_ID_PhysicsBody(mBody);​ 
 + 
 + ​if(pBody ​!is null) { 
 + 
 +  ... 
 + } 
 + 
 +
 +</​code>​ 
 + 
 + 
 +This retrives the class handle from the engine so that it can be used. Retriving the class handle from the ID is very fast. 
 + 
 + 
 +Using a ID instead of a class handle has two big advantages. Unlike class handles the ID can be saved. When loading the save file the ID will still work and retrive the same object. 
 + 
 + 
 +If the object that the ID handle points to gets deleted anywhere else in the code the ID will still be safe. When trying to retrive a deleted object the function will return null. Accessing null pointers will never cause the game to crash. When accessing a class handle that has been deleted that leads to accessing deallocated memory and the game will crash. 
 ===== Script Callbacks ===== ===== Script Callbacks =====
  
Line 237: Line 314:
 bool bArg0 = cScript_GetGlobalArgBool(0);​ bool bArg0 = cScript_GetGlobalArgBool(0);​
 cVector3f vArg1 = cScript_GetGlobalArgVector3f(1);</​code>​ cVector3f vArg1 = cScript_GetGlobalArgVector3f(1);</​code>​
-**5)** When calling a global function, it is okay to have one or more asterix in the object name and then several object will be called. For example //"​My*test"//​ would call: //"​MyNiceTest"//​ and //"​MyBadTest"//​. However, this will be a bit slower, so be careful when using it (eg not during things called every update)+**5)** When calling a global function, it is okay to have one or more asterix in the object name and then several object will be called. For example //"​My*test"//​ would call: //"​MyNiceTest"//​ and //"​MyBadTest"//​. However, this will be a bit slower, so be careful when using it (eg not during things called every update)
 + 
 +Asterix is also supported for the class name (eg "​cMyClass*"​). If you do not care about the class of the objects the class param can simply be empty (""​). The following will call MyGlobalFunc in all script modules named "​MyClassObj"​ no matter the class name: 
 + 
 +<code c++> 
 +cScript_RunGlobalFunc("​MyClassObj",​ "",​ "​MyGlobalFunc"​);​ 
 +</​code>​
 ===== Saving ===== ===== Saving =====
  
  
-To skip saving a variable, you must use metadata keyword [nosave] in front of the the variable name. Examples:\\  ​+To skip saving a variable, you must use metadata keyword [nosave] in front of the the variable name. Examples: 
 + 
 <code c++>​[nosave] float mfT; <code c++>​[nosave] float mfT;
-[nosave] cMyClass@ mHandle;</​code>​+[nosave] cMyClass@ mHandle; 
 +</​code>​ 
 + 
 + 
 +If you only want to save the actual pointer for a handle, but not any data, then use the prefix [nodatasave] Example: 
 + 
 + 
 +<code c++>​[nodatasave] cMyClass@ mNoSaveHandle;​ 
 +</​code>​ 
 + 
 +However it is almost always better to use the tID type for these situations!
  
-If you only want to save the actual pointer for a handle, but not any data, then use the prefix [nodatasave] Example:​\\ ​ 
-<code c++>​[nodatasave] cMyClass@ mNoSaveHandle;</​code>​ 
  
 Also, there is a the prefix [volatile], this will do the same as a [nosave] but will also make sure that variable is not even saved during script reload. This should be used on handles where you are never sure if saved variable can invalid, for instance cSoundEntity and cParticleSystem (that can be deleted by the engine). Also, there is a the prefix [volatile], this will do the same as a [nosave] but will also make sure that variable is not even saved during script reload. This should be used on handles where you are never sure if saved variable can invalid, for instance cSoundEntity and cParticleSystem (that can be deleted by the engine).
-<code c++>​[volatile] cSoundEnity@ mpCurrentSoundEntity;</​code>​+ 
 + 
 +<code c++>​[volatile] cSoundEnity@ mpCurrentSoundEntity;​ 
 +</​code>​ 
 + 
 + 
 +Instead of using class handle here it is better to store the ID to the object. The ID can always be saved and will work correctly on load even if the object no longer exists. Worst thing that can happen is that when getting the actual class NULL is returned. This leads to an excpection, stopping further execution of the current script file, but does not lead to a crash or similar major failure. 
 + 
 + 
 +<​code>​ 
 +tID mCurrentSoundEntity;​ 
 +</​code>​ 
  
 In case you have an array of handles where none of the properties should be saved, this is NOT possible. Instead save names of IDs of the objects in the array. In case you have an array of handles where none of the properties should be saved, this is NOT possible. Instead save names of IDs of the objects in the array.
 +===== Optimizing =====
 +
 +All of the optimizations tips are meant to be used when speed is of essence. It is good to always use them when possible, but it is even more important to have the code readable, so take that into account too!
 +
 +**Declare Local Variables Outside Loops**\\
 +Try and keep the local variables outside a loop. So instead of doing:
 +<code c++>​for(int i=0; i<1000; ++i) {
 + float fX = GetSomeThing(i);​
 + ...
 +}</​code>​
 +Do it like this instead:
 +<code c++>​float fX;
 +for(int i=0; i<1000; ++i) {
 + fX = GetSomeThing(i);​
 + ...
 +}</​code>​
 +That way they script does not need to create the local var for every loop and this can boost performance quite  a bit!
 +
 +**Include only what is needed**\\
 +Make sure that you only include hps files that are really needed. Having includes that are not used can eat up a lot of extra loading time very easily!
 ===== Important notes ===== ===== Important notes =====
  
 C++ scriptable classes with classes in can not be abstract ones. It must always be the top class in the hierarchy that is used and saved. C++ scriptable classes with classes in can not be abstract ones. It must always be the top class in the hierarchy that is used and saved.
 +
 +===== Specific Guidelines =====
 +
 +==== Helper Functions ====
 +
 +  * Helper functions should use degrees, not radians
hpl3/engine/script.txt · Last modified: 2020/07/01 07:07 by thomas