Further ENHANCE THE AUTO-BLOCK:

```
--[[
    Auto Block V.6 for Saber Showdown
    - Enhanced user customization with advanced settings and theme options
    - Advanced prediction algorithms considering acceleration and historical movement
    - Improved visual and audio feedback including cooldown progress bars and volume control
    - Optimized performance through asset preloading and efficient event management
    - Robust error handling and security measures for input validation and protected RemoteEvents
    - Comprehensive logging and analytics with exportable reports
    - Seamless integration with diverse game mechanics and support for multiple attack types
--]]

-- === 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")

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

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",
        Punch = "rbxassetid://12625897000",
        Kick = "rbxassetid://12625897500",
        KickUp = "rbxassetid://12625897944",
        KickBack = "rbxassetid://12625899752"
    },
    
    -- 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
    ui = {
        ScreenGuiName = "AutoBlockUI",
        BackgroundColor = Color3.fromRGB(30, 30, 30),
        PrimaryColor = Color3.fromRGB(45, 45, 45),
        AlternatePrimaryColor = Color3.fromRGB(55, 55, 55),
        AccentColor = Color3.fromRGB(0, 170, 255),
        TextColor = Color3.fromRGB(255, 255, 255),
        CornerRadius = UDim.new(0, 8),
        Font = Enum.Font.GothamSemibold,
        FontSize = 14,
        -- Frames
        MainPanel = {
            Size = UDim2.new(0.35, 0, 0.7, 0),
            Position = UDim2.new(0.325, 0, 0.15, 0),
            Color = Color3.fromRGB(50, 50, 50),
            Transparency = 0.9,
            Title = "Auto Block Settings",
            TitleSize = UDim2.new(1, 0, 0, 40)
        },
        StatisticsPanel = {
            Size = UDim2.new(0.2, 0, 0.2, 0),
            Position = UDim2.new(0.75, 0, 0.75, 0),
            Color = Color3.fromRGB(30, 30, 30),
            Transparency = 0.8,
            Title = "Stats",
            TitleSize = UDim2.new(1, 0, 0, 30)
        },
        -- Buttons
        ConfigButton = {
            Size = UDim2.new(0, 120, 0, 40),
            Position = UDim2.new(0.01, 0, 0.01, 0),
            Color = Color3.fromRGB(0, 170, 255),
            Text = "Settings"
        },
        SoundToggle = {
            Size = UDim2.new(0.8, 0, 0, 30),
            Position = UDim2.new(0.1, 0, 0.65, 0),
            Color = Color3.fromRGB(70, 70, 70),
            Text = "Sound Effects: On"
        },
        LogLevelIndicator = {
            Size = UDim2.new(0, 150, 0, 30),
            Position = UDim2.new(0.5, -75, 0, 10),
            Color = Color3.fromRGB(255, 255, 255),
            Text = "Log Level: Info"
        },
        ExportLogButton = {
            Size = UDim2.new(0.5, 0, 0, 30),
            Position = UDim2.new(0.25, 0, 0.85, 0),
            Color = Color3.fromRGB(70, 70, 70),
            Text = "Export Logs"
        },
        -- Notifications
        Notification = {
            Size = UDim2.new(0.3, 0, 0.05, 0),
            Position = UDim2.new(0.35, 0, 0.05, 0),
            Color = Color3.fromRGB(0, 0, 0),
            Text = "",
            Duration = 3, -- Duration in seconds
            FontSize = 14
        },
        -- Themes
        ThemeToggle = {
            Size = UDim2.new(0, 120, 0, 40),
            Position = UDim2.new(0.1, 0, 0.45, 0),
            Color = Color3.fromRGB(255, 165, 0),
            Text = "Toggle Theme"
        }
    },
    
    -- 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 = "Dark"           -- Default theme
}

-- === UI Elements ===
local UI = {
    ScreenGui = nil,
    MainPanel = nil,
    ConfigButton = nil,
    LogLevelIndicator = nil,
    StatisticsPanel = nil,
    SoundToggle = nil,
    LogDisplay = nil,
    ExportLogButton = nil,
    BlocksLabel = nil,
    CountersLabel = nil,
    DirectionIndicators = {},       -- [player.UserId] = ImageLabel
    Notification = nil,             -- Notification TextLabel
    ThemeToggle = nil               -- Theme Toggle Button
}

-- === 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 in-game log display
    if UI.LogDisplay then
        UI.LogDisplay.Text = UI.LogDisplay.Text .. "\n" .. logMessage
    end

    -- Trigger notification for high-level logs
    if level >= LOG_LEVELS.WARNING and UI.Notification then
        UI.Notification.Text = message
        UI.Notification.Visible = true
        -- 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
        -- Hide after duration
        task.delay(Settings.ui.Notification.Duration, function()
            if UI.Notification then
                UI.Notification.Visible = false
                UI.Notification.Text = ""
            end
        end)
    end
end

-- UI: Create a new UI element with rounded corners
local function createRoundedFrame(parent, size, position, color, transparency, name)
    local frame = Instance.new("Frame")
    frame.Name = name or "RoundedFrame"
    frame.Size = size
    frame.Position = position
    frame.BackgroundColor3 = color
    frame.BackgroundTransparency = transparency
    frame.BorderSizePixel = 0
    frame.Parent = parent

    local corner = Instance.new("UICorner")
    corner.CornerRadius = Settings.ui.CornerRadius
    corner.Parent = frame

    return frame
end

-- UI: Create a new TextLabel with consistent styling
local function createStyledTextLabel(parent, size, position, text, textSize, textColor, font, name)
    local label = Instance.new("TextLabel")
    label.Name = name or "StyledLabel"
    label.Size = size
    label.Position = position
    label.BackgroundTransparency = 1
    label.Text = text
    label.TextColor3 = textColor or Settings.ui.TextColor
    label.TextScaled = false
    label.Font = font or Settings.ui.Font
    label.TextSize = textSize or 14
    label.TextWrapped = true
    label.Parent = parent
    return label
end

-- UI: Create a new TextButton with rounded corners and hover effects
local function createStyledButton(parent, size, position, text, textSize, textColor, font, buttonColor, name)
    local button = Instance.new("TextButton")
    button.Name = name or "StyledButton"
    button.Size = size
    button.Position = position
    button.BackgroundColor3 = buttonColor or Settings.ui.PrimaryColor
    button.BackgroundTransparency = 0.2
    button.Text = text
    button.TextColor3 = textColor or Settings.ui.TextColor
    button.TextScaled = false
    button.Font = font or Settings.ui.Font
    button.TextSize = textSize or 14
    button.AutoButtonColor = false
    button.BorderSizePixel = 0
    button.Parent = parent

    -- Add rounded corners
    local corner = Instance.new("UICorner")
    corner.CornerRadius = Settings.ui.CornerRadius
    corner.Parent = button

    -- Hover Effect
    button.MouseEnter:Connect(function()
        TweenService:Create(button, TweenInfo.new(0.2), {BackgroundColor3 = buttonColor:lerp(Color3.new(1,1,1), 0.2)}):Play()
    end)

    button.MouseLeave:Connect(function()
        TweenService:Create(button, TweenInfo.new(0.2), {BackgroundColor3 = buttonColor}):Play()
    end)

    return button
end

-- UI: Create a new ImageLabel for Direction Indicator
local function createDirectionIndicator(parent, size, position, imageId, color, transparency, name)
    local indicator = Instance.new("ImageLabel")
    indicator.Name = name or "DirectionIndicator"
    indicator.Size = size
    indicator.Position = position
    indicator.BackgroundTransparency = 1
    indicator.Image = imageId
    indicator.ImageColor3 = color
    indicator.ImageTransparency = transparency
    indicator.AnchorPoint = Vector2.new(0.5, 0.5)
    indicator.Rotation = 0
    indicator.Visible = false
    indicator.Parent = parent

    return indicator
end

-- UI: Setup Notifications
local function createNotification(parent)
    local notification = createStyledTextLabel(
        parent,
        UDim2.new(Settings.ui.Notification.Size.X, 0, Settings.ui.Notification.Size.Y, 0),
        UDim2.new(0.5 - (Settings.ui.Notification.Size.X.Scale / 2), 0, Settings.ui.Notification.Position.Y, 0),
        Settings.ui.Notification.Text,
        Settings.ui.FontSize,
        Settings.ui.TextColor,
        Enum.Font.GothamSemibold,
        "Notification"
    )
    notification.BackgroundColor3 = Settings.ui.Notification.Color
    notification.BackgroundTransparency = 0.5
    notification.BorderSizePixel = 0
    notification.Visible = false
    notification.TextScaled = true
    return notification
end

-- UI: Setup Theme Toggle
local function setupThemeToggle()
    local themeToggle = UI.MainPanel:FindFirstChild("ThemeToggle")
    if not themeToggle then return end

    themeToggle.MouseButton1Click:Connect(function()
        if State.currentTheme == "Dark" then
            State.currentTheme = "Light"
            themeToggle.Text = "Toggle Theme: Light"
            -- Apply Light Theme
            UI.MainPanel.BackgroundColor3 = Settings.ui.BackgroundColor
            UI.MainPanel.BackgroundTransparency = 0.9
            UI.StatisticsPanel.BackgroundColor3 = Settings.ui.BackgroundColor
            UI.StatisticsPanel.BackgroundTransparency = 0.8
            UI.LogLevelIndicator.BackgroundColor3 = Color3.fromRGB(255, 255, 255)
        else
            State.currentTheme = "Dark"
            themeToggle.Text = "Toggle Theme: Dark"
            -- Apply Dark Theme
            UI.MainPanel.BackgroundColor3 = Settings.ui.PrimaryColor
            UI.MainPanel.BackgroundTransparency = 0.9
            UI.StatisticsPanel.BackgroundColor3 = Settings.ui.PrimaryColor
            UI.StatisticsPanel.BackgroundTransparency = 0.8
            UI.LogLevelIndicator.BackgroundColor3 = Settings.ui.AccentColor
        end
        log("Theme changed to " .. State.currentTheme, LOG_LEVELS.INFO)
    end)
end

-- UI: Setup the User Interface
local function setupUI()
    -- Create ScreenGui
    local screenGui = Instance.new("ScreenGui")
    screenGui.Name = Settings.ui.ScreenGuiName
    screenGui.Parent = LOCAL_PLAYER:WaitForChild("PlayerGui")
    screenGui.ResetOnSpawn = false
    screenGui.DisplayOrder = 1000  -- Ensure it's on top

    -- Main Configuration Panel
    local mainPanel = createRoundedFrame(
        screenGui,
        Settings.ui.MainPanel.Size,
        Settings.ui.MainPanel.Position,
        Settings.ui.MainPanel.Color,
        Settings.ui.MainPanel.Transparency,
        "MainPanel"
    )
    mainPanel.Visible = false -- Hidden by default

    -- Main Panel Title
    createStyledTextLabel(
        mainPanel,
        UDim2.new(1, 0, 0, 40),
        UDim2.new(0, 0, 0, 0),
        Settings.ui.MainPanel.Title,
        24,
        Settings.ui.TextColor,
        Enum.Font.GothamSemibold,
        "MainTitle"
    )

    -- Auto Block Toggle Button
    local autoBlockToggle = createStyledButton(
        mainPanel,
        UDim2.new(0.8, 0, 0, 40),
        UDim2.new(0.1, 0, 0.2, 0),
        "Auto Block: On",
        Settings.ui.FontSize,
        Settings.ui.TextColor,
        Enum.Font.GothamSemibold,
        Color3.fromRGB(0, 170, 255),
        "AutoBlockToggle"
    )
    
    -- Counter Key Configuration Button
    local counterKeyButton = createStyledButton(
        mainPanel,
        UDim2.new(0.8, 0, 0, 40),
        UDim2.new(0.1, 0, 0.35, 0),
        "Counter Key: " .. State.counterKey.Name,
        Settings.ui.FontSize,
        Settings.ui.TextColor,
        Enum.Font.GothamSemibold,
        Color3.fromRGB(0, 170, 255),
        "CounterKeyButton"
    )
    
    -- Log Level Dropdown Button
    local logLevelDropdown = createStyledButton(
        mainPanel,
        UDim2.new(0.8, 0, 0, 40),
        UDim2.new(0.1, 0, 0.5, 0),
        "Log Level: Info",
        Settings.ui.FontSize,
        Settings.ui.TextColor,
        Enum.Font.GothamSemibold,
        Color3.fromRGB(0, 170, 255),
        "LogLevelDropdown"
    )

    -- Sound Effects Toggle Button
    local soundToggle = createStyledButton(
        mainPanel,
        Settings.ui.SoundToggle.Size,
        Settings.ui.SoundToggle.Position,
        Settings.ui.SoundToggle.Text,
        Settings.ui.FontSize,
        Settings.ui.TextColor,
        Enum.Font.GothamSemibold,
        Color3.fromRGB(0, 170, 255),
        "SoundToggle"
    )
    
    -- Theme Toggle Button
    local themeToggle = createStyledButton(
        mainPanel,
        Settings.ui.ThemeToggle.Size,
        Settings.ui.ThemeToggle.Position,
        Settings.ui.ThemeToggle.Text,
        Settings.ui.FontSize,
        Settings.ui.TextColor,
        Enum.Font.GothamSemibold,
        Settings.ui.ThemeToggle.Color,
        "ThemeToggle"
    )
    
    -- Log Display (Scrollable TextBox)
    local logDisplay = Instance.new("ScrollingFrame")
    logDisplay.Name = "LogDisplay"
    logDisplay.Size = UDim2.new(0.9, 0, 0.35, -50)
    logDisplay.Position = UDim2.new(0.05, 0, 0.6, 0)
    logDisplay.BackgroundTransparency = 1
    logDisplay.BorderSizePixel = 0
    logDisplay.ScrollBarThickness = 5
    logDisplay.AutomaticCanvasSize = Enum.AutomaticSize.Y
    logDisplay.Parent = mainPanel

    local logText = Instance.new("TextLabel")
    logText.Name = "LogText"
    logText.Size = UDim2.new(1, 0, 1, 0)
    logText.Position = UDim2.new(0, 0, 0, 0)
    logText.BackgroundTransparency = 1
    logText.Text = ""
    logText.TextColor3 = Settings.ui.TextColor
    logText.TextSize = 14
    logText.TextWrapped = true
    logText.Font = Settings.ui.Font
    logText.Parent = logDisplay

    -- Export Log Button
    local exportLogButton = createStyledButton(
        mainPanel,
        Settings.ui.ExportLogButton.Size,
        Settings.ui.ExportLogButton.Position,
        Settings.ui.ExportLogButton.Text,
        Settings.ui.FontSize,
        Settings.ui.TextColor,
        Enum.Font.GothamSemibold,
        Color3.fromRGB(0, 170, 255),
        "ExportLogButton"
    )

    -- Statistics Panel
    local statisticsPanel = createRoundedFrame(
        screenGui,
        Settings.ui.StatisticsPanel.Size,
        Settings.ui.StatisticsPanel.Position,
        Settings.ui.StatisticsPanel.Color,
        Settings.ui.StatisticsPanel.Transparency,
        "StatisticsPanel"
    )

    -- Statistics Panel Title
    createStyledTextLabel(
        statisticsPanel,
        UDim2.new(1, 0, 0, 30),
        UDim2.new(0, 0, 0, 0),
        Settings.ui.StatisticsPanel.Title,
        18,
        Settings.ui.TextColor,
        Enum.Font.GothamSemibold,
        "StatsTitle"
    )

    -- Blocks Label
    local blocksLabel = createStyledTextLabel(
        statisticsPanel,
        UDim2.new(0.9, 0, 0, 20),
        UDim2.new(0.05, 0, 0.2, 0),
        "Blocks: 0",
        14,
        Settings.ui.TextColor,
        Enum.Font.Gotham,
        "BlocksLabel"
    )

    -- Counters Label
    local countersLabel = createStyledTextLabel(
        statisticsPanel,
        UDim2.new(0.9, 0, 0, 20),
        UDim2.new(0.05, 0, 0.4, 0),
        "Counters: 0",
        14,
        Settings.ui.TextColor,
        Enum.Font.Gotham,
        "CountersLabel"
    )

    -- Log Level Indicator
    local logLevelIndicator = createStyledTextLabel(
        screenGui,
        UDim2.new(0, 150, 0, 30),
        UDim2.new(0.5, -75, 0, 10),
        Settings.ui.LogLevelIndicator.Text,
        Settings.ui.FontSize,
        Color3.fromRGB(0, 0, 0),
        Enum.Font.GothamSemibold,
        "LogLevelIndicator"
    )
    logLevelIndicator.BackgroundColor3 = Settings.ui.LogLevelIndicator.Color
    logLevelIndicator.BackgroundTransparency = 0.3

    -- Notification Setup
    local notification = createNotification(screenGui)
    UI.Notification = notification

    -- Assign to UI table
    UI.ScreenGui = screenGui
    UI.MainPanel = mainPanel
    UI.ConfigButton = mainPanel:FindFirstChild("ConfigButton") or createStyledButton(
        mainPanel,
        Settings.ui.ConfigButton.Size,
        Settings.ui.ConfigButton.Position,
        Settings.ui.ConfigButton.Text,
        Settings.ui.FontSize,
        Settings.ui.TextColor,
        Enum.Font.GothamSemibold,
        Settings.ui.ConfigButton.Color,
        "ConfigButton"
    )
    UI.LogLevelIndicator = logLevelIndicator
    UI.StatisticsPanel = statisticsPanel
    UI.SoundToggle = soundToggle
    UI.LogDisplay = logText
    UI.ExportLogButton = exportLogButton
    UI.BlocksLabel = blocksLabel
    UI.CountersLabel = countersLabel
    UI.ThemeToggle = themeToggle

    -- Connect UI Button Events

    -- Auto Block Toggle
    autoBlockToggle.MouseButton1Click:Connect(function()
        Settings.autoBlockEnabled = not Settings.autoBlockEnabled
        autoBlockToggle.Text = "Auto Block: " .. (Settings.autoBlockEnabled and "On" or "Off")
        log("Auto Block " .. (Settings.autoBlockEnabled and "Enabled" or "Disabled"), LOG_LEVELS.INFO)
    end)

    -- Counter Key Button
    counterKeyButton.MouseButton1Click:Connect(function()
        log("Press a new key for Countering...", LOG_LEVELS.INFO)
        local connection
        connection = UserInputService.InputBegan:Connect(function(input, gameProcessed)
            if gameProcessed then return end
            if input.UserInputType == Enum.UserInputType.Keyboard then
                State.counterKey = input.KeyCode
                counterKeyButton.Text = "Counter Key: " .. State.counterKey.Name
                log("Counter Key changed to " .. State.counterKey.Name, LOG_LEVELS.INFO)
                connection:Disconnect()
            end
        end)
    end)

    -- Log Level Dropdown
    logLevelDropdown.MouseButton1Click:Connect(function()
        if Settings.logLevel == LOG_LEVELS.INFO then
            Settings.logLevel = LOG_LEVELS.WARNING
            logLevelDropdown.Text = "Log Level: Warning"
        elseif Settings.logLevel == LOG_LEVELS.WARNING then
            Settings.logLevel = LOG_LEVELS.ERROR
            logLevelDropdown.Text = "Log Level: Error"
        else
            Settings.logLevel = LOG_LEVELS.INFO
            logLevelDropdown.Text = "Log Level: Info"
        end
        updateLogLevelIndicator()
        log("Log level changed to " .. logLevelDropdown.Text:match("Log Level: (.+)"), LOG_LEVELS.INFO)
    end)

    -- Sound Effects Toggle
    soundToggle.MouseButton1Click:Connect(function()
        State.isSoundEnabled = not State.isSoundEnabled
        soundToggle.Text = "Sound Effects: " .. (State.isSoundEnabled and "On" or "Off")
        log("Sound Effects " .. (State.isSoundEnabled and "Enabled" or "Disabled"), LOG_LEVELS.INFO)
    end)

    -- Theme Toggle Button
    setupThemeToggle()

    -- Export Log Button
    exportLogButton.MouseButton1Click:Connect(function()
        local logs = UI.LogDisplay.Text
        if #logs == 0 then
            log("No logs to export.", LOG_LEVELS.WARNING)
            return
        end
        -- Encode logs to JSON
        local success, encodedLogs = pcall(function()
            return HttpService:JSONEncode({logs = logs})
        end)
        if success then
            -- Implement actual export logic here (e.g., send to server, save to file, or copy to clipboard)
            -- For demonstration, we'll display a notification
            log("Logs have been exported.", LOG_LEVELS.INFO)
            UI.Notification.Text = "Logs exported successfully!"
            UI.Notification.Visible = true
            task.delay(Settings.ui.Notification.Duration, function()
                if UI.Notification then
                    UI.Notification.Visible = false
                    UI.Notification.Text = ""
                end
            end)
        else
            log("Failed to encode logs for export.", LOG_LEVELS.ERROR)
        end
    end)
end

-- UI: Create Direction Indicator for a Specific Player
local function createDirectionIndicatorForPlayer(playerId)
    if UI.DirectionIndicators[playerId] then return end
    local indicator = createDirectionIndicator(
        UI.ScreenGui,
        UDim2.new(0, 60, 0, 60),
        UDim2.new(0.5, 0, 0.5, 0),
        "rbxassetid://6023426910", -- Example arrow image
        Color3.fromRGB(255, 255, 0),
        0.7,
        "DirectionIndicator_" .. playerId
    )
    UI.DirectionIndicators[playerId] = indicator
end

-- UI: Update Direction Indicator for a Specific Player
local function updateDirectionIndicator(playerId, rotation)
    local indicator = UI.DirectionIndicators[playerId]
    if indicator then
        indicator.Visible = true
        TweenService:Create(indicator, TweenInfo.new(Settings.ui.aimLockSmoothness), {Rotation = rotation}):Play()
        -- Hide after short duration
        task.delay(1, function()
            if indicator then
                indicator.Visible = false
            end
        end)
    end
end

-- UI: Show Notification
local function showNotification(message, level)
    level = level or LOG_LEVELS.INFO
    if level < Settings.logLevel then return end
    log(message, level)
end

-- Blocking: Start Blocking for a Specific Player
local function startBlocking(playerId)
    if not State.isBlocking then
        State.isBlocking = true
        BlockRemote:FireServer()
        UI.LogLevelIndicator.Text = "Blocking Active"
        UI.LogLevelIndicator.BackgroundColor3 = Settings.ui.AccentColor

        -- 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
        log("Blocking started", LOG_LEVELS.INFO)
    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()
        UI.LogLevelIndicator.Text = "Blocking Inactive"
        UI.LogLevelIndicator.BackgroundColor3 = Color3.fromRGB(255, 255, 255)

        -- 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
        log("Blocking stopped", LOG_LEVELS.INFO)
    end

    -- Hide Direction Indicator if present
    if UI.DirectionIndicators[playerId] then
        UI.DirectionIndicators[playerId].Visible = false
    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()
        UI.LogLevelIndicator.Text = "Blocking Active"
        UI.LogLevelIndicator.BackgroundColor3 = Settings.ui.AccentColor
    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)

        -- Update Direction Indicator
        createDirectionIndicatorForPlayer(attackerId)
        local rotation
        if desiredDirection == BLOCK_DIRECTIONS.Forward then
            rotation = 0
        elseif desiredDirection == BLOCK_DIRECTIONS.Right then
            rotation = 90
        elseif desiredDirection == BLOCK_DIRECTIONS.Backward then
            rotation = 180
        elseif desiredDirection == BLOCK_DIRECTIONS.Left then
            rotation = -90
        end
        updateDirectionIndicator(attackerId, rotation)
    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
    UI.CountersLabel.Text = "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
    UI.BlocksLabel.Text = "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 UI.StatisticsPanel then return end
    -- Update blocks and counters
    UI.BlocksLabel.Text = "Blocks: " .. Settings.statistics.blocks
    UI.CountersLabel.Text = "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
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
    UI.LogLevelIndicator.Text = isBlocking and "Blocking Active" or "Blocking Inactive"
    UI.LogLevelIndicator.BackgroundColor3 = isBlocking and Settings.ui.AccentColor or Color3.fromRGB(255, 255, 255)
end

-- Input Handling: Manual Blocking Toggle and Configurations
local function setupInputHandling()
    -- Manual Blocking Toggle
    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)

    -- Close configuration panel with Escape key
    UserInputService.InputBegan:Connect(function(input, gameProcessed)
        if gameProcessed then return end
        if input.KeyCode == Enum.KeyCode.Escape and State.isConfigOpen then
            State.isConfigOpen = false
            UI.MainPanel.Visible = false
            UI.ConfigButton.Text = "Settings"
            log("Configuration panel closed.", LOG_LEVELS.INFO)
        end
    end)

    -- Configuration Button Event
    UI.ConfigButton.MouseButton1Click:Connect(function()
        State.isConfigOpen = not State.isConfigOpen
        UI.MainPanel.Visible = State.isConfigOpen
        UI.ConfigButton.Text = State.isConfigOpen and "Close" or "Settings"
        log("Configuration panel " .. (State.isConfigOpen and "opened" or "closed") .. ".", LOG_LEVELS.INFO)
    end)
end

-- Logging: Update Log Level Indicator
local function updateLogLevelIndicator()
    local levelText
    if Settings.logLevel == LOG_LEVELS.INFO then
        levelText = "Info"
    elseif Settings.logLevel == LOG_LEVELS.WARNING then
        levelText = "Warning"
    elseif Settings.logLevel == LOG_LEVELS.ERROR then
        levelText = "Error"
    else
        levelText = "Unknown"
    end
    UI.LogLevelIndicator.Text = "Log Level: " .. levelText
end

-- UI: Setup Logging Controls in Configuration Panel
local function setupLoggingControls()
    -- Additional logging controls can be implemented here if needed
end

-- UI: Setup Configuration Controls
local function setupConfigurationControls()
    -- Setup Logging Controls
    setupLoggingControls()
    -- Additional configuration settings can be added here
end

-- UI: Setup All Configuration Controls
local function setupAllConfigControls()
    setupConfigurationControls()
    -- Additional configuration settings can be added here
end

-- Export Logs Functionality
local function exportLogs()
    local logs = UI.LogDisplay.Text
    if #logs == 0 then
        log("No logs to export.", LOG_LEVELS.WARNING)
        return
    end
    -- Encode logs to JSON
    local success, encodedLogs = pcall(function()
        return HttpService:JSONEncode({logs = logs})
    end)
    if success then
        -- Implement actual export logic here (e.g., send to server, save to file, or copy to clipboard)
        -- For demonstration, we'll display a notification
        log("Logs have been exported.", LOG_LEVELS.INFO)
        UI.Notification.Text = "Logs exported successfully!"
        UI.Notification.Visible = true
        task.delay(Settings.ui.Notification.Duration, function()
            if UI.Notification then
                UI.Notification.Visible = false
                UI.Notification.Text = ""
            end
        end)
    else
        log("Failed to encode logs for export.", LOG_LEVELS.ERROR)
    end
end

-- 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 UI
setupUI()

-- Setup All Configuration Controls
setupAllConfigControls()

-- Setup Input Handling
setupInputHandling()

-- Initialize Player Monitoring
initializePlayerMonitoring()

-- Setup Local Player Character Monitoring
setupLocalPlayerCharacterMonitoring()

-- Setup Combined UI Feedback and Directional Block Update
RunService.RenderStepped:Connect(updateUIAndDirection)

-- Initialize Advanced Reaction System
advancedReactionAutoBlock()

-- Connect Export Log Button
if UI.ExportLogButton then
    UI.ExportLogButton.MouseButton1Click:Connect(exportLogs)
end

-- Theme Persistence: Save and Load Theme Preferences
local function loadThemePreference()
    -- Assuming a BoolValue named 'ThemePreference' exists under ScreenGui
    local screenGui = LOCAL_PLAYER:WaitForChild("PlayerGui"):WaitForChild(Settings.ui.ScreenGuiName)
    local themePreference = screenGui:FindFirstChild("ThemePreference")
    if themePreference and themePreference.Value then
        State.currentTheme = "Light"
        UI.ThemeToggle.Text = "Toggle Theme: Light"
        -- Apply Light Theme
        UI.MainPanel.BackgroundColor3 = Settings.ui.BackgroundColor
        UI.StatisticsPanel.BackgroundColor3 = Settings.ui.BackgroundColor
        UI.LogLevelIndicator.BackgroundColor3 = Color3.fromRGB(255, 255, 255)
    else
        State.currentTheme = "Dark"
        UI.ThemeToggle.Text = "Toggle Theme: Dark"
        -- Apply Dark Theme
        UI.MainPanel.BackgroundColor3 = Settings.ui.PrimaryColor
        UI.StatisticsPanel.BackgroundColor3 = Settings.ui.PrimaryColor
        UI.LogLevelIndicator.BackgroundColor3 = Settings.ui.AccentColor
    end
end

local function saveThemePreference()
    local screenGui = LOCAL_PLAYER:WaitForChild("PlayerGui"):WaitForChild(Settings.ui.ScreenGuiName)
    local themePreference = screenGui:FindFirstChild("ThemePreference")
    if not themePreference then
        themePreference = Instance.new("BoolValue")
        themePreference.Name = "ThemePreference"
        themePreference.Parent = screenGui
    end
    themePreference.Value = (State.currentTheme == "Light")
end

-- Load Theme Preference on Script Start
loadThemePreference()

-- Save Theme Preference on Player Leaving
Players.PlayerRemoving:Connect(function(plr)
    if plr == LOCAL_PLAYER then
        saveThemePreference()
    end
end)

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

-- === End of Script ===
```

