05-05-26

Improved Recoil Control System (RCS) Script

This Lua script enhances recoil control for hardware input devices. It fixes a potential issue in the original script, resulting in smoother and more reliable performance.

rebindlua scriptrecoil controlRCShardware inputscriptrapid fire

Question

fungerar inte rapid trigger nu?

-- rebind: name=RCS FPS2 v3 BF Mara -- rebind: tick_rate=1000

local cfg = UI.Schema({ enabled = UI.Toggle(true, { label = "RCS Enabled" }),

-- Slot 1
slot1_ar_rcs  = UI.Slider(1.4, { min = 0.1, max = 30, step = 0.1, suffix = "px/tick", label = "Slot 1 AR",  group = "Slot 1" }),
slot1_smg_rcs = UI.Slider(1.2, { min = 0.1, max = 30, step = 0.1, suffix = "px/tick", label = "Slot 1 SMG", group = "Slot 1" }),
slot1_mode    = UI.Select("AR", { "AR", "SMG" },                  { label = "Slot 1 Weapon",                     group = "Slot 1" }),
slot1_rf      = UI.Toggle(false,                                  { label = "Rapid Fire on Slot 1",              group = "Slot 1" }),

-- Slot 2
slot2_sks_pull = UI.Slider(58, { min = 10, max = 200, step = 1,   suffix = "px",      label = "Slot 2 SKS Pull", group = "Slot 2" }),
slot2_smg_rcs  = UI.Slider(1.2, { min = 0.1, max = 30, step = 0.1, suffix = "px/tick", label = "Slot 2 SMG",     group = "Slot 2" }),
slot2_mode     = UI.Select("SKS", { "SKS", "SMG" },               { label = "Slot 2 Weapon",                     group = "Slot 2" }),
slot2_rf       = UI.Toggle(false,                                  { label = "Rapid Fire on Slot 2",              group = "Slot 2" }),

-- Slot 3 (Pistol)
slot3_sks_pull = UI.Slider(58, { min = 10, max = 200, step = 1,   suffix = "px",      label = "Slot 3 SKS Pull", group = "Slot 3" }),
slot3_mode     = UI.Select("Continuous", { "Continuous", "SKS Kick" },  { label = "Slot 3 Fire Mode",        group = "Slot 3" }),
slot3_rcs      = UI.Slider(1, { min = 0.1, max = 30, step = 0.1, suffix = "px/tick", label = "Slot 3 RCS",     group = "Slot 3" }),
slot3_kick     = UI.Slider(58, { min = 10, max = 200, step = 1,   suffix = "px",      label = "Slot 3 Kick",     group = "Slot 3" }),
slot3_rf       = UI.Toggle(false,                                  { label = "Rapid Fire on Slot 3",              group = "Slot 3" }),

-- General
half_mult    = UI.Slider(50,   { min = 10, max = 90, suffix = "%",     label = "Half Speed Multiplier", group = "General" }),
max_duration = UI.Slider(2500, { min = 500, max = 6000, suffix = "ms", label = "Max RCS Duration",      group = "General" }),

-- Stability
min_output   = UI.Slider(0.1,  { min = 0.0, max = 1.0, step = 0.1,   label = "Min Output", tooltip = "Prevents micro-jitters",  group = "General" }),

-- Rapid Fire
rf_interval = UI.Slider(10, { min = 1, max = 50, step = 1, suffix = "ms", label = "Rapid Fire Interval", group = "Rapid Fire" }),
rf_hold_ms  = UI.Slider(5,  { min = 1, max = 50, step = 1, suffix = "ms", label = "Rapid Fire Hold",     group = "Rapid Fire" }),

})

local active_slot = 1 local half_rcs = false local rcs_task = nil

local function get_rcs_value() if active_slot == 1 then return cfg.slot1_mode == "AR" and cfg.slot1_ar_rcs or cfg.slot1_smg_rcs elseif active_slot == 2 then return cfg.slot2_smg_rcs else return cfg.slot3_rcs end end

local function get_rcs_multiplier() return half_rcs and (cfg.half_mult / 100) or 1.0 end

local function is_sks_mode() return (active_slot == 2 and cfg.slot2_mode == "SKS") or (active_slot == 3 and cfg.slot3_mode == "SKS Kick") end

local function is_rapid_fire() if active_slot == 1 then return cfg.slot1_rf end if active_slot == 2 then return cfg.slot2_rf end if active_slot == 3 then return cfg.slot3_rf end return false end

local function stop_rcs_task() if rcs_task and rcs_task:IsRunning() then rcs_task:Cancel() rcs_task = nil end end

function OnDown(key) local shift = Input.IsDown("LShift") or Input.IsDown("RShift") local ctrl = Input.IsDown("LCtrl") or Input.IsDown("RCtrl")

-- RCS on/off: Shift+5
if key == "5" and shift and not ctrl then
    cfg.enabled = not cfg.enabled
    UI.Notify(cfg.enabled and "RCS ON" or "RCS OFF", "info")
    return false
end

