Help Needed with Game Table Data Store in Roblox

Hello everyone,

I’m currently working on a Roblox project where I need to store and retrieve a table of game data using DataStores.

Issue Description

I’m trying to save a table of game data to a DataStore and then load it to display the saved games in the game UI. The flow works as follows:

  1. A player inputs game details (Name, Description, IconId, ThumbnailId, GameId) and publishes the game.
  2. The game data is sent to the server, which saves it to a DataStore.
  3. The server then sends the updated game data to all clients.
  4. Clients receive the game data and clone a game template to display the game in the UI.

Problems Encountered

  1. Game Data Not Loading Properly: While I can see that the server successfully saves the game data, the client does not seem to properly receive and process this data.
  2. Nil Game Data: The game template cloning function on the client side often encounters nil game data, causing errors.

Screenshot 2024-07-11 154723

ServerScriptService

local DataStoreService = game:GetService("DataStoreService")
local gamesDataStore = DataStoreService:GetDataStore("GamesData")

local games = {}

local function LoadGames()
	local success, data = pcall(function()
		return gamesDataStore:GetAsync("games")
	end)
	if success then
		if data then
			games = data
			print("Games data loaded successfully.")
		else
			print("No games data found, initializing empty games table.")
			games = {}
		end
	else
		warn("Failed to load games data: " .. tostring(data))
		games = {}  
	end
end

local function SaveGames()
	local success, err = pcall(function()
		gamesDataStore:SetAsync("games", games)
	end)
	if not success then
		warn("Failed to save games data: " .. err)
	end
end

LoadGames()

local ReplicatedStorage = game:GetService("ReplicatedStorage")
local PublishGameEvent = ReplicatedStorage:FindFirstChild("PublishGameEvent")

if not PublishGameEvent then
	PublishGameEvent = Instance.new("RemoteEvent", ReplicatedStorage)
	PublishGameEvent.Name = "PublishGameEvent"
end

local LoadGamesEvent = ReplicatedStorage:FindFirstChild("LoadGamesEvent")

if not LoadGamesEvent then
	LoadGamesEvent = Instance.new("RemoteEvent", ReplicatedStorage)
	LoadGamesEvent.Name = "LoadGamesEvent"
end

game.Players.PlayerAdded:Connect(function(player)
	print("Player added, sending games data:", games)
	LoadGamesEvent:FireClient(player, games)
end)

PublishGameEvent.OnServerEvent:Connect(function(player, gameData)
	print("Received game data from client:", gameData)
	table.insert(games, gameData)
	SaveGames()
	print("Game data saved successfully.")

	PublishGameEvent:FireClient(player, true)

	for _, plr in pairs(game.Players:GetPlayers()) do
		LoadGamesEvent:FireClient(plr, games)
	end
end)

Local Script inside ScreenGui

local function PublishGame()
	local gameData = {
		Name = AddGame.GameName.GameName.Text,
		Description = AddGame.Description.Description.Text,
		IconId = AddGame.IconID.IconID.Text,
		ThumbnailId = AddGame.ThumbnailID.ThumbnailID.Text,
		GameId = AddGame.GameID.GameID.Text,
		Creator = game.Players.LocalPlayer.Name
	}

	print("Sending game data to server:", gameData)

	if gameData.Name ~= "" and gameData.Description ~= "" and gameData.IconId ~= "" and gameData.ThumbnailId ~= "" and gameData.GameId ~= "" then
		local success, errorMsg = pcall(function()
			return MarketplaceService:PromptProductPurchase(player, productID)
		end)

		if success then
			PublishGameEvent:FireServer(gameData)
			MarketplaceService.PromptProductPurchaseFinished:Once(function(player, productId, wasPurchased)
				if productId == productID and wasPurchased then
					table.insert(games, gameData)

					local gameTemplate = GameList.GameTemplate:Clone()
					gameTemplate.NameText.Text = gameData.Name
					gameTemplate.Icon.Image = "rbxassetid://" .. gameData.IconId
					gameTemplate.Parent = GameList
					gameTemplate.Visible = true

					gameTemplate.PlayButton.MouseButton1Click:Connect(function()
						TS:Teleport(gameData.GameId)
					end)

					gameTemplate.DescriptionButton.MouseButton1Click:Connect(function()
						InformationFrame.Visible = true
						InformationFrame.Position = UDim2.new(0, 0, 1, 0)
						local tweenInfo = TweenInfo.new(0.5, Enum.EasingStyle.Quad, Enum.EasingDirection.Out)
						local tween = TweenService:Create(InformationFrame, tweenInfo, { Position = UDim2.new(0, 0, 0, 0) })
						tween:Play()

						InformationFrame.Icon.Image = "rbxassetid://" .. gameData.IconId
						InformationFrame.DescFrame.Description.Text = gameData.Description
						InformationFrame.GameName.Text = gameData.Name
						InformationFrame.Thumbnail.Image = "rbxassetid://" .. gameData.ThumbnailId
						InformationFrame.Creator.Text = gameData.Creator
					end)
				end
			end)
		else
			local errorMessage = errorMsg or "Unknown error"
			warn("Publish failed: " .. errorMessage)
			print("Error message:", errorMessage)
		end
	else
		warn("Cannot publish: All fields are required.")
	end
	PublishGameEvent.OnClientEvent:Connect(function(success)
		if success then
			print("Game published successfully.")
			AddGame.GameName.GameName.Text = ""
			AddGame.Description.Description.Text = ""
			AddGame.IconID.IconID.Text = "" 
			AddGame.ThumbnailID.ThumbnailID.Text = ""
			AddGame.GameID.GameID.Text = ""
		else
			warn("Publish failed.")
		end
	end)
