These are some musings on writing an engine in the modern era should I happen to have a couple of hundred million dollars burning a hole in my pocket.
Introduction
THIS DOCUMENT IS VERY MUCH WORK IN PROGRESS!
Some of these items will appear minor and or irrelevant, but are listed here anyway. Some other items are self evident and no rational being could do it any other way. These are musings, and by
no means an even remotely full engine design. Items marked in [] are bullet points to be expanded into full sentences.
Goals
Direction
Implementation
C# scripting.
The biggest issue is C++ calling C# functions - this is not easy. However, there is no reason that there couldn't be a header file generated using reflection of public members in assemblies. I'm currently experimenting with this in a side project. There would need to be automatic conversions between managed and native memory in the header file to make this practical.
C# is a modern language that is performant enough for most tasks and very debuggable. It has many threading capabilities built in and is easy to read. Attributes can be used to decorate fields and functions to note extra functionality for the core engine.
API Driven.
Interface classes are the way to go; pure in C++ and an actual interface class in C#. This virtual function approach avoids excessive inlining leading to excessive compile times and client code bloat.
Folder Layout - Code
There is a tendency to mix editor and run time content together resulting in a client footprint that is larger than it needs to be. To resolve this, there should be editor source and run time source. Furthermore, the source should be split per platform as much as possible. There are only three practical editor platforms at the moment; Win-x64, Mac-x64, and Linux-x64.Having the editor resources local to the plugin like this means the UI cannot display options that can't be used; if it doesn't exist, it can't be misused!
Compression/LZMA/
Compression/LZMA/Editor/
Compression/LZMA/Editor/API/ // The API required by the editor. The Editor API is free to call client API methods.
Compression/LZMA/Editor/Common/ // Code common to all platforms but only used in the editor
Compression/LZMA/Editor/Win-x64/ // Code specific to Windows x64
Compression/LZMA/Editor/Mac-x64/
Compression/LZMA/Editor/Resources // Resources used by the editor (PNG format preferred)
Compression/LZMA/Runtime/
Compression/LZMA/Runtime/API/ // The API required by the client
Compression/LZMA/Runtime/Common/ // Code common to all platforms that is the minimal set required for the client
Compression/LZMA/Runtime/Android/ // Code specific to Android
Compression/LZMA/Runtime/XboxOne/ // There are more client/run time platforms than editor platforms.
Compression/LZMA/Runtime/Win-x64/
Compression/LZMA/Runtime/Mac-x64/
If the Compression/LZMA folder does not exist, then everything will compile fine, but the API will not have any implemented functions. This could be done with a static initializer registering the availability of LZMA. For most third party
software, the common folders will contain the vast majority of the code, and the platform specific folders will effectively be build instructions. [Use folders to infer platforms, or config file?]
[Plugin reference counts]
Folder Layout - Assets
Following a similar concept to the code, the source and run time assets should be kept distinct. Any update to the SourceAssets should be automatically updated in the parallel RunTime folder for the appropriate platform(s). Packaging a game then becomes a matter of iterating over all the platform folders and copying the files.The meta data for each asset should be part of the run-time version of the data. Everything should be self contained as much as possible. The editor version of the asset should have the meta data as a json file with strong versioning. If the version of the editor meta data changes, the run-time asset data is regenerated.
Each asset should have a parallel json file listing the assets that reference it and the assets it references. If there are no assets referencing it, the run-time version can be deleted. Using a json format for this allows external apps to analyze the hierarchy for profiling purposes.
ProjectName/SourceAssets/Meshes/A/B/SimpleMesh.fbx
ProjectName/RunTimeAssets/Win-x64/Meshes/A/B/SimpleMesh.runtime
ProjectName/RunTimeAssets/Android/Meshes/A/B/SimpleMesh.runtime
ProjectName/RunTimeAssets/XboxOne/Meshes/A/B/SimpleMesh.runtime
Solution generation.
Using the above folder structure, there would need to be a program that iterates over the available folders for the available modules to create a Visual Studio solution.
Json configuration files.
XML files would work here too, but it is critical that the format of the file can be validated independently and there is no ambiguity. Using a standard format like this allows third party apps to be written that can audit assets.
Localization/Internationalization.
Localization - all in UTF8 for reasons listed here. All locales should follow the language-region schema defined by the IETF language tag. e.g. en-US, de-DE, af-ZA. Typically, language-region definition is overkill, but this could be extended even further if necessary. ICU is also overkill for a game engine. Using string interpolation allows the localizer to do whatever is needed to make the grammar correct. e.g. $"Congratulations! You got {KillCount} kills!"