Greetings! This script has been in the works since October, and is a rewrite of the existing RaceHandler that supports multiple game modes, as before it would only support 1 game mode.
I am wondering how I am able to make sure this script runs as efficient as possible.
Anyways, here it is!
local Mode: string
-- Services
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local MarketplaceService = game:GetService("MarketplaceService")
local Workspace = game:GetService("Workspace")
local Players = game:GetService("Players")
local ServerStorage = game:GetService("ServerStorage")
local PlayerRankTable = {}
Players.PlayerAdded:Connect(function(Player: Player)
local Map = Workspace:WaitForChild("Map")
Player:SetAttribute("SpawnNumber", 1)
Player:SetAttribute("PlayerCompleted", false)
Player:SetAttribute("LapNumber", 1)
Player:SetAttribute("CheckpointNumber", 1)
Player:SetAttribute("IsSaving", false)
Player:SetAttribute("RankNumber", 1)
PlayerRankTable[Player:GetAttribute("RankNumber")] = Player
task.wait(1)
Mode = ServerStorage.MapInfo:GetAttribute("Gamemode")
ReplicatedStorage.MapLoader.SetClientGamemode:FireClient(Player, Mode)
CreateKeyCheckpointsValue(Player)
end)
-- Variables
local Map = Workspace:WaitForChild("Map")
local SavingCheckpoints = Map.SavingCheckpoints
local Checkpoints = Map.Checkpoints
local MapLaps = Map:GetAttribute("MaxLaps")
local MapName = Map:GetAttribute("Name")
-- Events
-- Functions
local function FormattedTime(Seconds: number)
return string.format("%d:%.02d", Seconds/60, Seconds%60, Seconds*1000%1000)
end
local NumberOfMapCheckpoints: number = #Checkpoints:GetChildren(...) - 1
function CreateKeyCheckpointsValue(Player: Player)
local NewFolder: Folder = Instance.new("BinaryStringValue")
for Checkpoint = 1, NumberOfMapCheckpoints do
NewFolder:SetAttribute(Checkpoint, false)
end
NewFolder.Name = "KeyCheckpoints"
NewFolder.Parent = Player
end
local function SetCheckpoint(Player, Checkpoint, Value)
local CheckpointNumber: number = tonumber(Checkpoint.Name)
if CheckpointNumber == 1 and Player.KeyCheckpoints:GetAttribute(NumberOfMapCheckpoints) then
for AttributeName, AttributeValue in pairs(Player.KeyCheckpoints:GetAttributes()) do
Player.KeyCheckpoints:SetAttribute(AttributeName, false)
end
end
if Mode == "Multiplayer" then
if not Player.KeyCheckpoints:GetAttribute(CheckpointNumber) then
if PlayerRankTable[Player:GetAttribute("RankNumber")] == Player then
PlayerRankTable[Player:GetAttribute("RankNumber")] = nil
end
Player:SetAttribute("RankNumber", Player:GetAttribute("RankNumber") + 1)
PlayerRankTable[Player:GetAttribute("RankNumber")] = Player
table.sort(PlayerRankTable, function(a, b)
return a > b
end)
print("Sorted")
local LoopTime = 1
for PlayerRank, TablePlayer in pairs(PlayerRankTable) do
print("Sending")
ReplicatedStorage.UpdateRanking:FireClient(TablePlayer, LoopTime)
LoopTime += 1
end
print("Process Finished")
print(PlayerRankTable)
end
end
Player.KeyCheckpoints:SetAttribute(CheckpointNumber, Value)
Player:SetAttribute("CheckpointNumber", CheckpointNumber)
end
-- The real action happens here
for _, SaverCheckpoint in pairs(SavingCheckpoints:GetChildren(...)) do
SaverCheckpoint.Touched:Connect(function(CharacterPart)
if CharacterPart.Parent:FindFirstChildOfClass("Humanoid") then
local Player: Player = game:GetService("Players"):GetPlayerFromCharacter(CharacterPart.Parent)
Player:SetAttribute("SpawnNumber", tonumber(SaverCheckpoint.Name))
end
end)
end
for _, KeyCheckpoint in pairs(Checkpoints:GetChildren(...)) do
KeyCheckpoint.Touched:Connect(function(CharacterPart)
if CharacterPart.Parent:FindFirstChildOfClass("Humanoid") then
local Player: Player = Players:GetPlayerFromCharacter(CharacterPart.Parent)
if KeyCheckpoint.Name ~= "EndRace" then
if CharacterPart.Parent:FindFirstChildOfClass("Humanoid") then
SetCheckpoint(Player, KeyCheckpoint, true)
end
else
if not Player:GetAttribute("PlayerCompleted") then
local Valid: boolean = true
for AttributeName, AttributeValue in pairs(Player.KeyCheckpoints:GetAttributes()) do
if not AttributeValue then
Valid = false
end
end
if Valid then
if Mode ~= "FreeRoam" then
if Player:GetAttribute("LapNumber") == MapLaps then
CompletedRace(Player)
else
CompletedLap(Player)
end
end
end
end
end
end
end)
end
function CompletedLap(Player: Player)
for AttributeName, AttributeValue in pairs(Player.KeyCheckpoints:GetAttributes()) do
Player.KeyCheckpoints:SetAttribute(AttributeName, false)
end
Player:SetAttribute("LapNumber", Player:GetAttribute("LapNumber") + 1)
ReplicatedStorage.ToClientLaps:FireClient(Player, Player:GetAttribute("LapNumber"))
end
local MapRewards = {
Stars1 = {XP = 50, Tires = 50},
Stars2 = {XP = 100, Tires = 100},
Stars3 = {XP = 200, Tires = 200},
}
function CompletedRace(Player: Player)
Player:SetAttribute("PlayerCompleted", true)
local TimeTrialsValue = ReplicatedStorage.TimeTrials.Value
local MapDataRewards = Map.Rewards
local Rank: string
if TimeTrialsValue >= MapDataRewards.Stars2:GetAttribute("Time") then
Rank = "Stars1"
end
if TimeTrialsValue <= MapDataRewards.Stars2:GetAttribute("Time") then
Rank = "Stars2"
end
if TimeTrialsValue <= MapDataRewards.Stars3:GetAttribute("Time") then
Rank = "Stars3"
end
if Player:FindFirstChild("TimeTrialsData") then
if Player.TimeTrialsData:GetAttribute(MapName) >= TimeTrialsValue then
Player.TimeTrialsData:SetAttribute(MapName, TimeTrialsValue)
end
if Rank == "Stars3" then
ReplicatedStorage.Music:FireClient(Player, "Stars3")
elseif Rank == "Stars2" then
ReplicatedStorage.Music:FireClient(Player, "Stars2")
else
ReplicatedStorage.Music:FireClient(Player, "Stars1")
end
Player.Levels:SetAttribute("Current", Player.Levels:GetAttribute("Current") + MapRewards[Rank].XP)
Player.Currencies:SetAttribute("Tires", Player.Currencies:GetAttribute("Tires") + MapRewards[Rank].Tires)
else
ReplicatedStorage.Music:FireClient(Player, "Stars3")
end
ReplicatedStorage.EndRace:FireClient(Player, MapRewards[Rank].Tires, Rank, MapDataRewards[Rank]:GetAttribute("XP"))
end
Thanks in advance!