Jump to content

  • Log In with Google      Sign In   
  • Create Account

Banner advertising on our site currently available from just $5!

1. Learn about the promo. 2. Sign up for GDNet+. 3. Set up your advert!

Andreas Jonsson

Member Since 26 Mar 2000
Offline Last Active Today, 08:23 PM

#5131299 asIScriptModule == asIScriptModule

Posted by Andreas Jonsson on 14 February 2014 - 10:01 AM

You can compare the asIScriptModule pointers directly. There is no need for an additional id.

#5129850 Don't think I'm handling objects properly...

Posted by Andreas Jonsson on 08 February 2014 - 10:45 AM

How is the vec3_t declared? You've registered it with asOBJ_APP_CLASS, with which you're telling AngelScript that this type doesn't have any default constructor nor any copy constructor. Is that really the case? If you don't register the value type with the correct asOBJ_APP_xxx flags AngelScript will not know how the type should be passed by value to native functions. If you're using a C++11 capable compiler you can use the GetTypeTraits<T>() function from scripthelpers add-on to automatically get the correct asOBJ_APP_xxx flags.



How is the playerState_t declared? The asOFFSET(playerState_t, persistant[PERS_ACCURACY_SHOTS]) macro expands to the following:






Is that giving the correct offset? I assume the persistant member is a static array, and not something like std::vector.

#5129560 Don't think I'm handling objects properly...

Posted by Andreas Jonsson on 07 February 2014 - 06:40 AM

As I suspected. Your AS_SetArgBasedOnType is not dereferencing the pointer when calling SetArgAddress.

void AS_SetArgBasedOnType(void* arg, const string& argument, int argNum) {
  if(!argument.compare("byte") || !argument.compare("int8") || !argument.compare("uint8") || !argument.compare("bool"))
    scrpContext->SetArgByte(argNum, *(byte*)arg);
  else if(!argument.compare("double"))
    scrpContext->SetArgDouble(argNum, *(double*)arg);
  else if(!argument.compare("dword") || !argument.compare("int") || !argument.compare("uint"))
    scrpContext->SetArgDWord(argNum, *(DWORD*)arg);
  else if(!argument.compare("float"))
    scrpContext->SetArgFloat(argNum, *(float*)arg);
  else if(!argument.compare("int16") || !argument.compare("uint16"))
    scrpContext->SetArgWord(argNum, *(short*)arg);
  else if(argument.find_first_of('@') != argument.npos || argument.find_first_of('&') != argument.npos)
    scrpContext->SetArgAddress(argNum, *(void**)arg);  // Must dereference to give the address of the object
    scrpContext->SetArgObject(argNum, *(void**)arg); // Must dereference to give the address of the object

Try making the change I did above and let me know if it works.

#5129355 Don't think I'm handling objects properly...

Posted by Andreas Jonsson on 06 February 2014 - 11:51 AM

What you're doing is not completely wrong (though it is quite inefficient, in that you do a lot of string processing with each call). The problem is probably some small detail, e.g. a missing dereference of the pointer to the object.



Can you show the implementation of AS_SetArgBasedOnType?


Based on how you're calling it, it should be doing something like this in order to be correct:


void AS_SetArgBasedOnType(void **arg, const string &type, int index)
   // check if the parameter is a handle (it's not really enough to do a find, but you get the idea)
   if( string.find("@") != string::npos ) 
      // Call SetArgObject and inform the address of the object
      scrpContext->SetArgObject(index, *arg);


For handles it would also be valid to use SetArgAddress.




Is the CalcMuzzlePoint() function called from the script, or does it crash before that? If it is called, is the pointer you receive the expected one?






Curiosity: Why is your loop that calls AS_SetArgBasedOnType going from 2 to numArgs + 2, when you subtract 2 whenever you use the index? ;)

#5127868 AngelScript 2.28.1

Posted by Andreas Jonsson on 31 January 2014 - 06:51 PM

It's time for the first release of 2014.


This one brings quite a lot of under-the-hood improvements, such as reduced compilation times, less overhead in calling script interface methods, inline allocation of class members, reduced size of saved bytecode, improved error reporting for loading invalid bytecode, automatically resolve ambigiuous enum values, etc.


