-- Remote Keybinder + Placement (placement fixes: sphere, StraightForward level, CustomPlacement follows entity) -- Place as LocalScript in StarterGui (runs in PlayerGui) local Players = game:GetService("Players") local UserInputService = game:GetService("UserInputService") local RunService = game:GetService("RunService") local TweenService = game:GetService("TweenService") local HttpService = game:GetService("HttpService") local Camera = workspace.CurrentCamera local player = Players.LocalPlayer local backpack = player:WaitForChild("Backpack") local guiParent = player:WaitForChild("PlayerGui") local character = player.Character or player.CharacterAdded:Wait() -- -------------------- -- Small helpers -- -------------------- local function trim(s) return (tostring(s):gsub("^%s*(.-)%s*$","%1")) end local function safeGetMouse() local ok,m = pcall(function() return player:GetMouse() end) if ok then return m end return nil end local function getMouseHitPos() local m = safeGetMouse() if not m then return nil end local ok, hit = pcall(function() return m.Hit end) if not ok or not hit then return nil end local p = hit.Position or (hit.p and hit.p) if typeof(p) == "Vector3" then return p end return nil end local function isRemote(inst) return inst and (inst:IsA("RemoteEvent") or inst:IsA("RemoteFunction")) end local function keyEnumToName(k) if not k then return "" end return tostring(k):gsub("Enum.KeyCode.","") end local function nameToKeyEnum(name) if not name then return nil end local ok,e = pcall(function() return Enum.KeyCode[name] end) return ok and e or nil end local function parseSingleToken(tok) tok = trim(tok) if tok == "" then return nil end local quoted = tok:match('^"(.*)"$') or tok:match("^'(.*)'$") if quoted then return tostring(quoted) end if tok:lower() == "true" then return true end if tok:lower() == "false" then return false end local n = tonumber(tok) if n then return n end local a,b,c = tok:match("^Vector3%.new%(%s*([-+]?%d*%.?%d+)%s*,%s*([-+]?%d*%.?%d+)%s*,%s*([-+]?%d*%.?%d+)%s*%)$") if a and b and c then return Vector3.new(tonumber(a), tonumber(b), tonumber(c)) end return tostring(tok) end local function parseArgsText(txt) txt = tostring(txt or "") txt = trim(txt) if txt == "" then return {} end local out = {} for token in txt:gmatch("([^,]+)") do local v = parseSingleToken(token) if v ~= nil then table.insert(out, v) end end return out end local function safeCallRemoteSingle(remote, argsTable, sendAsXYZ) if not remote or not remote.Parent then return false, "remote missing" end local ok, err = pcall(function() if sendAsXYZ then if #argsTable >= 1 and typeof(argsTable[1]) == "Vector3" then local v = argsTable[1] local rest = {} for i = 2, #argsTable do table.insert(rest, argsTable[i]) end local sendArgs = {v.X, v.Y, v.Z} for _,o in ipairs(rest) do table.insert(sendArgs, o) end if remote:IsA("RemoteEvent") then remote:FireServer(unpack(sendArgs)) else remote:InvokeServer(unpack(sendArgs)) end else if remote:IsA("RemoteEvent") then remote:FireServer(unpack(argsTable)) else remote:InvokeServer(unpack(argsTable)) end end else if remote:IsA("RemoteEvent") then remote:FireServer(unpack(argsTable)) else remote:InvokeServer(unpack(argsTable)) end end end) return ok, err end local function safeCallRemote(remoteOrList, argsTable, sendAsXYZ) if not remoteOrList then return false, "no remotes" end if typeof(remoteOrList) == "Instance" then return safeCallRemoteSingle(remoteOrList, argsTable, sendAsXYZ) elseif type(remoteOrList) == "table" then local anyOk = false local lastErr = nil for _,rm in ipairs(remoteOrList) do local ok, err = pcall(function() return safeCallRemoteSingle(rm, argsTable, sendAsXYZ) end) if ok and err ~= false then anyOk = true else lastErr = err end end return anyOk, lastErr else return false, "invalid remote type" end end -- -------------------- -- Prediction & humanoid cache -- -------------------- local function getLocalReferencePos() local ch = player.Character if ch and ch.PrimaryPart then return ch.PrimaryPart.Position end if ch and ch:FindFirstChild("HumanoidRootPart") and ch.HumanoidRootPart:IsA("BasePart") then return ch.HumanoidRootPart.Position end if Camera then return Camera.CFrame.p end return Vector3.new(0,0,0) end local function getLocalForwardVector() local ch = player.Character if ch and ch.PrimaryPart then return ch.PrimaryPart.CFrame.LookVector end if Camera then return Camera.CFrame.LookVector end return Vector3.new(0,0,-1) end local function clampPredictionForSpeed(predX, predY, speed) if speed > 200 then if predX > 0 then predX = math.min(predX, 200 / speed) end if predY > 0 then predY = math.min(predY, 200 / speed) end end return predX, predY end local humanoidCache = {} local humanoidCacheLock = false local HUMANOID_CACHE_INTERVAL = 0.6 local function refreshHumanoidCache() if humanoidCacheLock then return end humanoidCacheLock = true local newCache = {} for _, child in ipairs(workspace:GetChildren()) do if child and child:IsA("Model") and child.Name ~= player.Name then local humanoid = child:FindFirstChildOfClass("Humanoid") if humanoid and humanoid.Health > 0 then local root = child:FindFirstChild("HumanoidRootPart") or child.PrimaryPart if root and root:IsA("BasePart") then table.insert(newCache, { model = child, root = root, humanoid = humanoid }) end end end end humanoidCache = newCache humanoidCacheLock = false end task.spawn(function() while true do pcall(refreshHumanoidCache) task.wait(HUMANOID_CACHE_INTERVAL) end end) local function getNearestPlayerPredictedPos(predX, predY) predX = tonumber(predX) or 0; predY = tonumber(predY) or 0 local refPos = getLocalReferencePos() local bestPl, bestPos, bestDist = nil, nil, math.huge for _,pl in ipairs(Players:GetPlayers()) do if pl ~= player and pl.Character then local hrp = pl.Character:FindFirstChild("HumanoidRootPart") or pl.Character.PrimaryPart if hrp and hrp:IsA("BasePart") then local d = (hrp.Position - refPos).Magnitude if d < bestDist then bestDist = d; bestPl = pl; bestPos = hrp.Position end end end end if not bestPl or not bestPos then return nil, nil end local hrpInst = bestPl.Character and (bestPl.Character:FindFirstChild("HumanoidRootPart") or bestPl.Character.PrimaryPart) local vel = Vector3.new(0,0,0) if hrpInst and hrpInst:IsA("BasePart") then vel = hrpInst.Velocity or Vector3.new(0,0,0) end predX, predY = clampPredictionForSpeed(predX, predY, vel.Magnitude) local predicted = bestPos + Vector3.new(vel.X * predX, vel.Y * predY, vel.Z * predX) return predicted, bestPl end local function getNearestHumanoidPredictedPos(predX, predY) predX = tonumber(predX) or 0; predY = tonumber(predY) or 0 local refPos = getLocalReferencePos() local bestEntry, bestDist = nil, math.huge for _,entry in ipairs(humanoidCache) do local root, humanoid = entry.root, entry.humanoid if root and humanoid and humanoid.Health > 0 then local ok,pos = pcall(function() return root.Position end) if ok and pos then local d = (pos - refPos).Magnitude if d < bestDist then bestDist = d; bestEntry = entry end end end end if not bestEntry then for _,child in ipairs(workspace:GetChildren()) do if child and child:IsA("Model") and child.Name ~= player.Name then local humanoid = child:FindFirstChildOfClass("Humanoid") if humanoid and humanoid.Health > 0 then local root = child:FindFirstChild("HumanoidRootPart") or child.PrimaryPart if root and root:IsA("BasePart") then local ok,pos = pcall(function() return root.Position end) if ok and pos then local d = (pos - refPos).Magnitude if d < bestDist then bestDist = d; bestEntry = {model = child, root = root, humanoid = humanoid} end end end end end end end if not bestEntry or not bestEntry.root then return nil, nil end local rootPart = bestEntry.root local vel = Vector3.new(0,0,0) if rootPart and rootPart:IsA("BasePart") then vel = rootPart.Velocity or Vector3.new(0,0,0) end predX, predY = clampPredictionForSpeed(predX, predY, vel.Magnitude) local predicted = rootPart.Position + Vector3.new(vel.X * predX, vel.Y * predY, vel.Z * predX) return predicted, bestEntry.model end -- -------------------- -- Placement system state & helpers (fixed) -- -------------------- local placement = { part = nil, billboard = nil, studs = 6, lastPos = nil, selectedModel = nil, stickToEntity = false, clickCapture = false } local function findModelAdornee(model) if not model then return nil end local root = model:FindFirstChild("HumanoidRootPart") or model.PrimaryPart if root and root:IsA("BasePart") then return root end -- fallback: find the first BasePart for _,v in ipairs(model:GetDescendants()) do if v:IsA("BasePart") then return v end end return nil end local function createPlacementPartIfNeeded() if placement.part and placement.part.Parent then return end if placement.part then pcall(function() placement.part:Destroy() end) end local p = Instance.new("Part") p.Name = "RKB_PlacementPart" p.Size = Vector3.new(1.2,1.2,1.2) p.Shape = Enum.PartType.Ball -- sphere p.Anchored = true p.CanCollide = false p.Transparency = 0.45 p.Color = Color3.fromRGB(70, 200, 120) p.Material = Enum.Material.SmoothPlastic p.Parent = workspace placement.part = p if placement.billboard then pcall(function() placement.billboard:Destroy() end) end local bb = Instance.new("BillboardGui") bb.Name = "RKB_PlacementBB" bb.Size = UDim2.new(0,120,0,36) bb.Adornee = p bb.AlwaysOnTop = true local lbl = Instance.new("TextLabel", bb) lbl.Size = UDim2.new(1,0,1,0) lbl.BackgroundTransparency = 1 lbl.Text = "Placement" lbl.Font = Enum.Font.GothamBold lbl.TextSize = 14 lbl.TextColor3 = Color3.new(1,1,1) lbl.TextStrokeTransparency = 0.6 bb.Parent = p placement.billboard = bb end local function destroyPlacementVisual() if placement.billboard then pcall(function() placement.billboard:Destroy() end) placement.billboard = nil end if placement.part then pcall(function() placement.part:Destroy() end) placement.part = nil end end local function createSelectionBillboardForModel(model) if not model then return end local adornee = findModelAdornee(model) if not adornee then return end -- remove previous billboard attached to model local existing = model:FindFirstChild("RKB_SelectedBB") if existing then existing:Destroy() end local bb = Instance.new("BillboardGui") bb.Name = "RKB_SelectedBB" bb.Size = UDim2.new(0,160,0,36) bb.AlwaysOnTop = true bb.Adornee = adornee local lbl = Instance.new("TextLabel", bb) lbl.Size = UDim2.new(1,0,1,0) lbl.BackgroundTransparency = 0.6 lbl.BackgroundColor3 = Color3.fromRGB(30,30,40) lbl.Text = "Selected: "..tostring(model.Name) lbl.Font = Enum.Font.GothamBold lbl.TextSize = 14 lbl.TextColor3 = Color3.new(1,1,1) lbl.TextStrokeTransparency = 0.6 bb.Parent = model end local function clearSelectionBillboard(model) if not model then return end local existing = model:FindFirstChild("RKB_SelectedBB") if existing then existing:Destroy() end end local function updatePlacementVisual(aimMode) if aimMode == "StraightForward" then createPlacementPartIfNeeded() -- flatten forward so it doesn't aim up local forward = getLocalForwardVector() forward = Vector3.new(forward.X, 0, forward.Z) if forward.Magnitude == 0 then forward = Camera and Vector3.new(Camera.CFrame.LookVector.X, 0, Camera.CFrame.LookVector.Z) or Vector3.new(0,0,-1) end local base = getLocalReferencePos() local studs = tonumber(placement.studs) or 6 local pos = base + (forward.Unit * studs) -- lock Y to local reference Y (prevents aiming up) pos = Vector3.new(pos.X, base.Y, pos.Z) placement.lastPos = pos if placement.part then placement.part.Position = pos if placement.billboard and placement.billboard:FindFirstChildOfClass("TextLabel") then placement.billboard:FindFirstChildOfClass("TextLabel").Text = ("Straight: %.1f studs"):format(studs) end end if placement.selectedModel then clearSelectionBillboard(placement.selectedModel) placement.selectedModel = nil end elseif aimMode == "CustomPlacement" then createPlacementPartIfNeeded() -- if a model was selected, always follow the model's adornee (Primary/HumanoidRootPart) if placement.selectedModel then local adornee = findModelAdornee(placement.selectedModel) if adornee then local pos = adornee.Position placement.lastPos = pos placement.part.Position = pos if placement.billboard and placement.billboard:FindFirstChildOfClass("TextLabel") then placement.billboard:FindFirstChildOfClass("TextLabel").Text = ("Stuck to: %s"):format(tostring(placement.selectedModel.Name)) end -- ensure selection billboard exists createSelectionBillboardForModel(placement.selectedModel) else -- fallback to last known pos if placement.lastPos then placement.part.Position = placement.lastPos if placement.billboard and placement.billboard:FindFirstChildOfClass("TextLabel") then placement.billboard:FindFirstChildOfClass("TextLabel").Text = "Custom: "..tostring(placement.lastPos) end else placement.part.Position = getLocalReferencePos() + Vector3.new(0,-300,0) end end elseif placement.lastPos then placement.part.Position = placement.lastPos if placement.billboard and placement.billboard:FindFirstChildOfClass("TextLabel") then placement.billboard:FindFirstChildOfClass("TextLabel").Text = "Custom: "..tostring(placement.lastPos) end else -- nothing set yet: hide placement.part.Position = getLocalReferencePos() + Vector3.new(0,-300,0) if placement.billboard and placement.billboard:FindFirstChildOfClass("TextLabel") then placement.billboard:FindFirstChildOfClass("TextLabel").Text = "Custom: " end end else -- not a placement mode: move out of view but remember data if placement.part then placement.part.Position = getLocalReferencePos() + Vector3.new(0,-300,0) end if placement.selectedModel and not placement.stickToEntity then clearSelectionBillboard(placement.selectedModel) placement.selectedModel = nil end end end -- keep RenderStepped visual updates (reads global aim mode set by UI) RunService.RenderStepped:Connect(function() if _G.RKB_currentAimMode then pcall(function() updatePlacementVisual(_G.RKB_currentAimMode) end) end end) -- -------------------- -- Persistence storage helpers -- -------------------- local settingsFolder = player:FindFirstChild("RemoteKeybinderSettings") if not settingsFolder then settingsFolder = Instance.new("Folder") settingsFolder.Name = "RemoteKeybinderSettings" settingsFolder.Parent = player end local function saveBindingToFolder(keyName, bindingTable) if not keyName or not bindingTable then return false, "invalid params" end local data = { key = keyName, remotePath = bindingTable.remotePath or "", remotePaths = bindingTable.remotePaths or nil, extraArgsText = bindingTable.extraArgsText or "", hold = bindingTable.hold and true or false, interval = tonumber(bindingTable.interval) or 0.12, mode = bindingTable.mode or "Mouse", predictionX = tonumber(bindingTable.predictionX) or 0, predictionY = tonumber(bindingTable.predictionY) or 0, argFormat = bindingTable.argFormat or "Vector3", placeStuds = tonumber(bindingTable.placeStuds) or nil, placeLastPos = bindingTable.placeLastPos or nil, placeStick = bindingTable.placeStick and true or false } local s = HttpService:JSONEncode(data) local name = "binding_" .. keyName local existing = settingsFolder:FindFirstChild(name) if existing and existing:IsA("StringValue") then existing.Value = s else local sv = Instance.new("StringValue") sv.Name = name sv.Value = s sv.Parent = settingsFolder end return true end local function deleteSavedBinding(keyName) if not keyName then return false end local name = "binding_" .. keyName local existing = settingsFolder:FindFirstChild(name) if existing then existing:Destroy(); return true end return false end local function loadSavedBindingsIntoTable() local out = {} for _,child in ipairs(settingsFolder:GetChildren()) do if child:IsA("StringValue") and child.Name:match("^binding_") then local ok, data = pcall(function() return HttpService:JSONDecode(child.Value) end) if ok and type(data) == "table" and data.key then out[data.key] = data end end end return out end local function findInstanceByFullName(fullPath) if not fullPath or fullPath == "" then return nil end local function scanContainer(container) if not container then return nil end for _,inst in ipairs(container:GetDescendants()) do local ok, p = pcall(function() return inst:GetFullName() end) if ok and p == fullPath then return inst end end return nil end local res = scanContainer(backpack) if res then return res end res = scanContainer(character) if res then return res end return nil end -- -------------------- -- UI BUILD + placement controls (kept same layout as previous) -- -------------------- local existingGui = guiParent:FindFirstChild("PolishedRemoteKeybinder") if existingGui then existingGui:Destroy() end local ScreenGui = Instance.new("ScreenGui") ScreenGui.Name = "PolishedRemoteKeybinder" ScreenGui.ResetOnSpawn = false ScreenGui.Parent = guiParent local frameMain = Instance.new("Frame") frameMain.Name = "Main" frameMain.Size = UDim2.new(0, 920, 0, 520) frameMain.Position = UDim2.new(0.5, -460, 0.5, -260) frameMain.BackgroundColor3 = Color3.fromRGB(20,20,26) frameMain.BorderSizePixel = 0 frameMain.Active = true frameMain.Draggable = true frameMain.Parent = ScreenGui local header = Instance.new("Frame", frameMain) header.Size = UDim2.new(1,0,0,64) header.Position = UDim2.new(0,0,0,0) header.BackgroundColor3 = Color3.fromRGB(28,28,36) header.BorderSizePixel = 0 local title = Instance.new("TextLabel", header) title.Text = "Remote Keybinder — Inventory (Backpack + Character)" title.Font = Enum.Font.GothamBold title.TextSize = 18 title.TextColor3 = Color3.fromRGB(235,235,235) title.BackgroundTransparency = 1 title.Size = UDim2.new(0.7, -20, 1, 0) title.Position = UDim2.new(0, 14, 0, 0) title.TextXAlignment = Enum.TextXAlignment.Left local subtitle = Instance.new("TextLabel", header) subtitle.Text = "Click entries to inspect, or toggle Multi-Select below the list to pick several then bind." subtitle.Font = Enum.Font.Gotham subtitle.TextSize = 12 subtitle.TextColor3 = Color3.fromRGB(180,180,190) subtitle.BackgroundTransparency = 1 subtitle.Size = UDim2.new(0.7, -20, 1, 0) subtitle.Position = UDim2.new(0, 14, 0, 26) subtitle.TextXAlignment = Enum.TextXAlignment.Left local reloadBtn = Instance.new("TextButton", header) reloadBtn.Name = "Reload" reloadBtn.Size = UDim2.new(0, 110, 0, 36) reloadBtn.Position = UDim2.new(1, -360, 0, 14) reloadBtn.BackgroundColor3 = Color3.fromRGB(56,56,76) reloadBtn.Text = "Reload (R)" reloadBtn.Font = Enum.Font.Gotham reloadBtn.TextSize = 14 reloadBtn.TextColor3 = Color3.fromRGB(240,240,240) reloadBtn.BorderSizePixel = 0 local resetToolsBtn = Instance.new("TextButton", header) resetToolsBtn.Name = "ResetTools" resetToolsBtn.Size = UDim2.new(0, 130, 0, 36) resetToolsBtn.Position = UDim2.new(1, -236, 0, 14) resetToolsBtn.BackgroundColor3 = Color3.fromRGB(96,64,32) resetToolsBtn.Text = "Reset Tools" resetToolsBtn.Font = Enum.Font.Gotham resetToolsBtn.TextSize = 14 resetToolsBtn.TextColor3 = Color3.fromRGB(240,240,240) resetToolsBtn.BorderSizePixel = 0 -- left pane (remotes) local leftPane = Instance.new("Frame", frameMain) leftPane.Position = UDim2.new(0, 14, 0, 74) leftPane.Size = UDim2.new(0, 420, 0, 420) leftPane.BackgroundTransparency = 1 local leftTitle = Instance.new("TextLabel", leftPane) leftTitle.Size = UDim2.new(1, 0, 0, 20) leftTitle.Position = UDim2.new(0,0,0,0) leftTitle.BackgroundTransparency = 1 leftTitle.Font = Enum.Font.Gotham leftTitle.TextSize = 13 leftTitle.TextColor3 = Color3.fromRGB(210,210,210) leftTitle.Text = "Detected inventory remotes (click to inspect)" local leftScroll = Instance.new("ScrollingFrame", leftPane) leftScroll.Size = UDim2.new(1, 0, 1, -80) leftScroll.Position = UDim2.new(0, 0, 0, 28) leftScroll.BackgroundTransparency = 1 leftScroll.ScrollBarThickness = 6 local leftListLayout = Instance.new("UIListLayout", leftScroll) leftListLayout.Padding = UDim.new(0,8) leftListLayout.SortOrder = Enum.SortOrder.LayoutOrder -- multi-select control area (under the remote list) local multiArea = Instance.new("Frame", leftPane) multiArea.Position = UDim2.new(0, 0, 1, -46) multiArea.Size = UDim2.new(1, 0, 0, 46) multiArea.BackgroundTransparency = 1 local multiToggle = Instance.new("TextButton", multiArea) multiToggle.Position = UDim2.new(0,6,0,6) multiToggle.Size = UDim2.new(0,140,0,34) multiToggle.Text = "Multi-Select: Off" multiToggle.Font = Enum.Font.Gotham multiToggle.TextSize = 14 multiToggle.BackgroundColor3 = Color3.fromRGB(64,64,76) multiToggle.TextColor3 = Color3.fromRGB(240,240,240) multiToggle.BorderSizePixel = 0 local clearSelectionBtn = Instance.new("TextButton", multiArea) clearSelectionBtn.Position = UDim2.new(0,156,0,6) clearSelectionBtn.Size = UDim2.new(0,110,0,34) clearSelectionBtn.Text = "Clear Selection" clearSelectionBtn.Font = Enum.Font.Gotham clearSelectionBtn.TextSize = 14 clearSelectionBtn.BackgroundColor3 = Color3.fromRGB(84,44,44) clearSelectionBtn.TextColor3 = Color3.fromRGB(240,240,240) clearSelectionBtn.BorderSizePixel = 0 local clearMultiBindsBtn = Instance.new("TextButton", multiArea) clearMultiBindsBtn.Position = UDim2.new(0,276,0,6) clearMultiBindsBtn.Size = UDim2.new(0,136,0,34) clearMultiBindsBtn.Text = "Clear Multi Binds (Del)" clearMultiBindsBtn.Font = Enum.Font.Gotham clearMultiBindsBtn.TextSize = 13 clearMultiBindsBtn.BackgroundColor3 = Color3.fromRGB(42,122,255) clearMultiBindsBtn.TextColor3 = Color3.fromRGB(240,240,240) clearMultiBindsBtn.BorderSizePixel = 0 -- right pane (inspector + placement controls) local rightPane = Instance.new("Frame", frameMain) rightPane.Position = UDim2.new(0, 448, 0, 74) rightPane.Size = UDim2.new(0, 464, 0, 420) rightPane.BackgroundTransparency = 1 local inspectorTitle = Instance.new("TextLabel", rightPane) inspectorTitle.Position = UDim2.new(0,0,0,0) inspectorTitle.Size = UDim2.new(1,0,0,20) inspectorTitle.BackgroundTransparency = 1 inspectorTitle.Font = Enum.Font.Gotham inspectorTitle.TextSize = 13 inspectorTitle.TextColor3 = Color3.fromRGB(210,210,210) inspectorTitle.Text = "Inspector & Keybinds" local lblRemote = Instance.new("TextLabel", rightPane) lblRemote.Position = UDim2.new(0,0,0,28) lblRemote.Size = UDim2.new(1,0,0,20) lblRemote.BackgroundTransparency = 1 lblRemote.Font = Enum.Font.Gotham lblRemote.TextSize = 12 lblRemote.TextColor3 = Color3.fromRGB(220,220,220) lblRemote.Text = "Remote: " local lblParent = Instance.new("TextLabel", rightPane) lblParent.Position = UDim2.new(0,0,0,48) lblParent.Size = UDim2.new(1,0,0,16) lblParent.BackgroundTransparency = 1 lblParent.Font = Enum.Font.Gotham lblParent.TextSize = 11 lblParent.TextColor3 = Color3.fromRGB(170,170,170) lblParent.Text = "Parent: " local lblType = Instance.new("TextLabel", rightPane) lblType.Position = UDim2.new(0,0,0,66) lblType.Size = UDim2.new(1,0,0,16) lblType.BackgroundTransparency = 1 lblType.Font = Enum.Font.Gotham lblType.TextSize = 11 lblType.TextColor3 = Color3.fromRGB(170,170,170) lblType.Text = "Type: " local aimLabel = Instance.new("TextLabel", rightPane) aimLabel.Position = UDim2.new(0,0,0,92) aimLabel.Size = UDim2.new(0,220,0,18) aimLabel.BackgroundTransparency = 1 aimLabel.Font = Enum.Font.Gotham aimLabel.TextSize = 12 aimLabel.TextColor3 = Color3.fromRGB(200,200,200) aimLabel.Text = "Aim mode:" local aimDropdown = Instance.new("TextButton", rightPane) aimDropdown.Position = UDim2.new(0,0,0,114) aimDropdown.Size = UDim2.new(0,220,0,28) aimDropdown.Font = Enum.Font.Gotham aimDropdown.TextSize = 12 aimDropdown.TextColor3 = Color3.fromRGB(240,240,240) aimDropdown.Text = "Mouse" -- cycles: Mouse, NearestPlayer, NearestHumanoid, StraightForward, CustomPlacement aimDropdown.BackgroundColor3 = Color3.fromRGB(48,48,62) aimDropdown.BorderSizePixel = 0 local predXLabel = Instance.new("TextLabel", rightPane) predXLabel.Position = UDim2.new(0,232,0,92) predXLabel.Size = UDim2.new(0,110,0,18) predXLabel.BackgroundTransparency = 1 predXLabel.Font = Enum.Font.Gotham predXLabel.TextSize = 12 predXLabel.TextColor3 = Color3.fromRGB(200,200,200) predXLabel.Text = "Prediction X (s):" local predXBox = Instance.new("TextBox", rightPane) predXBox.Position = UDim2.new(0,232,0,114) predXBox.Size = UDim2.new(0,66,0,28) predXBox.BackgroundColor3 = Color3.fromRGB(34,34,40) predXBox.PlaceholderText = "0.15" predXBox.Text = "0.15" predXBox.ClearTextOnFocus = false predXBox.TextColor3 = Color3.fromRGB(230,230,230) predXBox.Font = Enum.Font.Gotham predXBox.TextSize = 12 local predYLabel = Instance.new("TextLabel", rightPane) predYLabel.Position = UDim2.new(0,302,0,92) predYLabel.Size = UDim2.new(0,160,0,18) predYLabel.BackgroundTransparency = 1 predYLabel.Font = Enum.Font.Gotham predYLabel.TextSize = 12 predYLabel.TextColor3 = Color3.fromRGB(200,200,200) predYLabel.Text = "Prediction Y (s):" local predYBox = Instance.new("TextBox", rightPane) predYBox.Position = UDim2.new(0,302,0,114) predYBox.Size = UDim2.new(0,66,0,28) predYBox.BackgroundColor3 = Color3.fromRGB(34,34,40) predYBox.PlaceholderText = "0.05" predYBox.Text = "0.05" predYBox.ClearTextOnFocus = false predYBox.TextColor3 = Color3.fromRGB(230,230,230) predYBox.Font = Enum.Font.Gotham predYBox.TextSize = 12 -- Place studs / click controls local placeLabel = Instance.new("TextLabel", rightPane) placeLabel.Position = UDim2.new(0,0,0,154) placeLabel.Size = UDim2.new(0,140,0,18) placeLabel.BackgroundTransparency = 1 placeLabel.Font = Enum.Font.Gotham placeLabel.TextSize = 12 placeLabel.TextColor3 = Color3.fromRGB(200,200,200) placeLabel.Text = "Place studs:" local placeStudsBox = Instance.new("TextBox", rightPane) placeStudsBox.Position = UDim2.new(0,140,0,150) placeStudsBox.Size = UDim2.new(0,60,0,26) placeStudsBox.BackgroundColor3 = Color3.fromRGB(34,34,40) placeStudsBox.PlaceholderText = "6" placeStudsBox.Text = tostring(placement.studs) placeStudsBox.ClearTextOnFocus = false placeStudsBox.TextColor3 = Color3.fromRGB(230,230,230) placeStudsBox.Font = Enum.Font.Gotham placeStudsBox.TextSize = 12 local placeClickBtn = Instance.new("TextButton", rightPane) placeClickBtn.Position = UDim2.new(0,220,0,150) placeClickBtn.Size = UDim2.new(0,140,0,26) placeClickBtn.Font = Enum.Font.Gotham placeClickBtn.Text = "Place / Select (Click)" placeClickBtn.BackgroundColor3 = Color3.fromRGB(56,56,76) placeClickBtn.TextColor3 = Color3.fromRGB(240,240,240) placeClickBtn.TextSize = 12 placeClickBtn.BorderSizePixel = 0 local stickToggle = Instance.new("TextButton", rightPane) stickToggle.Position = UDim2.new(0,370,0,150) stickToggle.Size = UDim2.new(0,86,0,26) stickToggle.Font = Enum.Font.Gotham stickToggle.Text = "Stick: Off" stickToggle.BackgroundColor3 = Color3.fromRGB(44,44,60) stickToggle.TextColor3 = Color3.fromRGB(230,230,230) stickToggle.TextSize = 12 stickToggle.BorderSizePixel = 0 local placementSelectedLabel = Instance.new("TextLabel", rightPane) placementSelectedLabel.Position = UDim2.new(0,0,0,182) placementSelectedLabel.Size = UDim2.new(1,0,0,18) placementSelectedLabel.BackgroundTransparency = 1 placementSelectedLabel.Font = Enum.Font.Gotham placementSelectedLabel.TextSize = 12 placementSelectedLabel.TextColor3 = Color3.fromRGB(200,200,200) placementSelectedLabel.Text = "Selected placement: " -- rest of previous UI (format, args, keybinds, etc.) local formatLabel = Instance.new("TextLabel", rightPane) formatLabel.Position = UDim2.new(0,0,0,206) formatLabel.Size = UDim2.new(0,200,0,18) formatLabel.BackgroundTransparency = 1 formatLabel.Font = Enum.Font.Gotham formatLabel.TextSize = 12 formatLabel.TextColor3 = Color3.fromRGB(200,200,200) formatLabel.Text = "Arg format:" local formatDropdown = Instance.new("TextButton", rightPane) formatDropdown.Position = UDim2.new(0,0,0,228) formatDropdown.Size = UDim2.new(0,120,0,26) formatDropdown.Font = Enum.Font.Gotham formatDropdown.TextSize = 12 formatDropdown.TextColor3 = Color3.fromRGB(240,240,240) formatDropdown.Text = "Vector3" formatDropdown.BackgroundColor3 = Color3.fromRGB(48,48,62) formatDropdown.BorderSizePixel = 0 local extraLabel = Instance.new("TextLabel", rightPane) extraLabel.Position = UDim2.new(0,0,0,262) extraLabel.Size = UDim2.new(1,0,0,18) extraLabel.BackgroundTransparency = 1 extraLabel.Font = Enum.Font.Gotham extraLabel.TextSize = 12 extraLabel.TextColor3 = Color3.fromRGB(180,180,180) extraLabel.Text = "Extra args (comma-separated):" local argsBox = Instance.new("TextBox", rightPane) argsBox.Position = UDim2.new(0,0,0,284) argsBox.Size = UDim2.new(1,-12,0,64) argsBox.BackgroundColor3 = Color3.fromRGB(34,34,40) argsBox.ClearTextOnFocus = false argsBox.TextWrap = true argsBox.MultiLine = true argsBox.Text = "" argsBox.TextColor3 = Color3.fromRGB(230,230,230) argsBox.Font = Enum.Font.Gotham argsBox.TextSize = 12 local setKeyBtn = Instance.new("TextButton", rightPane) setKeyBtn.Position = UDim2.new(0,0,1,-124) setKeyBtn.Size = UDim2.new(0,160,0,36) setKeyBtn.BackgroundColor3 = Color3.fromRGB(64,64,88) setKeyBtn.Font = Enum.Font.Gotham setKeyBtn.Text = "Set Keybind (single)" setKeyBtn.TextSize = 13 setKeyBtn.TextColor3 = Color3.fromRGB(240,240,240) setKeyBtn.BorderSizePixel = 0 local bindSelectedBtn = Instance.new("TextButton", rightPane) bindSelectedBtn.Position = UDim2.new(0,170,1,-124) bindSelectedBtn.Size = UDim2.new(0,160,0,36) bindSelectedBtn.BackgroundColor3 = Color3.fromRGB(56,96,120) bindSelectedBtn.Font = Enum.Font.Gotham bindSelectedBtn.Text = "Bind Selected (multi)" bindSelectedBtn.TextSize = 13 bindSelectedBtn.TextColor3 = Color3.fromRGB(240,240,240) bindSelectedBtn.BorderSizePixel = 0 local selectedCountLabel = Instance.new("TextLabel", bindSelectedBtn) selectedCountLabel.Size = UDim2.new(0,56,0,28) selectedCountLabel.Position = UDim2.new(1,-62,0,4) selectedCountLabel.BackgroundTransparency = 1 selectedCountLabel.Font = Enum.Font.Gotham selectedCountLabel.TextSize = 13 selectedCountLabel.TextColor3 = Color3.fromRGB(220,220,220) selectedCountLabel.Text = "0" local assignedLabel = Instance.new("TextLabel", rightPane) assignedLabel.Position = UDim2.new(0,0,1,-84) assignedLabel.Size = UDim2.new(1,0,0,24) assignedLabel.BackgroundTransparency = 1 assignedLabel.Font = Enum.Font.Gotham assignedLabel.TextSize = 12 assignedLabel.Text = "Assigned: " assignedLabel.TextColor3 = Color3.fromRGB(200,200,200) local holdToggle = Instance.new("TextButton", rightPane) holdToggle.Position = UDim2.new(0,0,1,-52) holdToggle.Size = UDim2.new(0,120,0,28) holdToggle.BackgroundColor3 = Color3.fromRGB(44,44,60) holdToggle.Font = Enum.Font.Gotham holdToggle.Text = "Hold mode" holdToggle.TextSize = 12 holdToggle.TextColor3 = Color3.fromRGB(230,230,230) holdToggle.BorderSizePixel = 0 local intervalLabel = Instance.new("TextLabel", rightPane) intervalLabel.Position = UDim2.new(0,132,1,-52) intervalLabel.Size = UDim2.new(0,120,0,18) intervalLabel.BackgroundTransparency = 1 intervalLabel.Font = Enum.Font.Gotham intervalLabel.TextSize = 11 intervalLabel.Text = "Interval (s):" intervalLabel.TextColor3 = Color3.fromRGB(180,180,180) local intervalBox = Instance.new("TextBox", rightPane) intervalBox.Position = UDim2.new(0,132,1,-34) intervalBox.Size = UDim2.new(0,80,0,28) intervalBox.BackgroundColor3 = Color3.fromRGB(34,34,40) intervalBox.Text = "0.12" intervalBox.ClearTextOnFocus = false intervalBox.Font = Enum.Font.Gotham intervalBox.TextSize = 12 intervalBox.TextColor3 = Color3.fromRGB(230,230,230) local saveBtn = Instance.new("TextButton", rightPane) saveBtn.Position = UDim2.new(0,0,1, -4) saveBtn.Size = UDim2.new(0,86,0,30) saveBtn.Font = Enum.Font.Gotham saveBtn.Text = "Save" saveBtn.BackgroundColor3 = Color3.fromRGB(36,120,44) saveBtn.TextSize = 12 saveBtn.TextColor3 = Color3.fromRGB(240,240,240) saveBtn.BorderSizePixel = 0 local updateBtn = Instance.new("TextButton", rightPane) updateBtn.Position = UDim2.new(0,96,1,-4) updateBtn.Size = UDim2.new(0,86,0,30) updateBtn.Font = Enum.Font.Gotham updateBtn.Text = "Update" updateBtn.BackgroundColor3 = Color3.fromRGB(52,140,46) updateBtn.TextSize = 12 updateBtn.TextColor3 = Color3.fromRGB(240,240,240) updateBtn.BorderSizePixel = 0 local loadBtn = Instance.new("TextButton", rightPane) loadBtn.Position = UDim2.new(0,192,1,-4) loadBtn.Size = UDim2.new(0,120,0,30) loadBtn.Font = Enum.Font.Gotham loadBtn.Text = "Load Saved" loadBtn.BackgroundColor3 = Color3.fromRGB(60,60,84) loadBtn.TextSize = 12 loadBtn.TextColor3 = Color3.fromRGB(240,240,240) loadBtn.BorderSizePixel = 0 local fireBtn = Instance.new("TextButton", rightPane) fireBtn.Position = UDim2.new(0,324,1,-4) fireBtn.Size = UDim2.new(0,86,0,30) fireBtn.Font = Enum.Font.Gotham fireBtn.Text = "Fire Now" fireBtn.TextSize = 12 fireBtn.TextColor3 = Color3.fromRGB(240,240,240) fireBtn.BackgroundColor3 = Color3.fromRGB(80,40,40) fireBtn.BorderSizePixel = 0 local statusBar = Instance.new("TextLabel", frameMain) statusBar.Position = UDim2.new(0,14,1,-32) statusBar.Size = UDim2.new(1,-28,0,24) statusBar.BackgroundTransparency = 1 statusBar.Font = Enum.Font.Gotham statusBar.TextSize = 12 statusBar.TextColor3 = Color3.fromRGB(200,200,200) statusBar.Text = "Ready." -- -------------------- -- State (keeps older state variables) -- -------------------- local entries = {} local infos = {} local selectedInfo = nil local selectedSet = {} local capturingKey = false local capturingConn = nil local bindings = {} local pendingSaved = {} local multiSelectMode = false local NORMAL_BG = Color3.fromRGB(36,36,44) local HOVER_BG = Color3.fromRGB(46,46,68) local SELECT_BG = Color3.fromRGB(42,122,255) -- store current aim mode so RenderStepped update can reference _G.RKB_currentAimMode = aimDropdown.Text -- -------------------- -- createEntryForRemote must be defined BEFORE scanInventoryOnce uses it (fixed) -- -------------------- local function createEntryForRemote(remote) if not remote or not remote.Parent then return end if entries[remote] then return end local info = { remote = remote, lastArgs = {}, lastArgsText = "" } table.insert(infos, info) local frame = Instance.new("Frame") frame.Size = UDim2.new(1, -12, 0, 60) frame.BackgroundColor3 = NORMAL_BG frame.BorderSizePixel = 0 frame.Parent = leftScroll local nameLbl = Instance.new("TextLabel", frame) nameLbl.Size = UDim2.new(1, -12, 0, 22) nameLbl.Position = UDim2.new(0, 6, 0, 6) nameLbl.BackgroundTransparency = 1 nameLbl.Font = Enum.Font.GothamBold nameLbl.TextSize = 12 nameLbl.TextColor3 = Color3.fromRGB(230,230,230) local ok, fullname = pcall(function() return remote:GetFullName() end) nameLbl.Text = ok and fullname or tostring(remote.Name) local parentLbl = Instance.new("TextLabel", frame) parentLbl.Size = UDim2.new(1, -12, 0, 14) parentLbl.Position = UDim2.new(0,6,0,30) parentLbl.BackgroundTransparency = 1 parentLbl.Font = Enum.Font.Gotham parentLbl.TextSize = 11 parentLbl.TextColor3 = Color3.fromRGB(170,170,170) parentLbl.Text = "Parent: " .. tostring(remote.Parent and remote.Parent.Name or "") local btn = Instance.new("TextButton", frame) btn.Size = UDim2.new(1, -12, 1, -10) btn.Position = UDim2.new(0,6,0,5) btn.BackgroundTransparency = 1 btn.Text = "" btn.AutoButtonColor = true btn.MouseEnter:Connect(function() if multiSelectMode then if selectedSet[remote] then return end pcall(function() frame.BackgroundColor3 = Color3.fromRGB(58,142,255) end) else pcall(function() frame.BackgroundColor3 = HOVER_BG end) end end) btn.MouseLeave:Connect(function() if multiSelectMode then if selectedSet[remote] then pcall(function() frame.BackgroundColor3 = SELECT_BG end) else pcall(function() frame.BackgroundColor3 = NORMAL_BG end) end else pcall(function() frame.BackgroundColor3 = NORMAL_BG end) end end) btn.MouseButton1Click:Connect(function() if multiSelectMode then if selectedSet[remote] then selectedSet[remote] = nil pcall(function() frame.BackgroundColor3 = NORMAL_BG end) else selectedSet[remote] = true pcall(function() frame.BackgroundColor3 = SELECT_BG end) end local c = 0 for _ in pairs(selectedSet) do c = c + 1 end selectedCountLabel.Text = tostring(c) statusBar.Text = ("Selected %d remotes."):format(c) else for r,f in pairs(entries) do if f and f:IsA("Frame") then pcall(function() TweenService:Create(f, TweenInfo.new(0.12), {BackgroundColor3 = NORMAL_BG}):Play() end) end end pcall(function() TweenService:Create(frame, TweenInfo.new(0.12), {BackgroundColor3 = HOVER_BG}):Play() end) selectedInfo = info local ok2, full2 = pcall(function() return remote:GetFullName() end) lblRemote.Text = "Remote: " .. (ok2 and full2 or tostring(remote.Name)) lblParent.Text = "Parent: " .. tostring(remote.Parent and remote.Parent:GetFullName() or "") lblType.Text = "Type: " .. (remote:IsA("RemoteEvent") and "RemoteEvent" or "RemoteFunction") argsBox.Text = info.lastArgsText or "" statusBar.Text = "Selected remote: " .. (ok2 and full2 or tostring(remote.Name)) local found = nil; local count = 0 for keyEnum,bd in pairs(bindings) do local rlist = bd.remote if typeof(rlist) == "Instance" then if rlist == remote then found = keyEnumToName(keyEnum); count = 1; break end else for _, rr in ipairs(rlist or {}) do if rr == remote then found = keyEnumToName(keyEnum); count = #rlist; break end end end if found then break end end if found then assignedLabel.Text = ("Assigned: %s (remotes: %d)"):format(found, count) else assignedLabel.Text = "Assigned: " end end end) entries[remote] = frame end -- cleanup when remote removed (keeps multi-selection & bindings clean) local function handleRemoteRemoved(remote) if selectedSet[remote] then selectedSet[remote] = nil if selectedCountLabel then local c = 0 for _ in pairs(selectedSet) do c = c + 1 end selectedCountLabel.Text = tostring(c) end end for keyEnum, bd in pairs(bindings) do local rr = bd.remote if typeof(rr) == "Instance" then if rr == remote then bindings[keyEnum] = nil pcall(function() deleteSavedBinding(keyEnumToName(keyEnum)) end) end elseif type(rr) == "table" then local changed = false for i = #rr, 1, -1 do if rr[i] == remote then table.remove(rr, i) changed = true end end if changed then if #rr == 0 then bindings[keyEnum] = nil pcall(function() deleteSavedBinding(keyEnumToName(keyEnum)) end) else if bd.remotePaths and type(bd.remotePaths) == "table" then for i = #bd.remotePaths, 1, -1 do local path = bd.remotePaths[i] if path and path:match("%." .. remote.Name .. "$") then table.remove(bd.remotePaths, i) end end bd.remotePath = bd.remotePaths[1] end bd.remote = rr end end end end end -- scanning inventory and creating entries (uses createEntryForRemote defined above) local function scanInventoryOnce() for r,fr in pairs(entries) do if not r or not r.Parent then if fr and fr.Parent then fr:Destroy() end entries[r] = nil pcall(function() handleRemoteRemoved(r) end) end end local function scanContainer(container) if not container then return end for _, inst in ipairs(container:GetDescendants()) do if isRemote(inst) and not entries[inst] then createEntryForRemote(inst) end end end -- scan backpack and character (covers tools in both) scanContainer(backpack) scanContainer(character) end -- -------------------- -- Argument builder & firing (now supports placement modes and follows model) -- -------------------- local function buildArgsForBinding(bd) if not bd or not bd.remote then return {} end local args = {} local targetPos = nil if bd.mode == "Mouse" then targetPos = getMouseHitPos() elseif bd.mode == "NearestPlayer" then local pos,pl = getNearestPlayerPredictedPos(bd.predictionX, bd.predictionY) if pos then targetPos = pos end elseif bd.mode == "NearestHumanoid" then local pos,mdl = getNearestHumanoidPredictedPos(bd.predictionX, bd.predictionY) if pos then targetPos = pos end elseif bd.mode == "StraightForward" then local studs = tonumber(bd.placeStuds) or tonumber(placeStudsBox.Text) or placement.studs or 6 local forward = getLocalForwardVector() forward = Vector3.new(forward.X, 0, forward.Z) if forward.Magnitude == 0 then forward = Camera and Vector3.new(Camera.CFrame.LookVector.X, 0, Camera.CFrame.LookVector.Z) or Vector3.new(0,0,-1) end local base = getLocalReferencePos() local pos = base + (forward.Unit * studs) pos = Vector3.new(pos.X, base.Y, pos.Z) targetPos = pos elseif bd.mode == "CustomPlacement" then -- IMPORTANT: prefer following the selected model's live position (do not use static block) -- Use binding's stored placeLastPos if it exists, otherwise live selection from placement.selectedModel takes priority local pos = nil -- if there's a live selected model (user-selected during session), prefer that live model position if placement.selectedModel then local adornee = findModelAdornee(placement.selectedModel) if adornee then pos = adornee.Position end end -- if no live selected model or not available, try stored binding last pos if not pos and bd.placeLastPos and typeof(bd.placeLastPos) == "table" and #bd.placeLastPos == 3 then pos = Vector3.new(bd.placeLastPos[1], bd.placeLastPos[2], bd.placeLastPos[3]) end -- fallback to placement.lastPos if still no pos if not pos and placement.lastPos then pos = placement.lastPos end targetPos = pos end if targetPos then if bd.argFormat == "Vector3" or bd.argFormat == "Vector3 " then table.insert(args, targetPos) else table.insert(args, targetPos.X) table.insert(args, targetPos.Y) table.insert(args, targetPos.Z) end end if bd.extraArgs and #bd.extraArgs > 0 then for _,v in ipairs(bd.extraArgs) do table.insert(args, v) end end return args end local function fireBindingOnce(bd) if not bd or not bd.remote then return false, "no binding" end local args = buildArgsForBinding(bd) local ok, err = pcall(function() return safeCallRemote(bd.remote, args, bd.argFormat == "XYZ") end) if ok then return err else return false, err end end -- -------------------- -- Binding management (unchanged but extended to include place fields) -- -------------------- local function removeBindingByKey(keyEnum) if bindings[keyEnum] then local kn = keyEnumToName(keyEnum) if kn and settingsFolder:FindFirstChild("binding_"..kn) then settingsFolder:FindFirstChild("binding_"..kn):Destroy() end local bd = bindings[keyEnum] if bd and bd.active then bd.active = false end bindings[keyEnum] = nil end end local function removeBindingByRemote(remote) if not remote then return end local toRemove = {} for k,bd in pairs(bindings) do local rr = bd.remote if typeof(rr) == "Instance" then if rr == remote then table.insert(toRemove, k) end elseif type(rr) == "table" then for _,r in ipairs(rr) do if r == remote then table.insert(toRemove, k); break end end end end for _,k in ipairs(toRemove) do local kn = keyEnumToName(k) if kn then deleteSavedBinding(kn) end local bd = bindings[k] if bd and bd.active then bd.active = false end bindings[k] = nil end end local function removeBindingByRemoteList(remoteList) if not remoteList then return end if typeof(remoteList) == "Instance" then removeBindingByRemote(remoteList) return end if type(remoteList) ~= "table" then return end local seen = {} for _,r in ipairs(remoteList) do if not seen[r] then removeBindingByRemote(r); seen[r] = true end end end local function setBindingForKey(keyEnum, bd) if not keyEnum or not bd or not bd.remote then return false, "invalid args" end removeBindingByKey(keyEnum) removeBindingByRemoteList(bd.remote) bindings[keyEnum] = { remote = bd.remote, extraArgs = bd.extraArgs or {}, hold = bd.hold and true or false, interval = tonumber(bd.interval) or 0.12, mode = bd.mode or "Mouse", predictionX = tonumber(bd.predictionX) or 0, predictionY = tonumber(bd.predictionY) or 0, argFormat = bd.argFormat or "Vector3", placeStuds = bd.placeStuds or nil, placeLastPos = bd.placeLastPos or nil, placeStick = bd.placeStick and true or false, active = false, remotePath = bd.remotePath or (pcall(function() return (typeof(bd.remote)=="Instance" and bd.remote:GetFullName()) end) and (typeof(bd.remote)=="Instance" and bd.remote:GetFullName())) or "", remotePaths = bd.remotePaths or nil } return true end local function startBinding(keyEnum) local bd = bindings[keyEnum] if not bd or not bd.remote then return end if bd.hold then if bd.active then return end bd.active = true bd._co = coroutine.create(function() while bd.active do pcall(function() fireBindingOnce(bd) end) task.wait(math.max(0.01, tonumber(bd.interval) or 0.12)) end end) coroutine.resume(bd._co) else bd.active = not bd.active if bd.active then bd._co = coroutine.create(function() while bd.active do pcall(function() fireBindingOnce(bd) end) task.wait(math.max(0.01, tonumber(bd.interval) or 0.12)) end end) coroutine.resume(bd._co) else bd.active = false end end end local function stopBinding(keyEnum) local bd = bindings[keyEnum] if not bd then return end if bd.hold then bd.active = false end end -- -------------------- -- Input handling & UI callbacks (add placement capture) -- -------------------- local function clearSelectedBindingsAndSelection() local remotesToClear = {} for r,_ in pairs(selectedSet) do if r then table.insert(remotesToClear, r) end end local cleared = 0 for _,r in ipairs(remotesToClear) do pcall(function() removeBindingByRemote(r) end) selectedSet[r] = nil cleared = cleared + 1 end selectedCountLabel.Text = "0" assignedLabel.Text = "Assigned: " statusBar.Text = ("Cleared bindings for %d selected remotes."):format(cleared) end UserInputService.InputBegan:Connect(function(input, gp) if input.UserInputType == Enum.UserInputType.Keyboard then local code = input.KeyCode if code then if code == Enum.KeyCode.R then pcall(function() scanInventoryOnce() statusBar.Text = "Reloaded (hotkey R)." leftScroll.CanvasSize = UDim2.new(0,0,0, leftListLayout.AbsoluteContentSize.Y + 12) local saved = loadSavedBindingsIntoTable() for k, data in pairs(saved) do pcall(function() local ok, err = applySavedBinding(data) if ok then pendingSaved[k] = nil end end) end end) return end if code == Enum.KeyCode.Delete then clearSelectedBindingsAndSelection() return end if bindings[code] then startBinding(code) end end end end) UserInputService.InputEnded:Connect(function(input, gp) if input.UserInputType == Enum.UserInputType.Keyboard then local code = input.KeyCode if code and bindings[code] then stopBinding(code) end end end) aimDropdown.MouseButton1Click:Connect(function() local cur = aimDropdown.Text if cur == "Mouse" then aimDropdown.Text = "NearestPlayer" elseif cur == "NearestPlayer" then aimDropdown.Text = "NearestHumanoid" elseif cur == "NearestHumanoid" then aimDropdown.Text = "StraightForward" elseif cur == "StraightForward" then aimDropdown.Text = "CustomPlacement" else aimDropdown.Text = "Mouse" end _G.RKB_currentAimMode = aimDropdown.Text pcall(function() updatePlacementVisual(_G.RKB_currentAimMode) end) end) formatDropdown.MouseButton1Click:Connect(function() formatDropdown.Text = (formatDropdown.Text == "Vector3") and "XYZ" or "Vector3" end) holdToggle.MouseButton1Click:Connect(function() if holdToggle.Text == "Hold mode" then holdToggle.Text = "Toggle mode" holdToggle.BackgroundColor3 = Color3.fromRGB(68,44,68) else holdToggle.Text = "Hold mode" holdToggle.BackgroundColor3 = Color3.fromRGB(44,44,60) end end) -- placement click capture flow (selection follows model) local mouse = safeGetMouse() local clickConn = nil placeClickBtn.MouseButton1Click:Connect(function() if not mouse then mouse = safeGetMouse() end if not mouse then statusBar.Text = "Mouse not available"; return end statusBar.Text = "Click somewhere in the world to place/select (Esc to cancel)." placement.clickCapture = true local function cancelCapture() placement.clickCapture = false statusBar.Text = "Placement canceled." if clickConn then clickConn:Disconnect(); clickConn = nil end end local escConn escConn = UserInputService.InputBegan:Connect(function(inp, gp) if inp.UserInputType == Enum.UserInputType.Keyboard and inp.KeyCode == Enum.KeyCode.Escape then cancelCapture() escConn:Disconnect(); escConn = nil end end) clickConn = mouse.Button1Down:Connect(function() if not placement.clickCapture then return end local target = mouse.Target local hit = nil pcall(function() hit = mouse.Hit.Position end) if target and target.Parent and target.Parent:IsA("Model") then local model = target.Parent local hum = model:FindFirstChildOfClass("Humanoid") if hum and model.Name ~= player.Name then -- select the model (follow it directly) if placement.selectedModel and placement.selectedModel ~= model then clearSelectionBillboard(placement.selectedModel) end placement.selectedModel = model placement.stickToEntity = stickToggle.Text == "Stick: On" createSelectionBillboardForModel(model) local adornee = findModelAdornee(model) placement.lastPos = (adornee and adornee.Position) or placement.lastPos placementSelectedLabel.Text = "Selected placement: "..tostring(model.Name) statusBar.Text = "Selected entity: "..tostring(model.Name) else if hit then placement.lastPos = hit if placement.selectedModel then clearSelectionBillboard(placement.selectedModel) placement.selectedModel = nil end placementSelectedLabel.Text = "Selected placement: Custom position" statusBar.Text = ("Placed at: %.1f, %.1f, %.1f"):format(hit.X, hit.Y, hit.Z) end end else if hit then placement.lastPos = hit if placement.selectedModel then clearSelectionBillboard(placement.selectedModel) placement.selectedModel = nil end placementSelectedLabel.Text = "Selected placement: Custom position" statusBar.Text = ("Placed at: %.1f, %.1f, %.1f"):format(hit.X, hit.Y, hit.Z) end end placement.clickCapture = false if clickConn then clickConn:Disconnect(); clickConn = nil end if escConn then escConn:Disconnect(); escConn = nil end pcall(function() updatePlacementVisual(_G.RKB_currentAimMode) end) end) end) stickToggle.MouseButton1Click:Connect(function() if stickToggle.Text == "Stick: Off" then stickToggle.Text = "Stick: On" stickToggle.BackgroundColor3 = Color3.fromRGB(42,122,255) placement.stickToEntity = true else stickToggle.Text = "Stick: Off" stickToggle.BackgroundColor3 = Color3.fromRGB(44,44,60) placement.stickToEntity = false end placementSelectedLabel.Text = placement.selectedModel and ("Selected placement: "..tostring(placement.selectedModel.Name)) or "Selected placement: " pcall(function() updatePlacementVisual(_G.RKB_currentAimMode) end) end) placeStudsBox:GetPropertyChangedSignal("Text"):Connect(function() local v = tonumber(placeStudsBox.Text) if v and v > 0 then placement.studs = v end pcall(function() updatePlacementVisual(_G.RKB_currentAimMode) end) end) -- key capture flows (when binding, store placement fields) local function endCapture() capturingKey = false setKeyBtn.Text = "Set Keybind (single)" bindSelectedBtn.Text = "Bind Selected (multi)" statusBar.Text = "Ready." if capturingConn then capturingConn:Disconnect(); capturingConn = nil end end local function beginKeyCaptureForRemotes(remotesTable) if capturingKey then return end capturingKey = true setKeyBtn.Text = "Press key (Esc cancel)" bindSelectedBtn.Text = "Press key (Esc cancel)" statusBar.Text = "Waiting for key..." capturingConn = UserInputService.InputBegan:Connect(function(input, gp) if not capturingKey then return end if input.UserInputType == Enum.UserInputType.Keyboard then local code = input.KeyCode if code == Enum.KeyCode.Escape then endCapture(); return end local bd = { remote = (type(remotesTable)=="table" and (#remotesTable==1 and remotesTable[1] or remotesTable)) or remotesTable, extraArgs = parseArgsText(argsBox.Text), hold = (holdToggle.Text == "Hold mode"), interval = tonumber(intervalBox.Text) or 0.12, mode = aimDropdown.Text, predictionX = tonumber(predXBox.Text) or 0, predictionY = tonumber(predYBox.Text) or 0, argFormat = formatDropdown.Text, remotePath = nil, remotePaths = nil, placeStuds = tonumber(placeStudsBox.Text) or placement.studs, placeLastPos = (placement.lastPos and {placement.lastPos.X, placement.lastPos.Y, placement.lastPos.Z}) or nil, placeStick = placement.stickToEntity } if type(bd.remote) == "Instance" then local ok, fp = pcall(function() return bd.remote:GetFullName() end) if ok and fp then bd.remotePath = fp end elseif type(bd.remote) == "table" then bd.remotePaths = {} for _,r in ipairs(bd.remote) do local ok, fp = pcall(function() return r:GetFullName() end) if ok and fp then table.insert(bd.remotePaths, fp) end end bd.remotePath = bd.remotePaths[1] end setBindingForKey(code, bd) deleteSavedBinding(keyEnumToName(code)) assignedLabel.Text = "Assigned: " .. keyEnumToName(code) .. " (remotes: " .. (type(bd.remote)=="table" and #bd.remote or 1) .. ")" statusBar.Text = "Bound to key " .. keyEnumToName(code) endCapture() end end) end setKeyBtn.MouseButton1Click:Connect(function() if not selectedInfo or not selectedInfo.remote then statusBar.Text = "Select a remote first (single)"; return end beginKeyCaptureForRemotes(selectedInfo.remote) end) bindSelectedBtn.MouseButton1Click:Connect(function() local remotes = {} for r,_ in pairs(selectedSet) do if r and r.Parent then table.insert(remotes, r) end end if #remotes == 0 then statusBar.Text = "No remotes selected (toggle Multi-Select on, then click entries)"; return end beginKeyCaptureForRemotes(remotes) end) clearMultiBindsBtn.MouseButton1Click:Connect(function() clearSelectedBindingsAndSelection() end) -- multi-toggle behaviors multiToggle.MouseButton1Click:Connect(function() multiSelectMode = not multiSelectMode if multiSelectMode then multiToggle.Text = "Multi-Select: On" statusBar.Text = "Multi-Select ON — click entries to add/remove them (blue = selected)." for r,fr in pairs(entries) do if selectedSet[r] then fr.BackgroundColor3 = SELECT_BG end end else multiToggle.Text = "Multi-Select: Off" statusBar.Text = "Multi-Select OFF — inspector mode." for r,fr in pairs(entries) do if selectedSet[r] then fr.BackgroundColor3 = NORMAL_BG end end end end) clearSelectionBtn.MouseButton1Click:Connect(function() for r,fr in pairs(entries) do if selectedSet[r] and fr and fr.Parent then fr.BackgroundColor3 = NORMAL_BG end end selectedSet = {} selectedCountLabel.Text = "0" statusBar.Text = "Selection cleared." end) -- Save/Update/Load/Fire/Clear UI handlers (behaviour kept but now store placement fields) local function buildBindingDataFromUIForKey(keyName) if not keyName then return nil, "no key" end local data = { key = keyName, remotePath = (selectedInfo and pcall(function() return selectedInfo.remote:GetFullName() end) and selectedInfo.remote:GetFullName()) or "", extraArgsText = argsBox.Text or "", hold = (holdToggle.Text == "Hold mode"), interval = tonumber(intervalBox.Text) or 0.12, mode = aimDropdown.Text or "Mouse", predictionX = tonumber(predXBox.Text) or 0, predictionY = tonumber(predYBox.Text) or 0, argFormat = formatDropdown.Text or "Vector3", placeStuds = tonumber(placeStudsBox.Text) or placement.studs, placeLastPos = (placement.lastPos and {placement.lastPos.X, placement.lastPos.Y, placement.lastPos.Z}) or nil, placeStick = placement.stickToEntity } return data end function applySavedBinding(data) if not data or not data.key then return false, "invalid data" end local keyEnum = nameToKeyEnum(data.key) if not keyEnum then return false, "invalid key name " .. tostring(data.key) end local resolvedRemotes = {} if data.remotePaths and type(data.remotePaths) == "table" then for _,p in ipairs(data.remotePaths) do local inst = findInstanceByFullName(p) if inst then table.insert(resolvedRemotes, inst) end end elseif data.remotePath and data.remotePath ~= "" then local inst = findInstanceByFullName(data.remotePath) if inst then table.insert(resolvedRemotes, inst) end end if #resolvedRemotes == 0 then if data.remotePath and data.remotePath ~= "" then local short = data.remotePath:match("([^%.]+)$") if short then for _,inst in ipairs(backpack:GetDescendants()) do if isRemote(inst) and inst.Name == short then table.insert(resolvedRemotes, inst) end end for _,inst in ipairs(character:GetDescendants()) do if isRemote(inst) and inst.Name == short then table.insert(resolvedRemotes, inst) end end end end end if #resolvedRemotes == 0 then pendingSaved[data.key] = data return false, "remote(s) not found" end local px = tonumber(data.predictionX); local py = tonumber(data.predictionY) if px == nil and tonumber(data.prediction) then px = tonumber(data.prediction) end if py == nil and tonumber(data.prediction) then py = tonumber(data.prediction) end px = px or 0; py = py or 0 local bd = { remote = (#resolvedRemotes==1) and resolvedRemotes[1] or resolvedRemotes, extraArgs = parseArgsText(data.extraArgsText or ""), hold = data.hold and true or false, interval = tonumber(data.interval) or 0.12, mode = data.mode or "Mouse", predictionX = px, predictionY = py, argFormat = data.argFormat or "Vector3", placeStuds = tonumber(data.placeStuds) or nil, placeLastPos = data.placeLastPos or nil, placeStick = data.placeStick and true or false, remotePath = data.remotePath or "", remotePaths = data.remotePaths or nil } setBindingForKey(keyEnum, bd) return true end _G.applySavedBinding = applySavedBinding saveBtn.MouseButton1Click:Connect(function() if not selectedInfo or not selectedInfo.remote then statusBar.Text = "Select a remote first to Save"; return end local boundKey = nil for k,bd in pairs(bindings) do if bd.remote and ((typeof(bd.remote)=="Instance" and bd.remote == selectedInfo.remote) or (type(bd.remote)=="table" and table.find(bd.remote, selectedInfo.remote))) then boundKey = keyEnumToName(k); break end end if not boundKey then statusBar.Text = "No keybind for selected remote. Use Set Keybind first."; return end local data, err = buildBindingDataFromUIForKey(boundKey) if not data then statusBar.Text = "Save error: "..tostring(err); return end local ok, e = saveBindingToFolder(boundKey, data) if ok then statusBar.Text = "Saved binding for key "..boundKey else statusBar.Text = "Save failed: "..tostring(e) end end) updateBtn.MouseButton1Click:Connect(function() if not selectedInfo or not selectedInfo.remote then statusBar.Text = "Select a remote first."; return end local boundKey = nil for k,bd in pairs(bindings) do if bd.remote and ((typeof(bd.remote)=="Instance" and bd.remote == selectedInfo.remote) or (type(bd.remote) == "table" and table.find(bd.remote, selectedInfo.remote))) then boundKey = keyEnumToName(k); break end end if not boundKey then statusBar.Text = "No keybind to update. Use Set Keybind first."; return end local data, err = buildBindingDataFromUIForKey(boundKey) if not data then statusBar.Text = "Update error: "..tostring(err); return end local ok, e = saveBindingToFolder(boundKey, data) if ok then statusBar.Text = "Updated saved binding for "..boundKey else statusBar.Text = "Update failed: "..tostring(e) end end) loadBtn.MouseButton1Click:Connect(function() statusBar.Text = "Loading saved bindings..." local saved = loadSavedBindingsIntoTable() pendingSaved = {} local applied = 0 for keyName, data in pairs(saved) do local ok, err = applySavedBinding(data) if ok then applied = applied + 1 else pendingSaved[keyName] = data end end statusBar.Text = ("Loaded %d saved. Pending: %d"):format(applied, (function() local c=0; for _ in pairs(pendingSaved) do c=c+1 end; return c end)()) leftScroll.CanvasSize = UDim2.new(0,0,0, leftListLayout.AbsoluteContentSize.Y + 12) end) fireBtn.MouseButton1Click:Connect(function() if not selectedInfo or not selectedInfo.remote then statusBar.Text = "Select a remote first."; return end local bd = { remote = selectedInfo.remote, extraArgs = parseArgsText(argsBox.Text), mode = aimDropdown.Text, predictionX = tonumber(predXBox.Text) or 0, predictionY = tonumber(predYBox.Text) or 0, argFormat = formatDropdown.Text, placeStuds = tonumber(placeStudsBox.Text) or placement.studs, placeLastPos = (placement.lastPos and {placement.lastPos.X, placement.lastPos.Y, placement.lastPos.Z}) or nil, placeStick = placement.stickToEntity } local ok, err = safeCallRemote(bd.remote, buildArgsForBinding(bd), bd.argFormat == "XYZ") if ok then statusBar.Text = "Test fire success." else statusBar.Text = "Test fire failed: "..tostring(err) end end) local function clearBindingsForSelected() if not selectedInfo or not selectedInfo.remote then statusBar.Text = "Select a remote first."; return end local removed = false local toDelete = {} for k,bd in pairs(bindings) do local rr = bd.remote if typeof(rr) == "Instance" then if rr == selectedInfo.remote then table.insert(toDelete, k); removed = true end else for _,r in ipairs(rr or {}) do if r == selectedInfo.remote then table.insert(toDelete, k); removed = true; break end end end end for _,k in ipairs(toDelete) do local kn = keyEnumToName(k) if kn then deleteSavedBinding(kn) end bindings[k] = nil end if removed then assignedLabel.Text = "Assigned: "; statusBar.Text = "Cleared binding(s) for selected remote." else statusBar.Text = "No binding found for selected remote." end end local clearBindBtn = Instance.new("TextButton", rightPane) clearBindBtn.Position = UDim2.new(0,324,1,-84) clearBindBtn.Size = UDim2.new(0,86,0,28) clearBindBtn.Font = Enum.Font.Gotham clearBindBtn.Text = "Clear Bind" clearBindBtn.BackgroundColor3 = Color3.fromRGB(92,36,36) clearBindBtn.TextColor3 = Color3.fromRGB(240,240,240) clearBindBtn.BorderSizePixel = 0 clearBindBtn.TextSize = 12 clearBindBtn.MouseButton1Click:Connect(clearBindingsForSelected) reloadBtn.MouseButton1Click:Connect(function() pcall(function() scanInventoryOnce() statusBar.Text = "Remotes reloaded." leftScroll.CanvasSize = UDim2.new(0,0,0, leftListLayout.AbsoluteContentSize.Y + 12) local saved = loadSavedBindingsIntoTable() for k,data in pairs(saved) do local ok, err = applySavedBinding(data) if ok then pendingSaved[k] = nil end end end) end) local function resetToolsNow() statusBar.Text = "Resetting tools..." pcall(function() character = player.Character or player.CharacterAdded:Wait() for _,obj in ipairs(character:GetChildren()) do if obj:IsA("Tool") then pcall(function() obj.Parent = backpack end) task.wait(0.06) pcall(function() obj.Parent = character end) task.wait(0.06) end end for _,obj in ipairs(backpack:GetChildren()) do if obj:IsA("Tool") then pcall(function() obj.Parent = character end) task.wait(0.03) pcall(function() obj.Parent = backpack end) end end scanInventoryOnce() leftScroll.CanvasSize = UDim2.new(0,0,0, leftListLayout.AbsoluteContentSize.Y + 12) end) statusBar.Text = "Reset tools attempted; reloaded inventory." end resetToolsBtn.MouseButton1Click:Connect(resetToolsNow) -- -------------------- -- Periodic scan start & load saved -- -------------------- task.spawn(function() while true do pcall(function() scanInventoryOnce() for r,fr in pairs(entries) do if fr and fr.Parent then local lbl = fr:FindFirstChildOfClass("TextLabel") if lbl then local ok, full = pcall(function() return r:GetFullName() end) lbl.Text = ok and full or tostring(r.Name) end end end leftScroll.CanvasSize = UDim2.new(0,0,0, leftListLayout.AbsoluteContentSize.Y + 12) end) task.wait(1.0) end end) task.spawn(function() task.wait(0.6) local saved = loadSavedBindingsIntoTable() for k,data in pairs(saved) do local ok, err = applySavedBinding(data) if not ok then pendingSaved[k] = data end end statusBar.Text = "Ready — Multi-Select button under list. Toggle it, click entries to select." end) -- -------------------- -- Respawn handling & cleanup (keep visuals following new character) -- -------------------- player.CharacterAdded:Connect(function(char) character = char task.delay(0.25, function() pcall(function() backpack = player:FindFirstChild("Backpack") or backpack refreshHumanoidCache() scanInventoryOnce() local saved = loadSavedBindingsIntoTable() for k,data in pairs(saved) do local ok, err = applySavedBinding(data) if not ok then pendingSaved[k] = data end end leftScroll.CanvasSize = UDim2.new(0,0,0, leftListLayout.AbsoluteContentSize.Y + 12) statusBar.Text = "Respawned — reloaded inventory & saved bindings." end) end) task.delay(0.2, function() pcall(function() updatePlacementVisual(_G.RKB_currentAimMode) end) end) end) player.AncestryChanged:Connect(function(_, parent) if not parent then pcall(destroyPlacementVisual) end end) -- debug helpers _G.RKB_getBindings = function() return bindings end _G.RKB_reload = function() scanInventoryOnce(); statusBar.Text = "Manual reload (exposed)"; end _G.RKB_resetTools = resetToolsNow -- end of script