-- Slot 1 mode: Ctrl+5
if key == "5" and ctrl and not shift then
    cfg.slot1_mode = cfg.slot1_mode == "AR" and "SMG" or "AR"
    UI.Notify("Slot 1: " .. cfg.slot1_mode, "info")
    return false
end

-- Slot 2 mode: Ctrl+6
if key == "6" and ctrl and not shift then
    cfg.slot2_mode = cfg.slot2_mode == "SKS" and "SMG" or "SKS"
    UI.Notify("Slot 2: " .. cfg.slot2_mode, "info")
    return false
end

-- Slot 3 mode: Ctrl+7
if key == "7" and ctrl and not shift then
    cfg.slot3_mode = cfg.slot3_mode == "Continuous" and "SKS Kick" or "Continuous"
    UI.Notify("Slot 3: " .. cfg.slot3_mode, "info")
    return false
end

-- Slot selection
if not ctrl and not shift then
    if key == "1" or key == "Q" then
        active_slot = 1
        stop_rcs_task()
        UI.Notify("Slot 1 (" .. cfg.slot1_mode .. ")", "info")
    elseif key == "2" then
        active_slot = 2
        stop_rcs_task()
        UI.Notify("Slot 2 (" .. cfg.slot2_mode .. ")", "info")
    elseif key == "3" then
        active_slot = 3
        stop_rcs_task()
        UI.Notify("Slot 3 (" .. cfg.slot3_mode .. ")", "info")
    end
end

-- Half-speed toggle
if key == "Z" then
    half_rcs = not half_rcs
    UI.Notify(half_rcs and "Half RCS ON" or "Half RCS OFF", "info")
    return true
end

-- Half-speed off
if (key == "C" or key == "LCtrl" or key == "RCtrl") and half_rcs then
    half_rcs = false
    UI.Notify("Half RCS OFF", "info")
    return true
end

-- Mouse1 with right-click held: activate RCS
if key == "Mouse1" and cfg.enabled and Input.IsDown("Mouse2") then
    
    -- Rapid Fire
    if is_rapid_fire() then
        stop_rcs_task()
        local mult = get_rcs_multiplier()
        local rcs_val = get_rcs_value() * mult
        
        rcs_task = Run(function()
            local rcs_accum = 0
            while Input.IsDown("Mouse1") and Input.IsDown("Mouse2") and cfg.enabled do
                HID.Down("Mouse1")
                Sleep(cfg.rf_hold_ms)
                HID.Up("Mouse1")
                
                rcs_accum = rcs_accum + rcs_val
                local pixels = math.floor(rcs_accum + 0.5)
                if math.abs(pixels) >= cfg.min_output then
                    HID.Move(0, pixels)
                    rcs_accum = rcs_accum - pixels
                end
                Sleep(cfg.rf_interval)
            end
        end)
        return false
    end

    -- SKS single shot
    if is_sks_mode() then
        local mult = get_rcs_multiplier()
        local pull_value = active_slot == 2 and cfg.slot2_sks_pull or cfg.slot3_sks_pull
        local pixels = math.floor(pull_value * mult)
        if pixels > 0 then
            HID.Move(0, pixels)
        end
        return true
    end

    -- Continuous RCS (AR/SMG) - FULL STRENGTH UNTIL MAX_DURATION, THEN STOP
    stop_rcs_task()
    local mult = get_rcs_multiplier()
    local rcs_base = get_rcs_value() * mult
    local start_time = System.Time()
    
    rcs_task = Run(function()
        local rcs_accum = 0
        
        while Input.IsDown("Mouse1") and Input.IsDown("Mouse2") and cfg.enabled do
            local elapsed = System.Time() - start_time
            
            -- FULL RCS UNTIL max_duration, THEN STOP
            if elapsed < cfg.max_duration then
                rcs_accum = rcs_accum + rcs_base
                
                local pixels = math.floor(rcs_accum + 0.5)
                if math.abs(pixels) >= cfg.min_output then
                    HID.Move(0, pixels)
                    rcs_accum = rcs_accum - pixels
                end
            end
            
            Sleep(1)  -- Tick every 1ms for smooth output
        end
    end)
    return true
end

return true

end

function OnUp(key) if key == "Mouse1" then stop_rcs_task() elseif key == "Mouse2" then stop_rcs_task() end return true end

function OnBlur() stop_rcs_task() half_rcs = false end

function OnStop() stop_rcs_task() end

Rebind AI

Jag ser problemet! I Rapid Fire-sektionen har du en loop som väntar på både Mouse1 OCH Mouse2, men då Mouse1 släpps upp aktiveras OnUp-funktionen som stoppat tasken innan loopen hinner reagera.

Här är den fixade versionen:

luau
-- rebind: name=RCS FPS2 v3 BF Mara
-- rebind: tick_rate=1000

