Player Players:WaitForLocalPlayer()

Which is why any module that depends upon the LocalPlayer should be loaded from the client?

1 Like

The module as a whole doesn’t depend on the LocalPlayer. Only a small part of it does.

That’s what I said. A ModuleScript that is required by a server-side script, ever, should probably not change behavior when required by a LocalScript. Like, I just don’t see an example where Roblox’s API is lacking rather than there might be a smarter way to do whatever it is that leads you to needing this.

1 Like

It’s easy to argue that 0% of it should.

1 Like

Please read the previous posts. This and my last two responses to you are duplicates of what’s already been posted.

Test servers are not suitable because they are slow to start up and I am not going to increase the time it takes to test by 10x every time I want to check for issues.

1 Like

So you’re saying this function’s primary purpose would be to avoid Start Server/Start Player?

2 Likes

Not avoid it completely – it has its uses – but yes. I want to catch issues involving this during rapid testing (Play Solo) rather than finalizing the build for publishing. Test servers are great for hunting down problems when you know of an issue involving client/server or for final testing, but less so for every other time a game is tested.

Why not put anything that is client-dependent in StarterPlayer.StarterPlayerScripts and then just know nothing outside of StarterPlayer.StarterPlayerScripts should ever require anything from there?

Because it’s more of a mess to strew connectors to shared utilities across the game hierarchy than to encapsulate in the shared utility.

This is not coming from someone who jams every script and module into Workspace. I have my client-only modules in ReplicatedStorage>Client, shares in ReplicatedStorage>Shared, and server in ServerStorage>Server. As someone who already segregates client/server as much as reasonably possible, I am telling you it’d solve less problems than it’d cause to set up the hierarchy the way you’re suggesting, and the entire point of segregation is to prevent problems – not cause them. Design is not a science, and there is no rule or guideline that holds true through every scenario – I encourage you to reflect on others’ experiences and that you may think there’s always a better way only because you haven’t yet come across an instance where that wasn’t true. I, myself, made the same suggestion as you but have since turned in the opposite direction because I experienced a case where there wasn’t a better way.

Thank you for this example. I now understand the problem.

There is one hard fact: a peer can be both a server and a client (play solo). Therefore, modules should be structured with this in mind from the start. In order to correctly handle the unusual but still possible case where a peer is of both types, the module must have one endpoint for each peer, so that they do not conflict. Differences in the code can be generalized, or common code can called by both endpoints.

local module = {}
if IsServer then
	function module.ServerEndpoint()
		commonCode()
		serverCode()
		moreCommonCode(generalizedServerData)
	end
end
if IsClient then
	function module.ClientEndpoint()
		commonCode()
		clientCode()
		moreCommonCode(generalizedClientData)
	end
end
return module

Remember that this only applies where there are differences. When the behavior is the same regardless of peer type (PrintTable), one endpoint is sufficient.


It’s a terrible hack and you shouldn’t do it, but it’s possible to use getfenv to query the “script” variable and see what kind of script it is.

function GetScriptContext()
	local env = getfenv(0)
	if type(env) == "table" and
		typeof(env.script) == "Instance" and
		env.script:IsA("LuaSourceContainer") then
		return env.script.ClassName
	end
	return ""
end

getfenv(0) returns the global environment from the bottom of the stack. Since each script has its own global environment, it will return the environment of the script that began the call stack.

Once again, do not do this.

6 Likes

I don’t want to know whether the module will work for a peer of both types – that defeats the purpose of testing because no in-game clients are both. I’m testing because I want to make sure it will work in-game.

I feel like I’m missing something. I’ve used shared modules for a long time and never had a problem with LocalPlayer not existing.

1 Like

You are missing something – the experience of encountering an instance where what you suggested didn’t work. Not everyone works on the same projects – just because you haven’t encountered it doesn’t mean it doesn’t exist.

Wasn’t saying it’s not happening to you, I’m frankly shocked it hasn’t happened to me, doing pretty much exactly what is said in this thread.

I do not understand how waiting for the local player will ever help find erroneous code on the server. If LocalPlayer is equal to nil, then you know that you’re on the server. Anything in the context of a LocalScript will only load after LocalPlayer has been set.
So, if you’re sure the best way to find out if your code is broken is to see that the local player is there, just simply check for Players.LocalPlayer.

I think this is wrong, and despite your claims that this is a big problem that I just haven’t encountered, you have yet to offer an example that actually proves that point.

1 Like

LocalPlayer is not nil on the server in Play Solo.

It is set to nil before the player loads.
Nevertheless, Players:WaitForLocalPlayer() does not solve your problem. Like, at all. In Play Solo, it would just return the Player object after a possible yield.

I’m very tempted to do that

3 Likes

The only problem I see in this thread is the usage of Play Solo when starting a server and a player is the obvious solution.

I think this feature request is much too niche to be added to the API. That’s just my opinion.

1 Like

I’m not telling you to handle the specific case where a peer is both a server and a client, I’m telling you to structure your code such that, if it works in play solo (server and client), then it will inherently work in-game (server or client).

Don’t do it.