Player instance now created on server instead of client

If my assumption about the implications are wrong, the opposite means the client can never know if the game is completely loaded – there is always uncertainty about a part being replicated during the entire play session.

I’m more-or-less asking, in a kind of roundabout way, if there is any point at which we can be certain that parts are replicated.

If I read your question right: if you should use WaitForChild() for that list of objects,

StarterPlayerScripts is a service, and is initialized before any LocalScripts run. It can be indexed with game:GetService("StarterPlayerScripts").

Same with StarterCharacterScripts, and ReplicatedFirst, and StarterGui.

However, children inside of those services aren’t guaranteed to be replicated before any LocalScripts initialize, so it is best to use game.StarterPlayerScripts:WaitForChild("NicePart")

LocalScript delivered to client when ServerScript detects player join: The LocalScript will run as soon as it’s sent to the client (maybe it is inside of PlayerGui, etc). In theory, it should be sent only after everything else has replicated (because objects/property changes are replicated in the order they were made, however the initial join can be necessarily random), but I would not rely on this because this behavior can change. Use :WaitForChild() for anything replicated from the server.

Same with Character created, and when character touches a part.

Does that answer your question? Sorry if I misunderstood.

A test done with a LocalScript in ReplicatedFirst, StarterGui, StarterPlayerScripts, and one in a server script that is cloned into the player as soon as they join with no delay, done in a place with 67k+ parts: image

print("ReplicatedFirst Loaded", game:IsLoaded())
print("ReplicatedFirst Map", workspace.Map)

image

All scripts other than the one in ReplicatedFirst can access the Map (a model with the parts in it) with the dot accessor syntax and report the game as being loaded.

These LocalScripts don’t start running until the game is loaded. If I’m making some invalid assumption here then I’d love to learn where I went wrong, but from what I can tell, they just don’t run until the game is ready (they may be replicated, but they don’t get cloned into the Player object until the client is ready)

1 Like

The OP @KnightTakami liked my post

So I assume it is correct.

But like I said, it is not guarteed that LocalScripts will run before everything else is replicated, but it is certainly still possible. Your test needs more stress, like 12+ players in the game moving around, etc.

2 Likes

I’m sorry that I wasn’t very clear. I was asking if Local Scripts that began life in those ways had any benefit of using :WaitForChild() versus :FindFirstChild().

For example, the following script

local a = workspace:FindFirstChild("NicePart")

is placed in various locations or delivered in various ways to the client:
image

My hypotheses are the following:

  • The script will not find NicePart if it starts in ReplicatedStorage
  • The script may not find NicePart if it starts in StarterPlayerScripts
  • The script will find NicePart if it starts in StarterCharacterScripts
  • The script may not find NicePart if it starts in StarterGui
  • The script will find NicePart if it is delivered to the client when the server detects the player object was added to Players
  • The script will find NicePart if it is delivered to the client when the server detects the player’s character is added
  • The script will find NicePart if it is delivered to the client when the server detects a player has touched a specific part.

Or, in other words, is there ever a point at which the client has fully loaded the game, and is there a distribution method that distributes local scripts after this point?

Out of interest, does this have anything to do with any planned performance upgrades for the :LoadCharacter() method?

1 Like

That would be cool. But my first assumption is that it’s for the updating the way players’ join data works, so that we don’t need to rely on trusting the client.

1 Like

This thread is public and the old behavior is still enabled, so engineers can’t go into specifics, but the change is necessary for security reasons. It also fixes a few unrelated bugs like the playerlist showing Player instead of Player1/etc in test servers, and is a prerequisite for fixing some deeper-rooted bugs as well.

It’s unfortunate that some games may be impacted, but specifically for the security-related reasons it’s necessary. On the bright side, the impact this has on games sounds worse than it is. Roblox did their due diligence and tested the changes against a number of top games to confirm that there weren’t any problems. That being said, you should still make sure you’re using WaitForChild appropriately in your games, as replication order isn’t guaranteed and any number of changes could potentially break your game if you rely on it.

8 Likes

So, I’ve seen Sharksie’s post spread around a lot as some rules of thumb for using WaitForChild. Since this post appears to be incorrect based on what I’ve learned from @alexnewtron and OP, does that mean that the assumption that an object’s children will be present is also false?

If an object exists in Workspace, will the object’s children be there, or do those have a potential to load in at a later time? So do I need to nest WaitForChild indefinitely for every object I want, or only the root container (like accessing a part from a Model, is workspace:WaitForChild("Model").Part sufficient)?

Another Roblox staff member confirmed to me that when using require with an asset ID, all of its children will be guaranteed to be loaded before the ModuleScript runs. Is this the only place where that paradigm exists, or does it also extend to normal require calls?

The UserId replication was patched a long time ago (~2015).

I’ve been chatting with OP privately, and he tells me that what I’ve said in this post is correct. LocalScripts will run immediately after it is replicated to the client, no matter the state of the DataModel (game).

Services exist immediately, but its children are not replicated until anything inside ReplicatedFirst replicates. LocalScripts inside RF will run immediately while other objects are downloaded into all the other services.

