Problem obtaining local player position from a module script

Hi All

I would like to use a module script to get the local player’s position. For this reason, I have inserted a module script under “StarterPlayer.StarterCharacterScripts” folder directory, because it replicates the script to the local character, but I can’t access the position still. the script code.

I have confirmed that the module script is being successfully present under the local character in the workspace after the game launches.

The following is the code in question:

local Player = game:GetService("Players").LocalPlayer

local Character = Player.Character or Player.CharacterAdded:wait()

local module = {}

module.PlayersCurrentPosition = script.Parent:WaitForChild("HumanoidRootPart").Position -- Character.HumanoidRootPart.Position

return module

And the following is the result:
02:55:39.879 - Infinite yield possible on 'StarterPlayer.StarterCharacterScripts:WaitForChild("HumanoidRootPart")'
which leads to pointing at a problem with the WaitForChild() line, and I cannot get a value in the module.PlayersCurrentPosition.

I would appreciate any help as to why I am getting this problem and how to achieve my goal of obtaining the local player position from a module script.

1 Like

Well a module script doesn’t actually run. You need to require it from some place in a real script.

Also if you require a module script from a local script. It behaves like a localscript. Likewise for the server side. In this case it looks like your module script is inside of StarterCharacterScripts… which does not have a HumanoidRootPart.

Also why are you using a module for this anyway? Could easily do this from anywhere.

You should place your module script somewhere in the context where you’d like to use it. Will both the server and the client be using it? Then put it inside of ReplicatedStorage. Only the server? Server Storage. Only the client? Put it in the player itself (not the character).

Require it from those locations.

Shouldn’t script.Parent be character? The error says that you’re waiting for the HumanoidRootPart under StarterCharacterScripts.

The script is present under the character model in workspace after running the game, so I am surprised why I cannot access the HumanoidRootPart using script.Parent.HumanoidRootPart.

Regarding more context on what I want to achieve: I would like to use a module script to obtain a reference to certain properties about the player, so that I can very elegantly access the same data across various other scripts. In other words, I want a common space from where I can access some attributes. I am not sure if there is a better way to access such properties which I myself set up? These properties are specifically about the local player and do not need to be on the server.
I want the particular property in question to be initialized to the humanoid’s position on the first run of the script.
Regarding the module script not running before requiring it, I did require it and in turn got to experience this difficulty.

local Players = game:GetService("Players")
local LocalPlayer = Players.LocalPlayer
local Character = LocalPlayer.Character or LocalPlayer.CharacterAdded:Wait()

With that you can get any property you want for the player. Roblox is so accessible that it doesn’t really make sense to use a module for this. Unless you’re making a library of functions specific to your game to achieve some type of behavior more easier to cut down on repeated code.

I can see if these were custom properties. But the data is the same regardless of where you require it from. The only thing that changes are the variables you store in a script.

If you’re trying to teleport the player to a location, you can handle this locally, but you should handle this on the server. You can simply put a script in ServerScriptService

reference the player service as I did above (Remove the localplayer stuff because it doesn’t exist on the server). And use the PlayerAdded and CharacterAdded events.

Players.PlayerAdded:Connect(function(Player)
  Player.CharacterAdded:Connect(function(Character)
    Character.HumanoidRootPart.CFrame = CFrame.new(POSITION) -- Change position to the vector3 that you want.
   end)
end)

I mean the experience is great and all, but if you can’t use a LocalScript and regular scripts in the right way that it’s meant to be used while taking full advantage of the API and Workspace, and you’re already over complicating things this much. You definitely should hold off on ModuleScripts.

Yes, I am exactly trying to make a library of functions specific to my game to cut down on repeated code. And yes, they are custom properties as I have indicated previously.

It seems straightforward that computation can be executed locally for such type of computation. Not trying to teleport anybody. I just want to initialize a variable in my local script to the player’s current position. I am using a module script so that I can require it among various other local scripts, thus using the module script as a common space of variables.

