Jump to content

  • Log In with Google      Sign In   
  • Create Account

Andreas Jonsson

Member Since 26 Mar 2000
Offline Last Active Jun 26 2016 07:05 PM

#5271553 Sharing modules (but not globally)

Posted by Andreas Jonsson on 17 January 2016 - 09:28 AM

An already compiled script module can be appended with new global functions and global variables through the use of asIScriptModule::CompileFunction and CompileGlobalVar, but it is not possible to append arbitrary scripts that may contain multiple functions, classes, etc.


Even if it was possible to append to an existing module (which is actually something I already have on my to-do list), I'm not sure it would be easy to remove part of the module when your GUI loaded a different document. How should the application or script engine know what should be removed?




Perhaps you could do something like this:


1. When loadDocument is called

2. Application serializes any existing objects, values in the module (i.e. store a backup)

3. Create a new module

4. Add the original "inventory.as" script, plus all the embedded script sections from the XML

5. Compile the module

6. If the compilation is successful, restore (deserialize) the objects and values from the previous backup



This is often known as 'hot loading' modified scripts, and normally used to allow the source code to be modified on-the-fly, but should work perfectly in your case too. The serializer add-on can be used to make the backup of values and objects and then restore them.

#5271267 Lambdas/Anon.Functions: Status, implementation

Posted by Andreas Jonsson on 15 January 2016 - 07:29 AM

Hi Ingwie. Welcome to the forum! :)


Yes. anonymous functions, a.k.a. lambdas, are now supported by AngelScript (since the last public release, 2.30.2).


Implementation wise, they are just ordinary script functions and can be passed to the application as a function pointer the same way. The function pointer is represented by the asIScriptFunction interface to the application. Using the function pointer it can be called using the script context normally.


The manual has an article that shows how to pass a function pointer to the application and then calling it.




#5268242 Accessing an object managed by the engine through a global variable

Posted by Andreas Jonsson on 28 December 2015 - 06:43 PM

What about setting the value of the global parameter through GetAddressOfGlobalVar() like I showed you above? Is that okay? And is the global variable still allowed to be a handle even though the object type is not garbage collected?


Yes. This is the correct way of doing it.


asOBJ_NOCOUNT just means that the type doesn't rely on reference counting for controlling the lifetime of the objects, it doesn't mean that the types cannot be references through handles (which in this case behave pretty much the same way as ordinary pointers in C++).


Had the type been reference counted, you would still use GetAddressOfGlobalVar() to set the value, but you would have to take care to call Release on the previous object and AddRef on the new object when changing the address.

#5268202 Accessing an object managed by the engine through a global variable

Posted by Andreas Jonsson on 28 December 2015 - 10:42 AM

What you've done is perfectly fine if you trust the script writers not to do something unexpected with the ScriptComponent reference. For example, if the script store a reference to the ScriptComponent in some other variable for use at a later time. That might end up causing crashes due to dangling pointers if the script tries to access the object after it has been destroyed in the game engine. 


If you do not trust the script writers, e.g. if you plan to allow end users to write their own scripts, then you may want to use a little more secure way of managing your pointers, e.g. add proper reference counting in the objects to make sure they aren't destroyed while there are still active references to them, and probably also use weak-references to avoid keeping objects alive longer than necessary.

#5265294 Array doesn't properly document find and findByRef

Posted by Andreas Jonsson on 07 December 2015 - 11:53 AM

Thanks. I'll make the necessary adjustments.

#5264130 Support for unicode identifiers

Posted by Andreas Jonsson on 29 November 2015 - 12:13 PM

Having the tokenizer call a callback for every identifier would probably impact the compiler performance quite a bit for everyone, even those who would not use the callback.  


Instead I suggest you modify the CScriptBuilder add-on to translate special identifiers to keywords before passing the script to the compiler. The CScriptBuilder already has logic for doing a pre-compile pass on the code script and change some things, so it should be quite easy for you to implement that on your own.


Alternatively you can customize the asCTokenizer to translate the special identifiers for you.

#5260114 Support for unicode identifiers

Posted by Andreas Jonsson on 02 November 2015 - 08:20 AM

I've implemented support for this in revision 2248.


You turn on the support for unicode in identifiers with engine->SetEngineProperty(asEP_ALLOW_UNICODE_IDENTIFIERS, true);




#5259346 Factory Functions

Posted by Andreas Jonsson on 27 October 2015 - 07:04 PM

instance = *((asIscriptObject**)asEngine->CreateScriptObject(ctrl->type));


This should be instance = (asIScriptObject*)asEngine->CreateScriptObject(ctrl->type);



instance->AddRef(); // this throws a null pointer error and crashes the program