Reference Script (REFERENCE BLOCKING ONLY):

```
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,
}

local Players = game:GetService("Players")
local RunService = game:GetService("RunService")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local UserInputService = game:GetService("UserInputService")
local VirtualInputManager = game:GetService("VirtualInputManager")

local LightsaberRemotes = ReplicatedStorage:WaitForChild("LightsaberRemotes")
local BlockRemote = LightsaberRemotes:WaitForChild("Block")
local UnblockRemote = LightsaberRemotes:WaitForChild("Unblock")

local ESP_COLOR = Color3.new(1, 0, 0)
local OUTLINE_THICKNESS = 3

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

local Window = Rayfield:CreateWindow({
    Name = "Saber Showdown GUI",
    LoadingTitle = "Saber Showdown Auto Block",
    LoadingSubtitle = "Created By xenon9012",
    ConfigurationSaving = {
        Enabled = true,
        FolderName = "SaberShowdownConfig",
        FileName = "Config"
    },
    KeySystem = false,
})

local ESPTab = Window:CreateTab("ESP Settings", 4483362458)
local AutoBlockTab = Window:CreateTab("Auto Block", 4483362458)
local AutoCounterTab = Window:CreateTab("Auto Counter", 4483362458)
local creditsTab = Window:CreateTab("Credits", 4483362458)

local Section = ESPTab:CreateSection("ESP Config")

local espEnabled = true
local autoBlockEnabled = true
local autoCounterEnabled = false
local autoHalfSwingEnabled = false
local espOutlineColor = Color3.new(1, 1, 1)
local espNameColor = Color3.new(1, 0, 0)
local espDistance = 100
local blockDistance = 20
local autoSlapDistance = 10
local rainbowESPEnabled = false
local highlightThickness = 0.5
local slapTimerEnabled = true
local slapTimerColor = Color3.new(0, 1, 0)
local autoHalfSwingDelay = 0.3

local function updateESPColors()
    for _, player in ipairs(Players:GetPlayers()) do
        if player ~= Players.LocalPlayer and player.Character then
            local espObjects = player.Character:FindFirstChild("ESPObjects")
            if espObjects then
                local highlight = espObjects:FindFirstChild("Highlight")
                local nameESP = espObjects:FindFirstChild("NameESP")
                if highlight then
                    highlight.OutlineColor = espOutlineColor
                    highlight.OutlineTransparency = 1 - highlightThickness
                end
                if nameESP then
                    nameESP.Color = espNameColor
                end
            end
        end
    end
end

local Toggle = ESPTab:CreateToggle({
    Name = "Enable ESP",
    CurrentValue = espEnabled,
    Flag = "ESPToggle",
    Callback = function(Value)
        espEnabled = Value
    end,
})

local RainbowToggle = ESPTab:CreateToggle({
    Name = "Rainbow Outline ESP",
    CurrentValue = rainbowESPEnabled,
    Flag = "RainbowESPToggle",
    Callback = function(Value)
        rainbowESPEnabled = Value
    end,
})

local SlapTimerToggle = ESPTab:CreateToggle({
    Name = "Enable Slap Timer",
    CurrentValue = slapTimerEnabled,
    Flag = "SlapTimerToggle",
    Callback = function(Value)
        slapTimerEnabled = Value
    end,
})

local ColorPicker1 = ESPTab:CreateColorPicker({
    Name = "ESP Outline Color",
    Color = espOutlineColor,
    Flag = "ESPOutlineColor",
    Callback = function(Value)
        espOutlineColor = Value
        updateESPColors()
    end,
})

local ColorPicker2 = ESPTab:CreateColorPicker({
    Name = "ESP Name Color",
    Color = espNameColor,
    Flag = "ESPNameColor",
    Callback = function(Value)
        espNameColor = Value
        updateESPColors()
    end,
})

local Slider1 = ESPTab:CreateSlider({
    Name = "ESP Distance",
    Range = {0, 500},
    Increment = 10,
    Suffix = "studs",
    CurrentValue = espDistance,
    Flag = "ESPDistance",
    Callback = function(Value)
        espDistance = Value
    end,
})

local Slider3 = ESPTab:CreateSlider({
    Name = "Highlight Thickness",
    Range = {0, 1},
    Increment = 0.1,
    Suffix = "",
    CurrentValue = highlightThickness,
    Flag = "HighlightThickness",
    Callback = function(Value)
        highlightThickness = Value
        updateESPColors()
    end,
})

local SlapTimerColorPicker = ESPTab:CreateColorPicker({
    Name = "Slap Timer Color",
    Color = slapTimerColor,
    Flag = "SlapTimerColor",
    Callback = function(Value)
        slapTimerColor = Value
    end,
})

local Toggle2 = AutoBlockTab:CreateToggle({
    Name = "Enable Auto Block",
    CurrentValue = autoBlockEnabled,
    Flag = "AutoBlockToggle",
    Callback = function(Value)
        autoBlockEnabled = Value
    end,
})

local Slider2 = AutoBlockTab:CreateSlider({
    Name = "Block Distance",
    Range = {0, 100},
    Increment = 1,
    Suffix = "studs",
    CurrentValue = blockDistance,
    Flag = "BlockDistance",
    Callback = function(Value)
        blockDistance = Value
    end,
})

local AutoCounterToggle = AutoCounterTab:CreateToggle({
    Name = "Enable Auto Slap",
    CurrentValue = autoCounterEnabled,
    Flag = "AutoCounterToggle",
    Callback = function(Value)
        autoCounterEnabled = Value
    end,
})

local AutoHalfSwingToggle = AutoCounterTab:CreateToggle({
    Name = "Auto Half Swing",
    CurrentValue = autoHalfSwingEnabled,
    Flag = "AutoHalfSwingToggle",
    Callback = function(Value)
        autoHalfSwingEnabled = Value
    end,
})

local AutoHalfSwingSlider = AutoCounterTab:CreateSlider({
    Name = "Auto Half Swing Delay",
    Range = {0.1, 1},
    Increment = 0.1,
    Suffix = "secs",
    CurrentValue = autoHalfSwingDelay,
    Flag = "AutoHalfSwingDelay",
    Callback = function(Value)
        autoHalfSwingDelay = Value
    end,
})

local AutoSlapDistanceSlider = AutoCounterTab:CreateSlider({
    Name = "Auto Slap Distance",
    Range = {0, 50},
    Increment = 1,
    Suffix = "studs",
    CurrentValue = autoSlapDistance,
    Flag = "AutoSlapDistance",
    Callback = function(Value)
        autoSlapDistance = Value
    end,
})

local function createPlayerESP(player)
    local espFolder = Instance.new("Folder")
    espFolder.Name = "ESPObjects"
    espFolder.Parent = player.Character

    local highlight = Instance.new("Highlight")
    highlight.FillColor = Color3.new(1, 0, 0)
    highlight.OutlineColor = espOutlineColor
    highlight.FillTransparency = 1
    highlight.OutlineTransparency = 1 - highlightThickness
    highlight.Adornee = player.Character
    highlight.Parent = espFolder

    local nameESP = Drawing.new("Text")
    nameESP.Visible = false
    nameESP.Center = true
    nameESP.Outline = true
    nameESP.Font = 2
    nameESP.Size = 13
    nameESP.Color = espNameColor

    local healthBar = Drawing.new("Line")
    healthBar.Visible = false
    healthBar.Thickness = 2
    healthBar.Color = Color3.new(0, 1, 0)

    local slapTimerESP = Drawing.new("Text")
    slapTimerESP.Visible = false
    slapTimerESP.Center = true
    slapTimerESP.Outline = true
    slapTimerESP.Font = 2
    slapTimerESP.Size = 13
    slapTimerESP.Color = slapTimerColor

    RunService.RenderStepped:Connect(function()
        if player.Character and player.Character:FindFirstChild("HumanoidRootPart") and player.Character:FindFirstChild("Humanoid") then
            local rootPart = player.Character.HumanoidRootPart
            local humanoid = player.Character.Humanoid
            local vector, onScreen = workspace.CurrentCamera:WorldToViewportPoint(rootPart.Position)
            local distance = (rootPart.Position - workspace.CurrentCamera.CFrame.Position).Magnitude
            
            if onScreen and distance <= espDistance and espEnabled then
                nameESP.Text = string.format("%s [%.1f]", player.Name, distance)
                nameESP.Position = Vector2.new(vector.X, vector.Y - 40)
                nameESP.Visible = true

                local healthPercentage = humanoid.Health / humanoid.MaxHealth
                healthBar.From = Vector2.new(vector.X + 50, vector.Y - 20)
                healthBar.To = Vector2.new(vector.X + 50, vector.Y - 20 + 40 * healthPercentage)
                healthBar.Color = Color3.new(1 - healthPercentage, healthPercentage, 0)
                healthBar.Visible = true

                highlight.Enabled = true

                if rainbowESPEnabled then
                    local hue = (tick() % 5) / 5
                    local rainbowColor = Color3.fromHSV(hue, 1, 1)
                    highlight.OutlineColor = rainbowColor
                    nameESP.Color = rainbowColor
                else
                    highlight.OutlineColor = espOutlineColor
                    nameESP.Color = espNameColor
                end
                highlight.OutlineTransparency = 1 - highlightThickness

                if slapTimerEnabled then
                    slapTimerESP.Position = Vector2.new(vector.X, vector.Y + 20)
                    slapTimerESP.Visible = true
                else
                    slapTimerESP.Visible = false
                end
            else
                nameESP.Visible = false
                healthBar.Visible = false
                highlight.Enabled = false
                slapTimerESP.Visible = false
            end
        else
            nameESP.Visible = false
            healthBar.Visible = false
            highlight.Enabled = false
            slapTimerESP.Visible = false
        end
    end)

    return {nameESP, healthBar, highlight, slapTimerESP}
end

local function getClosestPlayer()
    local closestPlayer = nil
    local shortestDistance = math.huge
    local localPlayer = Players.LocalPlayer
    local localCharacter = localPlayer.Character

    if localCharacter then
        local localPosition = localCharacter.PrimaryPart.Position

        for _, player in ipairs(Players:GetPlayers()) do
            if player ~= localPlayer and player.Character and player.Character:FindFirstChild("HumanoidRootPart") then
                local playerPosition = player.Character.PrimaryPart.Position
                local distance = (playerPosition - localPosition).Magnitude

                if distance < shortestDistance then
                    closestPlayer = player
                    shortestDistance = distance
                end
            end
        end
    end

    return closestPlayer
end

local function onCharacterAdded(character)
    local humanoid = character:WaitForChild("Humanoid")
    local player = Players:GetPlayerFromCharacter(character)
    
    local espObjects = createPlayerESP(player)
    local slapTimerESP = espObjects[4]
    local canSlap = true
    local blockEndTime = 0
    
    humanoid.AnimationPlayed:Connect(function(animTrack)
        for animName, animId in pairs(animIDs) do
            if animTrack.Animation.AnimationId == "rbxassetid://" .. animId then
                print(player.Name .. " used animation: " .. animName)
                
                if animName == "Slap" and slapTimerEnabled then
                    canSlap = false
                    local startTime = tick()
                    
                    task.spawn(function()
                        while tick() - startTime < 3 and slapTimerEnabled do
                            local timeLeft = math.ceil(3 - (tick() - startTime))
                            slapTimerESP.Text = string.format("%d cannot slap", timeLeft)
                            slapTimerESP.Color = slapTimerColor
                            slapTimerESP.Visible = true
                            task.wait(0.1)
                        end
                        
                        canSlap = true
                        slapTimerESP.Text = "Can slap"
                        slapTimerESP.Color = Color3.new(1, 0, 0)
                        slapTimerESP.Visible = true
                    end)
                end
                
                if (animName:find("Swing") or animName == "Slap") and autoBlockEnabled then
                    local localPlayer = Players.LocalPlayer
                    local localCharacter = localPlayer.Character
                    if localCharacter then
                        local localPosition = localCharacter.PrimaryPart.Position
                        local playerPosition = player.Character.PrimaryPart.Position
                        local distance = (playerPosition - localPosition).Magnitude
                        
                        if distance < blockDistance then 
                            BlockRemote:FireServer()
                            
                            task.wait(animTrack.Length)
                            
                            UnblockRemote:FireServer()
                            
                            if autoCounterEnabled and animName == "Slap" then
                                if distance < autoSlapDistance then
                                    VirtualInputManager:SendKeyEvent(true, Enum.KeyCode.E, false, game)
                                    task.wait(0.1)
                                    VirtualInputManager:SendKeyEvent(false, Enum.KeyCode.E, false, game)
                                end
                            end
                        end
                    end
                end
                
                if animName:find("Swing") and player == Players.LocalPlayer and autoHalfSwingEnabled then
                    task.delay(autoHalfSwingDelay, function()
                        mouse1click()
                    end)
                end
                
                break
            end
        end
    end)
end

local function monitorClosestPlayer()
    local closestPlayer = getClosestPlayer()
    if closestPlayer and closestPlayer.Character then
        local humanoid = closestPlayer.Character:FindFirstChild("Humanoid")
        if humanoid then
            humanoid.AnimationPlayed:Connect(function(animTrack)
                for animName, animId in pairs(animIDs) do
                    if animTrack.Animation.AnimationId == "rbxassetid://" .. animId then
                        if animName:find("Block") then
                            blockEndTime = tick() + 0.5
                        end
                    end
                end
            end)
        end
    end
end

RunService.RenderStepped:Connect(function()
    local closestPlayer = getClosestPlayer()
    if closestPlayer and closestPlayer.Character then
        local humanoid = closestPlayer.Character:FindFirstChild("Humanoid")
        if humanoid and tick() > blockEndTime then
            local localPlayer = Players.LocalPlayer
            local localCharacter = localPlayer.Character
            if localCharacter then
                local localPosition = localCharacter.PrimaryPart.Position
                local playerPosition = closestPlayer.Character.PrimaryPart.Position
                local distance = (playerPosition - localPosition).Magnitude
                
                if distance < autoSlapDistance then
                    VirtualInputManager:SendKeyEvent(true, Enum.KeyCode.E, false, game)
                    task.wait(0.1)
                    VirtualInputManager:SendKeyEvent(false, Enum.KeyCode.E, false, game)
                end
            end
        end
    end
end)

for _, player in ipairs(Players:GetPlayers()) do
    if player ~= Players.LocalPlayer then
        if player.Character then
            onCharacterAdded(player.Character)
        end
        player.CharacterAdded:Connect(onCharacterAdded)
    end
end

Players.PlayerAdded:Connect(function(player)
    if player ~= Players.LocalPlayer then
        player.CharacterAdded:Connect(onCharacterAdded)
    end
end)

local creditsSection = creditsTab:CreateSection("Credits")

local creditsText = {
    "Created by xenon90 on discord",
    "If any other comissions are needed then feel free to contact me",
    "Most of my scripts are free that i make due to it being for experience",
}

for _, text in ipairs(creditsText) do
    creditsTab:CreateLabel(text)
end

Rayfield:LoadConfiguration()

monitorClosestPlayer()