Need help with Storing DataStore in my Sol’s RNG-like roblox experience (attempted ProfileService)

Hello there, I have asked peoples in devforum to help me with fixing the issues with my roblox studio scripting, in this case I was trying to make an script for Sol’s RNG like game… and after to much times of using Roblox Studio’s in-built AI script helper and ChatGPT’s Script support for more then hours straight, I still couldn’t make the script work properly…

  1. What do you want to achieve? - I want this script I am about to show you below to Save and load the player’s data properly whenever they leave, got disconnected, rejoins the game,

  2. What is the issue? - I don’t know what exactly is causing an error that the old script which does not uses an profileservice does not save the new player data to the datastore, and why the new script which has adapted the profileservice system shows Error + Warn shown below section 3… but am asking developers in the devforum if they could help me with this issue…

  3. What solutions have you tried so far? I have attempted to Use an something called ProfileService for make the script do an Datastore deeds they were supposed to, but when I apply the script into Script in ServerScriptService, it shows Error and Warn at the same time, here is the result.

{Error + Warn that was shown on the Output when used an new script which uses an ProfileService}
DataStoreService: CantStoreValue: Cannot store Dictionary in data store. Data stores can only accept valid UTF-8 characters. API: UpdateAsync, Data Store: PlayerDataStore ” (Error)
[ProfileService]: DataStore API error [Store:“PlayerDataStore”;Key:“1015911803”] - “104: Cannot store Dictionary in data store. Data stores can only accept valid UTF-8 characters.” ” (Warn)

I will show you the Script codes of the old script which does not uses an profileservice + new script which uses an profileservice, and an rbxl file of the test experience which has other scripts in the ReplicatedStorage and such for the old version of script which does not uses an ProfileService, hope this helps for trying to fix the script :sweat_smile: :pray:

-- Old Script without ProfileService systems

local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Players = game:GetService("Players")

local RollEvent = ReplicatedStorage:WaitForChild("RollEvent")
local Chances = require(ReplicatedStorage:WaitForChild("Chances"))
local DataStoreService = game:GetService("DataStoreService")
local playerDataStore = DataStoreService:GetDataStore("PlayerDataStore")

local Inventory = {}

-- Function to save player data to DataStore
local function SavePlayerData(User)
	local userId = User.UserId
	local success, err = pcall(function()
		local rolls = User:FindFirstChild("leaderstats"):FindFirstChild("Rolls").Value
		local saveData = {Inventory = Inventory[userId], Rolls = rolls}
		-- Update the existing data in the DataStore instead of overwriting it
		local existingData = playerDataStore:GetAsync("PlayerData"..userId) or {}
		for key, value in pairs(saveData) do
			existingData[key] = value
		end
		playerDataStore:SetAsync("PlayerData"..userId, existingData)
	end)
	if not success then
		warn("Failed to save data for player "..userId..": "..err)
	end
end

-- Function to handle player join
local function PlayerJoined(User)
	-- Step 1: Create the leaderstats folder and parent it to the User
	local LeaderStats = Instance.new("Folder", User)
	LeaderStats.Name = "leaderstats"

	-- Step 2: Create the Rolls IntValue inside the leaderstats folder
	local Rolls = Instance.new("IntValue", LeaderStats)
	Rolls.Name = "Rolls"

	-- Attempt to load the player's data
	local userId = User.UserId
	local success, data = pcall(function()
		return playerDataStore:GetAsync("PlayerData"..userId)
	end)

	-- Handle the retrieved or default data
	if success then
		if data then
			Inventory[userId] = data.Inventory or {
				Limit = 10,
				LatestRoll = nil,
				Equipped = nil,
				Backpack = {}
			}
			-- Load the Rolls value
			local rollsValue = data.Rolls or 0
			Rolls.Value = rollsValue
		else
			Inventory[userId] = {
				Limit = 10,
				LatestRoll = nil,
				Equipped = nil,
				Backpack = {}
			}
			Rolls.Value = 0 -- Default Rolls value if no data is found
		end
	else
		-- Log an error if data retrieval failed
		warn("Failed to load data for player "..userId)
	end
end

-- Function to handle player leaving
local function PlayerLeft(User)
	SavePlayerData(User)
end

-- Connect events
Players.PlayerAdded:Connect(PlayerJoined)
Players.PlayerRemoving:Connect(PlayerLeft)

local SelectRNG = require(ReplicatedStorage:WaitForChild("SelectRNG"))

