Player Players:WaitForLocalPlayer()

Waits for the localplayer and returns it.

while game.Players.LocalPlayer == nil do
	game.Players:GetPropertyChangedSignal('LocalPlayer'):wait()
end
player = game.Players.LocalPlayer

Becomes:

player = game.Players:WaitForLocalPlayer()
23 Likes

I think the LocalPlayer is guaranteed to exist when local scripts start running. If this isn’t the case, I think we should make it the case. I think the first pattern is only common because we need to do it in the corescripts and that makes other people think that it is necessary.

13 Likes

No one runs code in LocalScripts anymore. It’s all in ModuleScripts, which are generally shared by both server and localscripts. So when the modulescript runs it needs to check if it’s in play solo or the client, then wait for the local player.

6 Likes

That’s cool but I run stuff in local scripts.

16 Likes

The top of all my local scripts uses my favorite line

repeat game:GetService("RunService").RenderStepped:wait() until game.Players.LocalPlayer ~= nil

I was thinking about writing a plugin to insert this into new localscripts but I think I’ll make it use @Sharksie 's more modern version

2 Likes

I also need to be able to determine whether a modulescript is being run locally or on the server.

2 Likes

I’ve never ran into a situation where client-running code had a nil LocalPlayer. But I do agree with being able to tell environment from ModuleScript. Last time I suggested it though, it was kinda shot down.

11 Likes

My local code always starts with this:

repeat game:GetService("RunService").RenderStepped:wait() until game.Players.LocalPlayer.Character ~= nil

And yes, I know I could’ve just left out the last part (it triggers my OCD)

Edit: I’ve never had issues with the ‘localplayer’ not returning anything. Might be on your end?

1 Like

IIRC LocalPlayer is nil when plugins run since it hasn’t loaded in yet.

Is this just preference or is there some weird obscure reason to not just wait()? i.e:

repeat wait() until game.Players.LocalPlayer
3 Likes

The best way to do this is probably:

local PlayersService = game:GetService("Player")

local localPlayer = PlayersService.LocalPlayer
while not localPlayer do
    PlayerService.PlayerAdded:wait()
    localPlayer = PlayersService.LocalPlayer
end

This avoids the unnecessary wait() when the LocalPlayer already exists and uses the PlayerAdded event rather than the RenderStepped event.

8 Likes

Why arbitrarily yield when you can get LocalPlayer as soon as it’s available?

local player = game:GetService'Players'.LocalPlayer or game:GetService'Players':GetPropertyChangedSignal'LocalPlayer':Wait() or game:GetService'Players'.LocalPlayer
11 Likes

Oo I like that one best.

@gkku
It’s 60hz but the logic that creates the localplayer might be 30hz so probably redundant. I just wanted the shortest possible wait.

breathes in … BOI

Not “everybody” uses just module scripts

4 Likes

I believe he was referring to games using more modern development frameworks. For less experienced developers, they don’t need to worry about this issue.

1 Like

Ok. Looks like a lot of people aren’t understanding the problem here.

Fact:

  • LocalPlayer doesn’t exist when Scripts run in play solo
  • By the time LocalScripts run, the LocalPlayer does exist

Now consider a common scenario:

  • ReplicatedStorage.Util is a ModuleScript used by both the server and the client.
  • Util contains code that uses the LocalPlayer

Here’s what happens when your game runs in play solo:

  • Scripts run first
  • A script runs and requires Util
  • Util needs to initialize both its server and client sides since you’re in play solo
  • Before it can initialize its client side it needs to wait for the LocalPlayer

And that’s where the use case is.

One could argue that this would be fixed by making the LocalPlayer exist before any scripts run in play solo, but even then that’s a behavior that’s prone to breaking. I would always have a failsafe that ensures my game doesn’t break if roblox breaks LocalPlayer and then waits for a week before fixing it. So it makes sense to me that there may as well be a function for it.

3 Likes

After re-reading your post I understand. This makes sense because your module is being shared by the server and client in play solo.

Honestly it seems kinda messy that you have a module shared by both server and client that uses client only features.

Yeah because that didn’t sound condescending at all.

4 Likes

Is a new function really necessary? Once your Util module acquires the LocalPlayer, all code that depends on the module won’t need to do the same check. You can even export the result as Util.LocalPlayer or Util:WaitForLocalPlayer() if you want to be explicit about the dependency.

Regardless, the example in your first post is simple, correct, and idiomatic. There aren’t any glaring problems that would be solved by implementing it as a function.

1 Like

You could say the same for GetDescendants and WaitForChild. Even FindFirstChild. I think “it’s possible to make this yourself” isn’t a good reason for not having a quick api to do it.

1 Like

WaitForLocalPlayer is not suitable because:

Server scripts in Play Solo can access LocalPlayer, so in Play Solo everything would be detected as a LocalScript. While this is kind of true, it means I have to spin up a test server to test my game and can never use Play Solo.

Server scripts will yield indefinitely since LocalPlayer will never exist in-game or in a test server. A timeout wouldn’t work either because some use cases require the script to know instantly – for instance, when I made a spawn at camera plugin, I needed to know whether to wait for the player or to create a CFrame reference the plugin would reference when I went into play solo later – I had to do some really hacky workarounds to accomplish this (seeing if ChangeHistoryService was active)

1 Like