Take the following example code from a ModuleScript called “PlayerFunctions” (has some helpful code that would be relevant for fetching/sending player-related data, whatever):
local PlayerFunctions = {}
-- Option #1: using a method via the . operator
function PlayerFunctions.getStatFromPlayer(plr, statToGet)
return plr:findFirstChild(statToGet).Value
end
--Option #2: using a function via the : operator
function PlayerFunctions:getStat(statToGet)
return ["??????"]:findFirstChild(statToGet).Value --idk
end
return PlayerFunctions
As you can see, Option #1 and Option #2 are meant to do the same thing.
Option #1 should work fine, since it has plr as an argument; I could use this in another script with no fuss, as long as I inputted a valid Player instance into that parameter.
I am fine with sticking with Option #1, but I am curious to know if there’s a reliable way to do Option #2 (primarily because it just feels less redundant). As far as I can tell, it doesn’t seem to be possible because there’s no way to implicitly reference the “plr” as seen in Option #1.
TL;DR: Is there a way to (in another script ofc) point PlayerFunctions to a Player of interest (maybe via some obscure declaration I’m not aware of) so that I can use PlayerFunctions:doBlah() instead of PlayerFunctions.doBlahTo(plr)?
Just want to add that I’ve done a bit of OOP in a few other coding languages but if the solution is right there and I’m missing it, I apologize, I think ModuleScripts are just tripping me up a bit
There is not really a good way I can think of.
I’m not sure how much you know exactly, so here’s a quick recap written for someone who understands OOP basics.
function class.Function(self, ...)
is the same as function class:Function(...)
and in both of these cases, self is all lowercase and refers to class.
They can be switched around, so I can call the first one with the method call syntax : and I can call the second one with the function call syntax . so long as I provide a working self to use.
Here is another example. game.Destroy(game.Workspace.BasePlate)
Here, I take what is usually performed with : and instead used the function with another self argument, being BasePlate.
If you wanted to use the : method call syntax, you would need PlayerFunctions to be some bizarre, messy, and inefficient metatable so that it can redirect your findFirstChild method call.
Alright, no guarantees, but I think I did this right. It’s late and I haven’t tested it. LocalPlayer won’t work directly with this example. Good luck!
local PlayerObj do -- this creates a throwaway scope to hide all variables involved in class creation and allow us to minimize in the editor
PlayerObj = {ClassName = "PlayerObj"} -- Table for our object, set static variables.
_PlayerObj = {} -- Metatable
function PlayerObj:new(player)
local object = {}
object.Player = assert(player and player:IsA("Player"), "Method PlayerObj:new(player) does not have a Player as the first parameter")
setmetatable(object, _PlayerObj) -- If you don't know metatables, learn. They are fun and almost essential for OOP.
return object
end
function PlayerObj:getStat(statToGet)
assert(self.ClassName == PlayerObj, "Method PlayerObj:getStat must be called with a valid PlayerObj as the 'self' argument")
return assert(type(statToGet)=="string" and self:FindFirstChild(statToGet) and self[statToGet].Value, "Method PlayerObj:getStat(statToGet) either does not have a string as the first parameter or can't find matching stat")
end
function _PlayerObj:__index(key)
return PlayerObj[key] or self[key] or self.Player[key]
end
function _PlayerObj:__newindex(key, value)
if self[key] then -- Depending on your use case, these and others may need to be rearranged.
self[key] = value -- Currently this defaults to custom variables (which must be declared either in a custom method or in PlayerObj:new())
else
self.Player[key] = value
end
end
end
local players = {}
game.Players.PlayerAdded:Connect(function(p))
players[p.Name] = PlayerObj:new(p)
end)
game.Players.PlayerRemoving:Connect(function(p)
players[p.Name] = nil
end)
print(players.Tokamak:getStat("TestStat"))
print(players[game.Players.LocalPlayer.Name]:getStat("TestStat"))
Thanks for the write-out, yeah that does seem to be the only plausible way to do it. I agree that it’s a bit unnecessary though… I think I’ll just stick with my little dot symbol + extra argument instead