Access table/variable from any script?

Hello! I am starting work on a new project and wondering if this is possible. What I’m doing is I have a global table where the players ID is used as a key and then that key is attached to a sub table with stats related to that player key. Just like this below:
Screenshot_20
This is fine but I want to be able to access the global table and subsequent player key from any script so I can do whatever I please with it
For example, this is the block that creates the stats table and assigns it to the player key in the global table:

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

local globalStats = {} --Stats of all players currently in the game.

PLRS.PlayerAdded:Connect(function(plr) --When a player gets added, create a stats table for them.
	
	local statsTable = { --Default stats table.
		
		["Health"] = 100,
		["Skill Points"] = 100,
		
	}
	
	globalStats[plr.UserId] = statsTable --Adds the players stats table to the global dictionary like: ["PlayerID"] = (Their stats table)
	
	print(globalStats)
	
end)

and I would want to be able to pull it into a separate script that contains something like this:

local RS = game:GetService("ReplicatedStorage")

RS.HealEvent.OnServerEvent:Connect(function(plr)

	globalStats[plr.UserId]["Health"] += 20 --Finds the players stats using their ID as the key from the global stats and changes it
	print(plr.UserId.. " Changed their health!")	

	print(globalStats[plr.UserId]["Health"]) --New health value
end)

How would I go about that?

1 Like

I believe DataStore can help with storing Player Data. This way, you wouldn’t need to have a GlobalStats Table in a single Script.

DataStore will let you use that player’s data too in any script you make, you’d simple just have to give your player’s Data a stand-alone Key and you would call it every time you need to add/fix/do something in a player’s data.

local dataStore = game:GetService("DataStoreService")
local globalStats_Key = "Key_Here" -- I believe this is where you'll place your Global Stats Data Key

You can also create ModuleScript in ReplicatedStorage for the Data, this way you’d easily call and even set up your own System easily.

ModuleScript is a game changer, and it’ll help you with this kind of set-up you need.

-- Example
-- ModuleScript

local dataStore = game:GetService("DataStoreService")
local dataStore_Key = "Key_Here"
local dataStore_ODS = dataStore:GetOrderedDataStore(dataStore_Key) -- This is where you'll access your Data Key every time.

local module = {}

-- Example
local function getData(player: player) -- this grabs your User's Data
	local data = dataStore_ODS:GetAsyn(player.UserId)
	print(data)
end

return module

of course, if you want to actually call it in another script, here’s an Example for it:

-- ServerScript
local replicatedStorage = game:GetService("ReplicatedStorage")
local globalDataStats = require(replicatedStorage.LOCATION_OF_YOUR_MODULESCRIPT) -- This will grab all functions in your module, this way you'll be able to use it in any scripts you want.

-- Calling it would look like this: (Example)
game:GetService("Players").PlayerAdded:Connect(Function(player: player)
	globalDataStats.getData(player) -- This will print your Player's Data
end)

-- This code, every time a player joins, will print their Data out.
1 Like

Summary

If you want to share data across scripts on the same network side (between same-client scripts or same server-scripts, but not between client and server), would could use SharedTables or the traditional globally shared table known as _G.

Method 1 | Attributes - (Hacky)

If you want to share a table between the client and the server, I believe you’ll have to create your own system to support that, one where the server is the dominant owner of said shared table. The easiest way I can think of is to use Attributes to store a JSON version of a table as a string attribute. But that could be read by any client unless you have the server clone into the specific player’s PlayerGui.

Method 2 | Remotes (Better?)

But the above option is a bit hacky and also has limitations as Roblox’s Encoder/Decoder for JSON doesn’t natively support custom value types that are unique to Roblox, for some reason. So the better option is just to have a table server-side and send it over a remote to the client. Both the client and server would have to send remotes to each other whenever one wants to make a change, or just the server if you want the client to be read-only.

Note

The only issue regarding either of these methods is that you can’t make nested references as the entire table would be replaced, unless you have some system that updates the existing one with the changes. It really depends what you actually want out of this and how much effort you’re willing to put into it to make it happen. It might even be a good idea to create a module of this system if you plan on reusing it in other projects.

1 Like

I kind of used something like this by creating a string value in a folder in ServerStorage named the players ID with the table as a JSON string within it. I can access it and change it from any other script. When they leave the game, that is saved to the actual datastore then the string value in ServerStorage is removed.

From there, you can also add attributes to it, making it a one-file, hold-all for player stats and gear.

Hey! So I believe I have the general idea of how to put a dictionary into a data store now, but I don’t know exactly how to access a specific piece of that dictionary from there so I can change the value. I may be overthinking it but this is what my current data store looks like:

local DSS = game:GetService("DataStoreService")
local globalStats_DS = DSS:GetDataStore("GlobalStats")

local dataModule = {}

function dataModule.getData(plr)
	
	local success, currentStats = pcall(function()
		
		local data = globalStats_DS:GetAsync(plr.UserId)

		if data then
			print("Data found for ID: "..plr.UserId)
			print(data)
				
		else
			print("No data found for ID: "..plr.UserId)
			local statsTable = {

				["Health"] = 100,
				["Skill Points"] = 100,
				
			}
			
			local success, errorMsg = pcall(function()
				globalStats_DS:SetAsync(plr.UserId, statsTable)	
			end)
			if success then
				print(statsTable)
			end
			
		end
	end)
