--//================================================== --// Persistent UI + DoorCollision / Collision Controller --// Place this LocalScript inside StarterPlayerScripts --//================================================== local Players = game:GetService("Players") local LocalPlayer = Players.LocalPlayer local PlayerGui = LocalPlayer:WaitForChild("PlayerGui") --================================================== -- SETTINGS --================================================== local DOOR_NAME = "DoorCollision" local COLLISION_NAME = "Collision" local FAR_POSITION = 1000000000 -- Smaller buttons local BUTTON_WIDTH = 125 local BUTTON_HEIGHT = 32 --================================================== -- UI STATE --================================================== local DoorToggleState = false local CollisionToggleState = false --================================================== -- DOORCOLLISION STORAGE --================================================== -- A fresh snapshot is created every time -- DoorCollision is toggled ON. -- -- Each entry: -- -- DoorStorage[1] = { -- Parent = original parent, -- Clone = cloned DoorCollision -- } -- local DoorStorage = {} --================================================== -- COLLISION POSITION STORAGE --================================================== -- A fresh snapshot is created every time -- Collision is toggled ON. -- -- CollisionStorage[Object] = { -- Type = "UDim2" or "Vector3", -- Position = original position -- } -- local CollisionStorage = {} --================================================== -- INTERNAL STATE --================================================== local ControllerGui local DoorButton local CollisionButton local RecreatingUI = false local RestoringDoors = false local RestoringCollisionPositions = false --================================================== -- SAVE UI STATE --================================================== local function SaveUIState() -- The values are intentionally stored outside -- the ScreenGui so deleting the UI does not -- delete the toggle states. local SavedDoorState = DoorToggleState local SavedCollisionState = CollisionToggleState return SavedDoorState, SavedCollisionState end --================================================== -- UPDATE BUTTON TEXT --================================================== local function UpdateButtonText() if not DoorButton or not DoorButton.Parent then return end if not CollisionButton or not CollisionButton.Parent then return end DoorButton.Text = DoorToggleState and "Door: ON" or "Door: OFF" CollisionButton.Text = CollisionToggleState and "Collision: ON" or "Collision: OFF" end --================================================== -- CLONE OBJECT --================================================== local function CloneObject(Object) if not Object then return nil end local PreviousArchivable = Object.Archivable pcall(function() Object.Archivable = true end) local Success, Clone = pcall(function() return Object:Clone() end) pcall(function() Object.Archivable = PreviousArchivable end) if Success and Clone then return Clone end return nil end --================================================== -- STORE DOORCOLLISION SNAPSHOT --================================================== local function StoreDoorCollisions() -- IMPORTANT: -- Every ON toggle gets a completely fresh snapshot. DoorStorage = {} for _, Object in ipairs(game:GetDescendants()) do if Object.Name == DOOR_NAME then local Parent = Object.Parent if Parent then local Clone = CloneObject(Object) if Clone then table.insert(DoorStorage, { Parent = Parent, Clone = Clone }) end end end end end --================================================== -- REMOVE DOORCOLLISION --================================================== local function RemoveDoorCollisions() for _, Object in ipairs(game:GetDescendants()) do if Object.Name == DOOR_NAME then pcall(function() Object:Destroy() end) end end end --================================================== -- RESTORE DOORCOLLISION --================================================== local function RestoreDoorCollisions() if RestoringDoors then return end RestoringDoors = true for _, Data in ipairs(DoorStorage) do local Parent = Data.Parent local StoredClone = Data.Clone if Parent and Parent.Parent and StoredClone then local NewObject = CloneObject(StoredClone) if NewObject then local Success = pcall(function() NewObject.Parent = Parent end) if not Success then pcall(function() NewObject:Destroy() end) end end end end -- The snapshot has now been used. DoorStorage = {} RestoringDoors = false end --================================================== -- STORE COLLISION POSITIONS --================================================== local function StoreCollisionPositions() -- Fresh snapshot every time Toggle 2 becomes ON. CollisionStorage = {} for _, Object in ipairs(game:GetDescendants()) do if Object.Name == COLLISION_NAME then -- GUI if Object:IsA("GuiObject") then local Success, Position = pcall(function() return Object.Position end) if Success then CollisionStorage[Object] = { Type = "UDim2", Position = Position } end -- Part / MeshPart / Union etc. elseif Object:IsA("BasePart") then local Success, Position = pcall(function() return Object.Position end) if Success then CollisionStorage[Object] = { Type = "Vector3", Position = Position } end -- Attachment elseif Object:IsA("Attachment") then local Success, Position = pcall(function() return Object.Position end) if Success then CollisionStorage[Object] = { Type = "Vector3", Position = Position } end -- Generic Position property else local Success, Position = pcall(function() return Object.Position end) if Success then if typeof(Position) == "UDim2" then CollisionStorage[Object] = { Type = "UDim2", Position = Position } elseif typeof(Position) == "Vector3" then CollisionStorage[Object] = { Type = "Vector3", Position = Position } end end end end end end --================================================== -- MOVE COLLISION --================================================== local function MoveCollisionObject(Object) if not Object then return end -- GUI if Object:IsA("GuiObject") then pcall(function() Object.Position = UDim2.new( 0, FAR_POSITION, 0, FAR_POSITION ) end) return end -- Part if Object:IsA("BasePart") then pcall(function() Object.Position = Vector3.new( FAR_POSITION, FAR_POSITION, FAR_POSITION ) end) return end -- Attachment if Object:IsA("Attachment") then pcall(function() Object.Position = Vector3.new( FAR_POSITION, FAR_POSITION, FAR_POSITION ) end) return end -- Generic Position pcall(function() local Position = Object.Position if typeof(Position) == "UDim2" then Object.Position = UDim2.new( 0, FAR_POSITION, 0, FAR_POSITION ) elseif typeof(Position) == "Vector3" then Object.Position = Vector3.new( FAR_POSITION, FAR_POSITION, FAR_POSITION ) end end) end --================================================== -- MOVE ALL COLLISIONS --================================================== local function MoveAllCollisions() for _, Object in ipairs(game:GetDescendants()) do if Object.Name == COLLISION_NAME then MoveCollisionObject(Object) end end end --================================================== -- RESTORE COLLISION POSITIONS --================================================== local function RestoreCollisionPositions() if RestoringCollisionPositions then return end RestoringCollisionPositions = true for Object, Data in pairs(CollisionStorage) do if Object and Object.Parent and Data then if Data.Type == "UDim2" then pcall(function() Object.Position = Data.Position end) elseif Data.Type == "Vector3" then pcall(function() Object.Position = Data.Position end) end end end -- Fresh snapshot will be made on the next ON toggle. CollisionStorage = {} RestoringCollisionPositions = false end --================================================== -- CREATE UI --================================================== local function CreateControllerUI() if RecreatingUI then return end RecreatingUI = true -- Remove an old copy if one somehow exists. local OldGui = PlayerGui:FindFirstChild( "DoorCollisionController" ) if OldGui then OldGui:Destroy() end --================================================== -- SCREEN GUI --================================================== ControllerGui = Instance.new("ScreenGui") ControllerGui.Name = "DoorCollisionController" ControllerGui.ResetOnSpawn = false ControllerGui.IgnoreGuiInset = true ControllerGui.ZIndexBehavior = Enum.ZIndexBehavior.Global ControllerGui.DisplayOrder = 2147483647 ControllerGui.Parent = PlayerGui --================================================== -- BUTTON 1 --================================================== DoorButton = Instance.new("TextButton") DoorButton.Name = "DoorCollisionToggle" DoorButton.AnchorPoint = Vector2.new(1, 0) DoorButton.Position = UDim2.new( 1, -8, 0, 8 ) DoorButton.Size = UDim2.new( 0, BUTTON_WIDTH, 0, BUTTON_HEIGHT ) DoorButton.BackgroundColor3 = Color3.fromRGB(45, 45, 45) DoorButton.BackgroundTransparency = 0.1 DoorButton.BorderSizePixel = 0 DoorButton.TextColor3 = Color3.fromRGB(255, 255, 255) DoorButton.TextSize = 14 DoorButton.Font = Enum.Font.GothamBold DoorButton.AutoButtonColor = true -- Highest ZIndex DoorButton.ZIndex = 2147483647 DoorButton.Parent = ControllerGui local DoorCorner = Instance.new("UICorner") DoorCorner.CornerRadius = UDim.new(0, 6) DoorCorner.Parent = DoorButton --================================================== -- BUTTON 2 --================================================== CollisionButton = Instance.new("TextButton") CollisionButton.Name = "CollisionToggle" CollisionButton.AnchorPoint = Vector2.new(1, 0) CollisionButton.Position = UDim2.new( 1, -8, 0, 46 ) CollisionButton.Size = UDim2.new( 0, BUTTON_WIDTH, 0, BUTTON_HEIGHT ) CollisionButton.BackgroundColor3 = Color3.fromRGB(45, 45, 45) CollisionButton.BackgroundTransparency = 0.1 CollisionButton.BorderSizePixel = 0 CollisionButton.TextColor3 = Color3.fromRGB(255, 255, 255) CollisionButton.TextSize = 14 CollisionButton.Font = Enum.Font.GothamBold CollisionButton.AutoButtonColor = true CollisionButton.ZIndex = 2147483647 CollisionButton.Parent = ControllerGui local CollisionCorner = Instance.new("UICorner") CollisionCorner.CornerRadius = UDim.new(0, 6) CollisionCorner.Parent = CollisionButton --================================================== -- RESTORE UI STATE --================================================== UpdateButtonText() --================================================== -- TOGGLE 1: DOORCOLLISION --================================================== DoorButton.Activated:Connect(function() DoorToggleState = not DoorToggleState -- Save UI state. SaveUIState() if DoorToggleState then --========================================== -- ON --========================================== -- Store the CURRENT DoorCollision state. StoreDoorCollisions() -- Then remove them. RemoveDoorCollisions() else --========================================== -- OFF --========================================== -- Restore exactly what was stored when -- this ON toggle happened. RestoreDoorCollisions() end UpdateButtonText() end) --================================================== -- TOGGLE 2: COLLISION --================================================== CollisionButton.Activated:Connect(function() CollisionToggleState = not CollisionToggleState -- Save UI state. SaveUIState() if CollisionToggleState then --========================================== -- ON --========================================== -- Freshly store current positions. StoreCollisionPositions() -- Move them away. MoveAllCollisions() else --========================================== -- OFF --========================================== -- Restore stored positions. RestoreCollisionPositions() end UpdateButtonText() end) RecreatingUI = false end --================================================== -- INITIAL UI --================================================== CreateControllerUI() --================================================== -- UI SELF-RECREATION --================================================== PlayerGui.ChildRemoved:Connect(function(Child) if Child ~= ControllerGui then return end task.defer(function() if ControllerGui and ControllerGui.Parent then return end -- Recreate ONLY the UI. -- The saved UI states remain outside it. CreateControllerUI() -- Reapply active effects. if DoorToggleState then RemoveDoorCollisions() end if CollisionToggleState then MoveAllCollisions() end end) end) --================================================== -- UI WATCHDOG --================================================== task.spawn(function() while true do task.wait(1) local ExistingGui = PlayerGui:FindFirstChild( "DoorCollisionController" ) if not ExistingGui then -- Recreate the UI from its saved state. CreateControllerUI() if DoorToggleState then RemoveDoorCollisions() end if CollisionToggleState then MoveAllCollisions() end end end end) --================================================== -- NEW OBJECT DETECTION --================================================== game.DescendantAdded:Connect(function(Object) task.defer(function() if not Object or not Object.Parent then return end --================================================== -- NEW DOORCOLLISION --================================================== if Object.Name == DOOR_NAME then if DoorToggleState and not RestoringDoors then -- While Door Toggle is ON, -- newly-created DoorCollision objects -- are also removed. pcall(function() Object:Destroy() end) end end --================================================== -- NEW COLLISION --================================================== if Object.Name == COLLISION_NAME then if CollisionToggleState and not RestoringCollisionPositions then -- While Collision Toggle is ON, -- newly-created Collision objects are -- moved away too. MoveCollisionObject(Object) end end end) end)