Alright.
Client code:
local ContextActionService = game:GetService("ContextActionService")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local UserInputService = game:GetService("UserInputService")
local TweenService = game:GetService("TweenService")
local RunService = game:GetService("RunService")
local Players = game:GetService("Players")
local Debris = game:GetService("Debris")
local Background = script.Parent:WaitForChild("Background")
local Modal = Background:WaitForChild("Modal")
local Cursor = ReplicatedStorage:WaitForChild("Cursor")
local PlayerList = Players:GetPlayers()
local Player = Players.LocalPlayer
local Mouse = Player:GetMouse()
local EasingDirection = Enum.EasingDirection
local RenderPriority = Enum.RenderPriority
local UserInputState = Enum.UserInputState
local UserInputType = Enum.UserInputType
local EasingStyle = Enum.EasingStyle
local KeyCode = Enum.KeyCode
local MouseButton1 = UserInputType.MouseButton1
local InputPriority = RenderPriority.Input
local Begin = UserInputState.Begin
local Linear = EasingStyle.Linear
local Out = EasingDirection.Out
local M = KeyCode.M
local insert = table.insert
local remove = table.remove
local find = table.find
local TINew = TweenInfo.new
local INew = Instance.new
local V2New = Vector2.new
local U2New = UDim2.new
local UNew = UDim.new
local atan = math.atan
local sqrt = math.sqrt
local abs = math.abs
local cos = math.cos
local deg = math.deg
local sin = math.sin
local pi = math.pi
local sel = select
local t = tick
local HoldingMouse = false
local Update = .05
local LastTick = t()
local LastPositions = {}
local Easing =
{
Direction = Out;
Style = Linear;
}
local PseudoCursor = INew("TextLabel")
PseudoCursor.Size = U2New(UNew(0, 100), UNew(0, 100))
PseudoCursor.Name = "PseudoCursor"
PseudoCursor.Text = Player.Name
PseudoCursor.Position = U2New()
PseudoCursor.TextScaled = true
local CursorObj = INew("TextLabel")
CursorObj.Size = U2New(UNew(0, 100), UNew(0, 100))
CursorObj.Name = Player.Name
CursorObj.Position = U2New()
CursorObj.Visible = false
PseudoCursor.Parent = script.Parent
CursorObj.Parent = script.Parent
LastPositions[Player.Name] = U2New()
function CreateCursor(vPlayer)
local CursorPlr = INew("TextLabel")
CursorPlr.Size = U2New(UNew(0, 100), UNew(0, 100))
CursorPlr.Name = vPlayer.Name
CursorPlr.Text = vPlayer.Name
CursorPlr.Position = U2New()
CursorPlr.TextScaled = true
CursorPlr.Visible = false
CursorPlr.Parent = script.Parent
LastPositions[vPlayer.Name] = U2New()
end
function DrawLine(OldUD, NewUD)
if OldUD and NewUD then
local OldPos = V2New(OldUD.X.Offset, OldUD.Y.Offset)
local NewPos = V2New(NewUD.X.Offset, NewUD.Y.Offset)
local Grad = (NewPos.Y - OldPos.Y) / (NewPos.X - OldPos.X)
local Dist = (NewPos - OldPos).Magnitude
local SubX = (NewPos.X - OldPos.X)
local SubY = (NewPos.Y - OldPos.Y)
local Slope = SubY / SubX
local RotRad = atan(Slope) * SubY / abs(SubY)
local DrawFrame = INew("Frame")
DrawFrame.Position = U2New(UNew(0, cos(RotRad) * Dist / 2 + OldPos.X - Dist / 2 + 1), UNew(0, sin(RotRad) * Dist / 2 + OldPos.Y))
DrawFrame.Size = U2New(UNew(0, Dist), UNew(0, 10))
DrawFrame.Rotation = atan(Grad) * 180 / pi
DrawFrame.BorderSizePixel = 0
DrawFrame.Parent = Background
Debris:AddItem(DrawFrame, 3.5)
delay(2, function()
local TransparencyTween = TweenService:Create(DrawFrame, TINew(1.5), {BackgroundTransparency = 1})
TransparencyTween:Play()
end)
end
end
function MapToggle(ActionName, InputState, InputObject)
if InputState == Begin then
local NewEnable = not script.Parent.Enabled
script.Parent.Enabled = NewEnable
Modal.Visible = NewEnable
Cursor:FireServer(1, NewEnable)
end
end
ContextActionService:BindAction("MapToggle", MapToggle, true, M)
Mouse.Move:Connect(function()
PseudoCursor.Position = U2New(UNew(0, Mouse.X), UNew(0, Mouse.Y + 37))
end)
UserInputService.InputBegan:Connect(function(Input)
if Input.UserInputType == MouseButton1 then
HoldingMouse = true
end
end)
UserInputService.InputEnded:Connect(function(Input)
if Input.UserInputType == MouseButton1 then
HoldingMouse = false
end
end)
Cursor.OnClientEvent:Connect(function(Type, PlayerName, ...)
local CursorFound = script.Parent:FindFirstChild(PlayerName)
if CursorFound then
if Type == 1 then
local LastPos = sel(2, ...)
local NewPos = sel(1, ...)
CursorFound:TweenPosition(NewPos, Easing.Dir, Easing.Style, Update, true)
LastPositions[PlayerName] = LastPos
else
local LastPos = sel(2, ...)
local NewPos = sel(1, ...)
DrawLine(LastPos, NewPos)
end
end
end)
RunService:BindToRenderStep("MouseMovement", InputPriority.Value, function()
for _,v in pairs(PlayerList) do
if v ~= Player then
local vCursor = script.Parent:FindFirstChild(v.Name)
local MenuOpen = v:FindFirstChild("MenuOpen")
if vCursor and MenuOpen then
vCursor.Visible = MenuOpen.Value
end
end
end
local TickMath = t() - LastTick
if TickMath >= Update and script.Parent.Enabled and LastPositions[Player.Name] ~= PseudoCursor.Position then
--warn(("Update %s"):format(TickMath))
LastPositions[Player.Name] = CursorObj.Position
CursorObj.Position = U2New(UNew(0, Mouse.X), UNew(0, Mouse.Y + 37))
LastTick = t()
local LastPos = LastPositions[Player.Name]
local Pos = CursorObj.Position
Cursor:FireServer(2, Pos, LastPos)
if HoldingMouse then
Cursor:FireServer(3, Pos, LastPos)
end
end
end)
Players.PlayerAdded:Connect(function(vPlayer)
insert(PlayerList, vPlayer)
CreateCursor(vPlayer)
end)
Players.PlayerRemoving:Connect(function(vPlayer)
remove(PlayerList, find(PlayerList, vPlayer))
local vCursor = script.Parent:FindFirstChild(vPlayer.Name)
if vCursor then
vCursor:Destroy()
end
end)
for _,v in pairs(PlayerList) do
if v ~= Player then
CreateCursor(v)
end
end
Server code:
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Players = game:GetService("Players")
local Cursor = ReplicatedStorage:WaitForChild("Cursor")
local PlayerList = Players:GetPlayers()
local insert = table.insert
local remove = table.remove
local find = table.find
local INew = Instance.new
local sel = select
Cursor.OnServerEvent:Connect(function(Player, Type, ...)
if Type == 1 then
local MenuOpen = Player:FindFirstChild("MenuOpen")
if MenuOpen then
MenuOpen.Value = ...
end
elseif Type == 2 then
for _,v in pairs(PlayerList) do
if v ~= Player then
local MenuOpen = v:FindFirstChild("MenuOpen")
if MenuOpen and MenuOpen.Value == true then
local NewPos = sel(1, ...)
local OldPos = sel(2, ...)
Cursor:FireClient(v, 1, Player.Name, NewPos, OldPos)
end
end
end
elseif Type == 3 then
for _,v in pairs(PlayerList) do
local MenuOpen = v:FindFirstChild("MenuOpen")
if MenuOpen and MenuOpen.Value == true then
local NewPos = sel(1, ...)
local OldPos = sel(2, ...)
Cursor:FireClient(v, 2, Player.Name, NewPos, OldPos)
end
end
end
end)
Players.PlayerAdded:Connect(function(Player)
insert(PlayerList, Player)
local MenuOpen = INew("BoolValue")
MenuOpen.Archivable = false
MenuOpen.Name = "MenuOpen"
MenuOpen.Value = false
MenuOpen.Parent = Player
end)
Players.PlayerRemoving:Connect(function(Player)
remove(PlayerList, find(PlayerList, Player))
end)