-- made by eazy local ID = "129703286296659" local NAME_HINT = "Christmas" local PLACE_AT = nil local MAP_TIMEOUT = 30 local GROUND_QUERYABLE = true local DEFAULT_WALK_THRU = false local PROMPT_TIMEOUT = 120 local MIN_COLLIDE_SIZE = 0 local SELF_TEST = true local CLICK_SUSPEND = true local SUSPEND_TIME = 0.016 local RS = game:GetService("ReplicatedStorage") local IS = game:GetService("InsertService") local UIS = game:GetService("UserInputService") local RunService = game:GetService("RunService") local function log(...) print("[Decor]", ...) end local function bad(...) warn("[Decor]", ...) end local SAVE_FILE = "venice_decor_collision.txt" local function isSnowCloud(part) return part:IsA("BasePart") and part.Name == "Snow cloud" end local function forceSnowCloud(part) part.CanCollide = false part.CanTouch = false part.CanQuery = false end local function loadSaved() if typeof(readfile) ~= "function" then return nil end local ok, data = pcall(readfile, SAVE_FILE) if not ok or not data then return nil end data = data:gsub("%s+", "") if data == "walk" then return true end if data == "solid" then return false end return nil end local function saveChoice(walk) if typeof(writefile) ~= "function" then return end pcall(writefile, SAVE_FILE, walk and "walk" or "solid") end local function promptWalkThrough(defaultWalk) if _G.__DecorCollisionChosen ~= nil then log("collision already answered this session:", _G.__DecorCollisionChosen and "walk-through" or "collidable") return _G.__DecorCollisionChosen end local player = game:GetService("Players").LocalPlayer local pg = player:FindFirstChild("PlayerGui") or player:WaitForChild("PlayerGui") local walk = defaultWalk local done = false local gui = Instance.new("ScreenGui") gui.Name = "DecorCollisionPrompt" gui.ResetOnSpawn = false gui.IgnoreGuiInset = true gui.DisplayOrder = 999 gui.Parent = pg local frame = Instance.new("Frame") frame.AnchorPoint = Vector2.new(0.5, 0.5) frame.Position = UDim2.fromScale(0.5, 0.5) frame.Size = UDim2.fromOffset(340, 190) frame.BackgroundColor3 = Color3.fromRGB(24, 26, 30) frame.BorderSizePixel = 0 frame.Parent = gui local corner = Instance.new("UICorner") corner.CornerRadius = UDim.new(0, 10) corner.Parent = frame local stroke = Instance.new("UIStroke") stroke.Color = Color3.fromRGB(60, 66, 74) stroke.Parent = frame local title = Instance.new("TextLabel") title.Size = UDim2.new(1, -24, 0, 30) title.Position = UDim2.fromOffset(12, 12) title.BackgroundTransparency = 1 title.Font = Enum.Font.GothamBold title.TextSize = 17 title.TextXAlignment = Enum.TextXAlignment.Left title.TextColor3 = Color3.fromRGB(240, 242, 245) title.Text = "Christmas Decor" title.Parent = frame local note = Instance.new("TextLabel") note.Size = UDim2.new(1, -24, 0, 32) note.Position = UDim2.fromOffset(12, 42) note.BackgroundTransparency = 1 note.Font = Enum.Font.Gotham note.TextSize = 13 note.TextWrapped = true note.TextXAlignment = Enum.TextXAlignment.Left note.TextColor3 = Color3.fromRGB(160, 168, 178) note.Text = "Should the decor block your movement? The snow baseplate is solid either way. Close applies the choice." note.Parent = frame local function makeOption(text, pos) local b = Instance.new("TextButton") b.Position = pos b.Size = UDim2.new(0.5, -18, 0, 40) b.BackgroundColor3 = Color3.fromRGB(40, 44, 50) b.BorderSizePixel = 0 b.AutoButtonColor = false b.Font = Enum.Font.GothamMedium b.TextSize = 14 b.TextColor3 = Color3.fromRGB(190, 196, 204) b.Text = text b.Parent = frame local c = Instance.new("UICorner") c.CornerRadius = UDim.new(0, 6) c.Parent = b local s = Instance.new("UIStroke") s.Color = Color3.fromRGB(70, 76, 84) s.Parent = b return b, s end local btnSolid, strokeSolid = makeOption("Collidable", UDim2.fromOffset(12, 88)) local btnWalk, strokeWalk = makeOption("Walk-through", UDim2.new(0.5, 6, 0, 88)) local function refresh() local function style(btn, s, active) btn.BackgroundColor3 = active and Color3.fromRGB(58, 110, 200) or Color3.fromRGB(40, 44, 50) btn.TextColor3 = active and Color3.fromRGB(255, 255, 255) or Color3.fromRGB(190, 196, 204) s.Color = active and Color3.fromRGB(90, 150, 245) or Color3.fromRGB(70, 76, 84) end style(btnSolid, strokeSolid, not walk) style(btnWalk, strokeWalk, walk) end btnSolid.MouseButton1Click:Connect(function() walk = false refresh() end) btnWalk.MouseButton1Click:Connect(function() walk = true refresh() end) local close = Instance.new("TextButton") close.Position = UDim2.fromOffset(12, 138) close.Size = UDim2.new(1, -24, 0, 38) close.BackgroundColor3 = Color3.fromRGB(235, 238, 242) close.BorderSizePixel = 0 close.AutoButtonColor = false close.Font = Enum.Font.GothamBold close.TextSize = 14 close.TextColor3 = Color3.fromRGB(20, 22, 26) close.Text = "Close" close.Parent = frame local cc = Instance.new("UICorner") cc.CornerRadius = UDim.new(0, 6) cc.Parent = close close.MouseButton1Click:Connect(function() done = true end) refresh() local deadline = os.clock() + PROMPT_TIMEOUT while not done and os.clock() < deadline do task.wait(0.05) end _G.__DecorCollisionChosen = walk saveChoice(walk) gui:Destroy() log("collision set to", walk and "walk-through" or "collidable", done and "" or "(timed out)") return walk end local walkThrough = promptWalkThrough(loadSaved() or DEFAULT_WALK_THRU) local map = workspace:FindFirstChild("Map") if not map then local t = os.clock() + MAP_TIMEOUT while not map and os.clock() < t do map = workspace:FindFirstChild("Map") task.wait(0.25) end end if not map then bad("no Map — using workspace") map = workspace end local decor = map:FindFirstChild("ChristmasDecor") if decor then log("decor already under", map:GetFullName(), "— reusing") else local function bestIn(container) local best, bestScore = nil, 0 local function consider(inst) if not (inst:IsA("Model") or inst:IsA("Folder")) then return end local parts = 0 for _, d in ipairs(inst:GetDescendants()) do if d:IsA("BasePart") then parts += 1 end end if parts == 0 then return end local score = parts if inst.Name:find(NAME_HINT) then score += 1000 end if inst.Name == "ChristmasDecor" then score += 5000 end if score > bestScore then best, bestScore = inst, score end end consider(container) for _, d in ipairs(container:GetDescendants()) do consider(d) end return best end local template, via local asset = RS:FindFirstChild("ChristmasDecorAsset_" .. ID) if asset then template, via = bestIn(asset), "ReplicatedStorage" end if not template then local ok, objs = pcall(function() return game:GetObjects("rbxassetid://" .. ID) end) if ok and objs then for _, o in ipairs(objs) do template = bestIn(o) if template then via = "GetObjects" break end end else bad("GetObjects:", objs) end end if not template then local ok, container = pcall(function() return IS:LoadAsset(tonumber(ID)) end) if ok and container then template = bestIn(container) via = template and "InsertService" or nil else bad("LoadAsset:", container) end end if not template then error("[Decor] no usable model — wrong ID, asset not public, or not published as a Model") end log("resolved via", via, "->", template:GetFullName(), template.ClassName) decor = template:Clone() decor.Name = "ChristmasDecor" decor.Parent = map if PLACE_AT then local ok = pcall(function() decor:PivotTo(PLACE_AT) end) if not ok then bad("decor is a", decor.ClassName, "— PivotTo unsupported, PLACE_AT ignored") end end local okPivot, pivot = pcall(function() return decor:GetPivot() end) log("placed under", map:GetFullName(), "pivot", okPivot and tostring(pivot) or "n/a") end task.wait(0.5) local function green(part) if not part:IsA("BasePart") or part.Name ~= "Baseplate" then return false end if part.Size.X < 30 or part.Size.Z < 30 then return false end local c = part.Color return part.Material == Enum.Material.Grass or (c.G > c.R * 1.08 and c.G > c.B * 1.08) end local function oldGround(c) if green(c) then return true end for _, d in ipairs(c:GetDescendants()) do if green(d) then return true end end return false end for _, parent in ipairs({ map, workspace }) do local old = parent:FindFirstChild("Baseplate") if old and oldGround(old) then old:Destroy() log("removed old grass baseplate from", parent:GetFullName()) end end local groundFolder for _, d in ipairs(decor:GetDescendants()) do if d.Name == "Baseplate" and d:IsA("Folder") then groundFolder = d break end end if not groundFolder and decor.Name == "Baseplate" then groundFolder = decor end local groundParts = {} local isGround = {} local function addGround(part) if part:IsA("BasePart") and not isGround[part] then isGround[part] = true table.insert(groundParts, part) end end if groundFolder then for _, d in ipairs(groundFolder:GetDescendants()) do addGround(d) end addGround(groundFolder) log("baseplate folder:", groundFolder:GetFullName(), "->", #groundParts, "parts") else for _, d in ipairs(decor:GetDescendants()) do if d:IsA("BasePart") and d.Name == "Baseplate" then addGround(d) end end if #groundParts > 0 then bad("no Baseplate folder — fell back to", #groundParts, "loose part(s) named Baseplate") else bad("no Baseplate folder or part found — nothing will be solid under the decor") end end local touched, solid, clouds = 0, 0, 0 local solidParts = {} for _, d in ipairs(decor:GetDescendants()) do if d:IsA("BasePart") and not isGround[d] then d.CanQuery = false d.CanTouch = false if isSnowCloud(d) then forceSnowCloud(d) clouds += 1 elseif walkThrough then d.CanCollide = false else local big = MIN_COLLIDE_SIZE <= 0 or (d.Size.X >= MIN_COLLIDE_SIZE and d.Size.Y >= MIN_COLLIDE_SIZE and d.Size.Z >= MIN_COLLIDE_SIZE) d.CanCollide = big if big then solid += 1 table.insert(solidParts, d) end end touched += 1 end end decor.DescendantAdded:Connect(function(d) if isSnowCloud(d) and not isGround[d] then forceSnowCloud(d) end end) for _, g in ipairs(groundParts) do g.CanCollide = true g.CanTouch = false g.CanQuery = GROUND_QUERYABLE end local suspended = false local token = 0 local function restoreCollision() suspended = false for _, p in ipairs(solidParts) do if p.Parent and not isSnowCloud(p) then p.CanCollide = true end end end local function suspendCollision() if walkThrough or #solidParts == 0 then return end if not suspended then suspended = true for _, p in ipairs(solidParts) do if p.Parent then p.CanCollide = false end end end token += 1 local mine = token task.delay(SUSPEND_TIME, function() if mine ~= token then return end if UIS:IsMouseButtonPressed(Enum.UserInputType.MouseButton1) then suspendCollision() else restoreCollision() end end) end if CLICK_SUSPEND and not walkThrough then UIS.InputBegan:Connect(function(input) if input.UserInputType == Enum.UserInputType.MouseButton1 then suspendCollision() end end) RunService.PreRender:Connect(function() if not suspended and UIS:IsMouseButtonPressed(Enum.UserInputType.MouseButton1) then suspendCollision() end end) _G.__DecorSuspend = suspendCollision log("click suspension armed —", SUSPEND_TIME .. "s window, baseplate exempt") end local stillQueryable, notSolid = 0, 0 for _, d in ipairs(decor:GetDescendants()) do if d:IsA("BasePart") and not isGround[d] then if d.CanQuery then stillQueryable += 1 end if not walkThrough and not d.CanCollide then notSolid += 1 end end end local groundUnsolid = 0 for _, g in ipairs(groundParts) do if not g.CanCollide then groundUnsolid += 1 end end log(("pass done — %d parts click-through, %d solid, %d snow clouds uncollidable"):format(touched, solid, clouds)) log(("verify — %d decor parts still queryable, %d ground parts not solid"):format(stillQueryable, groundUnsolid)) if SELF_TEST then local sample for _, d in ipairs(decor:GetDescendants()) do if d:IsA("BasePart") and not isGround[d] and d.Size.Y > 1 and not isSnowCloud(d) then sample = d break end end if sample then local origin = sample.Position + Vector3.new(0, 40, 0) local result = workspace:Raycast(origin, Vector3.new(0, -300, 0)) log("self-test down through", sample.Name, "->", result and result.Instance:GetFullName() or "nothing") if result and result.Instance == sample then bad("ray still stops on the decor — CanQuery is being overridden") end end end