File Based Storage
Introduction
Data Storage is what we use when we want data to persist through map changes and server restarts.
There are multiple ways of storing data in Garry's Mod. In this tutorial, we will go over File Based Storage.
Rules with data-handling
When handling any data, there are some rules that we should follow:
Never trust data that has been handled by a client. Keep all data backed up on the server as this is the only way that you can be sure that the data is authentic. Let's say we started letting clients keep track of their money; what's stopping them from adding a few zeros on the end?
Always use identification that the client can't manipulate. If we wanted to store a client's health when they log off, and we used their steam names as identification, what's stopping them from changing it before they next log on? Nothing. This is why we must use identification such as Player:SteamID's, since they can never be changed by the client.
In case you couldn't tell, there is an over-arching theme here: Never trust the client.
Unfortunately, Garry's mod servers aren't predictable - they can easily crash without warning or become overloaded. Therefore, you should deal with the data as quickly as possible to avoid losing it. Do not wait until the player leaves to save the number of tokens that they have earned whilst playing, as the server may suffer a fatal crash before then. Furthermore, you should not save data during the GM:ShutDown hook, as it may be too late to start saving data as some players will become invalid which means that their precious token count is now lost. However, you may be reading this and you think that your data should be saved at the very last minute, or is really not important enough to be saved every time it is altered - in which case, you can use the GM:ShutDown hook at your own risk!
About
Text files are a simple way of storing data. File Based Storage does not require any external modules, as it relies solely on the file library and is pretty straightforward. For these reasons, it is the recommended method for beginners.
Storing tables - util.TableToJSON
This is, perhaps, the easiest method for beginners that will circumvent frustration when converting data types such as Color or Vector, so we will start with this method first.
Turning tables into strings
A text file is basically a string of characters. This means that we need to convert all of our data into a string of characters...
util.TableToJSON is a function that will turn a Lua table into the JSON format. JSON is a popular format of representing certain data (such as Lua tables) as text, which can be saved in a file and turned back into the same data later.
Here is an example of how we can use util.TableToJSON:
Output:
Notice how the Color, Angle and Vector structures get converted into distinguishable string structures? These unique formats allows the reversing function util.JSONToTable to convert the formats back into their original data structures.
Let's write some further code so that we can see reversal process that will need to take place when reading the file.
Output:
As you can see, the JSON string has been converted back into a table format. Furthermore, we can check that the data types have been returned to their original format by using isvector with converted.pos
and isangle with converted.rot
which tell us that they have been converted back into a Vector and Angle. Unfortunately, passing converted.col
into IsColor highlights that it has not been correctly converted into the Color structure. Fortunately, we can write some code to convert it back to normal later on.
Saving JSON data
Now we've learnt how to convert a table into a storable format, and also how to reverse the stored format into a normal Lua table - we can now learn how to read/write files and save the JSON data.
Believe it or not, saving data to a file only requires one function: file.Write. Upon looking at the documentation we learn that it only needs two things:
- A filename
- Data to save
So let's go ahead and and write some code to finish saving the storeOwnerData table into a file called
storedata.json
:
That's it, that's the file saved!
If you want to view the file for your own eyes, you can go into the garrysmod/data
folder and the file will be called "storedata.json".
Reading JSON data from files, and converting it back to a table
Reading JSON data is just as easy with the key function now being file.Read that takes one argument... the Filename. Here we will also convert the table containing color data into a Color structure too:
The variable storeOwnerData
now contains all of the data and the col
value is now a Color!
Writing data types other than tables
The above method is excellent for storing tables, but what if we just want to store a number or a string?
Nothing is particularly different in this scenario, we just don't need the util functions anymore:
Saving the string
Loading the string
Not that difficult at all, is it?
Alternatives to file based storage
Let's say that we needed to keep track of a player's money count. Then, we would need to save to the file every time the player either leaves or has their money count updated, and thus, a 1,000 line file (or even more!) will need to be read, altered, and then completely overwritten with new data. This is slow, and it will get much slower the more players have their data stored in a file.
Therefore, we need an alternative.
Perhaps the most efficient method of storing large amounts of data in Garry's mod is through SQL. Unfortunately, SQL is not as easy to learn as file based storage, however, it is completely worth it if you do decide to learn.