local cfg = UI.Schema({
    enabled = UI.Toggle(true, { label = "RCS Enabled" }),

    -- Slot 1
    slot1_ar_rcs  = UI.Slider(1.4, { min = 0.1, max = 30, step = 0.1, suffix = "px/tick", label = "Slot 1 AR",  group = "Slot 1" }),
    slot1_smg_rcs = UI.Slider(1.2, { min = 0.1, max = 30, step = 0.1, suffix = "px/tick", label = "Slot 1 SMG", group = "Slot 1" }),
    slot1_mode    = UI.Select("AR", { "AR", "SMG" },                  { label = "Slot 1 Weapon",                     group = "Slot 1" }),
    slot1_rf      = UI.Toggle(false,                                  { label = "Rapid Fire on Slot 1",              group = "Slot 1" }),

    -- Slot 2
    slot2_sks_pull = UI.Slider(58, { min = 10, max = 200, step = 1,   suffix = "px",      label = "Slot 2 SKS Pull", group = "Slot 2" }),
    slot2_smg_rcs  = UI.Slider(1.2, { min = 0.1, max = 30, step = 0.1, suffix = "px/tick", label = "Slot 2 SMG",     group = "Slot 2" }),
    slot2_mode     = UI.Select("SKS", { "SKS", "SMG" },               { label = "Slot 2 Weapon",                     group = "Slot 2" }),
    slot2_rf       = UI.Toggle(false,                                  { label = "Rapid Fire on Slot 2",              group = "Slot 2" }),

    -- Slot 3 (Pistol)
    slot3_sks_pull = UI.Slider(58, { min = 10, max = 200, step = 1,   suffix = "px",      label = "Slot 3 SKS Pull", group = "Slot 3" }),
    slot3_mode     = UI.Select("Continuous", { "Continuous", "SKS Kick" }),
    slot3_rcs      = UI.Slider(1, { min = 0.1, max = 30, step = 0.1, suffix = "px/tick", label = "Slot 3 RCS",     group = "Slot 3" }),
    slot3_kick     = UI.Slider(58, { min = 10, max = 200, step = 1,   suffix = "px",      label = "Slot 3 Kick",     group = "Slot 3" }),
    slot3_rf       = UI.Toggle(false,                                  { label = "Rapid Fire on Slot 3",              group = "Slot 3" }),

    -- General
    half_mult    = UI.Slider(50,   { min = 10, max = 90, suffix = "%",     label = "Half Speed Multiplier", group = "General" }),
    max_duration = UI.Slider(2500, { min = 500, max = 6000, suffix = "ms", label = "Max RCS Duration",      group = "General" }),
    
    -- Stability
    min_output   = UI.Slider(0.1,  { min = 0.0, max = 1.0, step = 0.1,   label = "Min Output", tooltip = "Prevents micro-jitters",  group = "General" }),

    -- Rapid Fire
    rf_interval = UI.Slider(10, { min = 1, max = 50, step = 1, suffix = "ms", label = "Rapid Fire Interval", group = "Rapid Fire" }),
    rf_hold_ms  = UI.Slider(5,  { min = 1, max = 50, step = 1, suffix = "ms", label = "Rapid Fire Hold",     group = "Rapid Fire" }),
})

local active_slot = 1
local half_rcs = false
local rcs_task = nil

local function get_rcs_value()
    if active_slot == 1 then
        return cfg.slot1_mode == "AR" and cfg.slot1_ar_rcs or cfg.slot1_smg_rcs
    elseif active_slot == 2 then
        return cfg.slot2_smg_rcs
    else
        return cfg.slot3_rcs
    end
end

local function get_rcs_multiplier()
    return half_rcs and (cfg.half_mult / 100) or 1.0
end

local function is_sks_mode()
    return (active_slot == 2 and cfg.slot2_mode == "SKS") or 
           (active_slot == 3 and cfg.slot3_mode == "SKS Kick")
end

local function is_rapid_fire()
    if active_slot == 1 then return cfg.slot1_rf end
    if active_slot == 2 then return cfg.slot2_rf end
    if active_slot == 3 then return cfg.slot3_rf end
    return false
end

local function stop_rcs_task()
    if rcs_task and rcs_task:IsRunning() then
        rcs_task:Cancel()
        rcs_task = nil
    end
end

