Advertisement

Yet another C++ object instantiation question

Started by March 13, 2017 06:07 PM
5 comments, last by Solokiller 7 years, 8 months ago

[EDIT: March 14, 2017

I am very impressed with SamVanheer's (known as SoloKiller on this forum) AngelscriptUtils. I think it should be part of the Angelscript source. Using AngelscriptUtils I was able to easily implement C++ inheritance and event subscription, among other things.

AngelscriptUtils came from this thread:

https://www.gamedev.net/topic/680409-inheritance-from-internal-c-classes/

And on github: https://github.com/SamVanheer/AngelscriptUtils]

So I am presently determining how to best implement angelscript into a project. I've examined and torn apart the game example and fully understand how the script objects get a "self" object that refers back to a C++ instantiated object. Based on other posts from this forum I also understand you can hide the 'self' object by having a script proxy class that provides interfaces to 'self' without a script writer needing to understand the underlying mechanics.

However, I find myself not particularly excited with the game example approach as I'd like to enforce method constraints at the C++ level. What I mean to say is I want to have base C++ classes which are inherited by the script objects, with the C++ classes defining the various required member functions. I found documentation to this end within the help file, but, it has me wondering the following:

  1. What is the draw backs to having script objects inherit the C++ objects? Particularly when it comes to performance and memory with thousands of script modules loaded. On the C++ side i will need to perform a lot of lookups on 30k+ objects and it seems rather inefficient to perform a getmodule() call every time I need to find a particular object. The Game Example approach does a better job of this by providing a C++ pointer to each object that I could store and lookup efficiently.
  2. So with that said..What are the best practices for ensuring that I can have 30k modules loaded and easily traversed?

Thanks!

Having script classes "inherit" from C++ classes, is a low-level very similar to what the Game sample does. The difference is mostly that the interaction between the script class and the C++ class will be more hidden to the script writer.

As for recomendations. Avoid using 1 module for each object in your game. If two objects use the same scripts they should preferrably share the same module. Otherwise you will have a lot of unnecessary overhead with building the scripts for each object, keeping a copy of the compiled bytecode for each object, etc.

Yes, Solokiller's AngelScriptUtils library is very impressive, and I keep a link to it from my page "Further resources & support" so more people can find it. I have no intention of incorporating it into the core AngelScript library though. Not because I don't like it, but because I want to concentrate on the core, and not the surroundings. The add-ons I include in the AngelScript library are more intented to serve as starting point for application developers than to be used as-is. Application developers are encouraged to make their own custom integration with the application to best serve the purpose of each application.

Regards,
Andreas

AngelCode.com - game development and more - Reference DB - game developer references
AngelScript - free scripting library - BMFont - free bitmap font generator - Tower - free puzzle game

Advertisement

Having script classes "inherit" from C++ classes, is a low-level very similar to what the Game sample does. The difference is mostly that the interaction between the script class and the C++ class will be more hidden to the script writer.

As for recomendations. Avoid using 1 module for each object in your game. If two objects use the same scripts they should preferrably share the same module. Otherwise you will have a lot of unnecessary overhead with building the scripts for each object, keeping a copy of the compiled bytecode for each object, etc.

Yes, Solokiller's AngelScriptUtils library is very impressive, and I keep a link to it from my page "Further resources & support" so more people can find it. I have no intention of incorporating it into the core AngelScript library though. Not because I don't like it, but because I want to concentrate on the core, and not the surroundings. The add-ons I include in the AngelScript library are more intented to serve as starting point for application developers than to be used as-is. Application developers are encouraged to make their own custom integration with the application to best serve the purpose of each application.

Regards,
Andreas

I had not seen the 'Further resources & support' section. But I will be visiting it soon.

Re: inclusion of AngelscriptUtils in the angelscript source, I completely understand your desire to focus on the core. At the end of the day these peripheral projects should be maintained outside of the mainline trunk as you shouldn't be responsible for keeping everything compatible.. which is to say you should just be concerned with changes to the core without worrying about whether AngelscriptUtils will build/play nice.

On a completely different note, angelscript is exactly what I was looking for when I set out to write a mudlib from the ground up. It gives me the closest 'feel' to an LPmud driver-esque scripting engine while going further with object oriented support. I am extremely impressed. Also, I ran some ad-hoc performance tests last night with 10k modules loaded (using AngelscriptUtils as a test wrapper), and performance is very reasonable even with a debugger attached.

As for recomendations. Avoid using 1 module for each object in your game. If two objects use the same scripts they should preferrably share the same module. Otherwise you will have a lot of unnecessary overhead with building the scripts for each object, keeping a copy of the compiled bytecode for each object, etc.

I need to ask you a follow-up to your suggestion. On my mud I want creators/wizards to have the ability to make new rooms and 'compile' them into the driver to then test them out. To this end, each room is it's own .as file. This ensures that everything to do with a given room is encapsulated into a single script. But this will also result in the presence of many, many rooms being loaded as separate modules over time.. which is something you suggest I avoid.

So my question is how do I have 1 module load N number of rooms when each room is essentially its own program. What I mean by that is that each room has its own periodic events, state machines, I suppose as I sit here and consider the problem I could have 1 module that instantiates N number of room objects (using AddScriptSection()) and can call an interface method like 'DoWork' or 'Think' for each of the room objects to allow them to update their state/perform timed events etc. This would allow me to load each room script into that one module while maintaining each room as a separate script file.

But then the issue with that approach is that within each room script a class would need to be defined with a unique name relative to the other room scripts.. which would be cumbersome for creators to remember/implement. I suppose the way around that is via pre-processing of the room script files to append a unique portion on to each room class name so CRoom would become CRoomXxx with Xxx being perhaps the filename of the room script or something like that. Another issue is how to perform hot reload of rooms selectively when a creator makes a change and wants to test it out (or remove a room entirely).

I can't quite wrap my brain on how to avoid loading each room as a separate module. Any advice here?

Hmm. I'm not too familiar with how MUDs work. My only contact with MUDs was very brief in the computer labs at my university some 20 years ago, and I never really got into it, though it was quite popular among my friends.

Given your description, I take back my recommendation. :) In your particular case you'll be better off having a separate module for each room just as you had imagined from the start. I'd would imagine that very few rooms would have identical scripts, so the condition "If two objects use the same scripts they should preferably share the same module" in my previous recommendation wouldn't be true anyway.

