LanguageSourceData_Import_Google.cs 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385
  1. using System;
  2. using System.Collections;
  3. using System.Text;
  4. using UnityEditor;
  5. using UnityEngine;
  6. using UnityEngine.Networking;
  7. using UnityEngine.SceneManagement;
  8. using Object = UnityEngine.Object;
  9. namespace I2.Loc
  10. {
  11. public partial class LanguageSourceData
  12. {
  13. private string mDelayedGoogleData; // Data that was downloaded and is waiting for a levelLoaded event to apply the localization without a lag in performance
  14. #region Connection to Web Service
  15. public static void FreeUnusedLanguages()
  16. {
  17. var source = LocalizationManager.Sources[0];
  18. int langIndex = source.GetLanguageIndex(LocalizationManager.CurrentLanguage);
  19. for (int i=0; i<source.mTerms.Count; ++i)
  20. {
  21. var term = source.mTerms[i];
  22. for (int j=0; j<term.Languages.Length; j++)
  23. {
  24. if (j != langIndex)
  25. term.Languages[j] = null;
  26. }
  27. }
  28. }
  29. public void Import_Google_FromCache()
  30. {
  31. if (GoogleUpdateFrequency==eGoogleUpdateFrequency.Never)
  32. return;
  33. if (!I2Utils.IsPlaying())
  34. return;
  35. string PlayerPrefName = GetSourcePlayerPrefName();
  36. string I2SavedData = PersistentStorage.LoadFile(PersistentStorage.eFileType.Persistent, "I2Source_"+ PlayerPrefName + ".loc", false);
  37. if (string.IsNullOrEmpty (I2SavedData))
  38. return;
  39. if (I2SavedData.StartsWith("[i2e]", StringComparison.Ordinal))
  40. {
  41. I2SavedData = StringObfucator.Decode(I2SavedData.Substring(5, I2SavedData.Length-5));
  42. }
  43. //--[ Compare with current version ]-----
  44. bool shouldUpdate = false;
  45. string savedSpreadsheetVersion = Google_LastUpdatedVersion;
  46. if (PersistentStorage.HasSetting("I2SourceVersion_"+PlayerPrefName))
  47. {
  48. savedSpreadsheetVersion = PersistentStorage.GetSetting_String("I2SourceVersion_"+PlayerPrefName, Google_LastUpdatedVersion);
  49. // Debug.Log (Google_LastUpdatedVersion + " - " + savedSpreadsheetVersion);
  50. shouldUpdate = IsNewerVersion(Google_LastUpdatedVersion, savedSpreadsheetVersion);
  51. }
  52. if (!shouldUpdate)
  53. {
  54. PersistentStorage.DeleteFile(PersistentStorage.eFileType.Persistent, "I2Source_"+PlayerPrefName+".loc", false);
  55. PersistentStorage.DeleteSetting("I2SourceVersion_"+PlayerPrefName);
  56. return;
  57. }
  58. if (savedSpreadsheetVersion.Length > 19) // Check for corruption from previous versions
  59. savedSpreadsheetVersion = string.Empty;
  60. Google_LastUpdatedVersion = savedSpreadsheetVersion;
  61. //Debug.Log ("[I2Loc] Using Saved (PlayerPref) data in 'I2Source_"+PlayerPrefName+"'" );
  62. Import_Google_Result(I2SavedData, eSpreadsheetUpdateMode.Replace);
  63. }
  64. bool IsNewerVersion( string currentVersion, string newVersion )
  65. {
  66. if (string.IsNullOrEmpty (newVersion)) // if no new version
  67. return false;
  68. if (string.IsNullOrEmpty (currentVersion)) // there is a new version, but not a current one
  69. return true;
  70. long currentV, newV;
  71. if (!long.TryParse (newVersion, out newV) || !long.TryParse (currentVersion, out currentV)) // if can't parse either, then force get the new one
  72. return true;
  73. return newV > currentV;
  74. }
  75. // When JustCheck is true, importing from google will not download any data, just detect if the Spreadsheet is up-to-date
  76. public void Import_Google( bool ForceUpdate, bool justCheck)
  77. {
  78. if (!ForceUpdate && GoogleUpdateFrequency==eGoogleUpdateFrequency.Never)
  79. return;
  80. if (!I2Utils.IsPlaying())
  81. return;
  82. #if UNITY_EDITOR
  83. if (justCheck && GoogleInEditorCheckFrequency==eGoogleUpdateFrequency.Never)
  84. return;
  85. #endif
  86. #if UNITY_EDITOR
  87. var updateFrequency = GoogleInEditorCheckFrequency;
  88. #else
  89. var updateFrequency = GoogleUpdateFrequency;
  90. #endif
  91. string PlayerPrefName = GetSourcePlayerPrefName();
  92. if (!ForceUpdate && updateFrequency != eGoogleUpdateFrequency.Always)
  93. {
  94. #if UNITY_EDITOR
  95. string sTimeOfLastUpdate = EditorPrefs.GetString("LastGoogleUpdate_"+PlayerPrefName, "");
  96. #else
  97. string sTimeOfLastUpdate = PersistentStorage.GetSetting_String("LastGoogleUpdate_"+PlayerPrefName, "");
  98. #endif
  99. DateTime TimeOfLastUpdate;
  100. try
  101. {
  102. if (DateTime.TryParse( sTimeOfLastUpdate, out TimeOfLastUpdate ))
  103. {
  104. double TimeDifference = (DateTime.Now-TimeOfLastUpdate).TotalDays;
  105. switch (updateFrequency)
  106. {
  107. case eGoogleUpdateFrequency.Daily: if (TimeDifference<1) return;
  108. break;
  109. case eGoogleUpdateFrequency.Weekly: if (TimeDifference<8) return;
  110. break;
  111. case eGoogleUpdateFrequency.Monthly: if (TimeDifference<31) return;
  112. break;
  113. case eGoogleUpdateFrequency.OnlyOnce: return;
  114. case eGoogleUpdateFrequency.EveryOtherDay : if (TimeDifference < 2) return;
  115. break;
  116. }
  117. }
  118. }
  119. catch(Exception)
  120. { }
  121. }
  122. #if UNITY_EDITOR
  123. EditorPrefs.SetString("LastGoogleUpdate_" + PlayerPrefName, DateTime.Now.ToString());
  124. #else
  125. PersistentStorage.SetSetting_String("LastGoogleUpdate_"+PlayerPrefName, DateTime.Now.ToString());
  126. #endif
  127. //--[ Checking google for updated data ]-----------------
  128. CoroutineManager.Start(Import_Google_Coroutine(ForceUpdate, justCheck));
  129. }
  130. string GetSourcePlayerPrefName()
  131. {
  132. if (owner == null)
  133. return null;
  134. string sourceName = (owner as Object).name;
  135. if (!string.IsNullOrEmpty(Google_SpreadsheetKey))
  136. {
  137. sourceName += Google_SpreadsheetKey;
  138. }
  139. // If its a global source, use its name, otherwise, use the name and the level it is in
  140. if (Array.IndexOf(LocalizationManager.GlobalSources, (owner as Object).name)>=0)
  141. return sourceName;
  142. #if UNITY_4_6 || UNITY_4_7 || UNITY_4_8 || UNITY_4_9 || UNITY_5_0 || UNITY_5_1 || UNITY_5_2
  143. return Application.loadedLevelName + "_" + sourceName;
  144. #else
  145. return SceneManager.GetActiveScene().name+"_"+ sourceName;
  146. #endif
  147. }
  148. IEnumerator Import_Google_Coroutine(bool forceUpdate, bool JustCheck)
  149. {
  150. UnityWebRequest www = Import_Google_CreateWWWcall(forceUpdate, JustCheck);
  151. if (www==null)
  152. yield break;
  153. while (!www.isDone)
  154. yield return null;
  155. //Debug.Log ("Google Result: " + www.text);
  156. byte[] bytes = www.downloadHandler.data;
  157. bool notError = string.IsNullOrEmpty(www.error) && bytes!=null;
  158. if (notError)
  159. {
  160. string wwwText = Encoding.UTF8.GetString(bytes, 0, bytes.Length);
  161. bool isEmpty = string.IsNullOrEmpty(wwwText) || wwwText == "\"\"";
  162. if (JustCheck)
  163. {
  164. if (!isEmpty)
  165. {
  166. Debug.LogWarning("Spreadsheet is not up-to-date and Google Live Synchronization is enabled\nWhen playing in the device the Spreadsheet will be downloaded and translations may not behave as what you see in the editor.\nTo fix this, Import or Export replace to Google");
  167. GoogleLiveSyncIsUptoDate = false;
  168. }
  169. yield break;
  170. }
  171. if (!isEmpty)
  172. {
  173. mDelayedGoogleData = wwwText;
  174. switch (GoogleUpdateSynchronization)
  175. {
  176. case eGoogleUpdateSynchronization.AsSoonAsDownloaded:
  177. {
  178. ApplyDownloadedDataFromGoogle();
  179. break;
  180. }
  181. case eGoogleUpdateSynchronization.Manual:
  182. break;
  183. case eGoogleUpdateSynchronization.OnSceneLoaded:
  184. {
  185. SceneManager.sceneLoaded += ApplyDownloadedDataOnSceneLoaded;
  186. break;
  187. }
  188. }
  189. yield break;
  190. }
  191. }
  192. if (Event_OnSourceUpdateFromGoogle != null)
  193. Event_OnSourceUpdateFromGoogle(this, false, www.error);
  194. Debug.Log("Language Source was up-to-date with Google Spreadsheet");
  195. }
  196. void ApplyDownloadedDataOnSceneLoaded(Scene scene, LoadSceneMode mode)
  197. {
  198. SceneManager.sceneLoaded -= ApplyDownloadedDataOnSceneLoaded;
  199. ApplyDownloadedDataFromGoogle();
  200. }
  201. public void ApplyDownloadedDataFromGoogle()
  202. {
  203. if (string.IsNullOrEmpty(mDelayedGoogleData))
  204. return;
  205. var errorMsg = Import_Google_Result(mDelayedGoogleData, eSpreadsheetUpdateMode.Replace, true);
  206. if (string.IsNullOrEmpty(errorMsg))
  207. {
  208. if (Event_OnSourceUpdateFromGoogle != null)
  209. Event_OnSourceUpdateFromGoogle(this, true, "");
  210. LocalizationManager.LocalizeAll(true);
  211. Debug.Log("Done Google Sync");
  212. }
  213. else
  214. {
  215. if (Event_OnSourceUpdateFromGoogle != null)
  216. Event_OnSourceUpdateFromGoogle(this, false, "");
  217. Debug.Log("Done Google Sync: source was up-to-date");
  218. }
  219. }
  220. public UnityWebRequest Import_Google_CreateWWWcall( bool ForceUpdate, bool justCheck )
  221. {
  222. if (!HasGoogleSpreadsheet())
  223. return null;
  224. string savedVersion = PersistentStorage.GetSetting_String("I2SourceVersion_"+GetSourcePlayerPrefName(), Google_LastUpdatedVersion);
  225. if (savedVersion.Length > 19) // Check for corruption
  226. savedVersion= string.Empty;
  227. #if !UNITY_EDITOR
  228. if (IsNewerVersion(savedVersion, Google_LastUpdatedVersion))
  229. Google_LastUpdatedVersion = savedVersion;
  230. #endif
  231. string query = string.Format("{0}?key={1}&action=GetLanguageSource&version={2}",
  232. LocalizationManager.GetWebServiceURL(this),
  233. Google_SpreadsheetKey,
  234. ForceUpdate ? "0" : Google_LastUpdatedVersion);
  235. #if UNITY_EDITOR
  236. if (justCheck)
  237. {
  238. query += "&justcheck=true";
  239. }
  240. #endif
  241. UnityWebRequest www = UnityWebRequest.Get(query);
  242. I2Utils.SendWebRequest(www);
  243. return www;
  244. }
  245. public bool HasGoogleSpreadsheet()
  246. {
  247. return !string.IsNullOrEmpty(Google_WebServiceURL) && !string.IsNullOrEmpty(Google_SpreadsheetKey) &&
  248. !string.IsNullOrEmpty(LocalizationManager.GetWebServiceURL(this));
  249. }
  250. public string Import_Google_Result( string JsonString, eSpreadsheetUpdateMode UpdateMode, bool saveInPlayerPrefs = false )
  251. {
  252. try
  253. {
  254. string ErrorMsg = string.Empty;
  255. if (string.IsNullOrEmpty(JsonString) || JsonString == "\"\"")
  256. {
  257. return ErrorMsg;
  258. }
  259. int idxV = JsonString.IndexOf("version=", StringComparison.Ordinal);
  260. int idxSV = JsonString.IndexOf("script_version=", StringComparison.Ordinal);
  261. if (idxV < 0 || idxSV < 0)
  262. {
  263. return "Invalid Response from Google, Most likely the WebService needs to be updated";
  264. }
  265. idxV += "version=".Length;
  266. idxSV += "script_version=".Length;
  267. string newSpreadsheetVersion = JsonString.Substring(idxV, JsonString.IndexOf(",", idxV, StringComparison.Ordinal) - idxV);
  268. var scriptVersion = int.Parse(JsonString.Substring(idxSV, JsonString.IndexOf(",", idxSV, StringComparison.Ordinal) - idxSV));
  269. if (newSpreadsheetVersion.Length > 19) // Check for corruption
  270. newSpreadsheetVersion = string.Empty;
  271. if (scriptVersion != LocalizationManager.GetRequiredWebServiceVersion())
  272. {
  273. return "The current Google WebService is not supported.\nPlease, delete the WebService from the Google Drive and Install the latest version.";
  274. }
  275. //Debug.Log (Google_LastUpdatedVersion + " - " + newSpreadsheetVersion);
  276. if (saveInPlayerPrefs && !IsNewerVersion(Google_LastUpdatedVersion, newSpreadsheetVersion))
  277. #if UNITY_EDITOR
  278. return "";
  279. #else
  280. return "LanguageSource is up-to-date";
  281. #endif
  282. if (saveInPlayerPrefs)
  283. {
  284. string PlayerPrefName = GetSourcePlayerPrefName();
  285. PersistentStorage.SaveFile(PersistentStorage.eFileType.Persistent, "I2Source_" + PlayerPrefName + ".loc", "[i2e]" + StringObfucator.Encode(JsonString));
  286. PersistentStorage.SetSetting_String("I2SourceVersion_" + PlayerPrefName, newSpreadsheetVersion);
  287. PersistentStorage.ForceSaveSettings();
  288. }
  289. Google_LastUpdatedVersion = newSpreadsheetVersion;
  290. if (UpdateMode == eSpreadsheetUpdateMode.Replace)
  291. ClearAllData();
  292. int CSVstartIdx = JsonString.IndexOf("[i2category]", StringComparison.Ordinal);
  293. while (CSVstartIdx > 0)
  294. {
  295. CSVstartIdx += "[i2category]".Length;
  296. int endCat = JsonString.IndexOf("[/i2category]", CSVstartIdx, StringComparison.Ordinal);
  297. string category = JsonString.Substring(CSVstartIdx, endCat - CSVstartIdx);
  298. endCat += "[/i2category]".Length;
  299. int endCSV = JsonString.IndexOf("[/i2csv]", endCat, StringComparison.Ordinal);
  300. string csv = JsonString.Substring(endCat, endCSV - endCat);
  301. CSVstartIdx = JsonString.IndexOf("[i2category]", endCSV, StringComparison.Ordinal);
  302. Import_I2CSV(category, csv, UpdateMode);
  303. // Only the first CSV should clear the Data
  304. if (UpdateMode == eSpreadsheetUpdateMode.Replace)
  305. UpdateMode = eSpreadsheetUpdateMode.Merge;
  306. }
  307. GoogleLiveSyncIsUptoDate = true;
  308. if (I2Utils.IsPlaying())
  309. {
  310. SaveLanguages(true);
  311. }
  312. if (!string.IsNullOrEmpty(ErrorMsg))
  313. Editor_SetDirty();
  314. return ErrorMsg;
  315. }
  316. catch (Exception e)
  317. {
  318. Debug.LogWarning(e);
  319. return e.ToString();
  320. }
  321. }
  322. #endregion
  323. }
  324. }