CCCPaste

0fb64b66f236f

!strict
local Players = game:GetService("Players")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local GameInfo = ReplicatedStorage:WaitForChild("GameInfo") :: Folder
local Remotes = ReplicatedStorage:WaitForChild("Remotes") :: Folder
local MainGame = Remotes:WaitForChild("MainGame") :: Folder
local MatchState = MainGame:WaitForChild("MatchState") :: RemoteEvent
local Modules = script.Parent
local MapVoting = require(Modules:WaitForChild("MapVoting"))
local MapManager = require(Modules:WaitForChild("MapManager"))
local ModeManager = require(Modules:WaitForChild("ModeManager"))
local PlayerManager = require(Modules:WaitForChild("PlayerManager"))
type RBXConn = RBXScriptConnection
export type GameController = {
	state: string,
	currentMap: Instance?,
	connections: { RBXConn },
	SetState: (self: GameController, stateName: string) -> (),
	RunIntermission: (self: GameController) -> (),
	RunMatch: (self: GameController) -> (),
	Start: (self: GameController) -> (),
}
local INTERMISSION_DURATION: number = 25
local MIN_PLAYERS: number = 2
local MATCH_FALLBACK_DURATION: number = 180
local GameController = {}
GameController.__index = GameController
local function new(): GameController
	local self = setmetatable({
		state = "Idle",
		currentMap = nil,
		connections = {},
	}, GameController) :: GameController
	return self
end
function GameController:trackConnection(conn: RBXConn)
	local list = self.connections
	list[#list + 1] = conn
end
function GameController:cleanupConnections()
	local list = self.connections
	for i = 1, #list do
		local conn = list[i]
		if conn.Connected then
			conn:Disconnect()
		end
	end
	table.clear(list)
end
function GameController:playersReady(): boolean
	return #Players:GetPlayers() >= MIN_PLAYERS
end
function GameController:SetState(stateName: string)
	self.state = stateName
	MatchState:FireAllClients(stateName)
	local modeValue = GameInfo:FindFirstChild("Mode")
	if modeValue and modeValue:IsA("StringValue") then
		modeValue.Value = stateName
	end
end
local function setBool(folder: Instance, name: string, value: boolean)
	local obj = folder:FindFirstChild(name)
	if obj and obj:IsA("BoolValue") then
		obj.Value = value
	end
end
local function setString(folder: Instance, name: string, value: string)
	local obj = folder:FindFirstChild(name)
	if obj and obj:IsA("StringValue") then
		obj.Value = value
	end
end
local function setInt(folder: Instance, name: string, value: number)
	local obj = folder:FindFirstChild(name)
	if obj and obj:IsA("IntValue") then
		obj.Value = value
	end
end
function GameController:RunIntermission()
	self:SetState("Intermission")
	local duration = INTERMISSION_DURATION
	local elapsed = 0
	while self.state == "Intermission" do
		local enoughPlayers = self:playersReady()
		local remaining = math.max(duration - elapsed, 0)
		if enoughPlayers then
			if remaining <= 0 then
				break
			end
			setString(GameInfo, "ModeInfo", "Next round in " .. tostring(remaining))
		else
			setString(GameInfo, "ModeInfo", "Waiting for players...")
		end
		setBool(GameInfo, "OnGoing", false)
		setBool(GameInfo, "GradientBgAllowed", false)
		setBool(GameInfo, "GradientTextAllowed", false)
		setInt(GameInfo, "Countdown", remaining)
		if enoughPlayers and remaining <= 0 then
			break
		end
		task.wait(1)
		elapsed += 1
	end
end
function GameController:RunMatch()
	self:SetState("PreMatch")
	local mapConfig = MapVoting.Select()
	local mapInstance = MapManager.Load(mapConfig)
	self.currentMap = mapInstance
	ModeManager.Apply(mapConfig)
	PlayerManager.Prepare(mapInstance)
	self:cleanupConnections()
	setBool(GameInfo, "OnGoing", true)
	setBool(GameInfo, "GradientBgAllowed", true)
	setBool(GameInfo, "GradientTextAllowed", true)
	setString(GameInfo, "ModeInfo", "Match in progress")
	setInt(GameInfo, "Countdown", 0)
	self:SetState("InGame")
	local ended = false
	local matchEndedSignal = MainGame:FindFirstChild("MatchEnded")
	if matchEndedSignal and matchEndedSignal:IsA("BindableEvent") then
		self:trackConnection(matchEndedSignal.Event:Connect(function()
			ended = true
		end))
	end
	local elapsed = 0
	while not ended and self.state == "InGame" do
		if #Players:GetPlayers() < MIN_PLAYERS then
			ended = true
			break
		end
		if elapsed >= MATCH_FALLBACK_DURATION then
			ended = true
			break
		end
		task.wait(1)
		elapsed += 1
	end
	self:cleanupConnections()
	if self.currentMap then
		MapManager.Unload(self.currentMap)
		self.currentMap = nil
	end
	PlayerManager.Reset()
	self:SetState("PostMatch")
	setBool(GameInfo, "OnGoing", false)
	setString(GameInfo, "ModeInfo", "Round ended")
	setInt(GameInfo, "Countdown", 0)
end
function GameController:Start()
	while true do
		self:RunIntermission()
		if not self:playersReady() then
			continue
		end
		self:RunMatch()
	end
end
local controller = new()
task.defer(function()
	controller:Start()
end)
return controller