--[[ loadstring(game:HttpGet("https://gist.githubusercontent.com/hasanhluong-stack/13e9a9fd47f7e90e8e12127f23714967/raw/7472a0f6f6352af5ece95290ac58adc7ae9a7dea/Script"))() ]] local Players = game:GetService("Players") local UserInputService = game:GetService("UserInputService") local RunService = game:GetService("RunService") local TweenService = game:GetService("TweenService") local player = Players.LocalPlayer local playerGui = player:WaitForChild("PlayerGui") -- ================= Biến lưu trữ dữ liệu & Trạng thái ================= local lastTarget1, lastTarget2, lastDir local currentVec1, currentVec2 = Vector3.zero, Vector3.zero local listenState = 0 local tempStart1, tempStart2, tempEnd1, tempEnd2 local inputsLeft, inputsRight = {}, {} local settingsData = { repeatCount = 1, buildDir = Vector3.new(0, 1, 0), thickness = 1, buildDelay = 0.05, baseSize = "1x1", baseLayers = 2, baseOffset = 0.5, pillarHeight = 25, wallHeight = 10, wallLength = 5, autoSnapYaw = false, } local snapYawConnection = nil -- ================= Hàm hỗ trợ Làm tròn & Utility ================= local function round2(num) return num and math.floor(num * 100 + 0.5) / 100 or 0 end local function roundVec2(vec) return Vector3.new(round2(vec.X), round2(vec.Y), round2(vec.Z)) end local function formatNumStr(num) return string.format("%.2f", round2(num)) end local function formatTextBoxTo2Decimals(textBox) local num = tonumber(textBox.Text) if num then textBox.Text = formatNumStr(num) end end local function setVectorToInputs(inputs, vec, startIndex) startIndex = startIndex or 1 inputs[startIndex].Text = formatNumStr(vec.X) inputs[startIndex + 1].Text = formatNumStr(vec.Y) inputs[startIndex + 2].Text = formatNumStr(vec.Z) end local function parseVector3(str, defaultVec) if not str or str == "" then return defaultVec end local coords = {} for num in string.gmatch(str, "[^,]+") do local p = tonumber(num) if p then table.insert(coords, round2(p)) end end return #coords >= 3 and Vector3.new(coords[1], coords[2], coords[3]) or defaultVec end -- Hàm tạo UI Element nhanh để tránh lặp code Instance local function create(className, props) local inst = Instance.new(className) for k, v in pairs(props) do inst[k] = v end return inst end -- ================= ESP 4 vị trí ván ================= local plankESPFolder = create("Folder", { Name = "PlankPositionESP", Parent = workspace }) local plankESPParts = {} local function sameVector(a, b) return a and b and a.X == b.X and a.Y == b.Y and a.Z == b.Z end local function destroyPlankMarker(number) if plankESPParts[number] and plankESPParts[number].part then plankESPParts[number].part:Destroy() end plankESPParts[number] = nil end local function createPlankMarker(number, position) position = roundVec2(position) local existing = plankESPParts[number] if existing and existing.part and existing.part.Parent and sameVector(existing.position, position) then return end destroyPlankMarker(number) local part = create("Part", { Name = "ESP_Number_Part_" .. number, Anchored = true, CanCollide = false, CanTouch = false, CanQuery = false, Transparency = 1, Size = Vector3.new(0.2, 0.2, 0.2), CFrame = CFrame.new(position), Parent = plankESPFolder }) local billboard = create("BillboardGui", { Name = "ESP_Number_" .. number, Adornee = part, AlwaysOnTop = true, LightInfluence = 0, MaxDistance = math.huge, Size = UDim2.fromOffset(42, 42), StudsOffsetWorldSpace = Vector3.new(0, 0.15, 0), Enabled = true, Parent = part }) local label = create("TextLabel", { Name = "Number", BackgroundTransparency = 1, BorderSizePixel = 0, Size = UDim2.fromScale(1, 1), Font = Enum.Font.GothamBlack, Text = tostring(number), TextColor3 = Color3.fromRGB(255, 220, 60), TextSize = 23, TextStrokeColor3 = Color3.fromRGB(0, 0, 0), TextStrokeTransparency = 0, Parent = billboard }) plankESPParts[number] = { part = part, billboard = billboard, label = label, position = position } end local function getInputVector(inputs, startIndex) if not inputs then return nil end local x, y, z = tonumber(inputs[startIndex] and inputs[startIndex].Text), tonumber(inputs[startIndex+1] and inputs[startIndex+1].Text), tonumber(inputs[startIndex+2] and inputs[startIndex+2].Text) return (x and y and z) and roundVec2(Vector3.new(x, y, z)) or nil end local function refreshESPFromInputs() local positions = { getInputVector(inputsLeft, 1), getInputVector(inputsLeft, 4), getInputVector(inputsRight, 1), getInputVector(inputsRight, 4), } for i = 1, 4 do local pos = positions[i] if pos then local existing = plankESPParts[i] if existing and existing.part and existing.part.Parent then if not sameVector(existing.position, pos) then existing.part.CFrame = CFrame.new(pos) existing.position = pos end else createPlankMarker(i, pos) end else destroyPlankMarker(i) end end end -- ================= Hiệu ứng & Màu sắc ================= local TWEEN_FAST = TweenInfo.new(0.12, Enum.EasingStyle.Quad, Enum.EasingDirection.Out) local function tw(instance, tweenInfo, properties) local tween = TweenService:Create(instance, tweenInfo, properties) tween:Play() return tween end local THEME = { border = Color3.fromRGB(64, 71, 92), accentA = Color3.fromRGB(86, 163, 255) } local COLOR = { ink = Color3.fromRGB(20, 23, 31), surface = Color3.fromRGB(30, 34, 48), surface2 = Color3.fromRGB(38, 43, 61), border = Color3.fromRGB(58, 64, 85), text = Color3.fromRGB(242, 239, 234), textMuted = Color3.fromRGB(144, 152, 176), accent = Color3.fromRGB(232, 163, 61), stepBg = Color3.fromRGB(48, 54, 76), listening = Color3.fromRGB(200, 120, 30), baseplateBg = Color3.fromRGB(60, 110, 80), pillarBg = Color3.fromRGB(120, 70, 160), wallBg = Color3.fromRGB(180, 80, 60), settingsBg = Color3.fromRGB(25, 28, 40), offRed = Color3.fromRGB(160, 50, 50), onGreen = Color3.fromRGB(50, 160, 70), } local function addPress(button) local scale = create("UIScale", { Parent = button }) local function animate(input, targetScale) if input.UserInputType == Enum.UserInputType.MouseButton1 or input.UserInputType == Enum.UserInputType.Touch then tw(scale, TWEEN_FAST, { Scale = targetScale }) end end button.InputBegan:Connect(function(input) animate(input, 0.94) end) button.InputEnded:Connect(function(input) animate(input, 1) end) end -- ================= ScreenGui & Panels ================= local screenGui = create("ScreenGui", { Name = "FloatingPanelGui", ResetOnSpawn = false, ZIndexBehavior = Enum.ZIndexBehavior.Sibling, Parent = playerGui }) local panel = create("Frame", { Name = "Panel", AnchorPoint = Vector2.new(0.5, 0.5), Position = UDim2.fromScale(0.4, 0.5), Size = UDim2.fromOffset(480, 340), BackgroundColor3 = COLOR.surface, BorderSizePixel = 0, Visible = false, ZIndex = 10, Parent = screenGui }) create("UICorner", { CornerRadius = UDim.new(0, 10), Parent = panel }) create("UIStroke", { Color = COLOR.border, Thickness = 1, Parent = panel }) create("UIPadding", { PaddingTop = UDim.new(0, 10), PaddingBottom = UDim.new(0, 10), PaddingLeft = UDim.new(0, 12), PaddingRight = UDim.new(0, 12), Parent = panel }) local title = create("TextLabel", { Name = "TitleHeader", BackgroundTransparency = 1, Size = UDim2.new(1, 0, 0, 20), Font = Enum.Font.GothamBold, TextSize = 12, TextColor3 = COLOR.textMuted, TextXAlignment = Enum.TextXAlignment.Left, Text = "BuildPlank Auto Builder (Hold to Drag)", ZIndex = 11, Parent = panel }) -- Side GUI Settings local settingsPanel = create("Frame", { Name = "SettingsPanel", Size = UDim2.new(0, 240, 1, 0), Position = UDim2.new(1, 10, 0, 0), BackgroundColor3 = COLOR.settingsBg, BorderSizePixel = 0, ZIndex = 10, Parent = panel }) create("UICorner", { CornerRadius = UDim.new(0, 10), Parent = settingsPanel }) create("UIStroke", { Color = COLOR.border, Thickness = 1, Parent = settingsPanel }) create("UIPadding", { PaddingTop = UDim.new(0, 10), PaddingBottom = UDim.new(0, 10), PaddingLeft = UDim.new(0, 10), PaddingRight = UDim.new(0, 10), Parent = settingsPanel }) create("TextLabel", { BackgroundTransparency = 1, Size = UDim2.new(1, 0, 0, 20), Font = Enum.Font.GothamBold, TextSize = 13, TextColor3 = COLOR.accent, TextXAlignment = Enum.TextXAlignment.Left, Text = "⚙ Settings", ZIndex = 11, Parent = settingsPanel }) local settingsContent = create("ScrollingFrame", { BackgroundTransparency = 1, Size = UDim2.new(1, 0, 1, -25), Position = UDim2.new(0, 0, 0, 25), CanvasSize = UDim2.new(0, 0, 0, 500), ScrollBarThickness = 3, ScrollBarImageColor3 = COLOR.accent, BorderSizePixel = 0, ZIndex = 11, Parent = settingsPanel }) create("UIListLayout", { FillDirection = Enum.FillDirection.Vertical, Padding = UDim.new(0, 6), SortOrder = Enum.SortOrder.LayoutOrder, Parent = settingsContent }) local function createPairRow(layoutOrder) local row = create("Frame", { BackgroundTransparency = 1, Size = UDim2.new(1, -6, 0, 42), LayoutOrder = layoutOrder, ZIndex = 11, Parent = settingsContent }) create("UIListLayout", { FillDirection = Enum.FillDirection.Horizontal, Padding = UDim.new(0, 8), SortOrder = Enum.SortOrder.LayoutOrder, Parent = row }) return row end local function createSingleSettingItem(parent, labelText, defaultVal, widthScale, layoutOrder) local container = create("Frame", { BackgroundTransparency = 1, Size = UDim2.new(widthScale or 0.48, -4, 1, 0), LayoutOrder = layoutOrder, ZIndex = 11, Parent = parent }) create("TextLabel", { BackgroundTransparency = 1, Size = UDim2.new(1, 0, 0, 14), Font = Enum.Font.GothamMedium, TextSize = 9, TextColor3 = COLOR.textMuted, TextXAlignment = Enum.TextXAlignment.Left, Text = labelText, ZIndex = 11, Parent = container }) local boxFrame = create("Frame", { Size = UDim2.new(1, 0, 0, 24), Position = UDim2.new(0, 0, 0, 16), BackgroundColor3 = COLOR.surface2, BorderSizePixel = 0, ZIndex = 11, Parent = container }) create("UICorner", { CornerRadius = UDim.new(0, 5), Parent = boxFrame }) create("UIStroke", { Color = COLOR.border, Thickness = 1, Parent = boxFrame }) return create("TextBox", { BackgroundTransparency = 1, Size = UDim2.fromScale(1, 1), Font = Enum.Font.Gotham, TextSize = 10, TextColor3 = COLOR.text, Text = defaultVal, ClearTextOnFocus = false, ZIndex = 12, Parent = boxFrame }) end local function createToggleButton(parent, labelText, defaultState, layoutOrder) local container = create("Frame", { BackgroundTransparency = 1, Size = UDim2.new(1, -6, 0, 42), LayoutOrder = layoutOrder or 6, ZIndex = 11, Parent = parent }) create("TextLabel", { BackgroundTransparency = 1, Size = UDim2.new(1, 0, 0, 14), Font = Enum.Font.GothamMedium, TextSize = 9, TextColor3 = COLOR.textMuted, TextXAlignment = Enum.TextXAlignment.Left, Text = labelText, ZIndex = 11, Parent = container }) local btn = create("TextButton", { Size = UDim2.new(1, 0, 0, 24), Position = UDim2.new(0, 0, 0, 16), BackgroundColor3 = defaultState and COLOR.onGreen or COLOR.offRed, Font = Enum.Font.GothamBold, TextSize = 10, TextColor3 = COLOR.text, Text = defaultState and "Snap Yaw: ON" or "Snap Yaw: OFF", ZIndex = 11, Parent = container }) create("UICorner", { CornerRadius = UDim.new(0, 5), Parent = btn }) create("UIStroke", { Color = COLOR.border, Thickness = 1, Parent = btn }) return btn end -- Generates Settings UI Rows local row1, row2, row3, row4, row5 = createPairRow(1), createPairRow(2), createPairRow(3), createPairRow(4), createPairRow(5) local setLoopInput = createSingleSettingItem(row1, "Loop Count:", "1", 0.5) local setThickInput = createSingleSettingItem(row1, "Thickness (1-10):", "1", 0.5) local setSpeedInput = createSingleSettingItem(row2, "Speed (Delay):", "0.05", 0.5) local setDirInput = createSingleSettingItem(row2, "Vector (Dir):", "0, 1, 0", 0.5) local setBaseSizeInput = createSingleSettingItem(row3, "Base Size:", "1x1", 0.5) local setBaseLayerInput = createSingleSettingItem(row3, "Base Layers:", "2", 0.5) local setBaseOffsetInput = createSingleSettingItem(row4, "Base Offset:", "0.5", 0.5) local setPillarHeightInput= createSingleSettingItem(row4, "Pillar Height:", "25", 0.5) local setWallHeightInput = createSingleSettingItem(row5, "Wall Height (x0.5):", "10", 0.5) local setWallLengthInput = createSingleSettingItem(row5, "Wall Length:", "5", 0.5) local snapYawBtn = createToggleButton(settingsContent, "Snap Character (90°):", false, 6) local function updateSettingsFromUI() settingsData.repeatCount = tonumber(setLoopInput.Text) or 1 settingsData.buildDir = parseVector3(setDirInput.Text, Vector3.new(0, 1, 0)) settingsData.thickness = math.clamp(math.floor(tonumber(setThickInput.Text) or 1), 1, 10) settingsData.buildDelay = math.clamp(tonumber(setSpeedInput.Text) or 0.05, 0.001, 1) settingsData.baseSize = setBaseSizeInput.Text ~= "" and setBaseSizeInput.Text or "1x1" settingsData.baseLayers = math.clamp(tonumber(setBaseLayerInput.Text) or 2, 1, 2) settingsData.baseOffset = tonumber(setBaseOffsetInput.Text) or 0.5 settingsData.pillarHeight = tonumber(setPillarHeightInput.Text) or 25 settingsData.wallHeight = tonumber(setWallHeightInput.Text) or 10 settingsData.wallLength = tonumber(setWallLengthInput.Text) or 5 end for _, input in ipairs({setLoopInput, setDirInput, setThickInput, setSpeedInput, setBaseSizeInput, setBaseLayerInput, setBaseOffsetInput, setPillarHeightInput, setWallHeightInput, setWallLengthInput}) do input.FocusLost:Connect(updateSettingsFromUI) end -- Logic Snap Yaw snapYawBtn.MouseButton1Click:Connect(function() settingsData.autoSnapYaw = not settingsData.autoSnapYaw snapYawBtn.BackgroundColor3 = settingsData.autoSnapYaw and COLOR.onGreen or COLOR.offRed snapYawBtn.Text = settingsData.autoSnapYaw and "Snap Yaw: ON" or "Snap Yaw: OFF" if snapYawConnection then snapYawConnection:Disconnect() snapYawConnection = nil end if settingsData.autoSnapYaw then snapYawConnection = RunService.RenderStepped:Connect(function() local hrp = player.Character and player.Character:FindFirstChild("HumanoidRootPart") if hrp then local yaw = math.deg(math.atan2(-hrp.CFrame.LookVector.X, -hrp.CFrame.LookVector.Z)) hrp.CFrame = CFrame.new(hrp.Position) * CFrame.Angles(0, math.rad(math.round(yaw / 90) * 90), 0) end end) end end) -- Drag Logic cho Main Panel local panelDragging, panelDragStart, panelStartPos title.InputBegan:Connect(function(input) if input.UserInputType == Enum.UserInputType.MouseButton1 or input.UserInputType == Enum.UserInputType.Touch then panelDragging, panelDragStart, panelStartPos = true, input.Position, panel.Position input.Changed:Connect(function() if input.UserInputState == Enum.UserInputState.End then panelDragging = false end end) end end) UserInputService.InputChanged:Connect(function(input) if panelDragging and (input.UserInputType == Enum.UserInputType.MouseMovement or input.UserInputType == Enum.UserInputType.Touch) then local delta = input.Position - panelDragStart panel.Position = UDim2.new(panelStartPos.X.Scale, panelStartPos.X.Offset + delta.X, panelStartPos.Y.Scale, panelStartPos.Y.Offset + delta.Y) end end) -- Inputs Column Generation local function createSlotInput(parent, layoutOrder, placeholderText) local slot = create("Frame", { Name = "Slot", Size = UDim2.new(1, 0, 0, 30), LayoutOrder = layoutOrder, BackgroundColor3 = COLOR.surface2, BorderSizePixel = 0, ZIndex = 11, Parent = parent }) create("UICorner", { CornerRadius = UDim.new(0, 6), Parent = slot }) create("UIStroke", { Color = COLOR.border, Thickness = 1, Parent = slot }) local textBox = create("TextBox", { Name = "Input", BackgroundTransparency = 1, Size = UDim2.fromScale(1, 1), Font = Enum.Font.Gotham, TextSize = 11, TextColor3 = COLOR.text, PlaceholderColor3 = COLOR.textMuted, PlaceholderText = placeholderText, Text = "", ClearTextOnFocus = false, ZIndex = 12, Parent = slot }) textBox.FocusLost:Connect(function() formatTextBoxTo2Decimals(textBox) end) return textBox end local function createColumn6(labelText, xScale, storageTable) local column = create("Frame", { BackgroundTransparency = 1, Size = UDim2.new(0.48, 0, 0, 240), Position = UDim2.new(xScale, 0, 0, 25), ZIndex = 11, Parent = panel }) create("UIListLayout", { FillDirection = Enum.FillDirection.Vertical, Padding = UDim.new(0, 4), SortOrder = Enum.SortOrder.LayoutOrder, Parent = column }) create("TextLabel", { BackgroundTransparency = 1, Size = UDim2.new(1, 0, 0, 14), LayoutOrder = 0, Font = Enum.Font.GothamBold, TextSize = 11, TextColor3 = COLOR.accent, TextXAlignment = Enum.TextXAlignment.Left, Text = labelText, Parent = column }) local placeholders = { "Start X", "Start Y", "Start Z", "End X", "End Y", "End Z" } for i = 1, 6 do if i == 4 then create("TextLabel", { BackgroundTransparency = 1, Size = UDim2.new(1, 0, 0, 12), LayoutOrder = 3.5, Font = Enum.Font.GothamMedium, TextSize = 10, TextColor3 = COLOR.textMuted, TextXAlignment = Enum.TextXAlignment.Left, Text = "TO:", Parent = column }) end storageTable[i] = createSlotInput(column, i <= 3 and i or i + 1, placeholders[i]) end end createColumn6("Plank 1 (Left)", 0, inputsLeft) createColumn6("Plank 2 (Right)", 0.52, inputsRight) refreshESPFromInputs() RunService.RenderStepped:Connect(refreshESPFromInputs) -- ================= Bottom Action Buttons ================= local bottomFrame = create("Frame", { BackgroundTransparency = 1, Size = UDim2.new(1, 0, 0, 32), Position = UDim2.new(0, 0, 1, -32), ZIndex = 11, Parent = panel }) create("UIListLayout", { FillDirection = Enum.FillDirection.Horizontal, Padding = UDim.new(0, 4), SortOrder = Enum.SortOrder.LayoutOrder, Parent = bottomFrame }) local function createBottomBtn(text, sizeScale, bgCol, textCol, order) local btn = create("TextButton", { Size = UDim2.new(sizeScale, 0, 1, 0), LayoutOrder = order, BackgroundColor3 = bgCol, Font = Enum.Font.GothamBold, TextSize = 9, TextColor3 = textCol, Text = text, ZIndex = 11, Parent = bottomFrame }) create("UICorner", { CornerRadius = UDim.new(0, 6), Parent = btn }) return btn end local updateButton = createBottomBtn("Update", 0.16, COLOR.accent, COLOR.ink, 1) local actionButton = create("Frame", { Size = UDim2.new(0.24, 0, 1, 0), LayoutOrder = 2, BackgroundColor3 = COLOR.stepBg, BorderSizePixel = 0, ZIndex = 11, Parent = bottomFrame }) create("UICorner", { CornerRadius = UDim.new(0, 6), Parent = actionButton }) create("UIStroke", { ApplyStrokeMode = Enum.ApplyStrokeMode.Border, Color = COLOR.border, Thickness = 1, Transparency = 0.15, Parent = actionButton }) local actionSingleButton = create("TextButton", { Size = UDim2.fromScale(1, 1), BackgroundTransparency = 1, BorderSizePixel = 0, AutoButtonColor = false, Font = Enum.Font.GothamBold, TextSize = 9, TextColor3 = COLOR.text, Text = "Record Size", ZIndex = 12, Parent = actionButton }) local actionUndoButton = create("TextButton", { Size = UDim2.new(0.5, 0, 1, 0), BackgroundColor3 = COLOR.stepBg, BorderSizePixel = 0, AutoButtonColor = false, Font = Enum.Font.GothamBold, TextSize = 9, TextColor3 = COLOR.text, Text = "Undo", ZIndex = 12, Visible = false, Parent = actionButton }) local actionContinueButton = create("TextButton", { Size = UDim2.new(0.5, 0, 1, 0), Position = UDim2.new(0.5, 0, 0, 0), BackgroundColor3 = COLOR.accent, BorderSizePixel = 0, AutoButtonColor = false, Font = Enum.Font.GothamBold, TextSize = 9, TextColor3 = COLOR.ink, Text = "Continue", ZIndex = 12, Visible = false, Parent = actionButton }) create("UICorner", { CornerRadius = UDim.new(0, 6), Parent = actionUndoButton }) create("UICorner", { CornerRadius = UDim.new(0, 6), Parent = actionContinueButton }) local actionDivider = create("Frame", { Size = UDim2.new(0, 1, 1, -6), Position = UDim2.new(0.5, 0, 0, 3), BackgroundColor3 = COLOR.border, BackgroundTransparency = 0.35, BorderSizePixel = 0, ZIndex = 13, Visible = false, Parent = actionButton }) local function setActionSingle(text, backgroundColor, textColor) actionSingleButton.Visible = true actionSingleButton.Text = text or "" actionSingleButton.TextColor3 = textColor or COLOR.text actionButton.BackgroundColor3 = backgroundColor or COLOR.stepBg actionUndoButton.Visible, actionContinueButton.Visible, actionDivider.Visible = false, false, false end local function setActionSplit(backgroundLeft, backgroundRight, continueText) actionSingleButton.Visible = false actionUndoButton.Visible, actionContinueButton.Visible, actionDivider.Visible = true, true, true actionUndoButton.BackgroundColor3 = backgroundLeft or COLOR.stepBg actionContinueButton.BackgroundColor3 = backgroundRight or COLOR.accent actionContinueButton.Text = continueText or "Continue" actionButton.BackgroundColor3 = backgroundLeft or COLOR.stepBg end local baseplateButton = createBottomBtn("Baseplate", 0.2, COLOR.baseplateBg, COLOR.text, 3) local pillarButton = createBottomBtn("Build Pillar", 0.18, COLOR.pillarBg, COLOR.text, 4) local wallButton = createBottomBtn("Build Wall", 0.18, COLOR.wallBg, COLOR.text, 5) -- ================= Metamethod Hook ================= local oldNamecall oldNamecall = hookmetamethod(game, "__namecall", newcclosure(function(self, ...) local method = getnamecallmethod() local args = {...} if (method == "FireServer" or method == "InvokeServer") and self.Name == "BuildPlank" then if #args >= 2 and typeof(args[1]) == "Vector3" and typeof(args[2]) == "Vector3" then local v1, v2 = roundVec2(args[1]), roundVec2(args[2]) currentVec1, currentVec2 = v1, v2 setVectorToInputs(inputsLeft, v1, 1) setVectorToInputs(inputsRight, v2, 1) if #args == 5 then lastTarget1, lastTarget2, lastDir = args[3], args[4], args[5] else lastDir = args[3] end if listenState == 1 then tempStart1, tempStart2 = v1, v2 listenState = 2 setActionSplit(COLOR.surface2, COLOR.accent, "Continue") elseif listenState == 3 then tempEnd1, tempEnd2 = v1, v2 local altEnd = (tempEnd1 + tempEnd2) * 0.5 setVectorToInputs(inputsLeft, tempStart1, 4) setVectorToInputs(inputsRight, altEnd, 4) listenState = 4 setActionSplit(COLOR.surface2, COLOR.accent, "Create") end args[1], args[2] = v1, v2 end end return oldNamecall(self, unpack(args)) end)) -- ================= Build Executions ================= local function ensureBuildContext(hammer, event, timeout) if lastTarget1 and lastTarget2 then return true end timeout = timeout or 1.0 pcall(function() if hammer and hammer:IsA("Tool") then hammer:Activate() end end) local deadline = os.clock() + timeout while os.clock() < deadline do if lastTarget1 and lastTarget2 then return true end task.wait() end return lastTarget1 ~= nil and lastTarget2 ~= nil end local function executeBuild(start1, end1, start2, end2, callback) updateSettingsFromUI() local char = player.Character local hammer = char and char:FindFirstChild("Hammer") local event = hammer and hammer:FindFirstChild("BuildPlank") if not event or (not lastTarget1 and not ensureBuildContext(hammer, event, 1.0)) then if callback then callback(false, not event and "No Hammer!" or "BuildPlank context not ready!") end return end local diff1, diff2 = end1 - start1, end2 - start2 local maxDist = math.max(math.abs(diff1.X), math.abs(diff1.Y), math.abs(diff1.Z), math.abs(diff2.X), math.abs(diff2.Y), math.abs(diff2.Z)) local steps = math.max(1, math.floor((maxDist / 0.5) + 0.5)) local finalDir = settingsData.buildDir or lastDir or Vector3.new(0, 1, 0) task.spawn(function() for _ = 1, settingsData.repeatCount do local prevP1, prevP2 for i = 0, steps do local alpha = i / steps local curr1, curr2 = roundVec2(start1:Lerp(end1, alpha)), roundVec2(start2:Lerp(end2, alpha)) local function firePlank(p1, p2) if lastTarget1 and lastTarget2 then event:FireServer(p1, p2, lastTarget1, lastTarget2, finalDir) return true end return false end if not firePlank(curr1, curr2) then if callback then callback(false, "BuildPlank context lost!") end return end local thickness = math.clamp(math.floor(settingsData.thickness or 1), 1, 10) if thickness >= 2 and prevP1 and prevP2 then for t = 1, thickness - 1 do local ratio = t / thickness firePlank(roundVec2(prevP1:Lerp(curr1, ratio)), roundVec2(prevP2:Lerp(curr2, ratio))) end end prevP1, prevP2 = curr1, curr2 task.wait(settingsData.buildDelay) end task.wait(0.05) end if callback then callback(true) end end) end -- Helper lấy phẳng Character Look/Right Vector local function getCharOrientation(hrp) local rawLook = hrp.CFrame.LookVector local flatLook = Vector3.new(rawLook.X, 0, rawLook.Z) flatLook = flatLook.Magnitude < 0.001 and Vector3.new(0, 0, -1) or flatLook.Unit return flatLook, Vector3.new(-flatLook.Z, 0, flatLook.X) end -- Helper kiểm tra Nhân vật local function getHrpAndHumanoid(btn, defaultText) local char = player.Character local hrp, humanoid = char and char:FindFirstChild("HumanoidRootPart"), char and char:FindFirstChildOfClass("Humanoid") if not hrp or not humanoid then btn.Text = "No Char!" task.delay(1, function() btn.Text = defaultText end) return nil, nil end return hrp, humanoid end -- ================= Logic các Nút Xây ================= updateButton.MouseButton1Click:Connect(function() for i = 1, 6 do formatTextBoxTo2Decimals(inputsLeft[i]) formatTextBoxTo2Decimals(inputsRight[i]) end local start1 = Vector3.new(tonumber(inputsLeft[1].Text) or 0, tonumber(inputsLeft[2].Text) or 0, tonumber(inputsLeft[3].Text) or 0) local end1 = Vector3.new(tonumber(inputsLeft[4].Text) or start1.X, tonumber(inputsLeft[5].Text) or start1.Y, tonumber(inputsLeft[6].Text) or start1.Z) local start2 = Vector3.new(tonumber(inputsRight[1].Text) or 0, tonumber(inputsRight[2].Text) or 0, tonumber(inputsRight[3].Text) or 0) local end2 = Vector3.new(tonumber(inputsRight[4].Text) or start2.X, tonumber(inputsRight[5].Text) or start2.Y, tonumber(inputsRight[6].Text) or start2.Z) refreshESPFromInputs() executeBuild(start1, end1, start2, end2, function(success, msg) updateButton.Text = success and "Done!" or (msg or "Error!") task.delay(1, function() updateButton.Text = "Update" end) end) end) baseplateButton.MouseButton1Click:Connect(function() updateSettingsFromUI() local hrp, humanoid = getHrpAndHumanoid(baseplateButton, "Baseplate") if not hrp then return end local rows, cols = 1, 1 local rStr, cStr = string.match(settingsData.baseSize or "", "(%d+)[xX](%d+)") if rStr and cStr then rows, cols = math.max(1, tonumber(rStr) or 1), math.max(1, tonumber(cStr) or 1) else local singleNum = string.match(settingsData.baseSize or "", "%d+") if singleNum then rows = math.max(1, tonumber(singleNum) or 1); cols = rows end end baseplateButton.Text = "Calculating..." local footPos = hrp.Position - Vector3.new(0, (hrp.Size.Y / 2) + humanoid.HipHeight + settingsData.baseOffset, 0) local curX, curY, curZ = math.floor((footPos.X / 2) + 0.5) * 2, math.floor((footPos.Y / 2) + 0.5) * 2, math.floor((footPos.Z / 2) + 0.5) * 2 local totalWidthX, totalWidthZ = rows * 6, cols * 6 local xCount, zCount = math.ceil(totalWidthX / 2), math.ceil(totalWidthZ / 2) local flatLook, rightVector = getCharOrientation(hrp) local baseCenter = Vector3.new(curX, curY, curZ) local halfWidthX, halfWidthZ = totalWidthX * 0.5, totalWidthZ * 0.5 task.spawn(function() local function buildLayer(layerNum, isLayer2) baseplateButton.Text = string.format("Layer %d (%dx%d)...", layerNum, rows, cols) local count = isLayer2 and xCount or zCount for i = 0, count - 1 do local l1 = (isLayer2 and -halfWidthX or -halfWidthZ) + (i * 2) local l2 = math.min(l1 + 2, isLayer2 and halfWidthX or halfWidthZ) if l1 > (isLayer2 and halfWidthX or halfWidthZ) - 2 then l1 = (isLayer2 and halfWidthX or halfWidthZ) - 2 end local dir1 = isLayer2 and rightVector or flatLook local dir2 = isLayer2 and flatLook or rightVector local span = isLayer2 and halfWidthZ or halfWidthX local c1, c2 = baseCenter + dir1 * l1, baseCenter + dir1 * l2 local s1, e1 = c1 - dir2 * span, c1 + dir2 * span local s2, e2 = c2 - dir2 * span, c2 + dir2 * span setVectorToInputs(inputsLeft, s1, 1); setVectorToInputs(inputsLeft, e1, 4) setVectorToInputs(inputsRight, s2, 1); setVectorToInputs(inputsRight, e2, 4) local completedEvent = Instance.new("BindableEvent") executeBuild(s1, e1, s2, e2, function() completedEvent:Fire() end) completedEvent.Event:Wait() completedEvent:Destroy() task.wait(0.02) end end buildLayer(1, false) if settingsData.baseLayers >= 2 then buildLayer(2, true) end baseplateButton.Text = "Completed!" task.delay(1, function() baseplateButton.Text = "Baseplate" end) end) end) pillarButton.MouseButton1Click:Connect(function() updateSettingsFromUI() local hrp, humanoid = getHrpAndHumanoid(pillarButton, "Build Pillar") if not hrp then return end pillarButton.Text = "Building..." local footPos = roundVec2(hrp.Position - Vector3.new(0, (hrp.Size.Y / 2) + humanoid.HipHeight, 0)) local _, rightVector = getCharOrientation(hrp) local centerPos = Vector3.new(round2(footPos.X), round2(footPos.Y), round2(footPos.Z)) local pos1, pos2 = centerPos - rightVector, centerPos + rightVector local start1 = Vector3.new(round2(pos1.X), round2(footPos.Y), round2(pos1.Z)) local end1 = Vector3.new(round2(pos1.X), round2(footPos.Y + settingsData.pillarHeight), round2(pos1.Z)) local start2 = Vector3.new(round2(pos2.X), round2(footPos.Y), round2(pos2.Z)) local end2 = Vector3.new(round2(pos2.X), round2(footPos.Y + settingsData.pillarHeight), round2(pos2.Z)) setVectorToInputs(inputsLeft, start1, 1); setVectorToInputs(inputsLeft, end1, 4) setVectorToInputs(inputsRight, start2, 1); setVectorToInputs(inputsRight, end2, 4) executeBuild(start1, end1, start2, end2, function(success, msg) pillarButton.Text = success and "Completed!" or (msg or "Error!") task.delay(1, function() pillarButton.Text = "Build Pillar" end) end) end) wallButton.MouseButton1Click:Connect(function() updateSettingsFromUI() local hrp, humanoid = getHrpAndHumanoid(wallButton, "Build Wall") if not hrp then return end wallButton.Text = "Building..." local footPos = roundVec2(hrp.Position - Vector3.new(0, (hrp.Size.Y / 2) + humanoid.HipHeight, 0)) local wallHeightOffset, halfLength = settingsData.wallHeight * 0.5, settingsData.wallLength * 0.5 local _, rightVector = getCharOrientation(hrp) local lengthVec = rightVector * halfLength local pos1, pos2 = footPos - lengthVec, footPos + lengthVec local start1 = Vector3.new(round2(pos1.X), round2(footPos.Y), round2(pos1.Z)) local end1 = Vector3.new(round2(pos1.X), round2(footPos.Y + wallHeightOffset), round2(pos1.Z)) local start2 = Vector3.new(round2(pos2.X), round2(footPos.Y), round2(pos2.Z)) local end2 = Vector3.new(round2(pos2.X), round2(footPos.Y + wallHeightOffset), round2(pos2.Z)) setVectorToInputs(inputsLeft, start1, 1); setVectorToInputs(inputsLeft, end1, 4) setVectorToInputs(inputsRight, start2, 1); setVectorToInputs(inputsRight, end2, 4) executeBuild(start1, end1, start2, end2, function(success, msg) wallButton.Text = success and "Completed!" or (msg or "Error!") task.delay(1, function() wallButton.Text = "Build Wall" end) end) end) -- ================= Logic Quy Trình Lắng Nghe (Action State Machine) ================= local function resetActionButton() listenState = 0 setActionSingle("Record Size", COLOR.stepBg, COLOR.text) tempStart1, tempStart2, tempEnd1, tempEnd2 = nil, nil, nil, nil end actionUndoButton.MouseButton1Click:Connect(function() if listenState == 2 then resetActionButton() elseif listenState == 4 then tempEnd1, tempEnd2 = nil, nil listenState = 2 setActionSingle("End Position", COLOR.surface2, COLOR.text) end end) actionContinueButton.MouseButton1Click:Connect(function() if listenState == 2 then listenState = 3 setActionSingle("Listening End...", COLOR.listening, COLOR.text) elseif listenState == 4 then setActionSingle("Create", COLOR.accent, COLOR.ink) listenState = 5 end end) actionSingleButton.MouseButton1Click:Connect(function() if listenState == 0 then listenState = 1 setActionSingle("Listening Start...", COLOR.listening, COLOR.text) elseif listenState == 2 or listenState == 3 then listenState = 3 setActionSingle("Listening End...", COLOR.listening, COLOR.text) elseif listenState == 5 then if not tempStart1 or not tempEnd1 or not tempStart2 or not tempEnd2 then setActionSingle("Missing Pos!", COLOR.stepBg, COLOR.text) task.delay(1, function() if listenState == 5 then setActionSingle("Create", COLOR.accent, COLOR.ink) end end) return end setActionSingle("Building...", COLOR.accent, COLOR.ink) executeBuild(tempStart1, tempEnd1, tempStart2, tempEnd2, function(success, msg) setActionSingle(success and "Completed!" or (msg or "Error!"), COLOR.accent, COLOR.ink) task.wait(success and 0.8 or 1) resetActionButton() end) end end) -- ================= Menu Handle Toggle & Drag ================= local handle = create("TextButton", { Name = "Handle", Size = UDim2.fromOffset(50, 32), Position = UDim2.new(1, -70, 1, -50), BackgroundColor3 = COLOR.ink, BorderSizePixel = 0, AutoButtonColor = false, Text = "", ZIndex = 20, Parent = screenGui }) create("UICorner", { CornerRadius = UDim.new(0, 8), Parent = handle }) local handleStroke = create("UIStroke", { Name = "HandleBorder", ApplyStrokeMode = Enum.ApplyStrokeMode.Border, Color = THEME.border, Thickness = 2, Transparency = 0, Parent = handle }) for _, btn in ipairs({handle, actionSingleButton, actionUndoButton, actionContinueButton}) do addPress(btn) end local dotsHolder = create("Frame", { BackgroundTransparency = 1, Size = UDim2.fromOffset(16, 10), Position = UDim2.new(0.5, -8, 0.5, -5), ZIndex = 21, Parent = handle }) create("UIGridLayout", { CellSize = UDim2.fromOffset(3, 3), CellPadding = UDim2.fromOffset(3, 3), FillDirectionMaxCells = 3, Parent = dotsHolder }) local dots = {} for i = 1, 6 do local dot = create("Frame", { Size = UDim2.fromOffset(3, 3), BackgroundColor3 = COLOR.textMuted, BorderSizePixel = 0, ZIndex = 21, Parent = dotsHolder }) create("UICorner", { CornerRadius = UDim.new(1, 0), Parent = dot }) dots[i] = dot end local panelOpen = false local function setOpen(open) panelOpen = open panel.Visible = open tw(handleStroke, TWEEN_FAST, { Color = open and THEME.accentA or THEME.border }) for _, dot in ipairs(dots) do tw(dot, TWEEN_FAST, { BackgroundColor3 = open and THEME.accentA or COLOR.textMuted }) end end local dragging, moved, dragInput, dragStart, startPos = false, false local DRAG_THRESHOLD = 5 handle.InputBegan:Connect(function(input) if input.UserInputType == Enum.UserInputType.MouseButton1 or input.UserInputType == Enum.UserInputType.Touch then dragging, moved, dragStart, startPos = true, false, input.Position, handle.Position input.Changed:Connect(function() if input.UserInputState == Enum.UserInputState.End then dragging = false if not moved then setOpen(not panelOpen) end end end) end end) handle.InputChanged:Connect(function(input) if input.UserInputType == Enum.UserInputType.MouseMovement or input.UserInputType == Enum.UserInputType.Touch then dragInput = input end end) UserInputService.InputChanged:Connect(function(input) if dragging and input == dragInput then local delta = input.Position - dragStart if not moved and delta.Magnitude > DRAG_THRESHOLD then moved = true end if moved then handle.Position = UDim2.new(startPos.X.Scale, startPos.X.Offset + delta.X, startPos.Y.Scale, startPos.Y.Offset + delta.Y) end end end)