In the past few weeks, I was rewriting my toy engine. During the rewrite of the tools, I want to try out the Client/Server Tools Architecture that used in Insomniac Games because this architecture has a benefit that it is crash proofing and have "free" undo/redo. My tools is built using C# instead of web-apps like Insomniac Games because there are not much resources about it on the internet as they said. I don't want to spend lots of time to solve some tricky problems in my hobby project and instead focus on graphics programming after the tools are done. Currently only material editor, model editor and asset browser are implemented.
Screen shot showing all the editors |
Overview
The client/server architecture for tools is that, all the editors are clients and need to connect to the server to perform editing. All the editing states about a file are maintain in the server. The client/server communicate by sending/receiving JSON messages (which is easy and fast to parse) such as:
{
"message type" : "load file",
" file path" : "package/default.texture"
}
The client will send request to the server such as loading a file (all the assets are in JSON format such as mesh exported from Maya) and the server will reply with the appropriate response such as the loaded file, or whether the request operation is successful. If there is no client request, the server will do nothing, the clients will keep polling about the change of the editing state. My tools are designed both the client and server are run on the same machine and can run without internet connection.
The Server
The server is responsible for handling a set of client request such as create a new JSON file, load file, save file, change file... The server maintains the opened JSON files that loaded/created by the clients. An undo/redo queue is associate with each opened JSON file in the server. When client send a request to modify a JSON file, the inverse change operation is computed and stored in the undo/redo queue. So if the client program crash, all the editing states including the undo/redo queue will not be lost as they are stored in the server.
The editor launcher which runs the server in the background |
The Clients
All the editors are implemented as a client which need to connect to the server to perform editing. Each editor is a small application that perform only a specific task and they will keep polling changes from the server. Below shows the asset browser of the editor which is also a client program. The asset browser is used to import assets such as mesh, texture and surface shader. Also, it can change the loaded assets package directory and the current working directory by modifying the corresponding JSON file in the server so that other editor will know about the change. Besides, assets can be drag and drop to other editors which specific the relative path of the assets inside a package and other editors can get the assets from the server.
The asset browser, importing a texture |
The 3D viewport is logically separate from the user interface |
User is offered a last chance to undo the operation before the crash |
Delta JSON
For the client to communicate with the server about the file changes(poll changes/make changes), delta JSON is used. The delta JSON I used is similar to the one used in Client/Server Tools Architecture. For example, we have a material file "package/default.material" like:
{
"diffuse color" : "red",
"specular color" : "white",
"glossiness" : 0.5
}
To change the diffuse color to blue in the above file, a delta JSON message will be sent to the server:
{
"message type" : "delta changes",
"file" : "package/default.material",
"delta changes" :
[
{
"key" : "diffuse color",
"value" : "blue"
}
]
}
When the server receive the above message, it will change the "package/default.material" file, and at the same time, the server will compute the inverse of the delta change, i.e.
{
"key" : "diffuse color",
"value" : "red"
}
so that undo can be performed. Note that the delta changes is contained in the array of a JSON message since more than 1 change operation can be performed and all of the changes in a single message will be considered as an "atomic operation". The server will roll back to the previous change if the current change is invalid(such as changing a value of an array with an index greater than the length of the array).
After the above update, there may have other clients polling for the file change, the client need to tell the server what version of the file they held so that the server can send them the correct delta changes. But, instead of sending the whole JSON file to server to compute the delta changes, an 'editing step' counter is stored in the server for each opened file. This counter will be increased for each delta change (and decrease after undo). So the client only need to send their 'editing step' counter to the server and the server will know how many delta changes are needed to send back to the client. Also, this 'editing step' counter can be used to ensure that if 2 clients are making delta change requests to the server at the same time, only 1 client will success while the other would fail. However, there is one bug: there will have a chance of having the same 'editing step' but different file state if the file has perform an undo operation and the document is changed afterward. So to uniquely identify the 'editing step', a GUID is generated with each editing step. If the server check that the GUID does not match, the server cannot compute the delta changes for the client and the client may simply need to reload the whole document.
Conclusion
The client/server tool architecture approach is really a smart idea that can provide a crash proofing editor by taking the advantage of the server software would mature much earlier than the client editors. I really like this approach and glad that I give it a try to implement it. This approach gives my tools 'free' undo/redo function, multiple viewport, easier for debugging and splitting the editors into smaller client applications makes the code easier to maintain. I guess that this approach can do something interesting such as doing the rigs/animation in Maya which is live sync to the editors just like this CryEngine trailer.
References
[1] A Client/Server Tools Architecture http://www.itshouldjustworktm.com/?p=875
[2] Developing Imperfect Software: How to prepare for development failure : http://www.gdcvault.com/play/1015319/
[3] Developing Imperfect Software: The Movie http://www.itshouldjustworktm.com/?p=652
[4] New generation of @insomniacgames tools as webapp: http://www.insomniacgames.com/new-generation-of-insomniacgames-tools-as-webapp/
[5] bitsquid Our Tool Architecture: http://bitsquid.blogspot.hk/2010/04/our-tool-architecture.html
[6] Assets are exported from UDK
The client/server tool architecture approach is really a smart idea that can provide a crash proofing editor by taking the advantage of the server software would mature much earlier than the client editors. I really like this approach and glad that I give it a try to implement it. This approach gives my tools 'free' undo/redo function, multiple viewport, easier for debugging and splitting the editors into smaller client applications makes the code easier to maintain. I guess that this approach can do something interesting such as doing the rigs/animation in Maya which is live sync to the editors just like this CryEngine trailer.
References
[1] A Client/Server Tools Architecture http://www.itshouldjustworktm.com/?p=875
[2] Developing Imperfect Software: How to prepare for development failure : http://www.gdcvault.com/play/1015319/
[3] Developing Imperfect Software: The Movie http://www.itshouldjustworktm.com/?p=652
[4] New generation of @insomniacgames tools as webapp: http://www.insomniacgames.com/new-generation-of-insomniacgames-tools-as-webapp/
[5] bitsquid Our Tool Architecture: http://bitsquid.blogspot.hk/2010/04/our-tool-architecture.html
[6] Assets are exported from UDK