Moving to Backend Coding Systems

WooleyWool
Developer Baseplate
7 min readNov 16, 2021

When first creating my game, RoMurder Mystery, I set it up to revolve around instances (objects such as parts, models, boolvalues, etc.) and StringValues. These were mainly used to identify player roles — whether they are the Murderer, Sheriff, or Innocent. My first attempt at creating a player role system incorporated object values (StringValues, IntValues, and BoolValues) and it worked! As far as I could tell, there were no issues with how it functioned… but then I realized that anyone could see those values since they were parented to the player. Meaning, if someone with malicious intent joined the game, they could expose the roles of each player and ruin the mystery, a core mechanic of the game.

This situation is also known as the misuse of instances, that is, instances that are being misused by the developer. Misused instances are instances (typically object values) that are exposed, rather than being hidden from everyone.

In many cases, you may want to show a value — for instance, having a value that identifies if a plot of land is available is not a case of a misused instance. However, in my case, having secret player roles being seen by everyone is a misuse of instances because a murder mystery game revolves around those values remaining hidden. Because of this, I needed to dive deeper into backend programming to build a system where data is created on the server, stays on the server, and only reveals specific data to the player… not to everyone. For instance, determining the roles of each player on the server, storing that data in a dictionary (a table that allows you to set values, more on this below), and sharing information that pertains to the player, in my case, their role.

Backend programming is a necessity for all programmers to learn as it allows you to have full control over your game — from the player who is interacting with the game (frontend) to the server that is running everything (backend). But first, you will need to determine how you want your game to function. Please keep in mind, if you’re just starting out on Roblox Studio, focus on learning and understanding Lua and don’t worry as much about backend data. Backend programming allows you to store values on the server and read from those values to which your code will decide what to do next.

For instance, let’s say that the player wants to buy an apple, and the apple costs 10 dollars (expensive apple, I know). Looking at this from a programming perspective on the backend, first, you’ll want to check: Does the player have 10 dollars or more? And also, can the player buy this? You need to set up a system that confirms the player can buy the apple, deducts the cost, and adds it to their inventory. If you just stick to, “Can the player buy this?” it is likely going to cause oversights in your code and it will need additional checks.

Once you determine if they can buy the apple, then take care on the backend of how much money is lost from the purchase and add that they own the apple. From there, on the frontend, share that they have bought the apple, it’s in their inventory, and here’s their dollar amount leftover. This is an example of frontend vs. backend coding. In the backend, the server determines if everything is true and shares to the player (frontend) the resulting data. If you manage everything on the frontend, the player could manipulate the system into a state where they can buy the apple, when they can’t in reality.

I’m going to show you a code comparison of backend data and instance-based data. What this code is doing is creating a “Cash” value, but there are two different ways of doing so:

Backend Data Setup:

--Backend Data Setup

local Players = game:GetService("Players")

local PlayerData = {}

