8th July 2019
Since the last devlog, we have a UI framework ready to render our VCS docks in the editor and an Editor interface to the VCS in use is at its place as one of the vertical slices of the VCS integration framework.
The last couple of weeks, I have been studying GDNative, how other people use it and tried to replicate that workflow to suit our need further. However I haven't had any successes with getting the Git API registered to Godot from GDNative.
What we want to achieve is to successfully redirect function calls made to the
EditorVCSInterface from the rest of the Godot Editor to our actual VCS API implementation present as a GDNative plugin. When I say 'plugin', I will be referring to the editor plugin facilitating all the VCS talks coming forward, 'vcs interface' refers to the VCS agnostic API available to Godot for usage, and 'addon' refers to the GDNative supported implementation of vcs interface API for talking to a specified VCS.
EditorVCSInterface is the holy grail of all VCS related information required for the editor.
GitAPI is the extension of
EditorVCSInterface to override some specific functions that override the default interaction to the actual VCS of the project. Think of
EditorVCSInterface as the API and
GitAPI as one of its implementations written for interacting to Git controlled projects.
Below are a few of the approaches I have tested.
GitAPIthrough GDNative bindings.
This is one of the best ways to implement this workflow because this allows the user to swap in and out the specific VCS interaction they want for their project. You don't need the SVN implementation if you are working with Git.
However, this requires one to create GDNative bindings for all of the
EditorVCSInterfaceplus some added bindings to let Godot know about the new interaction API. My first objective was to get this up and running as soon as possible and then expand on it further. However, I found that overloading virtual functions from GDNative requires a bit more insight into how GDNative works. I was able to get the bindings generated from Godot and use custom bindings in my addon (GDNative addon) but the bindings had some specifiers missing like the
virtualkeyword, and it also didn't seem intuitive to be able to fully inherit some class in Godot by only specifying its public interface i.e. since private members and special members like function pointers etc. were not being recorded in the bindings, it was impossible to cast the addon class,
GitAPIto the Godot version of
I still see this as the best option to move forward, however, this is something I was trying to get to work for a lot of time. So for the time being, I tried out something different.
calls from the VCS interface that are executed in the GDNative plugin
This was our fallback plan if anything goes wrong in the previous method. If we had a
EditorVCSInterface::get_vcs_name()then it would simply return the variant we had acquired from a call to
GitAPI::_get_vcs_name()which should actually return
"Git". However, the call context couldn't find
_get_vcs_name()because it was only looking for it in
EditorVCSInterface's functions and not the other registered classes like
GitAPI, which is not what we wanted it to do.
This could be fixed by creating a reference to
EditorVCSInterfacejust like a singleton but this meant we were back at where we left in the previous method. So I tried something similar to creating my own vtable.
Defining function pointers in a struct that is populated by the GDNative addon
This one is the closest to being called as a hand-made vtable. My motive was to pass function pointers to the actual functions implementing the API but the downfall of this architecture was quickly realised because I needed to ensure the consistency of the members of the struct at both ends manually. I could see this becoming a hacky solution because at some point I would be forced to sync the offsets of these members by hand which is not something people will consider maintainable or even practical once the API largens.
However this also gave be some insight on how OpenVR and PluginScript have been implemented. These GDNative plugins have a dedicated handler for this struct at both sides and it is easily reflected in the implementations already present in 3.2 master. Finally I could see this method being another variant of how OpenVR has been implemented.
Not using GDNative for API development
This does not mean that the implementation won't be a GDNative implementation. This is a contingency plan for implementing the core of the project first and not worry about the porting, which can also be done later on. Currently, with the amount of time I have spent on figuring a way out, this method seems better just because it takes me to the hard part of the project quicker than any other method. Also the porting over to GDNative can also be done later when the integration with Git is minimally complete.
Finally, we have decided upon creating the API implementation in Godot itself, while ensuring a VCS agnostic API available to Godot at all times, and later think about porting it to GDNative.
Hopefully this entry explains the rationale behind this decision.