Add an advanced dynamic evaluation time-based auto block that'll condition itself to auto-blocking the nearest roblox humanoid character, when it detect a swing.

List of Animation ID'S:

```
local animIDs = {
    ["RightSwing"] = 12625839385,
    ["OverheadSwing"] = 12625841878,
    ["LeftSwing"] = 12625843823,
    ["BackLeftSwing"] = 12625846167,
    ["FrontRightSwing"] = 12625848489,
    ["BackRightSwing"] = 12625851115,
    ["FrontLeftSwing"] = 12625853257,
    ["RightBlock"] = 12625856098,
    ["LeftBlock"] = 12625858434,
    ["FrontLeftBlock"] = 12625860439,
    ["FrontRightBlock"] = 12625862519,
    ["FrontBlock"] = 12625864413,
    ["BackLeftBlock"] = 12625866538,
    ["BackRightBlock"] = 12625868684,
    ["Grab"] = 12625870437,
    ["Slap"] = 12625891544,
    ["SlappedLegs"] = 12671715182,
    ["SlappedArms"] = 12625896358,
    ["KickUp"] = 12625897944,
    ["KickBack"] = 12625899752,
    ["LeftRoll"] = 12625901874,
    ["RightRoll"] = 12625904322,
    ["Aerial"] = 12625908201,
    ["Idle"] = 13956175510,
    ["Throw"] = 12626569448,
    ["ForcePush"] = 12645928786,
    ["CrouchWalkRight"] = 12699256551,
    ["CrouchWalkLeft"] = 12699989478,
    ["CrouchWalkBack"] = 12699390244,
    ["CrouchWalkForward"] = 12699464592,
    ["FrontRoll"] = 12708915962,
    ["RightCrouchRoll"] = 12713661639,
    ["LeftCrouchRoll"] = 12713663289,
    ["Kata"] = 12735531097,
    ["Choking"] = 12814275189,
    ["Choke"] = 12815930160,
}
```

Here, you will refine this script and further enhance it based-off the requirements:

