Forest Logo
search
package_2

round-manager

By @moxxum

Roblox

Mirrored

round-manager

Match/round state machine — the RobloxWare backbone. States cycle Lobby → Intermission → Active → Results → Lobby with configurable durations, player ready/spectate handling, map/mode voting during Intermission, and a StateChanged signal per transition. Pure server-side state: replicate to clients through netkit however the game likes.

Server realm: RoundManager = "moxxum/round-manager@0.1.0" under [server-dependencies].

API

local rm = RoundManager.new(config?)
rm.StateChanged:Connect(function(newState, oldState, data) end)
rm:Start() / rm:Stop() / rm:Destroy()
rm:GetState()            -- "Lobby" | "Intermission" | "Active" | "Results"
rm:GetTimeRemaining()    -- seconds left in a timed state, nil in Lobby
rm:GetParticipants()     -- snapshot taken when the round went Active
rm:SetReady(player, bool) / rm:IsReady(player)          -- used when RequireReady
rm:SetSpectating(player, bool) / rm:IsSpectating(player)
rm:VoteMap(player, name) / rm:VoteMode(player, name)    -- Intermission only → boolean
rm:GetMapVotes() / rm:GetModeVotes()                    -- { [option] = count }
rm:EndRoundEarly(results?)                              -- Active → Results now

Config (defaults): IntermissionSeconds = 15, ActiveSeconds = 120, ResultsSeconds = 10, MinPlayers = 2, RequireReady = false, Maps/Modes (vote options; omit to skip voting).

StateChanged data: { Map, Mode, Duration, Participants, Results } (fields present where they make sense; Results is whatever you passed to EndRoundEarly).

Rules: below MinPlayers the machine sits in Lobby (Intermission falls back to Lobby if players leave). A round ends early when every participant leaves. Ready flags clear on each return to Lobby; ties and no-vote rounds pick randomly.

Example

local rm = RoundManager.new({
	IntermissionSeconds = GameConfig.Round.IntermissionSeconds,
	ActiveSeconds = GameConfig.Round.ActiveSeconds,
	MinPlayers = 2,
	Maps = { "Desert", "City" },
})

rm.StateChanged:Connect(function(newState, _old, data)
	Remotes.RoundState:FireAll(newState, data.Map, data.Duration)
	if newState == "Active" then
		for _, player in data.Participants do
			spawnIntoArena(player, data.Map)
		end
	end
end)

rm:Start()

Test

rojo build test.project.json -o test.rbxl, open in Studio, Play Solo, expect [round-manager-test] ALL PASS within ~15s (full cycle, voting, early end, spectate).

Package Details

Install command (Click to copy)


Version

0.1.0

License

MIT

check_circle

Safe for commercial use

infoThe package archive does not include its license text; the license is declared in its manifest metadata.

Automated license review — not legal advice.