Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- if not game:IsLoaded() then game.Loaded:Wait() end
- local function missing(t, f, fallback)
- if type(f) == t then return f end
- return fallback
- end
- getgenv = missing("function", getgenv, function() return _G end)
- cloneref = missing("function", cloneref, function(...) return ... end)
- newcclosure = missing("function", newcclosure, function(f) return f end)
- setscriptable = missing("function", setscriptable, nil)
- sethiddenproperty = missing("function", sethiddenproperty or set_hidden_property or set_hidden_prop, nil)
- getnilinstances = missing("function", getnilinstances, function() return {} end)
- setclipboard = missing("function", setclipboard or toclipboard or set_clipboard, nil)
- if getgenv().NanoRunning then
- if getgenv().NanoAPI and getgenv().NanoAPI.Stop then
- getgenv().NanoAPI.Stop()
- end
- task.wait(0.5)
- end
- getgenv().NanoRunning = true
- local sethidden = newcclosure(function(instance, property, value)
- local success = pcall(function()
- if sethiddenproperty then
- sethiddenproperty(instance, property, value)
- elseif setscriptable then
- setscriptable(instance, property, true)
- instance[property] = value
- task.wait()
- setscriptable(instance, property, false)
- else
- instance[property] = value
- end
- end)
- return success
- end)
- local Services = setmetatable({}, {
- __index = function(self, name)
- local success, cache = pcall(function()
- return cloneref(game:GetService(name))
- end)
- if success then
- rawset(self, name, cache)
- return cache
- end
- return nil
- end
- })
- local Players = Services.Players
- local RunService = Services.RunService
- local Workspace = Services.Workspace
- local StarterGui = Services.StarterGui
- local UserInputService = Services.UserInputService
- local PhysicsService = Services.PhysicsService
- local CoreGui = Services.CoreGui
- local LocalPlayer = Players.LocalPlayer
- local STARTING = false
- local STARTED = false
- local NANO_GROUP = "NanoParts"
- local CHAR_GROUP = "NanoChar"
- pcall(function()
- PhysicsService:RegisterCollisionGroup(NANO_GROUP)
- PhysicsService:RegisterCollisionGroup(CHAR_GROUP)
- end)
- pcall(function()
- PhysicsService:CollisionGroupSetCollidable(NANO_GROUP, NANO_GROUP, false)
- PhysicsService:CollisionGroupSetCollidable(NANO_GROUP, CHAR_GROUP, false)
- PhysicsService:CollisionGroupSetCollidable(NANO_GROUP, "Default", false)
- PhysicsService:CollisionGroupSetCollidable(CHAR_GROUP, "Default", true)
- PhysicsService:CollisionGroupSetCollidable(CHAR_GROUP, CHAR_GROUP, false)
- end)
- local ROTATIONS = {
- {cf = CFrame.Angles(0, 0, 0), order = {1, 2, 3}},
- {cf = CFrame.Angles(math.rad(90), 0, 0), order = {1, 3, 2}},
- {cf = CFrame.Angles(0, math.rad(90), 0), order = {3, 2, 1}},
- {cf = CFrame.Angles(0, 0, math.rad(90)), order = {2, 1, 3}},
- {cf = CFrame.Angles(math.rad(90), math.rad(90), 0), order = {3, 1, 2}},
- {cf = CFrame.Angles(math.rad(90), 0, math.rad(90)), order = {2, 3, 1}},
- }
- local LIMB_ORDER_R6 = {"Head", "Torso", "Left Arm", "Right Arm", "Left Leg", "Right Leg"}
- local LIMB_ORDER_R15 = {
- "Head", "UpperTorso", "LowerTorso",
- "LeftUpperArm", "LeftLowerArm", "LeftHand",
- "RightUpperArm", "RightLowerArm", "RightHand",
- "LeftUpperLeg", "LeftLowerLeg", "LeftFoot",
- "RightUpperLeg", "RightLowerLeg", "RightFoot"
- }
- local EXCLUDED_PARTS = {
- HumanoidRootPart = true,
- RootPart = true
- }
- local LIMB_DISPLAY_NAMES = {
- Head = "Head", Torso = "Torso",
- ["Left Arm"] = "L.Arm", ["Right Arm"] = "R.Arm",
- ["Left Leg"] = "L.Leg", ["Right Leg"] = "R.Leg",
- UpperTorso = "UpTorso", LowerTorso = "LoTorso",
- LeftUpperArm = "L.UpArm", LeftLowerArm = "L.LoArm", LeftHand = "L.Hand",
- RightUpperArm = "R.UpArm", RightLowerArm = "R.LoArm", RightHand = "R.Hand",
- LeftUpperLeg = "L.UpLeg", LeftLowerLeg = "L.LoLeg", LeftFoot = "L.Foot",
- RightUpperLeg = "R.UpLeg", RightLowerLeg = "R.LoLeg", RightFoot = "R.Foot"
- }
- local R15_EXTENSION_CONFIG = {
- Head = {sizeAdd = Vector3.new(0.4, 0.4, 0.4), offsetY = 0},
- LeftHand = {sizeAdd = Vector3.new(0.6, 1.2, 0.6), offsetY = -0.6},
- RightHand = {sizeAdd = Vector3.new(0.6, 1.2, 0.6), offsetY = -0.6},
- LeftLowerArm = {sizeAdd = Vector3.new(0.6, 0.4, 0.6), offsetY = 0},
- RightLowerArm = {sizeAdd = Vector3.new(0.6, 0.4, 0.6), offsetY = 0},
- LeftUpperArm = {sizeAdd = Vector3.new(0.4, 0.3, 0.4), offsetY = 0},
- RightUpperArm = {sizeAdd = Vector3.new(0.4, 0.3, 0.4), offsetY = 0},
- LeftFoot = {sizeAdd = Vector3.new(0.5, 0.8, 1.2), offsetY = -0.4},
- RightFoot = {sizeAdd = Vector3.new(0.5, 0.8, 1.2), offsetY = -0.4},
- LeftLowerLeg = {sizeAdd = Vector3.new(0.5, 0.4, 0.5), offsetY = 0},
- RightLowerLeg = {sizeAdd = Vector3.new(0.5, 0.4, 0.5), offsetY = 0},
- LeftUpperLeg = {sizeAdd = Vector3.new(0.4, 0.3, 0.4), offsetY = 0},
- RightUpperLeg = {sizeAdd = Vector3.new(0.4, 0.3, 0.4), offsetY = 0},
- UpperTorso = {sizeAdd = Vector3.new(0.5, 0.3, 0.3), offsetY = 0},
- LowerTorso = {sizeAdd = Vector3.new(0.4, 0.2, 0.3), offsetY = 0},
- }
- local R6_EXTENSION_CONFIG = {
- Head = {sizeAdd = Vector3.new(0.5, 0.5, 0.5), offsetY = 0},
- Torso = {sizeAdd = Vector3.new(0.4, 0.3, 0.3), offsetY = 0},
- ["Left Arm"] = {sizeAdd = Vector3.new(0.4, 0.4, 0.4), offsetY = 0},
- ["Right Arm"] = {sizeAdd = Vector3.new(0.4, 0.4, 0.4), offsetY = 0},
- ["Left Leg"] = {sizeAdd = Vector3.new(0.4, 0.4, 0.4), offsetY = 0},
- ["Right Leg"] = {sizeAdd = Vector3.new(0.4, 0.4, 0.4), offsetY = 0},
- }
- local PAPER_PHYSICS = PhysicalProperties.new(0.01, 0, 0, 0, 0)
- local NanoPool = {
- Attachments = {},
- AlignPositions = {},
- AlignOrientations = {},
- Stats = {Created = 0, Reused = 0, FromNil = 0}
- }
- function NanoPool.CollectFromNil()
- for _, obj in ipairs(getnilinstances()) do
- if obj.Name == "NanoPoolAtt" and obj:IsA("Attachment") then
- if not table.find(NanoPool.Attachments, obj) then
- table.insert(NanoPool.Attachments, obj)
- NanoPool.Stats.FromNil = NanoPool.Stats.FromNil + 1
- end
- elseif obj.Name == "NanoPoolAP" and obj:IsA("AlignPosition") then
- if not table.find(NanoPool.AlignPositions, obj) then
- table.insert(NanoPool.AlignPositions, obj)
- NanoPool.Stats.FromNil = NanoPool.Stats.FromNil + 1
- end
- elseif obj.Name == "NanoPoolAO" and obj:IsA("AlignOrientation") then
- if not table.find(NanoPool.AlignOrientations, obj) then
- table.insert(NanoPool.AlignOrientations, obj)
- NanoPool.Stats.FromNil = NanoPool.Stats.FromNil + 1
- end
- end
- end
- end
- function NanoPool.Init()
- NanoPool.CollectFromNil()
- end
- function NanoPool.GetAttachment()
- local att = table.remove(NanoPool.Attachments)
- if att then
- NanoPool.Stats.Reused = NanoPool.Stats.Reused + 1
- return att
- end
- NanoPool.Stats.Created = NanoPool.Stats.Created + 1
- local newAtt = Instance.new("Attachment")
- newAtt.Name = "NanoPoolAtt"
- return newAtt
- end
- function NanoPool.GetAlignPosition()
- local ap = table.remove(NanoPool.AlignPositions)
- if ap then
- NanoPool.Stats.Reused = NanoPool.Stats.Reused + 1
- return ap
- end
- NanoPool.Stats.Created = NanoPool.Stats.Created + 1
- local newAp = Instance.new("AlignPosition")
- newAp.Name = "NanoPoolAP"
- newAp.MaxForce = math.huge
- newAp.MaxVelocity = math.huge
- newAp.Responsiveness = 500
- newAp.RigidityEnabled = true
- return newAp
- end
- function NanoPool.GetAlignOrientation()
- local ao = table.remove(NanoPool.AlignOrientations)
- if ao then
- NanoPool.Stats.Reused = NanoPool.Stats.Reused + 1
- return ao
- end
- NanoPool.Stats.Created = NanoPool.Stats.Created + 1
- local newAo = Instance.new("AlignOrientation")
- newAo.Name = "NanoPoolAO"
- newAo.MaxTorque = math.huge
- newAo.MaxAngularVelocity = math.huge
- newAo.Responsiveness = 500
- newAo.RigidityEnabled = true
- return newAo
- end
- function NanoPool.Return(item)
- if not item then return end
- pcall(function() item.Parent = nil end)
- if item:IsA("Attachment") then
- item.CFrame = CFrame.identity
- table.insert(NanoPool.Attachments, item)
- elseif item:IsA("AlignPosition") then
- item.Attachment0 = nil
- item.Attachment1 = nil
- table.insert(NanoPool.AlignPositions, item)
- elseif item:IsA("AlignOrientation") then
- item.Attachment0 = nil
- item.Attachment1 = nil
- table.insert(NanoPool.AlignOrientations, item)
- end
- end
- function NanoPool.Clear()
- for _, att in ipairs(NanoPool.Attachments) do
- pcall(function() att:Destroy() end)
- end
- for _, ap in ipairs(NanoPool.AlignPositions) do
- pcall(function() ap:Destroy() end)
- end
- for _, ao in ipairs(NanoPool.AlignOrientations) do
- pcall(function() ao:Destroy() end)
- end
- NanoPool.Attachments = {}
- NanoPool.AlignPositions = {}
- NanoPool.AlignOrientations = {}
- NanoPool.Stats = {Created = 0, Reused = 0, FromNil = 0}
- end
- local NanoMath = {}
- function NanoMath.GetRotatedSize(size, rotationData)
- local order = rotationData.order
- local dims = {size.X, size.Y, size.Z}
- return Vector3.new(dims[order[1]], dims[order[2]], dims[order[3]])
- end
- function NanoMath.PartSizeToGridCells(partSize, cellSize)
- local cx = math.max(1, math.ceil(partSize.X / cellSize))
- local cy = math.max(1, math.ceil(partSize.Y / cellSize))
- local cz = math.max(1, math.ceil(partSize.Z / cellSize))
- return cx, cy, cz
- end
- local NanoGui = {
- Cache = {},
- DebugGui = nil,
- DebugFrame = nil,
- DebugLabel = nil,
- LimbsLabel = nil,
- Enabled = false,
- Minimized = false,
- LastUpdate = 0,
- Dragging = false,
- DragStart = nil,
- FrameStart = nil,
- DragConnection = nil,
- FullHeight = 500,
- MinHeight = 28,
- LastDebugText = "",
- LastLimbsText = ""
- }
- function NanoGui.CleanupDuplicates()
- pcall(function()
- for _, gui in ipairs(CoreGui:GetChildren()) do
- if gui.Name == "NanoDebugGui" then gui:Destroy() end
- end
- end)
- pcall(function()
- local pg = LocalPlayer:FindFirstChild("PlayerGui")
- if pg then
- for _, gui in ipairs(pg:GetChildren()) do
- if gui.Name == "NanoDebugGui" then gui:Destroy() end
- end
- end
- end)
- end
- function NanoGui.SaveState()
- NanoGui.Cache = {}
- local playerGui = LocalPlayer:FindFirstChild("PlayerGui")
- if not playerGui then return end
- for _, gui in ipairs(playerGui:GetChildren()) do
- if gui:IsA("ScreenGui") then
- NanoGui.Cache[gui.Name] = {Enabled = gui.Enabled, ResetOnSpawn = gui.ResetOnSpawn}
- end
- end
- end
- function NanoGui.RestoreState()
- local playerGui = LocalPlayer:FindFirstChild("PlayerGui")
- if not playerGui then return end
- for name, state in pairs(NanoGui.Cache) do
- local gui = playerGui:FindFirstChild(name)
- if gui and gui:IsA("ScreenGui") then
- pcall(function() gui.Enabled = state.Enabled end)
- end
- end
- end
- function NanoGui.CopyInfo(Runtime, CFG)
- if not setclipboard then
- StarterGui:SetCore("SendNotification", {
- Title = "NanoMech",
- Text = "Clipboard not supported!",
- Duration = 2
- })
- return
- end
- local info = "=== NANO-MECH v3.6 DEBUG INFO ===\n\n"
- info = info .. "=== GENERAL ===\n"
- info = info .. NanoGui.LastDebugText .. "\n\n"
- info = info .. "=== LIMBS ===\n"
- info = info .. NanoGui.LastLimbsText .. "\n\n"
- info = info .. "=== POOL STATS ===\n"
- info = info .. string.format("Attachments in pool: %d\n", #NanoPool.Attachments)
- info = info .. string.format("AlignPositions in pool: %d\n", #NanoPool.AlignPositions)
- info = info .. string.format("AlignOrientations in pool: %d\n", #NanoPool.AlignOrientations)
- info = info .. string.format("Created: %d | Reused: %d | FromNil: %d\n",
- NanoPool.Stats.Created, NanoPool.Stats.Reused, NanoPool.Stats.FromNil)
- info = info .. "\n=== CONFIG ===\n"
- info = info .. string.format("MechScale: %.1f\n", CFG.MechScale)
- info = info .. string.format("MechType: %s\n", CFG.MechType)
- info = info .. string.format("FakeRig: %s\n", CFG.FakeRig)
- info = info .. string.format("CellSize: %.2f (auto: %.2f)\n", CFG.CellSize, CFG.CellSize * CFG.MechScale)
- info = info .. string.format("ScanRadius: %d\n", CFG.ScanRadius)
- info = info .. string.format("MaxParts: %d\n", CFG.MaxParts)
- info = info .. "\n=== TRACKED PARTS ===\n"
- local limbCounts = {}
- for part, data in pairs(Runtime.TrackedParts or {}) do
- local limb = data.limbName or "Unknown"
- limbCounts[limb] = (limbCounts[limb] or 0) + 1
- end
- for limb, count in pairs(limbCounts) do
- info = info .. string.format("%s: %d parts\n", limb, count)
- end
- info = info .. "\n=== TIMESTAMP ===\n"
- info = info .. os.date("%Y-%m-%d %H:%M:%S")
- setclipboard(info)
- StarterGui:SetCore("SendNotification", {
- Title = "NanoMech",
- Text = "Debug info copied to clipboard!",
- Duration = 2
- })
- end
- function NanoGui.CreateDebug(Runtime, CFG)
- NanoGui.CleanupDuplicates()
- local sg = Instance.new("ScreenGui")
- sg.Name = "NanoDebugGui"
- sg.IgnoreGuiInset = true
- sg.ResetOnSpawn = false
- sg.DisplayOrder = 999
- pcall(function() sg.Parent = CoreGui end)
- if not sg.Parent then
- pcall(function() sg.Parent = LocalPlayer:WaitForChild("PlayerGui") end)
- end
- local frame = Instance.new("Frame")
- frame.Name = "DebugFrame"
- frame.Size = UDim2.new(0, 260, 0, NanoGui.FullHeight)
- frame.Position = UDim2.new(0, 10, 0, 10)
- frame.BackgroundColor3 = Color3.fromRGB(15, 15, 15)
- frame.BackgroundTransparency = 0.05
- frame.BorderSizePixel = 0
- frame.Active = true
- frame.ClipsDescendants = true
- frame.Parent = sg
- local corner = Instance.new("UICorner")
- corner.CornerRadius = UDim.new(0, 8)
- corner.Parent = frame
- local stroke = Instance.new("UIStroke")
- stroke.Color = Color3.fromRGB(0, 255, 100)
- stroke.Thickness = 2
- stroke.Parent = frame
- local titleBar = Instance.new("Frame")
- titleBar.Name = "TitleBar"
- titleBar.Size = UDim2.new(1, 0, 0, 28)
- titleBar.BackgroundColor3 = Color3.fromRGB(0, 180, 80)
- titleBar.BackgroundTransparency = 0.2
- titleBar.BorderSizePixel = 0
- titleBar.Parent = frame
- local titleCorner = Instance.new("UICorner")
- titleCorner.CornerRadius = UDim.new(0, 8)
- titleCorner.Parent = titleBar
- local titleFix = Instance.new("Frame")
- titleFix.Size = UDim2.new(1, 0, 0, 10)
- titleFix.Position = UDim2.new(0, 0, 1, -10)
- titleFix.BackgroundColor3 = Color3.fromRGB(0, 180, 80)
- titleFix.BackgroundTransparency = 0.2
- titleFix.BorderSizePixel = 0
- titleFix.Parent = titleBar
- local titleLabel = Instance.new("TextLabel")
- titleLabel.Size = UDim2.new(1, -130, 1, 0)
- titleLabel.Position = UDim2.new(0, 10, 0, 0)
- titleLabel.BackgroundTransparency = 1
- titleLabel.TextColor3 = Color3.fromRGB(255, 255, 255)
- titleLabel.TextSize = 14
- titleLabel.Font = Enum.Font.GothamBold
- titleLabel.Text = "NANO-MECH v3.6"
- titleLabel.TextXAlignment = Enum.TextXAlignment.Left
- titleLabel.Parent = titleBar
- local function createButton(name, text, color, posX, width)
- local btn = Instance.new("TextButton")
- btn.Name = name
- btn.Size = UDim2.new(0, width or 24, 0, 20)
- btn.Position = UDim2.new(1, posX, 0, 4)
- btn.BackgroundColor3 = color
- btn.BackgroundTransparency = 0.3
- btn.BorderSizePixel = 0
- btn.TextColor3 = Color3.fromRGB(255, 255, 255)
- btn.TextSize = 10
- btn.Font = Enum.Font.GothamBold
- btn.Text = text
- btn.Parent = titleBar
- local btnCorner = Instance.new("UICorner")
- btnCorner.CornerRadius = UDim.new(0, 4)
- btnCorner.Parent = btn
- return btn
- end
- local closeBtn = createButton("CloseBtn", "X", Color3.fromRGB(255, 60, 60), -30, 24)
- local minBtn = createButton("MinBtn", "-", Color3.fromRGB(255, 180, 0), -58, 24)
- local copyBtn = createButton("CopyBtn", "COPY", Color3.fromRGB(0, 150, 255), -105, 42)
- closeBtn.MouseButton1Click:Connect(function()
- NanoGui.DestroyDebug()
- end)
- minBtn.MouseButton1Click:Connect(function()
- NanoGui.Minimized = not NanoGui.Minimized
- if NanoGui.Minimized then
- frame.Size = UDim2.new(0, 260, 0, NanoGui.MinHeight)
- minBtn.Text = "+"
- else
- frame.Size = UDim2.new(0, 260, 0, NanoGui.FullHeight)
- minBtn.Text = "-"
- end
- end)
- copyBtn.MouseButton1Click:Connect(function()
- NanoGui.CopyInfo(Runtime, CFG)
- end)
- local contentFrame = Instance.new("Frame")
- contentFrame.Name = "Content"
- contentFrame.Size = UDim2.new(1, -12, 1, -36)
- contentFrame.Position = UDim2.new(0, 6, 0, 32)
- contentFrame.BackgroundTransparency = 1
- contentFrame.Parent = frame
- local statsLabel = Instance.new("TextLabel")
- statsLabel.Name = "Stats"
- statsLabel.Size = UDim2.new(1, 0, 0, 200)
- statsLabel.Position = UDim2.new(0, 0, 0, 0)
- statsLabel.BackgroundTransparency = 1
- statsLabel.TextColor3 = Color3.fromRGB(0, 255, 100)
- statsLabel.TextSize = 11
- statsLabel.Font = Enum.Font.Code
- statsLabel.TextXAlignment = Enum.TextXAlignment.Left
- statsLabel.TextYAlignment = Enum.TextYAlignment.Top
- statsLabel.Text = "Loading..."
- statsLabel.Parent = contentFrame
- local limbsLabel = Instance.new("TextLabel")
- limbsLabel.Name = "Limbs"
- limbsLabel.Size = UDim2.new(1, 0, 0, 260)
- limbsLabel.Position = UDim2.new(0, 0, 0, 205)
- limbsLabel.BackgroundTransparency = 1
- limbsLabel.TextColor3 = Color3.fromRGB(100, 255, 150)
- limbsLabel.TextSize = 10
- limbsLabel.Font = Enum.Font.Code
- limbsLabel.TextXAlignment = Enum.TextXAlignment.Left
- limbsLabel.TextYAlignment = Enum.TextYAlignment.Top
- limbsLabel.Text = ""
- limbsLabel.Parent = contentFrame
- titleBar.InputBegan:Connect(function(input)
- if input.UserInputType == Enum.UserInputType.MouseButton1 or input.UserInputType == Enum.UserInputType.Touch then
- NanoGui.Dragging = true
- NanoGui.DragStart = input.Position
- NanoGui.FrameStart = frame.Position
- end
- end)
- titleBar.InputEnded:Connect(function(input)
- if input.UserInputType == Enum.UserInputType.MouseButton1 or input.UserInputType == Enum.UserInputType.Touch then
- NanoGui.Dragging = false
- end
- end)
- if NanoGui.DragConnection then NanoGui.DragConnection:Disconnect() end
- NanoGui.DragConnection = UserInputService.InputChanged:Connect(function(input)
- if NanoGui.Dragging and (input.UserInputType == Enum.UserInputType.MouseMovement or input.UserInputType == Enum.UserInputType.Touch) then
- local delta = input.Position - NanoGui.DragStart
- frame.Position = UDim2.new(NanoGui.FrameStart.X.Scale, NanoGui.FrameStart.X.Offset + delta.X, NanoGui.FrameStart.Y.Scale, NanoGui.FrameStart.Y.Offset + delta.Y)
- end
- end)
- NanoGui.DebugGui = sg
- NanoGui.DebugFrame = frame
- NanoGui.DebugLabel = statsLabel
- NanoGui.LimbsLabel = limbsLabel
- NanoGui.Enabled = true
- NanoGui.Minimized = false
- end
- function NanoGui.UpdateDebug(Runtime, CFG)
- if not NanoGui.Enabled or not NanoGui.DebugLabel or NanoGui.Minimized then return end
- local now = tick()
- if now - NanoGui.LastUpdate < 0.4 then return end
- NanoGui.LastUpdate = now
- local trackedCount = 0
- for _ in pairs(Runtime.TrackedParts or {}) do trackedCount = trackedCount + 1 end
- local totalCells, occupiedCells = 0, 0
- local limbStats = {}
- local limbPartCounts = {}
- local limbOrder = Runtime.FakeRigType == "R15" and LIMB_ORDER_R15 or LIMB_ORDER_R6
- for _, limbName in ipairs(limbOrder) do
- local grid = Runtime.LimbGrids[limbName]
- if grid and grid.occupancy then
- local t, o = 0, 0
- local partCount = 0
- local countedParts = {}
- for x = 0, grid.gridSize.X - 1 do
- for y = 0, grid.gridSize.Y - 1 do
- for z = 0, grid.gridSize.Z - 1 do
- if grid.occupancy[x] and grid.occupancy[x][y] then
- if grid.partMap[x][y][z] ~= "INVALID" then
- totalCells = totalCells + 1
- t = t + 1
- if grid.occupancy[x][y][z] then
- occupiedCells = occupiedCells + 1
- o = o + 1
- local part = grid.partMap[x][y][z]
- if part and not countedParts[part] then
- countedParts[part] = true
- partCount = partCount + 1
- end
- end
- end
- end
- end
- end
- end
- limbStats[limbName] = {total = t, occupied = o}
- limbPartCounts[limbName] = partCount
- end
- end
- local state = Runtime.IsDead and "DEAD" or (Runtime.IsRunning and "RUNNING" or "IDLE")
- local fillPercent = totalCells > 0 and math.floor((occupiedCells / totalCells) * 100) or 0
- local fillBar = string.rep("ā", math.floor(fillPercent / 5)) .. string.rep("ā", 20 - math.floor(fillPercent / 5))
- local poolTotal = #NanoPool.Attachments + #NanoPool.AlignPositions + #NanoPool.AlignOrientations
- local effectiveCellSize = CFG.CellSize * CFG.MechScale
- local debugText = string.format(
- "STATE: %s\n" ..
- "TYPE: %s\n" ..
- "RIG: %s ā %s\n" ..
- "āāāāāāāāāāāāāāāāāāāāāāāā\n" ..
- "PARTS: %d / %d (scanned: %d)\n" ..
- "CELLS: %d / %d\n" ..
- "FILL: %s %d%%\n" ..
- "āāāāāāāāāāāāāāāāāāāāāāāā\n" ..
- "JUMP: %s | GND: %s\n" ..
- "SCALE: %.1fx | CELL: %.2f\n" ..
- "āāāāāāāāāāāāāāāāāāāāāāāā\n" ..
- "POOL: %d available\n" ..
- "NEW: %d | RE: %d | NIL: %d\n" ..
- "āāāāāāāāāāāāāāāāāāāāāāāā\n" ..
- "PENDING: %d",
- state, CFG.MechType or "Full",
- Runtime.RealRigType or "?", Runtime.FakeRigType or "?",
- trackedCount, CFG.MaxParts or 512, Runtime.ScannedPartsCount or 0,
- occupiedCells, totalCells, fillBar, fillPercent,
- Runtime.JumpState or "?", Runtime.IsGrounded and "Y" or "N",
- CFG.MechScale or 1, effectiveCellSize,
- poolTotal,
- NanoPool.Stats.Created, NanoPool.Stats.Reused, NanoPool.Stats.FromNil,
- Runtime.PendingPartsCount or 0
- )
- NanoGui.DebugLabel.Text = debugText
- NanoGui.LastDebugText = debugText
- local limbLines = {"āāāāāāāāāāāāāāāāāāāāāāāā", "LIMBS: FILL PCS"}
- for _, limbName in ipairs(limbOrder) do
- local stats = limbStats[limbName]
- local partCount = limbPartCounts[limbName] or 0
- if stats then
- local pct = stats.total > 0 and math.floor((stats.occupied / stats.total) * 100) or 0
- local displayName = LIMB_DISPLAY_NAMES[limbName] or limbName
- local bar = string.rep("ā", math.floor(pct / 10)) .. string.rep("ā", 10 - math.floor(pct / 10))
- table.insert(limbLines, string.format("%-8s %s %3d%% %2d", displayName, bar, pct, partCount))
- end
- end
- local limbsText = table.concat(limbLines, "\n")
- if NanoGui.LimbsLabel then
- NanoGui.LimbsLabel.Text = limbsText
- end
- NanoGui.LastLimbsText = limbsText
- end
- function NanoGui.DestroyDebug()
- if NanoGui.DragConnection then NanoGui.DragConnection:Disconnect() NanoGui.DragConnection = nil end
- if NanoGui.DebugGui then pcall(function() NanoGui.DebugGui:Destroy() end) end
- NanoGui.DebugGui = nil
- NanoGui.DebugFrame = nil
- NanoGui.DebugLabel = nil
- NanoGui.LimbsLabel = nil
- NanoGui.Enabled = false
- NanoGui.Dragging = false
- NanoGui.Minimized = false
- end
- local NanoGrid = {}
- function NanoGrid.Create(limbPart, cellSize, mechType, limbName, extensionConfig)
- local baseSize = limbPart.Size
- local size = baseSize
- local offsetY = 0
- if extensionConfig and extensionConfig[limbName] then
- local ext = extensionConfig[limbName]
- size = baseSize + ext.sizeAdd
- offsetY = ext.offsetY or 0
- end
- local gridSizeX = math.max(1, math.ceil(size.X / cellSize))
- local gridSizeY = math.max(1, math.ceil(size.Y / cellSize))
- local gridSizeZ = math.max(1, math.ceil(size.Z / cellSize))
- local grid = {
- bodyPart = limbPart,
- cellSize = cellSize,
- gridSize = Vector3.new(gridSizeX, gridSizeY, gridSizeZ),
- baseSize = baseSize,
- extendedSize = size,
- offsetY = offsetY,
- occupancy = {},
- partMap = {},
- totalCells = 0,
- validCells = 0
- }
- local centerX = (gridSizeX - 1) / 2
- local centerY = (gridSizeY - 1) / 2
- local centerZ = (gridSizeZ - 1) / 2
- local isHead = limbName == "Head"
- for x = 0, gridSizeX - 1 do
- grid.occupancy[x] = {}
- grid.partMap[x] = {}
- for y = 0, gridSizeY - 1 do
- grid.occupancy[x][y] = {}
- grid.partMap[x][y] = {}
- for z = 0, gridSizeZ - 1 do
- grid.totalCells = grid.totalCells + 1
- local isValid = true
- if isHead then
- local distX = math.abs(x - centerX) / math.max(1, centerX)
- local distY = math.abs(y - centerY) / math.max(1, centerY)
- local distZ = math.abs(z - centerZ) / math.max(1, centerZ)
- local sphereDist = math.sqrt(distX * distX + distY * distY + distZ * distZ)
- isValid = sphereDist <= 1.2
- elseif mechType == "Hollow" then
- local nx = gridSizeX > 1 and (x - centerX) / centerX or 0
- local nz = gridSizeZ > 1 and (z - centerZ) / centerZ or 0
- local dist = math.sqrt(nx * nx + nz * nz)
- isValid = dist >= 0.5
- elseif mechType == "Skeleton" then
- local threshX = math.max(1, gridSizeX * 0.2)
- local threshY = math.max(1, gridSizeY * 0.2)
- local threshZ = math.max(1, gridSizeZ * 0.2)
- local onX = math.abs(y - centerY) <= threshY and math.abs(z - centerZ) <= threshZ
- local onY = math.abs(x - centerX) <= threshX and math.abs(z - centerZ) <= threshZ
- local onZ = math.abs(x - centerX) <= threshX and math.abs(y - centerY) <= threshY
- isValid = onX or onY or onZ
- elseif mechType == "Armor" then
- local margin = math.max(1, math.min(gridSizeX, gridSizeY, gridSizeZ) * 0.3)
- local isOuterX = x < margin or x >= gridSizeX - margin
- local isOuterY = y < margin or y >= gridSizeY - margin
- local isOuterZ = z < margin or z >= gridSizeZ - margin
- isValid = isOuterX or isOuterY or isOuterZ
- end
- if isValid then
- grid.occupancy[x][y][z] = false
- grid.partMap[x][y][z] = nil
- grid.validCells = grid.validCells + 1
- else
- grid.occupancy[x][y][z] = true
- grid.partMap[x][y][z] = "INVALID"
- end
- end
- end
- end
- return grid
- end
- function NanoGrid.IsAreaFree(grid, startX, startY, startZ, sizeX, sizeY, sizeZ)
- local gs = grid.gridSize
- if startX < 0 or startY < 0 or startZ < 0 then return false end
- if startX + sizeX > gs.X or startY + sizeY > gs.Y or startZ + sizeZ > gs.Z then return false end
- for x = startX, startX + sizeX - 1 do
- for y = startY, startY + sizeY - 1 do
- for z = startZ, startZ + sizeZ - 1 do
- if grid.occupancy[x] and grid.occupancy[x][y] and grid.occupancy[x][y][z] then
- return false
- end
- end
- end
- end
- return true
- end
- function NanoGrid.GetNeighborScore(grid, startX, startY, startZ, sizeX, sizeY, sizeZ)
- local score = 0
- local gs = grid.gridSize
- local checked = {}
- local directions = {
- {-1, 0, 0}, {1, 0, 0},
- {0, -1, 0}, {0, 1, 0},
- {0, 0, -1}, {0, 0, 1}
- }
- for x = startX, startX + sizeX - 1 do
- for y = startY, startY + sizeY - 1 do
- for z = startZ, startZ + sizeZ - 1 do
- for _, dir in ipairs(directions) do
- local nx, ny, nz = x + dir[1], y + dir[2], z + dir[3]
- if nx >= startX and nx < startX + sizeX and
- ny >= startY and ny < startY + sizeY and
- nz >= startZ and nz < startZ + sizeZ then
- continue
- end
- local key = nx .. "_" .. ny .. "_" .. nz
- if checked[key] then continue end
- checked[key] = true
- if nx >= 0 and nx < gs.X and ny >= 0 and ny < gs.Y and nz >= 0 and nz < gs.Z then
- if grid.occupancy[nx] and grid.occupancy[nx][ny] and grid.occupancy[nx][ny][nz] then
- if grid.partMap[nx][ny][nz] and grid.partMap[nx][ny][nz] ~= "INVALID" then
- score = score + 1
- end
- end
- end
- end
- end
- end
- end
- return score
- end
- function NanoGrid.FindBestPlacement(grid, partSize, usePriority)
- local cellSize = grid.cellSize
- local gs = grid.gridSize
- local bestPos = nil
- local bestRot = nil
- local bestScore = -math.huge
- local bestCells = nil
- for _, rotData in ipairs(ROTATIONS) do
- local rotatedSize = NanoMath.GetRotatedSize(partSize, rotData)
- local cellsX, cellsY, cellsZ = NanoMath.PartSizeToGridCells(rotatedSize, cellSize)
- if cellsX > gs.X or cellsY > gs.Y or cellsZ > gs.Z then
- continue
- end
- for x = 0, gs.X - cellsX do
- for y = 0, gs.Y - cellsY do
- for z = 0, gs.Z - cellsZ do
- if NanoGrid.IsAreaFree(grid, x, y, z, cellsX, cellsY, cellsZ) then
- local score = 0
- if usePriority then
- score = score + NanoGrid.GetNeighborScore(grid, x, y, z, cellsX, cellsY, cellsZ) * 10
- end
- local centerX = gs.X / 2
- local centerZ = gs.Z / 2
- local distFromCenter = math.sqrt((x + cellsX/2 - centerX)^2 + (z + cellsZ/2 - centerZ)^2)
- score = score - distFromCenter
- score = score + y * 0.5
- local volume = cellsX * cellsY * cellsZ
- score = score + volume * 0.1
- if score > bestScore then
- bestScore = score
- bestPos = Vector3.new(x, y, z)
- bestRot = rotData
- bestCells = Vector3.new(cellsX, cellsY, cellsZ)
- end
- end
- end
- end
- end
- end
- return bestPos, bestRot, bestCells, bestScore
- end
- function NanoGrid.MarkAreaOccupied(grid, startX, startY, startZ, sizeX, sizeY, sizeZ, part)
- for x = startX, startX + sizeX - 1 do
- for y = startY, startY + sizeY - 1 do
- for z = startZ, startZ + sizeZ - 1 do
- if grid.occupancy[x] and grid.occupancy[x][y] then
- grid.occupancy[x][y][z] = true
- grid.partMap[x][y][z] = part
- end
- end
- end
- end
- end
- function NanoGrid.MarkAreaFree(grid, startX, startY, startZ, sizeX, sizeY, sizeZ)
- for x = startX, startX + sizeX - 1 do
- for y = startY, startY + sizeY - 1 do
- for z = startZ, startZ + sizeZ - 1 do
- if grid.occupancy[x] and grid.occupancy[x][y] then
- if grid.partMap[x][y][z] ~= "INVALID" then
- grid.occupancy[x][y][z] = false
- grid.partMap[x][y][z] = nil
- end
- end
- end
- end
- end
- end
- function NanoGrid.GetWorldOffset(grid, gridPos, cellsSize)
- local cellSize = grid.cellSize
- local gs = grid.gridSize
- local offsetX = (gridPos.X + cellsSize.X / 2 - gs.X / 2) * cellSize
- local offsetY = (gridPos.Y + cellsSize.Y / 2 - gs.Y / 2) * cellSize + (grid.offsetY or 0)
- local offsetZ = (gridPos.Z + cellsSize.Z / 2 - gs.Z / 2) * cellSize
- return Vector3.new(offsetX, offsetY, offsetZ)
- end
- local NanoPhysics = {}
- function NanoPhysics.CreateAlignMovers(part, limbPart, worldOffset, rotation)
- local attach = NanoPool.GetAttachment()
- attach.CFrame = CFrame.new(worldOffset) * rotation
- attach.Parent = limbPart
- local partAttach = NanoPool.GetAttachment()
- partAttach.Parent = part
- local ap = NanoPool.GetAlignPosition()
- ap.Attachment0 = partAttach
- ap.Attachment1 = attach
- ap.Parent = part
- local ao = NanoPool.GetAlignOrientation()
- ao.Attachment0 = partAttach
- ao.Attachment1 = attach
- ao.Parent = part
- return {
- position = ap,
- orientation = ao,
- limbAttachment = attach,
- partAttachment = partAttach
- }
- end
- function NanoPhysics.ReturnMovers(movers)
- if not movers then return end
- if movers.position then NanoPool.Return(movers.position) end
- if movers.orientation then NanoPool.Return(movers.orientation) end
- if movers.limbAttachment then NanoPool.Return(movers.limbAttachment) end
- if movers.partAttachment then NanoPool.Return(movers.partAttachment) end
- end
- function NanoPhysics.ApplyAntisleep(part, CFG, LocalPlayer)
- if not CFG.AntisleepEnabled then return end
- pcall(function()
- local isSleeping = false
- pcall(function()
- isSleeping = part:GetNetworkOwner() == LocalPlayer and part.AssemblyLinearVelocity.Magnitude < 0.01
- end)
- if isSleeping or part.AssemblyLinearVelocity.Magnitude < 0.01 then
- local vel = CFG.AntisleepVelocity
- part.AssemblyLinearVelocity = part.AssemblyLinearVelocity + Vector3.new(
- (math.random() - 0.5) * vel * 2,
- (math.random() - 0.5) * vel * 2,
- (math.random() - 0.5) * vel * 2
- )
- end
- end)
- pcall(function()
- sethidden(part, "NetworkIsSleeping", false)
- end)
- end
- local NanoCharacter = {}
- function NanoCharacter.GetRigType(char)
- if not char then return nil end
- local humanoid = char:FindFirstChildOfClass("Humanoid")
- if not humanoid then return nil end
- return humanoid.RigType == Enum.HumanoidRigType.R15 and "R15" or "R6"
- end
- function NanoCharacter.NormalizeRig(value)
- if value == nil then return "R6" end
- if type(value) == "string" and string.find(string.lower(value), "15") then
- return "R15"
- end
- return "R6"
- end
- function NanoCharacter.StopAllAnimations(char)
- if not char then return end
- local animate = char:FindFirstChild("Animate")
- if animate then animate.Disabled = true end
- local humanoid = char:FindFirstChildOfClass("Humanoid")
- if humanoid then
- local animator = humanoid:FindFirstChildOfClass("Animator")
- if animator then
- for _, track in ipairs(animator:GetPlayingAnimationTracks()) do
- pcall(function() track:Stop(0) end)
- end
- end
- for _, track in ipairs(humanoid:GetPlayingAnimationTracks()) do
- pcall(function() track:Stop(0) end)
- end
- end
- end
- function NanoCharacter.RestoreAnimations(char)
- if not char then return end
- local animate = char:FindFirstChild("Animate")
- if animate then
- animate.Disabled = true
- task.wait(0.1)
- animate.Disabled = false
- end
- end
- function NanoCharacter.HasTouchInterest(instance)
- for _, child in ipairs(instance:GetDescendants()) do
- if child:IsA("TouchTransmitter") or child.ClassName == "TouchInterest" then
- return true
- end
- end
- return false
- end
- function NanoCharacter.DisableTouchOnCharacter(char)
- if not char then return end
- for _, part in ipairs(char:GetDescendants()) do
- if part:IsA("BasePart") then
- pcall(function() part.CanTouch = false end)
- end
- end
- end
- function NanoCharacter.CreateFake(realChar, targetRig, CFG)
- if not realChar then return nil end
- local realHRP = realChar:FindFirstChild("HumanoidRootPart")
- if not realHRP then return nil end
- local realRig = NanoCharacter.GetRigType(realChar)
- local fakeRig = NanoCharacter.NormalizeRig(targetRig)
- local fake = nil
- if realRig == fakeRig then
- pcall(function()
- realChar.Archivable = true
- fake = realChar:Clone()
- realChar.Archivable = false
- end)
- else
- pcall(function()
- local rigType = fakeRig == "R6" and Enum.HumanoidRigType.R6 or Enum.HumanoidRigType.R15
- local desc = Players:GetHumanoidDescriptionFromUserId(LocalPlayer.UserId)
- fake = Players:CreateHumanoidModelFromDescription(desc, rigType)
- end)
- end
- if not fake then return nil end
- for _, desc in ipairs(fake:GetDescendants()) do
- if desc:IsA("Script") or desc:IsA("LocalScript") then
- if desc.Name ~= "Animate" and desc.Name ~= "Health" then
- desc:Destroy()
- end
- end
- end
- for _, child in ipairs(fake:GetChildren()) do
- if child:IsA("Accessory") then child:Destroy() end
- end
- local transparency = CFG.MechType == "Skeleton" and 1 or CFG.MechTransparency
- for _, part in ipairs(fake:GetDescendants()) do
- if part:IsA("BasePart") then
- part.Transparency = transparency
- part.CanCollide = true
- part.CanQuery = true
- part.Massless = false
- part.CanTouch = false
- pcall(function() part.CollisionGroup = CHAR_GROUP end)
- end
- end
- fake.Name = "NanoMech"
- fake.Parent = Workspace
- pcall(function() fake:ScaleTo(CFG.MechScale) end)
- fake:PivotTo(realChar:GetPivot())
- local humanoid = fake:FindFirstChildOfClass("Humanoid")
- if humanoid then
- humanoid.DisplayDistanceType = Enum.HumanoidDisplayDistanceType.None
- humanoid.HealthDisplayType = Enum.HumanoidHealthDisplayType.AlwaysOff
- humanoid.AutoRotate = true
- humanoid.WalkSpeed = 16
- humanoid.JumpPower = 50
- humanoid.JumpHeight = 7.2
- humanoid.UseJumpPower = true
- end
- return fake, fakeRig
- end
- function NanoCharacter.DisableReal(realChar, CFG, originalStates)
- if not realChar then return end
- NanoCharacter.StopAllAnimations(realChar)
- local realHum = realChar:FindFirstChildOfClass("Humanoid")
- if realHum then
- realHum.AutoRotate = false
- realHum.PlatformStand = true
- pcall(function() realHum:ChangeState(Enum.HumanoidStateType.Physics) end)
- end
- for _, part in ipairs(realChar:GetDescendants()) do
- if part:IsA("BasePart") then
- originalStates[part] = {
- Transparency = part.Transparency,
- CanCollide = part.CanCollide,
- CanTouch = part.CanTouch,
- CollisionGroup = part.CollisionGroup,
- Massless = part.Massless,
- CustomPhysicalProperties = part.CustomPhysicalProperties
- }
- part.Transparency = CFG.RealCharTransparency
- part.CanCollide = CFG.RealCharCanCollide
- part.CanTouch = CFG.RealCharCanTouch
- part.Massless = true
- part.CustomPhysicalProperties = PAPER_PHYSICS
- pcall(function() part.CollisionGroup = CHAR_GROUP end)
- elseif part:IsA("Decal") then
- originalStates[part] = {Transparency = part.Transparency}
- part.Transparency = 1
- end
- end
- end
- function NanoCharacter.RestoreReal(realChar, originalStates)
- if not realChar or not realChar.Parent then return end
- pcall(function() LocalPlayer.Character = realChar end)
- for obj, state in pairs(originalStates) do
- if obj and obj.Parent then
- pcall(function()
- if obj:IsA("BasePart") then
- obj.Transparency = state.Transparency or 0
- obj.CanCollide = state.CanCollide ~= false
- obj.CanTouch = state.CanTouch ~= false
- obj.CollisionGroup = state.CollisionGroup or "Default"
- obj.Massless = state.Massless or false
- if state.CustomPhysicalProperties then
- obj.CustomPhysicalProperties = state.CustomPhysicalProperties
- end
- elseif obj:IsA("Decal") then
- obj.Transparency = state.Transparency or 0
- end
- end)
- end
- end
- local realHum = realChar:FindFirstChildOfClass("Humanoid")
- if realHum then
- pcall(function()
- realHum.AutoRotate = true
- realHum.PlatformStand = false
- realHum:ChangeState(Enum.HumanoidStateType.GettingUp)
- end)
- end
- NanoCharacter.RestoreAnimations(realChar)
- pcall(function() Workspace.CurrentCamera.CameraSubject = realHum end)
- NanoGui.RestoreState()
- end
- function NanoCharacter.SetupAnimations(fakeChar, fakeRig, realRig)
- if not fakeChar then return end
- local humanoid = fakeChar:FindFirstChildOfClass("Humanoid")
- local animate = fakeChar:FindFirstChild("Animate")
- if humanoid and animate then
- animate.Disabled = true
- task.wait(0.15)
- animate.Disabled = false
- end
- end
- local function CleanupNano()
- STARTED = false
- STARTING = false
- getgenv().NanoRunning = false
- for _, connName in ipairs({
- "NanoConnection", "NanoAttachConnection", "NanoDescendantConnection",
- "NanoDeathConnection", "NanoCameraConnection", "NanoRenderConnection",
- "NanoFakeDescendantConnection", "NanoNewPartConnection"
- }) do
- if getgenv()[connName] then
- pcall(function() getgenv()[connName]:Disconnect() end)
- getgenv()[connName] = nil
- end
- end
- NanoGui.DestroyDebug()
- if getgenv().NanoRuntime then
- local Runtime = getgenv().NanoRuntime
- if Runtime.OriginalFallenPartsHeight then
- pcall(function() Workspace.FallenPartsDestroyHeight = Runtime.OriginalFallenPartsHeight end)
- end
- if Runtime.NoCollisionConstraints then
- for _, nc in ipairs(Runtime.NoCollisionConstraints) do
- pcall(function() nc:Destroy() end)
- end
- end
- for part, data in pairs(Runtime.TrackedParts or {}) do
- pcall(function()
- NanoPhysics.ReturnMovers(data.movers)
- part:SetAttribute("NanoLimb", nil)
- part:SetAttribute("NanoSlot", nil)
- part.CollisionGroup = "Default"
- if data.originalProps then
- part.CanCollide = data.originalProps.CanCollide
- part.Massless = data.originalProps.Massless
- part.CanTouch = data.originalProps.CanTouch
- end
- end)
- end
- NanoCharacter.RestoreReal(Runtime.RealCharacter, Runtime.OriginalStates)
- if Runtime.FakeCharacter then
- pcall(function() Runtime.FakeCharacter:Destroy() end)
- end
- end
- getgenv().NanoRuntime = nil
- end
- CleanupNano()
- local DEFAULT_CONFIGS = {
- MechScale = 2,
- MechTransparency = 0.5,
- MechType = "Full",
- FakeRig = "R6",
- R15ExtensionsEnabled = true,
- R6ExtensionsEnabled = true,
- RealCharTransparency = 1,
- RealCharCanCollide = false,
- RealCharCanTouch = false,
- RealCharOffset = CFrame.new(0, 0, 0),
- SimRadius = 1000,
- SlotPriority = true,
- CellSize = 0.5,
- AntisleepEnabled = true,
- AntisleepVelocity = 0.002,
- PartsCanCollide = false,
- PartsMassless = true,
- DisableTouchInterest = true,
- PackInterval = 0.1,
- MaxParts = 512,
- ChunkSize = 8,
- ScanMode = "Radius",
- ScanRadius = 500,
- ScanFromReal = true,
- ScanBoxSize = Vector3.new(60, 40, 60),
- ScanBoxOffset = CFrame.new(0, 0, 0),
- TransformTimeout = 0.2,
- DeathRestoreTimeout = 0.5,
- GroundCheckDistance = 3,
- JumpDebounce = 0.3,
- DebugStatsGui = true,
- MemoryCleanupInterval = 30
- }
- getgenv().NanoConfigs = getgenv().NanoConfigs or {}
- for key, defaultValue in pairs(DEFAULT_CONFIGS) do
- if getgenv().NanoConfigs[key] == nil then
- getgenv().NanoConfigs[key] = defaultValue
- end
- end
- local CFG = getgenv().NanoConfigs
- getgenv().NanoRuntime = {
- OriginalStates = {},
- NewPartsTimestamp = {},
- PendingParts = {},
- SimRadiusSet = false,
- FallenPartsSet = false,
- OriginalFallenPartsHeight = nil,
- IsRunning = false,
- IsDead = false,
- RealCharacter = nil,
- RealRigType = nil,
- FakeCharacter = nil,
- FakeRigType = nil,
- FakeBodyParts = {},
- LimbGrids = {},
- NoCollisionConstraints = {},
- TrackedParts = {},
- PartIndex = 0,
- JumpState = "GROUNDED",
- IsGrounded = true,
- LastJumpTime = 0,
- LastMemoryCleanup = 0,
- ScannedPartsCount = 0,
- PendingPartsCount = 0
- }
- local Runtime = getgenv().NanoRuntime
- local function SetSimulationRadius()
- if Runtime.SimRadiusSet then return end
- sethidden(LocalPlayer, "SimulationRadius", CFG.SimRadius)
- sethidden(LocalPlayer, "MaximumSimulationRadius", CFG.SimRadius)
- Runtime.SimRadiusSet = true
- end
- local function SetFallenPartsDestroyHeight()
- if Runtime.FallenPartsSet then return end
- Runtime.OriginalFallenPartsHeight = Workspace.FallenPartsDestroyHeight
- pcall(function() Workspace.FallenPartsDestroyHeight = -1e9 end)
- Runtime.FallenPartsSet = true
- end
- local function CleanupOldTimestamps()
- local now = tick()
- if now - Runtime.LastMemoryCleanup < CFG.MemoryCleanupInterval then return end
- Runtime.LastMemoryCleanup = now
- local toRemove = {}
- for part, ts in pairs(Runtime.NewPartsTimestamp) do
- if not part or not part.Parent or (now - ts) > 60 then
- table.insert(toRemove, part)
- end
- end
- for _, part in ipairs(toRemove) do
- Runtime.NewPartsTimestamp[part] = nil
- end
- NanoPool.CollectFromNil()
- end
- local function SetupCamera()
- local fakeHum = Runtime.FakeCharacter and Runtime.FakeCharacter:FindFirstChildOfClass("Humanoid")
- if not fakeHum then return end
- Workspace.CurrentCamera.CameraType = Enum.CameraType.Custom
- Workspace.CurrentCamera.CameraSubject = fakeHum
- if getgenv().NanoCameraConnection then getgenv().NanoCameraConnection:Disconnect() end
- getgenv().NanoCameraConnection = Workspace.CurrentCamera:GetPropertyChangedSignal("CameraSubject"):Connect(function()
- if Runtime.IsDead then
- local targetChar = Runtime.RealCharacter or LocalPlayer.Character
- if targetChar then
- local hum = targetChar:FindFirstChildOfClass("Humanoid")
- if hum then Workspace.CurrentCamera.CameraSubject = hum end
- end
- return
- end
- if not Runtime.IsRunning then return end
- if Workspace.CurrentCamera.CameraSubject ~= fakeHum then
- Workspace.CurrentCamera.CameraSubject = fakeHum
- end
- end)
- end
- local function SetupNoCollisionConstraints()
- local realChar = Runtime.RealCharacter
- local fakeChar = Runtime.FakeCharacter
- if not realChar or not fakeChar then return end
- Runtime.NoCollisionConstraints = {}
- task.spawn(function()
- local realParts = {}
- local fakeParts = {}
- for _, part in ipairs(realChar:GetChildren()) do
- if part:IsA("BasePart") then
- table.insert(realParts, part)
- end
- end
- for _, part in ipairs(fakeChar:GetChildren()) do
- if part:IsA("BasePart") then
- table.insert(fakeParts, part)
- end
- end
- local count = 0
- for _, realPart in ipairs(realParts) do
- for _, fakePart in ipairs(fakeParts) do
- local nc = Instance.new("NoCollisionConstraint")
- nc.Part0 = realPart
- nc.Part1 = fakePart
- nc.Parent = fakePart
- table.insert(Runtime.NoCollisionConstraints, nc)
- count = count + 1
- if count % 10 == 0 then
- task.wait()
- end
- end
- end
- end)
- end
- local function SetupFakeCharDescendantTracking()
- if getgenv().NanoFakeDescendantConnection then getgenv().NanoFakeDescendantConnection:Disconnect() end
- local fakeChar = Runtime.FakeCharacter
- if not fakeChar then return end
- getgenv().NanoFakeDescendantConnection = fakeChar.DescendantAdded:Connect(function(desc)
- if desc:IsA("BasePart") then
- pcall(function()
- desc.CanTouch = false
- desc.CollisionGroup = CHAR_GROUP
- end)
- end
- end)
- end
- local function CreateLimbGrids()
- local fakeChar = Runtime.FakeCharacter
- if not fakeChar then return end
- Runtime.FakeBodyParts = {}
- Runtime.LimbGrids = {}
- local partNames = Runtime.FakeRigType == "R15" and LIMB_ORDER_R15 or LIMB_ORDER_R6
- local effectiveCellSize = CFG.CellSize * CFG.MechScale
- local extensionConfig = nil
- if Runtime.FakeRigType == "R15" and CFG.R15ExtensionsEnabled then
- extensionConfig = {}
- for limbName, ext in pairs(R15_EXTENSION_CONFIG) do
- extensionConfig[limbName] = {
- sizeAdd = ext.sizeAdd * CFG.MechScale,
- offsetY = (ext.offsetY or 0) * CFG.MechScale
- }
- end
- elseif Runtime.FakeRigType == "R6" and CFG.R6ExtensionsEnabled then
- extensionConfig = {}
- for limbName, ext in pairs(R6_EXTENSION_CONFIG) do
- extensionConfig[limbName] = {
- sizeAdd = ext.sizeAdd * CFG.MechScale,
- offsetY = (ext.offsetY or 0) * CFG.MechScale
- }
- end
- end
- for _, partName in ipairs(partNames) do
- if EXCLUDED_PARTS[partName] then continue end
- local bodyPart = fakeChar:FindFirstChild(partName)
- if bodyPart and bodyPart:IsA("BasePart") then
- table.insert(Runtime.FakeBodyParts, bodyPart)
- Runtime.LimbGrids[partName] = NanoGrid.Create(
- bodyPart, effectiveCellSize, CFG.MechType, partName, extensionConfig
- )
- end
- end
- end
- local function SetupAttachConnection()
- if getgenv().NanoAttachConnection then getgenv().NanoAttachConnection:Disconnect() end
- getgenv().NanoAttachConnection = RunService.Heartbeat:Connect(function()
- if not Runtime.IsRunning or Runtime.IsDead then return end
- local realChar = Runtime.RealCharacter
- local fakeChar = Runtime.FakeCharacter
- if not realChar or not realChar.Parent then return end
- if not fakeChar or not fakeChar.Parent then return end
- local realHRP = realChar:FindFirstChild("HumanoidRootPart")
- local fakeHRP = fakeChar:FindFirstChild("HumanoidRootPart")
- if not realHRP or not fakeHRP then return end
- local realHum = realChar:FindFirstChildOfClass("Humanoid")
- if realHum then
- realHum.PlatformStand = true
- realHum.AutoRotate = false
- end
- realHRP.CFrame = fakeHRP.CFrame * CFG.RealCharOffset
- realHRP.AssemblyLinearVelocity = fakeHRP.AssemblyLinearVelocity
- realHRP.AssemblyAngularVelocity = Vector3.zero
- end)
- end
- local function SetupShiftLockRotation()
- if getgenv().NanoRenderConnection then getgenv().NanoRenderConnection:Disconnect() end
- getgenv().NanoRenderConnection = RunService.RenderStepped:Connect(function()
- if not Runtime.IsRunning or Runtime.IsDead then return end
- local fakeChar = Runtime.FakeCharacter
- if not fakeChar then return end
- local fakeHRP = fakeChar:FindFirstChild("HumanoidRootPart")
- local fakeHum = fakeChar:FindFirstChildOfClass("Humanoid")
- if not fakeHRP or not fakeHum then return end
- local isShiftLock = UserInputService.MouseBehavior == Enum.MouseBehavior.LockCenter
- if isShiftLock then
- fakeHum.AutoRotate = false
- local camCF = Workspace.CurrentCamera.CFrame
- local _, y, _ = camCF:ToEulerAnglesYXZ()
- fakeHRP.CFrame = CFrame.new(fakeHRP.Position) * CFrame.Angles(0, y, 0)
- else
- fakeHum.AutoRotate = true
- end
- end)
- end
- local function CheckGrounded(fakeHRP)
- local rayParams = RaycastParams.new()
- rayParams.FilterType = Enum.RaycastFilterType.Exclude
- rayParams.FilterDescendantsInstances = {Runtime.FakeCharacter, Runtime.RealCharacter}
- local checkDist = CFG.GroundCheckDistance * CFG.MechScale
- local offsets = {
- Vector3.new(0, 0, 0),
- Vector3.new(1, 0, 0), Vector3.new(-1, 0, 0),
- Vector3.new(0, 0, 1), Vector3.new(0, 0, -1),
- }
- for _, offset in ipairs(offsets) do
- local origin = fakeHRP.Position + offset * CFG.MechScale * 0.5
- local result = Workspace:Raycast(origin, Vector3.new(0, -checkDist, 0), rayParams)
- if result then return true end
- end
- return false
- end
- local function SyncMovement()
- if Runtime.IsDead then return end
- local fakeChar = Runtime.FakeCharacter
- local fakeHum = fakeChar and fakeChar:FindFirstChildOfClass("Humanoid")
- local fakeHRP = fakeChar and fakeChar:FindFirstChild("HumanoidRootPart")
- if not fakeHum or not fakeHRP then return end
- Runtime.IsGrounded = CheckGrounded(fakeHRP)
- local velY = fakeHRP.AssemblyLinearVelocity.Y
- if Runtime.IsGrounded and math.abs(velY) < 10 then
- Runtime.JumpState = "GROUNDED"
- elseif velY > 5 then
- Runtime.JumpState = "JUMPING"
- elseif velY < -5 then
- Runtime.JumpState = "FALLING"
- end
- if UserInputService:GetFocusedTextBox() then
- fakeHum:Move(Vector3.zero, false)
- return
- end
- local camera = Workspace.CurrentCamera
- local moveDir = Vector3.zero
- local W = UserInputService:IsKeyDown(Enum.KeyCode.W)
- local A = UserInputService:IsKeyDown(Enum.KeyCode.A)
- local S = UserInputService:IsKeyDown(Enum.KeyCode.S)
- local D = UserInputService:IsKeyDown(Enum.KeyCode.D)
- local spacePressed = UserInputService:IsKeyDown(Enum.KeyCode.Space)
- if W or A or S or D then
- local look = camera.CFrame.LookVector * Vector3.new(1, 0, 1)
- local right = camera.CFrame.RightVector * Vector3.new(1, 0, 1)
- if look.Magnitude > 0.01 then look = look.Unit end
- if right.Magnitude > 0.01 then right = right.Unit end
- if W then moveDir = moveDir + look end
- if S then moveDir = moveDir - look end
- if D then moveDir = moveDir + right end
- if A then moveDir = moveDir - right end
- if moveDir.Magnitude > 0.01 then moveDir = moveDir.Unit end
- end
- fakeHum:Move(moveDir, false)
- local now = tick()
- if spacePressed and Runtime.IsGrounded and (now - Runtime.LastJumpTime) > CFG.JumpDebounce then
- Runtime.LastJumpTime = now
- fakeHum.Jump = true
- end
- end
- local function IsValidPart(part)
- if part.Anchored then return false end
- if part:IsA("Terrain") then return false end
- if string.find(part.Name, "Nano") then return false end
- if Runtime.RealCharacter and part:IsDescendantOf(Runtime.RealCharacter) then return false end
- if Runtime.FakeCharacter and part:IsDescendantOf(Runtime.FakeCharacter) then return false end
- local ancestor = part.Parent
- while ancestor and ancestor ~= Workspace do
- if ancestor:FindFirstChildOfClass("Humanoid") then return false end
- ancestor = ancestor.Parent
- end
- local ts = Runtime.NewPartsTimestamp[part]
- if ts and tick() - ts < CFG.TransformTimeout then return false end
- if part.Size.X * part.Size.Y * part.Size.Z < 0.001 then return false end
- local maxSize = 10 * CFG.MechScale
- if part.Size.X > maxSize or part.Size.Y > maxSize or part.Size.Z > maxSize then
- return false
- end
- return true
- end
- local function SetupNewPartDetection()
- if getgenv().NanoNewPartConnection then getgenv().NanoNewPartConnection:Disconnect() end
- getgenv().NanoNewPartConnection = Workspace.DescendantAdded:Connect(function(desc)
- if not Runtime.IsRunning or Runtime.IsDead then return end
- if desc:IsA("BasePart") then
- Runtime.NewPartsTimestamp[desc] = tick()
- task.delay(CFG.TransformTimeout + 0.05, function()
- if not Runtime.IsRunning or Runtime.IsDead then return end
- if desc and desc.Parent and IsValidPart(desc) and not Runtime.TrackedParts[desc] then
- Runtime.PendingParts[desc] = true
- end
- end)
- end
- end)
- end
- local function ScanParts()
- local scanPos
- if CFG.ScanFromReal and Runtime.RealCharacter then
- local realHRP = Runtime.RealCharacter:FindFirstChild("HumanoidRootPart")
- if realHRP then scanPos = realHRP.Position end
- end
- if not scanPos and Runtime.FakeCharacter then
- local fakeHRP = Runtime.FakeCharacter:FindFirstChild("HumanoidRootPart")
- if fakeHRP then scanPos = fakeHRP.Position end
- end
- if not scanPos then return {} end
- local params = OverlapParams.new()
- params.FilterType = Enum.RaycastFilterType.Exclude
- local filterList = {}
- for _, player in ipairs(Players:GetPlayers()) do
- if player.Character then table.insert(filterList, player.Character) end
- end
- if Runtime.RealCharacter then table.insert(filterList, Runtime.RealCharacter) end
- if Runtime.FakeCharacter then table.insert(filterList, Runtime.FakeCharacter) end
- params.FilterDescendantsInstances = filterList
- params.MaxParts = CFG.MaxParts * 2
- local raw
- if CFG.ScanMode == "Box" then
- raw = Workspace:GetPartBoundsInBox(CFrame.new(scanPos) * CFG.ScanBoxOffset, CFG.ScanBoxSize, params)
- else
- raw = Workspace:GetPartBoundsInRadius(scanPos, CFG.ScanRadius, params)
- end
- local valid = {}
- for _, part in ipairs(raw) do
- if #valid >= CFG.MaxParts then break end
- if part:IsA("BasePart") and part.Parent and IsValidPart(part) then
- table.insert(valid, part)
- end
- end
- for part in pairs(Runtime.PendingParts) do
- if part and part.Parent and IsValidPart(part) and not Runtime.TrackedParts[part] then
- if #valid < CFG.MaxParts then
- table.insert(valid, part)
- end
- end
- Runtime.PendingParts[part] = nil
- end
- Runtime.ScannedPartsCount = #valid
- Runtime.PendingPartsCount = 0
- for _ in pairs(Runtime.PendingParts) do
- Runtime.PendingPartsCount = Runtime.PendingPartsCount + 1
- end
- table.sort(valid, function(a, b)
- return a.Size.X * a.Size.Y * a.Size.Z > b.Size.X * b.Size.Y * b.Size.Z
- end)
- return valid
- end
- local function FindBestLimbForPart(part)
- local existingLimb = part:GetAttribute("NanoLimb")
- if existingLimb and Runtime.LimbGrids[existingLimb] then return existingLimb end
- local partSize = part.Size
- local closest = nil
- local closestScore = -math.huge
- for name, grid in pairs(Runtime.LimbGrids) do
- if EXCLUDED_PARTS[name] then continue end
- if grid.bodyPart and grid.bodyPart.Parent then
- local gridPos, rotData, cells, score = NanoGrid.FindBestPlacement(grid, partSize, CFG.SlotPriority)
- if gridPos and score > closestScore then
- closestScore = score
- closest = name
- end
- end
- end
- return closest
- end
- local function AttachPartToGrid(part, grid)
- local partSize = part.Size
- local gridPos, rotData, cells, score = NanoGrid.FindBestPlacement(grid, partSize, CFG.SlotPriority)
- if not gridPos then return false end
- local limbName = grid.bodyPart.Name
- if EXCLUDED_PARTS[limbName] then return false end
- local hasTouchInterest = NanoCharacter.HasTouchInterest(part)
- local originalProps = {
- CanCollide = part.CanCollide,
- Massless = part.Massless,
- CollisionGroup = part.CollisionGroup,
- CanTouch = part.CanTouch
- }
- pcall(function()
- part.CollisionGroup = NANO_GROUP
- part.CanCollide = CFG.PartsCanCollide
- part.Massless = CFG.PartsMassless
- if CFG.DisableTouchInterest or hasTouchInterest then
- part.CanTouch = false
- end
- end)
- NanoGrid.MarkAreaOccupied(grid, gridPos.X, gridPos.Y, gridPos.Z, cells.X, cells.Y, cells.Z, part)
- local worldOffset = NanoGrid.GetWorldOffset(grid, gridPos, cells)
- local rotation = rotData.cf
- local movers = NanoPhysics.CreateAlignMovers(part, grid.bodyPart, worldOffset, rotation)
- Runtime.PartIndex = Runtime.PartIndex + 1
- part:SetAttribute("NanoLimb", limbName)
- part:SetAttribute("NanoSlot", Runtime.PartIndex)
- Runtime.TrackedParts[part] = {
- limbName = limbName,
- grid = grid,
- gridPos = gridPos,
- cells = cells,
- rotation = rotation,
- worldOffset = worldOffset,
- movers = movers,
- originalProps = originalProps,
- index = Runtime.PartIndex
- }
- return true
- end
- local function DetachPart(part)
- local data = Runtime.TrackedParts[part]
- if not data then return end
- NanoPhysics.ReturnMovers(data.movers)
- if data.grid and data.gridPos and data.cells then
- NanoGrid.MarkAreaFree(data.grid, data.gridPos.X, data.gridPos.Y, data.gridPos.Z, data.cells.X, data.cells.Y, data.cells.Z)
- end
- if data.originalProps and part and part.Parent then
- pcall(function()
- part.CanCollide = data.originalProps.CanCollide
- part.Massless = data.originalProps.Massless
- part.CollisionGroup = data.originalProps.CollisionGroup or "Default"
- part.CanTouch = data.originalProps.CanTouch
- end)
- end
- pcall(function()
- part:SetAttribute("NanoLimb", nil)
- part:SetAttribute("NanoSlot", nil)
- end)
- Runtime.TrackedParts[part] = nil
- end
- local function ProcessPartsChunked(parts)
- local currentParts = {}
- for _, p in ipairs(parts) do currentParts[p] = true end
- local toRemove = {}
- for part in pairs(Runtime.TrackedParts) do
- if not currentParts[part] or not part.Parent then
- table.insert(toRemove, part)
- end
- end
- for _, part in ipairs(toRemove) do DetachPart(part) end
- local toAttach = {}
- for _, part in ipairs(parts) do
- if not Runtime.TrackedParts[part] then
- table.insert(toAttach, part)
- end
- end
- if #toAttach == 0 then return end
- local chunkSize = CFG.ChunkSize
- local processed = 0
- local function processChunk()
- if Runtime.IsDead or not Runtime.IsRunning then return end
- local startIdx = processed + 1
- local endIdx = math.min(processed + chunkSize, #toAttach)
- for i = startIdx, endIdx do
- local part = toAttach[i]
- if part and part.Parent and not Runtime.TrackedParts[part] then
- local limbName = FindBestLimbForPart(part)
- if limbName and not EXCLUDED_PARTS[limbName] then
- local grid = Runtime.LimbGrids[limbName]
- if grid then AttachPartToGrid(part, grid) end
- end
- end
- end
- processed = endIdx
- if processed < #toAttach then task.defer(processChunk) end
- end
- task.spawn(processChunk)
- end
- local function UpdateMovers()
- if Runtime.IsDead then return end
- local toRemove = {}
- for part, data in pairs(Runtime.TrackedParts) do
- if not part or not part.Parent then
- table.insert(toRemove, part)
- elseif not data.grid or not data.grid.bodyPart or not data.grid.bodyPart.Parent then
- table.insert(toRemove, part)
- else
- NanoPhysics.ApplyAntisleep(part, CFG, LocalPlayer)
- end
- end
- for _, part in ipairs(toRemove) do DetachPart(part) end
- pcall(function() settings().Physics.AllowSleep = false end)
- end
- local function OnDeath()
- if Runtime.IsDead then return end
- Runtime.IsDead = true
- Runtime.IsRunning = false
- if Runtime.FakeCharacter then
- local fakeHum = Runtime.FakeCharacter:FindFirstChildOfClass("Humanoid")
- if fakeHum then
- pcall(function()
- fakeHum.WalkSpeed = 0
- fakeHum.JumpPower = 0
- fakeHum.PlatformStand = true
- end)
- end
- end
- local camera = Workspace.CurrentCamera
- camera.CameraType = Enum.CameraType.Custom
- local targetChar = Runtime.RealCharacter or LocalPlayer.Character
- if targetChar then
- local hum = targetChar:FindFirstChildOfClass("Humanoid")
- if hum then camera.CameraSubject = hum end
- end
- for part in pairs(Runtime.TrackedParts) do DetachPart(part) end
- task.delay(CFG.DeathRestoreTimeout, CleanupNano)
- end
- local function SetupDeathDetection()
- if getgenv().NanoDeathConnection then getgenv().NanoDeathConnection:Disconnect() end
- local fakeChar = Runtime.FakeCharacter
- local realChar = Runtime.RealCharacter
- if fakeChar then
- local hum = fakeChar:FindFirstChildOfClass("Humanoid")
- if hum then hum.Died:Once(OnDeath) end
- end
- if realChar then
- local hum = realChar:FindFirstChildOfClass("Humanoid")
- if hum then hum.Died:Once(OnDeath) end
- end
- getgenv().NanoDeathConnection = RunService.Heartbeat:Connect(function()
- if Runtime.IsDead then return end
- if not Runtime.FakeCharacter or not Runtime.FakeCharacter.Parent then OnDeath()
- elseif not Runtime.RealCharacter or not Runtime.RealCharacter.Parent then OnDeath() end
- end)
- end
- local function StartNano()
- if STARTING or STARTED then return end
- STARTING = true
- local char = LocalPlayer.Character
- if not char then STARTING = false return end
- local root = char:FindFirstChild("HumanoidRootPart")
- local hum = char:FindFirstChildOfClass("Humanoid")
- if not root or not hum then STARTING = false return end
- NanoPool.Init()
- NanoGui.SaveState()
- Runtime.RealCharacter = char
- Runtime.RealRigType = NanoCharacter.GetRigType(char)
- Runtime.IsDead = false
- Runtime.LastJumpTime = 0
- local fake, fakeRig = NanoCharacter.CreateFake(char, CFG.FakeRig, CFG)
- if not fake then
- warn("[NANO] Failed to create fake")
- STARTING = false
- return
- end
- Runtime.FakeCharacter = fake
- Runtime.FakeRigType = fakeRig
- local fakeHRP = fake:FindFirstChild("HumanoidRootPart")
- if not fakeHRP then
- fake:Destroy()
- STARTING = false
- return
- end
- SetupNoCollisionConstraints()
- NanoCharacter.DisableReal(char, CFG, Runtime.OriginalStates)
- NanoCharacter.DisableTouchOnCharacter(fake)
- SetupFakeCharDescendantTracking()
- CreateLimbGrids()
- LocalPlayer.Character = fake
- task.wait(0.1)
- NanoGui.RestoreState()
- SetupCamera()
- SetupAttachConnection()
- SetupShiftLockRotation()
- task.wait(0.2)
- NanoCharacter.SetupAnimations(fake, fakeRig, Runtime.RealRigType)
- Runtime.IsRunning = true
- STARTED = true
- STARTING = false
- SetSimulationRadius()
- SetFallenPartsDestroyHeight()
- SetupDeathDetection()
- SetupNewPartDetection()
- if CFG.DebugStatsGui then NanoGui.CreateDebug(Runtime, CFG) end
- local lastPackTime = 0
- getgenv().NanoConnection = RunService.Heartbeat:Connect(function()
- if not Runtime.IsRunning or Runtime.IsDead then return end
- local fakeChar = Runtime.FakeCharacter
- if not fakeChar or not fakeChar.Parent then return end
- SyncMovement()
- UpdateMovers()
- CleanupOldTimestamps()
- if CFG.DebugStatsGui then NanoGui.UpdateDebug(Runtime, CFG) end
- local now = tick()
- if now - lastPackTime >= CFG.PackInterval then
- lastPackTime = now
- local parts = ScanParts()
- ProcessPartsChunked(parts)
- end
- end)
- StarterGui:SetCore("SendNotification", {
- Title = "NanoMech v3.6",
- Text = string.format("%sā%s | Scale:%.1fx | %s",
- Runtime.RealRigType, Runtime.FakeRigType, CFG.MechScale, CFG.MechType),
- Duration = 3
- })
- end
- getgenv().NanoAPI = {
- Start = StartNano,
- Stop = CleanupNano,
- SetScale = function(scale)
- CFG.MechScale = scale
- if Runtime.FakeCharacter then
- pcall(function() Runtime.FakeCharacter:ScaleTo(scale) end)
- for part in pairs(Runtime.TrackedParts) do DetachPart(part) end
- CreateLimbGrids()
- end
- end,
- SetMechType = function(mechType)
- CFG.MechType = mechType
- for part in pairs(Runtime.TrackedParts) do DetachPart(part) end
- CreateLimbGrids()
- end,
- SetFakeRig = function(rig) CFG.FakeRig = NanoCharacter.NormalizeRig(rig) end,
- SetCellSize = function(size)
- CFG.CellSize = size
- for part in pairs(Runtime.TrackedParts) do DetachPart(part) end
- CreateLimbGrids()
- end,
- SetDebugGui = function(enabled)
- CFG.DebugStatsGui = enabled
- if enabled then NanoGui.CreateDebug(Runtime, CFG) else NanoGui.DestroyDebug() end
- end,
- ToggleR15Extensions = function(enabled)
- CFG.R15ExtensionsEnabled = enabled
- for part in pairs(Runtime.TrackedParts) do DetachPart(part) end
- CreateLimbGrids()
- end,
- ToggleR6Extensions = function(enabled)
- CFG.R6ExtensionsEnabled = enabled
- for part in pairs(Runtime.TrackedParts) do DetachPart(part) end
- CreateLimbGrids()
- end,
- SetChunkSize = function(size) CFG.ChunkSize = size end,
- SetScanRadius = function(radius) CFG.ScanRadius = radius end,
- SetJumpDebounce = function(time) CFG.JumpDebounce = time end,
- GetPoolStats = function() return NanoPool.Stats end,
- GetRuntime = function() return Runtime end,
- GetConfig = function() return CFG end,
- ForceRefreshGrids = function()
- for part in pairs(Runtime.TrackedParts) do DetachPart(part) end
- CreateLimbGrids()
- end,
- CopyDebugInfo = function()
- NanoGui.CopyInfo(Runtime, CFG)
- end
- }
- task.wait(0.5)
- StartNano()
Advertisement
Add Comment
Please, Sign In to add comment