Architecture Overview
Purpose
Section titled “Purpose”Mainframe Engine is a C# (.NET 10) game engine built on Vulkan 1.2 through Silk.NET. It is a
learning-oriented engine with a Godot-style scene model: a game is a project (project.mfproj) whose node library
GameHost runs (or, for the editor and tests, an Engine subclass), with nodes in the engine-owned SceneTree,
usually loaded from a scene file. The engine provides windowing, a Vulkan renderer, the node tree with servers behind
it, scene/resource files, materials and model import, lighting, cascaded shadows, skies, Spine skeletal animation,
RmlUi game UI, physics, audio, replication, localization and an RmlUi developer overlay (F12); the editor
(MainframeEngine.Editor) is built on the same engine and UI stack.
Assemblies
Section titled “Assemblies”| Project | Kind | Role |
|---|---|---|
MainframeEngine | class library | The engine. Ships Content/** (compiled .spv shaders, assets) to dependants’ output; shaders compile during the build (build/Shaders.targets). |
MainframeEngine.Generators | Roslyn source generator (netstandard2.0, referenced as an analyzer) | Registers every node/resource type’s [Export] properties and [Signal] events. See Scene serialization. |
MainframeEngine.L10n (mf-l10n) | exe (build tool) | Localization tooling: RML/scene extraction, .po update, pseudo-locale, .po → .mo compiler run by build/Localization.targets. See Localization. |
Examples/Demo | game project (own solution, not in MainframeEngine.slnx) | The Demo: a GameHost game with one scene per engine feature. See Demo. |
Examples/Forest | game project (own solution, not in MainframeEngine.slnx) | The Forest showcase: a first-person walk (scaffold: controller and a test stream). See Forest. |
MainframeEngine.Editor | exe | The editor (EditorApp : Engine, RmlUi panels); loads game projects’ assemblies into collectible contexts and plays them in separate processes. See Editor. |
Templates/MainframeEngine.Templates | dotnet new template package (not in the solution) | mfgame: a game’s node library + GameHost desktop project + project.mfproj. See Projects & GameHost. |
Tests/* | xUnit v3 test projects, render-test host, BenchmarkDotNet | See Testing. |
Plugins/Spine/spine-csharp | class library (git submodule) | Spine C# runtime. Vendored — do not modify. |
Source layout (MainframeEngine/Src)
Section titled “Source layout (MainframeEngine/Src)”| Folder | Contents | Doc |
|---|---|---|
Core/ | Engine, EngineOptions, GameTime, FPSCounter, ExitCode, RenderingBackend | Engine lifecycle |
Scene/ | Node, SceneTree, SceneViewport, World3D, Node3D/Node2D, Transform3D/Transform2D, NodePath, NodeId, Timer; Nodes3D/ (VisualInstance3D, Camera3D, lights, WorldEnvironment, Grid3D), Nodes2D/ (Camera2D), Input/ | Scene graph & nodes |
Nodes/ | SpineNode, NetworkNode | Scene graph & nodes |
Scene/Nodes3D/GeometryInstance3D.cs, Scene/SubViewport.cs | GeometryInstance3D, MeshInstance3D, Sprite3D, SubViewport | Materials & meshes |
Rendering/Resources/ | Mesh/ArrayMesh/MeshSurface, primitive meshes, StandardMaterial3D, Texture2D | Materials & meshes |
Rendering/Meshes/ | MeshRenderer (batching), PipelineStateCache, DrawList, Aabb/Frustum, picking, sub-viewport compositor | Materials & meshes |
Resources/Import/ | AssetImporters, TextureImporter, ModelImporter (Assimp) | Asset pipeline |
Servers/ | IServer, ServerRegistry, RenderServer | Scene graph & nodes |
Resources/ | Resource, PackedScene, ResourceLoader, SceneSaver/ResourceSaver, AssetDatabase, AssetUid | Scene serialization |
Serialization/ | attributes, TypeRegistry, NodeTypeInfo, codecs, scene reader/writer | Scene serialization |
Rendering/Vulkan/ | VulkanRenderer, IVulkanContext, VulkanLoaderBootstrap | Vulkan renderer |
Rendering/Shadows/ | ShadowSystem | Shadow system |
Rendering/Sky/ | SkyEnvironment + Procedural/Panoramic/Cubemap | Sky |
Rendering/Spine/ | SpineRenderer, SpineTextureLoader | Spine |
Rendering/SceneGrid/ | SceneGrid, SceneGrid2d, SceneGrid3d | Scene grid |
Rendering/Camera/ | ICamera, PerspectiveCamera, OrthographicCamera (math; the nodes wrap them) | Cameras & input |
Rendering/Gizmos/, Debugging/DevOverlay/ | ScreenGizmoBatch, LightGizmos, AxisGizmo, DevOverlay | Developer overlay |
Debugging/, Utils/ | Log and its sinks | Project & GameHost |
Lighting/ | LightEnvironment, Light + Directional/Point/Spot | Lighting |
Networking/ | MultiplayerApi (replication, RPCs), messages, transports (ENet, loopback, simulated), PeerId, NetBuffer* | Networking |
Physics/ | PhysicsServer3D (Jitter2), PhysicsServer2D (Box2D.NET), body/area/shape nodes, queries, DebugLines | Physics |
Audio/ | AudioServer (SoundFlow), buses, audio nodes, streams, decoders | Audio |
UI/ | Rml/ binding over mfrmlui, VulkanUiRenderer, UiServer/UiLayer/UiDocument | Game UI |
Project/, EditorLink/ | ProjectSettings, GameHost/GameSession, InputMap, GameAssemblyLoader; the game ↔ editor protocol | Projects & GameHost |
Imaging/ | Png codec | Testing |
Steamworks/ | Static Steam wrappers, SteamServer | Steamworks |
Localization/ | Tr, LocalizationOptions, LocaleId, catalogs, RmlLocalization, ITextTranslator, FontFallbackTable | Localization |
Dependency graph
Section titled “Dependency graph”flowchart LR
Demo["Examples/Demo<br/>(GameHost desktop project)"] --> Engine["MainframeEngine"]
Editor["MainframeEngine.Editor"] --> Engine
Game["mfgame projects<br/>(GameHost desktop project)"] --> Engine
Game -. analyzer .-> Gen
Demo -. analyzer .-> Gen["MainframeEngine.Generators"]
Demo -. build tool .-> L10n["mf-l10n<br/>(Tools/MainframeEngine.L10n)"]
L10n --> Engine
Engine -. analyzer .-> Gen
Engine --> SpineRT["spine-csharp<br/>(submodule)"]
Engine --> Silk["Silk.NET<br/>Windowing + Input (SDL2) · Vulkan · MoltenVK"]
Engine --> Stb["StbImageSharp"]
Engine --> ENet["ENet-CSharp"]
Engine --> Steam["Steamworks.NET"]
Engine --> Jitter["Jitter2 (3D physics)"]
Engine --> Box2D["Box2D.NET (2D physics)"]
Engine --> GetText["GetText.NET"]
Engine --> Audio["SoundFlow · NVorbis"]
Engine --> Rml["mfrmlui<br/>(RmlUi + FreeType, in-house native shim)"]
Engine --> Assimp["Silk.NET.Assimp"]
Design principles in the current code
Section titled “Design principles in the current code”- Games are node libraries. A game project’s code is node types;
GameHostruns it fromproject.mfproj(noEnginesubclass). AnEnginesubclass is still supported (the editor, the render-test host); its three legacy hooks (OnUpdate,OnShadowPass,OnRenderMainPass) are optional. - The engine owns the scene. A
SceneTree(Godot model) runs lifecycle, physics/process, deferred calls, transform sync and input for every node; behaviour is C# node subclasses. Scenes are data (.mscene) loaded throughResourceLoader; node properties are discovered by a source generator, not reflection. - Nodes are front-ends to servers. Nodes hold editable state; servers (
RenderServer, the physics serversPhysicsServer3D/PhysicsServer2D(M6),AudioServer(M7),UiServer(M8)) hold GPU, simulation, audio and native objects and are reached throughSceneTree.Servers. Physics library calls (Jitter2, Box2D.NET) never leave the physics spaces (Physics). - Vulkan is the only backend.
IRendereris backend-neutral in name, but everything that draws casts toIVulkanContext.EngineOptions.RenderingBackendis not consulted. - Shared GPU state. Meshes are batched by the render server with pipelines from a state-hash
PipelineStateCache, shared per-frame descriptor sets (set 0/1) and memory from the in-houseGpuAllocator(GPU resources, Materials & meshes); the sky, grid and Spine renderers keep their own pipelines, created through the render server when their node enters the tree. - Per-frame-slot resources. Uniform buffers, dynamic vertex buffers and their descriptor sets are
indexed by
IVulkanContext.FrameSlot(MaxFramesInFlight = 2), never by swapchain image, so they survive swapchain image-count changes (see Vulkan renderer). - No static service locators for nodes. The old
Node.Initialize(renderer, shadowSystem)globals are gone; per-world state lives inWorld3D, so the editor can render several worlds.
Ownership & disposal
Section titled “Ownership & disposal”| Object | Created by | Disposed by |
|---|---|---|
| Window | Engine ctor | Engine.Dispose |
SceneTree (root viewport, World3D with its LightEnvironment) | Engine ctor | Engine.OnClose (Tree.Shutdown() frees every node) |
Input context, VulkanRenderer, servers (RenderServer → ShadowSystem, DebugLinesRenderer; PhysicsServer3D/2D → one space per world) | Engine.OnLoad | Engine.OnClose (servers after the tree, before the renderer) |
| Nodes and their GPU objects (shapes, Spine, sky, grid) | the game / PackedScene.Instantiate (GPU objects: the render server on enter) | Free/QueueFree, else the tree shutdown; orphans by the render server |
Loaded resources (PackedScene, .mres) | ResourceLoader.Load | last Release(), else ResourceLoader.ClearCache() in Engine.OnClose |