📜 ⬆️ ⬇️

Unity Integration with Google Spreadsheets



Sooner or later, in the process of developing even the simplest game, its creators are faced with the task of data management, these can be the parameters of in-game items (units, weapons, skills), the economy in the game, localization, or data necessary for the application to work.

Spreadsheets can be a convenient tool for solving this problem. They are well suited for visual data display and visualization. Sorting and using formulas will help achieve mathematical accuracy in calculating the economy, game cycles and level management. The advantage of Google spreadsheets is that a large number of people can work with them simultaneously online, which significantly increases the speed of development, establishes reliable and understandable communication between team members: programmers, artists, game designers.
')
In this article, I want to tell you how good spreadsheets have brought to me, what difficulties I encountered when I was preparing the game for working with Google spreadsheets and also want to share a small tutorial on integrating the Unity project with Google Spreadsheets.


If we consider the case of our game, we used Google tables to store data and systematize the color schemes of the characters, miscalculate their value in the in-game currency and build a task system for the player. For me, as a person who is responsible for the software part of the application, using tables has saved a lot of time, especially when it came to graphics data and collaboration with the designer.



As you may have noticed, different color schemes added zest to a fairly simple game, made it a little more attractive and interesting for the user. Without data systematization, this would be almost impossible.



Formulas and sorting techniques helped to calculate all the parameters of in-game tasks (challenges): order, purpose, reward. The right approach to building an economy is very important for keeping the user in the game, and the mobility in changing data that tables provide is playing into this case.



Now let's move on to the technical aspect of integrating Google spreadsheets with Unity. The Unity game engine provides many ways to interact with Internet resources, including Google tables, one of which is integration based on a standalone application. But the main challenge in this case could be the use of the .NET 2.0 engine.

Since May 5, 2015, Google has stopped supporting the outdated OAuth 1.0 authorization protocol, and all those applications that have not switched to the new OAuth 2.0 have stopped working. It turned out that the developers of free plug-ins that I used, Unity-GData and its updated version of Unity-Quicksheet did not take care of this, and I had no choice but to look for a solution myself.

At first it seemed to me that problems with authorization on Unity and # should not arise, because the documentation on this topic is exhaustive. But it turned out not so simple.

Firstly, there were interruptions to the authorization process itself, as some parameters for the OAuth 2.0 request were not specified in the Google Spreadsheets documentation, for example, “Access Type” and “Token Type”.

Secondly, in some updated Google Data API. DLL libraries that I imported from the Google Data API SDK for mono, errors occurred during Unity during compilation, it was the same with a number of old .dll from the Unity-GData plugin. I had to combine.

Thirdly, it was necessary to add another suitable Newtonsoft library for working with JSON requests.

Let's get down to business . The process of integrating Google tables with Unity can be divided into several stages.

First you need to download the unitypackage , which already has all the necessary libraries and scripts.

Pre-set up your google account




Setting up access to the Google Drive API