This shouldn't be done. The pointer returned by CreateScriptObject already has one reference counted for, which is owned by the application that called CreateScriptObject. When you are done with the object you should call instance->Release() to free the memory.



On a side note, i would like the CGameObj  @self; link to be seamless, would it be better to define this inside the game code as a base class rather than using a interface.


I didn't quite understand your question. Do you want that the script writer doesn't have to declare CGameObj @self in the script class? If so, yes you can have the application implement a base class that all scripts controllers must inherit from instead of the controller interface.

#5259204 Factory Functions

Posted by Andreas Jonsson on 26 October 2015 - 04:16 PM

If the class doesn't define any constructor at all, then it will get a default constructor. asIScriptEngine::CreateScriptObject can be used to create instances of classes that have default constructors (or you can manually call the default factory). The application can then call the Start method on the class that the user defined.


When deserializing a script object you should preferably use the method asIScriptEngine::CreateUninitializedScriptObject. The method will basically just allocate the necessary memory, but will not call any of the class' constructors. Once created the application should enumerate the properties of the object and set the value of each of them to whatever was serialized before.

#5257715 Patch proposal for scriptany add-on issue

Posted by Andreas Jonsson on 17 October 2015 - 03:35 PM

I've fixed this in revision 2243.




#5252806 object function and variable list

Posted by Andreas Jonsson on 17 September 2015 - 08:54 PM

You'd use the asIObjectType interface to inspect the declaration of object properties, and asIScriptObject to get/set the values of the object properties.


The serializer add-on may be of help getting your save system working. 


You may also find the article on Reflection of interest.




#5252703 *.fnt files and Game Maker Studio

Posted by Andreas Jonsson on 17 September 2015 - 12:04 PM

xadvance is how much the cursor should be advanced after rendering the character before rendering the next character. It is unrelated to the xoffset, x and width values. Note, that kerning pairs alter this value for specific combinations of characters as determined by the font designer.


xoffset and yoffset are the offsets from the current position where the character quad should be rendered. xoffset is usually near 0, unless the character is designed to have an overlap with previous character (negative xoffset) or have extra spacing between previous character (positive xoffset). As yoffset is the distance from the top of the line to the top of the quad, it will have a higher value for smaller characters, e.g. capital A (id 65) has a small yoffset, and small a (id 97) has a larger yoffset, underline _ (id 95) has an even larger yoffset.


width and height give the size of the quad that should be rendered.


x and y show the position in the texture where the character should be copied from when rendering it.




I'm not sure what format and layout that Game Maker requires for its bitmap fonts, so I can't say what you need to do to transform the BMFont format into the Game Maker format.


I think you would benefit from taking a look at how fonts are actually rendered directly from the BMFont format. Take a look at the various tutorials and resouces that I link to from my site. Hopefully by seeing the code it will be easier for you to figure what needs to be done to transform the format.

#5252593 *.fnt files and Game Maker Studio

Posted by Andreas Jonsson on 16 September 2015 - 08:37 PM

I didn't even know of the Littera web app, much less that it exported fonts in the same format that I came up with for BMFont long back. biggrin.png


I'll gladly link to your project for converting the png+fnt BMFont format into the Game Maker format from my site. I'm sure others will be interested in using it too.

#5250697 How is cast<T>() registered?

Posted by Andreas Jonsson on 05 September 2015 - 10:22 AM

cast<T>() is not registered. This is a built-in function, and serves the same purpose as dynamic_cast<T>() in C++.


You can implement the opImplConv overload in the typeof<T>() class to allow it to be implicitly converted to the Type object.


You may want to take a look at this post. cvet has already implemented and shared code that does exactly what you want.

#5250338 Would this be misuse of aslScriptContext::Suspend()?

Posted by Andreas Jonsson on 02 September 2015 - 04:48 PM

A) This is a perfectly valid use case. Using this script engine like this can be thought of a form of coroutine. Just remember that it is currently not possible to serialize a context's state, so if you plan on allowing the user to save the game in the middle of a playthrough with coroutines still running you'll face trouble.


B) You'll probably be fine with 50 something contexts. Expect each context to take up a few KB of memory. If you're targeting platforms with limited amount of memory you can tweak the amount of memory that is allocated for the callstack in the contexts by setting the engine property asEP_MAX_STACK_SIZE.


C) Take a look at the code for the ExecuteString helper function. It is a good place to start, but you'll likely want to make some adaptions to suite your own specific needs. For example, resuming the context after it has been suspended. By default the function doesn't support resuming, since it discards the script code before returning.


D) Yes, PushState/PopState can be used to call the different script. Though, obviously you cannot resume the original script before the called script finishes if you do.