function RaceModule.SetRacers(N,v)for N=1,#v,1 do addRacer(v[N])end end function RaceModule.RegisterCheckpoint(N,v)if not checkpoints[v]then local N=Checkpoint.new(v,RaceModule)numCheckpoints=numCheckpoints+1 checkpoints[v]=N end end function RaceModule.PlayerCrossedCheckpoint(u,v,N)local j=racers[v]if not j or j.FinishedRace then return end local a=j.CurrentLap CheckpointEvent:FireClient(v,{{"\099\104\101\099\107\112\111\105\110\116\072\105\116";N.CollisionBody}})if not j:HasStartedLap(a)then j:StartLap(a)onLapStartedEvent:Fire(v,a)end if j:HasStartedLap(a)then local u=N:SetPlayerPassed(v,a)if not u then onCheckpointPassedEvent:Fire(N.CollisionBody)end end if hasPlayerFinishedLap(v,a)then local N=j:FinishLap(a)onLapFinishedEvent:Fire(v,a,N)if a==numLaps then if not winner then winner=v end j.FinishedRace=true onRaceFinishedEvent:Fire(winner)else wait()CheckpointEvent:FireClient(v,{{"\110\101\119\076\097\112"}})j.CurrentLap=j.CurrentLap+1 end end end function RaceModule.Start(N,v)if debugEnabled then print("\082\065\067\069\077\079\068\085\076\069\058 \083\116\097\114\116\105\110\103 \114\097\099\101")end winner=nil assert(numCheckpoints>0,"\078\111 \099\104\101\099\107\112\111\105\110\116\115 \114\101\103\105\115\116\101\114\101\100")assert(startCheckpoint,"\083\116\097\114\116 \067\104\101\099\107\112\111\105\110\116 \110\111\116 \115\101\116")assert(finishCheckpoint,"\070\105\110\105\115\104 \067\104\101\099\107\112\111\105\110\116 \110\111\116 \115\101\116")if debugEnabled then print("\082\065\067\069\077\079\068\085\076\069\058 \067\104\101\099\107\105\110\103 \105\102 \112\108\097\121\101\114\115 \115\101\116")end if#racers==0 then RaceModule:SetRacers(v)end for v,N in pairs(checkpoints)do N:Reset()end onRaceStartedEvent:Fire()local u=false local j j=RaceModule.RaceFinished:connect(function()u=true racers={}j:disconnect()end)spawn(function()wait(raceDuration)if not u then onRaceFinishedEvent:Fire(winner)end end)end
-- ================================================================================
-- PUBLIC FUNCTIONS
-- ================================================================================
function RaceModule:SetRacers(racerList)
	for i = 1, #racerList do
		addRacer(racerList[i])
	end
end -- RaceModule:SetRacers()

function RaceModule:RegisterCheckpoint(checkpoint)
	if not checkpoints[checkpoint] then
		local newCheckpoint = Checkpoint.new(checkpoint, RaceModule)
		numCheckpoints = numCheckpoints + 1
		checkpoints[checkpoint] = newCheckpoint
	end
end -- RaceModule:RegisterCheckpoint()

function RaceModule:PlayerCrossedCheckpoint(player, checkpoint)
	local racer = racers[player]

	if not racer or racer.FinishedRace then
		return
	end
	local currentLap = racer.CurrentLap

	CheckpointEvent:FireClient(player, { { "checkpointHit", checkpoint.CollisionBody } })

	if not racer:HasStartedLap(currentLap) then
		racer:StartLap(currentLap)
		onLapStartedEvent:Fire(player, currentLap)
	end

	if racer:HasStartedLap(currentLap) then
		local alreadyPassed = checkpoint:SetPlayerPassed(player, currentLap)
		if not alreadyPassed then
			onCheckpointPassedEvent:Fire(checkpoint.CollisionBody)
		end
	end

	if hasPlayerFinishedLap(player, currentLap) then
		local lapTime = racer:FinishLap(currentLap)
		onLapFinishedEvent:Fire(player, currentLap, lapTime)
		if currentLap == numLaps then
			if not winner then
				winner = player
			end
			racer.FinishedRace = true
			onRaceFinishedEvent:Fire(winner)
		else
			wait() -- Let the last checkpoint temporarily change to hit color

			CheckpointEvent:FireClient(player, { { "newLap" } })

			racer.CurrentLap = racer.CurrentLap + 1
		end
	end
end -- RaceModule:PlayerCrossedCheckpoint()

function RaceModule:Start(activePlayers)
	if debugEnabled then
		print("RACEMODULE: Starting race")
	end

	winner = nil

	assert(numCheckpoints > 0, "No checkpoints registered")
	assert(startCheckpoint, "Start Checkpoint not set")
	assert(finishCheckpoint, "Finish Checkpoint not set")

	if debugEnabled then
		print("RACEMODULE: Checking if players set")
	end
	if #racers == 0 then
		RaceModule:SetRacers(activePlayers)
	end

	for _, checkpoint in pairs(checkpoints) do
		checkpoint:Reset()
	end

	onRaceStartedEvent:Fire()

	local raceOver = false
	local finishedConnection
	finishedConnection = RaceModule.RaceFinished:connect(function()
		raceOver = true
		racers = {}
		finishedConnection:disconnect()
	end)
	spawn(function()
		wait(raceDuration)
		if not raceOver then
			onRaceFinishedEvent:Fire(winner)
		end
	end)
end -- RaceModule:Start()
