Skip to content

Latest commit

 

History

1 Commit

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Axogc Platform — DST mod

Server-side bridge between a Don't Starve Together cluster and the Axogc community platform core service.

What it does

  • Long-polls core for downstream commands (player.notify, server.broadcast, player.kick, chat.from_web, metrics.list, leaderboard.fetch, player.stats.fetch, admin.command.run).
  • Reports upstream events (player.joined, player.left, player.died, heartbeat, chat.message, binding.request).
  • Locally accumulates 6 DST-native stat axes (days_survived / play_time / sanity_avg / structures_built / mobs_killed / bosses_defeated) and serves them via the pull-mode leaderboard protocol introduced in PLAN §10.6.

Key design points

  • Master shard only. A DST cluster typically has Forest (Master) and Caves (Slave). modmain.lua early-returns on Slave shards. HTTP bridge work is per-cluster, not per-shard.
  • Long-poll with short hold. TheSim:QueryServer hard-timeouts at ~5s, so /api/srv/poll is called with max_hold_ms=3000 (PLAN §4.2). Downstream command latency is still ~100ms RTT — max_hold_ms only bounds idle reconnect cadence.
  • /bind over chat. DST has no real slash-command registry; the mod listens on each player's onsay and intercepts the /bind prefix. As a side-effect the code is visible to other players (P1: implement a talker:Say hook to suppress public broadcast).
  • Single in-memory stats file at TheSim:GetPersistentString("axo_platform_stats.json"), rewritten every 60s plus on every ms_worldsaved and on player leave.

Layout

modinfo.lua / modmain.lua / modworldgenmain.lua
scripts/platform/
├── settings.lua         # BASE_URL, TOKEN, intervals, boss prefab whitelist
├── util.lua             # tiny helpers (trim, find_player, log)
├── transport/
│   ├── http.lua         # post_srv / get_srv / reply_event / parse_envelope
│   └── poll.lua         # long-poll loop with max_hold_ms=3000
├── stats/
│   └── axes.lua         # the 6 DST metric definitions (metrics.list payload)
├── observation/
│   ├── stats.lua        # in-memory cache + PersistentString backing
│   ├── walk_sampler.lua # 1s position sampler → walk_distance_m
│   └── events.lua       # SINGLE subscription source: chat / death / killed / build / join / leave
├── chat/
│   └── chat.lua         # upstream chat.message + loopback dedup
├── commands/
│   └── bind.lua         # /bind handler + 3-fails/10min lockout
├── handlers/
│   ├── dispatch.lua     # downstream command router
│   ├── notify.lua / broadcast.lua / kick.lua / chat_from_web.lua
│   ├── stats_fetch.lua
│   ├── metrics_list.lua / leaderboard_fetch.lua
│   ├── whitelist.lua    # always NOT_SUPPORTED — DST has no whitelist mode
│   └── admin_command.lua
├── rank/
│   └── snapshot.lua     # pre-sorted snapshot every 5min, sliced on fetch
└── init.lua             # boot sequence wired into AddPrefabPostInit("world")

Deployment

This mod is a server-side bridge — clients don't need to install it. No Steam Workshop upload required (and not recommended — token is a secret).

1. Drop the mod folder

Copy the entire repo into your DST dedicated-server install:

/srv/dst/dst_server/mods/axogc-platform/
├── modinfo.lua
├── modmain.lua
├── modworldgenmain.lua
└── scripts/...

The folder name (axogc-platform) is arbitrary, but it MUST match the key you use in modoverrides.lua below.

2. Configure each cluster (per-shard modoverrides.lua)

DST clusters typically live under /srv/dst/data/DoNotStarveTogether/Cluster_<N>/<ShardName>/modoverrides.lua. Edit both the Master shard and any secondary shard (Caves, etc.); the mod loads on Slaves too and harmlessly early-returns from modmain.lua, but the declaration has to be present so DST keeps the mod enabled.

return {
  ["axogc-platform"] = {
    enabled = true,
    configuration_options = {
      base_url = "https://www.axogc.net",         -- no trailing slash
      token    = "abcdef0123456789...",           -- from platform admin panel
    },
  },
}

This is DST's standard GetModConfigData mechanism (see modindex.lua in the engine source) — modoverrides.lua values bypass the dropdown UI and are fed straight into GetModConfigData("base_url") / ("token") calls in modmain.lua. The mod folder itself stays free of credentials.

3. Restart the cluster

DST has no mod hot-reload — restart the whole cluster after any change to modoverrides.lua or any file under mods/axogc-platform/.

4. Verify

Watch the Master shard's console for:

[platform] booting bridge…
[platform] stats loaded — N players
[platform] poll loop starting (max_hold_ms=3000)
[platform] chat hook installed
[platform] bridge online

If you see base_url not configured or token not configured, the modoverrides.lua keys are missing, mis-spelled, or the mod folder name doesn't match the table key.

Verifying upstream traffic

After restart, the Master shard should immediately heartbeat. On core:

# Logs (heartbeats are noisy; filter):
docker compose logs core | grep -E "heartbeat|player\.joined|chat\.message"

# Redis:
redis-cli ZSCORE server:status <server_id>           # presence
redis-cli HGET   server:online <server_id>           # online count

When a player joins and runs /bind ABCD12, you should see one POST to /api/srv/binding.request immediately and one downstream player.notify delivered to the player within seconds.

Constraints to remember

  • Hardcoded 5s timeout on TheSim:QueryServer cannot be raised. Anything that needs more than ~3s server-side will time out client-side.
  • Every QueryServer call writes one line to the BDS log (SimLuaProxy::QueryServer()); at 3s poll cadence that's ~28,800 lines/day. Use logrotate; do not try to silence them.
  • Default DST sandbox blocks localhost. Use the host's real IP or a public domain even when DST and core run on the same machine.
  • Player.userid (KU_xxx) is permanent across renames, but the platform protocol still uses gamename as the identity key (per PLAN §9). userid is attached as external_id for future rename tolerance.

Known gaps (P1+)

  • /bind code visible in public chat — needs AddComponentPostInit("talker", ...) interceptor.
  • Day / season / boss status upstream (originally in PLAN §15.5) — deferred, not yet implemented.
  • Caves shard player events not aggregated into Master — accept cluster-level granularity for MVP.

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages