Jump to content

  • Log In with Google      Sign In   
  • Create Account

Andreas Jonsson

Member Since 26 Mar 2000
Offline Last Active Today, 12:13 PM

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

Posted by Andreas Jonsson 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 Andreas Jonsson 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 Andreas Jonsson 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 Andreas Jonsson 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.




#5080845 Interfaces and base classes

Posted by Andreas Jonsson on 26 July 2013 - 03:56 PM

No, a C++ class cannot derive from a script class, neither can a script class derive from a C++ class.


You can however provide a sharedAngelScript component base class that implements the desired binding mechanism to tie the script class to the C++ class. This shared class can then be derived by all the custom components.

#5078823 Detect if function argument is passed by reference

Posted by Andreas Jonsson on 18 July 2013 - 07:59 PM

GetParamTypeIdhas an optional output parameter 'flags'. That is what you need to determine if the argument is by reference or not.


'flags' is a bitmask with a combination of the enums asTM_INREF, asTM_OUTREF, or asTM_INOUTREF. The last one is equal to asTM_INREF|asTM_OUTREF.




#5078478 RegisterGlobalFunction returning script class

Posted by Andreas Jonsson on 17 July 2013 - 11:02 AM

It is possible for registered function to create and return script classes. Though you can't register the function with a declaration to return the class directly as the class type is not known at the time of registration. To solve this you can either register an interface that the script class must implement, or use the ScriptHandleadd-on to return a generic reference.



The manual has an article for how to use script classes from the application:




It ought to answer your questions. If not, please let me know so I can improve it.

#5078473 How to instantiate classes in script?

Posted by Andreas Jonsson on 17 July 2013 - 10:48 AM

SoulSharer is correct.


An object type cannot be both a value type and a reference type. They are mutually exclusive. Value types are allocated on the stack (or inline in objects if members of another type) and cannot outlive the scope in which they are declared. Reference types are allocated on the heap and will be kept alive until the last reference to them are removed.

#5077698 Delegates in AngelScript

Posted by Andreas Jonsson on 14 July 2013 - 03:37 PM

Hi vroad,


It took a while but I've finally reviewed your contribution carefully and I decided to include it with only a few minor adjustments to suit my own style. I've checked in the changes in revision 1666. I still have a few more changes to do, but I'm happy to say that weak references are now supported by AngelScript.


Thanks a lot for the contribution.




#5070875 asUnprepareMultithread

Posted by Andreas Jonsson on 18 June 2013 - 10:34 AM

The latter description is the correct one. asUnprepareMultithread should be called after the last engine has been released.


It is not absolutely necessary that the calls are made from the main thread, but it is easier to guarantee the correct order of execution if it is done that way.


I'll update the manual to correct this. Thanks for bringing it to my attention.




#5069864 How to...

Posted by Andreas Jonsson on 14 June 2013 - 03:59 PM

The CScriptHandle is meant to be used as a value type, so you should preferably store the CScriptHandle member by value rather than by pointer. Like this:


class Obj{
    CScriptHandle m_Handle;
    void SetScriptHandle(CScriptHandle &Handle){
      m_Handle = Handle;

    CScriptHandle &GetScriptHandle(void){
      return m_Handle;

//Registered like so:
ScriptEngine->RegisterObjectMethod("Obj", "void SetScriptHandle(const ref &in)", asMETHOD(Obj, SetScriptHandle), asCALL_THISCALL);
ScriptEngine->RegisterObjectMethod("Obj", "ref &GetScriptHandle()", asMETHOD(Obj, GetScriptHandle), asCALL_THISCALL);


In fact, you can expose the m_handle member directly as an object property, without the need for the Setter and Getter methods if you'd like:


ScriptEngine->RegistetObjectProperty("Obj", "ref @m_handle", asOFFSET(Obj, m_handle));


That would allow the script to manipulate it directly:


// AngelScript
class Data{
  int x;

void Func(Obj @A){
  Data @x = Data();
  x.x = 0;
  @A.m_handle = x;
  @x = cast<Data>(A.m_handle);




#5069638 [AngelScript 2.26.3] Global property issues [Solved]

Posted by Andreas Jonsson on 13 June 2013 - 09:43 PM

You can use the GetAddressOfGlobalVar() to inspect and modify the global variables like you found out. Just make sure you update the reference counters of the objects correctly.


int index = mod->GetGlobalVarIndexByName("topCloth");
GraphicsObject** adr = ((GraphicsObject**)mod->GetAddressOfGlobalVar(index));
if( *adr )
*adr = (GraphicsObject*)(topClothObject);
if( *adr )




#5064617 Initialization List

Posted by Andreas Jonsson on 24 May 2013 - 03:32 PM

I definitely plan to allow arbitrary objects to be initialized through initialization lists. It's not a trivial thing to implement though, and I currently have no estimate when I'll get to this.

I want to allow the application to register the different patterns that the initialization list must follow, so that the compiler can do most of the validation rather than the object doing it at run-time. E.g the Matrix class could be registered as taking only initialization lists with 4 float values, and the dictionary class can be registered to take lists with even number of values, and all even values must be of string type.

There are a lot of more things to think about. For example, the matrix type should preferably receive a pointer to the memory buffer rather than the index operator being called 4 times to set each element. The dictionary class on the other hand should receive each key/value pair together in the same call.

#5063999 AccessVersion

Posted by Andreas Jonsson on 22 May 2013 - 07:35 PM

I'll think about this suggestion of having a version alongside the access mask.


With the current implementation I believe I would solve your dilemma the following way:


1. Set up a main script engine with the full interface, i.e. with the latest version. This will be the script engine used for all script execution, but it will not be used for compiling scripts. Instead the scripts will be loaded from pre-compiled bytecode into this engine.


2. When compiling a script for a specific version, set up a separate engine with only the interface available for that particular version. Compile the script, then save the bytecode to memory, and finally load the bytecode into the main script engine where it will be executed.


Assuming each version only adds to the interface and never removes anything this will work well. You shouldn't see a noticeable delay with the saving and loading of the bytecode either as this is much much faster than the actual compilation.


The separate engine doesn't need to have access to the actual interface methods as it will never call them, so you'll be able to register this interface with dummy functions. You can even perform the compilation to bytecode in an offline compiler that can be completely separate from the rest of the game engine.


I suggest you take a look at the sample asbuild. It implements a generic offline compiler that can compile scripts for any application, assuming the interface is known in the form of a configuration file. (The configuration file can be created automatically from the application with a call to the helper function WriteConfigToFile)

#5062710 Global Variable Initialization Context

Posted by Andreas Jonsson on 17 May 2013 - 07:35 PM

You'll want to turn off the initialization of the global variables upon build, and then supply your own context when manually initalizing them.


engine->SetEngineProperty(asEP_INIT_GLOBAL_VARS_AFTER_BUILD, false);
module->Build(); // now the global variables won't be initialized
// Manually initialize the variables after the script has successfully completed the build
asIScriptContext *ctx = engine->CreateContext();
module->ResetGlobalVars(ctx); // now the global variables will be initialized using the supplied context that has the desired user data