public async Task LoadPlayLogAsync(string playLogCode) { var saveDbUrl = ConfigPopup.BaseUrl + "/playLog"; ProgressMessage.instance.Open("Loading play log"); playLogCode = playLogCode.Trim(); var url = string.Format("{0}/{1}", saveDbUrl, playLogCode); ConDebug.LogFormat("URL: {0}", url); try { using (var httpClient = new HttpClient()) { var getTask = await httpClient.GetAsync(url); if (getTask.IsSuccessStatusCode) { var text = await getTask.Content.ReadAsStringAsync(); var userPlayLogDataRoot = Json.Deserialize(text) as Dict; var userPlayLogDataFields = userPlayLogDataRoot["fields"] as Dict; var userPlayLogDataFieldsSaveData = userPlayLogDataFields["playLogData"] as Dict; var userPlayLogDataFieldsSaveDataStringValue = userPlayLogDataFieldsSaveData["bytesValue"] as string; var userPlayLogUncompressedSizeData = userPlayLogDataFields["playLogUncompressedSizeData"] as Dict; var userPlayLogUncompressedSizeDataIntegerValue = int.Parse(userPlayLogUncompressedSizeData["integerValue"] as string); var playLogDataBase64 = userPlayLogDataFieldsSaveDataStringValue; var playLogData = Convert.FromBase64String(playLogDataBase64); var playLogUncompressedData = new byte[userPlayLogUncompressedSizeDataIntegerValue]; LZ4Codec.Decode(playLogData, 0, playLogData.Length, playLogUncompressedData, 0, playLogUncompressedData.Length); readLogStream = new MemoryStream(playLogUncompressedData); ConDebug.LogFormat("Play Log Data Base64 ({0} bytes): {1}", playLogDataBase64 != null ? playLogDataBase64.Length : 0, playLogDataBase64); ConDebug.LogFormat("Play Log Data ({0} bytes - compresseed)", playLogData.Length); } else { Debug.LogError($"Loading play log failed - status code {getTask.StatusCode}"); } } } catch (Exception e) { Debug.LogError($"Play log upload exception: {e}"); } finally { // 어떤 경우가 됐든지 마지막으로는 진행 상황 창을 닫아야 한다. ProgressMessage.instance.Close(); } }
static bool SaveBlackSaveData(BlackSaveData blackSaveData) { //ConDebug.LogFormat("Start Saving JSON Data: {0}", JsonUtility.ToJson(blackSaveData)); var saveDataArray = MessagePackSerializer.Serialize(blackSaveData, Data.DefaultOptions); ConDebug.LogFormat("Saving path: {0}", SaveFileName); if (lastSaveDataArray != null && lastSaveDataArray.SequenceEqual(saveDataArray)) { ConDebug.LogFormat("Saving skipped since there is no difference made compared to last time saved."); } else { try { // 진짜 쓰자!! WriteAllBytesAtomically(SaveFileName, saveDataArray); // 마지막 저장 데이터 갱신 lastSaveDataArray = saveDataArray; ConDebug.Log($"{SaveFileName} Saved. (written to disk)"); // 유저 서비스를 위해 필요할 수도 있으니까 개발 중일 때는 base64 인코딩 버전 세이브 파일도 저장한다. // 실서비스 버전에서는 불필요한 기능이다. if (Application.isEditor) { var base64Path = SaveFileName + ".base64.txt"; ConDebug.LogFormat("Saving path (base64): {0}", base64Path); File.WriteAllText(base64Path, Convert.ToBase64String(saveDataArray)); ConDebug.Log($"{base64Path} Saved. (written to disk)"); } IncreaseSaveDataSlotAndWrite(); var lastBlackLevel = blackSaveData.lastClearedStageId; var gem = (blackSaveData.freeGemScUInt128 + blackSaveData.paidGemScUInt128).ToUInt128() .ToClampedLong(); BlackLogManager.Add(BlackLogEntry.Type.GameSaved, lastBlackLevel, gem); } catch (Exception e) { Debug.LogException(e); Debug.LogError("Writing to disk failed!!!"); ConfirmPopup.instance.Open("Writing to disk failed!!!"); BlackLogManager.Add(BlackLogEntry.Type.GameSaveFailure, 0, 0); return(false); } } return(true); }
static void GatherAllStaticLocalizedTextRef() { List <string> textRefList = new List <string>(); foreach (var root in SceneManager.GetActiveScene().GetRootGameObjects()) { foreach (var staticLocalizedText in root.GetComponentsInChildren <StaticLocalizedText>(true)) { textRefList.Add(staticLocalizedText.StrRef); } } textRefList = textRefList.Distinct().ToList(); textRefList.Sort(); File.WriteAllLines("textref.txt", textRefList.ToArray()); ConDebug.LogFormat("textref.txt written: {0} items", textRefList.Count); }
public void DebugPrintCloudMetadata(byte[] bytes) { var cloudMetadata = GetCloudMetadataFromBytes(bytes); if (cloudMetadata != null) { ConDebug.LogFormat("prevAccountLevel = {0}", cloudMetadata.level); ConDebug.LogFormat("prevAccountLevelExp = {0}", cloudMetadata.levelExp); ConDebug.LogFormat("prevAccountGem = {0}", cloudMetadata.gem); ConDebug.LogFormat("prevAccountGoldRate = {0}", cloudMetadata.goldRate); ConDebug.LogFormat("prevSaveDate = {0}", cloudMetadata.saveDate); } else { ConDebug.LogFormat("Cloud metadata is null."); } }
IEnumerator ProcessUserSaveCodeCoro(string userSaveCode, string domain) { var saveDbUrl = ConfigPopup.BaseUrl + "/" + domain; ProgressMessage.instance.Open("\\유저 세이브 코드 확인중...".Localized()); userSaveCode = userSaveCode.Trim(); var url = $"{saveDbUrl}/{userSaveCode}"; ConDebug.LogFormat("URL: {0}", url); using var request = UnityWebRequest.Get(url); yield return(request.SendWebRequest()); ProgressMessage.instance.Close(); if (request.result == UnityWebRequest.Result.ConnectionError) { ShortMessage.instance.Show("\\복구 정보 수신에 실패했습니다.".Localized(), true); } else { try { if (Json.Deserialize(request.downloadHandler.text) is Dict userSaveDataRoot) { // userSaveDataFields는 정렬되어 있지 않다. saveData, saveData, saveData3, ... 순으로 // 로드 시도하기 위해서 필터링 및 정렬한다. if (userSaveDataRoot["fields"] is Dict userSaveDataFields) { foreach (var fieldName in userSaveDataFields.Keys.Where(e => e.StartsWith("saveData")) .OrderBy(e => e)) { ConDebug.Log($"Checking save data field name '{fieldName}'..."); if (userSaveDataFields[fieldName] is Dict userSaveDataFieldsSaveData && userSaveDataFieldsSaveData.Keys.Count > 0) { var userSaveDataFieldsSaveDataStringValue = (userSaveDataFieldsSaveData.ContainsKey("bytesValue") ? userSaveDataFieldsSaveData["bytesValue"] : userSaveDataFieldsSaveData["stringValue"]) as string; var saveDataBase64 = userSaveDataFieldsSaveDataStringValue; var saveDataBytes = Convert.FromBase64String(saveDataBase64 ?? throw new NullReferenceException()); ConDebug.LogFormat("Save Data Base64 ({0} bytes): {1}", saveDataBase64.Length, saveDataBase64); if (saveDataBytes.Length > 0) { RestoreSaveDataAndLoadSplash(saveDataBytes); yield break; } ConDebug.Log($"Save data field name '{fieldName}' is empty!"); } else { ConDebug.Log($"Save data field name '{fieldName}' is empty!"); } } } } }
IEnumerator ProcessRecoveryCodeCoro(List <Exception> exceptionList, string st, string recoveryCode) { var recoveryDbUrl = ConfigPopup.BaseUrl + "/recovery"; ProgressMessage.instance.Open("\\복구 코드 확인중...".Localized()); recoveryCode = recoveryCode.Trim(); // 복구 코드를 특별히 입력하지 않았을 경우에는 Error Device ID가 기본으로 쓰인다. if (string.IsNullOrEmpty(recoveryCode)) { recoveryCode = GetOrCreateErrorDeviceId(); } // ReSharper disable once StringLiteralTypo else if (recoveryCode == "deleteall") { // 파일 삭제하고 새 게임 시작하는 개발자용 복구 코드 SaveLoadManager.DeleteSaveFileAndReloadScene(); yield break; } var url = $"{recoveryDbUrl}/{recoveryCode}"; using var request = UnityWebRequest.Get(url); yield return(request.SendWebRequest()); ProgressMessage.instance.Close(); if (request.result == UnityWebRequest.Result.ConnectionError) { ShortMessage.instance.Show("\\복구 정보 수신에 실패했습니다.".Localized(), true); } else { try { ConDebug.LogFormat("URL Text: {0}", request.downloadHandler.text); if (Json.Deserialize(request.downloadHandler.text) is Dict recoveryDataRoot) { foreach (var kv in recoveryDataRoot) { ConDebug.LogFormat("root key: {0}", kv.Key); } if (recoveryDataRoot["fields"] is Dict recoveryData) { foreach (var kv in recoveryData) { ConDebug.LogFormat("fields key: {0}", kv.Key); } foreach (var recovery in recoveryData) { var recoveryIndexParsed = int.TryParse(recovery.Key, out _); // 이미 받았거나 이상한 항목은 스킵 if (recoveryIndexParsed == false) { continue; } var fields = (Dict)((Dict)((Dict)recovery.Value)["mapValue"])["fields"]; var isValidErrorDeviceId = false; var saveDataBase64 = ""; byte[] saveDataBytes = null; var recoveryErrorDeviceId = ""; //var serviceValue = service.Value as foreach (var recoveryItem in fields) { if (recoveryItem.Key == "errorDeviceId") { recoveryErrorDeviceId = ((Dict)recoveryItem.Value)["stringValue"] as string; if (recoveryErrorDeviceId == GetOrCreateErrorDeviceId()) { isValidErrorDeviceId = true; } } else if (recoveryItem.Key == "saveData") { saveDataBase64 = ((Dict)recoveryItem.Value)["stringValue"] as string; if (string.IsNullOrEmpty(saveDataBase64) == false) { saveDataBytes = Convert.FromBase64String(saveDataBase64); } } } ConDebug.LogFormat("Error Device ID: {0}", GetOrCreateErrorDeviceId()); ConDebug.LogFormat("Recovery Error Device ID: {0}", recoveryErrorDeviceId); ConDebug.LogFormat("Save Data Base64 ({0} bytes): {1}", saveDataBase64?.Length ?? 0, saveDataBase64); if (isValidErrorDeviceId && saveDataBytes != null && saveDataBytes.Length > 0) { RestoreSaveDataAndLoadSplash(saveDataBytes); break; } } } } } catch { // 딱히 할 수 있는 게 없다 } // 여기까지 왔으면 복구가 제대로 안됐다는 뜻이다. ConfirmPopup.instance.Open(@"\$복구 코드 오류$".Localized(), () => SaveLoadManager.ProcessCriticalLoadError(exceptionList, st)); } }
public void LogFormat(string format, params object[] args) { ConDebug.LogFormat(format, args); }