Projects: the Editor, Projects, Templates, and Packaging
Status: Designed, not implemented.
The Problem
A project's code is compiled into the editor: Playground.exe is the editor and the Playground game in one executable, and the project folder is fixed when it is built (TNX_). So:
- the engine can't be packaged on its own:
scripts/package.pyships the editor only with Playground in it; - a new project means copying a folder and its
CMakeLists.txtby hand, and the editor can't open it; - there are no templates, and nothing to share one with.
The Idea
The editor is a program of its own that opens a project. A project is a folder with a project file, its content, and its C++, built as a module the editor loads. The engine is a shared library in development builds, so the editor, the project's module and the project's game executable all use one copy of it. A packaged game links everything statically, as today, and pays nothing for any of this.
Engine and project are meant to be built together: one CMake tree, one IDE, changes to either in the same session. The editor can also build the project itself, for anyone without an IDE open.
Every project has C++. Node graphs are C++ (TrinyxParser reads annotated methods into graphs and graph edits are written back as code), so a project's module exists from the first moment, even if it only holds a game mode.
Loading the project's module is the same mechanism as reloading it: that design's first stage is this design's foundation.
Shape
A project
MyGame/ MyGame.tnxproject the project's name, its module, and the engine it was made with MyGameDefaults.ini the project's settings (default scene, start state, rates, limits) EditorDefaults.ini the editor's overrides of them Keybinds.ini input bindings CMakeLists.txt generated once; the project owns it from then on src/ the module's C++ (Constructs, game modes, widget classes, graphs) content/ scenes, widget assets, strings, meshes, ... Saved/ per-user state: layouts, settings, logs (ignored by version control)
The project file is JSON, like every other Trinyx file, and small: what can't be found by looking in the folder. Settings stay in the .ini files, so nothing is in two places.
{ "project": "MyGame", "version": 1, "module": "MyGame", "engine": { "version": "0.9", "path": "D:/Dev/TrinyxEngine" } }
module is left out when it is the project's name. A program opens a project with --project <file or folder>; without it, the folder its build names (TNX_), or for a packaged game the executable's folder.
engine.path is where the engine's source is, relative to the project or absolute; empty means the engine installed on this machine (below). New projects go in a Trinyx Projects folder in the user's Documents by default; New Project can put one anywhere.
CMake: one function
The engine provides trinyx_add_project(<Name> [SOURCES ...]). A project's CMakeLists.txt is a few lines that call it; the function makes:
| Target | Development builds | Packaged game |
|---|---|---|
<Name>Module | Shared library of the project's code, linking the engine's shared library | Static, linked whole into the game |
<Name> | Small game executable that loads the module | The whole game, statically linked |
TrinyxEditor | The engine's editor host (one per engine, not per project) | Not built |
It also sets what TNX_ sets today, from the project file, so the project folder is never compiled in.
The engine as a shared library
In development builds the engine (Trinyx), GG-UI (GGUI, GGUIText) and Foundation are shared libraries; a packaged game links them statically.
- Exports are marked by hand, one macro per library (
TNX_API,GGUI_API,GGUITEXT_API,FOUNDATION_API), on whole classes and on free functions. What isn't marked isn't public, even in a public header, on Windows and on Linux (built with hidden visibility). Templates need no mark; the non-template core under one does. - One copy of shared state. Singletons and registries keep their instance in the library's sources, never in a header, so every module sees the same one.
- Type IDs by name. A component's or entity type's ID is asked of the engine by the type's name the first time a module uses it, then cached. Every module gets the same ID, and a reloaded module gets the ID it had before.
- Checked, not remembered. A script lists public classes and functions without a mark (presubmit runs it), and a test module that includes every public header must link.
Two ways to lay out the tree
- Engine workspace: the engine repository at the top, projects as folders in it (as Playground, Testbed and ResilienceDemo are today). For engine development.
- Project workspace: the project at the top; its
CMakeLists.txtadds the engine fromengine.path(add_subdirectory) or finds the installed one (find_package(Trinyx)). For game development, with the engine's source in the same IDE when it is a source engine.
Both build the same targets. A project created by the editor gets the project-workspace layout.
Engine build options
Some engine options are compile-time (TNX_ENABLE_ROLLBACK, TNX_DETERMINISM, TNX_ENABLE_NETWORK, entity limits). The project file lists the ones the project needs, and its tree builds the engine with them. An installed engine ships built for the default set, plus its source: a project that changes an option builds the engine from that source in its own tree, without the engine's folder being written to.
The editor without a project
TrinyxEditor started with no project shows the Project Browser: recent projects, Open (a folder or a .tnxproject), and New Project. Started with a project (TrinyxEditor MyGame.tnxproject, or a double-click on the file), it loads that project's module and opens its default scene. File gains Open Project… and Recent Projects; switching project unloads the module the way a reload does, then loads the other one.
Building from the editor, or not
Two setups, the same result:
- The IDE builds. The editor watches the module's output and loads a new build when it appears (the Code Reload path). The editor never runs a compiler.
- The editor builds. Build (and Build and Reload) runs CMake for the project's tree, with its output in the Log panel and its errors in a Problems list that opens the file at the line. This needs a compiler on the machine; the Project Browser checks for one and says what to install when it's missing.
The project's Saved/ settings say which one this machine uses; both can be on.
New Project and templates
A template is a project folder plus a template.json: name, description, preview image, category, the engine version it needs, and the names to replace when a project is made from it (the template's project and module names become the new project's in file names, the project file, and code).
- Built-in templates live in the engine (
Templates/). The first is Blank: a game mode, a start state, and an empty scene. Others (a player with a camera and a HUD; Host, Join, and Solo menus) come as their features settle. - New Project shows them with their previews; you choose one, a name, and a folder. The editor copies it, replaces the names, writes the project file and
CMakeLists.txt, builds the module (or waits for the IDE to), and opens the project. - Your own templates: File > Save Project as Template… writes a project as a template (without
Saved/and build output). A template packs into one.tnxtemplatefile (a zip of the folder) to share; Add Template… in New Project, or a double-click on the file, installs it into the user's template folder. A template made with an older engine is listed with what it needs.
Packaging
- Package Project (File menu, and
scripts/package.py --project MyGame.tnxprojectfor CI): builds the project's game executable in its packaged configuration (static,TNX_PACKAGE), stages its content, config, the engine's assets and shaders, and the runtime libraries it needs, and writes a folder and a zip. The menu and the command line run the same code and write the same thing. - Package Engine (
scripts/package.py --engine): the editor, the engine's shared library built for the default options, its headers, its CMake package (TrinyxConfig.cmake), its source, and the built-in templates. Unzipped anywhere, it opens to the Project Browser and can make, build, and package projects. package.py's currentEditoranddemomodes become Package Project of Playground and of ResilienceDemo.
Stages
- Foundation: the editor opens a project.
- The engine as a shared library in development builds;
trinyx_add_project; Playground, ResilienceDemo, and Testbed moved onto it. - The project file; the project folder found at runtime, never compiled in.
TrinyxEditoras its own executable, loading a project's module: Code Reload stage 1 (module-owned registries, the safe point, unload and load in order), which reload then reuses.- The Project Browser (recent, open), and Open Project in the editor.
- Package Engine and Package Project from the command line.
- A Testbed test makes a project from a template in a temporary folder, builds its module, loads it, and unloads it.
- The engine as a shared library in development builds;
- Production: projects from inside the editor.
- New Project with the Blank template; Save as Template;
.tnxtemplatefiles to share and install. - Build and Build and Reload from the editor, with errors in a Problems list; a check for a compiler.
- Package Project from the File menu, with its progress and output in the Log panel.
- Engine build options per project.
- New Project with the Blank template; Save as Template;
- Differentiators.
- Upgrading a project to a newer engine: the project file records the version it was made with, and the editor lists and applies what changed (renamed types, moved files) as one undoable step, with a report.
- Packaging profiles in the project file (platform, configuration, which content), run the same from the menu and from CI, with the build cached between runs.
- Templates that ask for options when used (networked or not, which starter HUD), built from the same widget and project-file machinery.
Later
- Source control: New Project writing ignore rules (
Saved/, build output) and starting a repository comes with source control in the editor, not before. - More templates: a player with a camera and a HUD made in the widget designer; a networked game once Host, Join, and Solo is in.