Live link refers to tech that allows you to make changes in the editor and see those changes reflected in a running player. It is a handy feature for tweaking object properties for mobile games. Without it, the workflow looks like this: make a change, build addressables, build the player, deploy the player, run the app and finally see the change. This loop can take minutes. A task I worked on required a solution to have a live link solution between unity and a mobile device.
The problem

The problem I had to solve was to tweak camera dragging and movement parameters which needed immediate feedback in the game so tweaking could be possible.
I am pretty sure Unity has a proper live link system in the works, but I needed something quick. Luckily we have a development server, which we use to serve addressables and set up various network conditions for testing downloads, so I decided to add this functionality there.
The idea
The idea was to have an endpoint in the dev server that accepts a POST request and stores whatever value the editor sends under a key in a dictionary. Then have the game connect to this dev server and periodically pull data changes from it using pre-defined key values. It’s pretty low-key, but we didn’t need anything more complicated.
Server-side
Using express.js, this is a simple task to do
const express = require('express')
const app = express()
...
app.use(express.text());
const valueStore = {};
app.post(`/valueStore/:keyName`, (req, res) => {
console.log(`POST/valueStore/${req.params.keyName} = ${req.body}`);
valueStore[req.params.keyName] = req.body;
res.sendStatus(200);
});
app.get(`/valueStore/:keyName`, (req, res) => {
console.log(`GET /valueStore/${req.params.keyName}`);
res.send(valueStore[req.params.keyName]);
});
app.listen(serverPort, () => {
console.log(`App is listening on port ${serverPort}`)
});
Code language: JavaScript (javascript)
Game-side
In the game, I keep the parameters I want to tweak in scriptable objects. They are great for sharing values between instances using them, but they are part of the game’s data set. So, I needed a way to change them post-build. So in the code, I had to make a few changes.
Firstly, I added a custom editor for my scriptable object type, which allows the user to click a button and send the current values to the server. Otherwise, it displays the default property editor for the scriptable object.
using UnityEditor;
using UnityEngine;
namespace SpongeHammer
{
[CustomEditor(typeof(ScreenDragHandlerConfig))]
public class ScreenDragHandlerConfigEditor : Editor
{
public override void OnInspectorGUI()
{
GUILayout.BeginVertical();
if (GUILayout.Button("Send update"))
{
var handler = target as ScreenDragHandlerConfig;
if (handler)
{
var stringToSend = handler.ToJson();
// Not using await here is intentional: fire and forget
HttpHandler.PostText($"http://localhost:8080/valueStore/{handler.RemoteConfigName}", stringToSend);
}
}
GUILayout.Space(20);
DrawDefaultInspector();
if (serializedObject.hasModifiedProperties)
{
serializedObject.ApplyModifiedProperties();
}
GUILayout.EndVertical();
}
}
}
Code language: C# (cs)
I also updated the scriptable object to be able to convert itself to and from JSON using Json.Net. Another addition is a serialised field that holds the key name, which I use for accessing the server’s key-value store.
[Serializable]
public class ScreenDragHandlerConfigData
{
[SerializeField, Tooltip("Max speed"), JsonIgnore]
private float dragSpeed = 1;
...
public float DragSpeed
{
get => dragSpeed;
set => dragSpeed = value;
}
}
[CreateAssetMenu(fileName = "ScreenDragConfig", menuName = "SHG/Screen Drag/ScreenDragConfig")]
public class ScreenDragHandlerConfig : ScriptableObject
{
[SerializeField]
private ScreenDragHandlerConfigData data;
[SerializeField]
private string remoteConfigKeyName;
public string RemoteConfigName => remoteConfigKeyName;
...
public string ToJson()
{
return JsonConvert.SerializeObject(data);
}
public void FromJson(string json)
{
data = JsonConvert.DeserializeObject<ScreenDragHandlerConfigData>(json);
}
}
Code language: C# (cs)
Finally, I added a coroutine to the component using this scriptable object. It starts when Unity calls OnEnable, and it periodically polls the server for new values and deserialises them using the new JSON function. Note the partial keyword, this file has a preprocessor guard that turns this functionality off by default, so we don’t leave such functionality in release builds. The skeleton of the code was taken from the Unity documentation.
using System.Collections;
using UnityEngine;
using UnityEngine.Networking;
#if UNITY_EDITOR
using UnityEditor;
#endif
namespace SpongeHammer
{
public partial class ScreenDragHandler
{
private void StartValuePolling()
{
var url = $"http://192.168.1.112:8080/valueStore/{this.config.RemoteConfigName}";
StartCoroutine(GetRequest(url));
}
IEnumerator GetRequest(string uri)
{
var waiter = new WaitForSeconds(5);
while (true)
{
yield return waiter;
using var webRequest = UnityWebRequest.Get(uri);
// Request and wait for the desired page.
yield return webRequest.SendWebRequest();
switch (webRequest.result)
{
case UnityWebRequest.Result.ConnectionError:
case UnityWebRequest.Result.DataProcessingError:
case UnityWebRequest.Result.ProtocolError:
default:
yield break;
case UnityWebRequest.Result.Success:
var text = webRequest.downloadHandler.text;
if (!string.IsNullOrEmpty(text))
{
config.FromJson(text);
}
break;
}
}
}
}
}
Conclusion
The code is not clean and could do with a bit of error handling and having smarter logic for not polling the server, but for now, it’ll do. When working with limited time, solutions like this can save the day. Later we can build on it more. Or use the official solution Unity will deliver.
Disclaimer: The code provided here demonstrates a possible solution to a problem. It is not a working application, and we supply it without any warranties, support or guarantees. You can use it and change it in any way you like for personal and commercial purposes. Use it at your own risk. Sponge Hammer takes no responsibility for any damage it might cause.
I hope Csaba’s post helped you. If you have a comment or idea or have another solution for the problem, please let us know here or get in touch with us on social media.
You can find other Unity posts here.