Skip to content

Repository files navigation

This is the reference game for TMC's Dot collection. If you want to see the assets working together before you commit to any of them, start here.

The Dot collection is a set of open source Godot 4 assets that provide modular building blocks for games and applications in the TMC ecosystem, covering core functionality, networking, authentication, cloud integration, and more. This project is built out of them, so it doubles as a worked example of what they look like in a real game rather than in a demo.

This project and the assets under it are COMPLETELY OPEN SOURCE. You are free to use, modify, and distribute them under the terms of the MIT license. The only thing not open source is the back-end web infrastructure. So if you opt into using your own authentication backend instead of integrating with TMC, you will need to build and integrate your own back-end infrastructure.

From Maintainer & WARNING

This project, along with every asset it is built on, was built initially with Claude Code and will continue to be maintained and extended using it. This is because I (gamemann) cannot build the entire TMC platform alone (I wish I could lol).

Please treat this as partially tested. It has its own headless test suite and that suite passes, but very little of this has been in front of real players yet. Expect rough edges, and please report anything you run into.

I intend on reviewing code, testing, and editing documentation regularly. If you're interested in helping out, please let me know!

The Reference Game

A 3D dev-textured arena deathmatch, built entirely out of the dot-* family. Four weapons, one map, a match that ends on its score limit, and a HUD and menus with no art assets anywhere.

This is the reference game. It exists to prove the addons compose, to show what the bridges between them look like, and to be the thing a new game is copied from.

Playing it

ln -s ../../dot-core/addons/dot_core addons/dot_core   # and the other seven
godot --path .                                         # bots, no server needed

No dedicated server, no dot-cloud, no downloads: with no dot_client_link registered the client is the authority, loads dm_atrium out of its own build and adds three bots. -- --offline forces that even when a link is available.

WASD Move
Space Jump. Hold it, auto-hop is on
Ctrl Crouch
Mouse 1 Fire
R Reload
1..4 / wheel Weapon slot
Tab (hold) Scoreboard
Esc Pause menu, and release the mouse

The match starts in warmup. It is WARMUP, then COUNTDOWN, then LIVE, and nobody spawns until LIVE, because dot-match's respawn queue is what places a player, and it does not run before then. On the shipped rules that is about thirteen seconds at 64 ticks, so a screenshot taken earlier than that shows an empty room and a player at the origin, which is correct and looks exactly like a broken spawn.

Running it headless

godot --headless --path . res://examples/headless_match.tscn   # a whole deathmatch
godot --headless --path . res://examples/headless_net.tscn     # the netcode
godot --headless --path . res://examples/dedicated.tscn        # a real DotServer
godot --headless --path . res://examples/headless_admin.tscn   # an admin's live tools on it

Or, once dot-serve is installed:

dotserve --game res://examples/dedicated.tscn --name "My arena"

What it is made of

dot-core Everything shared.
dot-player-controller Movement. Classic strafe acceleration, air-strafing, auto-hop.
dot-combat Health, weapons, hit registration.
dot-loadout What you take in, and what you may take.
dot-match Rounds, scoring, spawning, respawning.
dot-ui HUD, pause menu, settings, controls, scoreboard.
dot-server The dedicated server, through one module.

The four files that matter

maps/arena_map.gd: a level is a list of boxes, and that list becomes three things: meshes, physics bodies, and analytic geometry for a headless server. Building them separately means three descriptions that drift, and the drift is invisible until shots start passing through something clients can see.

game/arena_player.gd: movement, weapons, health and hitboxes on one body. Every addon says this wiring belongs in the game, because an addon that did it would dictate a scene shape.

game/arena_game.gd: the seam. Six addons, each correct alone; this is the fifty lines where a combat kill becomes a match score and a match respawn becomes a loadout.

game/arena_module.gd: the only file that names dot-server. About forty lines, and it is the entire dedicated-server integration.

The weapons

Four, because they are four genuinely different answers to "how do I close distance", and a deathmatch with fewer has one right answer.