end
return dataModule

I believe this is alright, but lets say (for the sake of example) I want to be able to press a button that gives the player 20 health.

local DSS = game:GetService("DataStoreService")
local RS = game:GetService("ReplicatedStorage")
local PLRS = game:GetService("Players")

local globalDataStats = require(RS:WaitForChild("PlayerData"))

PLRS.PlayerAdded:Connect(function(plr)
	
	globalDataStats.getData(plr)
	
end)

RS.HealEvent.OnServerEvent:Connect(function(plr)
	
	--I want to increment that health by 20 now. How would I access that part of the players dictionary specifically?
	
end)

What exactly would I do here? I know I have the players ID so that I can access their specified part of the data store but don’t understand exactly how to do it.

Ideally, you load the player’s data when they join, and keep that on the server. From your heal event function you’d change the value in the table. When the player leaves the game, you use SetAsync to update their data to the new table.

as what @Voidage said, you would use setAsync to set that Player’s Data. If you want it to only change when they leave, you can also use the PlayerRemoving and you’d use SetAsync from there.

preferably keep the SetAsync inside the ModuleScript too so you can Save Data from any Scripts you’d use the Module.

-- Exmaple
game:GetService("Players").PlayerRemoving:Connect(function(player)
   -- get you Player's current Data inside the game

 dataModule.PlayerLeft(player, data)
end)

-- on the Module
function dataModule.PlayerLeft(player, data)
 local setData = YOUR_DATASTORE_KEY_HERE:setAsync(player, data) -- I forgot if its the opposite way with the player & data
end

but generally, this is the way to save it. Though if you want to add Health to the person who’s playing Currently, as what I did with my previous games: I made a stand-alone Folder inside ReplicatedStorage that creates their current Data with StringValue, NumberValue, etc.

Whenever something happens in-game, the scripts will just keep adding value to their data. Until they leave, which will save it and on their next play, their previous Data will load.

(sorry if I’m explaining so bad rn, Its 6AM I’m also coding and my brain is having a meltdown)

This also applies to what you want to do. You can simply use LocalScript if you want it GUI based, or you can also do a different way which is using the Chat for adding specific Data’s (which is quite complicated)

though… if you we’re to create a stand-alone folder that consists of every player’s data, there are risks that they’ll exploit it. (Had an experience with this one and got to say, I had to reset the entire leaderboard for it)

That’s what I’m asking. How do I change the value in that table? It doesn’t seem like it’s as simple as doing what I was trying previously:

globalStats[plr.UserId]["Health"] += 20

In your data module you’ll need to create a table that contains all currently loaded data tables for players in your game. Then any other script could require this module, access this table, and change the values.

As for actually changing it, I’m a bit confused. You just set the variable like any other variable.

Example:

local myTable = {};
myTable[player.UserId] = {Health = 100};
myTable[player.UserId].Health = 200;

I got it all sorted! Just needed to access the variable manually from the module script. My brain was a little fried from learning data stores for the first time but I believe this is the correct way to do it!

local DSS = game:GetService("DataStoreService")
local globalStats_DS = DSS:GetDataStore("GlobalStats")

local dataModule = {}

dataModule.globalPlayerStats = {}

function dataModule.getData(plr)
	
	local success, currentStats = pcall(function()
		
		local data = globalStats_DS:GetAsync(plr.UserId)

		if data then
			print("Data found for ID: "..plr.UserId)
			dataModule.globalPlayerStats[plr.UserId] = data
			print(dataModule.globalPlayerStats)
				
		else
			print("No data found for ID: "..plr.UserId)
			local newData = {

				["Health"] = 100,
				["Skill Points"] = 100,
				
			}
			
			dataModule.globalPlayerStats[plr.UserId] = newData
			
			local success, errorMsg = pcall(function()
				globalStats_DS:SetAsync(plr.UserId, newData)	
			end)
			if success then
				print(" for ID: "..plr.UserId)
				print(newData)
			end
			
		end
	end)
end

function dataModule.saveData(plr)
	
	local success, errorMsg = pcall(function()
		globalStats_DS:SetAsync(plr.UserId, dataModule.globalPlayerStats[plr.UserId])
	end)
	if success then
		print("Data saved for ID: "..plr.UserId)
	end
	
end

return dataModule
local DSS = game:GetService("DataStoreService")
local RS = game:GetService("ReplicatedStorage")
local PLRS = game:GetService("Players")

local dataModule = require(RS:WaitForChild("PlayerData"))
local playerData = dataModule.globalPlayerStats

PLRS.PlayerAdded:Connect(function(plr)
	
	dataModule.getData(plr)
	
end)

PLRS.PlayerRemoving:Connect(function(plr)
	
	dataModule.saveData(plr)
	
end)

RS.HealEvent.OnServerEvent:Connect(function(plr)
	
	playerData[plr.UserId]["Health"] += 20 --Changes value of health in specified players dictionary.
	print(playerData[plr.UserId]["Health"])
	
end)
1 Like

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.