local PlayerLeagueUpdateModel = { }
PlayerLeagueUpdateModel.__index = PlayerLeagueUpdateModel
function PlayerLeagueUpdateModel.new(playerKey: StringValue)
local self = setmetatable({ }, PlayerLeagueUpdateModel)
self.PlayerKey = playerKey
return self
end
function PlayerLeagueUpdateModel:GetPlayerKey()
return self.PlayerKey
end
return PlayerLeagueUpdateModel
In a separate file I create a new instance of this model and I call GetPlayerKey(). Then print the result. It prints the expected value. I have provided the code below.
I then fire a bindable event.
local playerLeagueUpdateModel = PlayerLeagueUpdateModel.new(playerKey)
local playerKey = playerLeagueUpdateModel:GetPlayerKey()
print(playerKey)
PlayerBindableEvent:Fire(saveEventType, player, playerLeagueUpdateModel)
I have a script watching for this bindable event. The script is provided below
local function HandlePlayerActiveInLeagueUpdate(eventType: EventTypes, player: Player, playerLeagueUpdateModel: PlayerLeagueUpdateModel)
local playerKey = playerLeagueUpdateModel:GetPlayerKey()
print(playerKey)
PlayerDataManager.UpdatePlayerLeagueData(player, playerLeagueUpdateModel)
end
When I call playerLeagueUpdateModel:GetPlayerKey() I get the following error message
attempt to call missing method âGetPlayerKeyâ of table
What am I doing wrong? I have seen a couple of other people ask similar questions but Iâve not found any solutions.
Table passed through the bindable event loses the metatable. The recipient receives its own copy of the sent table. Look at the memory addresses in the illustration below:
The question is, why try to send the object through the bindable event. This is a lot of data sent via a signal.
Any script that needs access to the object should simply require it, or access the data from the module that required the object. For example:
local Class = require(Class)
module1.Objects = {}
-- Let's say some third script calls a function in this module that creates
-- an object for the sent player and stores it in module1.Objects.
-- inside the function:
module1.Objects[player] = Class.new()
local module2 = {}
local module1 = require(module1)
-- Call a method of the object returned by the Class:
module1.Objects[somePlayer]:PerformATask()
Bindable events and functions should be used for inter-script communication and signaling more than sending the data, normally in cases where two scripts depend on each other, but do not share functionality.
Thank you for your quick response. That backs up my thoughts (Chat GPT was telling my code was fine).
The question is, why try to send the object through the bindable event.
I have two separate modules (PlayerData and League). I want to save some some of the league data against the Player (e.g. their final position, current position etc). Obviously I can simply use the property to get the value, but I expected the instance to be passed.
No problem, and yeah, ChatGPT is an awesome assistance, but it can make mistakes.
So, two separate modules that have to share some data. Iâd say the approach entirely depends on your script architecture. Personally, I like to have a module that âpointsâ to all objects and data regarding clients.
Something like this.
local Client = {}
local playerInfo: {[Player]: any} = {}
local DataManager = require(...)
local CharacterModule = require(...)
function Client.Init(player: Player)
playerInfo[player] = {}
playerInfo[player].Data = {}
DataManager.DoThisAndThat()
playerInfo[player].Character = CharacterModule.new()
-- and so on
end
function Client.Discard(player: Player)
-- save and clear
end
setmetatable(Client, {__index = playerInfo})
return Client
Then any script can require Client and access data via Client[player].Data etc. The table the module returns is actually very lightweight, because all that data and objects reside in the module itself, and are accessible via __index metamethod.
This is just one way of going about it, though it has worked well for me numerous times. You could prefer a different hierarchy of modules. Letâs say you have a some DataController that controls both the data saving and LeagueUpdate. Maybe, in your case, you could have a module that requests the player data, updates the live data, keeps reading and updating the live data while occasionally calling auto save, then wraps everything up, updates and saves the data, and clears the live data at the end.
The general idea is modularity and hierarchy. Modules higher in hierarchy manage modules lower in the system. And two modules cannot require each other. It makes more sense to have a module that depends on the functionality of those two. At some point bindable signals come in handy too, but they are more suitable for lower amounts of sent data and signalling.
Thanks for that tip. I feel I have locked myself to an architecture that will be problematic in the future.
Although I am interested in why bindable events are only used for small amounts of data? I assumed as this is being passed around in memory there would be few issues with doing it this way, what are the negatives of passing larger objects around (apart from what you have already explained)?