LocalScripts inside of StarterPlayerScripts (as an example) run as soon as they are replicated, and can be replicated before anything in Workspace, etc is replicated.

4 Likes

The following should be true:

The script WILL NOT find NicePart if it starts in ReplicatedStorage
( Scripts do not run in ReplicatedStorage )

The script may not find NicePart if it starts in StarterPlayerScripts
( Correct )

The script MAY NOT find NicePart if it starts in StarterCharacterScripts
( This is necessarily true for the time being, but this behavior can and will possibly change in the future, so it is not recommended to rely on it. Use OPs recommendation and use WaitForChild() )

The script may not find NicePart if it starts in StarterGui
( Same reason as above )

The script could find NicePart if it is delivered to the client when the server detects the player object was added to Players
( It’s hard to say exactly when Roblox sends the “snapshot” of the game when the Player Object is created ( It could be before or after? ) I wouldn’t recommend this. )

The script will find NicePart if it is delivered to the client when the server detects the player’s character is added
( This is correct and should be okay, because the character is the last object replicated to the client. However, the behavior could change so I wouldn’t rely on it. )

The script will find NicePart if it is delivered to the client when the server detects a player has touched a specific part.
( Correct. Same as above )

I would recommend creating a feature request of being able to set a LocalScript not to run until everything replicates would be possible.

5 Likes

Even if you’re not able to create the object, it still usually has documentation in the Object Browser:

(I’m talking about this menu by the way to clear up confusion)

I mean they usually keep this menu pretty up-to-date so maybe there’s a reason why they’re not including the Player object in here? I reference this menu a lot if I just need to figure out which object a certain method is under or what kind of methods certain objects have and ironically the object I need to reference the docs most for is Player.

4 Likes

There seems to be a lot of confusion, so I made a diagram. Note that it is based only on my observations, and is not authoritative.

Each step depends on the completion of the previous step (on the same peer, anyway).

  1. The client connects.
  2. A snapshot of the objects under ReplicatedFirst is queued to be replicated.
  3. The server starts replicating objects in the queue to the client.
  4. Once the client has received all the objects, scripts under ReplicatedFirst start running.
  5. A snapshot of replicatable objects under the DataModel is queued. The server also starts queuing changes made to the DataModel.
    (note that ReplicatedFirst is not actually replicatable)
  6. Once the client receives all the objects in the snapshot, the game’s Loaded state is set to true.
    (game:IsLoaded returns true, game.Loaded is fired)
    (all snapshotted objects are protected by the Loaded state)
  7. Object under Starter containers are copied to their respective script containers, a side-effect being that LocalScripts start running.

Ambiguity arises for objects that are asynchronously added near the DataModel-snapshot point in time. That is, they may or may not be included in the snapshot, and so may or may not be present by the time LocalScripts are running. Such objects require WaitForChild in order to be accessed safely.

For example (I’m not sure if this is really true), let’s say that the Player is created on the client, but the PlayerGui is created on the server. That means the server must wait for the Player to be replicated from the client before it can insert the PlayerGui. Depending on latency, the PlayerGui may be added before or after the DataModel snapshot, which means WaitForChild must be used to get the PlayerGui safely.
If the Player were created on the server, then the server would be able to insert a PlayerGui immediately, so it would be included in the snapshot guaranteed, and would therefore not require WaitForChild.

As I understand it, the changes stated in the OP should not really affect existing scripts. The mention of WaitForChild is just a general reminder.

Edit: Updated diagram to clarify Starter containers

29 Likes

Would this change the way game.Players.Localplayer works?
Since that line isn’t usable on server scripts, I thought I’d ask just in case :stuck_out_tongue:

No

1 Like

If localScripts are run as they get replicated, wouldn’t they start running right in the middle of the DataModel replication?

In my experience, there’s no guarantee when a localscript will get replicated. The localscript needs to assume that all objects in the DataModel may or may not be loaded yet.

1 Like

Man, we really need you on the IX team.

2 Likes

So in conclusion, if I have the default map (a baseplate), will I have to do workspace:WaitForChild("Baseplate") in a LocalScript? That’s what I’m concerned about.

Well, that flies directly in the face of what alexnewtron said earlier. Two Roblox staff members liked his posts, which made me think that I was wrong and that LocalScripts don’t wait for the game to be loaded before running.

But now Anaminus said that they do wait, and Anaminus is one of the smartest guys on this forum and his post has more likes. Personally, I’ve never experienced a LocalScript running before the game was fully replicated / loaded (not including objects that are added by server Scripts manually). It looks to me that Anaminus’ diagram says “if an object is there in Studio, it’ll be there before the LocalScripts run” – which is what I believed to be the behavior as well.