Each module is independent, so hot-loading a module when the code is changed is relatively simple. You would just have to implement a method for serializing the current state. The serializer add-on can provide some help on that, though you'll probably still have to adapt it to your reality.

On a completely different note, angelscript is exactly what I was looking for when I set out to write a mudlib from the ground up. It gives me the closest 'feel' to an LPmud driver-esque scripting engine while going further with object oriented support. I am extremely impressed. Also, I ran some ad-hoc performance tests last night with 10k modules loaded (using AngelscriptUtils as a test wrapper), and performance is very reasonable even with a debugger attached.

Thanks for the kind words.

Please feel free to let me know if you encounter any performance issues, or hit any other restrictions in the library. If you happen to have a profiler of any kind it would be very useful too what bottlenecks it identifies in your application.

Your use-case is quite different from anything I imagined when designing AngelScript, so it wouldn't surprise me if you would encounter some issues due to the high number of different modules. But I'm always on the lookout for improvements that can be made, so I let me know and I'll see what I can do to fix the problems you may encounter.

Regards,
Andreas

AngelCode.com - game development and more - Reference DB - game developer references
AngelScript - free scripting library - BMFont - free bitmap font generator - Tower - free puzzle game

Hmm. I'm not too familiar with how MUDs work. My only contact with MUDs was very brief in the computer labs at my university some 20 years ago, and I never really got into it, though it was quite popular among my friends.

Given your description, I take back my recommendation. :) In your particular case you'll be better off having a separate module for each room just as you had imagined from the start. I'd would imagine that very few rooms would have identical scripts, so the condition "If two objects use the same scripts they should preferably share the same module" in my previous recommendation wouldn't be true anyway.

Each module is independent, so hot-loading a module when the code is changed is relatively simple. You would just have to implement a method for serializing the current state. The serializer add-on can provide some help on that, though you'll probably still have to adapt it to your reality.