The script language has a new built-in math operator ** for calculating the exponent. Of course, this operator is overloadable just like the rest of the operators. This operator also added 7 new instructions for the VM to handle the primitive types.


Several of the add-ons have been tweaked and adjusted to make them easier to use.


Some of the improvements in this release were contributed by the community members GGLucas and Jason Goepel. So thanks should go out to them this time.




#5127830 Delegates from application (for gui)

Posted by Andreas Jonsson on 31 January 2014 - 03:41 PM

I think you'll want to use delegates for this.


Your script would look something like this:


class Scene1 : IScene
     @controller = loadController("Menu/HUD.axm");
     Widget@ widget = controller.GetWidget("Overhead");
     // Create a delegate object and connect it to the signal handler

   void OnClick()

   GuiController@ controller;


The OnClickCallback is a funcdef that is registered from the application like this:


engine->RegisterFuncdef("void OnClickCallback()");


The SigClicked::Connect method is registered like this


engine->RegisterObjectMethod("SigClicked", "void Connect(OnClickCallback @)", asMETHODPR(SigClicked, (asIScriptFunction *), void), asCALL_THISCALL);


As you can see the Connect method will receive a pointer to the delegate as a normal script function, which you can then use to prepare and execute in a script context just as if it was a global script function.


Should you want to extract the object pointer and the class method from the delegate object and store those instead of the delegate itself, you can do so with the methods GetDelegateObject, GetDelegateObjectType, and GetDelegateFunction.




#5125895 When to use asOBJ_POD

Posted by Andreas Jonsson on 23 January 2014 - 10:06 AM

The existance of a user defined constructor doesn't imply that that the object is not a POD type. If the members can be safely accessed even before the constructor is called without causing any harm, then it can still be considered a POD type.


For example:


class Vec2
   Vec2() : x(0), y() {}
   Vec2(float _x, float _y) : x(_x), y(_y) {}
   float x,y;


The above class is an ordinary POD type even though it has user defined constructors. Think of it like this. Can any harm be done if you interpret a random address into uninitialized memory as the type and then access the members? If no harm can be done then the type is a POD type, but if some harm can be done then it is not a POD type.




asOBJ_POD and the various asOBJ_APP_CLASS_ flags are not directly related to each other. The first tells AngelScript that it is safe to access the unitialized memory and thus it can allow direct bitwise copies of the objects, and the second is used to allow AngelScript to properly passed values of the type to the application registered functions in native calling conventions.


Ideally you would use the templated GetTypeTraits<T>() helper add-on function to determine the correct combination of the asOBJ_APP_CLASS_ flags automatically. This function is only available for compilers that support C++11 though, so if you use an older compiler you'll need to determine the flags manually.

#5125701 When to use asOBJ_POD

Posted by Andreas Jonsson on 22 January 2014 - 01:19 PM

Basically you'll want to use asOBJ_POD for any C++ type that is a plain-old-data type, i.e. doesn't have any virtual function table, and doesn't have any members that require explicit initialization and/or clean-up (e.g. pointers, file handle ids, etc).


There is no problem in providing constructors for objects registered with asOBJ_POD. The flag just says they are not required, not that they are not allowed. Without the asOBJ_POD flag, AngelScript would require the application to register both constructor (at least one) and destructor for the object.


The use of asOBJ_POD also allows AngelScript to make some optimizations, as it can safely inline POD objects within script classes without worrying about invalid memory access due to uninitialized objects while executing the script class constructor.

#5121732 Android - virtual function call issue

Posted by Andreas Jonsson on 06 January 2014 - 03:35 PM

I've managed to reproduce the problem on my BeagleBone with Linux, which shares the code for the native calling convention with Android.


I'll investigate this problem further and update you as soon as I have a fix for it.

#5120786 No AS binary packages

Posted by Andreas Jonsson on 02 January 2014 - 04:53 PM

If your definition of 'mature' means that the libraries interface cannot evolve anymore, then I guess AngelScript isn't mature yet (even after 10+ years of development). But if your definition of 'mature' is how many successful projects use AngelScript and how long it's been available then AngelScript is really quite mature. Guess, which definition of 'mature' I use. ;)


