--[[ woodcarving_perfect.luau — BUILD 2026-10-04b Carve Wood (place 82712304391069): carves the log on your Wood Lathe to exactly the target shape → 100% accuracy. How it works (from the decompiled client): • LatheController keeps Cylinder.Profile (your log) and AccuracyCalculator.TargetProfile (the target). Accuracy = Progress × (1 − overcut penalty); every slice == target → 100. • WoodCarving:CompleteLatheWork() sends SaveCarvedWood { Serialized = your log, TargetSerialized = the client-generated target, ... }, so matching radii is all that counts. • We cut the radii with Profile:SetRadius + Cylinder:UpdateSlices (same path the chisel uses) and set HasModifiedWood so the game's own Confirm button works. Finding the lathe (no per-frame / periodic memory scans): 1. Hook LatheController.Update + WoodCarving.RenderStep through require() → the game hands us `self` every frame for free. 2. Fallback if the hook never fires: ONE getgc pass when the lathe's "TargetGhostMesh" appears (i.e. once per lathe entry), never on a timer. Usage: run it, sit at the lathe. Each log is carved down to the target over CARVE_SECONDS, then press the game's Confirm (or set AUTO_CONFIRM = true). Carve Next works too. Toggle on/off: TOGGLE_KEY. Re-running the script replaces the old instance. ]] local BUILD = "2026-10-04b" -- ── config ───────────────────────────────────────────────────────────────── local CFG = { CARVE_SECONDS = 6, -- time to cut a log from its current shape down to the target (0 = instant) STEP_HZ = 15, -- carve + mesh updates per second (lower = lighter on FPS, carving looks choppier) ONLY_REDUCE = true, -- true: never add wood back (like a real chisel). Slices you already -- overcut stay overcut and are reported. false: also raise them to target. AUTO_CONFIRM = false, -- true: call the game's CompleteLatheWork() once a log hits 100% AUTO_CONFIRM_DELAY = 0.75, -- seconds to wait at 100% before auto-confirming TOGGLE_KEY = Enum.KeyCode.RightBracket, VERBOSE = true, } local TAG = "[wcperfect " .. BUILD .. "]" local function log(...) print(TAG, ...) end local function vlog(...) if CFG.VERBOSE then print(TAG, ...) end end -- stop a previous run local G = getgenv and getgenv() or _G if G.__WCPerfect and G.__WCPerfect.Stop then pcall(G.__WCPerfect.Stop) end local RunService = game:GetService("RunService") local UserInputService = game:GetService("UserInputService") local Players = game:GetService("Players") local state = { Enabled = true, Lathe = nil, -- LatheController instance Carving = nil, -- WoodCarving client instance (owns CompleteLatheWork) Piece = nil, -- per-workpiece bookkeeping Accum = 0, LastHookCall = 0, Conns = {}, Unhooks = {}, } -- ── carve logic ──────────────────────────────────────────────────────────── local function getProfiles(lathe) if lathe.Destroyed or lathe.WoodTransition ~= nil then return nil end local cyl = lathe.Cylinder local calc = lathe.AccuracyCalculator if type(cyl) ~= "table" or cyl.Destroyed or type(calc) ~= "table" then return nil end local cur = cyl.Profile local tgt = calc.TargetProfile if type(tgt) == "table" and tgt.Profile then tgt = tgt.Profile end if type(cur) ~= "table" or type(tgt) ~= "table" or type(cur.Radii) ~= "table" or type(tgt.Radii) ~= "table" then return nil end return cyl, cur, tgt, calc end local function newPiece(cur, tgt, calc) local n = math.min(cur.SliceCount, tgt.SliceCount) local maxGap, overcut = 0, 0 local tol = calc.Tolerance or 0 for i = 1, n do local gap = cur.Radii[i] - tgt.Radii[i] local need = CFG.ONLY_REDUCE and gap or math.abs(gap) if need > maxGap then maxGap = need end if -gap > tol then overcut += 1 end end local speed = CFG.CARVE_SECONDS > 0 and (maxGap / CFG.CARVE_SECONDS) or math.huge vlog(("new log: %d slices, max cut %.3f, speed %.3f/s, already-overcut slices %d%s"):format( n, maxGap, speed == math.huge and 0 or speed, overcut, (overcut > 0 and CFG.ONLY_REDUCE) and " (ONLY_REDUCE=true → those stay; max accuracy < 100)" or "" )) return { Cur = cur, Tgt = tgt, N = n, Speed = speed, Done = false, DoneAt = nil, Confirmed = false, Started = os.clock() } end local modified = {} local function step(lathe, dt) local cyl, cur, tgt, calc = getProfiles(lathe) if not cyl then return end local p = state.Piece if not p or p.Cur ~= cur or p.Tgt ~= tgt then p = newPiece(cur, tgt, calc) state.Piece = p state.Accum = 0 end if p.Done then return end -- throttle: only cut + rebuild the mesh STEP_HZ times per second state.Accum += dt local interval = 1 / math.max(1, CFG.STEP_HZ) if state.Accum < interval then return end local budget = p.Speed * state.Accum state.Accum = 0 local count = 0 local eps = cur.ChangeEpsilon or 1e-5 table.clear(modified) local radii, tradii = cur.Radii, tgt.Radii for i = 1, p.N do local r, t = radii[i], tradii[i] local nr if r > t then nr = math.max(t, r - budget) elseif r < t and not CFG.ONLY_REDUCE then nr = math.min(t, r + budget) end if nr then if cur:SetRadius(i, nr) then count += 1 modified[count] = i elseif math.abs(nr - t) <= eps then radii[i] = t -- snap the last sub-epsilon bit so it equals the target exactly end end end if count > 0 then pcall(cyl.UpdateSlices, cyl, modified, count) lathe.HasModifiedWood = true return end -- nothing left to cut → done p.Done = true p.DoneAt = os.clock() local res = calc:Calculate() local msg = ("log finished in %.1fs: accuracy %.2f%% (max %.2f%%, progress %.4f, overcut slices %d)"):format( p.DoneAt - p.Started, res.Accuracy, res.MaximumAccuracy, res.Progress, math.floor(res.RuinedSliceFraction * res.SliceCount + 0.5) ) log(msg) if setclipboard then pcall(setclipboard, TAG .. " " .. msg) end end local function tryAutoConfirm() local p = state.Piece if not (CFG.AUTO_CONFIRM and p and p.Done and not p.Confirmed and p.DoneAt) then return end if os.clock() - p.DoneAt < CFG.AUTO_CONFIRM_DELAY then return end local c = state.Carving if not c or type(c.CompleteLatheWork) ~= "function" or c.SavePending then return end p.Confirmed = true log("auto-confirm → CompleteLatheWork()") local ok, err = pcall(c.CompleteLatheWork, c) if not ok then warn(TAG, "CompleteLatheWork failed:", err) end end local function tick(lathe, dt) if not state.Enabled or not lathe then return end if state.Lathe ~= lathe then state.Lathe = lathe state.Piece = nil end local ok, err = pcall(step, lathe, dt) if not ok then warn(TAG, "step error:", err) end tryAutoConfirm() end -- ── 1) hook the game's own frame functions ───────────────────────────────── local function findModule(name, parentName) local roots = { game:GetService("ReplicatedFirst") } local lp = Players.LocalPlayer local ps = lp and lp:FindFirstChildOfClass("PlayerScripts") if ps then table.insert(roots, ps) end for _, r in ipairs(roots) do for _, d in ipairs(r:GetDescendants()) do if d.Name == name and d:IsA("ModuleScript") and (not parentName or (d.Parent and d.Parent.Name == parentName)) then return d end end end end local function hookMethod(class, key, wrap) local orig = rawget(class, key) if type(orig) ~= "function" then return false end local hooked = wrap(orig) rawset(class, key, hooked) table.insert(state.Unhooks, function() if rawget(class, key) == hooked then rawset(class, key, orig) end end) return true end local hookedLathe, hookedCarving = false, false do local lcMod = findModule("LatheController", "WoodCarving") local wcMod = lcMod and lcMod.Parent if lcMod then local ok, LC = pcall(require, lcMod) if ok and type(LC) == "table" and type(rawget(LC, "UpdateActiveTool")) == "function" then hookedLathe = hookMethod(LC, "Update", function(orig) return function(self, dt, ...) local r = table.pack(orig(self, dt, ...)) state.LastHookCall = os.clock() tick(self, dt or 0) return table.unpack(r, 1, r.n) end end) else vlog("require(LatheController) failed:", ok and typeof(LC) or LC) end end if wcMod and wcMod:IsA("ModuleScript") then local ok, WC = pcall(require, wcMod) if ok and type(WC) == "table" and type(rawget(WC, "CompleteLatheWork")) == "function" then hookedCarving = hookMethod(WC, "RenderStep", function(orig) return function(self, ...) state.Carving = self return orig(self, ...) end end) end end log(("hooks: LatheController.Update=%s WoodCarving.RenderStep=%s"):format(tostring(hookedLathe), tostring(hookedCarving))) end -- ── 2) fallback: single scan per lathe entry, triggered by the ghost mesh ── local function scanOnce() local lathe, carving for _, t in ipairs(getgc(true)) do if type(t) == "table" then if not lathe and rawget(t, "ToolCarriage") ~= nil and rawget(t, "CarvingTool") ~= nil and rawget(t, "Destroyed") ~= true then lathe = t elseif not carving and type(rawget(t, "Lathe")) == "table" and rawget(t, "LatheSessionId") ~= nil then carving = t end if lathe and carving then break end end end return lathe, carving end local fallbackLathe = nil local function onGhost() -- give the hook a moment; only scan if it isn't delivering frames task.delay(1.5, function() if os.clock() - state.LastHookCall < 1 then return end local l, c = scanOnce() vlog("fallback scan:", l and "lathe found" or "no lathe", c and "+ carving client" or "") fallbackLathe = l if c then state.Carving = c end end) end table.insert(state.Conns, workspace.DescendantAdded:Connect(function(d) if d.Name == "TargetGhostMesh" then onGhost() end end)) if workspace:FindFirstChild("TargetGhostMesh", true) then onGhost() end table.insert(state.Conns, RunService.Heartbeat:Connect(function(dt) if not fallbackLathe then return end if fallbackLathe.Destroyed or os.clock() - state.LastHookCall < 1 then fallbackLathe = nil -- lathe closed, or the hook took over return end tick(fallbackLathe, dt) end)) -- ── toggle / lifecycle ───────────────────────────────────────────────────── table.insert(state.Conns, UserInputService.InputBegan:Connect(function(input, gpe) if gpe or input.KeyCode ~= CFG.TOGGLE_KEY then return end state.Enabled = not state.Enabled state.Piece = nil log(state.Enabled and "ENABLED" or "DISABLED") end)) G.__WCPerfect = { State = state, Config = CFG, Stop = function() for _, c in ipairs(state.Conns) do c:Disconnect() end for _, u in ipairs(state.Unhooks) do pcall(u) end table.clear(state.Conns) table.clear(state.Unhooks) log("stopped") end, } log(("loaded. CARVE_SECONDS=%s STEP_HZ=%s ONLY_REDUCE=%s AUTO_CONFIRM=%s toggle=%s — sit at the lathe."):format( tostring(CFG.CARVE_SECONDS), tostring(CFG.STEP_HZ), tostring(CFG.ONLY_REDUCE), tostring(CFG.AUTO_CONFIRM), CFG.TOGGLE_KEY.Name ))