revival/game/Assets/Scripts/Dialogue/DialogueDatabase.cs

157 lines
4.9 KiB
C#

using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Security.Cryptography.X509Certificates;
using System.Text;
using System.Threading;
using Google.Apis.Auth.OAuth2;
using Google.Apis.Services;
using Google.Apis.Sheets.v4;
using Google.Apis.Util.Store;
using UnityEngine;
#region Editor
#if UNITY_EDITOR
using UnityEditor;
public static partial class DialogueDatabase
{
public static string EDITOR_DialogueFile =>
Path.Combine(Application.dataPath, "Data", "Dialogue", DIALOGUE_FILENAME);
// TODO: neither of these should be in the repository! ideally, move them behind secure
// gitlab variables before there is too much data at risk
private const string SPREADSHEET_ID = "1H42653xGbKLxbsDzz7CSR0iaNMz1hU42LX5hWiFtn-Y";
private const string API_KEY = "AIzaSyD-tKzeKpAj5sFnbXbj2k4H2RQxipw8B8s";
private const string SERVICE_ACCOUNT_EMAIL = "gitlab-runner-dialogue-import@revival-304616.iam.gserviceaccount.com";
private const string CERTIFICATE_NAME = "revival-304616-7f150d13c408.p12";
private static string _workFolder => Path.Combine(Application.dataPath, "Data", "Dialogue");
private static string _certificateFile => Path.Combine(_workFolder, CERTIFICATE_NAME);
// makes a web request via google
// returns 0 on success
public static int Import()
{
var certificate = new X509Certificate2(_certificateFile, "notasecret", X509KeyStorageFlags.Exportable);
var credential = new ServiceAccountCredential(
new ServiceAccountCredential.Initializer(SERVICE_ACCOUNT_EMAIL)
{
Scopes = new[] {SheetsService.Scope.SpreadsheetsReadonly}
}.FromCertificate(certificate));
var service = new SheetsService(new BaseClientService.Initializer()
{
HttpClientInitializer = credential,
ApplicationName = "Kernel Panic - Revival Dialogue Importer",
ApiKey = API_KEY
});
// first two columns, ignore first row
var range = "Sheet1!A2:B";
var request = service.Spreadsheets.Values.Get(SPREADSHEET_ID, range);
var response = request.Execute();
var values = response.Values;
if (values == null || values.Count == 0)
{
Debug.LogError("no data");
return 1;
}
Debug.Log($":: importing dialogue");
var sb = new StringBuilder();
var lines = 0;
foreach (var row in values)
{
if (row.Count != 2)
{
Debug.Log($":: skipping non-matching line: {lines}: {(row.Count == 0 ? "empty" : string.Join(",", row))}");
continue;
}
sb.AppendLine($"{row[0]}{SPLIT_CHAR}{row[1]}");
lines++;
}
Debug.Log($":: imported {lines} lines of dialogue\n{sb}");
File.WriteAllText(EDITOR_DialogueFile, sb.ToString());
if (!File.Exists(EDITOR_DialogueFile))
{
Debug.LogError($":: import failed: file doesn't exist: {EDITOR_DialogueFile}");
return 1;
}
return 0;
}
[MenuItem("ktyl/Import Dialogue")]
private static void ImportDialogueMenuItem()
{
Import();
}
}
#endif
#endregion
public static partial class DialogueDatabase
{
private const char SPLIT_CHAR = '|';
public const string DIALOGUE_FILENAME = "dialogue.data";
public static string DialogueFile
{
get
{
#if UNITY_EDITOR
// ensure file exists and run import if necessary
if (!File.Exists(EDITOR_DialogueFile) && Import() != 0) return null;
return EDITOR_DialogueFile;
#else
return Path.Combine(Application.dataPath, DIALOGUE_FILENAME);
#endif
}
}
static DialogueDatabase()
{
Debug.Log($":: building dialogue database from file at {DialogueFile}");
int count = 0;
foreach (var line in File.ReadLines(DialogueFile))
{
var parts = line.Split(SPLIT_CHAR);
var key = parts[0];
var text = parts[1];
if (string.IsNullOrEmpty(key) || string.IsNullOrEmpty(text))
{
Debug.LogWarning($"bad line in csv: {line}");
continue;
}
_dict[key] = text;
count++;
}
Debug.Log($":: imported {count} lines of dialogue");
}
private static readonly Dictionary<string, string> _dict = new Dictionary<string, string>();
public static string[] Keys => _dict.Keys.ToArray();
public static string ReadDialogue(string key)
{
return _dict.ContainsKey(key)
? _dict[key]
: $"<color=\"red\">MISSING[{key}]</color>";
}
}