moymo,Docs
Skip to content
Games: the Moymo SDK

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.hThe C ABI of moymo.dll: open, close, emit, call, pump. Enough on its own for C.
include/moymo.hppThe C++ API on top of it.
lib/win64/moymo.dll, moymo.libThe library and its import library. Ship moymo.dll next to your game's .exe.
bin/moymo.exeThe moymo command.
  1. Build with it. Add include to your include path, link lib/win64/moymo.lib, and copy moymo.dll next to your game's executable. Put moymo.exe in your game's folder.
  2. Create moymo.toml and push it. In a terminal in that folder:
    bash
    ./moymo login
    ./moymo init --app <your app key>
    ./moymo push
    moymo init writes moymo.toml with [codegen] cpp = "moymo.g.h". Change the path if you want the header elsewhere. moymo push writes moymo.g.h and uploads moymo.toml to your sandbox. Push again after every change.
  3. 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 exit

The 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. An enum(...) field or a list is an enum class, and NameOf(value) gives a symbol's name as moymo.toml spells 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.

ResultMeans
OkDone, or on its way to Moymo.
InvalidA value moymo.toml does not allow: outside int(1..), say.
NotRunningStart was not called, did not succeed, or Stop was called.
UnknownIdThe generated header is older than moymo.toml: run moymo push again.
QueueFullToo 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, Paused

Steam ​

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.

The wiki is for Moymo's members and developers. Something wrong or missing? Use "Suggest a change" on any page.