Fixing Remote Event Spam

The error message suggests that the SkyboxChangeEvent is being fired too frequently, causing the event queue to be exhausted. This is likely happening because we're firing the event every time a player touches any part of the road, which can occur multiple times per second. Let's optimize this by introducing a cooldown and only firing the event when the biome actually changes. Here's the updated script:

-- ServerScriptService for road generation

local Workspace = game:GetService("Workspace")
local Lighting = game:GetService("Lighting")
local ReplicatedStorage = game:GetService("ReplicatedStorage")

local RoadTemplates = {
    Normal1 = Workspace.Road,
    Normal2 = Workspace.Road2,
    Normal3 = Workspace.Road3,
    Normal4 = Workspace.Road4,
    Normal5 = Workspace.Road5,
    Desert = Workspace.DesertRoad,
    Snow = Workspace.SnowRoad,
    Bridge = Workspace.BridgeRoad,
    Bloody = Workspace.BLOODYROAD,
}

local offsetX = 50
local lastXPosition = 0
local currentBiome = "Normal1"
local cloneCount = 0
local firstPlayerJoined = false

-- Create a RemoteEvent for client-side skybox changes
local SkyboxChangeEvent = Instance.new("RemoteEvent")
SkyboxChangeEvent.Name = "SkyboxChangeEvent"
SkyboxChangeEvent.Parent = ReplicatedStorage

local function getRandomBiomeLength()
    return math.random(30, 70)  -- Variable biome length between 30 and 70 segments
end

local function getNextBiome()
    local biomes = {"Normal1", "Normal2", "Normal3", "Normal4", "Normal5", "Desert", "Snow", "Bloody"}
    return biomes[math.random(#biomes)]
end

local function CloneRoom(xOffset, roomTemplate)
    local newRoom = roomTemplate:Clone()
    newRoom.Parent = Workspace

    for _, part in ipairs(newRoom:GetDescendants()) do
        if part:IsA("BasePart") then
            part.CFrame = part.CFrame + Vector3.new(xOffset, 0, 0)
        end
    end
    
    return newRoom
end

local playerBiomes = {}
local biomeChangeCooldown = {}

local function SetPlayerBiome(player, newBiome)
    if playerBiomes[player] ~= newBiome and (not biomeChangeCooldown[player] or tick() - biomeChangeCooldown[player] > 1) then
        playerBiomes[player] = newBiome
        biomeChangeCooldown[player] = tick()
        
        if newBiome == "Bloody" then
            SkyboxChangeEvent:FireClient(player, true)
        else
            SkyboxChangeEvent:FireClient(player, false)
        end
    end
end

local function GenerateRoads()
    local biomeLength = getRandomBiomeLength()
    local bridgeGenerated = false
    local currentBiomeInstance = nil

    while true do
        if currentBiome == "Bridge" and not bridgeGenerated then
            currentBiomeInstance = CloneRoom(lastXPosition, RoadTemplates.Bridge)
            lastXPosition += offsetX
            cloneCount += 1
            bridgeGenerated = true
        else
            currentBiomeInstance = CloneRoom(lastXPosition, RoadTemplates[currentBiome])
            lastXPosition += offsetX
            cloneCount += 1

            if cloneCount >= biomeLength then
                if math.random() < 0.1 then  -- 10% chance for a bridge
                    currentBiome = "Bridge"
                    bridgeGenerated = false
                else
                    currentBiome = getNextBiome()
                end
                biomeLength = getRandomBiomeLength()
                cloneCount = 0
            end
        end
        
        -- Set up TouchedEvent for the new biome instance
        if currentBiomeInstance then
            for _, part in ipairs(currentBiomeInstance:GetDescendants()) do
                if part:IsA("BasePart") then
                    part.Touched:Connect(function(hit)
                        local player = game.Players:GetPlayerFromCharacter(hit.Parent)
                        if player then
                            SetPlayerBiome(player, currentBiome)
                        end
                    end)
                end
            end
        end
        
        task.wait(1)  -- Using task.wait() for more consistent timing
    end
end

game.Players.PlayerAdded:Connect(function(player)
    if not firstPlayerJoined then
        firstPlayerJoined = true
        task.wait(5)
        GenerateRoads()
    end
    
    -- Set up client-side skybox changes
    local function onSkyboxChange(isBloody)
        if isBloody then
            -- Set bloody skybox and atmosphere
            Lighting.Ambient = Color3.new(1, 0, 0)
            Lighting.OutdoorAmbient = Color3.new(1, 0, 0)
            Lighting.ColorShift_Bottom = Color3.new(1, 0, 0)
            Lighting.ColorShift_Top = Color3.new(1, 0, 0)
        else
            -- Set normal skybox and atmosphere
            Lighting.Ambient = Color3.new(0.5, 0.5, 0.5)
            Lighting.OutdoorAmbient = Color3.new(0.5, 0.5, 0.5)
            Lighting.ColorShift_Bottom = Color3.new(0, 0, 0)
            Lighting.ColorShift_Top = Color3.new(0, 0, 0)
        end
    end
    
    SkyboxChangeEvent.OnClientEvent:Connect(onSkyboxChange)
end)

game.Players.PlayerRemoving:Connect(function(player)
    playerBiomes[player] = nil
    biomeChangeCooldown[player] = nil
end)

Key Changes:

These changes should significantly reduce the number of remote events being fired, preventing the "Remote event invocation queue exhausted" error. The skybox will now only change when a player moves to a different biome, and there's a cooldown to prevent rapid changes.