Add a good and aesthetic GUI to this:

```
--[[
    Super Advanced Auto Block Script for Saber Showdown
    Further Optimized for Enhanced Performance, Efficiency, and Maintainability
    - Consistently blocks slap attacks within close proximity
    - Enhanced throttling to prevent excessive blocking
    - Consistent block direction updater
    - Further optimized for performance and reduced computational overhead
    - Streamlined code structure for better maintainability
--]]

-- === 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 Workspace = workspace

-- === 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
}

-- === 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 = 12625891544,
        SlappedLegs = 12671715182,
        SlappedArms = 12625896358,
        Punch = 12625897000,         -- Example attack ID
        Kick = 12625897500,          -- Example attack ID
        KickUp = 12625897944,        -- Added KickUp
        KickBack = 12625899752        -- Added KickBack
    },
    
    -- Counter Attacking Settings
    autoCounterEnabled = true,       -- Enable/Disable auto counter attacks
    autoCounterDistance = 10,        -- Distance within which to auto counter
    counterCooldown = 1.5,           -- Cooldown between counters (seconds)
    counterKey = Enum.KeyCode.E,      -- Key to use for countering

    -- Reaction Settings
    reactionTimeThreshold = 0.2,     -- Threshold for reaction time (in seconds)
    predictionFactor = 0.5,          -- Factor for predicting enemy movements (0-1)

    -- Slap Lag Handling
    slapLagCompensation = 0.2,       -- 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",
        BlackBoxSize = UDim2.new(0.25, 0, 0.1, 0),
        BlackBoxPosition = UDim2.new(0, 0, 0.9, 0),
        BlackBoxColor = Color3.fromRGB(0, 0, 0),
        BlackBoxTransparency = 0.5,
        LoadingBarSize = UDim2.new(1, 0, 0.2, 0),
        LoadingBarPosition = UDim2.new(0, 0, -0.2, 0),
        LoadingBarColorActive = Color3.fromRGB(0, 255, 0),
        LoadingBarColorInactive = Color3.fromRGB(255, 0, 0),
        LoadingBarTransparency = 0.3,
        MessageBoxTextActive = "Blocking Active",
        MessageBoxTextInactive = "Press 'Q' to toggle Auto Block",
        MessageBoxColor = Color3.fromRGB(255, 255, 255),
        MessageBoxTransparency = 1,
    },
    
    -- Debris Settings
    debrisLifetime = 300,            -- Time in seconds before debris is removed (e.g., hitboxes)
}

-- === Inverse Mapping for Attack Types ===
local attackTypesInverse = {}
for attack, id in pairs(Settings.attackTypes) do
    attackTypesInverse[id] = attack
end

-- === State Tracking ===
local State = {
    isBlocking = false,
    lastBlockTime = {},         -- [player.UserId] = timestamp
    lastCounterTime = {},       -- [player.UserId] = timestamp
    currentBlockDirection = BLOCK_DIRECTIONS.Forward
}

-- === UI Elements ===
local UI = {
    ScreenGui = nil,
    BlackBox = nil,
    LoadingBar = nil,
    MessageBox = nil
}

-- === Helper Functions ===

-- Utility: Print with timestamp
local function debugPrint(message)
    print(string.format("[%s] %s", os.date("%H:%M:%S"), message))
end

-- UI: Setup the User Interface
local function setupUI()
    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

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

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

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

    UI.ScreenGui = screenGui
    UI.BlackBox = blackBox
    UI.LoadingBar = loadingBar
    UI.MessageBox = messageBox
end

-- Blocking: Start Blocking
local function startBlocking()
    if not State.isBlocking then
        State.isBlocking = true
        BlockRemote:FireServer()
        UI.MessageBox.Text = Settings.ui.MessageBoxTextActive
        UI.LoadingBar.BackgroundColor3 = Settings.ui.LoadingBarColorActive
        debugPrint("Blocking started")
    end
end

-- Blocking: Stop Blocking
local function stopBlocking()
    if State.isBlocking then
        State.isBlocking = false
        UnblockRemote:FireServer()
        UI.MessageBox.Text = Settings.ui.MessageBoxTextInactive
        UI.LoadingBar.BackgroundColor3 = Settings.ui.LoadingBarColorInactive
        debugPrint("Blocking stopped")
    end
end

-- Blocking: Toggle Blocking State
local function toggleBlocking()
    if State.isBlocking then
        stopBlocking()
    else
        startBlocking()
    end
end

-- Prediction: Predict Enemy Movement
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

    local velocity = enemyHRP.Velocity
    return enemyHRP.Position + (velocity * Settings.predictionFactor)
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.Z, direction.X)) % 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
local function updateBlockDirection(attackerPosition)
    local playerCharacter = LOCAL_PLAYER.Character
    if not playerCharacter then return BLOCK_DIRECTIONS.Forward end

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

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

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

    if desiredDirection ~= State.currentBlockDirection then
        State.currentBlockDirection = desiredDirection
        UpdateBlockDirectionRemote:FireServer(desiredDirection)
        debugPrint(string.format("Block direction updated to %s", desiredDirection))
    end

    return desiredDirection
end

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

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

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

    State.lastCounterTime[attackerId] = currentTime
    debugPrint("Auto counter performed against " .. attacker.Name)
end

-- Blocking: Handle Incoming Hit with Enhanced Proximity and Throttling
local function handleIncomingHit(attacker, attackerPosition, attackType)
    local attackerId = attacker.UserId
    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

    -- Check for cooldown
    if State.lastBlockTime[attackerId] and (currentTime - State.lastBlockTime[attackerId]) < cooldown then
        return
    end

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

    local playerHRP = playerCharacter.HumanoidRootPart  -- Cached access
    if not playerHRP then return end

    local distance = (playerHRP.Position - attackerPosition).Magnitude
    if distance > maxDistance then
        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")
    
    -- Determine reaction delay
    local reactionDelay = isSlap and Settings.slapLagCompensation or Settings.reactionTimeThreshold

    task.delay(reactionDelay, function()
        updateBlockDirection(attackerPosition)
        startBlocking()

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

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

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

    local animId = anim.AnimationId
    if not animId then return end

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

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

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

    local attackerCharacter = opponentPlayer.Character
    if not attackerCharacter then return end

    local attackerHRP = attackerCharacter.HumanoidRootPart
    if not attackerHRP then return end

    handleIncomingHit(opponentPlayer, attackerHRP.Position, attackType)
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
        debugPrint("Hitbox detected attack from " .. attackerPlayer.Name)
        handleIncomingHit(attackerPlayer, 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
            connection = hitbox.Touched:Connect(function(hitPart)
                onHitboxTouched(hitPart, attackerPlayer)
            end)

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

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

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

    local heartbeatThrottle = 0.05  -- Run logic every 0.05 seconds (20 times per second)
    local accumulatedTime = 0

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

        if accumulatedTime < heartbeatThrottle then
            return
        end

        accumulatedTime = accumulatedTime - heartbeatThrottle

        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 camCFrame = CAMERA.CFrame
        local camLookVector = camCFrame.LookVector
        local camRightVector = camCFrame.RightVector

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

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

            local distance = (playerPosition - enemyHRP.Position).Magnitude

            -- Determine maximum relevant distance for this enemy based on attack types
            local maxRelevantDistance = Settings.blockDistances.Default
            for _, attackType in pairs(Settings.attackTypes) do
                local attackDistance = Settings.blockDistances[attackType] or Settings.blockDistances.Default
                if attackDistance > maxRelevantDistance then
                    maxRelevantDistance = attackDistance
                end
            end

            if distance > maxRelevantDistance then continue end

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

            local enemyHumanoid = enemyCharacter:FindFirstChildOfClass("Humanoid")
            if not enemyHumanoid then continue end

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

                local animId = anim.AnimationId
                if not animId then continue end

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

                local attackType = 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, 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.LoadingBar.BackgroundColor3 = isBlocking and Settings.ui.LoadingBarColorActive or Settings.ui.LoadingBarColorInactive
    UI.MessageBox.Text = isBlocking and Settings.ui.MessageBoxTextActive or Settings.ui.MessageBoxTextInactive

    -- Update Block Direction based on Aim-Lock
    if Settings.aimLockEnabled and Settings.autoBlockEnabled and isBlocking then
        local mouseX, mouseY = UserInputService:GetMouseLocation()
        local mouseRay = CAMERA:ViewportPointToRay(mouseX, mouseY)
        local playerCharacter = LOCAL_PLAYER.Character
        if playerCharacter and playerCharacter:FindFirstChild("HumanoidRootPart") then
            local targetPosition = playerCharacter.HumanoidRootPart.Position + (mouseRay.Direction * 10)
            updateBlockDirection(targetPosition)
        end
    end
end

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

-- Character Cleanup: Handle Character Death or Removal
local function onCharacterRemoved()
    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 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()

-- Notify that the script is running
debugPrint("Advanced Auto Block Script is now running.")