Data storing/presenting using ProfileService and ReplicaService!

First mistake is about the script is trying to require the ReplicaService module but it couldn’t. This is because you tried to find it in ServerStorage, where it should be in ServerScriptService.

Hi,

Thanks for the help, ReplicaService is in the ServerScriptService and still I get the error.

Do you have a working project/example I can have?

I’m sorry but if you’re just gonna copy the code, I’m afraid you will not gain any knowledges from this.

I see that your ServerScriptService variable is not presented, which is why it gives that error. I encourage you to create a variable which gets this service and use it to refer ReplicaService.

Is it possible with this module etc to save up to 20/30+ values? And if yes, do i need to make some more other changes to the code?

This depends on DataStoreService itself, as every custom data storing modules, every module has the same limit of data you can set and call. Please read this APJ page for more info:

You don’t have to change much of your code, just change your template to your desired template.

Thank you for this guide.
Regarding ReplicaService you write: ‘Along with that, we wanna make sure to destroy their replica token when they leave the game…
Perhaps I’m missing something but I can’t find where the replica token get destroyed when they leave?

This function will be called when a player leaves the game, inside it we destroy their replica by setting it to nil in the dictionary. That’s essentially how you remove something from a dictionary, which is assigning the key’s value to nil.

1 Like

Thank you for your reply!

I get replication to work but when I try this on a live server with multiple people and leave and enter again I get the following message ‘Token for replica class “replica name here” was already created.’

The relevant code I’m using is this:

local UserID = player.UserId

PLAYER_REPLICA[player] = ReplicaService.NewReplica({
	ClassToken = ReplicaService.NewClassToken("PlayerReplica_"..UserID),
	Data = profile.Data,
	Replication = player,
})

game:GetService("Players").PlayerRemoving:Connect(function(player)
	
	local profile = Profiles[player]
	if profile ~= nil then profile:Release() end
	
end)

profile:ListenToRelease(function()

	Profiles[player] = nil
	PLAYER_REPLICA[player] = nil
end)

The ListenToRelease is running. I’ve tested with a print statement.
Any help with this would be greatly appreciated.

Is this under the scope of the Players.PlayerAdded event?

Yes. And everything work just fine but only the first time.

The problem is when I leave and enter the server again (another player keep the server alive). It’s as if the Replica Token is not removed when the player disconnects so when ReplicaService tries to create the Token it is already there from previous connection. But the ListenToRelease triggers correctly when I disconnect so I’m quite puzzled why it’s not working.

Oh, I know why now and it is my fault.

I forgot to mention that you have to destroy the Replica by using a function, and not just setting it to nil through the table since we are only just clearing the replica from the list, but it is still there, so do me a favor.

Inside the Profile:ListenToRelease() function, after setting both player profile and Replica to nil, add a next line where you reference the player’s Replica and call :Destroy() on it, like so;

PLAYER_REPLICA[player]:Destroy()

I’ll add this into the tutorial, thanks!

Thank you, but sadly that didn’t do the trick.
Here is my complete PlayerAdded.

local function PlayerAdded(player)
	
	local profile = GameProfileStore:LoadProfileAsync(
		"Player_" .. player.UserId,
		"ForceLoad"
	)
	
	if profile ~= nil then
		
		profile:AddUserId(player.UserId)
		
		profile:ListenToRelease(function()
					
			PLAYER_REPLICA[player]:Destroy()
			PLAYER_REPLICA[player] = nil
			
			Profiles[player] = nil
			
			player:Kick()
		end)
		
		if player:IsDescendantOf(Players) then
			
				Profiles[player] = profile
			
				PLAYER_REPLICA[player] = ReplicaService.NewReplica({
						ClassToken = ReplicaService.NewClassToken("PlayerReplica_"..player.UserId),
						Data = profile.Data,
						Replication = player,
				})
						
		else
	
			profile:Release()
		end
	else

		player:Kick('Could not load player data, please try again.')
	end
end

Do you have any errors that are in the output? I think you could instead setting it to nil, try only just destroying it.

I tried with only Destroy, It had the same result.
I get no errors in Studio and not the first time running on a live server.

The second time on a live server it says the token is already created and points to the line with:
ClassToken = ReplicaService.NewClassToken(“PlayerReplica_”…player.UserId)

That’s strange.

How about be this? Assign this function to the replica:

PLAYER_REPLICA[player]:AddCleanupTask(function()
    print(PLAYER_REPLICA[player]:IsActive())
end)

Add this code line after you created the Replica under the Players.PlayerAdded scope.

When I run this in studio I get the result FALSE.
So that would mean that the Replica gets removed properly, right?

Yeah, so either you did something wrong or I’m wrong. I’m really unsure, but I’ll test this in studio soon.

1 Like

I FOUND A FIX!

It seems like the backends of ReplicaService are affecting it, to fix this, go to the ReplicaService module script, find the DestroyReplicaAndDescendantsRecursive function or line 373, and replace the whole function with this line:

local function DestroyReplicaAndDescendantsRecursive(replica, not_first_in_stack)
	-- Scan children replicas:
	for _, child in ipairs(replica.Children) do
		DestroyReplicaAndDescendantsRecursive(child, true)
	end

	local id = replica.Id
	-- Clear replica entry:
	Replicas[id] = nil
	-- Cleanup:
	replica._maid:Cleanup()
	-- Remove _creation_data entry:
	replica._creation_data[tostring(id)] = nil
	-- Clear from children table of top parent replica:
	if not_first_in_stack ~= true then -- ehhhh... Yeah.
		if replica.Parent ~= nil then
			local children = replica.Parent.Children
			table.remove(children, table.find(children, replica))
		else
			TopLevelReplicas[id] = nil
		end
	end
	CreatedClassTokens[replica.Class] = nil	
	-- Swap metatables:
	setmetatable(replica, LockReplicaMethods)
end

Hope this works!

2 Likes

how would i set tables?

like, let’s say my profile looked like this:

Money = {
	Roya = 0	
},

how would I edit the roya value using the setdata function?

1 Like