Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- -- server position shower from client
- -- i recommend using it 3-5 times and getting a ms that isnt constantly changing
- -- for example 500 and then 502 or 550 on the next test is fine but 500 to 600 or 400 is bad
- local Players = game:GetService("Players")
- local RunService = game:GetService("RunService")
- local TweenService = game:GetService("TweenService")
- local UserInputService = game:GetService("UserInputService")
- local Stats = game:GetService("Stats")
- local CoreGui = game:GetService("CoreGui")
- local LocalPlayer = Players.LocalPlayer
- local mouse = LocalPlayer:GetMouse()
- -- Variables
- local showingGhost = false
- local ghostClone = nil
- local positionHistory = {} -- Stores past positions and timestamps
- local baseDelayOffset = 0 -- Manual delay offset (seconds)
- local calculatedPhysicsPing = 0 -- Total round-trip from the tool
- -- GUI Setup
- local ScreenGui = Instance.new("ScreenGui")
- ScreenGui.Name = "ServerGhostGUI"
- ScreenGui.ResetOnSpawn = false
- local success, uiParent = pcall(function() return gethui() or CoreGui end)
- if not success then uiParent = LocalPlayer:WaitForChild("PlayerGui") end
- ScreenGui.Parent = uiParent
- local MainFrame = Instance.new("Frame")
- MainFrame.Size = UDim2.new(0, 200, 0, 190)
- MainFrame.Position = UDim2.new(0.5, -100, 0.5, -95)
- MainFrame.BackgroundColor3 = Color3.fromRGB(35, 35, 35)
- MainFrame.BorderSizePixel = 0
- MainFrame.Parent = ScreenGui
- local UICorner = Instance.new("UICorner")
- UICorner.CornerRadius = UDim.new(0, 8)
- UICorner.Parent = MainFrame
- local Title = Instance.new("TextLabel")
- Title.Size = UDim2.new(1, 0, 0, 30)
- Title.BackgroundTransparency = 1
- Title.Text = "Server Ghost"
- Title.TextColor3 = Color3.fromRGB(255, 255, 255)
- Title.Font = Enum.Font.GothamBold
- Title.TextSize = 14
- Title.Parent = MainFrame
- -- Delay Offset Input
- local DelayBox = Instance.new("TextBox")
- DelayBox.Size = UDim2.new(0.9, 0, 0, 30)
- DelayBox.Position = UDim2.new(0.05, 0, 0, 40)
- DelayBox.BackgroundColor3 = Color3.fromRGB(50, 50, 50)
- DelayBox.TextColor3 = Color3.fromRGB(255, 255, 255)
- DelayBox.PlaceholderText = "Manual Offset (e.g. 0)"
- DelayBox.Text = "0"
- DelayBox.Font = Enum.Font.Gotham
- DelayBox.TextSize = 14
- DelayBox.Parent = MainFrame
- -- Ghost Toggle Button
- local GhostButton = Instance.new("TextButton")
- GhostButton.Size = UDim2.new(0.9, 0, 0, 35)
- GhostButton.Position = UDim2.new(0.05, 0, 0, 85)
- GhostButton.BackgroundColor3 = Color3.fromRGB(0, 150, 255)
- GhostButton.TextColor3 = Color3.fromRGB(255, 255, 255)
- GhostButton.Text = "Show Server Ghost"
- GhostButton.Font = Enum.Font.GothamBold
- GhostButton.TextSize = 14
- GhostButton.Parent = MainFrame
- -- Ping Checker Button
- local PingButton = Instance.new("TextButton")
- PingButton.Size = UDim2.new(0.9, 0, 0, 35)
- PingButton.Position = UDim2.new(0.05, 0, 0, 135)
- PingButton.BackgroundColor3 = Color3.fromRGB(255, 100, 100)
- PingButton.TextColor3 = Color3.fromRGB(255, 255, 255)
- PingButton.Text = "Get Ping Tool"
- PingButton.Font = Enum.Font.GothamBold
- PingButton.TextSize = 14
- PingButton.Parent = MainFrame
- -- Make GUI Draggable
- local dragging, dragInput, dragStart, startPos
- MainFrame.InputBegan:Connect(function(input)
- if input.UserInputType == Enum.UserInputType.MouseButton1 then
- dragging = true
- dragStart = input.Position
- startPos = MainFrame.Position
- input.Changed:Connect(function()
- if input.UserInputState == Enum.UserInputState.End then dragging = false end
- end)
- end
- end)
- MainFrame.InputChanged:Connect(function(input)
- if input.UserInputType == Enum.UserInputType.MouseMovement then dragInput = input end
- end)
- UserInputService.InputChanged:Connect(function(input)
- if input == dragInput and dragging then
- local delta = input.Position - dragStart
- MainFrame.Position = UDim2.new(startPos.X.Scale, startPos.X.Offset + delta.X, startPos.Y.Scale, startPos.Y.Offset + delta.Y)
- end
- end)
- -- Update Offset manually
- DelayBox.FocusLost:Connect(function()
- local val = tonumber(DelayBox.Text)
- if val then
- baseDelayOffset = val
- else
- DelayBox.Text = tostring(baseDelayOffset)
- end
- end)
- -- Safely get Network Ping actively
- local function getNetworkPing()
- local activePing = 0
- local success, result = pcall(function()
- local label = CoreGui.RobloxGui.PerformanceStats:GetChildren()[6].StatsMiniTextPanelClass.ValueLabel
- return label.Text
- end)
- if success and type(result) == "string" then
- local numStr = string.match(result, "[%d%.]+")
- if numStr then return tonumber(numStr) end
- end
- local statSuccess, statResult = pcall(function()
- return Stats.Network.ServerStatsItem["Data Ping"]:GetValue()
- end)
- if statSuccess and type(statResult) == "number" then
- return statResult
- end
- return activePing
- end
- -- Create Ghost Function
- local function createGhost()
- if ghostClone then ghostClone:Destroy() end
- local char = LocalPlayer.Character
- if not char then return end
- char.Archivable = true
- local clone = char:Clone()
- char.Archivable = false
- clone.Name = "ServerGhost"
- -- Fixes the sinking bug by explicitly locking the center of the model to the HRP
- clone.PrimaryPart = clone:FindFirstChild("HumanoidRootPart")
- for _, v in ipairs(clone:GetDescendants()) do
- if v:IsA("Script") or v:IsA("LocalScript") then
- v:Destroy()
- elseif v:IsA("BasePart") then
- -- Strip completely of physics
- v.CanCollide = false
- v.CanTouch = false
- v.CanQuery = false
- v.Massless = true
- v.Anchored = true
- v.Material = Enum.Material.ForceField
- v.Color = Color3.fromRGB(0, 255, 255) -- Cyan color
- v.CastShadow = false
- if v.Name == "HumanoidRootPart" then
- v.Transparency = 1
- else
- v.Transparency = 0
- end
- elseif v:IsA("Decal") or v:IsA("Texture") then
- v:Destroy()
- end
- end
- -- Paralyze the ghost's Humanoid so it doesn't force collision states
- local hum = clone:FindFirstChild("Humanoid")
- if hum then
- hum.DisplayDistanceType = Enum.HumanoidDisplayDistanceType.None
- hum.HealthDisplayType = Enum.HumanoidHealthDisplayType.AlwaysOff
- hum.PlatformStand = true
- for _, state in pairs(Enum.HumanoidStateType:GetEnumItems()) do
- pcall(function() hum:SetStateEnabled(state, false) end)
- end
- end
- clone.Parent = workspace
- ghostClone = clone
- end
- -- Toggle Logic
- GhostButton.MouseButton1Click:Connect(function()
- showingGhost = not showingGhost
- if showingGhost then
- createGhost()
- GhostButton.Text = "Hide Server Ghost"
- GhostButton.BackgroundColor3 = Color3.fromRGB(255, 50, 50)
- else
- if ghostClone then
- ghostClone:Destroy()
- ghostClone = nil
- end
- GhostButton.Text = "Show Server Ghost"
- GhostButton.BackgroundColor3 = Color3.fromRGB(0, 150, 255)
- Title.Text = "Server Ghost"
- end
- end)
- -- Re-create ghost if character respawns while enabled
- LocalPlayer.CharacterAdded:Connect(function()
- positionHistory = {} -- clear history
- if showingGhost then
- task.wait(0.5)
- createGhost()
- end
- end)
- -- Loop: Record History & Update Ghost
- RunService.Heartbeat:Connect(function()
- local char = LocalPlayer.Character
- local hrp = char and char:FindFirstChild("HumanoidRootPart")
- if not hrp then return end
- -- 1. Log Current Position
- table.insert(positionHistory, {
- t = os.clock(),
- cf = hrp.CFrame
- })
- -- 2. Clean up history older than 3 seconds (prevent memory leaks)
- while #positionHistory > 0 and (os.clock() - positionHistory[1].t) > 3 do
- table.remove(positionHistory, 1)
- end
- -- 3. Update Ghost if toggled
- if showingGhost and ghostClone and ghostClone.PrimaryPart then
- -- OVERRIDE ENFORCER: Absolutely ensure Roblox didn't turn collisions back on
- for _, v in ipairs(ghostClone:GetDescendants()) do
- if v:IsA("BasePart") and v.CanCollide then
- v.CanCollide = false
- end
- end
- local currentNetPing = getNetworkPing()
- local delayMs = currentNetPing -- Default to raw network ping
- -- Use our Physics test minus Network ping if available
- if calculatedPhysicsPing > 0 then
- delayMs = math.max(0, calculatedPhysicsPing - currentNetPing)
- end
- Title.Text = string.format("Delaying by %dms", delayMs)
- -- Target time we want to show (current time minus delay)
- local targetDelaySeconds = (delayMs / 1000) + baseDelayOffset
- local targetTime = os.clock() - targetDelaySeconds
- local targetCFrame = hrp.CFrame
- -- Interpolate to find exact CFrame in the past
- if #positionHistory >= 2 then
- for i = #positionHistory, 2, -1 do
- local current = positionHistory[i]
- local previous = positionHistory[i-1]
- if current.t >= targetTime and previous.t <= targetTime then
- local alpha = (targetTime - previous.t) / (current.t - previous.t)
- targetCFrame = previous.cf:Lerp(current.cf, alpha)
- break
- elseif i == 2 and targetTime < previous.t then
- targetCFrame = previous.cf
- end
- end
- end
- -- Pivot directly to the calculated CFrame (safe from ground-sinking due to PrimaryPart lock)
- ghostClone:PivotTo(targetCFrame)
- end
- end)
- -- Ping Checker Script Implementation
- PingButton.MouseButton1Click:Connect(function()
- if LocalPlayer.Backpack:FindFirstChild("PingCheck") then
- PingButton.Text = "Already have Tool!"
- task.wait(1)
- PingButton.Text = "Get Ping Tool"
- return
- end
- local tool = Instance.new("Tool")
- tool.Name = "PingCheck"
- tool.RequiresHandle = false
- tool.Parent = LocalPlayer.Backpack
- local function getHRP(p)
- local c = p and p.Character
- return c and c:FindFirstChild("HumanoidRootPart")
- end
- local function noCollide(c)
- for _, d in ipairs(c:GetDescendants()) do
- if d:IsA("BasePart") then d.CanCollide = false end
- end
- end
- local function slide(part, goal, dur)
- local tw = TweenService:Create(part, TweenInfo.new(dur, Enum.EasingStyle.Linear), { CFrame = goal })
- tw:Play()
- tw.Completed:Wait()
- end
- local function run(target)
- local th = getHRP(target)
- local mh = getHRP(LocalPlayer)
- if not th or not mh then return end
- noCollide(LocalPlayer.Character)
- task.wait(0.2)
- local last = th.Position
- local still = 0
- while still < 30 do
- RunService.Heartbeat:Wait()
- th = getHRP(target) or th
- local p = th.Position
- if (p - last).Magnitude > 0.15 then still = 0 else still += 1 end
- last = p
- end
- mh = getHRP(LocalPlayer) or mh
- th = getHRP(target) or th
- slide(mh, th.CFrame * CFrame.new(0, 0, 10), 1.2)
- task.wait(0.5)
- local t0 = nil
- local p0 = nil
- local moved = false
- local ms = 0
- local done = false
- local endT = nil
- task.spawn(function()
- local m = getHRP(LocalPlayer) or mh
- local t = getHRP(target) or th
- slide(m, t.CFrame * CFrame.new(0, 0, -10), 1.2)
- done = true
- endT = os.clock()
- end)
- while not moved do
- RunService.Heartbeat:Wait()
- mh = getHRP(LocalPlayer) or mh
- th = getHRP(target) or th
- if not t0 then
- if (mh.Position - th.Position).Magnitude <= 3 then
- t0 = os.clock()
- p0 = th.Position
- elseif done and endT and (os.clock() - endT) > 5 then
- break
- end
- else
- ms = (os.clock() - t0) * 1000
- if (th.Position - p0).Magnitude > 0.05 then
- moved = true
- elseif ms > 5000 then
- break
- end
- end
- end
- if moved then
- print(string.format("Calculated Physics Ping: %.6f ms", ms))
- -- Sync it with the ghost script
- calculatedPhysicsPing = ms
- end
- end
- tool.Activated:Connect(function()
- local hit = mouse.Target
- if not hit then return end
- local model = hit:FindFirstAncestorOfClass("Model")
- if not model then return end
- local plr = Players:GetPlayerFromCharacter(model)
- if plr and plr ~= LocalPlayer then
- run(plr)
- end
- end)
- PingButton.Text = "Tool Given!"
- task.wait(1)
- PingButton.Text = "Get Ping Tool"
- end)
Advertisement
Add Comment
Please, Sign In to add comment