doompanning/src/doomsim.cc

176 lines
3.6 KiB
C++
Raw Normal View History

#include <cassert>
#include <cstdlib>
#include <cstring>
#include <optional>
#include <nng/nng.h>
#include <nng/protocol/pubsub0/pub.h>
#include <nng/protocol/pubsub0/sub.h>
#include "dp_common.h"
#include "log.h"
enum DP_DoomState
{
DP_DS_Ready,
DP_DS_Running,
DP_DS_Quit,
DP_DS_COUNT,
};
static const char *const DP_DoomState_Strings[DP_DS_COUNT] =
{
"DoomState_Ready",
"DoomState_Running",
"DoomState_Quit",
};
#define doomstate_str(s) DP_DoomState_Strings[s]
struct DoomContext;
#define DEF_DOOM_STATE_FUNC(fn) int fn(DoomContext *ctx)
typedef DEF_DOOM_STATE_FUNC(DoomStateFunc);
typedef struct DoomContext
{
nng_socket pub;
nng_socket sub;
doomid_t id;
DP_DoomState state;
DoomStateFunc *f;
} DoomContext;
DEF_DOOM_STATE_FUNC(do_doom_ready)
{
assert(ctx->state == DP_DS_Ready);
int res = 0;
// Publish { DP_MT_DoomReady, doomid }.
{
nng_msg *msg = NULL;
if ((res = nng_msg_alloc(&msg, sizeof(dmt_t) + sizeof(doomid_t))))
dp_nng_fatal("doom/alloc", res);
if ((res = nng_msg_append_u16(msg, DP_MT_DoomReady)))
dp_nng_fatal("doom/msg", res);
if ((res = nng_msg_append_u32(msg, ctx->id)))
dp_nng_fatal("doom/msg", res);
if ((res = nng_sendmsg(ctx->pub, msg, 0)))
dp_nng_fatal("doom/sendmsg", res);
}
// Incoming Message | Next State
// -------------------------------
// DP_MT_RunDoom -> DP_DS_Running
// DP_MT_QuitDoom -> DP_DS_Quit
// */none -> DP_DS_Ready
{
nng_msg *msg = NULL;
if ((res = nng_msg_alloc(&msg, sizeof(int) + sizeof(doomid_t))))
dp_nng_fatal("doom/alloc", res);
if ((res = nng_recvmsg(ctx->sub, &msg, 0)))
{
if (res != NNG_ETIMEDOUT)
dp_nng_fatal("doom/recvmsg", res);
return 0;
}
dmt_t mt = DP_MT_Invalid;
if ((res = nng_msg_trim_u16(msg, &mt)))
dp_nng_fatal("doom/msg_trim", res);
nng_msg_free(msg);
if (mt == DP_MT_RunDoom)
ctx->state = DP_DS_Running;
else if (mt == DP_MT_QuitDoom)
ctx->state = DP_DS_Quit;
}
return res;
}
DEF_DOOM_STATE_FUNC(do_doom_running)
{
assert(ctx->state == DP_DS_Running);
// Read and handle input messages
// Let doom render a new frame
// Publish the frame
// Check if we should quit
return 0;
}
int doom_loop(nng_socket pubSock, nng_socket subSock, doomid_t doomId)
{
log_debug("doom#%zu started", doomId);
DoomContext ctx
{
pubSock,
subSock,
doomId,
DP_DS_Ready,
do_doom_ready,
};
int res = 0;
while (ctx.state != DP_DS_Quit && res == 0)
{
DP_DoomState prevState = ctx.state;
res = ctx.f(&ctx);
if (prevState != ctx.state)
{
log_info("transition %s -> %s",
doomstate_str(prevState), doomstate_str(ctx.state));
}
}
return res;
}
int main(int argc, char *argv[])
{
log_info("doomsim starting");
std::optional<doomid_t> doomId;
for (int i=1; i<argc; ++i)
{
if (i < argc-1 && strcmp(argv[i], "-doomid") == 0)
{
doomId = std::strtoull(argv[i+1], nullptr, 0);
}
}
if (!doomId)
{
log_error("Missing -doomid <id> parameter!");
return 1;
}
dp_nng_init_limits(1, 1, 1);
auto pubSock = make_doom_pub(DoomUrl);
auto subSock = make_doom_sub(CtrlUrl);
int ret = doom_loop(pubSock, subSock, *doomId);
nng_close(pubSock);
nng_close(subSock);
return ret;
}