C and C++
For your own engine, or none. The SDK is moymo.dll (Windows x64) with a C header, plus a header-only C++17 API on top of it. It has no other dependencies.
moymo.hpp and the header it generates follow the C++ Core Guidelines. They build without a warning at MSVC /W4 /permissive- and clang -Wall -Wextra -Wpedantic -Wconversion, and they pass the Core Guidelines checks of MSVC's Code Analysis and clang-tidy. moymo.h is plain C99.
What is in the zip
In your game's Setup tab in the Developer Portal, pick C or C++ and download Moymo SDK for C and C++ (moymo-sdk-cpp-<version>.zip):
include/moymo.h | The C ABI of moymo.dll: open, close, emit, call, pump. Enough on its own for C. |
include/moymo.hpp | The C++ API on top of it. |
lib/win64/moymo.dll, moymo.lib | The library and its import library. Ship moymo.dll next to your game's .exe. |
bin/moymo.exe | The moymo command. |
- Build with it. Add
includeto your include path, linklib/win64/moymo.lib, and copymoymo.dllnext to your game's executable. Putmoymo.exein your game's folder. - Create moymo.toml and push it. In a terminal in that folder:bash
./moymo login ./moymo init --app <your app key> ./moymo pushmoymo initwritesmoymo.tomlwith[codegen] cpp = "moymo.g.h". Change the path if you want the header elsewhere.moymo pushwritesmoymo.g.hand uploadsmoymo.tomlto your sandbox. Push again after every change. - Call it. Include the generated header (it includes
moymo.hpp), start the SDK once, and pump it every frame.
The API
cpp
#include "moymo.g.h"
using moymo::Connection, moymo::Environment;
// Once, at start-up, on the game thread. A development build talks to the emulator (`moymo dev`);
// the release build: moymo::game::Start(Environment::Live, Connection::MoymoForWindows).
moymo::game::Start(Environment::Sandbox, Connection::Emulator);
moymo::Emit(moymo::game::Ev::LevelFinished{3}); // never allocates, never blocks, from any thread
moymo::Presence::Set(moymo::game::Rp::Playing(3)); // when it changes, not every frame
moymo::Presence::Clear();
moymo::Moments::Mark(moymo::game::Moment::LevelFinished(3));
moymo::Achievements::Unlock(moymo::game::Ach::FirstBanner);
moymo::Stats::PutInt(moymo::game::Stat::Population, 14);
moymo::Stats::PutFloat(moymo::game::Stat::BestTime, 81.5);
moymo::Stats::PutFlag(moymo::game::Stat::SawEnding, true);
moymo::Stats::Add(moymo::game::Stat::BuildingKinds, moymo::game::NameOf(moymo::game::Buildings::Smithy));
moymo::Sdk::Pump(); // every frame, on the game thread
moymo::Sdk::Stop(); // at exitThe generated header has one type per thing in moymo.toml, in the namespace moymo::game. Change the namespace with [codegen] namespace = "MyGame.Moymo", which becomes MyGame::Moymo. The generated types are:
Ev::LevelFinished: one struct per event, with a field per event field. Anenum(...)field or a list is anenum class, andNameOf(value)gives a symbol's name asmoymo.tomlspells it.Rp::Playing(...): one function per presence line.Moment::LevelFinished(...): one function per moment.Ach::FirstBanner: one per achievement.Stat::Population: one per stat.
A misspelt name does not compile.
What a call returns
Every call returns a moymo::Result. A call never throws an exception, and never blocks a frame.
| Result | Means |
|---|---|
Ok | Done, or on its way to Moymo. |
Invalid | A value moymo.toml does not allow: outside int(1..), say. |
NotRunning | Start was not called, did not succeed, or Stop was called. |
UnknownId | The generated header is older than moymo.toml: run moymo push again. |
QueueFull | Too many events at once. This one was dropped. |
Some refusals come later, through Pump: a module the player did not allow, for example. They go to the log.
Start returns false when moymo.dll refused to start; the log says why. If Moymo for Windows is not running, Start succeeds and keeps connecting in the background. Until it connects, the calls do nothing visible.
Threads
Emit works from any thread between Start and Stop. Everything else belongs on the game thread. Call Stop only after your other threads have stopped emitting, because Stop frees the SDK's state.
The log
The SDK's lines go to stderr: refusals, and what the library says while connecting. Send them to your own log before Start:
cpp
moymo::Sdk::SetLog([](const std::string& line) { MyEngine::Log("moymo: %s", line.c_str()); });Focus
Tell the SDK when the window loses or gets focus, or when the game pauses. Moymo for Windows then shows its consent window at a pause, not over the game:
cpp
moymo::Sdk::SetGameState(moymo::GameState::Unfocused); // or Focused, PausedSteam
Define MOYMO_STEAMWORKS for the whole project (/DMOYMO_STEAMWORKS) and include steam_api.h before moymo.g.h. Every achievement with steam = "ACH_..." in moymo.toml is then unlocked on Steam too. That covers the ones from Achievements::Unlock and the ones a rule or an event unlocks, which reach Steam through Pump. Steam must be initialized by your game, as it is today.
Plain C
moymo.h is the whole contract: moymo_open, moymo_emit, moymo_call, moymo_pump, moymo_lifecycle and moymo_close. Every function returns a code and never blocks. moymo.hpp is a readable example of how to use it: start options and calls are small protocol-buffer messages, written by hand there.
Development builds
Run ./moymo dev and start the game with Connection::Emulator. It prints what would reach Moymo for Windows: presence lines, moments and achievements. Events and stats stay inside the game, where the moments and rules use them. A release build talks to Moymo for Windows, and the first time it starts, the player is asked what to allow.
Going live
Run ./moymo push --env live, have the release build start with moymo::Environment::Live, then follow the Go live tab in the portal. See Sandbox, testers and going live.