Players.PlayerAdded:Connect(function(player)
local PlayerJoinedTable = PlayerData[player.Name] or {};
PlayerData[player.Name] = PlayerJoinedData --Creates a new table (for the player's data) within the PlayerData table

PlayerJoinedTable["Cash"] = 0
end)

Instance-based Data Setup:

-- Instance based Data Setup

local Players = game:GetService("Players")

Players.PlayerAdded:Connect(function(player)
local CashIntValue = Instance.new("IntValue")
CashIntValue.Name = "CashIntValue"
CashIntValue.Value = 0
CashIntValue.Parent = player -- Creating the Cash value for the player using IntValue
end)

Let’s compare the two code blocks. Both of these coding blocks are creating a system to store and create a “Cash” value.

The backend data setup creates a dictionary of the player’s data and allows us to add in different things to store in that dictionary (like currency). In our case, we are creating the “Cash” currency value and setting it to 0. The instance-based code creates an instance, an IntValue, naming it to “CashIntValue” and setting the value to 0. Then, parenting it to the player.

These two code blocks do the same thing, however, the backend system is a lot more efficient because you can store a lot more data in the dictionary compared to instances where you have to create several different instances for the different values you want to create. Instance code can get very long depending on the amount of data you want to have for the player. In my case, when I used to use instances, it took up a minimum of 50 lines whereas using dictionaries for data took only 10 lines.

Let’s see what the code would look like if I were wanting to buy an apple. For this example, the player has 15 dollars to spend on apples which cost 10 each. Remote function is fired from the client to purchase the item:

Backend purchase:

-- Backend Shop

local ReplicatedStorage = game:GetService("ReplicatedStorage")

local ShopOptions = {
Apples = 10
}

ReplicatedStorage.BuyItem.OnServerInvoke = function(player, ItemName)
local CustomerData = PlayerData[player.Name]

if CustomerData["Cash"] >= ShopOptions[ItemName] then
CustomerData["Cash"] -= ShopOptions[ItemName] -- Player will have 5 dollars left
end
end

Instance-based purchase:
(Assume that there is an IntValue in ReplicatedStorage for shop items)

-- Instance based shop

local ReplicatedStorage = game:GetService("ReplicatedStorage")

ReplicatedStorage.BuyItem.OnServerInvoke = function(player, ItemName)
local ItemData = ReplicatedStorage:FindFirstChild(ItemName)
local PlayerCash = player.CashIntValue

if PlayerCash.Value >= ItemData.Value then
PlayerCash.Value -= ItemData.Value -- Player will have 5 dollars left
end
end

You may notice that at the end of the day, these two code blocks accomplish the exact same thing, but look completely different.

The backend code has a dictionary, ShopOptions, with all the costs for each item in the shop. We first check to see if the player has greater or equal to the shop item’s price, if we do, we then make the purchase and subtract the item’s price from the player’s cash.

The instance-based code looks for the Apple IntValue in ReplicatedStorage, then checks to see if the player has greater or equal to the shop item’s price. If we do, we then make the purchase and subtract the item’s price from the player’s cash IntValue. We had to do extra steps in the instance-based coding because we needed to find the Apples IntValue, whereas with the use of a dictionary, we can just plug the ItemName into the ShopOptions dictionary and get the value quickly.

The question you have in mind is what’s the difference between these two different methods if they end up having the same result? Backend coding is a lot cleaner, it’s a lot easier to identify errors (if there were to be any). For instance, an error stating that you have an error at line x because you forgot a comma or the value is nil and because of the shorter amount of lines, it’ll be a lot easier to fix. More importantly, it’ll be only you seeing these values, no one else can see nor request for the information (unless you write the code to do so).

Dictionaries are widely used in other coding languages as well (Python, C++, SQL, etc.). Learning how to use this kind of system will give you a jumpstart when you begin to code using these large systems. I do want to note that there are some cases where you may need to use instances, but remember: misusing them can be problematic because it may degrade the experience of the game you’ve designed if someone knows something they aren’t supposed to know.

Engines, like Roblox Studio, allow you to bring game ideas to life by programming specific functions, such as having objects to behave a certain way. Bringing an idea to life does not always mean doing it in the most efficient way possible. I find that with each new thing I learn I look back at old projects and discover new, more efficient ways to accomplish what I initially set out to create.

Hello! I’m WooleyWool, a Roblox Community Event Organizer and programmer. Turning game ideas into a reality, one line at a time.

I learned a lot of my initial foundation of programming knowledge from Roblox University and top programmers on YouTube. Recently, I’ve taken on the quest of creating my own game! RoMurder Mystery is my own take on a murder mystery-style game — creating it has taught me so much more about programming on Roblox than what I knew when I first started.

Keep up with me on Twitter

Join the millions of creators on Roblox and make your first experience with help from this page on getting started.

--

--

WooleyWool
Developer Baseplate

Hello! I’m a programmer, game creator, and Roblox Community Events Organizer.