-
Notifications
You must be signed in to change notification settings - Fork 162
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
AGS 4: Implement script RTTI #1922
AGS 4: Implement script RTTI #1922
Conversation
d076b7a
to
41fde01
Compare
I decided to do some refactor on this pr, because in the current variant the RTTI struct has too many internal "mechanics" exposed, so it's too easy to produce an invalid state (and there's code duplication too). |
030cfdd
to
840fe39
Compare
Added a separate "locations" table. Now the fully qualified type's name is generated at runtime by combining location's name and type's name. |
Does this PR have any impact on script performance? |
A little longer script saving and loading. I was planning to make one last refactor tbh in the nearest days (I got distracted by the latest 3.6.0 bugs), because I put everything in script.h/cpp, and one class may be split into two for more consistent behavior, but this may also be done later too. |
The script writing was reimplemented in the managed code (C++ CLR) in c5c7c87 , but this is quite inconvenient, as there's a script serialization code in the native part which is still used by the compiled room serialization code, and thus we'd have to duplicate any additions in native and managed code in parallel. This change removes managed reimplementation, and makes CompiledScript::Write use native serialization instead. Because the scripts are written in the middle of the compiled game format, which is serialized by the managed code too, we cannot use same stream object directly. There are two options: 1) Write to a temp file using native stream, then copy file contents to the provided managed stream. 2) Write to a native membuf, then copy buf's contents to the managed stream (might require conversion, or marshaling). I implemented this using a temp file for now. If this proves to be slow with large number of scripts, we may switch to using memory buffer (and memory stream) instead.
fd7fd67
to
8a6cf80
Compare
TODO: section names are missing, so fully qualified type names are not yet available.
Okay, I think this is done. I had doubts about how the structs are organized, but I am maybe overthinking again, and it should not be impossible to refactor into something more convenient (if a need arises). The serialization format is something I am certain about though. As been mentioned, it's possible to completely disable rtti generation by toggling a compiler option. Engine can load scripts both with and without rtti. |
Resolves #1259.
CC @fernewelten , because he is working on a new script compiler, and I added few functions to it.
The detailed description of the purpose is given in the task ticket #1259, here I will give a brief overview.
There are several potential operations within the script interpreter that are impossible to achieve without having an indication and description of object's type and its inner contents:
Following actions would be also potentially easier to implement if we had type indication and content description:
This is where RTTI feature comes from. The idea is to have a table of types and their contents, generated by the script compiler as an extra step, and written either as an extra (optional) part of a script data, or a separate file along with the game project.
This PR does the following:
--print-rtti
command arg is useful for testing the resulting RTTI table.Additionally, engine also creates "quick references" within the gathered RTTI, which is basically pointers between type and field structs. This allows for easier traversing of types and respective fields under the debugger.
Generation
Currently the type information consists of an ID, a name, a location (where this type was declared), a parent's ID (if it has a parent), a set of flags which define type's kind, and a collection of fields.
The fully qualified type's name may be generated by combining a location's name (usually header or script name) and a type's name. This is required to be able to distinguish potential unrelated types of same names declared in different scripts.
Fields info contains: relative offset, name, typeid, and a set of flags which define field's kind and qualifiers.
The gathered data may be easily expanded in the future (also see notes to the serialization).
Compilers generate RTTI per each compiled script unit. Because of that the type's ID is a local ID, which is relative to this compiled unit only. The engine will have to use fully qualified names to map script's local ID with a global ID in a joint table.
Serialization
The RTTI serialization format is designed having ease of expansion in mind. For that purpose it is not done as a single table with types and nested field items inside, but as a number of separate tables, where each table's entry has a fixed size. The RTTI header describes tables' offsets, and the fixed sizes of their items. The tables are connected using index references (meaning, an item in table 1 may refer to an item in table 2 using its index).
The advantages of such structure are:
Following is a format description.
RTTI header
RTTI tables
Location description
Type description
Field description
TODO
--print-rtti
output.