Globally disabling interactivity with click detectors when in "spectator mode"

It should work that way but it seems like with CharacterAutoLoads disabled and the player not having received the instruction to spawn yet, the player would be able to trigger click detectors at any range.

Here’s an example project:
Spectator Click Detectors.rbxl (15.3 KB)

Like everyone else mentioned - the easiest way may be to set MaxActivationDistance = 0 on the client
Since you can’t do that, as you say - would an option be to simply limit the interaction with the ClickDetector?

For example: A simple check like this. (base on your sample code)

local function PlayerSpectating(player)
	--check tag set in replicated storage or server data value here
	-- return true if the player is in spectate mode
	return true
end

script.Parent.MouseClick:Connect(function(player)
	if PlayerSpectating(player) then 
		return
	end
	script.Parent.Parent.BrickColor = BrickColor.Random()
end)

I don’t understand how that answers OP’s question though? You stated

which is anti-solution to the problem. They aren’t trying to make it work. Your second response contradicts your first response.

I suggested creating custom ClickDetector interactions to void what goes on internally with ClickDetectors and to have a further degree of control over click interaction.

Let me restate my predicament because I wasn’t really well rested yesterday so I think I might have said things that were unclear.

I have a game where players without a character are able to use free cam. However, in free cam mode, their client is able to trigger click detectors. I could, of course, iterate through each of these and set their MaxActivationDistance to 0 but, in cases where another script changes the MaxActivationDistance value, the value could get overridden.

I guess my real question was if there was a way to just disable all click detectors with the ContextActionService because of this quote on the developer wiki:

If an action bound with /ContextActionService uses the same input as a ClickDetector, the bound action will take priority and the ClickDetector events will not fire.

However, if this isn’t possible, I guess I’ll create a system where properties can be updated with a priority value. Something like:

Spectator script:

-- Upon entering spectator mode...
for _, click_detector in pairs(workspace:GetDescendants()) do
     if click_detector:IsA("ClickDetector") then
        InstancePropertyPriorityAPI:set_property_with_priority(
              InstancePropertyPriorityAPI.Priority.HIGH,
              click_detector, "MaxActivationDistance", 0)
     end
end

Some other script:

-- When a click detector needs to be disabled for some in-game thingy...

InstancePropertyPriorityAPI:set_property_with_priority(
         InstancePropertyPriorityAPI.Priority.LOW,
         click_detector, "MaxActivationDistance", 0)

The reason I didn’t really want to do this is that my project for school is nearing due date and I wasn’t too keen on the idea of changing all of the instances of click detector usage (of which there are a lot) but I guess I could “bite the bullet” as a last case scenario. But again, in development, sometimes the best solution is to change everything.

Sorry for the troubles,
Rad

Oh, that makes things significantly more easier to understand. In terms of “disabling” ClickDetectors without changing MaxActivationDistance, you can sink the input of MouseButton1. Do keep in mind the following though:

  • Regardless of what you do, an exploiter can modify the MaxActivationDistance or unbind the action and be able to click. If you don’t mind, this solution is completely effective.
  • This solution will not change the cursor icon, exploiter or not. You’ll still be able to hover over ClickDetectors and get the icon. This just prevents them from being clicked. Modifying MaxActivationDistance may still be necessary, or force-overriding the cursor to something else.
  • It’d be good to keep a check on the server that prevents ClickDetectors from being used by players that shouldn’t be using them, however you choose to go about this.

Rough script I used:

local A = game:GetService("ContextActionService")

A:BindActionAtPriority("B",
	function ()
		return Enum.ContextActionResult.Sink
	end,
	false,
	Enum.ContextActionPriority.High.Value,
	Enum.UserInputType.MouseButton1
)

Guis can still be interacted with.

Repro containing my rough implementation: ContextActionSink Repro.rbxl (17.4 KB)

1 Like

If the click detectors are connected directly to the server with a server script, you can check which player clicked it and filter out players that are spectating.

PlayersSpectating = {}

ClickDetector.MouseClick:connect(function(player)
    if PlayersSpectating[player] then
        return
    end
    -- if they are not spectating, actuate the function
end)

If the click detectors are detected on the client then connected to the server using a remote event, you can do the exact same thing:

PlayersSpectating = {}

RemoteEvent.OnServerEvent:connect(function(player)
    if PlayersSpectating[player] then
        return
    end
    -- if they are not spectating, actuate the function
end)

If for some reason the click detector has an effect on the client that is clicking, and there is no server-side check to determine if the player is allowed to click the button, you can add a check using a remote function:

PlayersSpectating = {}

function RemoteFunction.OnServerInvoke(player)
    if PlayersSpectating[player] then
        return false
    else
        return true
    end
end

Clients will be able to do whatever they like on their client, including removing the limitations on their mouse and clicking the button anyway. The only way to protect your game against hackers like that is not to remove the ability to click, but to remove the ability for the click to perform any action. For a game developer to expect the client to obey the limitations set by local code is like asking the scorpion not to sting the frog.