-- [[ Rscripts Risk Notice ]] -- This script is not verified by rscripts.net. Deal with caution. -- -- Stay safe: -- • Never log in on unofficial Roblox sites or lookalike domains. -- • Real Roblox links use roblox.com (check the .com ending). -- • Treat fake Roblox login / "claim reward" pages as phishing. -- [[ End Rscripts Risk Notice ]] local ReplicatedFirst = game:GetService("ReplicatedFirst") local CustomMeshCharacter = require(ReplicatedFirst.GunSystemPlugins.CustomMeshCharacter) local LocalFriendlyService = require(ReplicatedFirst.Core.Services.LocalFriendlyService) local Enemy = {} Enemy.__index = Enemy function Enemy.new(player, char) local self = setmetatable({}, Enemy) self.Player = player self.Character = char return self end local function GetEnemyTargets() local result = {} local enemies = LocalFriendlyService:GetEnemyPlayers() for _, player in enemies do if player:GetAttribute("Dead") then continue end local char = CustomMeshCharacter:GetWorldCharacterFromPlayer(player) if not char then continue end table.insert(result, Enemy.new(player, char)) end return result end local ESP = { Config = { ZIndex = 2, Enabled = true, ShowBoxes = true, BoxThickness = 1, FontSize = 12, BoxColor = Color3.new(1, 1, 1), ToolIconSize = 16 }, Callbacks = { getPartsToRenderCallback = nil, }, _activeObjects = {}, _drawingObjects = {}, _cache = { parts = {}, lastUpdate = 0, updateInterval = 0.1 }, _connections = {} } if DrawingImmediate then function ESP:WorldToScreen(worldPosition) local camera = workspace.CurrentCamera; if not camera then return nil end; local vector, onScreen = camera:WorldToViewportPoint(worldPosition) if onScreen and vector.Z > 0 then return Vector2.new(vector.X, vector.Y), vector.Z end; return nil, nil end; function ESP:GetPartBoxSize(part) if not part then return 2, 2 end local camera = workspace.CurrentCamera if not camera then return 2, 2 end local partPosition if part:IsA("BasePart") then partPosition = part.Position elseif part:IsA("Model") then partPosition = part:GetPivot().Position else return 2, 2 end local distance = (camera.CFrame.Position - partPosition).Magnitude if distance <= 0 then return 2, 2 end local height = (camera.ViewportSize.Y / distance) * (4 / math.tan(math.rad(camera.FieldOfView * 0.5))) return height * 0.4, height end function ESP:DrawBox(part, screenPos, boxWidth, boxHeight) if not self.Config.ShowBoxes then return end; local topLeft = Vector2.new(screenPos.X - (boxWidth / 2), screenPos.Y - boxHeight) local boxColor = self.Config.BoxColor; DrawingImmediate.Rectangle(topLeft, Vector2.new(boxWidth, boxHeight), boxColor, 1, 0, self.Config.BoxThickness) local accentSize = math.min(10, boxWidth * 0.2) local accentColor = Color3.new(1, 1, 1) DrawingImmediate.Line(topLeft, Vector2.new(topLeft.X + accentSize, topLeft.Y), accentColor, 0.8, 2) DrawingImmediate.Line(topLeft, Vector2.new(topLeft.X, topLeft.Y + accentSize), accentColor, 0.8, 2) local topRight = Vector2.new(topLeft.X + boxWidth, topLeft.Y) DrawingImmediate.Line(Vector2.new(topRight.X - accentSize, topRight.Y), topRight, accentColor, 0.8, 2) DrawingImmediate.Line(topRight, Vector2.new(topRight.X, topRight.Y + accentSize), accentColor, 0.8, 2) local bottomLeft = Vector2.new(topLeft.X, topLeft.Y + boxHeight) DrawingImmediate.Line(bottomLeft, Vector2.new(bottomLeft.X + accentSize, bottomLeft.Y), accentColor, 0.8, 2) DrawingImmediate.Line(bottomLeft, Vector2.new(bottomLeft.X, bottomLeft.Y - accentSize), accentColor, 0.8, 2) local bottomRight = Vector2.new(topLeft.X + boxWidth, topLeft.Y + boxHeight) DrawingImmediate.Line(Vector2.new(bottomRight.X - accentSize, bottomRight.Y), bottomRight, accentColor, 0.8, 2) DrawingImmediate.Line(bottomRight, Vector2.new(bottomRight.X, bottomRight.Y - accentSize), accentColor, 0.8, 2) end; function ESP:_UpdateCache() local currentTime = tick() if currentTime - self._cache.lastUpdate < self._cache.updateInterval then return end; self._cache.lastUpdate = currentTime; self._cache.parts = {} if self.Callbacks.getPartsToRenderCallback then local parts = self.Callbacks.getPartsToRenderCallback() if parts then for i, part in ipairs(parts) do self._cache.parts[#self._cache.parts + 1] = part; end end end end; function ESP:_OnRender() if not self.Config.Enabled then return end; self:_UpdateCache() for _, part in ipairs(self._cache.parts) do if part and part.Parent then local partPosition if part:IsA("BasePart") then partPosition = part.Position elseif part:IsA("Model") then partPosition = part:GetPivot().Position end local screenPos = self:WorldToScreen(partPosition) if screenPos then local w, h = self:GetPartBoxSize(part) self:DrawBox(part, screenPos, w, h) end end end; for _, obj in ipairs(self._activeObjects) do if obj.type == "circle" and obj.position then local screenPos = self:WorldToScreen(obj.position) if screenPos then DrawingImmediate.Circle(screenPos, obj.radius, obj.color, 1, 32, 2) end elseif obj.type == "line" and obj.from and obj.to then local fromScreen = self:WorldToScreen(obj.from) local toScreen = self:WorldToScreen(obj.to) if fromScreen and toScreen then DrawingImmediate.Line(fromScreen, toScreen, obj.color, 1, obj.thickness or 1) end end end end; function ESP:SetGetPartsToRenderCallback(callback) self.Callbacks.getPartsToRenderCallback = callback end; function ESP:AddObject(object) self._activeObjects[#self._activeObjects + 1] = object; return object end; function ESP:RemoveObject(object) for i, obj in ipairs(self._activeObjects) do if obj == object then table.remove(self._activeObjects, i) break end end end; function ESP:ClearObjects() self._activeObjects = {} end; function ESP:SetConfig(newConfig) for k, v in pairs(newConfig) do self.Config[k] = v end end; function ESP:Toggle() self.Config.Enabled = not self.Config.Enabled; return self.Config.Enabled end; function ESP:Init() if self._signal then self:_Cleanup() end; self._signal = DrawingImmediate.GetPaint(self.Config.ZIndex) local connection = self._signal:Connect(function() self:_OnRender() end) self._connections[#self._connections + 1] = connection end; function ESP:_Cleanup() for _, conn in ipairs(self._connections) do conn:Disconnect() end; self._connections = {} self._signal = nil end; function ESP:Destroy() self:_Cleanup() self._activeObjects = {} self:ClearCallbacks() self._cache = { parts = {}, lastUpdate = 0, updateInterval = 0.1 } end; function ESP:ForceUpdate() self._cache.lastUpdate = 0; self:_UpdateCache() end else if not Drawing then local drawingUI = Instance.new("ScreenGui", game:GetService("CoreGui")) drawingUI.Name = "Drawing" drawingUI.IgnoreGuiInset = true drawingUI.DisplayOrder = 0x7fffffff local drawingIndex = 0 local baseDrawingObj = setmetatable({ Visible = true, ZIndex = 0, Transparency = 1, Color = Color3.new(), Remove = function(self) setmetatable(self, nil) end, Destroy = function(self) setmetatable(self, nil) end }, { __add = function(t1, t2) local result = table.clone(t1) for index, value in t2 do result[index] = value end return result end }) local drawingFontsEnum = { [0] = Font.fromEnum(Enum.Font.Roboto), [1] = Font.fromEnum(Enum.Font.Legacy), [2] = Font.fromEnum(Enum.Font.SourceSans), [3] = Font.fromEnum(Enum.Font.RobotoMono), } local function convertTransparency(transparency) return math.clamp(1 - transparency, 0, 1) end local DrawingLib = {} DrawingLib.Fonts = { ["UI"] = 0, ["System"] = 1, ["Plex"] = 2, ["Monospace"] = 3 } function DrawingLib.new(drawingType) drawingIndex += 1 if drawingType == "Line" then local lineObj = ({ From = Vector2.zero, To = Vector2.zero, Thickness = 1 } + baseDrawingObj) local lineFrame = Instance.new("Frame") lineFrame.Name = drawingIndex lineFrame.AnchorPoint = (Vector2.one * .5) lineFrame.BorderSizePixel = 0 lineFrame.BackgroundColor3 = lineObj.Color lineFrame.Visible = lineObj.Visible lineFrame.ZIndex = lineObj.ZIndex lineFrame.BackgroundTransparency = convertTransparency(lineObj.Transparency) lineFrame.Size = UDim2.new() lineFrame.Parent = drawingUI return setmetatable({__type = "Drawing Object"}, { __newindex = function(_, index, value) if typeof(lineObj[index]) == "nil" then return end if index == "From" then local direction = (lineObj.To - value) local center = (lineObj.To + value) / 2 local distance = direction.Magnitude local theta = math.deg(math.atan2(direction.Y, direction.X)) lineFrame.Position = UDim2.fromOffset(center.X, center.Y) lineFrame.Rotation = theta lineFrame.Size = UDim2.fromOffset(distance, lineObj.Thickness) elseif index == "To" then local direction = (value - lineObj.From) local center = (value + lineObj.From) / 2 local distance = direction.Magnitude local theta = math.deg(math.atan2(direction.Y, direction.X)) lineFrame.Position = UDim2.fromOffset(center.X, center.Y) lineFrame.Rotation = theta lineFrame.Size = UDim2.fromOffset(distance, lineObj.Thickness) elseif index == "Thickness" then local distance = (lineObj.To - lineObj.From).Magnitude lineFrame.Size = UDim2.fromOffset(distance, value) elseif index == "Visible" then lineFrame.Visible = value elseif index == "ZIndex" then lineFrame.ZIndex = value elseif index == "Transparency" then lineFrame.BackgroundTransparency = convertTransparency(value) elseif index == "Color" then lineFrame.BackgroundColor3 = value end lineObj[index] = value end, __index = function(self, index) if index == "Remove" or index == "Destroy" then return function() lineFrame:Destroy() lineObj.Remove(self) return lineObj:Remove() end end return lineObj[index] end, __tostring = function() return "Drawing" end }) elseif drawingType == "Text" then local textObj = ({ Text = "", Font = DrawingLib.Fonts.UI, Size = 0, Position = Vector2.zero, Center = false, Outline = false, OutlineColor = Color3.new() } + baseDrawingObj) local textLabel, uiStroke = Instance.new("TextLabel"), Instance.new("UIStroke") textLabel.Name = drawingIndex textLabel.AnchorPoint = (Vector2.one * .5) textLabel.BorderSizePixel = 0 textLabel.BackgroundTransparency = 1 textLabel.Visible = textObj.Visible textLabel.TextColor3 = textObj.Color textLabel.TextTransparency = convertTransparency(textObj.Transparency) textLabel.ZIndex = textObj.ZIndex textLabel.FontFace = drawingFontsEnum[textObj.Font] textLabel.TextSize = textObj.Size textLabel:GetPropertyChangedSignal("TextBounds"):Connect(function() local textBounds = textLabel.TextBounds local offset = textBounds / 2 textLabel.Size = UDim2.fromOffset(textBounds.X, textBounds.Y) textLabel.Position = UDim2.fromOffset(textObj.Position.X + (if not textObj.Center then offset.X else 0), textObj.Position.Y + offset.Y) end) uiStroke.Thickness = 1 uiStroke.Enabled = textObj.Outline uiStroke.Color = textObj.Color textLabel.Parent, uiStroke.Parent = drawingUI, textLabel return setmetatable({__type = "Drawing Object"}, { __newindex = function(_, index, value) if typeof(textObj[index]) == "nil" then return end if index == "Text" then textLabel.Text = value elseif index == "Font" then value = math.clamp(value, 0, 3) textLabel.FontFace = drawingFontsEnum[value] elseif index == "Size" then textLabel.TextSize = value elseif index == "Position" then local offset = textLabel.TextBounds / 2 textLabel.Position = UDim2.fromOffset(value.X + (if not textObj.Center then offset.X else 0), value.Y + offset.Y) elseif index == "Center" then local position = ( if value then workspace.CurrentCamera.ViewportSize / 2 else textObj.Position ) textLabel.Position = UDim2.fromOffset(position.X, position.Y) elseif index == "Outline" then uiStroke.Enabled = value elseif index == "OutlineColor" then uiStroke.Color = value elseif index == "Visible" then textLabel.Visible = value elseif index == "ZIndex" then textLabel.ZIndex = value elseif index == "Transparency" then local transparency = convertTransparency(value) textLabel.TextTransparency = transparency uiStroke.Transparency = transparency elseif index == "Color" then textLabel.TextColor3 = value end textObj[index] = value end, __index = function(self, index) if index == "Remove" or index == "Destroy" then return function() textLabel:Destroy() textObj.Remove(self) return textObj:Remove() end elseif index == "TextBounds" then return textLabel.TextBounds end return textObj[index] end, __tostring = function() return "Drawing" end }) elseif drawingType == "Circle" then local circleObj = ({ Radius = 150, Position = Vector2.zero, Thickness = .7, Filled = false } + baseDrawingObj) local circleFrame, uiCorner, uiStroke = Instance.new("Frame"), Instance.new("UICorner"), Instance.new("UIStroke") circleFrame.Name = drawingIndex circleFrame.AnchorPoint = (Vector2.one * .5) circleFrame.BorderSizePixel = 0 circleFrame.BackgroundTransparency = (if circleObj.Filled then convertTransparency(circleObj.Transparency) else 1) circleFrame.BackgroundColor3 = circleObj.Color circleFrame.Visible = circleObj.Visible circleFrame.ZIndex = circleObj.ZIndex uiCorner.CornerRadius = UDim.new(1, 0) circleFrame.Size = UDim2.fromOffset(circleObj.Radius, circleObj.Radius) uiStroke.Thickness = circleObj.Thickness uiStroke.Enabled = not circleObj.Filled uiStroke.ApplyStrokeMode = Enum.ApplyStrokeMode.Border circleFrame.Parent, uiCorner.Parent, uiStroke.Parent = drawingUI, circleFrame, circleFrame return setmetatable({__type = "Drawing Object"}, { __newindex = function(_, index, value) if typeof(circleObj[index]) == "nil" then return end if index == "Radius" then local radius = value * 2 circleFrame.Size = UDim2.fromOffset(radius, radius) elseif index == "Position" then circleFrame.Position = UDim2.fromOffset(value.X, value.Y) elseif index == "Thickness" then value = math.clamp(value, .6, 0x7fffffff) uiStroke.Thickness = value elseif index == "Filled" then circleFrame.BackgroundTransparency = (if value then convertTransparency(circleObj.Transparency) else 1) uiStroke.Enabled = not value elseif index == "Visible" then circleFrame.Visible = value elseif index == "ZIndex" then circleFrame.ZIndex = value elseif index == "Transparency" then local transparency = convertTransparency(value) circleFrame.BackgroundTransparency = (if circleObj.Filled then transparency else 1) uiStroke.Transparency = transparency elseif index == "Color" then circleFrame.BackgroundColor3 = value uiStroke.Color = value end circleObj[index] = value end, __index = function(self, index) if index == "Remove" or index == "Destroy" then return function() circleFrame:Destroy() circleObj.Remove(self) return circleObj:Remove() end end return circleObj[index] end, __tostring = function() return "Drawing" end }) elseif drawingType == "Square" then local squareObj = ({ Size = Vector2.zero, Position = Vector2.zero, Thickness = .7, Filled = false } + baseDrawingObj) local squareFrame, uiStroke = Instance.new("Frame"), Instance.new("UIStroke") squareFrame.Name = drawingIndex squareFrame.BorderSizePixel = 0 squareFrame.BackgroundTransparency = (if squareObj.Filled then convertTransparency(squareObj.Transparency) else 1) squareFrame.ZIndex = squareObj.ZIndex squareFrame.BackgroundColor3 = squareObj.Color squareFrame.Visible = squareObj.Visible uiStroke.Thickness = squareObj.Thickness uiStroke.Enabled = not squareObj.Filled uiStroke.LineJoinMode = Enum.LineJoinMode.Miter squareFrame.Parent, uiStroke.Parent = drawingUI, squareFrame return setmetatable({__type = "Drawing Object"}, { __newindex = function(_, index, value) if typeof(squareObj[index]) == "nil" then return end if index == "Size" then squareFrame.Size = UDim2.fromOffset(value.X, value.Y) elseif index == "Position" then squareFrame.Position = UDim2.fromOffset(value.X, value.Y) elseif index == "Thickness" then value = math.clamp(value, 0.6, 0x7fffffff) uiStroke.Thickness = value elseif index == "Filled" then squareFrame.BackgroundTransparency = (if value then convertTransparency(squareObj.Transparency) else 1) uiStroke.Enabled = not value elseif index == "Visible" then squareFrame.Visible = value elseif index == "ZIndex" then squareFrame.ZIndex = value elseif index == "Transparency" then local transparency = convertTransparency(value) squareFrame.BackgroundTransparency = (if squareObj.Filled then transparency else 1) uiStroke.Transparency = transparency elseif index == "Color" then uiStroke.Color = value squareFrame.BackgroundColor3 = value end squareObj[index] = value end, __index = function(self, index) if index == "Remove" or index == "Destroy" then return function() squareFrame:Destroy() squareObj.Remove(self) return squareObj:Remove() end end return squareObj[index] end, __tostring = function() return "Drawing" end }) elseif drawingType == "Image" then local imageObj = ({ Data = "", Size = Vector2.zero, Position = Vector2.zero } + baseDrawingObj) local imageFrame = Instance.new("ImageLabel") imageFrame.Name = drawingIndex imageFrame.BorderSizePixel = 0 imageFrame.ScaleType = Enum.ScaleType.Stretch imageFrame.BackgroundTransparency = 1 imageFrame.Visible = imageObj.Visible imageFrame.ZIndex = imageObj.ZIndex imageFrame.ImageTransparency = convertTransparency(imageObj.Transparency) imageFrame.ImageColor3 = imageObj.Color imageFrame.Parent = drawingUI return setmetatable({__type = "Drawing Object"}, { __newindex = function(_, index, value) if typeof(imageObj[index]) == "nil" then return end if index == "Data" then imageFrame.Image = value elseif index == "Size" then imageFrame.Size = UDim2.fromOffset(value.X, value.Y) elseif index == "Position" then imageFrame.Position = UDim2.fromOffset(value.X, value.Y) elseif index == "Visible" then imageFrame.Visible = value elseif index == "ZIndex" then imageFrame.ZIndex = value elseif index == "Transparency" then imageFrame.ImageTransparency = convertTransparency(value) elseif index == "Color" then imageFrame.ImageColor3 = value end imageObj[index] = value end, __index = function(self, index) if index == "Remove" or index == "Destroy" then return function() imageFrame:Destroy() imageObj.Remove(self) return imageObj:Remove() end end return imageObj[index] end, __tostring = function() return "Drawing" end }) elseif drawingType == "Quad" then local QuadProperties = ({ Thickness = 1, PointA = Vector2.new(); PointB = Vector2.new(); PointC = Vector2.new(); PointD = Vector2.new(); Filled = false; } + baseDrawingObj) local PointA = DrawingLib.new("Line") local PointB = DrawingLib.new("Line") local PointC = DrawingLib.new("Line") local PointD = DrawingLib.new("Line") return setmetatable({__type = "Drawing Object"}, { __newindex = function(self, Property, Value) if Property == "Thickness" then PointA.Thickness = Value PointB.Thickness = Value PointC.Thickness = Value PointD.Thickness = Value end if Property == "PointA" then PointA.From = Value PointB.To = Value end if Property == "PointB" then PointB.From = Value PointC.To = Value end if Property == "PointC" then PointC.From = Value PointD.To = Value end if Property == "PointD" then PointD.From = Value PointA.To = Value end if Property == "Visible" then PointA.Visible = true PointB.Visible = true PointC.Visible = true PointD.Visible = true end if Property == "Filled" then PointA.BackgroundTransparency = 1 PointB.BackgroundTransparency = 1 PointC.BackgroundTransparency = 1 PointD.BackgroundTransparency = 1 end if Property == "Color" then PointA.Color = Value PointB.Color = Value PointC.Color = Value PointD.Color = Value end if (Property == "ZIndex") then PointA.ZIndex = Value PointB.ZIndex = Value PointC.ZIndex = Value PointD.ZIndex = Value end end, __index = function(self, Property) if (string.lower(tostring(Property)) == "remove") then return (function() PointA:Remove(); PointB:Remove(); PointC:Remove(); PointD:Remove(); end) end return QuadProperties[Property] end }); elseif drawingType == "Triangle" then local triangleObj = ({ PointA = Vector2.zero, PointB = Vector2.zero, PointC = Vector2.zero, Thickness = 1, Filled = false } + baseDrawingObj) local _linePoints = {} _linePoints.A = DrawingLib.new("Line") _linePoints.B = DrawingLib.new("Line") _linePoints.C = DrawingLib.new("Line") return setmetatable({__type = "Drawing Object"}, { __tostring = function() return "Drawing" end, __newindex = function(_, index, value) if typeof(triangleObj[index]) == "nil" then return end if index == "PointA" then _linePoints.A.From = value _linePoints.B.To = value elseif index == "PointB" then _linePoints.B.From = value _linePoints.C.To = value elseif index == "PointC" then _linePoints.C.From = value _linePoints.A.To = value elseif (index == "Thickness" or index == "Visible" or index == "Color" or index == "ZIndex") then for _, linePoint in _linePoints do linePoint[index] = value end elseif index == "Filled" then _linePoints.BackgroundTransparency = 1 end triangleObj[index] = value end, __index = function(self, index) if index == "Remove" or index == "Destroy" then return function() for _, linePoint in _linePoints do linePoint:Remove() end triangleObj.Remove(self) return triangleObj:Remove() end end return triangleObj[index] end }) end end if not getgenv then getfenv().getgenv = function() return getfenv(3) or getfenv(2) end end local isrenderobj = function(obj) local s, r = pcall(function() return obj.__type == "Drawing Object" end) return s and r end getgenv().isrenderobj = isrenderobj getgenv().cleardrawcache = function() drawingUI:ClearAllChildren() end getgenv().getrenderproperty = function(obj, prop) assert(isrenderobj(obj), "Object must be a Drawing", 3) return obj[prop] end getgenv().setrenderproperty = function(obj, prop, val) assert(isrenderobj(obj), "Object must be a Drawing", 3) obj[prop] = val end getgenv().Drawing = DrawingLib end function ESP:WorldToScreen(worldPosition) local camera = workspace.CurrentCamera; if not camera then return nil end; local vector, onScreen = camera:WorldToViewportPoint(worldPosition) if onScreen and vector.Z > 0 then return Vector2.new(vector.X, vector.Y), vector.Z end; return nil, nil end; function ESP:GetPartBoxSize(part) if not part then return 2, 2 end local camera = workspace.CurrentCamera if not camera then return 2, 2 end local partPosition if part:IsA("BasePart") then partPosition = part.Position elseif part:IsA("Model") then partPosition = part:GetPivot().Position else return 2, 2 end local distance = (camera.CFrame.Position - partPosition).Magnitude if distance <= 0 then return 2, 2 end local height = (camera.ViewportSize.Y / distance) * (6 / math.tan(math.rad(camera.FieldOfView * 0.5))) return height * 0.4, height end function ESP:_CreateDrawingObject(type, properties) local obj = Drawing.new(type) for k, v in pairs(properties) do obj[k] = v end; obj.Visible = true; obj.ZIndex = self.Config.ZIndex; table.insert(self._drawingObjects, obj) return obj end; function ESP:_UpdateDrawingObject(obj, properties) for k, v in pairs(properties) do obj[k] = v end end; function ESP:_ClearDrawingObjects() for _, obj in ipairs(self._drawingObjects) do obj:Remove() end; self._drawingObjects = {} end; function ESP:DrawBox(part, screenPos, boxWidth, boxHeight) if not self.Config.ShowBoxes then return end; local topLeft = Vector2.new(screenPos.X - (boxWidth / 2), screenPos.Y - boxHeight) local boxColor = self.Config.BoxColor; self:_CreateDrawingObject("Square", { Position = topLeft, Size = Vector2.new(boxWidth, boxHeight), Color = boxColor, Transparency = 0, Thickness = self.Config.BoxThickness, Filled = false }) local accentSize = math.min(10, boxWidth * 0.2) local accentColor = Color3.new(1, 1, 1) self:_CreateDrawingObject("Line", { From = topLeft, To = Vector2.new(topLeft.X + accentSize, topLeft.Y), Color = accentColor, Transparency = 0.2, Thickness = 2 }) self:_CreateDrawingObject("Line", { From = topLeft, To = Vector2.new(topLeft.X, topLeft.Y + accentSize), Color = accentColor, Transparency = 0.2, Thickness = 2 }) local topRight = Vector2.new(topLeft.X + boxWidth, topLeft.Y) self:_CreateDrawingObject("Line", { From = Vector2.new(topRight.X - accentSize, topRight.Y), To = topRight, Color = accentColor, Transparency = 0.2, Thickness = 2 }) self:_CreateDrawingObject("Line", { From = topRight, To = Vector2.new(topRight.X, topRight.Y + accentSize), Color = accentColor, Transparency = 0.2, Thickness = 2 }) local bottomLeft = Vector2.new(topLeft.X, topLeft.Y + boxHeight) self:_CreateDrawingObject("Line", { From = bottomLeft, To = Vector2.new(bottomLeft.X + accentSize, bottomLeft.Y), Color = accentColor, Transparency = 0.2, Thickness = 2 }) self:_CreateDrawingObject("Line", { From = bottomLeft, To = Vector2.new(bottomLeft.X, bottomLeft.Y - accentSize), Color = accentColor, Transparency = 0.2, Thickness = 2 }) local bottomRight = Vector2.new(topLeft.X + boxWidth, topLeft.Y + boxHeight) self:_CreateDrawingObject("Line", { From = Vector2.new(bottomRight.X - accentSize, bottomRight.Y), To = bottomRight, Color = accentColor, Transparency = 0.2, Thickness = 2 }) self:_CreateDrawingObject("Line", { From = bottomRight, To = Vector2.new(bottomRight.X, bottomRight.Y - accentSize), Color = accentColor, Transparency = 0.2, Thickness = 2 }) end; function ESP:_UpdateCache() local currentTime = tick() if currentTime - self._cache.lastUpdate < self._cache.updateInterval then return end; self._cache.lastUpdate = currentTime; self._cache.parts = {} if self.Callbacks.getPartsToRenderCallback then local parts = self.Callbacks.getPartsToRenderCallback() if parts then for i, part in ipairs(parts) do self._cache.parts[#self._cache.parts + 1] = part; end end end end; function ESP:_OnRender() if not self.Config.Enabled then return end; self:_ClearDrawingObjects() self:_UpdateCache() for _, part in ipairs(self._cache.parts) do if part and part.Parent then local partPosition if part:IsA("BasePart") then partPosition = part.Position elseif part:IsA("Model") then partPosition = part:GetPivot().Position end local screenPos = self:WorldToScreen(partPosition) if screenPos then local w, h = self:GetPartBoxSize(part) self:DrawBox(part, screenPos, w, h) end end end; for _, obj in ipairs(self._activeObjects) do if obj.type == "circle" and obj.position then local screenPos = self:WorldToScreen(obj.position) if screenPos then self:_CreateDrawingObject("Circle", { Position = screenPos, Radius = obj.radius, Color = obj.color, Transparency = obj.transparency or 0, Thickness = obj.thickness or 2, Filled = obj.filled or false, NumSides = 32 }) end elseif obj.type == "line" and obj.from and obj.to then local fromScreen = self:WorldToScreen(obj.from) local toScreen = self:WorldToScreen(obj.to) if fromScreen and toScreen then self:_CreateDrawingObject("Line", { From = fromScreen, To = toScreen, Color = obj.color, Transparency = obj.transparency or 0, Thickness = obj.thickness or 1 }) end end end end; function ESP:SetGetPartsToRenderCallback(callback) self.Callbacks.getPartsToRenderCallback = callback end; function ESP:AddObject(object) self._activeObjects[#self._activeObjects + 1] = object; return object end; function ESP:RemoveObject(object) for i, obj in ipairs(self._activeObjects) do if obj == object then table.remove(self._activeObjects, i) break end end end; function ESP:ClearObjects() self._activeObjects = {} end; function ESP:SetConfig(newConfig) for k, v in pairs(newConfig) do self.Config[k] = v end end; function ESP:Toggle() self.Config.Enabled = not self.Config.Enabled; return self.Config.Enabled end; function ESP:Init() if self._renderConnection then self:_Cleanup() end; self._renderConnection = game:GetService("RunService").RenderStepped:Connect(function() self:_OnRender() end) end; function ESP:_Cleanup() if self._renderConnection then self._renderConnection:Disconnect() self._renderConnection = nil end; self:_ClearDrawingObjects() end; function ESP:Destroy() self:_Cleanup() self._activeObjects = {} self:ClearCallbacks() self._cache = { parts = {}, lastUpdate = 0, updateInterval = 0.1 } end; function ESP:ForceUpdate() self._cache.lastUpdate = 0; self:_UpdateCache() end; end local Config = { Enabled = true, ShowNames = false, ShowBoxes = true, ShowTools = false, BoxThickness = 2, NameFont = 1, FontSize = 14, NameColor = Color3.new(1, 0, 0), BoxColor = Color3.new(1, 0, 0), ToolIconSize = 16, ZIndex = 2, } ESP:SetConfig(Config) local insert = function(t, v) t[#t+1]=v end ESP:SetGetPartsToRenderCallback(function() local Parts, Enemies = {}, GetEnemyTargets() for _, Enemy in Enemies do if Enemy.Character and Enemy.Character.Hitbox and Enemy.Character.Hitbox.Head then insert(Parts, Enemy.Character) end end return Parts end) ESP:Init()