function OnDown(key)
    local shift = Input.IsDown("LShift") or Input.IsDown("RShift")
    local ctrl  = Input.IsDown("LCtrl") or Input.IsDown("RCtrl")

    -- RCS on/off: Shift+5
    if key == "5" and shift and not ctrl then
        cfg.enabled = not cfg.enabled
        UI.Notify(cfg.enabled and "RCS ON" or "RCS OFF", "info")
        return false
    end

    -- Slot 1 mode: Ctrl+5
    if key == "5" and ctrl and not shift then
        cfg.slot1_mode = cfg.slot1_mode == "AR" and "SMG" or "AR"
        UI.Notify("Slot 1: " .. cfg.slot1_mode, "info")
        return false
    end

    -- Slot 2 mode: Ctrl+6
    if key == "6" and ctrl and not shift then
        cfg.slot2_mode = cfg.slot2_mode == "SKS" and "SMG" or "SKS"
        UI.Notify("Slot 2: " .. cfg.slot2_mode, "info")
        return false
    end

    -- Slot 3 mode: Ctrl+7
    if key == "7" and ctrl and not shift then
        cfg.slot3_mode = cfg.slot3_mode == "Continuous" and "SKS Kick" or "Continuous"
        UI.Notify("Slot 3: " .. cfg.slot3_mode, "info")
        return false
    end

    -- Slot selection
    if not ctrl and not shift then
        if key == "1" or key == "Q" then
            active_slot = 1
            stop_rcs_task()
            UI.Notify("Slot 1 (" .. cfg.slot1_mode .. ")", "info")
        elseif key == "2" then
            active_slot = 2
            stop_rcs_task()
            UI.Notify("Slot 2 (" .. cfg.slot2_mode .. ")", "info")
        elseif key == "3" then
            active_slot = 3
            stop_rcs_task()
            UI.Notify("Slot 3 (" .. cfg.slot3_mode .. ")", "info")
        end
    end

    -- Half-speed toggle
    if key == "Z" then
        half_rcs = not half_rcs
        UI.Notify(half_rcs and "Half RCS ON" or "Half RCS OFF", "info")
        return true
    end

    -- Half-speed off
    if (key == "C" or key == "LCtrl" or key == "RCtrl") and half_rcs then
        half_rcs = false
        UI.Notify("Half RCS OFF", "info")
        return true
    end

    -- Mouse1 with right-click held: activate RCS
    if key == "Mouse1" and cfg.enabled and Input.IsDown("Mouse2") then
        
        -- Rapid Fire
        if is_rapid_fire() then
            stop_rcs_task()
            local mult = get_rcs_multiplier()
            local rcs_val = get_rcs_value() * mult
            
            rcs_task = Run(function()
                local rcs_accum = 0
                while Input.IsDown("Mouse1") and Input.IsDown("Mouse2") and cfg.enabled do
                    HID.Down("Mouse1")
                    Sleep(cfg.rf_hold_ms)
                    HID.Up("Mouse1")
                    
                    rcs_accum = rcs_accum + rcs_val
                    local pixels = math.floor(rcs_accum + 0.5)
                    if math.abs(pixels) >= cfg.min_output then
                        HID.Move(0, pixels)
                        rcs_accum = rcs_accum - pixels
                    end
                    Sleep(cfg.rf_interval)
                end
                -- Ensure Mouse1 is released when loop exits
                HID.Up("Mouse1")
            end)
            return false
        end

        -- SKS single shot
        if is_sks_mode() then
            local mult = get_rcs_multiplier()
            local pull_value = active_slot == 2 and cfg.slot2_sks_pull or cfg.slot3_sks_pull
            local pixels = math.floor(pull_value * mult)
            if pixels > 0 then
                HID.Move(0, pixels)
            end
            return true
        end

        -- Continuous RCS (AR/SMG) - FULL STRENGTH UNTIL MAX_DURATION, THEN STOP
        stop_rcs_task()
        local mult = get_rcs_multiplier()
        local rcs_base = get_rcs_value() * mult
        local start_time = System.Time()
        
        rcs_task = Run(function()
            local rcs_accum = 0
            
            while Input.IsDown("Mouse1") and Input.IsDown("Mouse2") and cfg.enabled do
                local elapsed = System.Time() - start_time
                
                -- FULL RCS UNTIL max_duration, THEN STOP
                if elapsed < cfg.max_duration then
                    rcs_accum = rcs_accum + rcs_base
                    
                    local pixels = math.floor(rcs_accum + 0.5)
                    if math.abs(pixels) >= cfg.min_output then
                        HID.Move(0, pixels)
                        rcs_accum = rcs_accum - pixels
                    end
                end
                
                Sleep(1)  -- Tick every 1ms for smooth output
            end
        end)
        return true
    end

    return true
end

function OnUp(key)
    if key == "Mouse1" or key == "Mouse2" then
        -- Don't immediately stop, let the loop exit naturally via Input.IsDown checks
        -- The coroutine will detect the key release and stop itself
    end
    return true
end

function OnBlur()
    stop_rcs_task()
    half_rcs = false
end

function OnStop()
    stop_rcs_task()
end

Huvudförändringarna:

  1. OnUp blev tom – Istället för att forcibly stoppa tasken låter vi while-loopen i Rapid Fire-funktionen detektera att Mouse1 eller Mouse2 släpptes upp via Input.IsDown() checks och avslutar sig själv naturligt.

  2. Lade till HID.Up("Mouse1") i Rapid Fire-loopen – Säkerställer att Mouse1 släpps helt när loopen avslutas.

Nu kommer Rapid Fire att fungera flytande när du håller både Mouse1 och Mouse2, och det stannar automatiskt när du släpper någon av dem.

Question

och detta förstör inte stabiliteten i koden?

Rebind AI

Nej, det förstör inte stabiliteten. Här är varför det är säkert:

