DaemonAgent — dual-language game engine bridging a C++ DaemonEngine foundation with embedded V8 JavaScript game logic
DaemonAgent (formerly "daemon-agent") is a research-grade C++ game application that embeds the Google V8 JavaScript engine to enable a dual-language architecture: performance-critical systems (rendering, audio, entity management) live in C++ (DaemonEngine) while game logic and rapid prototyping are written in JavaScript and executed in V8. The project emphasizes hot-reloadable JavaScript logic, crash isolation between language runtimes, and a frame-based double-buffered communication pattern (EntityStateBuffer / CameraStateBuffer) to achieve stable rendering and lock-free parallelism.
Prerequisites
- Microsoft Visual Studio 2022 with the C++ development workload
- Windows 10/11 (x64)
- NuGet for package dependencies
Build & run
- Open the solution:
- Open
DaemonAgent.slnin Visual Studio 2022.
- Open
- Choose a configuration:
- Select
Debug|x64orRelease|x64.
- Select
- Build the solution:
- Build → Build Solution (Ctrl+Shift+B).
- Run the application:
- From the IDE: Start Debugging / Start Without Debugging.
- Or from the Run folder:
- cd Run
- Run the produced binary (e.g.,
DaemonAgent_Debug_x64.exeorDaemonAgent_Release_x64.exe).
If you are working on the JavaScript side:
- Edit scripts under
Run/Data/Scripts/— hot-reload is supported by the engine. - Use Chrome DevTools integration for JS debugging when running the application.
- Primary JS entry point:
Run/Data/Scripts/main.js(ES6 module). The JS framework exposes a JSEngine and uses a CommandQueue facade (seeRun/Data/Scripts/Interface/CommandQueue.js). Note:main.jscreates theCommandQueueinstance and setsglobalThis.CommandQueueAPIbefore the game systems are initialized (CommandQueue MUST be available to JS systems such asJSGame).
| Tool / Subsystem | Description |
|---|---|
| V8 Subsystem (embedded) | Embedded JavaScript runtime for game logic and hot-reloadable systems. Integrated with Chrome DevTools for debugging. |
| DaemonEngine (Engine/) | C++ game engine foundation providing Core, Entity, Camera, Rendering, Audio, and Resource management subsystems. |
| Entity API / EntityScriptInterface | C++ ↔ JS bindings for entity management. Includes EntityStateBuffer double-buffering for lock-free state exchange. |
| Camera API / CameraScriptInterface | C++ ↔ JS bindings for camera control with CameraStateBuffer. |
| Rendering (DirectX) | DirectX-based renderer implemented in the engine (Engine/Renderer/). |
| Audio (FMOD) / AudioStateBuffer | FMOD integration for audio playback and mixing. Audio can be conditionally disabled at build-time via Code/Game/EngineBuildPreferences.hpp (ENGINE_DISABLE_AUDIO). AudioStateBuffer is used alongside EntityStateBuffer for audio state exchange. |
| Hot-Reload System (JSEngine) | JSEngine (JS-side, Run/Data/Scripts/JSEngine.js) manages JS systems, their priorities, and hot-reload replacement. Uses an internal event bus (Event/EventBus.js) and priority-based execution (0-100, lower = earlier). main.js is the ES6 entry module loaded by the C++ host. |
| DevTools Integration | Chrome DevTools connection for JavaScript inspection and breakpointing at runtime. |
| Command/Callback Queues | JS-visible CommandQueue facade and C++ lock-free/queued mechanisms for submitting render and engine commands. Callback processing uses a queued/lock-free design (see CallbackQueue / CallbackQueueScriptInterface). |
Primary runtime configuration now lives under the Run/Data tree and engine/project files:
Run/Data/GameConfig.xml— primary runtime configuration for the application (game-specific settings).Run/Data/Scripts/— JavaScript game logic and hot-reloadable modules; entry pointmain.js.Run/Data/— assets (models, shaders, textures, audio) and other data files.Code/Game/EngineBuildPreferences.hpp— per-game engine build flags. The current game header definesENGINE_DEBUG_RENDER,CONSOLE_HANDLER, andENGINE_SCRIPTING_ENABLEDby default. Note:ENGINE_SCRIPTING_ENABLEDis used in Phase 2 to enable async audio support via the AudioCommandQueue.ENGINE_DISABLE_AUDIOremains available (commented-out by default) to disable FMOD/audio code and linkage if needed.DaemonAgent.sln— Visual Studio solution and build configuration.Code/Game/— C++ game application sources that reference the externalEngine/repository.
Common runtime settings are configured in Run/Data/GameConfig.xml and per-script configuration may be present inside Run/Data/Scripts/. Hot-reload and debugging behavior are controlled by runtime flags and GameConfig.xml.
DaemonAgent.sln— Visual Studio solution (entry point for development).Code/Game/— main application sources (C++). Look forApp.cpp/Appentry points that drive the main loop. Notable files:Code/Game/EngineBuildPreferences.hpp— game-specific engine build preference flags (definesENGINE_DEBUG_RENDER,CONSOLE_HANDLER, andENGINE_SCRIPTING_ENABLEDby default;ENGINE_DISABLE_AUDIOmay be uncommented to disable audio).Code/Game/Framework/App.hpp— application lifecycle methods:Startup(),Shutdown(),RunFrame(), andRunMainLoop(). UsesEntityStateBufferandAudioStateBuffer. TheAppclass declares per-process quitting state (static bool m_isQuitting) and exposes frame-phase methods (BeginFrame(),Update(),Render(),EndFrame()). It also declares static callbacks used with the engine'sEventSystem, includingstatic std::any OnPrint(std::vector<std::any> const& args),static bool OnCloseButtonClicked(EventArgs& args), andstatic void RequestQuit().Code/Game/Framework/GameScriptInterface.hpp— scriptable bridge derived fromIScriptableObjectthat registers and exposes methods to JS. Current callable methods include:- ExecuteAppRequestQuit
- ExecuteJavaScriptCommand
- ExecuteJavaScriptFile
- ExecuteCreateScriptFile / ExecuteReadScriptFile / ExecuteDeleteScriptFile (KADI file operations)
- ExecuteInjectKeyPress / ExecuteInjectKeyHold / ExecuteKeyHoldSequence (key-hold sequence accepts a JSON string) / ExecuteGetKeyHoldStatus / ExecuteCancelKeyHold / ExecuteListActiveKeyHolds (input injection and key-hold management)
- ExecuteAddWatchedFile / ExecuteRemoveWatchedFile (file-watcher management)
Code/Game/Framework/JSGameLogicJob.hpp— worker-thread job for JavaScript execution (usesJobSystemprimitives and thread synchronization). The JS worker is implemented around an abstractIJSGameLogicContextand coordinates with callback/command queues. The header documents a continuous worker-thread design usingstd::mutex+std::condition_variablefor frame coordination and mentions V8 thread-safety viav8::Locker.Code/Game/Framework/GameCommon.hpp— common helpers and globals (g_app,g_game) and utilities such as theGAME_SAFE_RELEASEmacro.
Engine/— external engine library containing:Engine/Entity/—EntityAPI,EntityScriptInterface,EntityStateBufferEngine/Renderer/—CameraAPI,CameraScriptInterface,CameraStateBufferEngine/Audio/—AudioStateBufferand audio subsystem (FMOD integration unless disabled)Engine/Core/— sharedStateBuffertemplate and core utilities,JobSystem.hpp
Run/Data/Scripts/— JavaScript game logic, including:main.js— ES6 entry point (createsCommandQueue, setsglobalThis.CommandQueueAPI, initializesJSEngine/JSGame); contains hot-reload cleanup logic for prior JS game instances (destroys old prop/player/camera game objects on the C++ side before re-creating).JSEngine.js— core JS framework for system registration, priority execution, hot-reload handling, and event-bus integration (Event/EventBus.js).JSGame.js— JS-side game orchestration (imported bymain.js) that wires up subsystems such as input and audio.Interface/CommandQueue.js— CommandQueue facade exposed to JS for engine interactions.main.jscreates an instance and exposes it asglobalThis.CommandQueueAPI(the CommandQueue provides runtime availability checks such asisAvailable()).InputSystemCommon.js— shared key code constants used by input-related systems.InputSystem.js,AudioSystem.js— concrete JS subsystems imported/used byJSGame.js.- Utility / gameplay systems imported by
JSGame/main.js:CppBridgeSystem.js,CubeSpawner.js,PropMover.js,CameraShaker.js(examples of JS subsystems that interact with the C++ engine via the CommandQueue/Script interfaces). Event/EventBus.js— JS event bus used byJSEngineand subsystems for decoupled communication.
Input, audio, and other systems are registered with JSEngine and execute each frame in priority order. Hot-reload replaces modified subsystem instances and main.js performs safe cleanup of previously-created C++ side objects on reload.
- Hot-reload behavior:
main.jsimplements a hot-reload cleanup sequence that attempts to call.destroy()on previously-created prop/player/camera game objects (these.destroy()calls are bridged to the C++ side).- The JS framework (`JSEngine