using System; using System.Collections.Generic; using System.Security.Cryptography; using System.Text; using UnityEngine; using UnityEngine.Serialization; namespace Touka { public class Server : NormalSingleton { // debug private const string BASE_URL = "https://tk.dgtverse.cn/"; public void Login(LoginType loginType, Action callback) { var deviceId = PlayerPrefs.GetString("device_id", ""); if (string.IsNullOrEmpty(deviceId)) { deviceId = SystemInfo.deviceUniqueIdentifier; PlayerPrefs.SetString("device_id", deviceId); } var thirdUserId = ""; if (loginType == LoginType.LOGIN_BY_GUESTER) { thirdUserId = deviceId.Replace("-", ""); } else if (loginType == LoginType.LOGIN_BY_GOOGLE) { thirdUserId = PlayerPrefs.GetString("google_user_id"); } else if (loginType == LoginType.LOGIN_BY_FACEBOOK) { thirdUserId = PlayerPrefs.GetString("facebook_user_id"); } var body = new Dictionary() { ["user_type"] = (int)loginType, ["third_uid"] = thirdUserId, ["user_id"] = PlayerPrefs.GetString("user_id") }; Post("ztp/game/user/login", body, callback); } private static void Post(string url, Dictionary args, Action callback, Dictionary headers = null) { if (args == null) { args = new Dictionary(); } if (headers == null) { headers = new Dictionary(); } AddBaseParameters(args); EncryptionParameters(args); var requestBody = ConvertDictionaryToJson(args); Debug.Log("[server]" + url); Debug.Log("[server]" + requestBody); RequestHandler.Instance.SendPostRequest(BASE_URL + url, requestBody, headers, (code, res) => { if (code == 0) { var resp = JsonUtility.FromJson>(res); callback(resp.code == 0 ? 0 : resp.code, resp.msg, resp.data); } else { callback.Invoke(code, "", (T)new object()); } Debug.Log("[server]" + "[res] " + res); }); } private static void Get(string url, Action callback, Dictionary headers = null) { if (headers == null) { headers = new Dictionary(); } RequestHandler.Instance.SendGetRequest(BASE_URL + url, headers, (code, res) => { if (code == 0) { var resp = JsonUtility.FromJson>(res); callback(resp.code == 0 ? 0 : resp.code, resp.msg, resp.data); } else { callback.Invoke(code, "", (T)new object()); } Debug.Log("[server]" + "[res] " + res); }); } private static string GetMD5Hash(string input) { using (var md5 = MD5.Create()) { var inputBytes = Encoding.ASCII.GetBytes(input); var hashBytes = md5.ComputeHash(inputBytes); var builder = new StringBuilder(); foreach (var t in hashBytes) { builder.Append(t.ToString("x2")); // Convert byte to hexadecimal string } return builder.ToString(); } } private static void EncryptionParameters(Dictionary args) { const string secretKey = "tk~!@#$%^&*()_+0708"; var signString = $"{secretKey}platform={args["platform"]}packagename={args["package_name"]}channel={args["channel"]}appversion={args["app_version"]}appversioncode={args["app_version_code"]}language={args["language"]}ip={args["ip"]}ts={args["ts"]}"; var sign = GetMD5Hash(signString); args["sign"] = sign; } private static void AddBaseParameters(Dictionary args) { args.Add("platform", "Unity"); args.Add("package_name", "Unity"); args.Add("channel", "Unity"); args.Add("app_version", "1.0.0"); args.Add("app_version_code", "1"); args.Add("language", "ZH"); args.Add("ip", ""); args.Add("device_id", PlayerPrefs.GetString("device_id")); // var time = (int)Time.time; var currentTime = DateTime.Now; var timeSpan = currentTime - new DateTime(1970, 1, 1, 8, 0, 0, DateTimeKind.Utc); var timestamp = (int)(timeSpan.TotalMilliseconds / 1000); args.Add("ts", "" + timestamp); } public static string ConvertDictionaryToJson(Dictionary dictionary) { StringBuilder jsonBuilder = new StringBuilder(); jsonBuilder.Append("{"); int count = 0; foreach (KeyValuePair kvp in dictionary) { string key = kvp.Key; object value = kvp.Value; jsonBuilder.AppendFormat("\"{0}\":", key); if (value is int || value is float || value is bool) { jsonBuilder.Append(value.ToString().ToLower()); } else if (value is string) { jsonBuilder.AppendFormat("\"{0}\"", value); } else { // Handle other types or nested dictionaries recursively Dictionary nestedDictionary = value as Dictionary; if (nestedDictionary != null) { string nestedJson = ConvertDictionaryToJson(nestedDictionary); jsonBuilder.Append(nestedJson); } } count++; if (count < dictionary.Count) { jsonBuilder.Append(","); } } jsonBuilder.Append("}"); return jsonBuilder.ToString(); } public void DeleteAccount(string userId, Action callback) { var args = new Dictionary { { "user_id", userId } }; Post("ztp/game/user/delete", args, (code, msg, obj) => { callback.Invoke(code, code == 0 ? userId : msg); }); } public void SaveCloudArchiving(string userId, string token, string content, Action callback) { var args = new Dictionary { { "user_id", userId }, { "token", token }, { "content", content } }; var headers = new Dictionary { { "Authorization", "a5ca9093ac792ed386b641281eded3b1" } }; Post("ztp/third/game/user/progress/save", args, (code, msg, obj) => { callback.Invoke(code, msg); }, headers); } public void DetailCloudArchiving(string userId, string token, Action callback) { var headers = new Dictionary { { "Authorization", "a5ca9093ac792ed386b641281eded3b1" } }; Get($"ztp/third/game/user/progress/detail?user_id={userId}&token={token}", (code, msg, content) => { callback(code, msg, content.content); }, headers); } public void Bind(LoginType loginType, BindType bindType, string thirdUid, string userId, Action callback) { var args = new Dictionary { { "user_type", (int)loginType }, { "third_uid", thirdUid }, { "user_id", userId }, { "is_force", (int)bindType }, }; Post("ztp/game/user/bind", args, callback); } } [System.Serializable] public struct Response { public int code; public string msg; public T data; } [System.Serializable] public struct LoginInfo { public string user_id; public string token; public int user_type; public int first_login; } [System.Serializable] public struct Bind { public string user_id; public string token; public string[] user_ids; } [System.Serializable] public struct Content { public string content; } }