How else can I organize this line of codes?

Hmm, ReplicaService was my answer all along. Anyway’s here’s my new, NEW script, is there anything else that I can modify to make it more clean, it’s kind of messy.

Script
local ReplicaService = require(script.Parent.ReplicaService)
local ProfileService = require(script.ProfileService)
local Trello = require(script.Parent.TrelloAPI)

local count = game.ServerScriptService:GetAttribute("TestCount")

local Profiles = {}
local default = {
	Armors = "",
	Attack = 0,
	Current_Armor = "",
	Current_Weapon = "",
	Defense = 0,
	Health = 100,
	Money = 0,
	Rank = "F-1",
	Skill_Attack = 0,
	Speed = 16,
	Weapons = ""
}

local ProfileStore = ProfileService.GetProfileStore("Test"..tostring(count), default)
local PlayerToken = ReplicaService.NewClassToken("PlayerProfile")

local function PlayerDataLoaded(player)
	local profile = Profiles[player]
	local data = profile.Replica.Data
	local logs = ""
	
	for name, value in pairs(data) do
		if not default[name] then
			data[name] = nil
			warn(string.format("%s data does not exist, data was found on %s", name, player.Name))
			logs += string.format("%s data does not exist, data was found on %s", name, player.Name).."\n"
		else
			player:SetAttribute(name, value)
		end
	end
	
	for name, value in pairs(default) do
		if not data[name] then
			data[name] = value
			player:SetAttribute(name, value)
			
			warn(string.format("%s had no data on %s, set back to %s.", player.Name, name, value))
			logs += string.format("%s data does not exist, data was found on %s", name, player.Name).."\n"
		end
	end
	
	if logs ~= "" then
		Trello:LogMessage(player.Name, logs)
	end
end

local function PlayerAdded(player)
	local profile = ProfileStore:LoadProfileAsync("Player_"..player.UserId, "ForceLoad")
	
	if profile then
		profile:ListenToRelease(function()
			Profiles[player].Replica:Destroy()
			Profiles[player] = nil
			player:Kick(player, "Your data was loaded remotely. Please rejoin.", script)
		end)
		
		if player:IsDescendantOf(game.Players) then
			local player_profile = {
				Profile = profile,
				Replica = ReplicaService.NewReplica({
					ClassToken = PlayerToken,
					Tags = {Player = player},
					Data = profile.Data,
					Replication = "All",
				}),
				_player = player
			}

			Profiles[player] = player_profile
			
			PlayerDataLoaded(player)
		else
			profile:Release()
		end
	else
		Trello:Kick(player, "Your data did not load.", script)
	end
end

local function PlayerRemoving(player)
	local profile = Profiles[player]
	
	if profile then
		profile.Profile:Release()
	end
end

game.Players.PlayerAdded:Connect(PlayerAdded)
game.Players.PlayerRemoving:Connect(PlayerRemoving)

for _, player in ipairs(game.Players:GetPlayers()) do
	spawn(function()
		PlayerAdded(player)
	end)
end

game:BindToClose(function()
	table.foreach(game.Players:GetPlayers(), function(_, player)
		PlayerRemoving(player)
	end)
end)

function Profiles:GetData(Player : Player)
	local profile = Profiles[Player]

	if profile then
		return profile.Replica.Data
	end
end

function Profiles:SetData(Player : Player, Attribute, Value : Value)
	local profile = Profiles[Player]
	
	if profile then
		profile.Replica:SetValue({Attribute}, Value)
	end	
end

return Profiles
LocalScript
local ReplicaController = require(game.ReplicatedStorage.ReplicaService.ReplicaController)

local player = game.Players.LocalPlayer

ReplicaController.RequestData()

ReplicaController.ReplicaOfClassCreated("PlayerProfile", function(replica)
	local is_local = replica.Tags.Player == player
	local replica_data = replica.Data
	
	if is_local then
		for name, value in pairs(replica_data) do
			replica:ListenToChange({name}, function(new_value)
				player:SetAttribute(name, new_value)
			end)
		end
	end
end)

Sounds better besides a few points:

  • Why are you still using player attributes? It’s not necessary, on the client you directly read the data onto the replica, same thing on the server
  • Unless I’m wrong, DataStore Service already handles BindToClose for saving data on server shutdown
  • Why are you trying to reconciliate player data with its model? It’s already handled by DataStore Service, use profile:Reconcile()

You can take a look at the docs of both libraries if you don’t understand how they work.
https://madstudioroblox.github.io/ReplicaService/
https://madstudioroblox.github.io/ProfileService/

1 Like