Storing Values in the Player: Good or Bad?

Whenever I’ve needed to store values (Ints, Strings, Numbers) that would need to be accessed by different scripts, I’ve always stored them in the Player because it’s easy to access from anywhere.
But I realize that this isn’t necessarily the most secure place to store values.
Storing them in ServerStorage and using RemoteEvents/Functions to access/change them is more secure…but it takes more work to do it.

I’m curious to hear your thoughts. Do you store values in the player? Have you previous and switched to storing them elsewhere? Where do you store values and why?

8 Likes

Hey there.

The way I’d approach storing values/data is by putting them in SS and making RE, but like you said that takes more work. Another approach would be to create a Server Script that does an

Instance.New("IntValue") -- or what ever value

and then just parent that to the player, that way it is kind of secure and you’re not directly putting it into the player your making it kind of “secure” but it wont be as secure.

But to answer your question, it’s bad storing them in the player yes.

4 Likes

I don’t think there is a one-size-fits-all solution to where to store values because it depends on what scripts need the values and the principle of least privilege.

  • If many server scripts need the values, _G / shared is a decent place for them. If they must be manipulated in some way they can be in one module script and the getters/setters can be in _G / shared.

  • If a few server scripts need them, then you can put them in a module script and require it in the needed scripts. It isn’t much better than the above, but it avoids cluttering the global table.

  • If local scripts in all players require the value, then putting it in a values folder in workspace would be fine.

  • If there are a lot of values or some values were player-specific then you could make a module in replicated storage that handles keeping the values in sync between the server / client and exposes a simple table with the current values. I like this method because it gives a lot of control while hiding all of the complicated details from other scripts.

  • In more complicated frameworks like Roact / ECS / OOP or in systems with lots of changes that don’t need to be kept up to date, keeping values in sync may need to be on a by value basis. I’d only expect 1 remote function to get updated values and 1 remote event to receive server updates, and an API components / systems / objects use to get these values.

7 Likes

For me, I keep Integer values in the player, while string values in ServerStorage. In my game, the integer value is their cash in the game, while the string value (names of the items owned) are in ServerStorage. So, I am unsure what’s best. However as @Hikoutai said it’s safer with the: IntValue made with the Instance.New.

Cash = Instance.New("IntValue")
Cash.Parent = Player
1 Like

My oppinion on this is, don’t store them anywhere but inside a server script (or local script if you need to have it locally) making instances out of values to access them is quite insecure to do. using remote events/functions (or bindable events/functions) properly is more secure for your game.

Important Values

lets take data from a database as example. you do not want to store that anywhere the client can access (for the safety of your datafolder structure and exploits) so if you do decide to instanciate them, put them in serverStorage and use remote events/functions to access them via localscript -> script -> localscript.
however i do faily reccomend you to not instanciate those kind of values as it will be a hustle to turn it back into a table. just keep it in the script and use OOP1

1 Object Orientated Programming

Less important values

even if its less important and only accessed by local scripts (especially if its only by local scripts) still don’t instanciate values. exploits can change these values and your local scripts will be rigged and less secure. if you do decide to still use instanciated values let a server script check them and keep them as they should be (exploit changes aren’t visible for server side that’s why)

story short. it’s better to keep all your important values in the ServerStorage (if you do need it to be instanciated) otherwise keep it in the script and still use remotes for both of these. they are more reliable than exposing the values in their state to the client (able to adjust them via exploits). don’t trust the client :wink:

4 Likes

Storing the values in the player is perfectly fine.

All you need to do is change/and check those values from the server to be completely safe! :slight_smile:

5 Likes

I would recommend against storing values in the player. I would actually argue that this is less accessible and could pose problems for you. For example, unless you have a strong reference to those data objects, they’ll get garbage collected along with the Player object when they disconnect. If you fail to get rid of that reference as well, you could experience a memory leak.

I personally, if I need to use ValueObjects, would store them in ServerStorage or ReplicatedStorage depending on what it is that the ValueObject needs to be used for. Recently though, I’ve become more fond of using ModuleScripts to store that kind of information. I like ValueObjects but I don’t want to get hammered for practice-related issues again. :triumph:

3 Likes

How I Manage Storing Values


Overview
As you can see, the game uses a client-server model, which filters what an exploiter can do on their machine in order to affect the server. I would never store those physical value objects somewhere, as tables can be the replacement for that.

The only way I want the information from the table sent to the client is when the visuals need to be adjusted or updated.

Current Set-up
For my set-up, I create a table called sessionData which uses keys of the player.UserId. Then attach some pre-made data under that key, which is also another table. This table will contain the values such as:

  • In-game Currency
  • Game Progress
  • Inventory

Simply create functions for sessionData to be handled.

How To Retrieve Values From Client?
Simply use a RemoteFunction, if the signal is coming from the client, which requests for an update of some visuals. RemoteFunction’s hooked function needs a return (your values here) to pass it to the client. Then the client script(also LocalScript) can update something using the value read from it.

Beware that when you want to set values from client to server, make sure you have sanity checks around the passed values. Never-trust-the-client is a great practice against exploiters, who intend to cheat the game by adding up values in their stats.

If the server is the input. Use a RemoteEvent, pass the value in the tuple argument when using RemoteEvent:FireClient(). First argument always player.

Values In Player?
Highly against it. Not the best practice out there. Storing it somewhere else would be better, or else it’ll have problems as mentioned in the post above.

Summary
I would not store the values in the player object, I’d preferably store them in a table where I can later on erase when the player leaves without any technical issues.

The advantage of storing them in a table:

  • More writing
  • Less hierarchy focus around the Explorer
  • Technically secure

…but also…

  • Easier organisation
  • Easier to write values to – if done correctly

Of course, all of this is managed through a hierarchy of ModuleScripts. Around this is DataStoreService and the DataStore, it skips the step of writing all values from the objects into a table to save it.

14 Likes

Same discussion here, you might find answers there!

1 Like

If I use a ModuleScript to hold all my stats…Should all of my datastores and everything be in that same ModuleScript, or should I have a separate ModuleScript for the datastores and have it save the data in the other Module?

Hopefully that makes sense…

Keep it all in a single ModuleScript. This makes it more readable and maintainable. There shouldn’t be much reason to split this work into two modules - that’s depending on your structure.

2 Likes

Should I keep it in ServerScriptService or ReplicatedStorage?

ServerScriptService. You can add RemoteFunctions to ReplicatedStorage to allow for the client to request for data. The ModuleScript will handle what to do when the client invokes those remotes.

2 Likes

So ReplicatedStorage will hold the “MiddleMan” script to say “Hey, we need some data”?

1 Like

Essentially. An example structure would look something like this:

  • ServerScriptService.DataModule: Main location where data is handled. Can also be a regular script, but probably more preferable to have it as a ModuleScript to allow for things such as exposing methods for other scripts to use to modify data. If a ModuleScript, should be eagerly loaded.

  • ReplicatedStorage.Remotes: Main location for remotes. There may be a RemoteFunction called “RetrieveData”, which the client would call InvokeServer on. The data module would have defined a function to OnServerInvoke which fetches the player’s data and returns it to them.

  • Somewhere.LocalScript: Something related to the client that needs data.

In other cases, you can also use RemoteEvents and have the server use FireClient on a remote to tell a client what data they have or if their data updated. It all depends on the structure or approach you take. Experimentation is a good thing - try out some structures.

11 Likes

So I have a script in ReplicatedStorage that handles the RemoteFunctions…But when I attempt to InvokeServer, doesn’t work at all. No errors. So the RemoteFunction is never returning a value. But when I move the Script into ServerScriptService…It works fine. What am I doing wrong here?

Code doesn’t run in ReplicatedStorage. An exception is ModuleScripts, though they only run code upon being required regardless of where they are placed.

Oooh. I misunderstood. I thought I was placing a script in ReplicatedStorage and the RemoteEvents. Should the script be placed in ServerScriptService?

Yes. If it’s a script, it should be in ServerScriptService. Modules should also go here as well if the client does not need access to them.

2 Likes

Can I store the data in the player but all ways have the server check it