Data Storage
From GMod Wiki
Flood this page with links, tutorials, wiki pages and overall categories regarding how to save and load things!
This page has been deemed a mess. It may contain unnecessary information or be poorly organized. You can discuss changes on this article's talk page. |
Contents |
File based storage
Using text files to store data is a simple and effective way of storing data. You are free in your implementation, but this article aims to give some suggestions on how to store data. You use the standard file library, on both the server and client, to read and write files and then use string operations to write or extract the data you want.
A benefit of using this method is you have absolute freedom and it doesn't require any extra libraries.
Delimiter-seperated values
The most common and simplest method to load text files is to 'explode' the string. Exploding a string means you split a string up in chunks by a delimiter. In Lua the function to do this is string.explode and a table is returned.
Example
Let's assume we want to store everyone who has ever been to our server. We want to keep track of player names, steam id and their total playing time.
In the following example, ';' is the delimiter between values and a new row is indicated by a new line. This means that each player is on its own line. The data is formatted like so where total playing time is in seconds:
Steam ID;Player name;Total playing time Steam ID;Player name;Total playing time Steam ID;Player name;Total playing time
and with some values filled:
STEAM_0:1:14884029;Manadar;60 STEAM_0:0:11956651;Overv;240
Put this file into garrysmod\data\playerdata.txt
Now let's try to read the values from our file in Lua.
print("\n\n\nReading playerdata.txt ...") textdata = file.Read("playerdata.txt") print("playerdata.txt is read. Data: \n" .. textdata) print("") print("Seperating lines ...") lines = string.Explode("\n", textdata) print("Lines split. The lines are:") PrintTable( lines ) // Now let's loop through all the lines so we can split those too for i, line in ipairs(lines) do // line is the current line, and i is the current line number data = string.Explode(";", line) playersteam = data[1] playername = data[2] playertotaltime = data[3] print(playername .. " (" .. playersteam .. ") has played on this server " .. playertotaltime .. " seconds") end print("\n\n")
Output:
Reading playerdata.txt ... playerdata.txt is read. Data: STEAM_0:1:14884029;Manadar;60 STEAM_0:0:11956651;Overv;240 Seperating lines ... Lines split. The lines are: 1 = STEAM_0:1:14884029;Manadar;60 2 = STEAM_0:0:11956651;Overv;240 Parsing player data ... Manadar (STEAM_0:1:14884029) has played on this server 60 seconds Overv (STEAM_0:0:11956651) has played on this server 240 seconds
As you can see. We've successfully split each succeeding line and put the data in separate variables, ready to be passed to another function or whatever you want to do with it.
Putting the data in a text file is a lot easier. You make a new table and put your values in and then use the string.Implode function. Like so:
function file.AppendLine(filename, addme) data = file.Read(filename) if ( data ) then file.Write(filename, data .. "\n" .. tostring(addme)) else file.Write(filename, tostring(addme)) end end print("Getting local player data ...") ply = LocalPlayer() print(ply) values = { ply:GetName(), ply:GetName(), 0 } // create a new table with our required values print("Building data string ... ") data = string.Implode(";", values) print("Data string: " .. data) file.AppendLine("playerdata.txt", data)
Output:
Getting local player data ... Player [1][Manadar] Building data string ... Data string: STEAM_0:1:14884029;Manadar;0
and our playerdata.txt now contains:
STEAM_0:1:14884029;Manadar;60 STEAM_0:0:11956651;Overv;240 STEAM_0:1:14884029;Manadar;0
Great success!
Note: Alternatively, if you want to store A LOT of data about you can choose to store the data of one player, one row in our example, in a separate file. This way you won't have to split each line or have to rewrite the entire file every time you make a change resulting in a performance boost.
TODO (Deco Da Man): Fill this in with links
Disadvantages
This implementation relies on its data not having a ; in the values. If someone joined our server with a name HiThar;;lol our example would fail horribly because one row now contains 5 values instead of the expected 3. To overcome this problem, see this serialization chapter just below this one.
Serialization
The example above only works for simple data types, but if you try to store things such as tables in tables or vectors you'll run into problems quickly. That is why there is serialization. Serialization is turning any object or variable into a sequence of bits so that it can be restored to its previous state. After the serialization we can store the bits into a file and read from the file to restore it. In Gmod the recommended method to serialize your variables is using GLON. GLON provides you with a complete layer of abstraction so you can store and restore any variables of any Gmod type you desire.
TODO (Deco Da Man): Fill this in with an example (like the above ones)
Note: Util.TableToKeyValues and Util.KeyValuesToTable are deprecated. Use GLON instead.
Relational database
Relational databases is what modern applications use to store their data. There are a great deal of benefits for using relational database, but the learning curve is much more steep than with using file based storage.
There are a number of database storage options for GMod. There is the SQLite module, built into GMod If SQLite does not suit your needs because you want to use a SQL server, you can use one of the (My)SQL modules available.
SQL
All of the relational databases listed below use SQL as their data definition language and data manipulation language. There are some minor changes between the different instances but using a quick reference guide those are easy to solve.
TODO (Deco Da Man): Fill this in with an example (like the above ones)
One of the most difficult things to learn here is to design a good database. You want to use primary keys and foreign keys where they are required, or you'll find yourself writing more queries than is necessary.
TODO (Deco Da Man): Fill this in with links
SQLite
Garry's Mod comes with a built-in SQLite library. You can use it both from server and client, and saves to the cl.db and sv.db files (I bet you can't guess which one is which!). SQLite is a small but powerful database and is often compatible with MySQL. The SQLite interface is available via the built-in sql library.
TODO (Deco Da Man): Fill this in with an example (like the above ones)
There are many tutorials for SQLite, and uncountable numbers of tutorials for SQL to be found on the internet. For SQL tutorials, see this great resource: Here are a few: General tutorials for SQL: http://www.w3schools.com/sql/default.asp Documentation for SQLite: http://www.sqlite.org/docs.html Language Specifications for SQLite: http://theopensourcery.com/sqlitedocs.htm
MySQL
Coming soon
TCP and UDP Connections
TCP or UDP connections can be used to communicate directly with another application or server. More detail will follow. Coming soon