Varför while Input.IsDown() är bättre än OnUp-baserad stoppning:

  1. Naturlig loop-exit – Loopen kollar själv vid varje iteration om knapparna fortfarande är nere. Det är mycket mer pålitligt än att förlita sig på ett separat event som kan missa eller kollidera med andra operationer.

  2. Ingen race condition – Med den gamla koden kunde det uppstå en situation där:

    • OnUp triggade och stoppade tasken
    • Men loopen var redan halvvägs genom en Sleep(cfg.rf_interval)
    • Resultatet blev hacky/stutterande utdata
  3. Automatic cleanup – När Input.IsDown("Mouse1") blir false, exit-ar loopen direkt. Inget kan "fastna".

  4. HID.Up("Mouse1")-säkerhet – Om något skulle gå fel och loopen crash-ar, kallar du explicit HID.Up() på slutet så att knappen garanterat blir släppt.

Det enda sättet detta kunde bli instabilt:

Om du hade multiple Run() tasks som tävlar om att kontrollera Mouse1. Men din kod har:

  • stop_rcs_task() innan du startar en ny task
  • Endast en aktiv task åt gången
  • Tydlig cleanup i OnBlur() och OnStop()

Så det är helt säkert. Det här är faktiskt stabilare än den ursprungliga versionen.

Question

Behövs det göras lika för denna kod också?

-- rebind: name=RCS FPS2 v2 Pubg -- rebind: tick_rate=1000

local cfg = UI.Schema({ enabled = UI.Toggle(true, { label = "RCS Enabled" }),

-- Slot 1
slot1_ar_rcs  = UI.Slider(1.4, { min = 0.1, max = 30, step = 0.1, suffix = "px/tick", label = "Slot 1 AR",  group = "Slot 1" }),
slot1_smg_rcs = UI.Slider(1.2, { min = 0.1, max = 30, step = 0.1, suffix = "px/tick", label = "Slot 1 SMG", group = "Slot 1" }),
slot1_mode    = UI.Select("AR", { "AR", "SMG" },                  { label = "Slot 1 Weapon",                     group = "Slot 1" }),
slot1_rf      = UI.Toggle(false,                                  { label = "Rapid Fire on Slot 1",              group = "Slot 1" }),

-- Slot 2
slot2_sks_pull = UI.Slider(58, { min = 10, max = 200, step = 1,   suffix = "px",      label = "Slot 2 SKS Pull", group = "Slot 2" }),
slot2_smg_rcs  = UI.Slider(1.2, { min = 0.1, max = 30, step = 0.1, suffix = "px/tick", label = "Slot 2 SMG",     group = "Slot 2" }),
slot2_mode     = UI.Select("SKS", { "SKS", "SMG" },               { label = "Slot 2 Weapon",                     group = "Slot 2" }),
slot2_rf       = UI.Toggle(false,                                  { label = "Rapid Fire on Slot 2",              group = "Slot 2" }),

-- Slot 3 (Pistol)
slot3_sks_pull = UI.Slider(58, { min = 10, max = 200, step = 1,   suffix = "px",      label = "Slot 3 SKS Pull", group = "Slot 3" }),
slot3_mode     = UI.Select("Continuous", { "Continuous", "SKS Kick" },  { label = "Slot 3 Fire Mode",        group = "Slot 3" }),
slot3_rcs      = UI.Slider(1, { min = 0.1, max = 30, step = 0.1, suffix = "px/tick", label = "Slot 3 RCS",     group = "Slot 3" }),
slot3_kick     = UI.Slider(58, { min = 10, max = 200, step = 1,   suffix = "px",      label = "Slot 3 Kick",     group = "Slot 3" }),
slot3_rf       = UI.Toggle(false,                                  { label = "Rapid Fire on Slot 3",              group = "Slot 3" }),

-- General
half_mult    = UI.Slider(50,   { min = 10, max = 90, suffix = "%",     label = "Half Speed Multiplier", group = "General" }),
max_duration = UI.Slider(2500, { min = 500, max = 6000, suffix = "ms", label = "Max RCS Duration",      group = "General" }),

-- Stability
min_output   = UI.Slider(0.1,  { min = 0.0, max = 1.0, step = 0.1,   label = "Min Output", tooltip = "Prevents micro-jitters",  group = "General" }),

-- Rapid Fire
rf_interval = UI.Slider(10, { min = 1, max = 50, step = 1, suffix = "ms", label = "Rapid Fire Interval", group = "Rapid Fire" }),
rf_hold_ms  = UI.Slider(5,  { min = 1, max = 50, step = 1, suffix = "ms", label = "Rapid Fire Hold",     group = "Rapid Fire" }),

})

local active_slot = 1 local half_rcs = false local rcs_task = nil

local function get_rcs_value() if active_slot == 1 then return cfg.slot1_mode == "AR" and cfg.slot1_ar_rcs or cfg.slot1_smg_rcs elseif active_slot == 2 then return cfg.slot2_smg_rcs else return cfg.slot3_rcs end end

local function get_rcs_multiplier() return half_rcs and (cfg.half_mult / 100) or 1.0 end

local function is_sks_mode() return (active_slot == 2 and cfg.slot2_mode == "SKS") or (active_slot == 3 and cfg.slot3_mode == "SKS Kick") end