On a completely different note, angelscript is exactly what I was looking for when I set out to write a mudlib from the ground up. It gives me the closest 'feel' to an LPmud driver-esque scripting engine while going further with object oriented support. I am extremely impressed. Also, I ran some ad-hoc performance tests last night with 10k modules loaded (using AngelscriptUtils as a test wrapper), and performance is very reasonable even with a debugger attached.

Thanks for the kind words.

Please feel free to let me know if you encounter any performance issues, or hit any other restrictions in the library. If you happen to have a profiler of any kind it would be very useful too what bottlenecks it identifies in your application.

Your use-case is quite different from anything I imagined when designing AngelScript, so it wouldn't surprise me if you would encounter some issues due to the high number of different modules. But I'm always on the lookout for improvements that can be made, so I let me know and I'll see what I can do to fix the problems you may encounter.

Regards,
Andreas

What is ironic is that I thought Angelscript was tailored to text games, particularly so because of the game example provided in the source. But even without a conscious effort on your part to make it mud-friendly it appears to have everything needed. Scale will certainly be an issue, and I'll keep you informed as to any bottlenecks that I encounter.

Advertisement

I'm glad you like my work, but some of the stuff in AngelscriptUtils is not yet finalized. I've been working on a tool that aims to automate the generation of C++ wrapper classes for inheritance.

It would eliminate some of the lookup issues by performing them up front. The idea is that required methods (pure virtual) and commonly called methods (e.g. GetPosition()) would always be looked up, rarely called ones would be looked up on demand to reduce memory usage in terms of caching. By automating it it would make it easy to use with little to no overhead (no hash map of functions to cache things, just a member variable), you'd simply add an annotation to indicate the usage and the generator does the rest.

I'm using CMake to help with this by using its JSON compile commands database to process a codebase and extract the information, in addition to XML config file provided alternative annotations. Most of the inheritance code would thus become autogenerated, using Mustache templates to provide the class layout. libClang does the work of processing the codebase.

I was also thinking of generating function calls at compile time using C++11 variadic templates combined with template overloads for classes that provide metadata for application registered types, which would also be autogenerated. At compile time, the function would know that a CBaseEntity* is a reference type with no reference counter, that Vector& is a value type, etc.

AngelscriptUtils itself is intended to be more of a starter's kit than a fully functional implementation. You can easily implement Angelscript with it, but eventually you'll have to replace it with purpose built systems when you need more specific features. The features provided are designed to be usable on their own when possible, but that may not always make them applicable to your use cases.

I'd like to see built-in support for inheritance as well, but it's not always possible to integrate that into existing codebases. For example, i implemented it in the GoldSource engine, which has entity classes that have a rigid construction method that isn't easily adapted to Angelscript. I had to use the template based inheritance pattern to insert Angelscript support for every class that needs to be inherited from, and manually write every overrideable method, which is pretty painstaking and error prone.

That's why i chose to focus on automated code generation, it eliminates most of the problems right off the bat, handles every edge case (e.g. converting std::string to char*) and lets you insert debug code to test things at runtime to validate that the usages of the generated code are correct.

For example, even if you use a variadic function to set up a context for execution with compile time deduction, it won't prevent you from calling a function or method with a different signature than what you passed into the helper. That can only be validated using either a preprocessing tool (verify that the given function matches the given arguments, only possible if the function's signature is known at compile time) or by validating the call at runtime.

Automating it also has a major benefit in that you can extract documentation and generate API information from it. The tool would generate the adapter classes, and generate a list of all methods complete with the changes made to make them compatible with Angelscript. A method that takes a const char* would take const string& in in a script class, so the tool would transform the call and properly handle those calls. The documentation would be based off of libClang's Doxygen documentation interface output, transformed to match the parameter changes.

It would then be output to an XML file, which can be fed as input to any program that can transform that data. I was thinking of writing a program that uses Mustache templates to generate HTML, text and Markdown versions for use on websites, minified documentation and Github wikis, respectively.

I haven't had the time to work this stuff out yet since i've taken a break from programming, but if you think you can make it work, it's possible.

This topic is closed to new replies.

Advertisement