In only one of my places in a game, the contents of StarterGui are not being copied over to the PlayerGui folder when a player joins.
Link to place: Outlast: Adrenaline - Roblox (Note: This is not the start place. In order to reach this place, you will have to press ‘Play’ in the main start lobby)
It’s really frustrating, and I’ve already tried disabling all of my scripts, so it cannot be my own scripts causing it.
I personally cannot understand why does it work that way (I see one circumstance that justifies it, but a better solution can be implemented imo). There are games which do not require the character to play and therefore Players.CharacterAutoLoads is ticked off and Player:LocalCharacter() is never called - you don’t need them, so in the least they’re just wasting server & client resources.
This forces you to take one of the two hacky paths (there may be more) to work around the system:
Place the gui’s in ReplicatedStorage or ReplicatedFirst and use a script to clone them to Player.PlayerGui
Tick Players.CharacterAutoLoads on and make a script that ensures all the UI components have been sucessfully loaded before firing a RemoteEvent requesting the server to destroy the character.
Workarounds aren’t the ideal solution for most cases (if not all cases). I understand that less experienced programmers can benefit of this - when a LocalScript in StarterGui is deployed onto Player.PlayerGui, there is zero chance that indexing Player.Character gets you nil, unless he/she/it willingly destroys said character.
If this is the reason Roblox implemented this behaviour (because it might be not), then I’d suggest that when Players.CharacterAutoLoads is false, this behaviour should be overrided. When that happens, the developer knows that the result of Player.Character only depends on how he/she/it implements the character spawning.
If you add a Model called “StarterCharacter” to StarterPlayerScripts, which has an anchored part as PrimaryPart, then that model will be used for player characters. Probably less hacky than the two things you suggest since it’s a proper way to have more or less empty characters. #1 you suggest may not be future-proof in case they patch this behavior (you’d suddenly have 2 versions of each UI), and #2 still makes the server/clients load all the assets related to the character, which is a waste.
That’s not to say I don’t think there should be a better method. I think it would make sense for UI to load when CharacterAutoLoads is set to false.
Just clone your ScreenGui from game:GetService(“StarterGui”) and parent it to PlayerGui. There is no need to move it to ReplicatedStorage and then back when you need to edit it. A ScreenGui only needs to be in ReplicatedFirst if it’s your loading screen. I don’t think this option is especially hacky.
If you don’t use the player character, don’t spawn it, that’s actually more than just hacky, it has game performance implications and you’ll likely encounter bugs to work around. It’s a waste to let it be created even briefly like you describe because it starts replicating characters to everyone’s clients forcing them to at least get a StarterCharacter, or worst case their actual avatar (if you didn’t think to put a simple model as StarterCharacter), in which case you’re making everyone’s clients fetch everyone else’s packages, models, clothing textures, etc., just like a normal game, totally unnecessarily. If you’re using any Roblox localscripts that get a reference to the character on CharacterAdded, you’d need to make sure they all get cleaned up gracefully to, and you’ll need to edit any camera scripts that reference character Head, Torso, etc. if your basic StarterCharacter doesn’t have these parts. The property CharacterAutoLoads also means auto respawning too. The short of it is: if you’re not going to use the character, you save yourself a pile of headaches by never spawning it.
Does it first check for existence of the guis inside PlayerGui, and if a gui wasn’t copied over from StarterGui, it just copies it?
Seems like it’s kinda annoying to make UI that is independent of a character altogether?
Why are there even inconsistencies between the way guis and scripts are handled? (eg: We have StarterCharacterScripts, and StarterPlayerScripts; Why is this not designed the same way with StarterPlayerGui and StarterCharacterGui, completely removing the weird “ResetOnSpawn” option from properties?)
Also, by the time a script in StarterPlayerScripts is ran, are we guaranteed that all the guis in StarterGui are loaded, so that we can copy them over to PlayerGui? (eg: if I wanted to make a script that simply did that copy operation you stated)
Lots of things on Roblox are simplest when you use the autoloading player character, because historically that’s just how Roblox has always worked. Even now, games that don’t spawn the player character are a small minority. Manually cloning and parenting a ScreenGui can be 1 or 2 lines of code, so as far as things you need to work around to make a game without a character, this one is pretty minor and straightforward.
Backwards compatibility. When you have a platform that has grown steadily to meet the needs of developers and players over a decade, and on which there are literally tens of thousands of active games using every single feature of the API–including all deprecated functions and instance types–these inconsistencies arise naturally. When we add a new feature, it’s simply not possible to continuously refactor the platform to keep everything consistent while also maintaining backwards compatibility for all live games.
I don’t actually know if this is guaranteed, I will look at the server replication stages tomorrow to see if I can answer this conclusively. I usually code everything to be tolerant of not having been replicated yet, and I haven’t noticed. Everything in ReplicatedFirst is certainly available, and ReplicatedStorage definitely not.
Ugh I came across this issue again after nearly two years, only to realize that I had previously posted it as a bug.
This behavior is really counterintuitive, and should really be clarified somewhere or fixed. I still don’t fully understand the ordering of events going on here, and any solution I’ve managed to come up for this problem is in the end a hacky workaround that has weird consequences (e.g. two copies of the same gui in PlayerGui).