function RaceModule.SetRacers(m,o)for m=1,#o,1 do addRacer(o[m])end end function RaceModule.RegisterCheckpoint(m,o)if not checkpoints[o]then local m=Checkpoint.new(o,RaceModule)numCheckpoints=numCheckpoints+1 checkpoints[o]=m end end function RaceModule.PlayerCrossedCheckpoint(T,o,m)local g=racers[o]if not g or g.FinishedRace then return end local z=g.CurrentLap CheckpointEvent:FireClient(o,{{"\099\104\101\099\107\112\111\105\110\116\072\105\116",m.CollisionBody}})if not g:HasStartedLap(z)then g:StartLap(z)onLapStartedEvent:Fire(o,z)end if g:HasStartedLap(z)then local T=m:SetPlayerPassed(o,z)if not T then onCheckpointPassedEvent:Fire(m.CollisionBody)end end if hasPlayerFinishedLap(o,z)then local m=g:FinishLap(z)onLapFinishedEvent:Fire(o,z,m)if z==numLaps then if not winner then winner=o end g.FinishedRace=true onRaceFinishedEvent:Fire(winner)else wait()CheckpointEvent:FireClient(o,{{"\110\101\119\076\097\112"}})g.CurrentLap=g.CurrentLap+1 end end end function RaceModule.Start(m,o)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")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(o)end for o,m in pairs(checkpoints)do m:Reset()end onRaceStartedEvent:Fire()local T=false local g g=RaceModule.RaceFinished:connect(function()T=true racers={}g:disconnect()end)spawn(function()wait(raceDuration)if not T then onRaceFinishedEvent:Fire(winner)end end)end

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")
	
	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()