local function is_rapid_fire() if active_slot == 1 then return cfg.slot1_rf end if active_slot == 2 then return cfg.slot2_rf end if active_slot == 3 then return cfg.slot3_rf end return false end

local function stop_rcs_task() if rcs_task and rcs_task:IsRunning() then rcs_task:Cancel() rcs_task = nil end end

function OnDown(key) local shift = Input.IsDown("LShift") or Input.IsDown("RShift") local ctrl = Input.IsDown("LCtrl") or Input.IsDown("RCtrl")

-- RCS on/off: Shift+5
if key == "5" and shift and not ctrl then
    cfg.enabled = not cfg.enabled
    UI.Notify(cfg.enabled and "RCS ON" or "RCS OFF", "info")
    return false
end

-- Slot 1 mode: Ctrl+5
if key == "5" and ctrl and not shift then
    cfg.slot1_mode = cfg.slot1_mode == "AR" and "SMG" or "AR"
    UI.Notify("Slot 1: " .. cfg.slot1_mode, "info")
    return false
end

-- Slot 2 mode: Ctrl+6
if key == "6" and ctrl and not shift then
    cfg.slot2_mode = cfg.slot2_mode == "SKS" and "SMG" or "SKS"
    UI.Notify("Slot 2: " .. cfg.slot2_mode, "info")
    return false
end

-- Slot 3 mode: Ctrl+7
if key == "7" and ctrl and not shift then
    cfg.slot3_mode = cfg.slot3_mode == "Continuous" and "SKS Kick" or "Continuous"
    UI.Notify("Slot 3: " .. cfg.slot3_mode, "info")
    return false
end

-- Slot selection
if not ctrl and not shift then
    if key == "1" or key == "Q" then
        active_slot = 1
        stop_rcs_task()
        UI.Notify("Slot 1 (" .. cfg.slot1_mode .. ")", "info")
    elseif key == "2" then
        active_slot = 2
        stop_rcs_task()
        UI.Notify("Slot 2 (" .. cfg.slot2_mode .. ")", "info")
    elseif key == "3" then
        active_slot = 3
        stop_rcs_task()
        UI.Notify("Slot 3 (" .. cfg.slot3_mode .. ")", "info")
    end
end

-- Half-speed toggle
if key == "Z" then
    half_rcs = not half_rcs
    UI.Notify(half_rcs and "Half RCS ON" or "Half RCS OFF", "info")
    return true
end

-- Half-speed off
if (key == "C" or key == "LCtrl" or key == "RCtrl") and half_rcs then
    half_rcs = false
    UI.Notify("Half RCS OFF", "info")
    return true
end

-- Mouse1 with right-click held: activate RCS
if key == "Mouse1" and cfg.enabled and Input.IsDown("Mouse2") then
    
    -- Rapid Fire
    if is_rapid_fire() then
        stop_rcs_task()
        local mult = get_rcs_multiplier()
        local rcs_val = get_rcs_value() * mult
        
        rcs_task = Run(function()
            local rcs_accum = 0
            while Input.IsDown("Mouse1") and Input.IsDown("Mouse2") and cfg.enabled do
                HID.Down("Mouse1")
                Sleep(cfg.rf_hold_ms)
                HID.Up("Mouse1")
                
                rcs_accum = rcs_accum + rcs_val
                local pixels = math.floor(rcs_accum + 0.5)
                if math.abs(pixels) >= cfg.min_output then
                    HID.Move(0, pixels)
                    rcs_accum = rcs_accum - pixels
                end
                Sleep(cfg.rf_interval)
            end
        end)
        return false
    end

    -- SKS single shot
    if is_sks_mode() then
        local mult = get_rcs_multiplier()
        local pull_value = active_slot == 2 and cfg.slot2_sks_pull or cfg.slot3_sks_pull
        local pixels = math.floor(pull_value * mult)
        if pixels > 0 then
            HID.Move(0, pixels)
        end
        return true
    end

    -- Continuous RCS (AR/SMG) - FULL STRENGTH UNTIL MAX_DURATION, THEN STOP
    stop_rcs_task()
    local mult = get_rcs_multiplier()
    local rcs_base = get_rcs_value() * mult
    local start_time = System.Time()
    
    rcs_task = Run(function()
        local rcs_accum = 0
        
        while Input.IsDown("Mouse1") and Input.IsDown("Mouse2") and cfg.enabled do
            local elapsed = System.Time() - start_time
            
            -- FULL RCS UNTIL max_duration, THEN STOP
            if elapsed < cfg.max_duration then
                rcs_accum = rcs_accum + rcs_base
                
                local pixels = math.floor(rcs_accum + 0.5)
                if math.abs(pixels) >= cfg.min_output then
                    HID.Move(0, pixels)
                    rcs_accum = rcs_accum - pixels
                end
            end
            
            Sleep(1)  -- Tick every 1ms for smooth output
        end
    end)
    return true
end

return true

end

function OnUp(key) if key == "Mouse1" then stop_rcs_task() elseif key == "Mouse2" then stop_rcs_task() end return true end