```
--[[
    Auto Block V.7 for Saber Showdown
    - Integrated ESP features for player visualization
    - Enhanced UI using Rayfield for a more interactive experience
    - Expanded attack handling with additional attack types
    - Improved logging with exportable detailed reports
    - Performance optimizations and refined prediction algorithms
    - Updated security measures and robust error handling
--]]

-- === Services ===
local Players = game:GetService("Players")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local UserInputService = game:GetService("UserInputService")
local RunService = game:GetService("RunService")
local VirtualInputManager = game:GetService("VirtualInputManager")
local CollectionService = game:GetService("CollectionService")
local Debris = game:GetService("Debris")
local TweenService = game:GetService("TweenService")
local SoundService = game:GetService("SoundService")
local Workspace = workspace
local HttpService = game:GetService("HttpService")

-- === External Libraries ===
local Rayfield = loadstring(game:HttpGet('https://raw.githubusercontent.com/shlexware/Rayfield/main/source'))()

-- === Constants ===
local LOCAL_PLAYER = Players.LocalPlayer
local CAMERA = Workspace.CurrentCamera
local ATTACK_HITBOX_TAG = "AttackHitbox"
local ESP_MAX_DISTANCE = 100

local BLOCK_DIRECTIONS = {
    Forward = 1,
    Right = 2,
    Backward = 3,
    Left = 4
}

local LOG_LEVELS = {
    INFO = 1,
    WARNING = 2,
    ERROR = 3
}

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

-- === Settings ===
local Settings = {
    -- Blocking Settings
    blockDistances = { -- Max distance to attempt a block per attack type
        Slap = 10,       -- Slaps require closer proximity
        Default = 15     -- Default distance for other attacks
    },
    autoBlockEnabled = true,         -- Enable/Disable dynamic auto-blocking
    blockCooldown = 0.5,             -- General cooldown between blocks (seconds)
    attackBlockCooldowns = {         -- Cooldown between blocks per attack type (seconds)
        Slap = 0.2,
        Default = 0.5
    },
    attackTypes = {                  -- Attack animation IDs
        Slap = "rbxassetid://12625891544",
        SlappedLegs = "rbxassetid://12671715182",
        SlappedArms = "rbxassetid://12625896358",
        Kick = "rbxassetid://12625897500",
        KickUp = "rbxassetid://12625897944",
        -- Additional Attack Types
        RightSwing = "rbxassetid://12625839385",
        OverheadSwing = "rbxassetid://12625841878",
        LeftSwing = "rbxassetid://12625843823",
        BackLeftSwing = "rbxassetid://12625846167",
        FrontRightSwing = "rbxassetid://12625848489",
        BackRightSwing = "rbxassetid://12625851115",
        FrontLeftSwing = "rbxassetid://12625853257",
        -- Add more as needed
    },
    
    -- 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)
    defaultCounterKey = Enum.KeyCode.E,-- Default key to use for countering
    
    -- Reaction Settings
    reactionTimeThreshold = 0.15,     -- Threshold for reaction time (in seconds)
    predictionFactor = 1.5,           -- Factor for predicting enemy movements based on velocity and acceleration
    
    -- Slap Lag Handling
    slapLagCompensation = 0.1,        -- Additional delay to compensate for lag in slap attacks
    
    -- Aim-Lock Directional Block Settings
    aimLockEnabled = true,            -- Enable/Disable aim-lock directional blocking
    aimLockSmoothness = 0.1,          -- Smoothness factor for direction adjustment
    
    -- UI Settings (Using Rayfield)
    ui = {
        WindowName = "Auto Block V.7",
        Tabs = {
            Settings = "Settings",
            ESP = "ESP",
            Statistics = "Statistics",
            Logs = "Logs",
            Credits = "Credits"
        },
        Sections = {
            Settings = {
                "Blocking Settings",
                "Counter Attacking Settings",
                "Reaction Settings",
                "UI Settings"
            },
            ESP = {
                "ESP Config"
            },
            Statistics = {
                "Performance Metrics"
            },
            Logs = {
                "Log Controls"
            },
            Credits = {
                "Credits"
            }
        },
        Theme = "Dark" -- Options: "Dark", "Light"
    },
    
    -- Debris Settings
    debrisLifetime = 300,             -- Time in seconds before debris is removed (e.g., hitboxes)
    
    -- Logging Settings
    logLevel = LOG_LEVELS.INFO,       -- Current logging level
    
    -- Statistics Tracking
    statistics = {
        blocks = 0,
        counters = 0,
        blocksPerAttack = {},           -- [attackType] = count
        countersPerAttack = {}          -- [attackType] = count
    },
    
    -- Sound Settings (Preloaded for performance)
    sounds = {
        blockStart = "rbxassetid://YourBlockStartSoundID",
        blockStop = "rbxassetid://YourBlockStopSoundID",
        counter = "rbxassetid://YourCounterSoundID",
        notification = "rbxassetid://YourNotificationSoundID"
    }
}

-- === Inverse Mapping for Attack Types ===
Settings.attackTypesInverse = {}
for attack, id in pairs(Settings.attackTypes) do
    local matches = id:match("rbxassetid://(%d+)")
    if matches then
        Settings.attackTypesInverse[matches] = attack
    end
end

-- === State Tracking ===
local State = {
    isBlocking = false,
    lastBlockTime = {},            -- [player.UserId] = timestamp
    lastCounterTime = {},          -- [player.UserId] = timestamp
    currentBlockDirections = {},   -- [player.UserId] = set of BLOCK_DIRECTIONS
    isConfigOpen = false,
    isSoundEnabled = true,
    counterKey = Settings.defaultCounterKey,
    currentTheme = Settings.ui.Theme,
    ESPObjects = {},                -- [player.UserId] = {Highlight, NameLabel}
}

-- === UI Setup using Rayfield ===
local Window = Rayfield:CreateWindow({
    Name = Settings.ui.WindowName,
    LoadingTitle = Settings.ui.WindowName,
    LoadingSubtitle = "Advanced Auto Block Script",
    ConfigurationSaving = {
        Enabled = true,
        FolderName = "SaberShowdownConfig",
        FileName = "AutoBlockConfig"
    },
    KeySystem = false,
})

-- === Tabs Creation ===
local Tabs = {}
for tabName, icon in pairs(Settings.ui.Tabs) do
    Tabs[tabName] = Window:CreateTab(icon, 4483362458) -- Replace with appropriate icon asset ID
end

-- === ESP Tab Elements ===
local ESPTab = Tabs.ESP
local ESPSection = ESPTab:CreateSection("ESP Config")

-- ESP Settings
local espEnabled = true
local rainbowESPEnabled = false
local espOutlineColor = Color3.new(1, 1, 1)
local espNameColor = Color3.new(1, 0, 0)
local espDistance = 100
local highlightThickness = 0.5
local slapTimerEnabled = true
local slapTimerColor = Color3.new(0, 1, 0)

-- Toggle ESP
ESPTab:CreateToggle({
    Name = "Enable ESP",
    CurrentValue = espEnabled,
    Callback = function(Value)
        espEnabled = Value
        if not espEnabled then
            -- Disable existing ESP
            for _, esp in pairs(State.ESPObjects) do
                esp.Highlight.Enabled = false
                esp.NameLabel.Visible = false
            end
        else
            -- Enable existing ESP
            for _, esp in pairs(State.ESPObjects) do
                esp.Highlight.Enabled = true
                esp.NameLabel.Visible = true
            end
        end
        log("ESP " .. (espEnabled and "Enabled" or "Disabled"), LOG_LEVELS.INFO)
    end,
})

-- Toggle Rainbow ESP
ESPTab:CreateToggle({
    Name = "Rainbow ESP",
    CurrentValue = rainbowESPEnabled,
    Callback = function(Value)
        rainbowESPEnabled = Value
        log("Rainbow ESP " .. (rainbowESPEnabled and "Enabled" or "Disabled"), LOG_LEVELS.INFO)
    end,
})

-- ESP Outline Color Picker
ESPTab:CreateColorPicker({
    Name = "ESP Outline Color",
    Color = espOutlineColor,
    Callback = function(Value)
        espOutlineColor = Value
        updateESPColors()
    end,
})

-- ESP Name Color Picker
ESPTab:CreateColorPicker({
    Name = "ESP Name Color",
    Color = espNameColor,
    Callback = function(Value)
        espNameColor = Value
        updateESPColors()
    end,
})

-- ESP Distance Slider
ESPTab:CreateSlider({
    Name = "ESP Distance",
    Range = {0, 500},
    Increment = 10,
    Suffix = "studs",
    CurrentValue = espDistance,
    Callback = function(Value)
        espDistance = Value
        log("ESP Distance set to " .. espDistance, LOG_LEVELS.INFO)
    end,
})

-- Highlight Thickness Slider
ESPTab:CreateSlider({
    Name = "Highlight Thickness",
    Range = {0, 1},
    Increment = 0.1,
    Suffix = "",
    CurrentValue = highlightThickness,
    Callback = function(Value)
        highlightThickness = Value
        updateESPColors()
        log("Highlight Thickness set to " .. highlightThickness, LOG_LEVELS.INFO)
    end,
})

-- Slap Timer Color Picker
ESPTab:CreateColorPicker({
    Name = "Slap Timer Color",
    Color = slapTimerColor,
    Callback = function(Value)
        slapTimerColor = Value
        log("Slap Timer Color updated", LOG_LEVELS.INFO)
    end,
})

-- === Settings Tab Elements ===
local SettingsTab = Tabs.Settings
local SettingsSection1 = SettingsTab:CreateSection("Blocking Settings")
local SettingsSection2 = SettingsTab:CreateSection("Counter Attacking Settings")
local SettingsSection3 = SettingsTab:CreateSection("Reaction Settings")
local SettingsSection4 = SettingsTab:CreateSection("UI Settings")

-- Blocking Settings
SettingsTab:CreateToggle({
    Name = "Enable Auto Block",
    CurrentValue = Settings.autoBlockEnabled,
    Callback = function(Value)
        Settings.autoBlockEnabled = Value
        log("Auto Block " .. (Settings.autoBlockEnabled and "Enabled" or "Disabled"), LOG_LEVELS.INFO)
    end,
})

SettingsTab:CreateSlider({
    Name = "Default Block Distance",
    Range = {5, 30},
    Increment = 1,
    Suffix = "studs",
    CurrentValue = Settings.blockDistances.Default,
    Callback = function(Value)
        Settings.blockDistances.Default = Value
        log("Default Block Distance set to " .. Value, LOG_LEVELS.INFO)
    end,
})

-- Counter Attacking Settings
SettingsTab:CreateToggle({
    Name = "Enable Auto Counter",
    CurrentValue = Settings.autoCounterEnabled,
    Callback = function(Value)
        Settings.autoCounterEnabled = Value
        log("Auto Counter " .. (Settings.autoCounterEnabled and "Enabled" or "Disabled"), LOG_LEVELS.INFO)
    end,
})

SettingsTab:CreateSlider({
    Name = "Auto Counter Distance",
    Range = {5, 20},
    Increment = 1,
    Suffix = "studs",
    CurrentValue = Settings.autoCounterDistance,
    Callback = function(Value)
        Settings.autoCounterDistance = Value
        log("Auto Counter Distance set to " .. Value, LOG_LEVELS.INFO)
    end,
})

SettingsTab:CreateKeyPicker({
    Name = "Counter Key",
    CurrentKey = Settings.defaultCounterKey,
    ComboKey = Enum.KeyCode.E,
    Callback = function(Key)
        Settings.defaultCounterKey = Key
        State.counterKey = Key
        log("Counter Key set to " .. Key.Name, LOG_LEVELS.INFO)
    end,
})

-- Reaction Settings
SettingsTab:CreateSlider({
    Name = "Reaction Time Threshold",
    Range = {0.05, 0.5},
    Increment = 0.05,
    Suffix = "secs",
    CurrentValue = Settings.reactionTimeThreshold,
    Callback = function(Value)
        Settings.reactionTimeThreshold = Value
        log("Reaction Time Threshold set to " .. Value .. " seconds", LOG_LEVELS.INFO)
    end,
})

SettingsTab:CreateSlider({
    Name = "Prediction Factor",
    Range = {1, 3},
    Increment = 0.1,
    Suffix = "",
    CurrentValue = Settings.predictionFactor,
    Callback = function(Value)
        Settings.predictionFactor = Value
        log("Prediction Factor set to " .. Value, LOG_LEVELS.INFO)
    end,
})

-- Slap Lag Compensation
SettingsTab:CreateSlider({
    Name = "Slap Lag Compensation",
    Range = {0, 0.5},
    Increment = 0.05,
    Suffix = "secs",
    CurrentValue = Settings.slapLagCompensation,
    Callback = function(Value)
        Settings.slapLagCompensation = Value
        log("Slap Lag Compensation set to " .. Value .. " seconds", LOG_LEVELS.INFO)
    end,
})

-- UI Settings
SettingsTab:CreateButton({
    Name = "Toggle Theme",
    Callback = function()
        if Settings.currentTheme == "Dark" then
            Settings.currentTheme = "Light"
            Window:SetTheme("Light")
            log("Theme changed to Light", LOG_LEVELS.INFO)
        else
            Settings.currentTheme = "Dark"
            Window:SetTheme("Dark")
            log("Theme changed to Dark", LOG_LEVELS.INFO)
        end
    end,
})

SettingsTab:CreateToggle({
    Name = "Enable Sound",
    CurrentValue = State.isSoundEnabled,
    Callback = function(Value)
        State.isSoundEnabled = Value
        log("Sound " .. (State.isSoundEnabled and "Enabled" or "Disabled"), LOG_LEVELS.INFO)
    end,
})

-- === Statistics Tab Elements ===
local StatisticsTab = Tabs.Statistics
StatisticsTab:CreateLabel("Blocks: 0")
StatisticsTab:CreateLabel("Counters: 0")
-- Future Enhancements: Add per attack type statistics

-- === Logs Tab Elements ===
local LogsTab = Tabs.Logs
local logViewer = LogsTab:CreateTextBox({
    Name = "Log Viewer",
    PlaceholderText = "Logs will appear here...",
    Text = "",
    MultiLine = true,
    ReadOnly = true,
})

LogsTab:CreateButton({
    Name = "Export Logs",
    Callback = function()
        local logs = logViewer.Text
        if #logs == 0 then
            log("No logs to export.", LOG_LEVELS.WARNING)
            return
        end
        local success, encodedLogs = pcall(function()
            return HttpService:JSONEncode({logs = logs})
        end)
        if success then
            -- Implement actual export logic here
            log("Logs have been exported.", LOG_LEVELS.INFO)
            Rayfield:Notify({
                Title = "Export Logs",
                Content = "Logs exported successfully!",
                Duration = 3,
                Image = nil,
                Actions = {}
            })
        else
            log("Failed to encode logs for export.", LOG_LEVELS.ERROR)
        end
    end,
})

-- === Credits Tab Elements ===
local CreditsTab = Tabs.Credits
CreditsTab:CreateLabel("Created by xenon90 on Discord")
CreditsTab:CreateLabel("For commissions, contact xenon90")
CreditsTab:CreateLabel("Most scripts are free for experience")

-- === Helper Functions ===

-- Utility: Log with timestamp and level
local function log(message, level)
    level = level or LOG_LEVELS.INFO
    if level < Settings.logLevel then return end
    local prefix
    if level == LOG_LEVELS.INFO then
        prefix = "[INFO]"
    elseif level == LOG_LEVELS.WARNING then
        prefix = "[WARNING]"
    elseif level == LOG_LEVELS.ERROR then
        prefix = "[ERROR]"
    else
        prefix = "[LOG]"
    end
    local timestamp = os.date("%H:%M:%S")
    local logMessage = string.format("[%s] [%s] %s", timestamp, prefix, message)
    print(logMessage)
    
    -- Append to Rayfield log viewer
    if logViewer then
        logViewer.Text = logViewer.Text .. "\n" .. logMessage
    end
    
    -- Trigger notification for high-level logs
    if level >= LOG_LEVELS.WARNING then
        Rayfield:Notify({
            Title = "Auto Block Notification",
            Content = message,
            Duration = 3,
            Image = nil,
            Actions = {}
        })
        
        -- Play notification sound
        if State.isSoundEnabled and Settings.sounds.notification then
            local sound = Instance.new("Sound")
            sound.SoundId = Settings.sounds.notification
            sound.Volume = 0.5
            sound.Parent = SoundService
            sound:Play()
            Debris:AddItem(sound, sound.TimeLength)
        end
    end
end

-- UI: Update ESP Colors
local function updateESPColors()
    for _, esp in pairs(State.ESPObjects) do
        if esp.Highlight then
            esp.Highlight.OutlineColor = espOutlineColor
            esp.Highlight.OutlineTransparency = 1 - highlightThickness
        end
        if esp.NameLabel then
            esp.NameLabel.Color = espNameColor
        end
    end
end

-- ESP: Create ESP for Player
local function createPlayerESP(player)
    -- Highlight
    local highlight = Instance.new("Highlight")
    highlight.Name = "ESPHighlight"
    highlight.FillColor = Color3.new(1, 0, 0)
    highlight.OutlineColor = espOutlineColor
    highlight.FillTransparency = 1
    highlight.OutlineTransparency = 1 - highlightThickness
    highlight.Adornee = player.Character
    highlight.Parent = player.Character
    
    -- Name Label
    local nameLabel = Rayfield:CreateLabel("ESP for " .. player.Name)
    nameLabel.Text = player.Name
    nameLabel.Visible = espEnabled
    nameLabel.Color = espNameColor
    
    -- Store ESP Objects
    State.ESPObjects[player.UserId] = {
        Highlight = highlight,
        NameLabel = nameLabel
    }
    
    -- Update ESP based on settings
    if not espEnabled then
        highlight.Enabled = false
        nameLabel.Visible = false
    end
end

-- ESP: Remove ESP for Player
local function removePlayerESP(player)
    if State.ESPObjects[player.UserId] then
        if State.ESPObjects[player.UserId].Highlight then
            State.ESPObjects[player.UserId].Highlight:Destroy()
        end
        if State.ESPObjects[player.UserId].NameLabel then
            State.ESPObjects[player.UserId].NameLabel:Destroy()
        end
        State.ESPObjects[player.UserId] = nil
    end
end

-- UI: Setup ESP for Existing Players
for _, player in ipairs(Players:GetPlayers()) do
    if player ~= LOCAL_PLAYER and player.Character then
        createPlayerESP(player)
    end
end

-- ESP: Connect Player Added/Removed Events
Players.PlayerAdded:Connect(function(player)
    if player ~= LOCAL_PLAYER then
        player.CharacterAdded:Connect(function(character)
            createPlayerESP(player)
        end)
    end
end)

Players.PlayerRemoving:Connect(function(player)
    if player ~= LOCAL_PLAYER then
        removePlayerESP(player)
    end
end)

-- Blocking: Start Blocking for a Specific Player
local function startBlocking(playerId)
    if not State.isBlocking then
        State.isBlocking = true
        BlockRemote:FireServer()
        log("Blocking started", LOG_LEVELS.INFO)
        
        -- Play block start sound
        if State.isSoundEnabled and Settings.sounds.blockStart then
            local sound = Instance.new("Sound")
            sound.SoundId = Settings.sounds.blockStart
            sound.Volume = 0.5
            sound.Parent = SoundService
            sound:Play()
            Debris:AddItem(sound, sound.TimeLength)
        end
    end
end

-- Blocking: Stop Blocking for a Specific Player
local function stopBlocking(playerId)
    -- Remove the direction from the current block directions
    if State.currentBlockDirections[playerId] then
        State.currentBlockDirections[playerId] = nil
    end

    -- If no more blocking directions, stop blocking
    local isStillBlocking = false
    for _, directions in pairs(State.currentBlockDirections) do
        if next(directions) then
            isStillBlocking = true
            break
        end
    end

    if not isStillBlocking and State.isBlocking then
        State.isBlocking = false
        UnblockRemote:FireServer()
        log("Blocking stopped", LOG_LEVELS.INFO)
        
        -- Play block stop sound
        if State.isSoundEnabled and Settings.sounds.blockStop then
            local sound = Instance.new("Sound")
            sound.SoundId = Settings.sounds.blockStop
            sound.Volume = 0.5
            sound.Parent = SoundService
            sound:Play()
            Debris:AddItem(sound, sound.TimeLength)
        end
    end
end

-- Blocking: Toggle Blocking State with Debounce
local debounceToggle = false
local function toggleBlocking()
    if debounceToggle then return end
    debounceToggle = true
    if State.isBlocking then
        -- Stop blocking for all players
        for playerId, _ in pairs(State.currentBlockDirections) do
            stopBlocking(playerId)
        end
    else
        -- Start blocking (default to forward direction if needed)
        State.isBlocking = true
        BlockRemote:FireServer()
        log("Blocking started", LOG_LEVELS.INFO)
    end
    task.delay(0.2, function()
        debounceToggle = false
    end)
end

-- Prediction: Predict Enemy Movement with Enhanced Algorithm
local function predictEnemyMovement(enemy)
    local enemyCharacter = enemy.Character
    if not enemyCharacter then return nil end
    
    local enemyHRP = enemyCharacter:FindFirstChild("HumanoidRootPart")
    if not enemyHRP then return nil end

    -- Fetch velocity and acceleration if available
    local velocity = enemyHRP.Velocity
    local humanoidRootPartScript = enemyHRP:FindFirstChild("MovementScript") -- Assuming there's a script tracking acceleration
    local acceleration = humanoidRootPartScript and humanoidRootPartScript.Acceleration.Value or Vector3.new(0,0,0)

    -- Enhanced prediction with acceleration
    local predictedPosition = enemyHRP.Position + (velocity * Settings.predictionFactor) + (acceleration * Settings.predictionFactor * 0.5)
    return predictedPosition
end

-- Direction: Get Hit Direction Based on Attacker Position
local function getHitDirection(attackerPosition, playerPosition, camLookVector, camRightVector)
    local direction = (attackerPosition - playerPosition).Unit
    local dotProduct = direction:Dot(camLookVector)

    if Settings.aimLockEnabled then
        if dotProduct > math.cos(math.rad(45)) then
            return BLOCK_DIRECTIONS.Forward
        elseif dotProduct < -math.cos(math.rad(45)) then
            return BLOCK_DIRECTIONS.Backward
        else
            return direction:Dot(camRightVector) > 0 and BLOCK_DIRECTIONS.Right or BLOCK_DIRECTIONS.Left
        end
    else
        local angle = math.deg(math.atan2(direction.X, direction.Z)) % 360

        if angle < 45 or angle >= 315 then
            return BLOCK_DIRECTIONS.Forward
        elseif angle < 135 then
            return BLOCK_DIRECTIONS.Right
        elseif angle < 225 then
            return BLOCK_DIRECTIONS.Backward
        else
            return BLOCK_DIRECTIONS.Left
        end
    end
end

-- Direction: Update Block Direction with Smooth Transitions
local function updateBlockDirection(attackerId, attackerPosition)
    local playerCharacter = LOCAL_PLAYER.Character
    if not playerCharacter then return end

    local playerHRP = playerCharacter:FindFirstChild("HumanoidRootPart")
    if not playerHRP then return end

    local playerPosition = playerHRP.Position
    local camLookVector = CAMERA.CFrame.LookVector
    local camRightVector = CAMERA.CFrame.RightVector

    local desiredDirection = getHitDirection(attackerPosition, playerPosition, camLookVector, camRightVector)

    if not State.currentBlockDirections[attackerId] then
        State.currentBlockDirections[attackerId] = {}
    end

    if not State.currentBlockDirections[attackerId][desiredDirection] then
        State.currentBlockDirections[attackerId][desiredDirection] = true
        UpdateBlockDirectionRemote:FireServer(desiredDirection)
        log(string.format("Block direction updated to %s for attacker %d", desiredDirection, attackerId), LOG_LEVELS.INFO)
    end

    return desiredDirection
end

-- Counter Attacking: Perform Auto Counter
local function performAutoCounter(attacker, attackType)
    local attackerId = attacker.UserId
    local currentTime = tick()

    if State.lastCounterTime[attackerId] and (currentTime - State.lastCounterTime[attackerId]) < Settings.counterCooldown then
        return
    end

    VirtualInputManager:SendKeyEvent(true, Settings.counterKey, false, game)
    task.delay(0.05, function()
        VirtualInputManager:SendKeyEvent(false, Settings.counterKey, false, game)
    end)

    State.lastCounterTime[attackerId] = currentTime
    log("Auto counter performed against " .. attacker.Name, LOG_LEVELS.INFO)
    
    -- Play counter sound
    if State.isSoundEnabled and Settings.sounds.counter then
        local sound = Instance.new("Sound")
        sound.SoundId = Settings.sounds.counter
        sound.Volume = 0.5
        sound.Parent = SoundService
        sound:Play()
        Debris:AddItem(sound, sound.TimeLength)
    end

    -- Update Statistics
    Settings.statistics.counters = Settings.statistics.counters + 1
    StatisticsTab.Elements.CountersLabel:SetText("Counters: " .. Settings.statistics.counters)
    -- Update counters per attack type
    Settings.statistics.countersPerAttack[attackType] = (Settings.statistics.countersPerAttack[attackType] or 0) + 1
end

-- Blocking: Handle Incoming Hit with Enhanced Proximity and Slap-Specific Handling
local function handleIncomingHit(attacker, attackerId, attackerPosition, attackType)
    local currentTime = tick()

    -- Determine appropriate cooldown and distance based on attack type
    local cooldown = Settings.attackBlockCooldowns[attackType] or Settings.blockCooldown
    local maxDistance = Settings.blockDistances[attackType] or Settings.blockDistances.Default

    -- Validate attackerId is a number
    if type(attackerId) ~= "number" then
        log("Invalid attacker ID detected.", LOG_LEVELS.ERROR)
        return
    end

    -- Check for cooldown
    if State.lastBlockTime[attackerId] and (currentTime - State.lastBlockTime[attackerId]) < cooldown then
        log("Block on cooldown for " .. attacker.Name, LOG_LEVELS.WARNING)
        return
    end

    -- Check distance
    local playerCharacter = LOCAL_PLAYER.Character
    if not playerCharacter then return end

    local playerHRP = playerCharacter:FindFirstChild("HumanoidRootPart")
    if not playerHRP then return end

    local distance = (playerHRP.Position - attackerPosition).Magnitude
    if distance > maxDistance then
        log("Attacker " .. attacker.Name .. " is too far: " .. tostring(distance), LOG_LEVELS.INFO)
        return
    end

    -- Update last block time for throttling
    State.lastBlockTime[attackerId] = currentTime

    -- Determine if the attack is a slap for specific handling
    local isSlap = (attackType == "Slap")
    
    -- Adjust reaction delay based on attack type
    local reactionDelay = isSlap and Settings.slapLagCompensation or math.min(math.random() * Settings.reactionTimeThreshold, Settings.reactionTimeThreshold)

    task.delay(reactionDelay, function()
        local predictedPosition = predictEnemyMovement(attacker)
        updateBlockDirection(attackerId, predictedPosition or attackerPosition)
        startBlocking(attackerId)

        -- Schedule unblocking with different delays based on attack type
        local unblockDelay = isSlap and Settings.slapLagCompensation or 0.5
        task.delay(unblockDelay, function()
            stopBlocking(attackerId)
        end)
    end)

    -- Handle Auto Countering if enabled and within counter distance
    if Settings.autoCounterEnabled and distance <= Settings.autoCounterDistance then
        performAutoCounter(attacker, attackType)
    end

    -- Update Statistics
    Settings.statistics.blocks = Settings.statistics.blocks + 1
    StatisticsTab.Elements.BlocksLabel:SetText("Blocks: " .. Settings.statistics.blocks)
    Settings.statistics.blocksPerAttack[attackType] = (Settings.statistics.blocksPerAttack[attackType] or 0) + 1

    -- Additional Slap-Specific Handling
    if isSlap then
        log("Slap attack handled from " .. attacker.Name, LOG_LEVELS.INFO)
        -- Future Enhancement: Add visual effects or specific reactions for slaps
    end
end

-- Attack Detection: Handle Animation Played
local function onAnimationPlayed(animTrack, opponentPlayer)
    local success, anim = pcall(function()
        return animTrack.Animation
    end)
    if not success or not anim then return end

    local successId, animId = pcall(function()
        return anim.AnimationId
    end)
    if not successId or not animId then return end

    -- Extract numeric ID from AnimationId
    local numericAnimId = animId:match("rbxassetid://(%d+)")
    if not numericAnimId then return end

    local attackType = Settings.attackTypesInverse[numericAnimId]
    if not attackType then return end

    log(string.format("Detected attack '%s' from %s", attackType, opponentPlayer.Name), LOG_LEVELS.INFO)

    local attackerHRP = opponentPlayer.Character and opponentPlayer.Character:FindFirstChild("HumanoidRootPart")
    if attackerHRP then
        handleIncomingHit(opponentPlayer, opponentPlayer.UserId, attackerHRP.Position, attackType)
    end
end

-- Animation Monitoring: Connect Animation Events
local function monitorAnimations(character, opponentPlayer)
    local humanoid = character:FindFirstChildOfClass("Humanoid")
    if not humanoid then return end

    local connection
    connection = humanoid.AnimationPlayed:Connect(function(animTrack)
        onAnimationPlayed(animTrack, opponentPlayer)
    end)

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

-- Hitbox Detection: Handle Hitbox Touched
local function onHitboxTouched(part, attackerPlayer)
    if not part or attackerPlayer == LOCAL_PLAYER then return end

    local attackerCharacter = part.Parent
    if not attackerCharacter then return end

    local attackerHRP = attackerCharacter:FindFirstChild("HumanoidRootPart")
    if attackerHRP then
        log("Hitbox detected attack from " .. attackerPlayer.Name, LOG_LEVELS.INFO)
        handleIncomingHit(attackerPlayer, attackerPlayer.UserId, attackerHRP.Position, "Default") -- Assuming 'Default' for non-slap attacks
    end
end

-- Hitbox Monitoring: Connect Hitbox Events
local function monitorHitboxes(character, attackerPlayer)
    local hitboxes = CollectionService:GetTagged(ATTACK_HITBOX_TAG)
    for _, hitbox in ipairs(hitboxes) do
        if hitbox:IsDescendantOf(character) then
            local connection = hitbox.Touched:Connect(function(hitPart)
                onHitboxTouched(hitPart, attackerPlayer)
            end)

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

            -- Remove hitbox after specified time to prevent memory leaks
            Debris:AddItem(hitbox, Settings.debrisLifetime)
        end
    end
end

-- Statistics Update: Refresh Statistics Panel
local function updateStatisticsPanel()
    if not StatisticsTab.Elements then return end
    -- Update blocks and counters
    StatisticsTab.Elements.BlocksLabel:SetText("Blocks: " .. Settings.statistics.blocks)
    StatisticsTab.Elements.CountersLabel:SetText("Counters: " .. Settings.statistics.counters)
    -- Future enhancements: Display per attack type stats
end

-- Advanced Reaction System: Continuous Monitoring with Throttling
local function advancedReactionAutoBlock()
    if not Settings.autoBlockEnabled then return end

    local lastHeartbeat = 0
    local heartbeatThrottle = 0.05  -- Throttle to run logic every 0.05 seconds (20 times per second)

    RunService.Heartbeat:Connect(function(deltaTime)
        lastHeartbeat = lastHeartbeat + deltaTime

        if lastHeartbeat < heartbeatThrottle then
            return
        end

        lastHeartbeat = 0

        local playerCharacter = LOCAL_PLAYER.Character
        if not playerCharacter then return end

        local playerHRP = playerCharacter:FindFirstChild("HumanoidRootPart")
        if not playerHRP then return end

        local playerPosition = playerHRP.Position
        local camLookVector = CAMERA.CFrame.LookVector
        local camRightVector = CAMERA.CFrame.RightVector

        for _, plr in ipairs(Players:GetPlayers()) do
            if plr == LOCAL_PLAYER or not plr.Character then continue end

            local enemyHRP = plr.Character:FindFirstChild("HumanoidRootPart")
            if not enemyHRP then continue end

            local distance = (playerPosition - enemyHRP.Position).Magnitude
            if distance > (Settings.blockDistances.Default) then continue end

            -- Prediction and Direction Update
            local predictedPosition = predictEnemyMovement(plr) or enemyHRP.Position
            updateBlockDirection(plr.UserId, predictedPosition)

            -- Early continue if no Humanoid found
            local enemyHumanoid = plr.Character:FindFirstChildOfClass("Humanoid")
            if not enemyHumanoid then continue end

            -- Check for active attack animations
            for _, animTrack in ipairs(enemyHumanoid:GetPlayingAnimationTracks()) do
                local success, anim = pcall(function()
                    return animTrack.Animation
                end)
                if not success or not anim then continue end

                local successId, animId = pcall(function()
                    return anim.AnimationId
                end)
                if not successId or not animId then continue end

                local numericAnimId = animId:match("rbxassetid://(%d+)")
                if not numericAnimId then continue end

                local attackType = Settings.attackTypesInverse[numericAnimId]
                if not attackType then continue end

                -- Determine if the attack should be considered based on distance
                local requiredDistance = Settings.blockDistances[attackType] or Settings.blockDistances.Default
                if distance > requiredDistance then continue end

                handleIncomingHit(plr, plr.UserId, enemyHRP.Position, attackType)
            end
        end
    end)
end

-- Player Monitoring: Handle New Players
local function onPlayerAdded(plr)
    if plr == LOCAL_PLAYER then return end

    local function onCharacterAdded(character)
        monitorAnimations(character, plr)
        monitorHitboxes(character, plr)
    end

    plr.CharacterAdded:Connect(onCharacterAdded)

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

    -- Setup ESP
    createPlayerESP(plr)
end

-- Initialize Player Monitoring
local function initializePlayerMonitoring()
    for _, plr in ipairs(Players:GetPlayers()) do
        onPlayerAdded(plr)
    end
    Players.PlayerAdded:Connect(onPlayerAdded)
end

-- UI Feedback & Directional Block Update
local function updateUIAndDirection()
    -- Update UI based on blocking state
    local isBlocking = State.isBlocking
    -- Update in Rayfield if applicable
    -- For example, update a status label or indicator
end

-- Input Handling: Manual Blocking Toggle and Configurations
local function setupInputHandling()
    -- Manual Blocking Toggle with 'Q' Key
    UserInputService.InputBegan:Connect(function(input, gameProcessed)
        if gameProcessed then return end
        if input.KeyCode == Enum.KeyCode.Q then
            toggleBlocking()
        end
        -- Additional custom key bindings can be handled here
    end)

    -- Configuration Button Event handled by Rayfield UI
end

-- Logging: Update Log Level Indicator (Handled by Rayfield)

-- Export Logs Functionality is already implemented in Logs Tab

-- Character Cleanup: Handle Character Death or Removal
local function onCharacterRemoved()
    -- Stop blocking when character is removed or dies
    stopBlocking()
end

local function connectCharacterEvents(character)
    local humanoid = character:FindFirstChildOfClass("Humanoid")
    if humanoid then
        humanoid.Died:Connect(onCharacterRemoved)
    end

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

local function setupLocalPlayerCharacterMonitoring()
    local function onLocalCharacterAdded(character)
        connectCharacterEvents(character)
    end

    if LOCAL_PLAYER.Character then
        connectCharacterEvents(LOCAL_PLAYER.Character)
    end

    LOCAL_PLAYER.CharacterAdded:Connect(onLocalCharacterAdded)
end

-- === Initialization ===

-- Setup Input Handling
setupInputHandling()

-- Initialize Player Monitoring
initializePlayerMonitoring()

-- Setup Local Player Character Monitoring
setupLocalPlayerCharacterMonitoring()

-- Initialize Advanced Reaction System
advancedReactionAutoBlock()

-- Final Notification
log("Auto Block V.7 is now running with enhanced features and optimizations.", LOG_LEVELS.INFO)

-- === End of Script ===