Pistol Never runs out, always loses a fair fight. Which is what makes picking something up worth doing.
Rifle Wins at range, loses in a corridor. Bloom punishes holding the trigger.
Shotgun Nine pellets in a learnable ring, so range is a skill rather than a dice roll.
Rocket Launcher Low direct damage, high splash. The interesting part is what it does to the floor, and to your own feet.

Loadouts are two weapons on a six-point budget: a rifle and a shotgun, or a rocket launcher and a pistol, and not a rocket launcher and a shotgun. Four numbers instead of an enumeration.

Configuring the map vote

The vote for the next map is dot-vote, and the rules in game/arena_vote.gd are only this game's defaults. A server owner overrides any of dot-vote's settings without touching code, in user://cfg/arena_vote.json, then DOT_VOTE_*, then --vote-* — later wins — or, on a TMC server, under metadata: map_vote: in the game's game.yml. A file that does not validate is refused whole and the defaults stand, with the reason in the log.

The end-of-map vote and the option to extend the current map:

{ "end_vote": true, "vote_lead_sec": 120, "include_extend": true, "extend_seconds": 600, "max_extends": 3 }

end_vote: false turns the end-of-map ballot off (the map still ends, on the rotation); include_extend: false takes "extend" off the ballot; extend_seconds is how much one extension adds and max_extends how many there may be. Every setting is in dot-vote's README, and its docs/parity.md maps the long-standing community map-chooser plugins' settings onto them.

Validating

godot --headless --path . --import
find . -name '*.gd' -not -path './.godot/*' -not -path './addons/*' | while read f; do
    godot --headless --path . --check-only --script "res://${f#./}"
done
godot --headless --path . res://examples/headless_match.tscn
godot --headless --path . res://examples/headless_net.tscn
godot --headless --path . res://examples/dedicated.tscn
godot --headless --path . res://examples/headless_admin.tscn

headless_match: 311 checks. Plays an entire deathmatch: four bots, real movement, real shots, real kills, real respawns, ending on the score limit. Then builds the HUD and the menus and drives them.

headless_net: 136 checks. Runs a server and a client in one process over a loopback that drops packets: the wire round-trips, a spawn is mirrored, movement replicates, the client moves on the tick it presses, the two stay together under loss, a player an admin noclips on the server is predicted flying by their own client rather than rubber-banding, and an admin's blind reaches the blinded player's client and no other while a beacon reaches both.

dedicated: 100 checks. Boots a real DotServer, binds a port, loads the module, runs its console commands, unloads it and loads it again.

headless_admin: 44 checks over nine sections. The same real server, with an administrator, a moderator and a player typing !noclip, !god, !freeze, !slay and the rest: a noclipped player goes through the wall and the floor, a godded one takes a hit and loses nothing, a frozen one holding forward does not move, a slain one dies and is counted, a moderator cannot noclip anybody, a player with no flags is refused, a blind lifts on its own when its seconds are up, a slay inside spawn protection still kills, and blind and beacon survive a respawn.

The admin tools

dot-moderation's live tools, with this game's verbs in game/arena_mod_tools.gd. Everything is typable in chat with a !:

Command Flag
noclip, god, buddha [player] [on|off] cheats bare, they act on you
hp <player> <n>, speed <player> <x>, gravity <player> <x> cheats speed and gravity are steps from 0.25× to 3×, so the client can predict them
give <player> <weapon>, strip <player> cheats
freeze <player> [seconds], unfreeze, slay, slap <player> [damage], respawn, rename, burn slay
blind <player> [on|off|seconds] slay blacks out that player's own screen and nobody else's
beacon <player> [on|off] slay a pulsing ring, a column through walls and a ping, on every screen, until turned off
bring, goto, send <player> <to>, return teleport
modtools [player] generic what this game supports, or what is on somebody

Targets are anything kick takes, plus @me, @all, @others, @alive, @dead and @team:<n>. Blind and beacon both outlive a death, as god does; noclip and freeze end with the body. tools/screenshot.sh dm_box --admin renders both.

Licence

MIT. See LICENSE.

About

A 3D Godot DeathMatch game with modes and maps for TDM, FFA, GunGame, and more. Uses @modcommunity's Dot assets and servers are deployed onto the gaming platform!

Topics

Resources

Stars

2 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages