Jump to content

  • Log In with Google      Sign In   
  • Create Account

Andreas Jonsson

Member Since 26 Mar 2000
Offline Last Active Today, 02:13 AM

#5095209 Script object reference in C++

Posted by on 19 September 2013 - 10:56 AM

GetAddressOfVar() will return the address of the value in the variable. If the variable is a primitive type then the address will point to the value of the primitive, if the variable is a handle then the address will point to the handle, if the variable is local object (even if it is a ref type) then the address will point to the object.


You can use the typeId to know if the variable is a handle or not by checking for the bit asTYPEID_OBJHANDLE. If it is not a handle, then the variable will not be null.


I suggest you take a look at the CDebugger add-on in the SDK, particularly the ToString() and PrintValue() methods. It shows how to interpret the information you get about the variables.




#5094724 Register Parameter Names

Posted by on 17 September 2013 - 01:22 PM

Yes, AngelScript doesn't store the name of the parameters for registered functions as it is not something that is needed by the engine.


You can use the user data in the function object to store the parameter names if you wish.




const char *decl = "void SetSize(int nRows, int nCols)";
r = engine->RegisterObjectMethod("Matrix", decl,
    asMETHODPR(Matrix, SetSize, (int,int), void), asCALL_THISCALL);
if( r > 0 )
   asIScriptFunction *func = engine->GetFunctionById(r);

#5094246 Ownership problem of Funcdefs.

Posted by on 15 September 2013 - 10:16 AM

The asIScriptFunction object is the actual script code. As long as you don't discard the script module the function object will be valid. You do not need to increase the reference of the asIScriptFunction if you have control over when the script modules are discarded. If you want you can use the user data of the asIScriptFunction to receive a callback when the actual script function is being removed from the engine. With the callback you will then be able to cleanup any code that is still referencing the asIScriptFunction.







While I could theoretically change the built-in delegate object to use weak references it is currently not something I plan to do. Delegates can be used with application registered types as well, and not all application types are implemented to support weak references. 




#5094089 Ownership problem of Funcdefs.

Posted by on 14 September 2013 - 04:07 PM

Hi Wracky,


If you don't want the delegate to hold a strong reference to the original object, then you'll need to look into implementing a weak-reference container.


Luckily for you, with version 2.27.1 weak references is already a reality, so it should be quite easy for you to do cool.png


I recommend you keep using the built-in delegates for allowing the script to pass the callback to the application, but instead of storing the received delegate directly, you dissect it and store the object pointer with a weak reference and the method pointer normally.


void FuncReceivingDelegate(asIScriptFunction *delegate)
   // Get the object pointer from the delegate
   if( delegate->GetFuncType() == asFUNC_DELEGATE )
     void *obj = delegate->GetDelegateObject();
     asIObjectType *objType = delegate->GetDelegateObjectType();
     asIScriptFunction *method = delegate->GetDelegateMethod();
     // Create a weak ref to keep the pointer to the object
     CScriptWeakRef *weakRefToDelegatedObject = new CScriptWeakRef(obj, objType);
     // Store the weak ref and the method instead of the original delegate


In case you wish to explore the generic funcdefs option, then you need to know that the generic handle add-on is capable of holding references to funcdefs too.




#5091630 Strange asOBJ_POD behavior with copy constructor and opAdd

Posted by on 04 September 2013 - 02:24 PM

Whatever you do, do not try to trick to AngelScript. It will just cause difficult to find bugs as things don't quite work as it should in all cases. ph34r.png


Seriously, the asOBJ_APP_ flags must be registered correctly, as these are what AngelScript uses to know exactly how the host application expects to handle the type in the native calling convention. If you can, I recommend that you use the GetTypeTraits<T>() helper function. It will make sure you don't make a mistake in chosing the wrong flags.


A few flags cannot be determined automatically though, and these are asOBJ_APP_CLASS_ALLINTS, asOBJ_APP_CLASS_ALLFLOATS, and asOBJ_APP_CLASS_ALIGN8. On platforms that split value types in different CPU registers (e.g. 64bit Linux) these flags may be needed to tell AngelScript about the content of the type, so that it will be able to place the data in the correct CPU registers.


The manual explains what each flags means and how to use them.

#5091064 Strange asOBJ_POD behavior with copy constructor and opAdd

Posted by on 02 September 2013 - 10:43 AM

It is all related to the native calling convention. In your first test you hadn't registered the Integer class correctly, which is why you were getting the wrong result. The original declaration should be registered with the flags asOBJ_APP_CLASS_C, not asOBJ_APP_CLASS_CK as it didn't have an explicit copy constructor.


When you explicitly declared the copy constructor in the Integer class the result was corrected as now the flag asOBJ_APP_CLASS_CK was correct.


If you're using a compiler with support for C++11 features (e.g. gnuc 4.7+, or MSVC 2012+), you can use the helper function GetTypeTraits<T>() to automatically determine the correct flags. For example:


#include <add_on/scripthelper/scripthelper.h>
r = _engine->RegisterObjectType("Integer", sizeof(Integer), asOBJ_VALUE | asOBJ_POD | GetTypeTraits<Integer>()); assert(r >= 0);


As for AngelScript calling or not calling the copy constructor, that is an optimization thing. There are still some places in the library where AngelScript will first create the object with the default constructor and then assign the value with the opAssign method. These are already on my to-do list to improve so that the copy constructor is called directly.



The btVector3 type has another trait that is not yet supported by AngelScript, and that is that the type is 16byte aligned (to optimize it for SIMD instructions). As such you cannot register this type as a value type. If you really want to use btVector3 directly in the scripts you need to register it as a scoped reference type, which will behave as a value type in the script, but is really allocated on the heap where it can be properly aligned to 16byte boundaries. Combine that with a memory pool for the allocation and deallocation of the vectors and you should not have any noticeable performance impacts.


Another option is that you avoid exposing the btVector3 type directly to the script, and instead use an ordinary unaligned structure for the vector3 type that the script will use. Of course, you will need to create wrappers for the functions that expect the btVector3 type, but hopefully you don't have too many of those exposed to the scripts.

#5090461 Reference Objects as Properties

Posted by on 30 August 2013 - 03:37 PM

asOBJ_GC is necessary if the object can form circular references that will not be resolved by the application.


The classes TypeA, TypeB, and TypeC in your example can't form any circular references, 


If TypeA could hold a pointer to TypeC too, then a circular reference could be formed between TypeA and TypeC. If the application doesn't keep track of these and resolve them itself then the asOBJ_GC flag and related behaviours are necessary to avoid memory leaks.

#5090409 Reference Objects as Properties

Posted by on 30 August 2013 - 11:39 AM

TypeB is complicated. TypeA is in this case used as a value type in C++ even though it is a reference type. Unless you implement the control to make sure TypeB stays alive as long as there are references to the member you'd do best not to expose this to the scripts at all. Instead I suggest that you use property accessors to allow the script to manipulate the TypeA member without directly accessing it.


For TypeC you're correct to use @. If you want to prevent that the pointer is reassigned, then ideally AngelScript should allow the member as &, but that is currently not supported. For now you'll need to use property accessors to make sure the script cannot reassign the handle. In this case you just need to expose a get accessor that returns the handle to the member.

#5088589 AngelScript 2.27.1 is here (so soon? yes)

Posted by on 23 August 2013 - 10:02 PM

Maybe not the same syntax, but I definitely have plans to add support for variadic functions in the future.

#5088221 AngelScript 2.27.1 is here (so soon? yes)

Posted by on 22 August 2013 - 04:56 PM

I'm working on improving the initialization lists. Not only will they be more efficient, but they will also be more versatile, and should allow AngelScript to be viable option for those looking for a script language to do a lot of data configuration.


Currently the initialization lists are very limited as the compiler is only able to use them via the index operator. It will then invoke the index operator for each element provided in the initialization list. This works well for ordinary arrays, but when you want something a little more complex, like a dictionary or grid of data, then the current solution doesn't work well at all.


With the new solution that I'm working on, the application will be able to define the pattern that the initialization list for a type must follow. The compiler will do the validation of this pattern at compile time, and will then provide a single buffer with all the data to the object constructor/factory. The object constructor can then parse this buffer to initialize the entire object before leaving.


The way the application will register the desired pattern will be something like this:


RegisterObjectBehaviour("array<T>", asBEHAVE_LIST_FACTORY, "array<T> @f() = {T repeat}", ...);