I will give an example of the script.
There is a script
using UnityEngine; using UnityEditor; using System.Collections; using System.Collections.Generic; using Google.GData.Client; using Google.GData.Spreadsheets; [InitializeOnLoad] public class SpreadsheetEntity : MonoBehaviour { // enter Client ID and Client Secret values const string _ClientId = ""; const string _ClientSecret = ""; // enter Access Code after getting it from auth url const string _AccessCode = ""; // enter Auth 2.0 Refresh Token and AccessToken after succesfully authorizing with Access Code const string _RefreshToken = ""; const string _AccessToken = ""; const string _SpreadsheetName = ""; static SpreadsheetsService service; public static GOAuth2RequestFactory RefreshAuthenticate() { OAuth2Parameters parameters = new OAuth2Parameters() { RefreshToken = _RefreshToken, AccessToken = _AccessToken, ClientId = _ClientId, ClientSecret = _ClientSecret, Scope = "https://www.googleapis.com/auth/drive https://spreadsheets.google.com/feeds", AccessType = "offline", TokenType = "refresh" }; string authUrl = OAuthUtil.CreateOAuth2AuthorizationUrl(parameters); return new GOAuth2RequestFactory("spreadsheet", "MySpreadsheetIntegration-v1", parameters); } static void Auth() { GOAuth2RequestFactory requestFactory = RefreshAuthenticate(); service = new SpreadsheetsService("MySpreadsheetIntegration-v1"); service.RequestFactory = requestFactory; } // Use this for initialization static SpreadsheetEntity(){ if (_RefreshToken == "" && _AccessToken == "") { Init(); return; } Auth(); Google.GData.Spreadsheets.SpreadsheetQuery query = new Google.GData.Spreadsheets.SpreadsheetQuery(); // Make a request to the API and get all spreadsheets. SpreadsheetFeed feed = service.Query(query); if (feed.Entries.Count == 0) { Debug.Log("There are no spreadsheets in your docs."); return; } AccessSpreadsheet(feed); } // access spreadsheet data static void AccessSpreadsheet(SpreadsheetFeed feed) { string name = _SpreadsheetName; SpreadsheetEntry spreadsheet = null; foreach (AtomEntry sf in feed.Entries) { if (sf.Title.Text == name) { spreadsheet = (SpreadsheetEntry)sf; } } if (spreadsheet == null) { Debug.Log("There is no such spreadsheet with such title in your docs."); return; } // Get the first worksheet of the first spreadsheet. WorksheetFeed wsFeed = spreadsheet.Worksheets; WorksheetEntry worksheet = (WorksheetEntry)wsFeed.Entries[0]; // Define the URL to request the list feed of the worksheet. AtomLink listFeedLink = worksheet.Links.FindService(GDataSpreadsheetsNameTable.ListRel, null); // Fetch the list feed of the worksheet. ListQuery listQuery = new ListQuery(listFeedLink.HRef.ToString()); ListFeed listFeed = service.Query(listQuery); foreach (ListEntry row in listFeed.Entries) { //access spreadsheet data here } } static void Init() { //////////////////////////////////////////////////////////////////////////// // STEP 1: Configure how to perform OAuth 2.0 //////////////////////////////////////////////////////////////////////////// if (_ClientId == "" && _ClientSecret == "") { Debug.Log("Please paste Client ID and Client Secret"); return; } string CLIENT_ID = _ClientId; string CLIENT_SECRET = _ClientSecret; string SCOPE = "https://www.googleapis.com/auth/drive https://spreadsheets.google.com/feeds https://docs.google.com/feeds"; string REDIRECT_URI = "urn:ietf:wg:oauth:2.0:oob"; string TOKEN_TYPE = "refresh"; //////////////////////////////////////////////////////////////////////////// // STEP 2: Set up the OAuth 2.0 object //////////////////////////////////////////////////////////////////////////// // OAuth2Parameters holds all the parameters related to OAuth 2.0. OAuth2Parameters parameters = new OAuth2Parameters(); parameters.ClientId = CLIENT_ID; parameters.ClientSecret = CLIENT_SECRET; parameters.RedirectUri = REDIRECT_URI; //////////////////////////////////////////////////////////////////////////// // STEP 3: Get the Authorization URL //////////////////////////////////////////////////////////////////////////// parameters.Scope = SCOPE; parameters.AccessType = "offline"; // IMPORTANT and was missing in the original parameters.TokenType = TOKEN_TYPE; // IMPORTANT and was missing in the original // Authorization url. string authorizationUrl = OAuthUtil.CreateOAuth2AuthorizationUrl(parameters); Debug.Log(authorizationUrl); Debug.Log("Please visit the URL above to authorize your OAuth " + "request token. Once that is complete, type in your access code to " + "continue..."); parameters.AccessCode = _AccessCode; if (parameters.AccessCode == "") { Application.OpenURL(authorizationUrl); return; } //////////////////////////////////////////////////////////////////////////// // STEP 4: Get the Access Token //////////////////////////////////////////////////////////////////////////// OAuthUtil.GetAccessToken(parameters); string accessToken = parameters.AccessToken; string refreshToken = parameters.RefreshToken; Debug.Log("OAuth Access Token: " + accessToken + "\n"); Debug.Log("OAuth Refresh Token: " + refreshToken + "\n"); } } 


I will note a certain feature: this script is executed when the Unity editor is launched, it is very convenient, because all the data will already be in place before executing the main application code, for more details, click here .

After you have completed all the necessary steps, the project is ready for working with Google spreadsheets.

Retrieving and storing data from Google spreadsheets

At Google, the process of working with tables is well described in the above documentation for developers. But for clarity, I will give a small example. To retrieve data, I use list-based requests (list-based feeds), and XML files for storage. More information on working with XML in Unity can be found here .

Code example
 // modified AccessSpreadsheet Method void AccessSpreadsheet(SpreadsheetFeed feed) { string name = _SpreadsheetName; SpreadsheetEntry spreadsheet = null; foreach (AtomEntry sf in feed.Entries) { if (sf.Title.Text == name) { spreadsheet = (SpreadsheetEntry)sf; } } if (spreadsheet == null) { Debug.Log("There is no such spreadsheet with such title in your docs."); return; } // Get the first worksheet of the first spreadsheet. WorksheetFeed wsFeed = spreadsheet.Worksheets; WorksheetEntry worksheet = (WorksheetEntry)wsFeed.Entries[0]; // Define the URL to request the list feed of the worksheet. AtomLink listFeedLink = worksheet.Links.FindService(GDataSpreadsheetsNameTable.ListRel, null); // Fetch the list feed of the worksheet. ListQuery listQuery = new ListQuery(listFeedLink.HRef.ToString()); ListFeed listFeed = service.Query(listQuery); //create list to add dynamic data List<TestEntity> testEntities = new List<TestEntity>(); foreach (ListEntry row in listFeed.Entries) { TestEntity entity = new TestEntity(); entity.name = row.Elements[0].Value; entity.number = int.Parse(row.Elements[1].Value); //use Parse method to get int value Debug.Log("Element: " + entity.name + ", " + entity.number.ToString()); testEntities.Add(entity); } TestContainer container = new TestContainer(testEntities.ToArray()); container.Save("test.xml"); } // classes for xml serialization public class TestEntity { public string name; public int number; public TestEntity(){ name = "default"; number = 0; } } [XmlRoot("TestCollection")] public class TestContainer { [XmlArray("TestEntities")] [XmlArrayItem("testEntity")] public TestEntity[] testEntities;// = new skinEntity[]; public TestContainer(){ } public TestContainer(TestEntity[] arch){ testEntities = arch; } public void Save(string path) { var serializer = new XmlSerializer(typeof(TestContainer)); using(var stream = new FileStream(path, FileMode.Create)) { serializer.Serialize(stream, this); } } public static TestContainer Load(string path) { var serializer = new XmlSerializer(typeof(TestContainer)); using(var stream = new FileStream(path, FileMode.Open)) { return serializer.Deserialize(stream) as TestContainer; } } } 


It is also worth adding that the script only works in the editor, you cannot use the Google table functionality on the device, at least with the versions of plug-ins that I found, this is due to compatibility problems of some libraries with some platforms. The libraries offered by me in unitypackage will not be compiled for any platform other than the editor. If you still need to use the tables on the device, then in version 5 of Unity, you can choose the platform that the plugin should support, using the Plugin Inspector, and in earlier versions, put the plugin in the right folder, read more here .

So, spreadsheets are indispensable tools in the game development process. They help to optimize the routine work and improve the interaction of the whole team, visualize huge data arrays and use mathematics to calculate them. Integrating Google Spreadsheets with Unity is a simple process, but it requires a little knowledge and effort.

Here is the link to the GitHub project.

Thank you for your attention, I hope the article was useful to you.

Source: https://habr.com/ru/post/262901/


All Articles