Feedback on speed-handler

Hello! Recently I’ve struggled for a few days to find a way over walkspeed overlapping in stuns, slows.
(scenario-below)

[Say you click M1 to swing in game, you get briefly slowed as you swing for about 0.65 seconds, then say you get slowed for a longer duration between the first 0.65 seconds, you’d be un-slowed by the first brief slow and the new one would be ignored, which is what I wanted to overcome without using TICK() or OS.CLOCK() in while loops.)

Now I would like to hear feedback on any bad practices here or generally what could be improved, if there’s an embarassing mistake that’s my bad I’m dead tired from this, here’s the code.

local AddedSpeeds = {}
local repStorage = game:GetService("ReplicatedStorage")
local character = script.Parent
local player = game.Players:GetPlayerFromCharacter(character)
 
 
local function getlength(Dictionary)
    local currentIteration = 0
    local iterationIncrement = 1
    for _,Table in pairs(Dictionary) do 
        currentIteration += iterationIncrement
    end
    return currentIteration
end
 
local speedHandlerEvent = Instance.new("BindableEvent")
speedHandlerEvent.Parent = character
 
speedHandlerEvent.Event:Connect(function(a,b)
    if a == "AddWS" then
        local name,ws,dura,priority = b.Name or "AddedWalkSpeed",b.WSVal or 16,b.Dura or 0, b.Priorty or 0
        local returnState = repStorage.Remotes.Functions.mainFunc:InvokeClient(player,"ReturnState")--get a state which is just a table containing the speed number
 
        if not AddedSpeeds[name] then --create a table for the new string if it doesnt exist
            print(name.." has been added to WalkSpeedQueue")
            AddedSpeeds[name] = {
                Name = name, --the string 
                Speed = ws, --the speed amount 
                Duration = dura, --duration 
                Priority = priority, --speed priority [higher-prefered]
            }
        else
            return
        end
        --set speed to new speed only if the new speed is lower than the current OR if new priority is higher than current
        local LastSpeedFirst = ws 
 
        for i,Table in pairs(AddedSpeeds) do 
            local foundName, foundSpeed, foundDuration, foundPriority = Table.Name, Table.Speed, Table.Duration, Table.Priority;
            if foundSpeed <=ws then
                LastSpeedFirst = foundSpeed
            end
            if foundPriority < priority then
                LastSpeedFirst = foundSpeed
            end
        end
        returnState.Speed = LastSpeedFirst
        repStorage.Remotes.Events.Main:FireClient(player,"SetSpeed",returnState)--update to new speed
        
        if dura and dura ~= math.huge then --if duration is math.huge that means its a speed modifications that lasts until manually removed using ``bindableEvent:Fire("RemoveWS",{Name = ..string..})``
            task.delay(dura,function()
                --remove added speed from queue
                if AddedSpeeds and AddedSpeeds[name] then
                    print("Removed speed table "..name..".")
                    AddedSpeeds[name] = nil
                end
 
                local Length = getlength(AddedSpeeds)
                if Length<=0 then --remove any speed modifications if the table is empty 
                    local returnState = repStorage.Remotes.Functions.mainFunc:InvokeClient(player,"ReturnState")
                    returnState.Speed = 16 --set speed to roblox default
 
                    repStorage.Remotes.Events.Main:FireClient(player,"SetSpeed",returnState) --update to new speed
                else 
 
                    --if the table isnt empty after the added speed is removed it means there's more speeds in queue so we check for the one with lowest speed and duration then use it
                    local returnState2 = repStorage.Remotes.Functions.mainFunc:InvokeClient(player,"ReturnState")--update to new speed
                    local LastSpeed,LastDuration,LastPriority,LastName = 16,50,0,"";
                    for i,Table in pairs(AddedSpeeds) do 
                        local foundName, foundSpeed, foundDuration, foundPriority = Table.Name, Table.Speed, Table.Duration, Table.Priority;
                        if foundName then
                            LastName = foundName
                        end
                        if foundSpeed<LastSpeed and foundDuration>LastDuration then
                            LastSpeed,LastDuration = foundSpeed,foundDuration;
                        end
                        if foundPriority > LastPriority then
                            LastSpeed,LastDuration = foundSpeed,foundDuration;
                        end
                    end
                    returnState2.Speed = LastSpeed
                    repStorage.Remotes.Events.Main:FireClient(player,"SetSpeed",returnState2)--update to new speed
 
                end
            end)
        end
    elseif a == "RemoveWS" then
        local name = b.Name
 
 
        --remove a speed (based on the sent string) from queue table
        if AddedSpeeds and AddedSpeeds[name] then
            print("Removed speed table "..name..".")
            AddedSpeeds[name] = nil
        end
        local returnState2 = repStorage.Remotes.Functions.mainFunc:InvokeClient(player,"ReturnState")
        returnState2.Speed = 16
 
 
 
        --check for more speed modifications incase there is some left.
        local LastSpeed,LastDuration,LastPriority = 16,50,0;
        for i,Table in pairs(AddedSpeeds) do 
            local foundSpeed, foundDuration, foundPriority =  Table.Speed, Table.Duration, Table.Priority;
            if foundSpeed<LastSpeed and foundDuration>LastDuration then
                LastSpeed,LastDuration = foundSpeed,foundDuration;
            end
            if foundPriority > LastPriority then
                LastSpeed,LastDuration = foundSpeed,foundDuration;
            end
        end
        returnState2.Speed = LastSpeed
        repStorage.Remotes.Events.Main:FireClient(player,"SetSpeed",returnState2)--update to new speed
    end
end)

Let me know where to improve!

Please move to

in the future.

Oopsies! I’ve read the Help and “Feedback” so I thought it’s here, will do.

I think you just need a tag for each unique slow origin and then overwrite this tag whenever a slow effect happens. When you come to stop a slow effect, check the tag is the same as it was when the slow was applied and only remove the slow if this is the case.

I have tried this earlier but had problems I can’t overcome with tags removing when they’re not supposed to and mainly, not removing at all, will try again though.