When a project is being developed on a computer, the problem of viewing the log does not arise. But when you start to develop on the tablet, then everything becomes much sadder. The developers of the engine added a lot of different useful things to the profiler, but unfortunately they forgot about a simple console, so that switching to its tab, the developer could watch messages from his game and send some console commands directly from the computer to the tablet.
We will now correct this omission.
In short, we will create a table in Google Docs, and a script that will add a value there when called. And create a script in the engine that will listen to commands like Debug.Log () and send them to our script. Affairs for 10 minutes, but the convenience rises significantly. If you have a console in your project, you can make the script send a response (say, the contents of the table you wrote in a cell of the table), you can send this as a command to the console.
Everything works pretty fast, I have 50 mbit Internet, messages appear almost instantly. Google table is updated itself, no need to refresh.
First, the simplest option, to understand the point.
1. Configure the server side.')
For the server part, you need a Google account, because we will create a table in Google Drive.
Create Spreadsheet.
In the menu, create a script (Tools -> Script Editor -> Script as Web App).
Delete the created template and copy the following code:
function doGet(e) { var sheet = SpreadsheetApp.openById("0Ap2rwVyty8rZdElOTFhlTG9BSEZGY29BZDlpQWdMR2c"); var n = sheet.getLastRow() + 1; sheet.getRange("A"+n).setValue( new Date() ); sheet.getRange("B"+n).setValue(e.parameter.p); return ContentService.createTextOutput("OK"); }
!!! In the id code 0Ap2rwVyty8rZdElOTFhlTG9BSEZGY29BZDlpQWdMR2c you must replace with the id of your page, you can take it from the URL of the Spreadsheet you created.When calling this script, it will take the table you created, and add to the last row the time and value that came at the GET request with the key p.
Save the script under the name, for example, RemoteLogger.
Now you need to create a version (File -> Manage versions -> Save new version).
Now we can release it (Publish -> Deploy as Web App) with the following settings:
!!! Execute the app as: me
!!! Who has access to the app: Anyone, even anonymous
After clicking Deploy, Google gives us a URL like this:
script.google.com/macros/s/AKfycbyubkC0TQbyrRYvVD9nYezvxuDkya0Asbvff67EUK0G0oqFndws/execwhen you start it, a row with the start time and the value undefined will appear in the table you created, if at the end you add? p = test
script.google.com/macros/s/AKfycbyubkC0TQbyrRYvVD9nYezvxuDkya0Asbvff67EUK0G0oqFndws/exec?p=testthen a row will appear in the table with the word "test"
We can assume that the server part is working properly.
2. Client Unity script.Create a script, for example RemoteLogger.cs and place the following code there:
using UnityEngine; using System.Collections; using System.IO; public class RemoteLogger : MonoBehaviour { string url = "https://script.google.com/macros/s/AKfycbyubkC0TQbyrRYvVD9nYezvxuDkya0Asbvff67EUK0G0oqFndws/exec"; // Your URL copy here // Use this for initialization void Start () { Debug.Log("Hello world!"); } // Update is called once per frame void Update () { } //get method here http://forum.antichat.ru/showthread.php?t=290347 string UrlEncode(string instring) { StringReader strRdr = new StringReader(instring); StringWriter strWtr = new StringWriter(); int charValue = strRdr.Read(); while (charValue != -1) { if (((charValue >= 48) && (charValue <= 57)) // 0-9 || ((charValue >= 65) && (charValue <= 90)) // AZ || ((charValue >= 97) && (charValue <= 122))) // az { strWtr.Write((char) charValue); } else if (charValue == 32) // Space { strWtr.Write("+"); } else { strWtr.Write("%{0:x2}", charValue); } charValue = strRdr.Read(); } return strWtr.ToString(); } void SendLog(string mes) { string t_url = url + "?p=" + UrlEncode(mes); WWW www = new WWW(t_url); StartCoroutine(WaitForRequest(www)); } IEnumerator WaitForRequest(WWW www) { yield return www; // check for errors if (www.error == null) { //OK } else { //Error } } void OnEnable() { Application.RegisterLogCallback(HandleLog); } void OnDisable() { Application.RegisterLogCallback(null); } void HandleLog(string logString, string stackTrace, LogType type) { SendLog(logString); } }
!!! Do not forget to change the url value to the address of your script.This script listens to the log, takes the message, encodes it for transmission by the GET method and sends it to our script so that it adds it to the table.
After adding to GameObject and launching, “Hello world!” Should appear on the table opened in your browser (the table is updated automatically). If this does not happen, then you probably forgot to change the id of the table, url, or set up the permissions incorrectly when publishing the script.
3. Batching.If the program has a lot of messages, it is too wasteful to create a new request for each. We will transmit up to 10 messages at a time, depending on how many are at the moment.
There is nothing difficult in the changes, so I’ll just publish the code and explain briefly.
First we fix the script on the server:
function doGet(e) { var sheet = SpreadsheetApp.openById("0Ap2rwVyty8rZdElOTFhlTG9BSEZGY29BZDlpQWdMR2c"); var n = sheet.getLastRow() + 1; sheet.getRange("A"+n).setValue( new Date() ); for (var j = 0; j < 10; j++) { if (e.parameter["p" + j] != null) { sheet.getRange("B"+n).setValue(e.parameter["p" + j]); n++; } } return ContentService.createTextOutput("OK"); }
That is, the parameters from p0 to p9 are searched, if there is a value, then it is added.
Now the code of the class RemoteLogger.cs
using UnityEngine; using System.Collections; using System.Collections.Generic; using System.IO; public class RemoteLogger : MonoBehaviour { string url = "https://script.google.com/macros/s/AKfycbx6q4xPM-5S7FJn1QFHHd9eXhF4yXvaguawc-yEoxU6ETFrZmU/exec"; bool sema = false; Queue<string> log = new Queue<string>(); // Use this for initialization void Awake () { DontDestroyOnLoad(gameObject); } // Use this for initialization void Start () { Debug.Log("Hello world!"); } // Update is called once per frame void Update () { if (!sema && log.Count > 0) { SendLog(); } } //get method here http://forum.antichat.ru/showthread.php?t=290347 string UrlEncode(string instring) { StringReader strRdr = new StringReader(instring); StringWriter strWtr = new StringWriter(); int charValue = strRdr.Read(); while (charValue != -1) { if (((charValue >= 48) && (charValue <= 57)) // 0-9 || ((charValue >= 65) && (charValue <= 90)) // AZ || ((charValue >= 97) && (charValue <= 122))) // az { strWtr.Write((char) charValue); } else if (charValue == 32) // Space { strWtr.Write("+"); } else { strWtr.Write("%{0:x2}", charValue); } charValue = strRdr.Read(); } return strWtr.ToString(); } void SendLog() { if (sema) return; sema = true; int count = log.Count > 10 ? 10 : log.Count; string t_url = url + "?p0=" + UrlEncode(log.Dequeue()); for (int i = 1; i < count; i++) { t_url += "&p" + i + "=" + UrlEncode(log.Dequeue()); } WWW www = new WWW(t_url); StartCoroutine(WaitForRequest(www)); } IEnumerator WaitForRequest(WWW www) { yield return www; // check for errors if (www.error == null) { //OK } else { //Error } sema = false; } void OnEnable() { Application.RegisterLogCallback(HandleLog); } void OnDisable() { Application.RegisterLogCallback(null); } void HandleLog(string logString, string stackTrace, LogType type) { log.Enqueue(logString); } }
We made sure that the logger did not disappear when loading the next scene. We also added a queue to which the game messages are added, and from which they are periodically sent. We also created a semaphore so that there were not too many connections for 1 moment.
TODO:Depending on your needs, you can transfer to the table what the error / warning / message is and highlight it accordingly, as is done in Unity.
You can transfer the stack if it is important for you to see where it was sent from.
Theoretically, you can use the construction of graphs.
You can make feedback, and transfer some commands into the game, there already listening to the response of the script and passing it to the console. Easy to add.
You can not do the console, but add menu items, for example, “Make screenshot”, “Enable cheats”, and send them.
In general, there is room for improvement and expansion. Share your ideas and their implementations, maybe they will be useful to someone. :)
PS: Many thanks to the author of this
article from the sandbox.