Further enhance, and add an advanced anti-slap system and also an advanced close proximity block:

```
-- Enhanced Roblox Script with Advanced Dynamic Universal Slap Blocking System and Toggle Feature

-- Services
local Players = game:GetService("Players")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local RunService = game:GetService("RunService")
local VirtualInputManager = game:GetService("VirtualInputManager")
local TweenService = game:GetService("TweenService")
local UserInputService = game:GetService("UserInputService")
local UIS = game:GetService("UserInputService")

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

-- Settings
local Settings = {
    BaseBlockDistance = 15, -- Base distance for blocking
    AutoCounterEnabled = true,
    AutoSlapDistance = 10,
    ReactionTimeThreshold = 0.15, -- Base reaction time in seconds
    BlockDuration = 0.3, -- Duration to block in seconds
    Cooldown = 1.0, -- Cooldown period between blocks in seconds
    SlapAnimations = {
        ["Slap"] = 12625891544,
        ["SlappedLegs"] = 12671715182,
        ["SlappedArms"] = 12625896358,
        ["RightSwing"] = 12625891545,
        ["LeftSwing"] = 12625891546,
        ["OverheadSwing"] = 12625891547,
        ["DoubleSlap"] = 12625891548
    },
    GUI = {
        BlockIndicatorSize = UDim2.new(0, 250, 0, 120),
        BlockIndicatorPosition = UDim2.new(0.5, -125, 0, 10),
        ToggleIndicatorSize = UDim2.new(0, 200, 0, 50),
        ToggleIndicatorPosition = UDim2.new(0.5, -100, 0, 140),
        IndicatorColors = {
            Enabled = Color3.fromRGB(0, 255, 0),
            Disabled = Color3.fromRGB(255, 0, 0)
        }
    },
    Animations = {
        -- Add any additional animations here
    },
    PingHandler = {
        EnablePingAdjustment = true,
        MaxPing = 1.0, -- Maximum expected ping in seconds
        MinPing = 0.05 -- Minimum ping in seconds
    },
    PredictiveDistance = {
        EnablePrediction = true,
        PredictionFactor = 1.2 -- Multiplier for predicting distance based on movement
    }
}

-- State Management
local blockingPlayers = {} -- Tracks blocking state per opponent
local isBlockingEnabled = true -- Toggle state

-- GUI Setup for Visual Feedback
local function setupGUI()
    local screenGui = Instance.new("ScreenGui")
    screenGui.Name = "AdvancedAntiSlapIndicator"
    screenGui.ResetOnSpawn = false
    screenGui.Parent = Players.LocalPlayer:WaitForChild("PlayerGui")

    -- Block Indicator Frame
    local blockIndicator = Instance.new("Frame")
    blockIndicator.Size = Settings.GUI.BlockIndicatorSize
    blockIndicator.Position = Settings.GUI.BlockIndicatorPosition
    blockIndicator.BackgroundColor3 = Color3.fromRGB(0, 0, 0)
    blockIndicator.BackgroundTransparency = 0.5
    blockIndicator.BorderSizePixel = 0
    blockIndicator.Visible = false
    blockIndicator.Parent = screenGui

    -- Block Text Label
    local blockText = Instance.new("TextLabel")
    blockText.Size = UDim2.new(1, 0, 1, 0)
    blockText.Position = UDim2.new(0, 0, 0, 0)
    blockText.BackgroundTransparency = 1
    blockText.Text = "Blocking System:\nEnabled\nAgainst: None"
    blockText.TextColor3 = Settings.GUI.IndicatorColors.Enabled
    blockText.TextScaled = true
    blockText.TextWrapped = true
    blockText.Parent = blockIndicator

    -- Directional Indicators (e.g., Top, Bottom, Left, Right)
    local directions = {"Top", "Bottom", "Left", "Right", "TopLeft", "TopRight", "BottomLeft", "BottomRight"}
    local directionIndicators = {}
    for _, dir in ipairs(directions) do
        local indicator = Instance.new("Frame")
        indicator.Size = UDim2.new(0, 20, 0, 20)
        indicator.BackgroundColor3 = Color3.fromRGB(255, 0, 0)
        indicator.BackgroundTransparency = 0.7
        indicator.BorderSizePixel = 0
        indicator.Visible = false
        indicator.Name = dir .. "Indicator"
        indicator.Parent = blockIndicator

        -- Position indicators around the blockIndicator
        if dir == "Top" then
            indicator.Position = UDim2.new(0.5, -10, 0, -25)
        elseif dir == "Bottom" then
            indicator.Position = UDim2.new(0.5, -10, 1, 5)
        elseif dir == "Left" then
            indicator.Position = UDim2.new(0, -25, 0.5, -10)
        elseif dir == "Right" then
            indicator.Position = UDim2.new(1, 5, 0.5, -10)
        elseif dir == "TopLeft" then
            indicator.Position = UDim2.new(0, -15, 0, -15)
        elseif dir == "TopRight" then
            indicator.Position = UDim2.new(1, -5, 0, -15)
        elseif dir == "BottomLeft" then
            indicator.Position = UDim2.new(0, -15, 1, -5)
        elseif dir == "BottomRight" then
            indicator.Position = UDim2.new(1, -5, 1, -5)
        end

        directionIndicators[dir] = indicator
    end

    -- Toggle Indicator Frame
    local toggleIndicator = Instance.new("Frame")
    toggleIndicator.Size = Settings.GUI.ToggleIndicatorSize
    toggleIndicator.Position = Settings.GUI.ToggleIndicatorPosition
    toggleIndicator.BackgroundColor3 = Color3.fromRGB(0, 0, 0)
    toggleIndicator.BackgroundTransparency = 0.5
    toggleIndicator.BorderSizePixel = 0
    toggleIndicator.Visible = false
    toggleIndicator.Parent = screenGui

    -- Toggle Text Label
    local toggleText = Instance.new("TextLabel")
    toggleText.Size = UDim2.new(1, 0, 1, 0)
    toggleText.Position = UDim2.new(0, 0, 0, 0)
    toggleText.BackgroundTransparency = 1
    toggleText.Text = "Blocking System Disabled"
    toggleText.TextColor3 = Settings.GUI.IndicatorColors.Disabled
    toggleText.TextScaled = true
    toggleText.TextWrapped = true
    toggleText.Parent = toggleIndicator

    return blockIndicator, blockText, toggleIndicator, toggleText, directionIndicators
end

local blockIndicator, blockText, toggleIndicator, toggleText, directionIndicators = setupGUI()

-- Tween for Smooth Appearance/Disappearance
local tweenInfoVisible = TweenInfo.new(0.2, Enum.EasingStyle.Quad, Enum.EasingDirection.Out)
local tweenInfoHidden = TweenInfo.new(0.2, Enum.EasingStyle.Quad, Enum.EasingDirection.In)

local showTweenBlock = TweenService:Create(blockIndicator, tweenInfoVisible, {BackgroundTransparency = 0.3, Visible = true})
local hideTweenBlock = TweenService:Create(blockIndicator, tweenInfoHidden, {BackgroundTransparency = 0.5, Visible = false})

local showTweenToggle = TweenService:Create(toggleIndicator, tweenInfoVisible, {BackgroundTransparency = 0.3, Visible = true})
local hideTweenToggle = TweenService:Create(toggleIndicator, tweenInfoHidden, {BackgroundTransparency = 0.5, Visible = false})

-- Utility Function to Get Current Time
local function getCurrentTime()
    return tick()
end

-- Function to Get Player's Current Ping
local function getPlayerPing()
    local localPlayer = Players.LocalPlayer
    if localPlayer and typeof(localPlayer.GetNetworkPing) == "function" then
        return localPlayer:GetNetworkPing()
    else
        return 0
    end
end

-- Function to Get Closest Players within BlockDistance
local function getClosestPlayers()
    local players = {}
    local localPlayer = Players.LocalPlayer
    local localCharacter = localPlayer.Character

    if localCharacter and localCharacter:FindFirstChild("HumanoidRootPart") then
        local localPosition = localCharacter.HumanoidRootPart.Position

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

                if distance <= Settings.BaseBlockDistance then
                    table.insert(players, {Player = player, Distance = distance})
                end
            end
        end
    end

    table.sort(players, function(a, b) return a.Distance < b.Distance end)
    return players
end

-- Function to Determine Direction from LocalPlayer to Opponent
local function getDirection(localPos, opponentPos)
    local directionVector = (opponentPos - localPos).Unit
    local angle = math.deg(math.atan2(directionVector.Z, directionVector.X)) -- Y is up

    -- Determine direction based on angle
    if angle >= -22.5 and angle < 22.5 then
        return "Right"
    elseif angle >= 22.5 and angle < 67.5 then
        return "TopRight"
    elseif angle >= 67.5 and angle < 112.5 then
        return "Top"
    elseif angle >= 112.5 and angle < 157.5 then
        return "TopLeft"
    elseif (angle >= 157.5 and angle <= 180) or (angle >= -180 and angle < -157.5) then
        return "Left"
    elseif angle >= -157.5 and angle < -112.5 then
        return "BottomLeft"
    elseif angle >= -112.5 and angle < -67.5 then
        return "Bottom"
    elseif angle >= -67.5 and angle < -22.5 then
        return "BottomRight"
    end
end

-- Function to Update GUI Indicators based on Blocking State and Directions
local function updateGUI(opponent, direction)
    local blockingNames = {}
    for opponentName, info in pairs(blockingPlayers) do
        blockingNames[#blockingNames + 1] = opponentName
        -- Show directional indicator
        if directionIndicators[info.Direction] then
            directionIndicators[info.Direction].Visible = true
        end
    end

    if isBlockingEnabled and #blockingNames > 0 then
        blockIndicator.Visible = true
        blockText.Text = "Blocking System:\nEnabled\nAgainst:\n" .. table.concat(blockingNames, ", ")
        blockText.TextColor3 = Settings.GUI.IndicatorColors.Enabled
    else
        blockIndicator.Visible = false
        blockText.Text = "Blocking System:\nEnabled\nAgainst:\nNone"
        blockText.TextColor3 = Settings.GUI.IndicatorColors.Enabled
    end
end

-- Function to Clear Directional Indicators
local function clearDirectionalIndicators()
    for _, indicator in pairs(directionIndicators) do
        indicator.Visible = false
    end
end

-- Function to Toggle Blocking System
local function toggleBlockingSystem()
    isBlockingEnabled = not isBlockingEnabled
    if isBlockingEnabled then
        -- Enable Blocking System
        hideTweenToggle:Play()
        toggleIndicator.Visible = false
        print("Blocking System Enabled")
    else
        -- Disable Blocking System
        showTweenToggle:Play()
        toggleIndicator.Visible = true
        blockingPlayers = {} -- Clear any existing blocking states
        UnblockRemote:FireServer()
        print("Blocking System Disabled")
        clearDirectionalIndicators()
    end
    updateGUI()
end

-- Key Binding for Toggle (R Key)
UserInputService.InputBegan:Connect(function(input, gameProcessed)
    if gameProcessed then return end
    if input.KeyCode == Enum.KeyCode.R then
        toggleBlockingSystem()
    end
end)

-- Function to Calculate Dynamic Reaction Time based on Distance and Ping
local function calculateDynamicReactionTime(distance)
    local dynamicReactionTime = Settings.ReactionTimeThreshold * (Settings.BaseBlockDistance / distance)

    -- Clamp the reaction time within thresholds
    dynamicReactionTime = math.clamp(dynamicReactionTime, 0.05, Settings.ReactionTimeThreshold)

    if Settings.PingHandler.EnablePingAdjustment then
        local ping = getPlayerPing() -- Ping in seconds
        dynamicReactionTime = dynamicReactionTime + ping
        -- Clamp again after adding ping
        dynamicReactionTime = math.clamp(dynamicReactionTime, 0.05, Settings.ReactionTimeThreshold + Settings.PingHandler.MaxPing)
    end

    return dynamicReactionTime
end

-- Function to Predict Distance based on opponent's movement (Optional Enhancement)
local function predictDistance(currentDistance, targetDistance)
    if Settings.PredictiveDistance.EnablePrediction then
        return targetDistance * Settings.PredictiveDistance.PredictionFactor
    else
        return currentDistance
    end
end

-- Function to Handle Slap Animation with Advanced Blocking Logic
local function handleSlapAnimation(opponent, animTrack)
    if not isBlockingEnabled then return end

    local localPlayer = Players.LocalPlayer
    local character = localPlayer.Character
    if not character or not character:FindFirstChild("HumanoidRootPart") then return end

    local opponentRoot = opponent.Character:FindFirstChild("HumanoidRootPart")
    if not opponentRoot then return end

    local localPos = character.HumanoidRootPart.Position
    local opponentPos = opponentRoot.Position
    local distance = (localPos - opponentPos).Magnitude

    if distance > Settings.BaseBlockDistance then return end

    local currentTime = getCurrentTime()
    local lastBlockInfo = blockingPlayers[opponent.Name]
    local lastBlock = lastBlockInfo and lastBlockInfo.LastBlock or 0
    local timeSinceLastBlock = currentTime - lastBlock

    if timeSinceLastBlock < Settings.Cooldown then
        print("Block on cooldown for:", opponent.Name, "Time left:", string.format("%.2f", Settings.Cooldown - timeSinceLastBlock))
        return
    end

    -- Dynamic Reaction Time based on distance and ping
    local dynamicReactionTime = calculateDynamicReactionTime(distance)

    -- Predictive Distance Adjustment
    local predictedDistance = predictDistance(distance, Settings.BaseBlockDistance)
    if predictedDistance < distance then
        predictedDistance = distance -- Prevent reducing the necessary distance
    end

    -- Determine if block should be initiated based on animation
    local shouldBlock = false
    local reactiveAnims = {"Slap", "RightSwing", "LeftSwing", "OverheadSwing", "DoubleSlap"}

    for _, animName in ipairs(reactiveAnims) do
        if animTrack.Animation and animTrack.Animation.AnimationId == "rbxassetid://" .. Settings.SlapAnimations[animName] then
            shouldBlock = true
            break
        end
    end

    if shouldBlock then
        local direction = getDirection(localPos, opponentPos)
        blockingPlayers[opponent.Name] = {
            LastBlock = currentTime,
            Direction = direction
        }
        BlockRemote:FireServer()
        print("Blocking initiated against:", opponent.Name, "from direction:", direction)

        updateGUI(opponent, direction)

        -- Schedule Unblock
        task.delay(Settings.BlockDuration, function()
            blockingPlayers[opponent.Name] = nil
            UnblockRemote:FireServer()
            print("Blocking ended for:", opponent.Name)
            updateGUI()
        end)

        -- Auto Counter Slap if enabled and within AutoSlapDistance
        if Settings.AutoCounterEnabled and distance <= Settings.AutoSlapDistance then
            task.delay(dynamicReactionTime, function()
                VirtualInputManager:SendKeyEvent(true, Enum.KeyCode.E, false, game)
                task.wait(0.1)
                VirtualInputManager:SendKeyEvent(false, Enum.KeyCode.E, false, game)
                print("Automatic counter-slap performed against:", opponent.Name)
            end)
        end
    end
end

-- Monitor Opponent's Animations
local function onOpponentAnimationPlayed(opponent, animTrack)
    for animName, animId in pairs(Settings.SlapAnimations) do
        if animTrack.Animation and animTrack.Animation.AnimationId == "rbxassetid://" .. animId then
            print("Detected slap animation:", animName, "from:", opponent.Name)
            handleSlapAnimation(opponent, animTrack)
            break
        end
    end
end

-- Setup Character Connections
local function onCharacterAdded(character, player)
    local humanoid = character:WaitForChild("Humanoid")
    humanoid.AnimationPlayed:Connect(function(animTrack)
        onOpponentAnimationPlayed(player, animTrack)
    end)
end

-- Setup Player Connections
local function setupPlayer(player)
    if player == Players.LocalPlayer then return end
    if player.Character then
        onCharacterAdded(player.Character, player)
    end
    player.CharacterAdded:Connect(function(character)
        onCharacterAdded(character, player)
    end)
end

-- Initialize Existing Players
for _, player in ipairs(Players:GetPlayers()) do
    setupPlayer(player)
end

-- Listen for New Players
Players.PlayerAdded:Connect(setupPlayer)

-- Listen for Player Removing
Players.PlayerRemoving:Connect(function(player)
    if blockingPlayers[player.Name] then
        blockingPlayers[player.Name] = nil
        updateGUI()
    end
end)

-- Initial GUI Update
updateGUI()

-- Clear directional indicators periodically to avoid stale indicators
RunService.RenderStepped:Connect(function()
    if not isBlockingEnabled then return end
    -- Hide all directional indicators if no active blocking
    if next(blockingPlayers) == nil then
        clearDirectionalIndicators()
    end
end)

-- Optional: Display Instructions in the Output
print("Advanced Dynamic Universal Slap Blocking System Initialized.")
print("Press 'R' to toggle the blocking system on and off.")