Further enhance and add an advanced game-state blocking with advanced consistent slap-block methods.

```
-- Enhanced Roblox Script with Advanced Dynamic Slap Blocking System

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

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

-- Settings
local Settings = {
    BlockDistance = 15,
    AutoCounterEnabled = true,
    AutoSlapDistance = 10,
    ReactionTimeThreshold = 0.15, -- Base reaction time
    BlockDuration = 0.3,
    Cooldown = 1.0,
    SlapAnimations = {
        ["Slap"] = 12625891544,
        ["SlappedLegs"] = 12671715182,
        ["SlappedArms"] = 12625896358,
        ["SlappedHead"] = 12625897000,
        ["DoubleSlap"] = 12625897500,
        ["RightSwing"] = 12625839385,
        ["LeftSwing"] = 12625843823,
        ["OverheadSwing"] = 12625841878
    },
    PredictionEnabled = true,
    PredictionFactor = 0.5, -- 0 to 1, higher means more aggressive prediction
    LearningRate = 0.1, -- Rate at which the system adapts to player styles
    VariableBlockDuration = true
}

-- State Management
local blockingPlayers = {} -- Tracks blocking state per opponent
local playerStyles = {} -- Tracks individual player styles for adaptive learning

-- Prediction System
local function predictOpponentMovement(opponent)
    if not Settings.PredictionEnabled then return opponent.Character.HumanoidRootPart.Position end
    
    local predictedPosition = opponent.Character.HumanoidRootPart.Position
    local velocity = opponent.Character.HumanoidRootPart.Velocity
    
    predictedPosition = predictedPosition + (velocity * Settings.PredictionFactor)
    return predictedPosition
end

-- Learning System
local function updatePlayerStyle(opponentName, reactionTime)
    if not playerStyles[opponentName] then
        playerStyles[opponentName] = {averageReactionTime = reactionTime, sampleCount = 1}
    else
        local style = playerStyles[opponentName]
        style.averageReactionTime = (style.averageReactionTime * style.sampleCount + reactionTime) / (style.sampleCount + 1)
        style.sampleCount = style.sampleCount + 1
    end
end

local function getAdaptiveReactionTime(opponentName, baseReactionTime)
    if not playerStyles[opponentName] then return baseReactionTime end
    
    local playerStyle = playerStyles[opponentName]
    return (baseReactionTime + playerStyle.averageReactionTime) / 2
end

-- Variable Block Duration
local function getBlockDuration(animName)
    if not Settings.VariableBlockDuration then return Settings.BlockDuration end
    
    local durationMap = {
        ["Slap"] = 0.3,
        ["DoubleSlap"] = 0.5,
        ["RightSwing"] = 0.4,
        ["LeftSwing"] = 0.4,
        ["OverheadSwing"] = 0.6
    }
    
    return durationMap[animName] or Settings.BlockDuration
end

-- 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")
    
    local blockIndicator = Instance.new("Frame")
    blockIndicator.Size = UDim2.new(0, 200, 0, 100)
    blockIndicator.Position = UDim2.new(0.5, -100, 0, 10)
    blockIndicator.BackgroundColor3 = Color3.new(0, 0, 0)
    blockIndicator.BackgroundTransparency = 0.5
    blockIndicator.Visible = false
    blockIndicator.Parent = screenGui
    
    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 against:\nNone"
    blockText.TextColor3 = Color3.new(1, 1, 1)
    blockText.TextScaled = true
    blockText.TextWrapped = true
    blockText.Parent = blockIndicator
    
    return blockIndicator, blockText
end

local blockIndicator, blockText = setupGUI()

-- Tween for Smooth Appearance/Disappearance
local tweenInfo = TweenInfo.new(0.2, Enum.EasingStyle.Quad, Enum.EasingDirection.Out)
local showTween = TweenService:Create(blockIndicator, tweenInfo, {BackgroundColor3 = Color3.new(0, 0, 0), Visible = true})
local hideTween = TweenService:Create(blockIndicator, tweenInfo, {BackgroundColor3 = Color3.new(0, 0, 0), Visible = false})

local function showBlockIndicator(opponentNames)
    if not blockIndicator.Visible then
        blockIndicator.Visible = true
        showTween:Play()
    end
    blockText.Text = "Blocking against:\n" .. table.concat(opponentNames, ", ")
end

local function hideBlockIndicator(opponentNames)
    if blockIndicator.Visible and #opponentNames == 0 then
        hideTween:Play()
        task.delay(tweenInfo.Time, function()
            blockIndicator.Visible = false
            blockText.Text = "Blocking against:\nNone"
        end)
    else
        blockText.Text = "Blocking against:\n" .. (opponentNames[1] or "None")
    end
end

-- Utility Function to Get Current Time
local function getCurrentTime()
    return tick()
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.BlockDistance 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 Update GUI Indicators based on Blocking State
local function updateGUI()
    local blockingNames = {}
    for opponentName, _ in pairs(blockingPlayers) do
        table.insert(blockingNames, opponentName)
    end
    showBlockIndicator(blockingNames)
    hideBlockIndicator(blockingNames)
end

-- Handle Slap Animation with Advanced Blocking Logic
local function handleSlapAnimation(opponent, animTrack)
    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 predictedPosition = predictOpponentMovement(opponent)
    local distance = (character.HumanoidRootPart.Position - predictedPosition).Magnitude

    if distance > Settings.BlockDistance then return end

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

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

    -- Dynamic Reaction Time based on distance and learned player style
    local baseReactionTime = Settings.ReactionTimeThreshold * (Settings.BlockDistance / distance)
    baseReactionTime = math.clamp(baseReactionTime, 0.05, Settings.ReactionTimeThreshold)
    local adaptiveReactionTime = getAdaptiveReactionTime(opponent.Name, baseReactionTime)

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

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

    if shouldBlock then
        blockingPlayers[opponent.Name] = currentTime
        BlockRemote:FireServer()
        print("Blocking initiated against:", opponent.Name)

        updateGUI()

        -- Variable block duration
        local blockDuration = getBlockDuration(detectedAnimName)

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

        -- Update player style
        updatePlayerStyle(opponent.Name, adaptiveReactionTime)

        -- Auto Counter Slap if enabled and within AutoSlapDistance
        if Settings.AutoCounterEnabled and distance <= Settings.AutoSlapDistance then
            task.delay(adaptiveReactionTime, 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 (same as before)
for _, player in ipairs(Players:GetPlayers()) do
    setupPlayer(player)
end

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

-- Configuration UI
local function createConfigUI()
    local screenGui = Instance.new("ScreenGui")
    screenGui.Name = "BlockConfigGUI"
    screenGui.ResetOnSpawn = false
    screenGui.Parent = Players.LocalPlayer:WaitForChild("PlayerGui")

    local frame = Instance.new("Frame")
    frame.Size = UDim2.new(0, 200, 0, 300)
    frame.Position = UDim2.new(1, -220, 0.5, -150)
    frame.BackgroundColor3 = Color3.new(0.2, 0.2, 0.2)
    frame.BorderSizePixel = 2
    frame.Parent = screenGui

    local title = Instance.new("TextLabel")
    title.Size = UDim2.new(1, 0, 0, 30)
    title.Text = "Block Config"
    title.TextColor3 = Color3.new(1, 1, 1)
    title.BackgroundTransparency = 1
    title.Parent = frame

    local yOffset = 40
    local function addSlider(name, min, max, default)
        local sliderFrame = Instance.new("Frame")
        sliderFrame.Size = UDim2.new(0.9, 0, 0, 50)
        sliderFrame.Position = UDim2.new(0.05, 0, 0, yOffset)
        sliderFrame.BackgroundTransparency = 1
        sliderFrame.Parent = frame

        local label = Instance.new("TextLabel")
        label.Size = UDim2.new(1, 0, 0, 20)
        label.Text = name
        label.TextColor3 = Color3.new(1, 1, 1)
        label.BackgroundTransparency = 1
        label.Parent = sliderFrame

        local slider = Instance.new("TextBox")
        slider.Size = UDim2.new(1, 0, 0, 30)
        slider.Position = UDim2.new(0, 0, 0, 20)
        slider.Text = tostring(default)
        slider.TextColor3 = Color3.new(0, 0, 0)
        slider.BackgroundColor3 = Color3.new(0.8, 0.8, 0.8)
        slider.Parent = sliderFrame

        slider.FocusLost:Connect(function()
            local value = tonumber(slider.Text)
            if value then
                value = math.clamp(value, min, max)
                slider.Text = tostring(value)
                Settings[name] = value
            else
                slider.Text = tostring(default)
            end
        end)

        yOffset = yOffset + 60
    end

    addSlider("BlockDistance", 5, 30, Settings.BlockDistance)
    addSlider("ReactionTimeThreshold", 0.05, 0.5, Settings.ReactionTimeThreshold)
    addSlider("BlockDuration", 0.1, 1, Settings.BlockDuration)
    addSlider("Cooldown", 0.5, 3, Settings.Cooldown)
    addSlider("PredictionFactor", 0, 1, Settings.PredictionFactor)
end

createConfigUI()

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

-- Optimize GUI Updates with Heartbeat
RunService.Heartbeat:Connect(function()
    -- You can add additional logic here if needed
    -- For now, GUI updates are handled within the blocking functions
end)

-- Toggle Config UI Visibility
local configVisible = true
UserInputService.InputBegan:Connect(function(input, gameProcessed)
    if not gameProcessed and input.KeyCode == Enum.KeyCode.RightControl then
        configVisible = not configVisible
        Players.LocalPlayer.PlayerGui.BlockConfigGUI.Enabled = configVisible
    end
end)