New Player and Character Destroy Behavior Enabled by Default

Welp I’ve tried this method before, but it doesn’t work because all the parents of PlayerData and its descendants are set to nil when the PlayerRemoving event triggers. This means that if I attempt to Clone() the PlayerData folder at that point, I can’t access its descendants.

That said, I can Clone() the PlayerData folder before the PlayerRemoving event. However, how would I detect when the player is about to leave in order to handle this properly? :thinking:

Are you sure? It seems to work for me when I tested it.

local players = game:GetService("Players")

local function playerAdded(player)	
	local playerData = Instance.new("Folder")
	playerData.Name = "PlayerData"
	playerData.Parent = player
	
	local cash = Instance.new("IntValue")
	cash.Name = "Cash"
	cash.Value = 50
	cash.Parent = playerData
	
	local cash = Instance.new("IntValue")
	cash.Name = "Gems"
	cash.Value = 100
	cash.Parent = playerData		
end

local function playerRemoving(player)		
	local clonedPlayerData = player.PlayerData:Clone()	
	
	task.wait(1) -- to allow parents of the original values to be set to nil by the new behavior
	
	print(clonedPlayerData.Cash, clonedPlayerData.Cash.Value)
	print(clonedPlayerData.Gems, clonedPlayerData.Gems.Value)	
end

players.PlayerAdded:Connect(playerAdded)
players.PlayerRemoving:Connect(playerRemoving)


game:BindToClose(function() -- to allow player removing function to run
	task.wait(2)
end)





2 Likes

To anyone currently wondering, the best alternative way to save data with these new changes would be to parent every piece of data that you want to save under a folder in another instance or service. Recommendations for such would be ReplicatedStorage (so that the client can access data too) and the ServerStorage (to ensure your data is save there).

When the player is removed, you can then first call for a save of all the data within the folder and than afterwards destroy the folder.

If anyone has alternative ways, please share them :slight_smile:

1 Like

I was hoping my game was immune to this change, I tested today and it turns out my datastore script won’t work the way its coded. I’m testing it now. I don’t save much data, but the workaround that I’m using that seems to be working is to just create local variables for all of the data items before calling any async functions.

Its confusing to me what is meant by " This task is deferred and occurs after bound event connections are invoked, including PlayerRemoving ."

What does deferred mean? From my testing you don’t get much time to access the player before its gone. It seems any async call will finish after the player is gone(so if you have more than one async call to save data, the subsequent reference to the player’s children will throw an error)

If cycle through 4 or 5 values that I save in the player and put those into a table (or individual variables would probably work also), then use those variables to make my database async calls then it seems to work. (I guess its deferred long enough to save the values to variables, but not long enough to make more than one async call).

Somebody let me know if i’m doing this wrong or can explain what deferred means, how much time does this give you to access the instance.

abstract pseudo code with Enabled before fix and after ‘fix’:

So I reckon if we have it Enabled we don’t have to do any garbage collection of events connected to Player or Character instances when they leave or character is removed?

like I don’t need to do this:

PLAYERS.PlayerRemoving:connect(function(player)
	task.defer(player.Destroy, player)
end)

or

PLAYERS.PlayerAdded:Connect(function(player)
	player.CharacterRemoving:Connect(function(character)
		task.defer(character.Destroy, character)
	end)
end)

anymore?

Why this update? You could’ve at least set it to disabled for us to make some changes on our script. After that, we can just enabled it. But no, it literally wiped out all of my player’s data. My datastore fires a save function whenever an item is added or destroyed from their inventory. Because of this, the script save function fires after all the items from their inventories being removed or destroyed which ended up saving an empty inventory. Damage has already been done and all of my players are not happy.

Datastores have version history going back to a week iirc. You might still be able to recover from this!

Can you explain more? I’m using the DataStore Editor and I don’t see that setting where I could revert the entire datastore rather than doing one by one on each player.

I was curious about this as well but I haven’t been able to find any examples of how it works or how to use it.

All I can find is how datastore2 has automatic versioning, well that’s great… unless you can’t figure out how to use it!

If it requires you to rewrite your data saving scripts then its not going to be very useful for most people.

edit: this thread has some examples but I’m still not seeing how you would do this for all players

Apologies on the confusion earlier. I mixed up PlayerRemoving with AncenstryChanged. The initial issue was related to AncenstryChanged hence the inability to clone PlayerData upon the event signal fired. Thank you for the reassurance regarding PlayerRemoving. I’ve applied that but ultimately decided to go with DevFofo’s suggestion on handling player’s data entirely within ReplicatedStorage instead.

As DevFofo mentioned, if anyone has alternative methods, please share them—I’d love to find out if there areany more efficient ways to handle this :slightly_smiling_face: :+1:

1 Like

My suggestion is to revert the data as the player loads in, but that would require being able to tell that they were impacted by the issue.

Maybe check if the last save falls after things started to break, and if a save before that exists. If so, revert.

Could you let us know what this issue is? Are live games still safe to have PlayerCharacterDestroyBehavior = enabled with this issue?

1 Like

The ‘Enabled’ option is still safe to use.

The issue was that making ‘Enabled’ the Default option negatively affected more experiences than we anticipated, where the experience code was not prepared for destroyed Character or Player, but did not select ‘Disabled’ mode.

If the ‘Enabled’ option doesn’t work for you today, consider switching it to ‘Disabled’ until you have time to adjust to changes instead of leaving the ‘Default’.

We are also in the process of developing a different transition option which will provide most of the benefit, but will keep the Character/Player connected to the children (but will destroy connections).
We will post an update once we select the best path to continue.

3 Likes

Awesome to hear it, although we are all very heated about it, as long we are indeed being heard and given fair options, no real damage should be caused.

Thanks for everything and keep up the good work.