I have also attempted inserting ObjectValues/Vector3Values/IntValues/etc as children to my character and access those. But I require a “TableValue” as one of my properties which Roblox does not support, thus I am resorting to the technique in my question as an alternative.

Cool, so place the ModuleScript inside of the Player in the Players Service. To note it doesn’t have to be there. But the difference between a ModuleScript and a LocalScript is. A LocalScript runs when it’s inside of the Player, or Player’s Character, while a ModuleScript doesn’t run at all until it is required (require()).

Meanwhile in a script you usually work relative to the script. But for a ModuleScript you reference things relative to the ModuleScript. This means that where ever that ModuleScript is located, is where it’s going to start trying to reference things from. (In this case script.Parent = ModuleScript.Parent) Since you want this to be accessible by all LocalScripts then you should put that somewhere they can all find it. Not that in the player is bad. nothing wrong with it. It’s preference really. But it should be in PlayerScripts because its more appropriate for the context. Also it won’t keep getting deleted and re-inserted on death.

After which you can require the ModuleScript.

local Players = game:GetService("Players")
local LocalPlayer = Players.LocalPlayer
local PlayerScripts = LocalPlayer.PlayerScripts

local MyModule = require(PlayerScripts:FindFirstChild("MyModule")) -- Change My Module to the name of your module script.

And your code as you typed above should work correctly.

When you say “place the ModuleScript inside of the Player in the Players Service” do you mean to move this into the StarterPlayer.StarterPlayerScripts directory or Players directory or something else?

My bad, put it in StarterPlayerScripts. That’s what I meant. Idk what I was talking about. But yeah never put a ModuleScript inside of StarterCharacterScripts. Because it will re-generate the module when the player die. It’s fine for regular scripts and localscripts but not modulescripts.

It’ll automatically get copied to PlayerScripts inside of the Players Service. In which you can easily reference it and require it in other localscripts.

Thanks, following your suggestion it works great now and and appears to be what I want.

Had to change my code a bit. The following is the updated version.

local Player = game:GetService("Players").LocalPlayer

local Character = Player.Character or Player.CharacterAdded:wait()

local module = {}

module.PlayersCurrentPosition = Character:WaitForChild("HumanoidRootPart").Position 

return module

However, I have some further questions if you could please help.

First, could you elaborate on whether this script now becomes a local module script or not? On the same note, where would I place the module script if I wanted it to be server sided, given the context of the problem? I am guessing in the ServerScriptService?

Lastly, if a script, 10 seconds later, requires this module script, I am guessing that the module.PlayersCurrentPosition value will be updated. What if I do not want the value to be changed beyond the first time a user has called it? Can this be avoided by setting a simple variable indicated that the script was initialized already? Is there another solution?

...
if (not init) then
    module.PlayersCurrentPosition = Character:WaitForChild("HumanoidRootPart").Position 
    init = true
end
...

If the script is required by a LocalScript I believe it becomes a localscript. Also the script being in Players now, I don’t believe it will be replicated to the server. Meaning it can’t see what the server see. So it won’t be able to access ServerScriptService or ServerStorage for example.

If it was on the server, I used to put my ModuleScripts as children of scripts or localscripts (which you can totally do by the way. Roblox does it as well when they put together a “system” that is self contained, and they want to split functionality between modules.

I keep my ModuleScripts in ServerStorage now, and require them in a script from ServerScriptService.

Also that’s a good question.

I don’t really pay attention to details like this. But I believe you’ll be getting a cached version of it. Basically the position won’t update. You’ll need to use a function, and return the property of the character that you want that way it always fetches the most up to date info.

It’s doing

local DoorLocked = false

It will always be false unless you manually set it to true. I could be wrong about this though.

Thanks once again for your help.

So it seems that if multiple scripts require() the same module script, and each module script execute some code when it is called by requiring it, this code will only be executed one time - when the code was first required? That sounds like a very important detail. Hope someone can confirm it. Or I could do that soon once I get some free time.

1 Like