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
- 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)
- local sethidden = newcclosure(function(instance, property, value)
- 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)
- end)
- local Services = setmetatable({}, {
- __index = function(self, name)
- local ok, svc = pcall(function() return cloneref(game:GetService(name)) end)
- if ok then rawset(self, name, svc) return svc end
- error("Invalid Service: " .. tostring(name))
- end
- })
- local Players = Services.Players
- local RunService = Services.RunService
- local Workspace = Services.Workspace
- local UserInputService = Services.UserInputService
- local LocalPlayer = Players.LocalPlayer
- local function CleanupNano()
- if getgenv().NanoConnection then
- getgenv().NanoConnection:Disconnect()
- getgenv().NanoConnection = nil
- end
- if getgenv().NanoRuntime and getgenv().NanoRuntime.BodyMovers then
- for part, _ in pairs(getgenv().NanoRuntime.BodyMovers) do
- pcall(function()
- if part and part.Parent then
- local bp = part:FindFirstChild("NanoBP")
- local bg = part:FindFirstChild("NanoBG")
- if bp then bp:Destroy() end
- if bg then bg:Destroy() end
- local state = getgenv().NanoRuntime.OriginalStates[part]
- if state then
- part.CanCollide = state.CanCollide
- part.Massless = state.Massless
- end
- end
- end)
- end
- end
- if getgenv().NanoGui then
- pcall(function() getgenv().NanoGui:Destroy() end)
- getgenv().NanoGui = nil
- end
- if getgenv().NanoDebugBox then
- pcall(function() getgenv().NanoDebugBox:Destroy() end)
- getgenv().NanoDebugBox = nil
- end
- getgenv().NanoRuntime = nil
- end
- CleanupNano()
- getgenv().NanoConfigs = {
- ContainerSize = Vector3.new(10, 10, 10),
- OffsetX = 0,
- OffsetY = 5,
- OffsetZ = -14,
- RotateX = 0,
- RotateY = 0,
- RotateZ = 0,
- ScanRadius = 100,
- ScanBoxSize = Vector3.new(80, 40, 80),
- MaxParts = 500,
- SimRadius = 1000,
- PartsCanCollide = false,
- PartsMassless = true,
- Padding = 0.05,
- BinFollow = false,
- PackInterval = 0.4,
- BodyPositionP = 50000,
- BodyPositionD = 800,
- BodyPositionMaxForce = 1e9,
- BodyGyroP = 10000,
- BodyGyroD = 300,
- BodyGyroMaxTorque = 1e9,
- AutoResize = true,
- MinSize = Vector3.new(5, 5, 5),
- MaxSize = Vector3.new(25, 25, 25),
- CheckNetworkOwner = true,
- UseRootPriority = true,
- RootPriorityValue = 2147483647,
- Whitelist = nil,
- Blacklist = nil,
- Debug = true,
- ShowContainer = true
- }
- local CFG = getgenv().NanoConfigs
- getgenv().NanoRuntime = {
- BodyMovers = {},
- OriginalStates = {},
- Placements = {},
- LastPackTime = 0,
- LastPartCount = 0,
- StaticLocation = nil,
- SimRadiusSet = false,
- IsRunning = false,
- CurrentSize = nil,
- Stats = {
- Parts = 0,
- Efficiency = 0,
- Dropped = 0
- }
- }
- local Runtime = getgenv().NanoRuntime
- local function Log(msg)
- if CFG.Debug then print("[NANO]", msg) end
- end
- local function SetSimRadius()
- if Runtime.SimRadiusSet then return end
- sethidden(LocalPlayer, "SimulationRadius", CFG.SimRadius)
- sethidden(LocalPlayer, "MaximumSimulationRadius", CFG.SimRadius)
- Runtime.SimRadiusSet = true
- end
- local function GetContainerCFrame(rootCF)
- local offset = CFrame.new(CFG.OffsetX, CFG.OffsetY, CFG.OffsetZ)
- local rotation = CFrame.Angles(math.rad(CFG.RotateX), math.rad(CFG.RotateY), math.rad(CFG.RotateZ))
- return rootCF * offset * rotation
- end
- local Shelf3D = {}
- Shelf3D.__index = Shelf3D
- function Shelf3D.new(containerSize, padding)
- local self = setmetatable({}, Shelf3D)
- self.W = containerSize.X
- self.H = containerSize.Y
- self.D = containerSize.Z
- self.padding = padding or 0.05
- self.halfSize = containerSize / 2
- self.layers = {}
- self.currentLayerZ = 0
- self.currentLayerMaxD = 0
- self.shelves = {}
- self.currentShelfY = 0
- self.currentShelfMaxH = 0
- self.cursorX = 0
- self.placements = {}
- self.usedVolume = 0
- self.containerVolume = containerSize.X * containerSize.Y * containerSize.Z
- return self
- end
- function Shelf3D:getBestRotation(partSize)
- local rotations = {
- {s = Vector3.new(partSize.X, partSize.Y, partSize.Z), r = CFrame.new()},
- {s = Vector3.new(partSize.Z, partSize.Y, partSize.X), r = CFrame.Angles(0, math.rad(90), 0)},
- {s = Vector3.new(partSize.X, partSize.Z, partSize.Y), r = CFrame.Angles(math.rad(90), 0, 0)},
- {s = Vector3.new(partSize.Y, partSize.X, partSize.Z), r = CFrame.Angles(0, 0, math.rad(90))},
- {s = Vector3.new(partSize.Z, partSize.X, partSize.Y), r = CFrame.Angles(math.rad(90), math.rad(90), 0)},
- {s = Vector3.new(partSize.Y, partSize.Z, partSize.X), r = CFrame.Angles(0, math.rad(90), math.rad(90))}
- }
- local best = nil
- local bestScore = math.huge
- for _, rot in ipairs(rotations) do
- local s = rot.s
- if s.X <= self.W and s.Y <= self.H and s.Z <= self.D then
- local score = s.Y * 100 + s.Z * 10 + s.X
- if score < bestScore then
- bestScore = score
- best = rot
- end
- end
- end
- return best
- end
- function Shelf3D:place(part)
- local rot = self:getBestRotation(part.Size)
- if not rot then return nil end
- local w, h, d = rot.s.X, rot.s.Y, rot.s.Z
- local pad = self.padding
- if self.cursorX + w > self.W then
- self.cursorX = 0
- self.currentShelfY = self.currentShelfY + self.currentShelfMaxH + pad
- self.currentShelfMaxH = 0
- end
- if self.currentShelfY + h > self.H then
- self.currentShelfY = 0
- self.currentShelfMaxH = 0
- self.cursorX = 0
- self.currentLayerZ = self.currentLayerZ + self.currentLayerMaxD + pad
- self.currentLayerMaxD = 0
- end
- if self.currentLayerZ + d > self.D then
- return nil
- end
- local x = self.cursorX
- local y = self.currentShelfY
- local z = self.currentLayerZ
- local localPos = Vector3.new(
- x + w/2 - self.halfSize.X,
- y + h/2 - self.halfSize.Y,
- z + d/2 - self.halfSize.Z
- )
- self.cursorX = x + w + pad
- self.currentShelfMaxH = math.max(self.currentShelfMaxH, h)
- self.currentLayerMaxD = math.max(self.currentLayerMaxD, d)
- self.usedVolume = self.usedVolume + (w * h * d)
- local placement = {
- part = part,
- localPos = localPos,
- rotation = rot.r,
- size = rot.s
- }
- self.placements[#self.placements + 1] = placement
- return placement
- end
- function Shelf3D:getEfficiency()
- if self.containerVolume == 0 then return 0 end
- return self.usedVolume / self.containerVolume
- end
- function Shelf3D:getUsedBounds()
- local maxX = self.cursorX
- local maxY = self.currentShelfY + self.currentShelfMaxH
- local maxZ = self.currentLayerZ + self.currentLayerMaxD
- return Vector3.new(maxX, maxY, maxZ)
- end
- local function CreateGui()
- if getgenv().NanoGui then return end
- local gui = Instance.new("ScreenGui")
- gui.Name = "NanoGui"
- gui.ResetOnSpawn = false
- local main = Instance.new("Frame")
- main.Size = UDim2.new(0, 200, 0, 140)
- main.Position = UDim2.new(0, 10, 0.5, -70)
- main.BackgroundColor3 = Color3.fromRGB(20, 20, 30)
- main.BorderSizePixel = 0
- main.Active = true
- main.Parent = gui
- Instance.new("UICorner", main).CornerRadius = UDim.new(0, 8)
- local stroke = Instance.new("UIStroke", main)
- stroke.Color = Color3.fromRGB(0, 200, 150)
- stroke.Thickness = 1
- local dragging, dragStart, startPos
- main.InputBegan:Connect(function(input)
- if input.UserInputType == Enum.UserInputType.MouseButton1 then
- dragging = true
- dragStart = input.Position
- startPos = main.Position
- end
- end)
- main.InputEnded:Connect(function(input)
- if input.UserInputType == Enum.UserInputType.MouseButton1 then
- dragging = false
- end
- end)
- UserInputService.InputChanged:Connect(function(input)
- if dragging and input.UserInputType == Enum.UserInputType.MouseMovement then
- local delta = input.Position - dragStart
- main.Position = UDim2.new(startPos.X.Scale, startPos.X.Offset + delta.X, startPos.Y.Scale, startPos.Y.Offset + delta.Y)
- end
- end)
- local title = Instance.new("TextLabel")
- title.Size = UDim2.new(1, -30, 0, 25)
- title.Position = UDim2.new(0, 8, 0, 2)
- title.BackgroundTransparency = 1
- title.Text = "NanoBin Shelf3D"
- title.TextColor3 = Color3.fromRGB(0, 255, 180)
- title.TextSize = 14
- title.Font = Enum.Font.GothamBold
- title.TextXAlignment = Enum.TextXAlignment.Left
- title.Parent = main
- local closeBtn = Instance.new("TextButton")
- closeBtn.Size = UDim2.new(0, 22, 0, 22)
- closeBtn.Position = UDim2.new(1, -26, 0, 3)
- closeBtn.BackgroundColor3 = Color3.fromRGB(180, 50, 50)
- closeBtn.Text = "X"
- closeBtn.TextColor3 = Color3.new(1, 1, 1)
- closeBtn.TextSize = 12
- closeBtn.Font = Enum.Font.GothamBold
- closeBtn.Parent = main
- Instance.new("UICorner", closeBtn).CornerRadius = UDim.new(0, 4)
- closeBtn.MouseButton1Click:Connect(CleanupNano)
- local stats = Instance.new("TextLabel")
- stats.Name = "Stats"
- stats.Size = UDim2.new(1, -16, 1, -32)
- stats.Position = UDim2.new(0, 8, 0, 28)
- stats.BackgroundTransparency = 1
- stats.Text = "..."
- stats.TextColor3 = Color3.fromRGB(180, 180, 180)
- stats.TextSize = 11
- stats.Font = Enum.Font.Gotham
- stats.TextXAlignment = Enum.TextXAlignment.Left
- stats.TextYAlignment = Enum.TextYAlignment.Top
- stats.Parent = main
- pcall(function() gui.Parent = game:GetService("CoreGui") end)
- if not gui.Parent then gui.Parent = LocalPlayer:WaitForChild("PlayerGui") end
- getgenv().NanoGui = gui
- task.spawn(function()
- while gui.Parent and Runtime do
- local s = Runtime.Stats
- local sz = Runtime.CurrentSize or CFG.ContainerSize
- stats.Text = string.format(
- "Parts: %d\nEfficiency: %.1f%%\nDropped: %d\n\nContainer: %.0fx%.0fx%.0f\nOffset: %.0f, %.0f, %.0f\nRotate: %.0f°, %.0f°, %.0f°",
- s.Parts,
- s.Efficiency * 100,
- s.Dropped,
- sz.X, sz.Y, sz.Z,
- CFG.OffsetX, CFG.OffsetY, CFG.OffsetZ,
- CFG.RotateX, CFG.RotateY, CFG.RotateZ
- )
- task.wait(0.2)
- end
- end)
- end
- local function UpdateDebugBox(cf)
- if not CFG.Debug or not CFG.ShowContainer then
- if getgenv().NanoDebugBox then
- pcall(function() getgenv().NanoDebugBox:Destroy() end)
- getgenv().NanoDebugBox = nil
- end
- return
- end
- local size = Runtime.CurrentSize or CFG.ContainerSize
- if not getgenv().NanoDebugBox or not getgenv().NanoDebugBox.Parent then
- local box = Instance.new("Part")
- box.Name = "NanoDebugBox"
- box.Anchored = true
- box.CanCollide = false
- box.CastShadow = false
- box.Material = Enum.Material.ForceField
- box.Color = Color3.fromRGB(0, 255, 180)
- box.Transparency = 0.9
- box.Parent = Workspace
- getgenv().NanoDebugBox = box
- end
- getgenv().NanoDebugBox.CFrame = cf
- getgenv().NanoDebugBox.Size = size
- end
- local function GetOrCreateBP(part)
- local bp = part:FindFirstChild("NanoBP")
- if not bp then
- bp = Instance.new("BodyPosition")
- bp.Name = "NanoBP"
- bp.MaxForce = Vector3.new(CFG.BodyPositionMaxForce, CFG.BodyPositionMaxForce, CFG.BodyPositionMaxForce)
- bp.P = CFG.BodyPositionP
- bp.D = CFG.BodyPositionD
- bp.Parent = part
- end
- return bp
- end
- local function GetOrCreateBG(part)
- local bg = part:FindFirstChild("NanoBG")
- if not bg then
- bg = Instance.new("BodyGyro")
- bg.Name = "NanoBG"
- bg.MaxTorque = Vector3.new(CFG.BodyGyroMaxTorque, CFG.BodyGyroMaxTorque, CFG.BodyGyroMaxTorque)
- bg.P = CFG.BodyGyroP
- bg.D = CFG.BodyGyroD
- bg.Parent = part
- end
- return bg
- end
- local function RemoveMovers(part)
- pcall(function()
- local bp = part:FindFirstChild("NanoBP")
- local bg = part:FindFirstChild("NanoBG")
- if bp then bp:Destroy() end
- if bg then bg:Destroy() end
- end)
- end
- local function IsValidPart(part)
- if not part or not part.Parent then return false end
- if not part:IsA("BasePart") then return false end
- if part.Anchored then return false end
- if part:IsA("Terrain") then return false end
- if part.Name == "NanoDebugBox" then return false end
- local char = LocalPlayer.Character
- if char and part:IsDescendantOf(char) 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
- if CFG.Whitelist and #CFG.Whitelist > 0 then
- local found = false
- for _, name in ipairs(CFG.Whitelist) do
- if part.Name == name or string.find(part.Name, name) then
- found = true
- break
- end
- end
- if not found then return false end
- end
- if CFG.Blacklist then
- for _, name in ipairs(CFG.Blacklist) do
- if part.Name == name or string.find(part.Name, name) then
- return false
- end
- end
- end
- if CFG.CheckNetworkOwner then
- local ok, owner = pcall(function() return part:GetNetworkOwner() end)
- if ok and owner and owner ~= LocalPlayer then return false end
- end
- local containerSize = Runtime.CurrentSize or CFG.ContainerSize
- local minDim = math.min(containerSize.X, containerSize.Y, containerSize.Z)
- local partMax = math.max(part.Size.X, part.Size.Y, part.Size.Z)
- if partMax > minDim * 0.9 then return false end
- if part.Size.Magnitude < 0.3 then return false end
- return true
- end
- local function SaveState(part)
- if not Runtime.OriginalStates[part] then
- Runtime.OriginalStates[part] = {
- CanCollide = part.CanCollide,
- Massless = part.Massless
- }
- end
- end
- local function PreparePart(part)
- pcall(function()
- SaveState(part)
- if part.Locked then part.Locked = false end
- if CFG.UseRootPriority then
- part.RootPriority = CFG.RootPriorityValue
- end
- for _, child in ipairs(part:GetChildren()) do
- local cn = child.ClassName
- if cn == "BodyPosition" or cn == "BodyGyro" or cn == "BodyVelocity" or cn == "BodyForce" then
- if child.Name ~= "NanoBP" and child.Name ~= "NanoBG" then
- child:Destroy()
- end
- elseif cn == "RopeConstraint" or cn == "RodConstraint" then
- child.Length = math.huge
- child.Visible = false
- elseif cn == "SpringConstraint" then
- child.FreeLength = math.huge
- child.Stiffness = 0
- elseif cn == "AlignPosition" then
- child.MaxForce = 0
- elseif cn == "AlignOrientation" then
- child.MaxTorque = 0
- end
- end
- part.CanCollide = CFG.PartsCanCollide
- part.Massless = CFG.PartsMassless
- end)
- end
- local function ScanParts(rootPos)
- local params = OverlapParams.new()
- params.FilterType = Enum.RaycastFilterType.Exclude
- local filter = {}
- for _, player in ipairs(Players:GetPlayers()) do
- if player.Character then filter[#filter + 1] = player.Character end
- end
- params.FilterDescendantsInstances = filter
- params.MaxParts = CFG.MaxParts
- local parts = Workspace:GetPartBoundsInRadius(rootPos, CFG.ScanRadius, params)
- local valid = {}
- for _, part in ipairs(parts) do
- if IsValidPart(part) then
- valid[#valid + 1] = part
- end
- end
- table.sort(valid, function(a, b)
- local volA = a.Size.X * a.Size.Y * a.Size.Z
- local volB = b.Size.X * b.Size.Y * b.Size.Z
- return volA > volB
- end)
- return valid
- end
- local function PackParts(parts, containerCF)
- local oldMovers = Runtime.BodyMovers
- Runtime.BodyMovers = {}
- local partsSet = {}
- for _, p in ipairs(parts) do partsSet[p] = true end
- for part, _ in pairs(oldMovers) do
- if part and part.Parent and not partsSet[part] then
- RemoveMovers(part)
- end
- end
- local containerSize = Runtime.CurrentSize or CFG.ContainerSize
- local packer = Shelf3D.new(containerSize, CFG.Padding)
- local dropped = 0
- for _, part in ipairs(parts) do
- PreparePart(part)
- local placement = packer:place(part)
- if placement then
- local bp = GetOrCreateBP(part)
- local bg = GetOrCreateBG(part)
- local targetCF = containerCF * CFrame.new(placement.localPos) * placement.rotation
- bp.Position = targetCF.Position
- bg.CFrame = targetCF
- Runtime.BodyMovers[part] = {
- bp = bp,
- bg = bg,
- localPos = placement.localPos,
- rotation = placement.rotation
- }
- else
- dropped = dropped + 1
- RemoveMovers(part)
- end
- end
- Runtime.Stats.Parts = #packer.placements
- Runtime.Stats.Efficiency = packer:getEfficiency()
- Runtime.Stats.Dropped = dropped
- if CFG.AutoResize and packer:getEfficiency() > 0.85 and dropped > 0 then
- local usedBounds = packer:getUsedBounds()
- local newSize = Vector3.new(
- math.min(containerSize.X * 1.1, CFG.MaxSize.X),
- math.min(containerSize.Y * 1.1, CFG.MaxSize.Y),
- math.min(containerSize.Z * 1.1, CFG.MaxSize.Z)
- )
- if newSize ~= containerSize then
- Runtime.CurrentSize = newSize
- Log(string.format("Resize: %.1fx%.1fx%.1f", newSize.X, newSize.Y, newSize.Z))
- end
- end
- Runtime.Placements = packer.placements
- return packer.placements
- end
- local function UpdatePositions(containerCF)
- for part, data in pairs(Runtime.BodyMovers) do
- if part and part.Parent and data.bp and data.bg then
- local targetCF = containerCF * CFrame.new(data.localPos) * data.rotation
- data.bp.Position = targetCF.Position
- data.bg.CFrame = targetCF
- end
- end
- end
- local function StartNano()
- local char = LocalPlayer.Character
- if not char then return end
- local root = char:FindFirstChild("HumanoidRootPart")
- local hum = char:FindFirstChildOfClass("Humanoid")
- if not root or not hum then return end
- if Runtime.IsRunning then return end
- Runtime.IsRunning = true
- Runtime.CurrentSize = CFG.ContainerSize
- Runtime.BodyMovers = {}
- Runtime.OriginalStates = {}
- SetSimRadius()
- CreateGui()
- if not CFG.BinFollow then
- Runtime.StaticLocation = GetContainerCFrame(root.CFrame)
- end
- hum.Died:Once(function()
- Log("Died")
- Runtime.IsRunning = false
- for part, _ in pairs(Runtime.BodyMovers) do
- if part and part.Parent then RemoveMovers(part) end
- end
- Runtime.BodyMovers = {}
- end)
- local conn = RunService.Heartbeat:Connect(function()
- if not Runtime.IsRunning then return end
- local c = LocalPlayer.Character
- local r = c and c:FindFirstChild("HumanoidRootPart")
- local h = c and c:FindFirstChildOfClass("Humanoid")
- if not r or not h or h.Health <= 0 then return end
- local containerCF
- if CFG.BinFollow then
- containerCF = GetContainerCFrame(r.CFrame)
- else
- containerCF = Runtime.StaticLocation
- end
- UpdateDebugBox(containerCF)
- UpdatePositions(containerCF)
- local now = tick()
- if now - Runtime.LastPackTime >= CFG.PackInterval then
- Runtime.LastPackTime = now
- local parts = ScanParts(r.Position)
- local count = #parts
- if count ~= Runtime.LastPartCount then
- Runtime.LastPartCount = count
- PackParts(parts, containerCF)
- end
- end
- end)
- getgenv().NanoConnection = conn
- Log("Started - Shelf3D Packer")
- end
- StartNano()
Advertisement
Add Comment
Please, Sign In to add comment