end

local function CloneGameTemplate(gameData)
	local gameTemplate = GameList:FindFirstChild("GameTemplate")
	if not gameTemplate then
		warn("GameTemplate not found in GameList.")
		return
	end

	gameTemplate = gameTemplate:Clone()

	print("Cloning game template:")
	print("gameData:", gameData)

	if not gameData then
		warn("gameData is nil.")
		return
	end

	local nameText = gameTemplate:FindFirstChild("NameText")
	local icon = gameTemplate:FindFirstChild("Icon")
	local playButton = gameTemplate:FindFirstChild("PlayButton")
	local descriptionButton = gameTemplate:FindFirstChild("DescriptionButton")

	if not nameText then
		warn("NameText not found in gameTemplate.")
	else
		nameText.Text = gameData.Name
	end

	if not icon then
		warn("Icon not found in gameTemplate.")
	else
		icon.Image = "rbxassetid://" .. gameData.IconId
	end

	if not playButton then
		warn("PlayButton not found in gameTemplate.")
	else
		playButton.MouseButton1Click:Connect(function()
			TS:Teleport(gameData.GameId)
		end)
	end

	if not descriptionButton then
		warn("DescriptionButton not found in gameTemplate.")
	else
		descriptionButton.MouseButton1Click:Connect(function()
			InformationFrame.Visible = true
			InformationFrame.Position = UDim2.new(0, 0, 1, 0)
			local tweenInfo = TweenInfo.new(0.5, Enum.EasingStyle.Quad, Enum.EasingDirection.Out)
			local tween = TweenService:Create(InformationFrame, tweenInfo, { Position = UDim2.new(0, 0, 0, 0) })
			tween:Play()

			InformationFrame.Icon.Image = "rbxassetid://" .. gameData.IconId
			InformationFrame.DescFrame.Description.Text = gameData.Description
			InformationFrame.GameName.Text = gameData.Name
			InformationFrame.Thumbnail.Image = "rbxassetid://" .. gameData.ThumbnailId
			InformationFrame.Creator.Text = gameData.Creator
		end)
	end

	gameTemplate.Parent = GameList
	gameTemplate.Visible = true
end

local function LoadGames(games)
	if not games then
		warn("No games data received from server.")
		return
	end
	print("Loading games:", games)
	for _, gameData in pairs(games) do
		print("Loading gameData:", gameData)
		CloneGameTemplate(gameData)
	end
end

LoadGamesEvent.OnClientEvent:Connect(function(games)
	print("Received games data from server:", games)
	LoadGames(games)
end)

Did you check the data right before you sending it to the clients ?

1 Like

I’d suggest you use ProfileService. Save your player data with ProfileService! (DataStore Module)

It deals with everything so you don’t have to. I know it may seem it might seem very inefficient to switch your datastores and all but im telling you it’s 100% worth it.

1 Like

Try using

local DataStoreService = game:GetService("DataStoreService")
local HttpService = game:GetService("HttpService")
local gamesDataStore = DataStoreService:GetDataStore("GamesData")

local games = {}

local function LoadGames()
	local success, data = pcall(function()
		return gamesDataStore:GetAsync("games")
	end)
	if success then
		if data then
			data = HttpService:JSONDecode(data)
			games = data
			print("Games data loaded successfully.")
		else
			print("No games data found, initializing empty games table.")
			games = {}
		end
	else
		warn("Failed to load games data: " .. tostring(data))
		games = {}  
	end
end

local function SaveGames()
	local success, err = pcall(function()
		gamesDataStore:SetAsync("games", HttpService:JSONEncode(games))
	end)
	if not success then
		warn("Failed to save games data: " .. err)
	end
end
1 Like