-- [[ 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 Players = game:GetService("Players") local RepStorage = game:GetService("ReplicatedStorage") local RunService = game:GetService("RunService") local TweenService = game:GetService("TweenService") local UIS = game:GetService("UserInputService") local lp = Players.LocalPlayer local char = lp.Character or lp.CharacterAdded:Wait() local hrp = char:FindFirstChild("HumanoidRootPart") lp.CharacterAdded:Connect(function(c) char = c hrp = c:WaitForChild("HumanoidRootPart") end) local remote = RepStorage:WaitForChild("DrywallClicked", 10) local pickup = RepStorage:WaitForChild("PickupSound", 10) if not remote then warn("[EatDrywall] DrywallClicked not found") end local CFG = { Active = false, FireRate = 0.65, RateMin = 0.1, RateMax = 5.0, Noclip = true, AutoMove = true, } local Eaten = 0 local Fired = 0 local lastFire = 0 local lastUI = 0 local lastScan = 0 local dwCache = {} local approachCache = {} local activeTween = nil local lastTarget = nil local noclipConn = nil local function enableNoclip() if noclipConn then return end noclipConn = RunService.Heartbeat:Connect(function() if not CFG.Noclip or not char then return end for _, p in ipairs(char:GetDescendants()) do if p:IsA("BasePart") then p.CanCollide = false end end end) end local function disableNoclip() if noclipConn then noclipConn:Disconnect(); noclipConn = nil end if char then for _, p in ipairs(char:GetDescendants()) do if p:IsA("BasePart") then p.CanCollide = true end end end end local APPROACH_DIRS = { Vector3.new( 0, 1, 0), Vector3.new( 0, -1, 0), Vector3.new( 1, 0, 0), Vector3.new(-1, 0, 0), Vector3.new( 0, 0, 1), Vector3.new( 0, 0, -1), Vector3.new( 1, 1, 0).Unit, Vector3.new(-1, 1, 0).Unit, Vector3.new( 1, 0, 1).Unit, Vector3.new(-1, 0, 1).Unit, Vector3.new( 1, 1, 1).Unit, Vector3.new(-1, 1, -1).Unit, } local function findApproach(part) if not part or not part.Parent then return nil, nil end local model = (part.Parent and part.Parent:IsA("Model")) and part.Parent or part local excludeParams = RaycastParams.new() excludeParams.FilterType = Enum.RaycastFilterType.Exclude excludeParams.FilterDescendantsInstances = char and {char} or {} local includeParams = RaycastParams.new() includeParams.FilterType = Enum.RaycastFilterType.Include includeParams.FilterDescendantsInstances = {model} for _, dir in ipairs(APPROACH_DIRS) do local origin = part.Position + dir * 15 local toward = -dir * 18 local hit = workspace:Raycast(origin, toward, excludeParams) if hit then local isTarget = hit.Instance == part or hit.Instance:IsDescendantOf(model) if isTarget then local surface = workspace:Raycast(origin, toward, includeParams) local hitPos = surface and surface.Position or hit.Position local camPos = hitPos + dir * 5 return hitPos, camPos end end end return nil, nil end local function refreshCache() local t, seen = {}, {} for _, map in ipairs(workspace:GetChildren()) do if not (map:IsA("Model") or map:IsA("Folder")) then continue end local dw = map:FindFirstChild("Drywall") if not dw then continue end for _, item in ipairs(dw:GetChildren()) do local part = nil if item:IsA("BasePart") or item:IsA("MeshPart") or item:IsA("UnionOperation") then part = item elseif item:IsA("Model") then part = item.PrimaryPart if not part then for _, d in ipairs(item:GetDescendants()) do if d:IsA("BasePart") then part = d break end end end end if part and part.Parent and not seen[part] then seen[part] = true table.insert(t, part) end end end dwCache = t approachCache = {} end local function getNearestPart() local best, bestD = nil, math.huge local alive = {} for _, p in ipairs(dwCache) do if p and p.Parent then table.insert(alive, p) if hrp then local d = (hrp.Position - p.Position).Magnitude if d < bestD then bestD = d; best = p end end end end dwCache = alive return best, bestD, #alive end local function getApproach(part) if approachCache[part] then return approachCache[part] end local hitPos, camPos = findApproach(part) if hitPos then approachCache[part] = {hitPos = hitPos, camPos = camPos} return approachCache[part] end return nil end local function moveToTarget(part) if not hrp or not part or not part.Parent then return end local approach = getApproach(part) local goalPos = approach and approach.camPos or (part.Position + Vector3.new(0, 5, 0)) if (hrp.Position - goalPos).Magnitude < 1.5 then return end if activeTween then activeTween:Cancel() end local dist = (hrp.Position - goalPos).Magnitude local t = math.clamp(dist / 20, 0.1, 2.0) local hum = char and char:FindFirstChildOfClass("Humanoid") if hum then hum:Move(Vector3.new(0, 0, 0)) end activeTween = TweenService:Create( hrp, TweenInfo.new(t, Enum.EasingStyle.Quad, Enum.EasingDirection.Out), { CFrame = CFrame.new(goalPos) } ) activeTween:Play() lastTarget = part end if pickup then pickup.OnClientEvent:Connect(function() Eaten = Eaten + 1 end) end local guiParent = (typeof(gethui) == "function" and gethui()) or game:GetService("CoreGui") pcall(function() local o = guiParent:FindFirstChild("EatDrywallFinal") if o then o:Destroy() end end) local sg = Instance.new("ScreenGui") sg.Name = "EatDrywallFinal"; sg.ResetOnSpawn = false; sg.Parent = guiParent local C = { BG = Color3.fromRGB(15,15,20), TopBar = Color3.fromRGB(10,10,15), Card = Color3.fromRGB(22,22,30), Accent = Color3.fromRGB(220,55,55), Green = Color3.fromRGB(50,200,100), Yellow = Color3.fromRGB(220,180,50), Text = Color3.fromRGB(225,225,230), Dim = Color3.fromRGB(110,110,125), Border = Color3.fromRGB(35,35,48), Track = Color3.fromRGB(32,32,45), White = Color3.fromRGB(255,255,255), } local function mkCorner(r,p) local c=Instance.new("UICorner"); c.CornerRadius=UDim.new(0,r); c.Parent=p end local function mkStroke(col,th,p) local s=Instance.new("UIStroke"); s.Color=col; s.Thickness=th; s.Parent=p end local function mkPad(l,r,t,b,p) local u=Instance.new("UIPadding") u.PaddingLeft=UDim.new(0,l); u.PaddingRight=UDim.new(0,r) u.PaddingTop=UDim.new(0,t); u.PaddingBottom=UDim.new(0,b); u.Parent=p end local function mkLbl(txt,size,col,font,xa,parent) local l=Instance.new("TextLabel") l.Text=txt; l.TextSize=size; l.TextColor3=col l.Font=font or Enum.Font.Gotham l.TextXAlignment=xa or Enum.TextXAlignment.Left l.BackgroundTransparency=1; l.Size=UDim2.new(1,0,1,0) l.Parent=parent; return l end local WIN_H = 460 local Main=Instance.new("Frame") Main.Name="Main"; Main.Size=UDim2.new(0,275,0,WIN_H) Main.Position=UDim2.new(0.5,-137,0.5,-230) Main.BackgroundColor3=C.BG; Main.BorderSizePixel=0 Main.ClipsDescendants=true; Main.Parent=sg mkCorner(10,Main); mkStroke(C.Border,1,Main) local TB=Instance.new("Frame") TB.Size=UDim2.new(1,0,0,40); TB.BackgroundColor3=C.TopBar TB.BorderSizePixel=0; TB.Parent=Main mkCorner(10,TB) local TBfix=Instance.new("Frame") TBfix.Size=UDim2.new(1,0,0,8); TBfix.Position=UDim2.new(0,0,1,-8) TBfix.BackgroundColor3=C.TopBar; TBfix.BorderSizePixel=0; TBfix.Parent=TB local icon=mkLbl("🧱",16,C.Accent,Enum.Font.GothamBold,Enum.TextXAlignment.Center,TB) icon.Size=UDim2.new(0,28,0,28); icon.Position=UDim2.new(0,8,0.5,-14) local titleTxt=mkLbl("EAT DRYWALL",13,C.Text,Enum.Font.GothamBold,Enum.TextXAlignment.Left,TB) titleTxt.Size=UDim2.new(1,-100,0,20); titleTxt.Position=UDim2.new(0,42,0,4) local subTxt=mkLbl("v5.1 · approach finder",10,C.Dim,Enum.Font.Gotham,Enum.TextXAlignment.Left,TB) subTxt.Size=UDim2.new(1,-100,0,14); subTxt.Position=UDim2.new(0,42,0,24) local function mkHdrBtn(txt,xOff,bg) local b=Instance.new("TextButton") b.Size=UDim2.new(0,26,0,26); b.Position=UDim2.new(1,xOff,0.5,-13) b.BackgroundColor3=bg; b.Font=Enum.Font.GothamBold b.TextSize=15; b.TextColor3=C.White; b.Text=txt b.BorderSizePixel=0; b.Parent=TB mkCorner(6,b); return b end local MinBtn = mkHdrBtn("—",-62,Color3.fromRGB(38,38,55)) local CloseBtn = mkHdrBtn("×",-33,Color3.fromRGB(55,25,25)) local Content=Instance.new("Frame") Content.Name="Content"; Content.Size=UDim2.new(1,0,1,-40) Content.Position=UDim2.new(0,0,0,40) Content.BackgroundTransparency=1; Content.Parent=Main local CL=Instance.new("UIListLayout") CL.Padding=UDim.new(0,7); CL.SortOrder=Enum.SortOrder.LayoutOrder; CL.Parent=Content mkPad(10,10,10,10,Content) local StatCard=Instance.new("Frame") StatCard.Size=UDim2.new(1,0,0,76); StatCard.BackgroundColor3=C.Card StatCard.BorderSizePixel=0; StatCard.LayoutOrder=1; StatCard.Parent=Content mkCorner(8,StatCard); mkStroke(C.Border,1,StatCard) local function mkStatCol(parent,labelTxt,xpos,valCol) local col=Instance.new("Frame") col.Size=UDim2.new(0,78,1,0); col.Position=UDim2.new(0,xpos,0,0) col.BackgroundTransparency=1; col.Parent=parent local val=mkLbl("0",24,valCol or C.Accent,Enum.Font.GothamBold,Enum.TextXAlignment.Center,col) val.Size=UDim2.new(1,0,0,36); val.Position=UDim2.new(0,0,0,12) local sub=mkLbl(labelTxt,9,C.Dim,Enum.Font.GothamBold,Enum.TextXAlignment.Center,col) sub.Size=UDim2.new(1,0,0,12); sub.Position=UDim2.new(0,0,0,52) return val end local FiredVal = mkStatCol(StatCard,"FIRED", 2, C.Yellow) local EatenVal = mkStatCol(StatCard,"EATEN", 88, C.Green) local FoundVal = mkStatCol(StatCard,"ITEMS", 172, C.Dim) for _, xp in ipairs({84,168}) do local div=Instance.new("Frame") div.Size=UDim2.new(0,1,0,44); div.Position=UDim2.new(0,xp,0,16) div.BackgroundColor3=C.Border; div.BorderSizePixel=0; div.Parent=StatCard end local Badge=Instance.new("Frame") Badge.Size=UDim2.new(1,0,0,28); Badge.BackgroundColor3=C.Card Badge.BorderSizePixel=0; Badge.LayoutOrder=2; Badge.Parent=Content mkCorner(8,Badge); mkStroke(C.Border,1,Badge) local BDot=Instance.new("Frame") BDot.Size=UDim2.new(0,8,0,8); BDot.Position=UDim2.new(0,10,0.5,-4) BDot.BackgroundColor3=C.Dim; BDot.BorderSizePixel=0; BDot.Parent=Badge mkCorner(4,BDot) local BTxt=mkLbl("INACTIVE",10,C.Dim,Enum.Font.GothamBold,Enum.TextXAlignment.Left,Badge) BTxt.Size=UDim2.new(1,-90,1,0); BTxt.Position=UDim2.new(0,24,0,0) local BRight=mkLbl("nearest: —",10,C.Dim,Enum.Font.Gotham,Enum.TextXAlignment.Right,Badge) BRight.Size=UDim2.new(0,85,1,0); BRight.Position=UDim2.new(1,-92,0,0) -- map row local MapRow=Instance.new("Frame") MapRow.Size=UDim2.new(1,0,0,24); MapRow.BackgroundColor3=C.Card MapRow.BorderSizePixel=0; MapRow.LayoutOrder=3; MapRow.Parent=Content mkCorner(8,MapRow); mkStroke(C.Border,1,MapRow) local MapDot=Instance.new("Frame") MapDot.Size=UDim2.new(0,6,0,6); MapDot.Position=UDim2.new(0,10,0.5,-3) MapDot.BackgroundColor3=C.Green; MapDot.BorderSizePixel=0; MapDot.Parent=MapRow mkCorner(3,MapDot) local MapTxt=mkLbl("scanning maps...",10,C.Dim,Enum.Font.GothamBold,Enum.TextXAlignment.Left,MapRow) MapTxt.Size=UDim2.new(1,-20,1,0); MapTxt.Position=UDim2.new(0,22,0,0) -- main button local MainBtn=Instance.new("TextButton") MainBtn.Size=UDim2.new(1,0,0,42); MainBtn.BackgroundColor3=Color3.fromRGB(45,45,60) MainBtn.BorderSizePixel=0; MainBtn.Font=Enum.Font.GothamBold MainBtn.TextSize=13; MainBtn.TextColor3=C.White MainBtn.Text="▶ START"; MainBtn.LayoutOrder=4; MainBtn.Parent=Content mkCorner(8,MainBtn) local function mkToggle(parent,order,title,desc,initVal,cb) local row=Instance.new("Frame") row.Size=UDim2.new(1,0,0,46); row.BackgroundColor3=C.Card row.BorderSizePixel=0; row.LayoutOrder=order; row.Parent=parent mkCorner(8,row); mkStroke(C.Border,1,row) local t=mkLbl(title,12,C.Text,Enum.Font.GothamBold,Enum.TextXAlignment.Left,row) t.Size=UDim2.new(1,-60,0,16); t.Position=UDim2.new(0,12,0,7) local d=mkLbl(desc,10,C.Dim,Enum.Font.Gotham,Enum.TextXAlignment.Left,row) d.Size=UDim2.new(1,-60,0,14); d.Position=UDim2.new(0,12,0,25) local pill=Instance.new("Frame") pill.Size=UDim2.new(0,42,0,22); pill.Position=UDim2.new(1,-52,0.5,-11) pill.BackgroundColor3=initVal and C.Accent or C.Dim pill.BorderSizePixel=0; pill.Parent=row mkCorner(11,pill) local knob=Instance.new("Frame") knob.Size=UDim2.new(0,16,0,16) knob.Position=initVal and UDim2.new(1,-19,0.5,-8) or UDim2.new(0,3,0.5,-8) knob.BackgroundColor3=C.White; knob.BorderSizePixel=0; knob.Parent=pill mkCorner(8,knob) local state=initVal local hb=Instance.new("TextButton") hb.Size=UDim2.new(1,0,1,0); hb.BackgroundTransparency=1 hb.Text=""; hb.Parent=row hb.MouseButton1Click:Connect(function() state=not state TweenService:Create(pill,TweenInfo.new(0.15),{ BackgroundColor3=state and C.Accent or C.Dim }):Play() TweenService:Create(knob,TweenInfo.new(0.15),{ Position=state and UDim2.new(1,-19,0.5,-8) or UDim2.new(0,3,0.5,-8) }):Play() cb(state) end) end mkToggle(Content,5,"Auto Move","tween to clear LOS position per drywall",CFG.AutoMove,function(v) CFG.AutoMove=v if not v and activeTween then activeTween:Cancel() end end) mkToggle(Content,6,"Noclip","pass through geometry to reach drywall",CFG.Noclip,function(v) CFG.Noclip=v if v then enableNoclip() else disableNoclip() end end) local RateCard=Instance.new("Frame") RateCard.Size=UDim2.new(1,0,0,88); RateCard.BackgroundColor3=C.Card RateCard.BorderSizePixel=0; RateCard.LayoutOrder=7; RateCard.Parent=Content mkCorner(8,RateCard); mkStroke(C.Border,1,RateCard) mkPad(10,10,8,8,RateCard) local RateHeader=Instance.new("Frame") RateHeader.Size=UDim2.new(1,0,0,18) RateHeader.BackgroundTransparency=1; RateHeader.Parent=RateCard local RateLbl=mkLbl("EAT INTERVAL",10,C.Dim,Enum.Font.GothamBold,Enum.TextXAlignment.Left,RateHeader) RateLbl.Size=UDim2.new(0,120,1,0) local RateBox=Instance.new("TextBox") RateBox.Size=UDim2.new(0,68,0,18); RateBox.Position=UDim2.new(1,-68,0,0) RateBox.BackgroundColor3=Color3.fromRGB(28,28,40); RateBox.BorderSizePixel=0 RateBox.Font=Enum.Font.GothamBold; RateBox.TextSize=11 RateBox.TextColor3=C.White; RateBox.PlaceholderColor3=C.Dim RateBox.Text=string.format("%.2f",CFG.FireRate) RateBox.TextXAlignment=Enum.TextXAlignment.Center RateBox.ClearTextOnFocus=false; RateBox.Parent=RateHeader mkCorner(4,RateBox); mkStroke(C.Border,1,RateBox) local Track=Instance.new("Frame") Track.Size=UDim2.new(1,0,0,6); Track.Position=UDim2.new(0,0,0,30) Track.BackgroundColor3=C.Track; Track.BorderSizePixel=0; Track.Parent=RateCard mkCorner(3,Track) local Fill=Instance.new("Frame") Fill.Size=UDim2.new(0,0,1,0); Fill.BackgroundColor3=C.Accent Fill.BorderSizePixel=0; Fill.Parent=Track mkCorner(3,Fill) local Knob=Instance.new("Frame") Knob.Size=UDim2.new(0,16,0,16); Knob.AnchorPoint=Vector2.new(0.5,0.5) Knob.Position=UDim2.new(0,0,0.5,0); Knob.BackgroundColor3=C.White Knob.BorderSizePixel=0; Knob.ZIndex=3; Knob.Parent=Track mkCorner(8,Knob); mkStroke(C.Border,1,Knob) local MinRLbl=mkLbl(string.format("%.1fs",CFG.RateMin),9,C.Dim,Enum.Font.Gotham,Enum.TextXAlignment.Left,RateCard) MinRLbl.Size=UDim2.new(0,30,0,12); MinRLbl.Position=UDim2.new(0,0,0,42) local MaxRLbl=mkLbl(string.format("%.1fs",CFG.RateMax),9,C.Dim,Enum.Font.Gotham,Enum.TextXAlignment.Right,RateCard) MaxRLbl.Size=UDim2.new(0,30,0,12); MaxRLbl.Position=UDim2.new(1,-30,0,42) local CurLbl=mkLbl("",10,C.Accent,Enum.Font.GothamBold,Enum.TextXAlignment.Center,RateCard) CurLbl.Size=UDim2.new(1,0,0,12); CurLbl.Position=UDim2.new(0,0,0,56) local function setRate(rate) rate=math.clamp(math.floor(rate/0.05+0.5)*0.05,CFG.RateMin,CFG.RateMax) CFG.FireRate=rate local alpha=(rate-CFG.RateMin)/(CFG.RateMax-CFG.RateMin) Fill.Size=UDim2.new(alpha,0,1,0) Knob.Position=UDim2.new(alpha,0,0.5,0) CurLbl.Text=string.format("%.2fs per eat (%.1f/min)",rate,60/rate) RateBox.Text=string.format("%.2f",rate) local col=rate<=0.5 and C.Green or (rate<=1.5 and C.Yellow or C.Accent) Fill.BackgroundColor3=col; CurLbl.TextColor3=col end setRate(CFG.FireRate) local sliderDragging=false local function alphaFromMouse(pos) local ap=Track.AbsolutePosition; local as=Track.AbsoluteSize return math.clamp((pos.X-ap.X)/as.X,0,1) end local function rateFromAlpha(a) return CFG.RateMin+a*(CFG.RateMax-CFG.RateMin) end Knob.InputBegan:Connect(function(i) if i.UserInputType==Enum.UserInputType.MouseButton1 then sliderDragging=true end end) Track.InputBegan:Connect(function(i) if i.UserInputType==Enum.UserInputType.MouseButton1 then sliderDragging=true; setRate(rateFromAlpha(alphaFromMouse(i.Position))) end end) UIS.InputChanged:Connect(function(i) if sliderDragging and i.UserInputType==Enum.UserInputType.MouseMovement then setRate(rateFromAlpha(alphaFromMouse(i.Position))) end end) UIS.InputEnded:Connect(function(i) if i.UserInputType==Enum.UserInputType.MouseButton1 then sliderDragging=false end end) RateBox.FocusLost:Connect(function() local v=tonumber(RateBox.Text) if v then setRate(v) else RateBox.Text=string.format("%.2f",CFG.FireRate) end end) local function mkNudge(lbl,xOff,delta) local b=Instance.new("TextButton") b.Size=UDim2.new(0,22,0,18); b.Position=UDim2.new(0,xOff,0,56) b.BackgroundColor3=Color3.fromRGB(32,32,46); b.Font=Enum.Font.GothamBold b.TextSize=13; b.TextColor3=C.Dim; b.Text=lbl b.BorderSizePixel=0; b.Parent=RateCard mkCorner(4,b) b.MouseButton1Click:Connect(function() setRate(CFG.FireRate+delta) end) local held=false b.MouseButton1Down:Connect(function() held=true task.spawn(function() task.wait(0.4) while held do setRate(CFG.FireRate+delta) task.wait(0.07) end end) end) b.MouseButton1Up:Connect(function() held=false end) end mkNudge("−",0,-0.05); mkNudge("+",26,0.05) MainBtn.MouseButton1Click:Connect(function() if not remote then return end CFG.Active=not CFG.Active if CFG.Active then TweenService:Create(MainBtn,TweenInfo.new(0.15),{BackgroundColor3=C.Accent}):Play() MainBtn.Text="⏸ PAUSE"; BTxt.Text="EATING" BTxt.TextColor3=C.Green; BDot.BackgroundColor3=C.Green if CFG.Noclip then enableNoclip() end task.spawn(refreshCache) else TweenService:Create(MainBtn,TweenInfo.new(0.15),{BackgroundColor3=Color3.fromRGB(45,45,60)}):Play() MainBtn.Text="▶ START"; BTxt.Text="INACTIVE" BTxt.TextColor3=C.Dim; BDot.BackgroundColor3=C.Dim if activeTween then activeTween:Cancel() end disableNoclip() end end) if pickup then pickup.OnClientEvent:Connect(function() BDot.BackgroundColor3=C.White TweenService:Create(BDot,TweenInfo.new(0.25),{BackgroundColor3=C.Green}):Play() end) end local minimized=false CloseBtn.MouseButton1Click:Connect(function() sg:Destroy() end) MinBtn.MouseButton1Click:Connect(function() minimized=not minimized; Content.Visible=not minimized TweenService:Create(Main,TweenInfo.new(0.18,Enum.EasingStyle.Quad),{ Size=minimized and UDim2.new(0,275,0,40) or UDim2.new(0,275,0,WIN_H) }):Play() end) local drag,ds,sp=false,nil,nil TB.InputBegan:Connect(function(i) if i.UserInputType==Enum.UserInputType.MouseButton1 then drag=true; ds=i.Position; sp=Main.Position end end) TB.InputEnded:Connect(function(i) if i.UserInputType==Enum.UserInputType.MouseButton1 then drag=false end end) UIS.InputChanged:Connect(function(i) if drag and i.UserInputType==Enum.UserInputType.MouseMovement then local d=i.Position-ds Main.Position=UDim2.new(sp.X.Scale,sp.X.Offset+d.X,sp.Y.Scale,sp.Y.Offset+d.Y) end end) task.spawn(refreshCache) if CFG.Noclip then enableNoclip() end RunService.Heartbeat:Connect(function() local now=tick() if now-lastScan >= 3.0 then lastScan=now task.spawn(function() refreshCache() local maps={} for _, map in ipairs(workspace:GetChildren()) do if map:FindFirstChild("Drywall") then table.insert(maps,map.Name) end end MapTxt.Text = #maps.." map(s): "..table.concat(maps,", ") MapTxt.TextColor3= C.Green end) end local nearest,d,count = getNearestPart() if now-lastUI >= 0.1 then lastUI=now FiredVal.Text = tostring(Fired) EatenVal.Text = tostring(Eaten) FoundVal.Text = tostring(count) BRight.Text = nearest and string.format("nearest: %.1f",d) or "nearest: —" end if not CFG.Active or not remote then return end if not nearest then return end -- compute approach lazily in background so it never blocks heartbeat if not approachCache[nearest] then task.spawn(function() getApproach(nearest) end) end -- automove: tween player to camPos (outside geometry, clear LOS) if CFG.AutoMove then local approach = approachCache[nearest] local goalPos = approach and approach.camPos or (nearest.Position + Vector3.new(0,5,0)) local drifted = hrp and (hrp.Position - goalPos).Magnitude > 1.5 if drifted or lastTarget ~= nearest then moveToTarget(nearest) end end if now-lastFire >= CFG.FireRate then lastFire=now Fired=Fired+1 if not hrp then return end local approach = approachCache[nearest] if approach then -- clean LOS confirmed by raycast -- server: camPos (outside wall) → hitPos (drywall surface) = always hits pcall(function() remote:FireServer(approach.hitPos, approach.camPos) end) else -- approach not computed yet — brute force all 6 axes -- one direction will have clear LOS local offsets = { Vector3.new( 0,10, 0), Vector3.new( 0,-10, 0), Vector3.new(10, 0, 0), Vector3.new(-10, 0, 0), Vector3.new( 0, 0,10), Vector3.new( 0, 0,-10), } for _, offset in ipairs(offsets) do local camPos = nearest.Position + offset pcall(function() remote:FireServer(nearest.Position, camPos) end) end end end end) print("[EatDrywall v1]")