Most developers that use AngelScript keep a copy of the version they integrate, they even check-in the source code in their own repository. This removes any dependency on my repository and avoids confusion when other users download your project (as it will include the exact version of AngelScript you're using). The developer is then also in full control when he wants to upgrade to the latest version of AngelScript, or if he'd rather continue using an older version. Some developers upgrade with every new release (usually it is just a couple of tweaks to the existing code), others only upgrade every couple of years (and usually have a little more work).



On the topic of version numbering. The 1st digit is the major version. I'll only change this to 3 when I'm ready to take the step to remove old functionality (and breaking script compatibility). The 2nd digit is the interface version. I change this everytime there is a change to the interface (though usually it is just an additional parameter, or method, or similar). The 3rd digit is for releases that doesn't change the interface, but implement something new. On some occasions I've also used a final letter, without changing the numbers. This is when releasing only bug fixes, without any other changes.



I try to avoid changing the interface all the time. Normally I hold off on features that change the interface until I have a couple of different ones that I can release together, but I cannot stop it all together as then I'll soon run out of options to evolve the library. I also definitely will not maintain 2 parallel versions. That would only lead to even more confusion and would take away from my already too few available hours to work on the library.

#5118108 variable persistence and does it make sense to have an 'idle loop'

Posted by Andreas Jonsson on 19 December 2013 - 07:43 AM

Think of your first alternative as a parallel thread in your application. The application will allow the context to execute for a while, then the context will wait (suspend) until it is time to execute again.


The other option is more like to event handling. Anytime there is an event in the application, the context is executed to handle that even and may use global variables (or properties registered by the application) to keep state information between executions.



Both options are perfectly viable with AngelScript, and it will only depend on your preference.


In my opinion the second option is easier to implement and manage, for the same reason that a singlethreaded application is easier to implement and manage compared to a multithreaded application.

#5115666 When to use asOBJ_APP_CLASS_ALLINTS

Posted by Andreas Jonsson on 09 December 2013 - 09:37 AM

The flags asOBJ_APP_CLASS_ALLINTS/FLOATS are used to tell AngelScript what the type of content the object has, so AngelScript can decide how the object should be passed to registered functions in native calling conventions. The only ABI so far that needs these flags is the AMD/Intel 64bit ABI that the g++ compiler uses. This specific ABI can decide to put the object in the CPU float registers or general registers depending on the type of the members of the class.


On any other platform or compiler the flags will have no effect.


The documentation that describes when/how to use these flags is here:


Manual: Value types and native calling convention




#5113915 Update script function argument on resume from suspend

Posted by Andreas Jonsson on 02 December 2013 - 07:15 PM

You can only set arguments on the context after Prepare() and before the first Execute(). The SetArg methods returns an error if not in this state. I bet you didn't check the return code, am I right? ;)


When a context is suspended and then resumed with another call to Execute() it will continue at the exact same position where it was suspended, which means that any function arguments that were passed into the function in the first call will already have been read and used. Even if the context would allow you to set the arguments while the context was suspended there would be no guarantee that the script would actually re-read the arguments when resuming.


If you mean to change the argument, why not allow the script to run to it end and then simply call the script again with the new argument? I.e. remove the while loop and the SuspendMe() call. 


void main(float frameDelta)
  if( something )

#5113559 Default constructors vs default arguments

Posted by Andreas Jonsson on 01 December 2013 - 03:26 PM

I've implemented this in revision 1792.




#5112862 Alignment requirements

Posted by Andreas Jonsson on 28 November 2013 - 06:01 PM

I don't think it is because of anything malloc does. More likely the debug build uses different instructions to load the SIMD registers so the __m128 types doesn't require alignment. This is however something that would be in your application, and not in AngelScript. 


You can set custom memory functions with asSetGlobalMemoryFunctions(). With this the application can use memory routines that is guaranteed to always return 16byte aligned memory to the script library. You probably don't want to use 16byte aligned allocations for everything though, as it will waste a lot of memory when the allocations are smaller than 16bytes. 


This gave me an idea. The code in as_memory.h can perhaps be enhanced to have a new macro for allocating 16byte aligned memory, e.g. asNEW16 and asNEWARRAY16. This macro can then call a new userAlloc16 global function. The pieces of code I mentioned above that need to guarantee 16byte aligned memory would then only have to call these macros instead of the existing ones to allocate the memory.