It’s clear that there’s a ton of confusion about this. I don’t know who to trust. Maybe e̵v̶e̵r̸y̸o̵n̵e̶’̷s̵ right. Maybe everyone’s wrong. Maybe Roblox changes the b̸e̴h̵a̶v̶i̵o̵r̴ weekly with a FFlag to keep everyone on their t̷o̸e̶s̵. Maybe ̵a̶l̶l̷ ̵_the_ ̶n̷e̸t̴w̸o̶r̶k̶i̸n̷g̵ ̸c̶o̶d̴e̷ ̶is ̵generated ̶b̸y̵ ̴mahine ̵l̴e̶a̶r̷n̷i̶n̷g̷.̴ Maybe Roblox i̸s̸ ̷j̶u̸s̸t̸ a pyramid s̴c̶h̵e̶m̷e̴. M̸̳͆a̷̻͒y̷͍̒b̷̨̀e̷̯̕ ̷̒ͅn̵̙̈ỏ̷̹n̵͔̈́e̶̡̅ ̸̜͌ō̸̰f̷̥̈́ ̴̻̓u̵͓̿s̸̫̈́ e̶͈̲̎v̴̺͌̄̂e̵̘͇̍́̾̿ṅ̵̗̜̳̎̀͝ ̴͖͓̳͈̓̄_ḛ̷̺̗̃̇̎̽x̷̙̀͑͋̿ḯ̸̛͉̦̱̍̀s̵̡̞̺̩͠ẗ̴̖͕͋̉͗ͅ_.

R̶̲̜̜̳͌̄͝e̴͚͍̽̑ͅp̸͙̋͑̃ļ̷̰̞́ͅì̴̪͗c̶̨̗͕̰̓͛ȃ̸̺͉͊͂̈́t̴̤͝i̷̙̪͇̺͊ò̸͍͋̎͠ǹ̴̡͋̄*,̸̡̘́̑̏͝ ̷͍͌͗Ṛ̷͍̘́͌̽̕͜e̵̯͊̂̇͗ͅp̴̧̖̐͜͝͝ͅl̷̗͔̔̍̈́̕i̷͓̾́c̸͔͖̈ͅḁ̵̇ẗ̶̡̻̱́i̷̩͐̒ó̸̡̨̱̰̿̕n̵̫͋̊̚,̵̥͊̃̏͆ ̵̝̩̹̮̎̽̊́Ȓ̵͉͎̑e̷̢̛̒̿ṕ̸̡̠̲͎͐̔͋l̷̩͇͌ȋ̵̼̭̲̎c̶͖̀͐͘a̵̜̽̏̉t̷͇̦̣͂̍i̶͔̅ơ̶͎̘̊̓̀ͅn̴̬̯͌.̴̞̪͈̒́̀̐.̴̖̃͊̒.̵̨̙̐͋̋ No… stop it…R̶̲̜̜̳͌̄͝e̴͚͍̽̑ͅp̸͙̋͑̃ļ̷̰̞́ͅì̴̪͗c̶̨̗͕̰̓͛ȃ̸̺͉͊͂̈́t̴̤͝i̷̙̪͇̺͊ò̸͍͋̎͠ǹ̴̡͋̄*,̸̡̘́̑̏͝ ̷͍͌͗Ṛ̷͍̘́͌̽̕͜e̵̯͊̂̇͗ͅp̴̧̖̐͜͝͝ͅl̷̗͔̔̍̈́̕i̷͓̾́c̸͔͖̈ͅḁ̵̇ẗ̶̡̻̱́i̷̩͐̒ó̸̡̨̱̰̿̕n̵̫͋̊̚,̵̥͊̃̏͆ ̵̝̩̹̮̎̽̊́I̶̜̦͖͊̉̚s̷̺̩̲͝ ̵̹̥̼̀͐b̸̜̀͗̂̏ụ̵̏̕i̷̮͝l̷̪̯̫̩͋̅̋d̷͔͑̃̊͌ͅe̶͕̬̦̍r̴̡̤̯̪͊̑͂̂m̸̝͙̪͂͑̾ä̷͈́n̸̝̭̳͂̾͗̓ ̸̼̐̈à̵̢̜́̅̚ ̴͇͛̊͂̋ṟ̵̓̽̾e̶̛̠͒̄̕ͅp̵̱̟͈̄̋̓̔l̶̻̼͋̓̓͆͜ï̵̭̔ĉ̴̺̺̉̚a̶͚̭̳̽n̸̠͍̘̰͗̈́ţ̸̓̚̚?̶̰̼̰̍̋̀ H̵e̴l̶p̴ ̴m̶E̵….Ḯ̴͉̙̲̫̓’̵̨͙̲͕͗̿m̸̪̑̾͊͜͝ ̷͖̜̖͛̾͠b̷̘̈̅̔e̴̖͔͙̔̓ͅī̶̬͈̙̙n̸̢͔̬̆g̸̞̗̤̖̋ ̴̹̬̙̀͛̊̾͜****R̵̡̩͂̃͘͘E̴͚̥̩̒̄L̶̰̟̐͂͗͊P̸͇̘̈́̈́͆̄Ȋ̷͓̣͕̟Ć̸͇̹͕A̵̧̭̗̐̆̅T̴̛̥͈̠͌̄̇Ḝ̷̛̣̥̀D̶̨͂̈.̸̀͌ͅ.̵̨̙̻͛̌.̷̧̟̖̲̒̒

44 Likes