Skip to main content

World and liveops

The root hub: the world's clock, weather and resource nodes, advanced on a timer while the app runs, and the liveops events its developers schedule. It hears players enter and leave the app, and other hubs watch its world topic: the areas' mobs grow bolder at night and under an event's aggro modifier. The root hub takes 50 calls a second for the whole app, so clients read it from its topics and never poll state.

Starter: crate world-tick, node type world, the root hub, keyed by the empty key (one per app). Module: kit.world in CrowdyJS, world() in CrowdyCPP, kit.world in CrowdyPy.

Endpoints​

EndpointWhoWhat
stateanyoneThe conditions, the clock, every node, the events, the players online
harvest { node }playersTakes one from a node; answers what it holds now. cooldown, empty (it grows back), not_found
schedule { name, start_ms, end_ms, modifiers }developersSchedules or replaces a liveops event; while it runs its modifiers apply (overlapping ones multiply)
cancel { name }developersCancels one; answers whether there was one

Every change takes an action_id, answered once; refusals carry the codes above (see the protocol).

Topics​

world: snapshots of the conditions (time_of_day, night, weather, modifiers). nodes: a delta per resource node (amount, regrow_at).

Config​

A type's seed (seed_b64 in the manifest, the same for every key) is the starter's JSON config; what it leaves out keeps its default. day_ms (real milliseconds in a game day), nodes, node_amount, regrow_ms.

CrowdyJS​

const kit = game.kit(appId);
await kit.world.conditions.start();
kit.world.conditions.subscribe((c) => setSky(c?.night ? 'night' : 'day'));
await kit.world.nodes.start();
const left = await kit.world.harvest(kit.world.nodes.list('Node')[0].id);

// A developer's kit schedules liveops:
const dev = client.kit(appId, { developer: true });
await dev.world.schedule({ name: 'double-xp', start_ms: Date.now(), end_ms: Date.now() + 3_600_000, modifiers: { xp: 2 } });

CrowdyCPP​

auto kit = crowdy::kit::makeKit(game, appId);
kit->world().conditions().subscribe([&] { setSky(kit->world().conditions().get()["night"].asBool()); });
kit->world().conditions().start();
kit->world().harvest(nodeId, [](crowdy::kit::KitReply r) {
if (r.code() == "empty") showRegrowing();
});
game.poll(); // replies, topic messages and mirror changes arrive here

CrowdyPy​

kit = game.kit(app_id)
await kit.world.conditions.start()
kit.world.conditions.subscribe(lambda c: set_sky("night" if c and c["night"] else "day"))
left = await kit.world.harvest(node_id)