local Players = game:GetService("Players") local RunService = game:GetService("RunService") local ReplicatedStorage = game:GetService("ReplicatedStorage") local UserInputService = game:GetService("UserInputService") local StarterGui = game:GetService("StarterGui") local localPlayer = Players.LocalPlayer local CONFIG = { -- configurations FOLLOW_DISTANCE = 1.2, -- how close do you want to be to the protected user STOP_DISTANCE = 0.45, -- which studs do you want to stop backing up to the protected user's back MAX_SPEED = 130, -- how fast do you want to follow to the protected user ACCELERATION = 30, -- speed-up AUTO_INTERVAL = 20 * 60, -- adjustions RATE_LIMIT = 1.2, -- limits ig } local targetPlayer = nil local connection = nil local lastCommandTime = {} local lastMessageTime = 0 local function serverChat(message) if not localPlayer.Character then return end local success = pcall(function() local chatEvents = ReplicatedStorage:FindFirstChild("DefaultChatSystemChatEvents") if chatEvents then local sayRequest = chatEvents:FindFirstChild("SayMessageRequest") if sayRequest then sayRequest:FireServer(message, "All") return end end end) if success then return end success = pcall(function() local tcs = game:GetService("TextChatService") if tcs.ChatVersion == Enum.ChatVersion.TextChatService then local channel = tcs:FindFirstChild("TextChannels") and tcs.TextChannels:FindFirstChild("RBXGeneral") if channel then channel:SendAsync(message) return end end end) if success then return end pcall(function() StarterGui:SetCore("ChatMakeSystemMessage", { Text = "[Protector] " .. message, Color = Color3.fromRGB(0, 255, 100), Font = Enum.Font.SourceSansBold }) end) end local function findPlayer(query) if not query or #query < 1 then return nil end query = query:lower():gsub("%s+", "") local best, bestScore = nil, -1 for _, plr in ipairs(Players:GetPlayers()) do if plr == localPlayer then continue end local uname = plr.Name:lower() local dname = plr.DisplayName:lower() local score = 0 if uname == query or dname == query then return plr end if uname:find(query, 1, true) then score = 88 elseif dname:find(query, 1, true) then score = 78 end if uname:sub(1, #query) == query then score += 25 elseif dname:sub(1, #query) == query then score += 20 end if score > bestScore then bestScore = score best = plr end end return best end local function stopFollowing() targetPlayer = nil if connection then connection:Disconnect() connection = nil end local char = localPlayer.Character if char then local hum = char:FindFirstChild("Humanoid") local root = char:FindFirstChild("HumanoidRootPart") if hum then hum.PlatformStand = false hum.WalkSpeed = 16 end if root then root.AssemblyLinearVelocity = Vector3.new(0, 0, 0) end end end local function startFollowing(target) if not target or target == localPlayer then return end targetPlayer = target if connection then connection:Disconnect() end connection = RunService.Heartbeat:Connect(function() local myChar = localPlayer.Character local tChar = targetPlayer.Character if not myChar or not tChar then stopFollowing() return end local myRoot = myChar:FindFirstChild("HumanoidRootPart") local tRoot = tChar:FindFirstChild("HumanoidRootPart") local myHum = myChar:FindFirstChild("Humanoid") if not myRoot or not tRoot or not myHum then stopFollowing() return end myHum.PlatformStand = false myHum.WalkSpeed = 60 local behindPos = (tRoot.CFrame * CFrame.new(0, 0, CONFIG.FOLLOW_DISTANCE)).Position local dist = (behindPos - myRoot.Position).Magnitude if dist > CONFIG.STOP_DISTANCE then local dir = (behindPos - myRoot.Position).Unit local speed = math.min(dist * CONFIG.ACCELERATION, CONFIG.MAX_SPEED) myRoot.AssemblyLinearVelocity = Vector3.new(dir.X * speed, myRoot.AssemblyLinearVelocity.Y, dir.Z * speed) else myRoot.AssemblyLinearVelocity = Vector3.new(0, myRoot.AssemblyLinearVelocity.Y, 0) end if dist > 8 then myRoot.CFrame = CFrame.lookAt(myRoot.Position, tRoot.Position) else local desired = -tRoot.CFrame.LookVector local current = myRoot.CFrame.LookVector myRoot.CFrame = CFrame.lookAt(myRoot.Position, myRoot.Position + current:Lerp(desired, 0.25)) end end) end local function canRunCommand(player, cmd) local key = tostring(player.UserId) .. cmd local now = tick() if lastCommandTime[key] and now - lastCommandTime[key] < CONFIG.RATE_LIMIT then return false end lastCommandTime[key] = now return true end local function onPlayerChatted(player, message) if not message or message:sub(1,1) ~= ";" then return end if not canRunCommand(player, message) then return end local args = {} for word in message:gmatch("%S+") do table.insert(args, word) end local cmd = args[1]:lower() if cmd == ";protect" and args[2] then local target = findPlayer(args[2]) if not target then serverChat("Player not found: " .. args[2]) return end if targetPlayer and targetPlayer ~= player then serverChat(targetPlayer.DisplayName .. " is currently protected. Only they can change it.") return end if targetPlayer == target then stopFollowing() serverChat("Stopped protecting " .. target.DisplayName) else startFollowing(target) serverChat("Now protecting " .. target.DisplayName .. " (" .. target.Name .. ")") end elseif cmd == ";unprotect" then if targetPlayer == player then stopFollowing() serverChat("Stopped protecting you.") else serverChat("You are not being protected right now.") end end end local function setupListeners() for _, plr in Players:GetPlayers() do if plr ~= localPlayer then plr.Chatted:Connect(function(msg) onPlayerChatted(plr, msg) end) end end Players.PlayerAdded:Connect(function(plr) if plr ~= localPlayer then plr.Chatted:Connect(function(msg) onPlayerChatted(plr, msg) end) end end) end local function autoMessageLoop() while true do task.wait(1) if tick() - lastMessageTime >= CONFIG.AUTO_INTERVAL then serverChat("20 minutes passed! Use ;protect [name] to get protected. Protected players: say ;unprotect when done.") lastMessageTime = tick() end end end local function onCharacterAdded(char) task.wait(1) if targetPlayer then startFollowing(targetPlayer) end end local function init() if localPlayer.Character then onCharacterAdded(localPlayer.Character) end localPlayer.CharacterAdded:Connect(onCharacterAdded) setupListeners() spawn(autoMessageLoop) serverChat("Ultimate Protector Script Loaded!") serverChat("Commands: ;protect [name] | ;unprotect") end Players.PlayerRemoving:Connect(function(plr) if plr == targetPlayer then stopFollowing() serverChat("Target left. Protection stopped.") end end) UserInputService.InputBegan:Connect(function(inp, gp) if gp then return end if inp.KeyCode == Enum.KeyCode.F then -- STOP PROTECTING MANUALLY! stopFollowing() serverChat("Manual stop (F key)") end end) init()