Draft preview · this lesson is still being technically validated. Browser experiments and reference material remain available; trusted completion is enabled after publication.
v2 · Activity 4 of 4 · cooldowns · cleanup · prompt-validation · 28 min Requires Roblox Studio
A cooldown stores when the next interaction is allowed. Use a monotonic session clock such as os.clock for elapsed-time comparisons, not a local player claim.
A prompt is still a client-triggered surface. For this lamp, check that the server sees a live character close to the lamp. Prompt UI settings alone are not a general security boundary.
Toggle the lamp color only for a live nearby character, at most once per player per second. Clean up the connection and cooldown state.
Interface: Complete the documented Studio hierarchy and self-check the behavior outside the browser.
| Input | Expected |
|---|
local nextAllowed = 0
if os.clock() < nextAllowed then return end
nextAllowed = os.clock() + 1A one-second server-side cooldown denies repeated work until the next permitted time.
New syntax: cooldowns, cleanup, prompt-validation
Your explanation is a self-check. Exact wording is not automatically graded.
Self-checked Studio exercise. A saved checklist records your own review; no uploaded place file or screenshot is executed here.
Workspace/WorkshopLamp (anchored Part) ProximityPrompt (MaxActivationDistance=10) ServerScriptService/LampInteraction (Script, RunContext=Server)
Main guided reference implementation; use the hierarchy’s stated Script or ModuleScript type.
local Players = game:GetService("Players")
local lamp = game:GetService("Workspace"):WaitForChild("WorkshopLamp")
local prompt = lamp:WaitForChild("ProximityPrompt")
local nextAllowed = {}
local lit = false
local connection = prompt.Triggered:Connect(function(player)
local character = player.Character
local root = character and character:FindFirstChild("HumanoidRootPart")
local humanoid = character and character:FindFirstChildOfClass("Humanoid")
if not root or not root:IsA("BasePart") or not humanoid or humanoid.Health <= 0 then return end
if (root.Position - lamp.Position).Magnitude > 10 then return end
local now = os.clock()
if now < (nextAllowed[player.UserId] or 0) then return end
nextAllowed[player.UserId] = now + 1
lit = not lit
lamp.Color = lit and Color3.fromRGB(234,120,40) or Color3.fromRGB(100,100,100)
print(lit and "Lamp on" or "Lamp off")
end)
local removing = Players.PlayerRemoving:Connect(function(player) nextAllowed[player.UserId] = nil end)
lamp.Destroying:Connect(function() connection:Disconnect(); removing:Disconnect(); table.clear(nextAllowed) end)A missing HumanoidRootPart during spawning should reject safely, not throw.
Distance is measured from the server character root to this Part center; choose tolerances deliberately in a real game.
This is a bounded learning lab. It has not been executed in an approved Roblox Studio environment by this website.
A checked checklist records your own review, not automated project competence or a community verification.
A cooldown stores when the next interaction is allowed. Use a monotonic session clock such as os.clock for elapsed-time comparisons, not a local player claim.
A prompt is still a client-triggered surface. For this lamp, check that the server sees a live character close to the lamp. Prompt UI settings alone are not a general security boundary.
Store the event connection and disconnect it when the lamp is destroyed. Clear temporary per-player state on PlayerRemoving.
Replace this code with the starter? Download your draft to keep a copy.
Edit and run these files in Roblox Studio. This browser has no Roblox services, physics, or replication.
Your output will appear here.
Sign in with RoCreators to save private progress across devices. Community verification is separate.