Improve this roblox script, and add auto-counter block and slap lag handler as well as dynamic Directional Block (Aim-Lock), and an advanced Reaction-Based Auto-Block (Triggered by Attacks).

```
-- Super Advanced Auto Block Script for Saber Showdown
-- Enhanced with Dynamic Auto-Blocking, Hitbox Detection, and Animation State Detection

-- === Services !==
local Players = game:GetService("Players")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local UserInputService = game:GetService("UserInputService")
local RunService = game:GetService("RunService")
local StarterGui = game:GetService("StarterGui")
local VirtualInputManager = game:GetService("VirtualInputManager")
local CollectionService = game:GetService("CollectionService") -- For tagging hitboxes

-- === Player Setup ===
local player = Players.LocalPlayer
local character = player.Character or player.CharacterAdded:Wait()
local humanoid = character:WaitForChild("Humanoid")
local humanoidRootPart = character:WaitForChild("HumanoidRootPart")

-- === Remotes ===
local LightsaberRemotes = ReplicatedStorage:WaitForChild("LightsaberRemotes")
local BlockRemote = LightsaberRemotes:WaitForChild("Block")
local UnblockRemote = LightsaberRemotes:WaitForChild("Unblock")
local UpdateManualBlockRemote = LightsaberRemotes:WaitForChild("UpdateManualBlock")
local UpdateBlockDirectionRemote = LightsaberRemotes:WaitForChild("UpdateBlockDirection")

-- === Settings ===
local Settings = {
    -- Blocking Settings
    blockDistance = 15,            -- Max distance to attempt a block
    autoBlockEnabled = true,       -- Enable/Disable dynamic auto-blocking
    blockCooldown = 0.5,           -- Cooldown between blocks (seconds)
    attackTypes = {                -- Attack animation IDs
        Slap = 12625891544,
        SlappedLegs = 12671715182,
        SlappedArms = 12625896358,
        Punch = 12625897000,       -- Example attack ID
        Kick = 12625897500,        -- Example attack ID
        KickUp = 12625897944,      -- Added KickUp
        KickBack = 12625899752      -- Added KickBack
    },
    
    -- Counter Attacking Settings
    autoCounterEnabled = true,     -- Enable/Disable auto counter attacks
    autoCounterDistance = 10,      -- Distance within which to auto counter
    counterCooldown = 1.5,         -- Cooldown between counters (seconds)
    counterKey = Enum.KeyCode.E,    -- Key to use for countering
    
    -- UI Settings
    ui = {
        ScreenGuiName = "AutoBlockUI",
        BlackBoxSize = UDim2.new(0.25, 0, 0.1, 0),
        BlackBoxPosition = UDim2.new(0, 0, 0.9, 0),
        BlackBoxColor = Color3.fromRGB(0, 0, 0),
        BlackBoxTransparency = 0.5,
        LoadingBarSize = UDim2.new(1, 0, 0.2, 0),
        LoadingBarPosition = UDim2.new(0, 0, -0.2, 0),
        LoadingBarColor = Color3.fromRGB(0, 255, 0),
        LoadingBarTransparency = 0.3,
        MessageBoxText = "Press 'Q' to toggle Auto Block",
        MessageBoxColor = Color3.fromRGB(255, 255, 255),
        MessageBoxTransparency = 1,
    }
}

-- === State Tracking ===
local isBlocking = false
local lastBlockTime = {}
local lastCounterTime = {}

-- === UI Setup ===
local screenGui = Instance.new("ScreenGui")
screenGui.Name = Settings.ui.ScreenGuiName
screenGui.Parent = player:WaitForChild("PlayerGui")
screenGui.ResetOnSpawn = false

-- Black Box Frame
local blackBox = Instance.new("Frame")
blackBox.Size = Settings.ui.BlackBoxSize
blackBox.Position = Settings.ui.BlackBoxPosition
blackBox.BackgroundColor3 = Settings.ui.BlackBoxColor
blackBox.BackgroundTransparency = Settings.ui.BlackBoxTransparency
blackBox.Parent = screenGui

-- Loading Bar
local loadingBar = Instance.new("Frame")
loadingBar.Size = Settings.ui.LoadingBarSize
loadingBar.Position = Settings.ui.LoadingBarPosition
loadingBar.BackgroundColor3 = Settings.ui.LoadingBarColor
loadingBar.BackgroundTransparency = Settings.ui.LoadingBarTransparency
loadingBar.Parent = blackBox

-- Message Box
local messageBox = Instance.new("TextLabel")
messageBox.Size = UDim2.new(1, 0, 1, 0)
messageBox.Position = UDim2.new(0, 0, 0, 0)
messageBox.BackgroundTransparency = Settings.ui.MessageBoxTransparency
messageBox.TextColor3 = Settings.ui.MessageBoxColor
messageBox.TextScaled = true
messageBox.Text = Settings.ui.MessageBoxText
messageBox.Parent = blackBox

-- === Utility Functions ===

-- Function to start blocking
local function startBlocking()
    if not isBlocking then
        isBlocking = true
        BlockRemote:FireServer()
        print("[AutoBlock] Blocking started")
    end
end

-- Function to stop blocking
local function stopBlocking()
    if isBlocking then
        isBlocking = false
        UnblockRemote:FireServer()
        print("[AutoBlock] Blocking stopped")
    end
end

-- Function to toggle blocking manually
local function toggleBlocking()
    if isBlocking then
        stopBlocking()
    else
        startBlocking()
    end
end

-- Function to determine hit direction based on the position of the attacker
local function getHitDirection(attackerPosition)
    local characterPosition = humanoidRootPart.Position
    local direction = (attackerPosition - characterPosition).Unit
    local angle = math.deg(math.atan2(direction.Z, direction.X))
    if angle < 0 then angle = angle + 360 end

    if angle >= 0 and angle < 45 then
        return 1 -- Forward
    elseif angle >= 45 and angle < 135 then
        return 2 -- Right
    elseif angle >= 135 and angle < 225 then
        return 3 -- Backward
    elseif angle >= 225 and angle < 315 then
        return 4 -- Left
    else
        return 1 -- Forward (default wrap-around)
    end
end

-- Function to update block direction
local function updateBlockDirection(direction)
    UpdateBlockDirectionRemote:FireServer(direction)
end

-- Function to handle incoming hits (via hitbox or animation detection)
local function handleIncomingHit(attacker, attackerPosition)
    local currentTime = tick()
    
    -- Cooldown Check
    if lastBlockTime[attacker] and (currentTime - lastBlockTime[attacker]) < Settings.blockCooldown then
        return -- Still in cooldown; cannot block
    end

    -- Distance Check
    local distance = (humanoidRootPart.Position - attackerPosition).Magnitude
    if distance > Settings.blockDistance then
        return -- Attacker is too far; no need to block
    end

    -- Determine Block Direction
    local blockDirection = getHitDirection(attackerPosition)
    updateBlockDirection(blockDirection)
    
    -- Start Blocking
    startBlocking()
    lastBlockTime[attacker] = currentTime

    -- Schedule Unblock after a short duration (adjust as needed)
    RunService.Heartbeat:Wait() -- Ensure this runs in the next frame
    task.delay(0.5, function()
        stopBlocking()
    end)

    -- Handle Auto Countering
    if Settings.autoCounterEnabled and distance <= Settings.autoCounterDistance then
        if not lastCounterTime[attacker] or (currentTime - lastCounterTime[attacker]) >= Settings.counterCooldown then
            -- Simulate Counter Key Press
            VirtualInputManager:SendKeyEvent(true, Settings.counterKey, false, game)
            task.wait(0.1)
            VirtualInputManager:SendKeyEvent(false, Settings.counterKey, false, game)
            lastCounterTime[attacker] = currentTime
            print("[AutoBlock] Countered attack from " .. attacker.Name)
        end
    end
end

-- === Animation State Detection ===
local function onCharacterAdded(characterInstance)
    local humanoidInstance = characterInstance:WaitForChild("Humanoid")
    local opponentPlayer = Players:GetPlayerFromCharacter(characterInstance)
    if not opponentPlayer or opponentPlayer == player then
        return -- Ignore self or non-player characters
    end

    -- Connect to AnimationPlayed
    local animationConnection
    animationConnection = humanoidInstance.AnimationPlayed:Connect(function(animTrack)
        -- Validate Animation ID
        if not animTrack.Animation or not animTrack.Animation.AnimationId then return end

        -- Check if the animation is an attack
        for attackType, animId in pairs(Settings.attackTypes) do
            if animTrack.Animation.AnimationId == "rbxassetid://" .. animId then
                print("[AutoBlock] Detected attack '" .. attackType .. "' from " .. opponentPlayer.Name)
                local attackerRoot = characterInstance:FindFirstChild("HumanoidRootPart")
                if attackerRoot then
                    handleIncomingHit(opponentPlayer, attackerRoot.Position)
                end
                break
            end
        end
    end)

    -- Cleanup when character is removed
    characterInstance.AncestryChanged:Connect(function(_, parent)
        if not parent then
            if animationConnection then
                animationConnection:Disconnect()
            end
        end
    end)
end

-- === Hitbox Detection ===
-- Assumes that attack hitboxes are parts tagged with "AttackHitbox"
local ATTACK_HITBOX_TAG = "AttackHitbox"

local function onHitboxTouched(hit)
    local attackerPart = hit.Parent
    local attackerPlayer = Players:GetPlayerFromCharacter(attackerPart.Parent)
    if not attackerPlayer or attackerPlayer == player then
        return -- Ignore self or non-player characters
    end

    local attackerRoot = attackerPart.Parent:FindFirstChild("HumanoidRootPart")
    if attackerRoot then
        local attackerPosition = attackerRoot.Position
        print("[AutoBlock] Hitbox detected attack from " .. attackerPlayer.Name)
        handleIncomingHit(attackerPlayer, attackerPosition)
    end
end

local function monitorHitboxes(characterInstance)
    -- Find all parts tagged as "AttackHitbox" within the character
    for _, hitbox in ipairs(CollectionService:GetTagged("AttackHitbox")) do
        if hitbox:IsDescendantOf(characterInstance) then
            -- Connect Touch event
            hitbox.Touched:Connect(onHitboxTouched)
        end
    end
end

-- === Player Monitoring ===
local function monitorPlayer(plr)
    if plr == player then return end -- Ignore self

    -- Monitor existing character
    if plr.Character then
        onCharacterAdded(plr.Character)
        monitorHitboxes(plr.Character)
    end

    -- Connect to CharacterAdded for future character spawns
    plr.CharacterAdded:Connect(function(characterInstance)
        onCharacterAdded(characterInstance)
        monitorHitboxes(characterInstance)
    end)

    -- Cleanup when player leaves
    plr.AncestryChanged:Connect(function(_, parent)
        if not parent then
            -- Optionally handle any cleanup if needed
        end
    end)
end

-- === Initialize Monitoring for Existing and Future Players ===
for _, plr in ipairs(Players:GetPlayers()) do
    monitorPlayer(plr)
end

Players.PlayerAdded:Connect(monitorPlayer)

-- === Manual Blocking Toggle ===
UserInputService.InputBegan:Connect(function(input, gameProcessed)
    if gameProcessed then return end
    if input.KeyCode == Enum.KeyCode.Q then
        toggleBlocking()
    end
end)

-- === UI Feedback Update ===
RunService.RenderStepped:Connect(function()
    if isBlocking then
        messageBox.Text = "Blocking Active"
        loadingBar.BackgroundColor3 = Color3.fromRGB(0, 255, 0)
    else
        messageBox.Text = Settings.ui.MessageBoxText
        loadingBar.BackgroundColor3 = Color3.fromRGB(255, 0, 0)
    end
end)

-- === Cleanup on Character Death or Removal ===
local function onCharacterDied()
    stopBlocking()
end

humanoid.Died:Connect(onCharacterDied)

character.AncestryChanged:Connect(function(_, parent)
    if not parent then
        stopBlocking()
    end
end)
```