RollEvent.OnServerInvoke = function(User, Header)
	local UserInventory = Inventory[User.UserId]
	local UserLimit = UserInventory["Limit"]
	local Backpack = UserInventory["Backpack"]

	if Header == "Get" then
		if #Backpack >= UserLimit then
			table.remove(Backpack, table.find(Backpack, UserInventory["Equipped"]) or UserLimit)
		end
		table.insert(Backpack, UserInventory["LastestRoll"])

	elseif Header == "Waste" then
		UserInventory["LastestRoll"] = nil
	elseif Header == "GetInventory" then
		return Backpack
	else
		local Result = Chances[SelectRNG(User)][1]
		UserInventory["LastestRoll"] = Result
		return Result
	end
	print(Backpack)
	return
end

--new script which uses an profileservice system

local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Players = game:GetService("Players")
local ProfileService = game.ServerScriptService.ProfileService -- Assuming ProfileService is in ServerScriptService

local RollEvent = ReplicatedStorage:WaitForChild("RollEvent")
local Chances = require(ReplicatedStorage:WaitForChild("Chances"))
local DataStoreService = game:GetService("DataStoreService")
local playerDataStore = DataStoreService:GetDataStore("PlayerDataStore")

local Inventory = {}

-- ProfileService Setup
local profileStore = ProfileService.GetProfileStore(
	"PlayerDataStore", 
	{
		DataStore = playerDataStore,
		OnProfileLoad = function(profile)
			-- Initialize default values if profile data is empty
			profile.Data.Inventory = profile.Data.Inventory or {
				Limit = 10,
				LatestRoll = nil,
				Equipped = nil,
				Backpack = {}
			}
			profile.Data.Rolls = profile.Data.Rolls or 0
		end
	}
)

-- Function to save player data
local function SavePlayerData(profile)
	profile.Data.Inventory = Inventory[profile.UserId]
	profile:Save()
end

-- Function to handle player join
local function PlayerJoined(User)
	local profile = profileStore:LoadProfileAsync(User.UserId, "ForceLoad")
	if profile then
		profile:Reconcile()
	else
		warn("Failed to load profile for player "..User.UserId)
	end
end

-- Function to handle player leaving
local function PlayerLeft(User)
	local profile = profileStore:LoadProfileAsync(User.UserId)
	if profile then
		SavePlayerData(profile)
		profile:Release()
	end
end

-- Connect events
Players.PlayerAdded:Connect(PlayerJoined)
Players.PlayerRemoving:Connect(PlayerLeft)

local SelectRNG = require(ReplicatedStorage:WaitForChild("SelectRNG"))

RollEvent.OnServerInvoke = function(User, Header)
	local profile = profileStore:LoadProfileAsync(User.UserId)
	if profile then
		local UserInventory = profile.Data.Inventory
		local UserLimit = UserInventory["Limit"]
		local Backpack = UserInventory["Backpack"]

		if Header == "Get" then
			if #Backpack >= UserLimit then
				table.remove(Backpack, table.find(Backpack, UserInventory["Equipped"]) or UserLimit)
			end
			table.insert(Backpack, UserInventory["LastestRoll"])

		elseif Header == "Waste" then
			UserInventory["LastestRoll"] = nil
		elseif Header == "GetInventory" then
			return Backpack
		else
			local Result = Chances[SelectRNG(User)][1]
			UserInventory["LastestRoll"] = Result
			return Result
		end
		print(Backpack)
	end
	if profile then profile:Release() end
	return
end

and also this rbxl file of the test game to, I can donate the people who did fixed the issues or errors in the script ~70 R$ in their game if they do want to… I am that desperate to fix this script… I have used ChatGPT and such to fix the script by myself but it keeps on not working properly… :sob:

SolsRNGLikeGameTest1.rbxl (72.2 KB)

thank you for reading my Topic post :hugs:

Hello? is anyone here able to respond to my topic post…? :sob:

Don’t use profile service
It makes the code unorganised and complex for no reason

Btw the problem is:
You trying to save Tables
But you can only store string/number in datastore

How to fix?
Use Http service’s JSONEncode() and JSONDecode()
Encode takes the table and turn it into a string

And decode takes the encoded string and turn it back to a table

Use encode when saving the data
And use decode when getting the data

No need to thank me :slight_smile:

You can save Tables in DataStore

So can you fix here probably smart guy ?

This is unnecessary because saving to a data store automatically converts the data to JSON (and yes you can save tables)

SolsRNGLikeGameTest1 (Data Saving Working).rbxl (73.3 KB)