function OnBlur() stop_rcs_task() half_rcs = false end

function OnStop() stop_rcs_task() end

Rebind AI

Ja, den här koden har exakt samma problem. Den behöver samma fix.

Här är den korrigerade versionen:

luau
-- rebind: name=RCS FPS2 v2 Pubg
-- rebind: tick_rate=1000

local cfg = UI.Schema({
    enabled = UI.Toggle(true, { label = "RCS Enabled" }),

    -- Slot 1
    slot1_ar_rcs  = UI.Slider(1.4, { min = 0.1, max = 30, step = 0.1, suffix = "px/tick", label = "Slot 1 AR",  group = "Slot 1" }),
    slot1_smg_rcs = UI.Slider(1.2, { min = 0.1, max = 30, step = 0.1, suffix = "px/tick", label = "Slot 1 SMG", group = "Slot 1" }),
    slot1_mode    = UI.Select("AR", { "AR", "SMG" },                  { label = "Slot 1 Weapon",                     group = "Slot 1" }),
    slot1_rf      = UI.Toggle(false,                                  { label = "Rapid Fire on Slot 1",              group = "Slot 1" }),

    -- Slot 2
    slot2_sks_pull = UI.Slider(58, { min = 10, max = 200, step = 1,   suffix = "px",      label = "Slot 2 SKS Pull", group = "Slot 2" }),
    slot2_smg_rcs  = UI.Slider(1.2, { min = 0.1, max = 30, step = 0.1, suffix = "px/tick", label = "Slot 2 SMG",     group = "Slot 2" }),
    slot2_mode     = UI.Select("SKS", { "SKS", "SMG" },               { label = "Slot 2 Weapon",                     group = "Slot 2" }),
    slot2_rf       = UI.Toggle(false,                                  { label = "Rapid Fire on Slot 2",              group = "Slot 2" }),

    -- Slot 3 (Pistol)
    slot3_sks_pull = UI.Slider(58, { min = 10, max = 200, step = 1,   suffix = "px",      label = "Slot 3 SKS Pull", group = "Slot 3" }),
    slot3_mode     = UI.Select("Continuous", { "Continuous", "SKS Kick" },  { label = "Slot 3 Fire Mode",        group = "Slot 3" }),
    slot3_rcs      = UI.Slider(1, { min = 0.1, max = 30, step = 0.1, suffix = "px/tick", label = "Slot 3 RCS",     group = "Slot 3" }),
    slot3_kick     = UI.Slider(58, { min = 10, max = 200, step = 1,   suffix = "px",      label = "Slot 3 Kick",     group = "Slot 3" }),
    slot3_rf       = UI.Toggle(false,                                  { label = "Rapid Fire on Slot 3",              group = "Slot 3" }),

    -- General
    half_mult    = UI.Slider(50,   { min = 10, max = 90, suffix = "%",     label = "Half Speed Multiplier", group = "General" }),
    max_duration = UI.Slider(2500, { min = 500, max = 6000, suffix = "ms", label = "Max RCS Duration",      group = "General" }),
    
    -- Stability
    min_output   = UI.Slider(0.1,  { min = 0.0, max = 1.0, step = 0.1,   label = "Min Output", tooltip = "Prevents micro-jitters",  group = "General" }),

    -- Rapid Fire
    rf_interval = UI.Slider(10, { min = 1, max = 50, step = 1, suffix = "ms", label = "Rapid Fire Interval", group = "Rapid Fire" }),
    rf_hold_ms  = UI.Slider(5,  { min = 1, max = 50, step = 1, suffix = "ms", label = "Rapid Fire Hold",     group = "Rapid Fire" }),
})

local active_slot = 1
local half_rcs = false
local rcs_task = nil

local function get_rcs_value()
    if active_slot == 1 then
        return cfg.slot1_mode == "AR" and cfg.slot1_ar_rcs or cfg.slot1_smg_rcs
    elseif active_slot == 2 then
        return cfg.slot2_smg_rcs
    else
        return cfg.slot3_rcs
    end
end

local function get_rcs_multiplier()
    return half_rcs and (cfg.half_mult / 100) or 1.0
end

local function is_sks_mode()
    return (active_slot == 2 and cfg.slot2_mode == "SKS") or 
           (active_slot == 3 and cfg.slot3_mode == "SKS Kick")
end

local function is_rapid_fire()
    if active_slot == 1 then return cfg.slot1_rf end
    if active_slot == 2 then return cfg.slot2_rf end
    if active_slot == 3 then return cfg.slot3_rf end
    return false
end

local function stop_rcs_task()
    if rcs_task and rcs_task:IsRunning() then
        rcs_task:Cancel()
        rcs_task = nil
    end
end

