Scripting Helpers is winding down operations and is now read-only. More info→
Ad
Log in to vote
3

Player is nil in Module Script?

Asked by 9 years ago

Boom boom complicated metatables ahead!

Great, I'm inexperienced in writing questions for I have only written answers, ain't that dandy?

My issue is that whenever I try to access the player in a module script, it thinks it's nil, here is the source code

01local DS = game:GetService("DataStoreService"):GetDataStore("Stuff_DS_V1");
02local PM = {} do
03    PM.RegisteredPlayers = {};
04    local Methods = {};
05 
06    Methods.GetData = function(plr, key, defaultVal)
07        local data = DS:GetAsync(plr.player.userId.."_"..key);
08        if data then
09            if type(defaultVal) == "table"then
10                return data;
11            else
12                return data;
13            end
14        else
15            return defaultVal;
View all 80 lines...

That is the module script, as you can see, if the index is "player", then it returns the player object

And this is the normal handler script

01local PM = require(game.ServerScriptService:WaitForChild("Modules"):WaitForChild("PlayerManager"));
02 
03game.Players.PlayerAdded:connect(function(plr)
04    local makeshiftPlayer = PM.Get(plr);
05    print(makeshiftPlayer.Player.userId);
06    makeshiftPlayer:LoadData();
07end)
08 
09game.Players.PlayerRemoving:connect(function(plr)
10    local makeshiftPlayer = PM:Get(plr);
11    makeshiftPlayer:SaveData("Stats", {Blox = makeshiftPlayer.Blox, Lvl = makeshiftPlayer.Lvl, Exp = makeshiftPlayer.Exp});
12    makeshiftPlayer:SaveData("Backpack",{Backpack = plr.Backpack, Equipped = plr.Equipped});
13    wait();
14    makeshiftPlayer:Destroy();
15end)

But what's interesting is, the error only happens when a player leaves, I've already tested if the player is nil if you send it to a module, it is not.

The very error happens in the PM.Get function, which isn't even all that complicated, but even the script can't find the player for some reason.

11:49:06.526 - ServerScriptService.Modules.PlayerManager:74: attempt to concatenate field 'Name' (a nil value) 11:49:06.527 - Stack Begin 11:49:06.529 - Script 'ServerScriptService.Modules.PlayerManager', Line 74 - method Get 11:49:06.530 - Script 'ServerScriptService.Scripts.Player', Line 10 11:49:06.531 - Stack End

If I remove the 'print("Getting the Player Table for: "..plr.Name)', it errors in the Methods.SaveData function, where it says userId is nil.

11:49:06.526 - ServerScriptService.Modules.PlayerManager:68: attempt to concatenate field 'userId' (a nil value) 11:49:06.527 - Stack Begin 11:49:06.529 - Script 'ServerScriptService.Modules.PlayerManager', Line 68 - method SaveData 11:49:06.530 - Script 'ServerScriptService.Scripts.Player', Line 11 11:49:06.531 - Stack End

And, like the other error, it only errors when you leave. I suspected that when you index 'player' it returns nil since the player left.

How can I access the player, without it being nil?

0
Whoops, seems like my output is outdated LegitimatlyMe 519 — 9y

1 answer

Log in to vote
6
Answered by
BlueTaslem 18071 Moderation Voter Administrator Community Moderator Super Administrator
9 years ago

ROBLOX Objects shouldn't be able to have fields like Name or userId set to nil, so this is a weird error. My instinct was that plr in PM.Get wasn't actually a Player object.

Adding this line of debugging:

1if plr == nil then print("Argument 'plr' is nil.") return; end
2print("This is the player: ", plr)
3print("Getting the Player Table for: "..plr.Name);

This is indeed the case:

This is the player: table: 0E0360B0

This is really weird, since I checked that plr was indeed being passed in as a Player object:

1        print("PlayerRemoving(", plr, ")")
2        local makeshiftPlayer = PM:Get(plr);
3-- PlayerRemoving( Player1 )

Where is the table coming from?


Hint: one character is wrong PM:Get(plr).


You're calling PM.Get as a method, but it wasn't designed to be used as one! Thus the plr argument is actually being populated as PM!


A tweak that would have helped catch this is adding a metamethod to the PM module table to error if you try to grab a field (like Name or userId) that doesn't exist:

1setmetatable(PM, {__index = function(_, key) error("`" .. key .. "` is not a function provided by this module", 2) end})

You can also add checks that the first parameter is never PM.

Cleanup Aside

GetData can be simplified a lot:

1function Methods.GetData(plr, key, defaultValue)
2    return DS:GetAsync(plr.player.userId .. ("_" .. key)) or defaultValue
3end
Ad

Answer this question