- CMake 3.21+
- Ninja
- vcpkg for dependency management
Install packages:
cd /path/to/coherence-cpp
/path/to/vcpkg/vcpkg install
If using VS Code, add vcpkg to cmake.configureSettings
:
"cmake.configureSettings": {
"CMAKE_TOOLCHAIN_FILE": "/path/to/vcpkg/scripts/buildsystems/vcpkg.cmake",
"VCPKG_TARGET_TRIPLET": "x64-windows-static"
}
The triplet is only required on windows to build a static lib. On macOS, the arm64-osx
should be fine.
Run all tests (from the project root):
python tests
Run specific test, suite, or test prefix:
python tests --filter test_set_viewport_format
python tests --filter TestTrackedChanges
python tests --filter test_set
More commands available via:
python tests --help
Use the @tag('skip_client')
decorator on a test to skip setting up a client instance within setUp()
. Use this tag on syncing feature tests for new clients (re)connecting to a server with pre-existing data.
There's a POD {type}State
struct in Library.h
that contains the public data for the entity that's made available to host applications. These get exposed through the API as getters and are modified either through direct setters or other manipulators.
Methods on entities typically fall under the pattern:
get_
are const property accessors for whatever is currently stored locally for that entity.set_
methods will update internal state and replicate to the connected application.on_
methods receive network events, change internal state to match, and add a change tracking record to the scene.
The entity should be responsible for all network messages in/out of itself.
Instantiation process looks like:
- (REMOTE) creates an entity through
Scene::create
with an initial state - (REMOTE) calls
on_create
to do any necessary work after instantiation - (REMOTE) calls
sync()
to sync all of entity data over the network in one go. - (LOCAL) instantiates a copy of the entity.
- (LOCAL) sets initial state from
create_*
network event payload. - (LOCAL) calls
on_create
for the new entity and adds a change tracking record to the scene.
External applications query for changes after network updates to get an aggregate list of all entity changes. This was chosen over callbacks to decouple network update frequencies from app updates - e.g. frequent transform changes do not need to be immediately handled in apps, and to simplify the API a bit so we don't need a plethora of callback handler types.
The general idea is:
- (REMOTE) performs changes on one of end of the pipeline (e.g.
.SetTransform
) - (REMOTE) and (LOCAL) both sync up network messages via
.Update
- (LOCAL) queries for a batch of changes on a fixed interval (say 60 FPS)
- (LOCAL) pops off a
Change
and calls.GetTransform
for the entity that has changed to use for the host application - (REMOTE) can continue to write more changes in the background.
- Currently, this is synchronous and only happens during an
.Update
call, but may change in the future.
- Currently, this is synchronous and only happens during an
Current table of (REMOTE) events and the changes they trigger:
Event | Flag |
---|---|
Scene.on_create() | CHG_CREATED |
Scene.on_destroy() | CHG_DESTROYED |
{entity}.on_update() | CHG_UPDATED_STATE |
SceneObject.on_transform() | CHG_TRANSFORMED |
Component.on_update_property() | CHG_UPDATED_PROPERTY |
Image.on_pixels() | CHG_UPDATED_PIXELS |
Note that if an entity is created and destroyed before the changes are polled, it'll create a single record with CREATED | DESTROYED
. TBD whether or not that should be fixed somehow.