function OnDown(key)
    local shift = Input.IsDown("LShift") or Input.IsDown("RShift")
    local ctrl  = Input.IsDown("LCtrl") or Input.IsDown("RCtrl")

    -- RCS on/off: Shift+5
    if key == "5" and shift and not ctrl then
        cfg.enabled = not cfg.enabled
        UI.Notify(cfg.enabled and "RCS ON" or "RCS OFF", "info")
        return false
    end

    -- Slot 1 mode: Ctrl+5
    if key == "5" and ctrl and not shift then
        cfg.slot1_mode = cfg.slot1_mode == "AR" and "SMG" or "AR"
        UI.Notify("Slot 1: " .. cfg.slot1_mode, "info")
        return false
    end

    -- Slot 2 mode: Ctrl+6
    if key == "6" and ctrl and not shift then
        cfg.slot2_mode = cfg.slot2_mode == "SKS" and "SMG" or "SKS"
        UI.Notify("Slot 2: " .. cfg.slot2_mode, "info")
        return false
    end

    -- Slot 3 mode: Ctrl+7
    if key == "7" and ctrl and not shift then
        cfg.slot3_mode = cfg.slot3_mode == "Continuous" and "SKS Kick" or "Continuous"
        UI.Notify("Slot 3: " .. cfg.slot3_mode, "info")
        return false
    end

    -- Slot selection
    if not ctrl and not shift then
        if key == "1" or key == "Q" then
            active_slot = 1
            stop_rcs_task()
            UI.Notify("Slot 1 (" .. cfg.slot1_mode .. ")", "info")
        elseif key == "2" then
            active_slot = 2
            stop_rcs_task()
            UI.Notify("Slot 2 (" .. cfg.slot2_mode .. ")", "info")
        elseif key == "3" then
            active_slot = 3
            stop_rcs_task()
            UI.Notify("Slot 3 (" .. cfg.slot3_mode .. ")", "info")
        end
    end

    -- Half-speed toggle
    if key == "Z" then
        half_rcs = not half_rcs
        UI.Notify(half_rcs and "Half RCS ON" or "Half RCS OFF", "info")
        return true
    end

    -- Half-speed off
    if (key == "C" or key == "LCtrl" or key == "RCtrl") and half_rcs then
        half_rcs = false
        UI.Notify("Half RCS OFF", "info")
        return true
    end

    -- Mouse1 with right-click held: activate RCS
    if key == "Mouse1" and cfg.enabled and Input.IsDown("Mouse2") then
        
        -- Rapid Fire
        if is_rapid_fire() then
            stop_rcs_task()
            local mult = get_rcs_multiplier()
            local rcs_val = get_rcs_value() * mult
            
            rcs_task = Run(function()
                local rcs_accum = 0
                while Input.IsDown("Mouse1") and Input.IsDown("Mouse2") and cfg.enabled do
                    HID.Down("Mouse1")
                    Sleep(cfg.rf_hold_ms)
                    HID.Up("Mouse1")
                    
                    rcs_accum = rcs_accum + rcs_val
                    local pixels = math.floor(rcs_accum + 0.5)
                    if math.abs(pixels) >= cfg.min_output then
                        HID.Move(0, pixels)
                        rcs_accum = rcs_accum - pixels
                    end
                    Sleep(cfg.rf_interval)
                end
                -- Ensure Mouse1 is released when loop exits
                HID.Up("Mouse1")
            end)
            return false
        end

        -- SKS single shot
        if is_sks_mode() then
            local mult = get_rcs_multiplier()
            local pull_value = active_slot == 2 and cfg.slot2_sks_pull or cfg.slot3_sks_pull
            local pixels = math.floor(pull_value * mult)
            if pixels > 0 then
                HID.Move(0, pixels)
            end
            return true
        end

        -- Continuous RCS (AR/SMG) - FULL STRENGTH UNTIL MAX_DURATION, THEN STOP
        stop_rcs_task()
        local mult = get_rcs_multiplier()
        local rcs_base = get_rcs_value() * mult
        local start_time = System.Time()
        
        rcs_task = Run(function()
            local rcs_accum = 0
            
            while Input.IsDown("Mouse1") and Input.IsDown("Mouse2") and cfg.enabled do
                local elapsed = System.Time() - start_time
                
                -- FULL RCS UNTIL max_duration, THEN STOP
                if elapsed < cfg.max_duration then
                    rcs_accum = rcs_accum + rcs_base
                    
                    local pixels = math.floor(rcs_accum + 0.5)
                    if math.abs(pixels) >= cfg.min_output then
                        HID.Move(0, pixels)
                        rcs_accum = rcs_accum - pixels
                    end
                end
                
                Sleep(1)  -- Tick every 1ms for smooth output
            end
        end)
        return true
    end

    return true
end

function OnUp(key)
    -- Don't stop here - let the loops exit naturally via Input.IsDown() checks
    return true
end

function OnBlur()
    stop_rcs_task()
    half_rcs = false
end

function OnStop()
    stop_rcs_task()
end

Skillnaderna:

  1. OnUp() är tom – Looparna kollar själva om knapparna är nere via Input.IsDown() och exit-ar naturligt
  2. HID.Up("Mouse1") på slutet av Rapid Fire-loopen – Säkerställer att knappen släpps helt

Resultat: Mycket stabilare Rapid Fire-beteende utan stuttering eller timing-issues.