Game Frameworks  
Lecture 08: RESTful Web Services and HTTP  
Communication in Unity  
Edirlei Soares de Lima  
<edirlei.lima@universidadeeuropeia.pt>  
What is a REST Web Service?  
A Web Service is a software system identified by a URI/URL,  
whose public interfaces and bindings are defined and  
described using XML (or JSON).  
It is designed to support interoperable machine-to-machine  
interaction over a network (HTTP or HTTPS).  
REST (Representational State Transfer) is an architectural style  
for creating web services.  
The underlying protocol for REST is HTTP, which is the basic web  
protocol.  
REST web services are lightweight, maintainable, and scalable.  
REST Web Services  
REST Web Services allow the requesting systems to access and  
manipulate textual representations of web resources by using  
a uniform and predefined set of stateless operations.  
A resource is identified by a URI/URL;  
A request returns a document with a representation of the requested  
resource;  
Each request contains all the information needed to be processed  
(stateless operations).  
All resources are accessed by a well-known set of HTTP operations:  
POST, GET, PUT, DELETE.  
Information transmitted in the requests and answers is encoded as  
XML or JSON.  
XML vs. JSON  
XML:  
<players>  
<player>  
<
<
name>John</name>  
score>100</score>  
<
<
/player>  
player>  
<
<
name>Anna</name>  
score>200</score>  
</player>  
</players>  
JSON:  
{"players":[  
{
{
"name":"John", "score":"100"},  
"name":"Anna", "score":"200"}  
]}  
REST Web Services Key Elements  
Resources:  
Considering a REST web service that has records of several players’  
scores. We can access the score of a player (resource) via a URL:  
http://example.com/player/1, where 1 would be the ID of a player.  
Request Verbs:  
Describe what the client want to do with the resource. For example, a  
GET verb is used to get data. Other verbs: POST, PUT, and DELETE.  
Request Headers:  
Additional instructions sent with a request. These might define the type  
of response required or the authorization details.  
REST Web Services Key Elements  
Request Body:  
Is the data that is sent with the request to the REST web service.  
Response Body:  
Is the data that comes from the REST web service as response of  
request.  
Response Status:  
Are general codes that are returned along with the response from the  
web server. For example, 404 indicates that the resource was not found.  
REST Architectural Characteristics  
Distributed resources:  
Every resource should be accessible via the normal HTTP commands of  
GET, POST, PUT, or DELETE.  
Client/Server:  
The client send requests to the web service (server). The server either  
reject the requests or comply and provide an adequate response to  
the client.  
Stateless:  
The server should not maintain any sort of information between  
requests from clients.  
REST Architectural Characteristics  
Layered:  
Any additional layer can be inserted between the client and the actual  
server hosting the REST web service.  
Supports Caching:  
Since each server client request is independent in nature, sometimes  
the client might ask the server for the same request again.  
The cache is implemented on the client. If the same request is  
necessary, instead of going to the server, the client go to the cache and  
get the required information.  
REST Web Service in Unity  
REST Web Service in Node.js  
Requirements:  
Linux (local virtual machine or a cloud virtual machine)  
Cloud option: DigitalOcean (https://www.digitalocean.com/)  
Virtual machine: https://www.virtualbox.org/  
MySQL  
Node.js  
Setup:  
sudo apt update  
sudo apt install mysql-server  
sudo mysql_secure_installation  
curl -sL https://deb.nodesource.com/setup_14.x -o nodesource_setup.sh  
sudo bash nodesource_setup.sh  
sudo apt install nodejs  
npm install mysql --save  
npm install express --save  
npm install cors body-parser --save  
REST Web Service in Node.js  
MySQL User and Database Creation:  
CREATE DATABASE nodejs_db;  
CREATE USER 'nodeuser'@'localhost' IDENTIFIED BY 'yourpassword’;  
GRANT ALL ON nodejs_db.* TO 'nodeuser'@'localhost’;  
ALTER USER 'nodeuser'@'localhost' IDENTIFIED WITH  
mysql_native_password BY 'yourpassword’;  
USE nodejs_db;  
CREATE TABLE players(  
id INT AUTO_INCREMENT PRIMARY KEY,  
username VARCHAR(40),  
password VARCHAR(40),  
score INT  
)
;
REST Web Service in Node.js  
index.js:  
var http = require('http');  
var mysql = require('mysql');  
var express = require('express');  
var cors = require('cors');  
var bodyParser = require('body-parser');  
var playersRouter = require('./routes/players');  
const hostname = '127.0.0.1';  
const port = 3131;  
dbcon = mysql.createConnection({  
host: 'localhost',  
user: 'nodeuser',  
password: 'yourpassword',  
database: 'nodejs_db'  
}
);  
dbcon.connect(function(err) {  
if (err) throw err;  
console.log("MySQL Connected!");  
}
);  
REST Web Service in Node.js  
index.js:  
var app = express();  
app.use(cors())  
app.use(bodyParser.json());  
app.use('/players', playersRouter);  
app.listen(port, hostname, () => console.log(`Server running at  
http://${hostname}:${port}/`));  
routes/players.js:  
var express = require('express');  
var router = express.Router();  
router.get('/list', function(req, res) {  
let sql = `SELECT username, score FROM players`;  
dbcon.query(sql, function(err, players, fields) {  
if (err) throw err;  
res.json({players})  
}
)
}
);  
REST Web Service in Node.js  
routes/players.js:  
router.post('/new', function(req, res) {  
let sql = `INSERT INTO players(username, password, score) VALUES (?)`;  
let values = [  
req.body.username,  
req.body.password,  
0
]
;
dbcon.query(sql, [values], function(err, data, fields) {  
if (err) throw err;  
res.json({  
status: 200,  
message: "New player added successfully"  
}
)
}
)
}
);  
REST Web Service in Node.js  
routes/players.js:  
router.post('/setscore', function(req, res) {  
let sql = `UPDATE players SET score = ? WHERE id = ?`;  
let values = [  
req.body.score,  
req.body.id  
]
;
dbcon.query(sql, values, function(err, data, fields) {  
if (err) throw err;  
res.json({  
status: 200,  
message: "Score updated successfully"  
}
)
}
)
}
);  
module.exports = router;  
REST Web Service in Node.js  
Test the Web Service (GET):  
http://SERVER_IP:3131/players/list  
Test the Web Service (POST):  
http://SERVER_IP:3131/players/new  
Header:  
User-Agent: Fiddler  
Content-Type: application/json  
Body:  
{
"username":"MyUser", "password":"123456"}  
REST Web Service in Unity  
REST Web Service in Unity  
PlayerInfo.cs  
[
System.Serializable]  
public class PlayerInfo  
{
public string username;  
public int score;  
public PlayerInfo(string user, int pscore)  
{
username = user;  
score = pscore;  
}
}
[
System.Serializable]  
public class PlayerList  
{
public PlayerInfo[] players;  
}
REST Web Service in Unity  
PlayerInfo.cs  
[
System.Serializable]  
public class NewPlayerInfo{  
public string username;  
public string password;  
public NewPlayerInfo(string user, string pass){  
username = user;  
password = pass;  
}
}
[
System.Serializable]  
public class NewUpdateScoreInfo{  
public int id;  
public int score;  
public NewUpdateScoreInfo(int nid, int nscore){  
id = nid;  
score = nscore;  
}
}
REST Web Service in Unity  
using UnityEngine.Networking;  
using UnityEngine.UI;  
PlayerScoreManager.cs  
public class PlayerScoreManager : MonoBehaviour{  
public string BaseAPI = "http://192.168.56.101:3131/";  
public Canvas canvas;  
public Font font;  
public int maxPlayers = 10;  
public GameObject refreshButtonPrefab;  
public GameObject registerButtonPrefab;  
public GameObject newUserUIPrefab;  
private List<PlayerInfo> playerList;  
private bool playerListUpdated;  
private GameObject[] playerLabelsNames;  
private GameObject[] playerLabelsScores;  
private GameObject refreshButton;  
private GameObject registerButton;  
private GameObject newUserUI;  
REST Web Service in Unity  
PlayerScoreManager.cs  
IEnumerator GetRequest(string uri)  
{
UnityWebRequest webRequest = UnityWebRequest.Get(uri);  
yield return webRequest.SendWebRequest();  
if (webRequest.isNetworkError)  
{
Debug.Log(webRequest.error);  
}
else  
{
PlayerList playersList = JsonUtility.FromJson<PlayerList>(  
webRequest.downloadHandler.text);  
playerList.Clear();  
foreach (PlayerInfo player in playersList.players) {  
playerList.Add(new PlayerInfo(player.username, player.score));  
}
playerListUpdated = true;  
}
}
REST Web Service in Unity  
PlayerScoreManager.cs  
IEnumerator PostRequest(string uri, string jsondata)  
{
UnityWebRequest webRequest = new UnityWebRequest(uri, "POST");  
byte[] jsonToSend = new System.Text.UTF8Encoding().GetBytes(jsondata);  
webRequest.uploadHandler = (UploadHandler)new  
UploadHandlerRaw(jsonToSend);  
webRequest.downloadHandler = (DownloadHandler)new  
DownloadHandlerBuffer();  
webRequest.SetRequestHeader("Content-Type", "application/json");  
yield return webRequest.SendWebRequest();  
if (webRequest.isNetworkError)  
{
Debug.Log(webRequest.error);  
}
else  
{
Debug.Log(webRequest.downloadHandler.text);  
}
}
REST Web Service in Unity  
PlayerScoreManager.cs  
public void RegisterNewPlayer(string username, string password)  
{
string jsondata = JsonUtility.ToJson(new NewPlayerInfo(username,  
password));  
StartCoroutine(PostRequest(BaseAPI + "players/new", jsondata));  
}
public void UpdatePlayerScore(int userid, int score)  
{
string jsondata = JsonUtility.ToJson(new NewUpdateScoreInfo(userid,  
score));  
StartCoroutine(PostRequest(BaseAPI + "players/setscore", jsondata));  
}
public void UIUpdatePlayerList()  
{
StartCoroutine(GetRequest(BaseAPI + "players/list"));  
}
REST Web Service in Unity  
PlayerScoreManager.cs  
public void UIRegisterNewPlayer(){  
if (newUserUI == null){  
newUserUI = GameObject.Instantiate(newUserUIPrefab,  
canvas.transform, false);  
newUserUI.GetComponent<RectTransform>().anchoredPosition = new  
Vector3(0, 0, 0);  
refreshButton.SetActive(false);  
}
else{  
InputField usernameInput = GameObject.FindGameObjectWithTag  
"Username").GetComponent<InputField>();  
InputField passwordInput = GameObject.FindGameObjectWithTag  
"Password").GetComponent<InputField>();  
(
(
RegisterNewPlayer(usernameInput.text, passwordInput.text);  
Destroy(newUserUI);  
newUserUI = null;  
refreshButton.SetActive(true);  
}
}
REST Web Service in Unity  
PlayerScoreManager.cs  
private void CreateScoreList()  
{
playerList = new List<PlayerInfo>();  
playerLabelsNames = new GameObject[maxPlayers];  
playerLabelsScores = new GameObject[maxPlayers];  
/
/Usernames label  
GameObject namesLabel = new GameObject();  
namesLabel.name = "PlayerInfoNameLabel";  
namesLabel.transform.SetParent(canvas.transform);  
Text text = namesLabel.AddComponent<Text>();  
text.text = "Player";  
text.font = font;  
text.fontStyle = FontStyle.Bold;  
text.rectTransform.anchoredPosition = new Vector3(-80, (maxPlayers *  
3
0) - ((maxPlayers / 2) * 30), 0);  
REST Web Service in Unity  
PlayerScoreManager.cs  
/
/Scores label  
GameObject scoreLabel = new GameObject();  
scoreLabel.name = "PlayerInfoNameLabel";  
scoreLabel.transform.SetParent(canvas.transform);  
text = scoreLabel.AddComponent<Text>();  
text.text = "Score";  
text.font = font;  
text.fontStyle = FontStyle.Bold;  
text.rectTransform.anchoredPosition = new Vector3(130, (maxPlayers *  
3
0) - ((maxPlayers / 2) * 30), 0);  
for (int i = 0; i < maxPlayers; i++){  
/
/Name label  
playerLabelsNames[i] = new GameObject();  
playerLabelsNames[i].name = "PlayerInfoName" + i;  
playerLabelsNames[i].transform.SetParent(canvas.transform);  
text = playerLabelsNames[i].AddComponent<Text>();  
text.text = "";  
text.font = font;  
text.rectTransform.anchoredPosition = new Vector3(-80, (i * 30) –  
(
(maxPlayers / 2) * 30), 0);  
REST Web Service in Unity  
PlayerScoreManager.cs  
//Score label  
playerLabelsScores[i] = new GameObject();  
playerLabelsScores[i].name = "PlayerInfoScore" + i;  
playerLabelsScores[i].transform.SetParent(canvas.transform);  
text = playerLabelsScores[i].AddComponent<Text>();  
text.text = "";  
text.font = font;  
text.rectTransform.anchoredPosition = new Vector3(130, (i * 30) –  
(
(maxPlayers / 2) * 30), 0);  
}
playerListUpdated = false;  
}
REST Web Service in Unity  
PlayerScoreManager.cs  
private void CreateButtons()  
{
refreshButton = GameObject.Instantiate(refreshButtonPrefab,  
canvas.transform, false);  
refreshButton.GetComponent<RectTransform>().anchoredPosition = new  
Vector3(-100, -((maxPlayers / 2) * 30) - 30, 0);  
refreshButton.GetComponent<Button>().onClick.AddListener(  
UIUpdatePlayerList);  
registerButton = GameObject.Instantiate(registerButtonPrefab,  
canvas.transform, false);  
registerButton.GetComponent<RectTransform>().anchoredPosition = new  
Vector3(100, -((maxPlayers / 2) * 30) - 30, 0);  
registerButton.GetComponent<Button>().onClick.AddListener(  
UIRegisterNewPlayer);  
}
REST Web Service in Unity  
PlayerScoreManager.cs  
private void Update(){  
if ((playerList.Count > 0) && (playerListUpdated)){  
int index = maxPlayers - 1;  
foreach (PlayerInfo player in playerList){  
if (index >= 0){  
playerLabelsNames[index].GetComponent<Text>().text =  
player.username;  
playerLabelsScores[index].GetComponent<Text>().text =  
player.score.ToString();  
index--;  
}
}
playerListUpdated = false;  
}
}
private void Start(){  
CreateScoreList();  
CreateButtons();  
}
}
REST Web Service in Unity  
Exercises  
1
2
) Implement the login process:  
When the game starts, the player must enter his username and  
password.  
The web service must check if the username and password match with  
an exiting player.  
If the username and password are correct, the web service returns the  
user ID, which must be stored by the game to perform future score  
updates.  
If the username and password are NOT correct, the web service returns an error  
message. The game must inform the player about the error.  
) Update the player score:  
After receiving the valid ID of the current player, use this information to  
change the score of the player.  
Use a button that is only visible after the login process.  
Further Reading  
Scripting Reference, Available at: https://docs.unity3d.com/ScriptReference/  
Networking & Classes  
UnityWebRequest  
JsonUtility  
Coroutine  
Node.js documentation:  
https://nodejs.org/en/docs/  
Books  
Jeremy G. (2017). Introduction to Game Design, Prototyping, and Development:  
from the Concept to Playable Game - with Unity and C# (2nd ed.). Boston, MA:  
Addison-Wesley Professional. ISBN: 978-0134659862  
Hocking, J. (2018). Unity in Action: Multiplatform Game Development in C#  
(
2nd ed.). Shelter Island, NY: Manning Publications. ISBN: 978-1617294969