No way to give player persistent script

As far as I can tell there has been a change to the way scripts are handled in PlayerGui, and it has made certain things impossible to do in Roblox, namely perpetual local scripts distributed during the game.

Some context:

I have an animation script that runs some train wheels. When the train loads, it gives players a LocalScript that is custom for the set of train wheels. This script is for use in free models and is designed in such a way to require as little infrastructure as possible. To that end, it uses a server script to manage players receiving the LocalScript: any time a player joins, it gives them the LocalScript by placing it in their PlayerGui. The LocalScript initializes by wait()ing and then parenting itself to PlayerScripts, with the intention of preventing it from being deleted when the player resets. This is a change from several months ago where I had to change the server script from placing the LocalScript in the Backpack because a change to how Roblox works made it unusable.

Now, recently, I have discovered that placing it in PlayerGui is not viable either. At some point recently, these scripts started getting deleted when the player resets. I’m not sure of the exact time. I’ve asked the train community that uses the scripts the most and they told me they do recall the LocalScript persisting – even on games with

Since this change it’s now impossible for a server script to give a player a LocalScript for an arbitrarily long time period because PlayerScripts is not replicated. There’s simply no way for a server script to tell a client, “see this LocalScript? I want you to run it until the game closes or the train is deleted. Don’t stop running even when the character resets.”

There’s the possibility of making a bootstrapper LocalScript, which acts similarly (is copied into PlayerGui) but the LocalScript copies the LocalScript into PlayerScripts instead of the ServerScript, but this is extremely hacky and I don’t like it one bit. There’s got to be a better way.

Hundreds of users have used the script in hundreds more locomotives, and whatever the solution ends up being, I will have to inform them of the update and get them to update each script individually.

Here is an example of a model that uses this process. The relevant scritps are Advanced Loco Animation and its child.

Expected behavior: local scripts placed in PlayerGui are not destroyed when character reloads
Observed behavior: local scripts placed in PlayerGui are destroyed when character reloads

1 Like

ScreenGui has a ResetOnSpawn check box, if you place the local script in there it should work just fine in PlayerGui

Try using a ScreenGUI in starterGUI then set reset on spawn to false then parent the script to that GUI.

Edit: wravager posted above.

This seems almost as hacky as what I proposed.

1 Like

This is typically why I design my code to be placed in PlayerScripts implicitly and function lazily rather than eagerly (borrowing these words from loading styles). That way, I don’t have to go through this nonsense of parenting scripts through other scripts. I feel that parenting things this way is hacky in itself and “persistent scripts” should be available immediately.

You could try dropping the LocalScript into each player’s character, and then either have the client reparent the LocalScript if it doesn’t have that LocalScript in the PlayerScripts folder, or delete itself if it already exists.

Alternatively you can tell the developer to parent a specific LocalScript into their StarterPlayerScripts. Instead of using individual LocalScripts for each train, you can use CollectionService tags to mount animation logic when trains are added or removed. To make it generic you could even have some ModuleScript that the client mounts onto when it detects a train is added/removed with the CollectionService.

1 Like

What if you parent the LocalScript to a dummy LocalScript and then parent the dummy to the player’s GUI, then the dummy parents the main LocalScript to PlayerScripts and enables it?

I ended up going the ScreenGui method since it seems to be the least hacky. It still bugs me there’s no ‘proper’ ‘pythonic’ way of doing this. The hard part is now to get everyone to convert to the new system.


I don’t know if it was made clear, so I’d just like to point out that these problems are
caused by ResetOnSpawn = false NOT being honored anymore when changed in code
on the client side, but the flag IS honored on the server side–So just rework anything that relies
on clearing ResetOnSpawn in a LocalScript / on the client, to relying on the In-Studio checkmark
(that will replicate from the server StarterGui with the correct setting.) This will prevent the stompage.