RegisterObjectBehaviour("dictionary", asBEHAVE_LIST_FACTORY, "dictionary @f() = {{string ?} repeat", ...);

RegisterObjectBehaviour("grid<T>", asBEHAVE_LIST_FACTORY, "grid<T> @f() = {{T repeat(x)} repeat}", ...);


For the array, the list will then be a list of values of the type T, e.g. {1, 2, 3, 4}

For the dictionary the list will be an array of key-value pairs, e.g. {{"car", @Car}, {"health", 23}}  

For the grid the list will be an array of arrays, where the compiler will guarantee that each row has the same amount of elements as the first one, e.g. {{0,1,2},{3,4,5},{6,7,8}}


I will take a while to have this implemented, and I may not be able to finish it all for version 2.28.0. For now I'm focusing on just implementing the way the buffer is initialized and then passed to the constructor. This may seem simple but I need to make sure the exception handler is capable of handling errors in the middle of the execution and also to have the offsets within the buffer adjusted properly when saving the bytecode to keep it platform independent.

#5086996 "global" and "static" module

Posted by on 18 August 2013 - 04:02 AM

You can use function imports to accomplish this.


In your "static" modules add the following:


import void def_item_drop_behavior() from "global";


When the application compiles the "static" modules it must call the method BindAllImportedFunctions on the module after the build completes.


You may also want to read up on shared entities, with which you can share classes and interfaces between modules so you don't have to work with just primitives and registered types in the imported functions.




#5086610 AngelScript 2.27.1 is here (so soon? yes)

Posted by on 16 August 2013 - 04:51 PM

This release of AngelScript is quite small as I wanted to get started on the next big update. Still, this version has a few bug fixes, a reduced memory footprint (especially for applications with a lot of registered functions), a new 'void' expression that can be used to skip output parameters in function calls, and finally the support for anonymous parameters with default arguments.





#5085067 Weird string crash.

Posted by on 11 August 2013 - 07:12 PM

The problem is with passing the string by value to application registered functions. When this is done AngelScript does a bitwise copy of the object to the stack in order to place the memory of object as the function expects it. Unfortunately Microsoft has in its "infinite wisdom" implemented a back-reference within the object to the object itself which doesn't get updated with the bitwise copy and thus points back to the memory location. It appears this back-reference is only there in debug mode, so it is obviously only used for debugging purposes.


Unfortunately this is not a problem that I can easily fix in AngelScript. Fortunately there is a quite easy work-around, and that is to change your functions to take the string by reference instead of by value.


void QuestData::SetQuestClass(const std::wstring &moduleName, const std::wstring &classname)
std::string modulenameAscii = WStringToString(moduleName);
std::string classnameAscii = WStringToString(classname);

r = scriptEngine->RegisterObjectMethod("QuestData", "void SetQuestClass(const string &in, const string &in)", asMETHOD(QuestData,SetQuestClass), asCALL_THISCALL); assert( r >= 0 );

#5081693 [Help] Need to know what is wrong.

Posted by on 30 July 2013 - 07:12 AM

Are you working on a Windows platform? If so you need to open the file in binary mode, i.e. fopen("bin.asc", "w+b") and fopen("bin.asc", "r+b"), otherwise bytes may be modified as Windows translates line break characters.


Let me know if that doesn't solve your problem and I'll investigate this closer.




#5081330 AngelScript 2.27.0 is out

Posted by on 28 July 2013 - 08:11 PM

A new version of the increasingly popular scripting library is available. As customary with the dot-zero releases I've made incremental changes to the interface to improve the usability of the library. A few methods that used type ids have been deprecated in favor of new methods that uses the asIObjectType instead.


The interface has gained methods for creating delegates from the application as well as inspecting existing delegates.


The existing methods for inspecting function argument types and return types can now indicate when an argument or return value is a const reference.


The garbage collector has been enhanced to keep a sequence number for added objects, and a method has been added to allow the application to enumerate the objects currently known to the garbage collector. The intention of this is to allow the application developers to better analyse the behaviour of the garbage collector so they can make the necessary tuning to get the best performance.


Last but definitely not least, the library has now received the support for weak references, thanks to a code contribution from vroad. Both script classes and application registered classes can provide weak references.