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

That would be an off-topic question but if you want, when we’re done, I could send you a link through a private chat or whatever the equivalent would be on the DevForums. It’s basically a game where two teams fight to destroy their user created space crafts.

Try putting your code in Lua blocks. Here’s what a code block looks like in a post:

local foo = 2
local bar = "cool"
local function getSomething()
    return foo .. bar
end

print(getSomething()) --> 2cool

To use them, enter this into the editor to use a code block:

``‌`Lua
your code here
``‌`

On UK keyboard layouts, that little symbol is directly above the Tab key. I’m not sure about other keyboards from other regions tho.

2 Likes

Yeah, we need to see the stuff. I can see the circles people have walked in.

The only real options you have to “disable” a ClickDetector is either to destroy it or make it inaccessible to the client, which in itself is not entirely possible since a client can restore controls. I would’ve also suggested throwing a Frame with its Active property set to true, but seeing as you’re making a freecam spectator system, probably not the best idea - it’ll catch right mouse as well. Such is the shortcoming of using objects interfaced on the backend.

Perhaps you may want to think about handling click detection through a custom implementation? It’s not too complicated - just have the mouse click, fire a RemoteEvent and the server receives that event. It voids the usage of ClickDetectors and gives you explicit control over the mouse behaviour.

The above is not a proper solution, but it’s an alternative. I know of no other way to disable ClickDetectors since you don’t have explicit control over its internal behaviour.

1 Like

After reading through your post and the solutions that others have tried to come up with for you. It seems that your implementation of “Spectator Mode” is simply bad by design. Or in this case the way that you designed it causes collisions. This functionality that you want to disable click detectors would be better handled by default if you just redesigned your “Spectator Mode” just a tiny bit differently to accommodate it from the start.

Cheers.

2 Likes

@radbuglet If it makes you feel any better, I created this place with some scripts to help you with your game.
Button Activation.rbxl (19.9 KB)
I hope this helps :slight_smile:

There is a gui to change teams to see the results faster. Players on the “Playing” team are allowed to click the bricks on the baseplate. Players on the “Lobby” or “Spectating” team are not allowed to click the bricks. I also added minimal server security to prevent some exploits from occuring.

Apparently ClickDetectors already have a property to handle this for you: ClickDetector | Documentation - Roblox Creator Hub
Edit:
When in spectator mode set the property to 0 to disable the detector. On the server you’ll need to also check the distance since you’re only setting it on the client.

I don’t see how it is bad by design. I created a system to handle different camera states and have two methods to engage and disengage the system. Free cam locks the cursor in the middle of the screen and modifies pitch and yaw through the deltas of the mouse movement. All of this works fine except that cameras without an attached player can trigger click detectors at any distance. I was asking if there was a way to override the behavior of click detectors globally but it seems to me like I would have to modify each one manually so I’m probably going to use a react style listen and update workflow where the update logic can inherit the functionality of click detector disabling in spectate mode.

My issue isn’t that I can’t disable click detectors, it that multiple mechanics would have to share this one property. I didn’t want to code a system to allow for state based updating of an instance but I guess that would be the best way. I’m going to release the code I wrote soon after a bit of framework redesigning.

How have you implemented spectating? If you change the camera’s subject to a part the player can control without a Humanoid, or simply manipulate the camera’s position in the world, you shouldn’t be able to activate ClickDetectors.

Spectating is only possible when the player doesn’t have a character. When the player enters spectating mode, I bind Stepped and Input events to be able to look around and move the camera. To move the camera, I simply change the workspace.CurrentCamera.CFrame.

Hope this helps!

i found out that you have to have a character at the click detector for it to work so you wont have any issues

OP is trying to disable ClickDetectors, not make them work.

yes i know but the click detectors only work with a character next to them so in a way its disabled

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.