Cmdr
Cmdr copied to clipboard
Cmdr ScreenGui is added twice to PlayerGUI
This is probably a timing issue, so it might be hard to reproduce. But in our game the Cmdr ScreenGui is consistently added twice to the PlayerGUI in Studio (has not validated this in production).
I assume that it this is caused by the following flow:
- Cmdr ScreenGui is added to StarterGui by the server
- The client bootstrap script runs and require CmdrClient that causes the Cmdr ScreenGui to be copied to the PlayerGui
- The Roblox default behaviour copies the CmdrClient from StarterGui to PlayerGui
Affected versions: 1.4.0, 1.5.0
Screenshot of the issue:
The LocalScript we use to start Cmdr on the client (located in StarterPlayerScripts):
local Players = game:GetService("Players")
local TGSMisc = require(workspace.Lib.TGSMisc)
if not TGSMisc.IsDeveloper(Players.LocalPlayer) then
return
end
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Cmdr = require(ReplicatedStorage:WaitForChild("CmdrClient"))
Cmdr:SetActivationKeys({ Enum.KeyCode.BackSlash })
Script used on the server:
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Cmdr = require(workspace.Lib.External.Cmdr)
local TGSMisc = require(workspace.Lib.TGSMisc)
Cmdr.Registry:RegisterHook("BeforeRun", function(context)
if not TGSMisc.IsDeveloper(context.Executor.UserId) then
return "You don't have permission to run this command"
end
end)
Cmdr:RegisterDefaultCommands()
Cmdr.Registry:RegisterCommandsIn(workspace.Lib.Commands)
A simple modification of the client bootstrap script to wait for Roblox default behaviour to copy StarterGui to PlayerGui before initializing Cmdr solves the issue.
This is a work around and a proper fix would probably be in the library itself.
local Players = game:GetService("Players")
local TGSMisc = require(workspace.Lib.TGSMisc)
if not TGSMisc.IsDeveloper(Players.LocalPlayer) then
return
end
while Players.LocalPlayer:WaitForChild("PlayerGui"):FindFirstChild("Cmdr") == nil do
wait(1)
end
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Cmdr = require(ReplicatedStorage:WaitForChild("CmdrClient"))
Cmdr:SetActivationKeys({ Enum.KeyCode.BackSlash })
Is CharacterAutoLoads = false in your game?
We have the same issue in Adopt Me, and this is what I said about that:
I think it's because GUIs gets cloned into playergui on character spawn, but because CharacterAutoLoads = false, Cmdr gets initialized before the player spawns, which clones the gui into the player thinking that the gui didn't get copied because of it being inserted into startergui too late, but then the player really spawns and roblox copies the gui from starter gui, so there's 2
@evaera CharacterAutoLoads is true in our game.
Seems like we came to the same conclusion :). These kind of issues can be kind of tough to crack without breaking things for other developers.
We (Wil and I) have been discussing this for the better part of 90 minutes and decided that this issue won't be fixed.
To solve this issue without breaking some expected behaviour is impossible. We ran through a bunch of different possible solutions, including looking at the two previous PRs that have attempted this, and found it super difficult to get an ideal solution.
The impact of the issue is - to our perspectives - very minor. It's not something that has a noticeable user impact unless you're looking through the explorer (like in the original issue ticket), but this only happens if you're a developer or exploiter, and even still the impact is almost nil.
However, there is one very specific scenario in which this issue causes a noticeable developer issue:
- You have CharacterAutoLoads false
- You load CmdrClient before the starter gui loads, creating the duplicate
Cmdr
screenguis - While there are two duplicate screenguis, you attempt to modify the Cmdr interface by hooking into
PlayerGui.Cmdr
Although the bug here is minor, the developer code may not apply its modifications to the 'real' Cmdr window, having very little user impact. This is all very specific and while the solutions are simple, which one is best for your game depends on how you're planning to use Cmdr and how your game is architected.
Balancing the impact of fixing vs not fixing, we don't think it's currently worthwhile for this to be solved.
If a - breaking - 2.0.0 update is ever on the table (which there's no current plans or foreseeability for) then a discussion about behaviours we can change, like this, will almost certainly take place.