Metadata in ScriptBuilder, splitting code in client-server architecture

Started by
11 comments, last by WitchLord 5 years, 11 months ago

Hello,

I'm working on a client-server architecture for my game and I'd like to reuse code as much as possible - while it may be possible to split server and client code into separate source files, it would be much easier to follow if I could somehow annotate methods and variables with meta data - which is what ScriptBuilder is already capable of. There are two problems to fully make use of it:

1) ScriptBuilder seems to only allow single [] metainfo - it can't collect all of them and put them into an array. I will look into the way to add this possibility - do you think it would make sense to include in ScriptBuilder, or I should keep it for myself? This change would allow to put metainfo in such way, which will be very useful for me:  (UPDATE: This may actually work, for some reason I think I was getting assert when "stacking" meta data, now I'm running it and it seems to gather them all, I'll see if it works till the point of fetching)
UPDATE2: It's partially possible - the data is there but it's getting lost when saving to the final meta-data map, because it's a map, so multiple values will get ignored when inserting. I'm checking if changing this storage to std::multimap and slightly changing retrieval methods wouldn't make it possible to have multiple metainfo.


[sync]
[persistent]
[doc="This is current amount of health points"]
int health;

2) Second thing is ability to annotate methods and vars as server or client-only. I know there is a possibility to leave some code out by using #ifdefs but this isn't pretty compared to doing it like this:


[sever-only]
void calculateDamage(Object@ target, Object@ attacker);

[client-only]
void spawnParticleEffect();

Unfortunately due to deferred way that metadata is gathered I have no idea if it's even possible to leave out certain method or variable during compilation based on what's marked as such in metainfo. But the final result would be including first method only when compiling on server and second only for client execution. Maybe someone has idea how to achieve this in some reasonable way - the fallback solution is just slapping tons of #ifs in each script, but per-method&variable approach would make it much cleaner.

Thanks!


Where are we and when are we and who are we?
How many people in how many places at how many times?
Advertisement

The current implementation in the CScriptBuilder add-on only accepts one [] block before each declaration. But the content of that block is free text so there is nothing stopping you from putting multiple meta-datas inside that block. Example: [sync, persistent] or perhaps [[sync] [persistent]]

As for using the meta-data to decide what to include in server side or client side is perfectly doable. However you'll have to change the code so that when it identifies that a function or class shouldn't be included it superficially parses the following entity to find the end of it and then replace everything up to that point with spaces.

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

You replied as I were typing some update :) So, I spent some time hacking ScriptBuilder and managed to add both functions, so storing multiple metadata per decl (I prefer non-nested syntax so each [] separately rather than braces inside braces, this is pretty trival because it already parses it, just needs different way of storing, as mentioned multimap instead of map) and adding special type of meta_data that allows excluding parts of the code. To make it more universal I think I will add some callback that can decide whether section should be skipped or not. Not sure how bulletproof it is yet, as I know very little about the way it parses, but it overrides methods, variables and global functions from what I checked, so almost all things that I need hidden. 

I downloaded SVN code and will do some changeset in case someone is interested. 


Where are we and when are we and who are we?
How many people in how many places at how many times?

Sounda good. I should be able to incorporate these changes into the add-on without causing any trouble for exusting users.

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

Trying it now with most recent source as it seems that something changed in the way declarations are looked up. Will let you know when I have something ready to show.


Where are we and when are we and who are we?
How many people in how many places at how many times?

I managed to rewrite how metadata is extracted, seems to work but needs more testing. It now returns std::vector<std::string> for metadata instead of just single string and allows storing unlimited number of metadatas per type. I'm right now investigating how *mixin class* behaves, as when I included file with a defined mixin and that mixin has metadata on one of the properties, it seems to break on compilation try. Considering such mixin is included, I'm not really sure this goes through metadata extraction - checking right now when include mechanism kicks in and if it's after or before extraction.

@WitchLord how are mixins treated internally? As I assume they may not exist as a type? Right now it seems that extracting part is missing mixin decls from metadata extraction, but after I started thinking about it I'm not sure it's even possible to have metadata for mixin? It would make sense from class that implements mixin as it basically inherits its properties (which can have metadata), but not sure it's possible right now. 


Where are we and when are we and who are we?
How many people in how many places at how many times?

mixin's are just pieces of code that gets merged into whatever class that uses them. They do not exist as stand-alone types. After compiling the script the mixin's do not exists any longer.

metadata for mixins is not possibly with the current implementation. But if you wish to implement it, it would require keeping track of the mixin's metadata, and then find the classes that includes the mixins so the metadata can be copied to these ones.

 

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

Thanks - I will try, though it may be just easier to accept mixins can't have metadata :) I will see if this will lead anywhere.

One question because it's not clear to me - metadata will be saved for a class it's been defined in, so if I have Foo < Bar and I have property with metaclass in Bar it won't show up when I iterate properties of Foo, even if the property itself is listed? So to gether all metadatas, I'll need to go down the inheritance tree and check all properties on each following type, right?


Where are we and when are we and who are we?
How many people in how many places at how many times?

Yes. with the current implementation you would have to go down the inheritance tree to look for metadata in parent classes,

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

Ok, I also found some small bugs like not taking into account keywords like shared and abstract when extracting metadata, so this skipped such classes and never found the metadata for them. I'm not sure if the "stacked" metadata functionality will be of any use to anyone and if it's worth adding to the default builder - I definitely need a lot of metadata for my client/server annotations (synchronizing state, persisting - I want it all defined in a most convenient and readable way, which happens to be metadata) so I will keep these changes locally. 

I attach a changeset it if you want to have a look into my solution - I'm not really experienced in parsing, so this may be a bit hacky, but I tried to make it robust and as generic as possible. It won't be backwards compatible because it makes no sense to keep the const char* methods for accessing metadata (although they can remain as wrappers to new methods, which just call the new ones and extract first element of the vector, this would allow to keep this backwards compat) when I added a generic solution that works for 0..n metadata strings. I also tried to avoid C++11+ features, just in case you'd like to use some of this code. Makes these loops pretty ugly and verbose, could be cleaned a bit with some typedefs though. 

Btw, it's been AGES since I used SVN, I'm so used to GIT workflow now I actually didn't even realize that comitting to SVN repo pushes this to remote :D As I have no idea how to collaborate using this VCS, I'm just attaching changeset - mind that it's not final and still trying to make it better and finding some edge cases where metadata is not properly recognized. Would love to hear what you think.

Maybe it would make more sense to use different container than multimap, but I went for the quickest solution which didn't involve bigger refactoring of how metadata is inserted into these maps.

PS. Sorry for some messed up indentation in patch, I use spaces and it seems AS uses tabs, I did re-convert back to tabs but seems like some indents are now wrong after that.

metadata_changes_v1.patch


Where are we and when are we and who are we?
How many people in how many places at how many times?

This topic is closed to new replies.

Advertisement