diff --git a/Assets/000_assets/material/M_SquareFrame 1.mat b/Assets/000_assets/material/M_SquareFrame 1.mat
index f098d43e..88a8355b 100644
--- a/Assets/000_assets/material/M_SquareFrame 1.mat
+++ b/Assets/000_assets/material/M_SquareFrame 1.mat
@@ -213,7 +213,7 @@ Material:
- _Dst: 10
- _DstBlend: 0
- _DstBlendAlpha: 0
- - _EdgeValue: 0.040686816
+ - _EdgeValue: 0.9979626
- _EnvironmentReflections: 1
- _FNLfanxiangkaiguan: 0
- _Face: 1
@@ -258,7 +258,7 @@ Material:
- _Mask_scale: 1
- _Metallic: 0
- _OcclusionStrength: 1
- - _Opacity: 0.95931315
+ - _Opacity: 0.002037406
- _Parallax: 0.005
- _Pass: 0
- _QueueOffset: 0
diff --git a/Assets/FR2_Cache.asset b/Assets/FR2_Cache.asset
index 3678319f..c0f8f1c3 100644
--- a/Assets/FR2_Cache.asset
+++ b/Assets/FR2_Cache.asset
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:fc7866e0dae0b8d5c8fcb7bdbf58e682a75ed984ba1b151da5fcf6d07cc79e60
-size 8134239
+oid sha256:f3238b25d22219c867e93f6939ba3ef80afd14f856bd169b9941edfaf88805ff
+size 8363818
diff --git a/Assets/Fonts/zh-CN/Kongyuan Sans R SDF.asset b/Assets/Fonts/zh-CN/Kongyuan Sans R SDF.asset
index cea3608d..a81cc0af 100644
--- a/Assets/Fonts/zh-CN/Kongyuan Sans R SDF.asset
+++ b/Assets/Fonts/zh-CN/Kongyuan Sans R SDF.asset
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:dba243b05c4ba7ada5702bfc0d6fef0a8ad291339a4168b99dd0dcbdccd6e81f
-size 2201677
+oid sha256:a1e7732ea5290a6a4896c3a128bcf76c3c3283da4bc6f04434ad44d31cff610c
+size 102405
diff --git a/Assets/Plugins/Android/AndroidManifest.xml b/Assets/Plugins/Android/AndroidManifest.xml
new file mode 100644
index 00000000..9da7ccac
--- /dev/null
+++ b/Assets/Plugins/Android/AndroidManifest.xml
@@ -0,0 +1,27 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Assets/TapSDK/Core/link.xml.meta b/Assets/Plugins/Android/AndroidManifest.xml.meta
similarity index 75%
rename from Assets/TapSDK/Core/link.xml.meta
rename to Assets/Plugins/Android/AndroidManifest.xml.meta
index 81b141b7..29d60482 100644
--- a/Assets/TapSDK/Core/link.xml.meta
+++ b/Assets/Plugins/Android/AndroidManifest.xml.meta
@@ -1,5 +1,5 @@
fileFormatVersion: 2
-guid: aa2f8b129fc4c46ca9a18b1f4e61ee57
+guid: 0409f4966cdb7064eb86f782bd83211b
TextScriptImporter:
externalObjects: {}
userData:
diff --git a/Assets/Plugins/Easy Save 3/Resources/ES3/ES3Defaults.asset b/Assets/Plugins/Easy Save 3/Resources/ES3/ES3Defaults.asset
index 4802d886..be6ebb1f 100644
--- a/Assets/Plugins/Easy Save 3/Resources/ES3/ES3Defaults.asset
+++ b/Assets/Plugins/Easy Save 3/Resources/ES3/ES3Defaults.asset
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:83ce86ada500b08e61b2feda07083a6bc9bfc462f878721a62c3aa5849073bfe
-size 2228
+oid sha256:eb5f3e82eacb2bd8fa175f634cb4eddb3adbab8345ac16a829308ce9f32a64b9
+size 2265
diff --git a/Assets/Scenes/MenuScene.unity b/Assets/Scenes/MenuScene.unity
index 40b22278..74ec4de4 100644
--- a/Assets/Scenes/MenuScene.unity
+++ b/Assets/Scenes/MenuScene.unity
@@ -21925,6 +21925,7 @@ GameObject:
m_Component:
- component: {fileID: 1644203571}
- component: {fileID: 1644203570}
+ - component: {fileID: 1644203572}
m_Layer: 0
m_Name: ThirdPartyService
m_TagString: Untagged
@@ -21968,6 +21969,18 @@ Transform:
m_Children: []
m_Father: {fileID: 0}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
+--- !u!114 &1644203572
+MonoBehaviour:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 1644203569}
+ m_Enabled: 1
+ m_EditorHideFlags: 0
+ m_Script: {fileID: 11500000, guid: ce4f9cf53ae8deb498233195d542cf58, type: 3}
+ m_Name:
+ m_EditorClassIdentifier: IchniOnline::IchniOnline.Online.Logic.IchniProtocolHandler
--- !u!1 &1647879290
GameObject:
m_ObjectHideFlags: 0
diff --git a/Assets/Scripts/Online/Logic/AuthService.cs b/Assets/Scripts/Online/Logic/AuthService.cs
index a4753483..1d0f41bb 100644
--- a/Assets/Scripts/Online/Logic/AuthService.cs
+++ b/Assets/Scripts/Online/Logic/AuthService.cs
@@ -1,6 +1,8 @@
using System;
using System.Text;
+using System.Threading;
using Cysharp.Threading.Tasks;
+using IchniOnline.Online.Models;
using IchniOnline.Online.Network;
using IchniOnline.Online.Network.Models;
using TapSDK.Login;
@@ -30,11 +32,24 @@ namespace IchniOnline.Online.Logic
///
public static event Action OnLoginCanceled;
+ ///
+ /// TapTap 未绑定账号时触发,参数为 pendingBindOauthId 和浏览器绑定页面 URL
+ ///
+ public static event Action OnTapTapUnbound;
+
///
/// 是否正在进行登录流程,用于防止并发登录请求
///
public static bool IsLoggingIn { get; private set; }
+ ///
+ /// 当前未绑定的 TapTap oauthId
+ ///
+ private static string _pendingBindOauthId;
+ private static CancellationTokenSource _pollingCts;
+
+ private const string WebBaseUrl = "https://ichni.hoshino.fan";
+
#region TapTap Login
///
@@ -108,9 +123,23 @@ namespace IchniOnline.Online.Logic
if (result.IsSuccess && result.Data != null)
{
- LoginCacheManager.SaveAuthSession(result.Data.token, result.Data);
- IchniOnlineApiClient.Instance.JwtToken = result.Data.token;
- OnLoginSuccess?.Invoke(result.Data);
+ if (!string.IsNullOrEmpty(result.Data.pendingBindOauthId))
+ {
+ _pendingBindOauthId = result.Data.pendingBindOauthId;
+ var bindUrl = $"{WebBaseUrl}/bind?method=0&id={_pendingBindOauthId}";
+ OnTapTapUnbound?.Invoke(_pendingBindOauthId, bindUrl);
+ OpenBrowserBindPage(bindUrl);
+
+ _pollingCts?.Cancel();
+ _pollingCts = new CancellationTokenSource();
+ PollBindStatusAsync(_pendingBindOauthId, _pollingCts.Token).Forget();
+ }
+ else
+ {
+ LoginCacheManager.SaveAuthSession(result.Data.token, result.Data);
+ IchniOnlineApiClient.Instance.JwtToken = result.Data.token;
+ OnLoginSuccess?.Invoke(result.Data);
+ }
}
else if (result.IsSuccess && result.Data == null)
{
@@ -132,6 +161,94 @@ namespace IchniOnline.Online.Logic
}
}
+ private static void OpenBrowserBindPage(string url)
+ {
+ Application.OpenURL(url);
+ }
+
+ private static async UniTaskVoid PollBindStatusAsync(string oauthId, CancellationToken cancellationToken)
+ {
+ var startTime = DateTime.UtcNow;
+ var timeout = TimeSpan.FromMinutes(5);
+ var pollInterval = TimeSpan.FromSeconds(2);
+
+ while (!cancellationToken.IsCancellationRequested)
+ {
+ if (DateTime.UtcNow - startTime > timeout)
+ {
+ IsLoggingIn = false;
+ OnLoginFailed?.Invoke("绑定超时");
+ return;
+ }
+
+ try
+ {
+ var result = await IchniOnlineApiClient.Instance.GetAsync(
+ $"/api/auth/third-party/bind-status?oauthId={oauthId}",
+ cancellationToken);
+
+ if (result.IsSuccess && result.Data != null)
+ {
+ if (result.Data.status == "bound" && !string.IsNullOrEmpty(result.Data.token))
+ {
+ var loginResponse = new LoginResponseDto
+ {
+ token = result.Data.token,
+ user = result.Data.user
+ };
+
+ LoginCacheManager.SaveAuthSession(result.Data.token, loginResponse);
+ IchniOnlineApiClient.Instance.JwtToken = result.Data.token;
+ IsLoggingIn = false;
+ OnLoginSuccess?.Invoke(loginResponse);
+ return;
+ }
+ }
+ }
+ catch (Exception ex)
+ {
+ Debug.LogWarning($"[IchniOnlineAuthService] Polling error: {ex.Message}");
+ }
+
+ await UniTask.Delay(pollInterval,DelayType.Realtime,PlayerLoopTiming.Update,cancellationToken);
+ }
+ }
+
+ public static void HandleIchniProtocolCallback(string token)
+ {
+ if (string.IsNullOrEmpty(token))
+ {
+ OnLoginFailed?.Invoke("浏览器回调 token 为空");
+ return;
+ }
+
+ _pollingCts?.Cancel();
+ _pollingCts = null;
+ _pendingBindOauthId = null;
+
+ IchniOnlineApiClient.Instance.JwtToken = token;
+
+ LoginCacheData cachedData = LoginCacheManager.CachedData;
+ if (cachedData != null)
+ {
+ cachedData.jwtToken = token;
+ cachedData.hasServerSession = true;
+ }
+
+ OnLoginSuccess?.Invoke(new LoginResponseDto
+ {
+ token = token,
+ user = cachedData != null ? new UserResponseDto
+ {
+ userId = cachedData.userId,
+ username = cachedData.name,
+ displayName = cachedData.displayName,
+ avatarUrl = cachedData.avatarUrl,
+ permission = cachedData.permission
+ } : null
+ });
+ }
+
private static void UnsubscribeTapTapEvents(
Action onSuccess,
Action onCanceled,
diff --git a/Assets/Scripts/Online/Logic/IchniProtocolHandler.cs b/Assets/Scripts/Online/Logic/IchniProtocolHandler.cs
new file mode 100644
index 00000000..26d54f8c
--- /dev/null
+++ b/Assets/Scripts/Online/Logic/IchniProtocolHandler.cs
@@ -0,0 +1,108 @@
+using System;
+using UnityEngine;
+
+namespace IchniOnline.Online.Logic
+{
+ public class IchniProtocolHandler : MonoBehaviour
+ {
+ private static IchniProtocolHandler _instance;
+ public static IchniProtocolHandler Instance => _instance;
+
+ private void Awake()
+ {
+ if (_instance != null)
+ {
+ Destroy(gameObject);
+ return;
+ }
+
+ _instance = this;
+ DontDestroyOnLoad(gameObject);
+
+ Application.deepLinkActivated += OnDeepLinkActivated;
+
+ if (!string.IsNullOrEmpty(Application.absoluteURL))
+ {
+ OnDeepLinkActivated(Application.absoluteURL);
+ }
+ }
+
+ private void OnDestroy()
+ {
+ if (_instance == this)
+ {
+ Application.deepLinkActivated -= OnDeepLinkActivated;
+ }
+ }
+
+ private void OnDeepLinkActivated(string url)
+ {
+ if (string.IsNullOrEmpty(url))
+ {
+ Debug.LogWarning("[IchniProtocolHandler] Deep link URL is empty");
+ return;
+ }
+
+ Debug.Log($"[IchniProtocolHandler] Deep link activated: {url}");
+
+ if (url.StartsWith("ichni://auth"))
+ {
+ HandleAuthCallback(url);
+ }
+ else
+ {
+ Debug.LogWarning($"[IchniProtocolHandler] Unknown deep link: {url}");
+ }
+ }
+
+ private void HandleAuthCallback(string url)
+ {
+ try
+ {
+ var uri = new Uri(url);
+ var query = uri.Query.TrimStart('?');
+ var queryParams = ParseQueryString(query);
+ var token = queryParams.ContainsKey("token") ? queryParams["token"] : null;
+
+ if (!string.IsNullOrEmpty(token))
+ {
+ Debug.Log("[IchniProtocolHandler] Auth callback received, completing login");
+ IchniOnlineAuthService.HandleIchniProtocolCallback(token);
+ }
+ else
+ {
+ var error = queryParams.ContainsKey("error") ? queryParams["error"] : null;
+ if (!string.IsNullOrEmpty(error))
+ {
+ Debug.LogError($"[IchniProtocolHandler] Auth callback error: {error}");
+ }
+ else
+ {
+ Debug.LogError("[IchniProtocolHandler] Auth callback missing token");
+ }
+ }
+ }
+ catch (Exception ex)
+ {
+ Debug.LogError($"[IchniProtocolHandler] Failed to parse deep link: {ex.Message}");
+ }
+ }
+
+ private static System.Collections.Generic.Dictionary ParseQueryString(string query)
+ {
+ var result = new System.Collections.Generic.Dictionary();
+ if (string.IsNullOrEmpty(query)) return result;
+
+ var pairs = query.Split('&');
+ foreach (var pair in pairs)
+ {
+ var parts = pair.Split('=');
+ if (parts.Length == 2)
+ {
+ result[Uri.UnescapeDataString(parts[0])] = Uri.UnescapeDataString(parts[1]);
+ }
+ }
+ return result;
+ }
+ }
+}
diff --git a/Assets/Scripts/Online/Logic/IchniProtocolHandler.cs.meta b/Assets/Scripts/Online/Logic/IchniProtocolHandler.cs.meta
new file mode 100644
index 00000000..3c9f358e
--- /dev/null
+++ b/Assets/Scripts/Online/Logic/IchniProtocolHandler.cs.meta
@@ -0,0 +1,2 @@
+fileFormatVersion: 2
+guid: ce4f9cf53ae8deb498233195d542cf58
\ No newline at end of file
diff --git a/Assets/Scripts/Online/Network/ApiClient.cs b/Assets/Scripts/Online/Network/ApiClient.cs
index 9cbc9e42..df640df3 100644
--- a/Assets/Scripts/Online/Network/ApiClient.cs
+++ b/Assets/Scripts/Online/Network/ApiClient.cs
@@ -1,6 +1,7 @@
using System;
using System.IO;
using System.Text;
+using System.Threading;
using Best.HTTP;
using Cysharp.Threading.Tasks;
using IchniOnline.Online.Network.Models;
@@ -17,12 +18,12 @@ namespace IchniOnline.Online.Network
private static IchniOnlineApiClient _instance;
public static IchniOnlineApiClient Instance => _instance ??= new IchniOnlineApiClient();
- public string BaseUrl { get; set; } = "http://localhost:5308";
+ public string BaseUrl { get; set; } = "https://ichni.hoshino.fan";
public string JwtToken { get; set; }
private IchniOnlineApiClient() { }
- public async UniTask> GetAsync(string endpoint)
+ public async UniTask> GetAsync(string endpoint, CancellationToken cancellationToken = default)
{
string url = BuildUrl(endpoint);
var request = new HTTPRequest(new Uri(url), HTTPMethods.Get);
@@ -30,16 +31,20 @@ namespace IchniOnline.Online.Network
try
{
- var resp = await SendAsync(request);
+ var resp = await SendAsync(request, cancellationToken);
return ProcessResponse(resp);
}
+ catch (OperationCanceledException)
+ {
+ return ApiResult.Fail(ResponseCode.InternalServerError, "Request canceled");
+ }
catch (Exception ex)
{
return ApiResult.Fail(ResponseCode.InternalServerError, "Network error", ex.Message);
}
}
- public async UniTask> PostAsync(string endpoint, object body)
+ public async UniTask> PostAsync(string endpoint, object body, CancellationToken cancellationToken = default)
{
string url = BuildUrl(endpoint);
var request = new HTTPRequest(new Uri(url), HTTPMethods.Post);
@@ -54,9 +59,13 @@ namespace IchniOnline.Online.Network
try
{
- var resp = await SendAsync(request);
+ var resp = await SendAsync(request, cancellationToken);
return ProcessResponse(resp);
}
+ catch (OperationCanceledException)
+ {
+ return ApiResult.Fail(ResponseCode.InternalServerError, "Request canceled");
+ }
catch (Exception ex)
{
return ApiResult.Fail(ResponseCode.InternalServerError, "Network error", ex.Message);
@@ -81,12 +90,23 @@ namespace IchniOnline.Online.Network
}
}
- private UniTask SendAsync(HTTPRequest request)
+ private UniTask SendAsync(HTTPRequest request, CancellationToken cancellationToken = default)
{
var completionSource = new UniTaskCompletionSource();
+ var cancellationRegistration = default(CancellationTokenRegistration);
+
+ if (cancellationToken.CanBeCanceled)
+ {
+ cancellationRegistration = cancellationToken.Register(() =>
+ {
+ request.Abort();
+ completionSource.TrySetCanceled();
+ });
+ }
request.Callback = (req, resp) =>
{
+ cancellationRegistration.Dispose();
switch (req.State)
{
case HTTPRequestStates.Finished:
diff --git a/Assets/Scripts/Online/Network/Models/AuthDtos.cs b/Assets/Scripts/Online/Network/Models/AuthDtos.cs
index 191b9a3d..640ee3f3 100644
--- a/Assets/Scripts/Online/Network/Models/AuthDtos.cs
+++ b/Assets/Scripts/Online/Network/Models/AuthDtos.cs
@@ -32,6 +32,7 @@ namespace IchniOnline.Online.Network.Models
{
public string token;
public UserResponseDto user;
+ public string pendingBindOauthId; // 未绑定时有值,用于打开浏览器绑定页面
}
[Serializable]
@@ -43,4 +44,39 @@ namespace IchniOnline.Online.Network.Models
public string avatarUrl;
public int permission;
}
+
+ [Serializable]
+ public class PendingBindInfoDto
+ {
+ public string oauthId;
+ public string name;
+ public string avatarUrl;
+ public int method;
+ }
+
+ [Serializable]
+ public class BindExistingRequestDto
+ {
+ public string oauthId;
+ public string username;
+ public string encryptedPassword;
+ public string sessionKey;
+ }
+
+ [Serializable]
+ public class CreateAndBindRequestDto
+ {
+ public string oauthId;
+ public string username;
+ public string password;
+ public string displayName;
+ }
+
+ [Serializable]
+ public class BindStatusDto
+ {
+ public string status;
+ public string token;
+ public UserResponseDto user;
+ }
}
diff --git a/Assets/Scripts/Online/Util.meta b/Assets/Scripts/Online/Util.meta
new file mode 100644
index 00000000..267e54bc
--- /dev/null
+++ b/Assets/Scripts/Online/Util.meta
@@ -0,0 +1,3 @@
+fileFormatVersion: 2
+guid: 443958d017e24a7da33ad36fecf13d33
+timeCreated: 1781771657
\ No newline at end of file
diff --git a/Assets/Scripts/Online/Util/EditorFileLogger.cs b/Assets/Scripts/Online/Util/EditorFileLogger.cs
new file mode 100644
index 00000000..dcb13828
--- /dev/null
+++ b/Assets/Scripts/Online/Util/EditorFileLogger.cs
@@ -0,0 +1,130 @@
+namespace IchniOnline.Online.Util
+{
+ using System;
+using System.IO;
+using System.Text;
+using UnityEditor;
+using UnityEngine;
+
+[InitializeOnLoad]
+public static class EditorFileLogger
+{
+ private static readonly object LockObj = new();
+ private static StreamWriter writer;
+
+ static EditorFileLogger()
+ {
+ try
+ {
+ string logDir = Path.Combine(
+ Environment.GetFolderPath(Environment.SpecialFolder.Desktop),
+ "UnityEditorLogs");
+
+ Directory.CreateDirectory(logDir);
+
+ string logFile = Path.Combine(
+ logDir,
+ $"Editor_{DateTime.Now:yyyyMMdd_HHmmss}.log");
+
+ writer = new StreamWriter(
+ new FileStream(
+ logFile,
+ FileMode.Create,
+ FileAccess.Write,
+ FileShare.ReadWrite,
+ 4096,
+ FileOptions.WriteThrough),
+ Encoding.UTF8);
+
+ writer.AutoFlush = true;
+
+ Application.logMessageReceivedThreaded += OnLog;
+
+ EditorApplication.quitting += Shutdown;
+ EditorApplication.playModeStateChanged += OnPlayModeStateChanged;
+
+ WriteLine("====================================");
+ WriteLine($"Unity Version : {Application.unityVersion}");
+ WriteLine($"Project : {Application.productName}");
+ WriteLine($"Started : {DateTime.Now:yyyy-MM-dd HH:mm:ss.fff}");
+ WriteLine("====================================");
+ }
+ catch (Exception e)
+ {
+ Debug.LogException(e);
+ }
+ }
+
+ private static void OnPlayModeStateChanged(PlayModeStateChange state)
+ {
+ switch (state)
+ {
+ case PlayModeStateChange.ExitingEditMode:
+ WriteLine("[EDITOR] >>> Preparing To Enter Play Mode");
+ break;
+
+ case PlayModeStateChange.EnteredPlayMode:
+ WriteLine("[EDITOR] >>> Entered Play Mode");
+ break;
+
+ case PlayModeStateChange.ExitingPlayMode:
+ WriteLine("[EDITOR] <<< Exiting Play Mode");
+ break;
+
+ case PlayModeStateChange.EnteredEditMode:
+ WriteLine("[EDITOR] <<< Returned To Edit Mode");
+ break;
+ }
+ }
+
+ private static void OnLog(
+ string condition,
+ string stackTrace,
+ LogType type)
+ {
+ lock (LockObj)
+ {
+ if (writer == null)
+ return;
+
+ writer.WriteLine(
+ $"[{DateTime.Now:yyyy-MM-dd HH:mm:ss.fff}] [{type}] {condition}");
+
+ if (!string.IsNullOrWhiteSpace(stackTrace))
+ {
+ writer.WriteLine(stackTrace);
+ }
+
+ writer.Flush();
+ }
+ }
+
+ private static void WriteLine(string message)
+ {
+ lock (LockObj)
+ {
+ if (writer == null)
+ return;
+
+ writer.WriteLine(
+ $"[{DateTime.Now:yyyy-MM-dd HH:mm:ss.fff}] {message}");
+
+ writer.Flush();
+ }
+ }
+
+ private static void Shutdown()
+ {
+ EditorApplication.playModeStateChanged -= OnPlayModeStateChanged;
+ EditorApplication.quitting -= Shutdown;
+ Application.logMessageReceivedThreaded -= OnLog;
+
+ lock (LockObj)
+ {
+ writer?.Flush();
+ writer?.Dispose();
+ writer = null;
+ }
+ }
+}
+}
\ No newline at end of file
diff --git a/Assets/Scripts/Online/Util/EditorFileLogger.cs.meta b/Assets/Scripts/Online/Util/EditorFileLogger.cs.meta
new file mode 100644
index 00000000..22bfdb6d
--- /dev/null
+++ b/Assets/Scripts/Online/Util/EditorFileLogger.cs.meta
@@ -0,0 +1,3 @@
+fileFormatVersion: 2
+guid: 2169063fd004462880557c15613be8f9
+timeCreated: 1781771972
\ No newline at end of file
diff --git a/Assets/Scripts/Online/Util/PresisentFileLogger.cs b/Assets/Scripts/Online/Util/PresisentFileLogger.cs
new file mode 100644
index 00000000..34d7602c
--- /dev/null
+++ b/Assets/Scripts/Online/Util/PresisentFileLogger.cs
@@ -0,0 +1,141 @@
+using System;
+using System.IO;
+using System.Text;
+using UnityEngine;
+namespace IchniOnline.Online.Util
+{
+ public class PersistentFileLogger : MonoBehaviour
+ {
+ private static StreamWriter _writer;
+ private static readonly object LockObj = new object();
+
+ private string _logFilePath;
+
+ [Header("日志文件夹名称")]
+ public string logFolderName = "Logs";
+
+ [Header("启动时打印日志路径")]
+ public bool printLogPath = true;
+
+ private void Awake()
+ {
+ DontDestroyOnLoad(gameObject);
+
+ InitializeLogger();
+ }
+
+ private void InitializeLogger()
+ {
+ if (_writer != null)
+ return;
+
+ string logDir = Path.Combine(
+ Application.persistentDataPath,
+ logFolderName);
+
+ Directory.CreateDirectory(logDir);
+
+ string fileName =
+ $"log_{DateTime.Now:yyyyMMdd_HHmmss}.txt";
+
+ _logFilePath = Path.Combine(logDir, fileName);
+
+ _writer = new StreamWriter(
+ new FileStream(
+ _logFilePath,
+ FileMode.Create,
+ FileAccess.Write,
+ FileShare.ReadWrite,
+ 4096,
+ FileOptions.WriteThrough),
+ Encoding.UTF8);
+
+ _writer.AutoFlush = true;
+
+ Application.logMessageReceivedThreaded += OnLogReceived;
+
+ WriteRaw("==================================================");
+ WriteRaw($"Unity Version : {Application.unityVersion}");
+ WriteRaw($"Platform : {Application.platform}");
+ WriteRaw($"Start Time : {DateTime.Now:yyyy-MM-dd HH:mm:ss.fff}");
+ WriteRaw($"Log File : {_logFilePath}");
+ WriteRaw("==================================================");
+
+ if (printLogPath)
+ {
+ Debug.Log($"Log file: {_logFilePath}");
+ }
+ }
+
+ private void OnDestroy()
+ {
+ ShutdownLogger();
+ }
+
+ private void OnApplicationQuit()
+ {
+ ShutdownLogger();
+ }
+
+ private void ShutdownLogger()
+ {
+ Application.logMessageReceivedThreaded -= OnLogReceived;
+
+ lock (LockObj)
+ {
+ if (_writer != null)
+ {
+ WriteRaw("Application Exit");
+
+ _writer.Flush();
+ _writer.Close();
+ _writer.Dispose();
+
+ _writer = null;
+ }
+ }
+ }
+
+ private static void OnLogReceived(
+ string condition,
+ string stackTrace,
+ LogType type)
+ {
+ lock (LockObj)
+ {
+ if (_writer == null)
+ return;
+
+ string timestamp =
+ DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff");
+
+ _writer.WriteLine(
+ $"[{timestamp}] [{type}] {condition}");
+
+ if (type == LogType.Error ||
+ type == LogType.Exception ||
+ type == LogType.Assert)
+ {
+ if (!string.IsNullOrWhiteSpace(stackTrace))
+ {
+ _writer.WriteLine(stackTrace);
+ }
+ }
+
+ _writer.Flush();
+ }
+ }
+
+ private static void WriteRaw(string message)
+ {
+ lock (LockObj)
+ {
+ if (_writer == null)
+ return;
+
+ _writer.WriteLine(message);
+ _writer.Flush();
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/Assets/Scripts/Online/Util/PresisentFileLogger.cs.meta b/Assets/Scripts/Online/Util/PresisentFileLogger.cs.meta
new file mode 100644
index 00000000..7f62b278
--- /dev/null
+++ b/Assets/Scripts/Online/Util/PresisentFileLogger.cs.meta
@@ -0,0 +1,3 @@
+fileFormatVersion: 2
+guid: 7e726f6c24c3464cbc0ccc66f372c55f
+timeCreated: 1781771683
\ No newline at end of file
diff --git a/Assets/TapSDK/Core/link.xml b/Assets/TapSDK/Core/link.xml
deleted file mode 100644
index d46dc3dd..00000000
--- a/Assets/TapSDK/Core/link.xml
+++ /dev/null
@@ -1,4 +0,0 @@
-
-
-
-
\ No newline at end of file
diff --git a/Assets/TapSDK/Login/link.xml b/Assets/TapSDK/Login/link.xml
deleted file mode 100644
index 3ab6b6a0..00000000
--- a/Assets/TapSDK/Login/link.xml
+++ /dev/null
@@ -1,4 +0,0 @@
-
-
-
-
\ No newline at end of file
diff --git a/Assets/TapSDK/Login/link.xml.meta b/Assets/TapSDK/Login/link.xml.meta
deleted file mode 100644
index 9037108d..00000000
--- a/Assets/TapSDK/Login/link.xml.meta
+++ /dev/null
@@ -1,7 +0,0 @@
-fileFormatVersion: 2
-guid: e204f0586cdf241c9aaa0ff5e8934163
-TextScriptImporter:
- externalObjects: {}
- userData:
- assetBundleName:
- assetBundleVariant:
diff --git a/ProjectSettings/ProjectSettings.asset b/ProjectSettings/ProjectSettings.asset
index 179e72ba..498d25c9 100644
--- a/ProjectSettings/ProjectSettings.asset
+++ b/ProjectSettings/ProjectSettings.asset
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:e3441711e207198b66b8ac19703e560a52a738e768f8a63c39d479cb17dcb55b
-size 29333
+oid sha256:46338b4fb0422e46d83504c1d3874f27990e4d277531fc0e4695033123a24cb5
+size 29340
diff --git a/UserSettings/Layouts/default-6000.dwlt b/UserSettings/Layouts/default-6000.dwlt
index 6ac3ca60..d3dfa67e 100644
--- a/UserSettings/Layouts/default-6000.dwlt
+++ b/UserSettings/Layouts/default-6000.dwlt
@@ -14,16 +14,16 @@ MonoBehaviour:
m_EditorClassIdentifier: UnityEditor.dll::UnityEditor.ContainerWindow
m_PixelRect:
serializedVersion: 2
- x: 1
- y: 66
- width: 1598
- height: 886
+ x: 0
+ y: 43
+ width: 2560
+ height: 1349
m_ShowMode: 4
- m_Title: Inspector
+ m_Title: Game
m_RootView: {fileID: 2}
m_MinSize: {x: 875, y: 300}
m_MaxSize: {x: 10000, y: 10000}
- m_Maximized: 0
+ m_Maximized: 1
--- !u!114 &2
MonoBehaviour:
m_ObjectHideFlags: 52
@@ -44,8 +44,8 @@ MonoBehaviour:
serializedVersion: 2
x: 0
y: 0
- width: 1598
- height: 886
+ width: 2560
+ height: 1349
m_MinSize: {x: 875, y: 300}
m_MaxSize: {x: 10000, y: 10000}
m_UseTopView: 1
@@ -69,7 +69,7 @@ MonoBehaviour:
serializedVersion: 2
x: 0
y: 0
- width: 1598
+ width: 2560
height: 36
m_MinSize: {x: 50, y: 50}
m_MaxSize: {x: 4000, y: 4000}
@@ -90,8 +90,8 @@ MonoBehaviour:
m_Position:
serializedVersion: 2
x: 0
- y: 866
- width: 1598
+ y: 1329
+ width: 2560
height: 20
m_MinSize: {x: 0, y: 0}
m_MaxSize: {x: 0, y: 0}
@@ -113,12 +113,12 @@ MonoBehaviour:
serializedVersion: 2
x: 0
y: 36
- width: 1598
- height: 830
+ width: 2560
+ height: 1293
m_MinSize: {x: 300, y: 112}
m_MaxSize: {x: 24288, y: 16192}
vertical: 1
- controlID: 52
+ controlID: 77
draggingID: 0
--- !u!114 &6
MonoBehaviour:
@@ -139,12 +139,12 @@ MonoBehaviour:
serializedVersion: 2
x: 0
y: 0
- width: 1598
- height: 830
+ width: 2560
+ height: 1293
m_MinSize: {x: 300, y: 112}
m_MaxSize: {x: 24288, y: 16192}
vertical: 0
- controlID: 53
+ controlID: 78
draggingID: 0
--- !u!114 &7
MonoBehaviour:
@@ -165,12 +165,12 @@ MonoBehaviour:
serializedVersion: 2
x: 0
y: 0
- width: 1119
- height: 830
+ width: 1793
+ height: 1293
m_MinSize: {x: 200, y: 112}
m_MaxSize: {x: 16192, y: 16192}
vertical: 1
- controlID: 54
+ controlID: 79
draggingID: 0
--- !u!114 &8
MonoBehaviour:
@@ -191,8 +191,8 @@ MonoBehaviour:
serializedVersion: 2
x: 0
y: 0
- width: 1119
- height: 582
+ width: 1793
+ height: 907
m_MinSize: {x: 200, y: 56}
m_MaxSize: {x: 16192, y: 8096}
vertical: 0
@@ -215,8 +215,8 @@ MonoBehaviour:
serializedVersion: 2
x: 0
y: 0
- width: 279
- height: 582
+ width: 447
+ height: 907
m_MinSize: {x: 201, y: 226}
m_MaxSize: {x: 4001, y: 4026}
m_ActualView: {fileID: 15}
@@ -239,10 +239,10 @@ MonoBehaviour:
m_Children: []
m_Position:
serializedVersion: 2
- x: 279
+ x: 447
y: 0
- width: 840
- height: 582
+ width: 1346
+ height: 907
m_MinSize: {x: 202, y: 226}
m_MaxSize: {x: 4002, y: 4026}
m_ActualView: {fileID: 17}
@@ -268,9 +268,9 @@ MonoBehaviour:
m_Position:
serializedVersion: 2
x: 0
- y: 582
- width: 1119
- height: 248
+ y: 907
+ width: 1793
+ height: 386
m_MinSize: {x: 101, y: 126}
m_MaxSize: {x: 4001, y: 4026}
m_ActualView: {fileID: 19}
@@ -296,10 +296,10 @@ MonoBehaviour:
m_Children: []
m_Position:
serializedVersion: 2
- x: 1119
+ x: 1793
y: 0
- width: 479
- height: 830
+ width: 767
+ height: 1293
m_MinSize: {x: 276, y: 76}
m_MaxSize: {x: 4001, y: 4026}
m_ActualView: {fileID: 22}
@@ -332,8 +332,8 @@ MonoBehaviour:
m_Pos:
serializedVersion: 2
x: 0
- y: 0
- width: 1598
+ y: 43
+ width: 2560
height: 36
m_SerializedDataModeController:
m_DataMode: 0
@@ -559,12 +559,12 @@ MonoBehaviour:
displayed: 1
id: Play Mode Controls
index: 0
- contents: '{"m_Layout":4,"m_Collapsed":false,"m_Folded":false,"m_Floating":false,"m_FloatingSnapOffset":{"x":-781.333251953125,"y":-36.0},"m_SnapOffsetDelta":{"x":0.0,"y":0.0},"m_FloatingSnapCorner":3,"m_Size":{"x":0.0,"y":0.0},"m_SizeOverridden":false}'
+ contents: '{"m_Layout":4,"m_Collapsed":false,"m_Folded":false,"m_Floating":false,"m_FloatingSnapOffset":{"x":93.666748046875,"y":0.0},"m_SnapOffsetDelta":{"x":0.0,"y":0.0},"m_FloatingSnapCorner":0,"m_Size":{"x":0.0,"y":0.0},"m_SizeOverridden":false}'
floating: 0
collapsed: 0
- snapOffset: {x: -781.33325, y: -36}
+ snapOffset: {x: 93.66675, y: 0}
snapOffsetDelta: {x: 0, y: 0}
- snapCorner: 3
+ snapCorner: 0
layout: 4
size: {x: 0, y: 0}
sizeOverridden: 0
@@ -808,9 +808,9 @@ MonoBehaviour:
m_Pos:
serializedVersion: 2
x: 0
- y: 24
- width: 278
- height: 556
+ y: 79
+ width: 446
+ height: 881
m_SerializedDataModeController:
m_DataMode: 0
m_PreferredDataMode: 0
@@ -831,7 +831,7 @@ MonoBehaviour:
m_LastClickedID:
m_Data: 0
m_ExpandedIDs:
- - m_Data: -1324
+ - m_Data: -1340
m_RenameOverlay:
m_UserAcceptedRename: 0
m_Name:
@@ -1661,10 +1661,10 @@ MonoBehaviour:
m_TextWithWhitespace: "Game\u200B"
m_Pos:
serializedVersion: 2
- x: 280
- y: 24
- width: 838
- height: 556
+ x: 447
+ y: 79
+ width: 1344
+ height: 881
m_SerializedDataModeController:
m_DataMode: 0
m_PreferredDataMode: 0
@@ -1722,23 +1722,23 @@ MonoBehaviour:
serializedVersion: 2
x: 0
y: 21
- width: 838
- height: 535
- m_Scale: {x: 0.43645832, y: 0.43645835}
- m_Translation: {x: 419, y: 267.5}
+ width: 1344
+ height: 860
+ m_Scale: {x: 0.7, y: 0.7}
+ m_Translation: {x: 672, y: 430}
m_MarginLeft: 0
m_MarginRight: 0
m_MarginTop: 0
m_MarginBottom: 0
m_LastShownAreaInsideMargins:
serializedVersion: 2
- x: -960.00006
- y: -612.8878
- width: 1920.0001
- height: 1225.7756
+ x: -960
+ y: -614.2857
+ width: 1920
+ height: 1228.5714
m_MinimalGUI: 1
- m_defaultScale: 0.43645832
- m_LastWindowPixelSize: {x: 838, y: 556}
+ m_defaultScale: 0.7
+ m_LastWindowPixelSize: {x: 1344, y: 881}
m_ClearInEditMode: 1
m_NoCameraWarning: 1
m_LowResolutionForAspectRatios: 00000000000000000000
@@ -1875,9 +1875,9 @@ MonoBehaviour:
m_Pos:
serializedVersion: 2
x: 0
- y: 606
- width: 1118
- height: 222
+ y: 986
+ width: 1792
+ height: 360
m_SerializedDataModeController:
m_DataMode: 0
m_PreferredDataMode: 0
@@ -1993,10 +1993,10 @@ MonoBehaviour:
m_TextWithWhitespace: "Inspector\u200B"
m_Pos:
serializedVersion: 2
- x: 1120
- y: 24
- width: 478
- height: 804
+ x: 1793
+ y: 79
+ width: 766
+ height: 1267
m_SerializedDataModeController:
m_DataMode: 0
m_PreferredDataMode: 0
diff --git a/ichni Official_WwiseProject/.cache/LMDB/data.mdb b/ichni Official_WwiseProject/.cache/LMDB/data.mdb
index 427603de..750e4c60 100644
Binary files a/ichni Official_WwiseProject/.cache/LMDB/data.mdb and b/ichni Official_WwiseProject/.cache/LMDB/data.mdb differ
diff --git a/ichni Official_WwiseProject/ichni Official_WwiseProject.wxtal.validationcache b/ichni Official_WwiseProject/ichni Official_WwiseProject.wxtal.validationcache
index f4dfa941..8edbbf6c 100644
--- a/ichni Official_WwiseProject/ichni Official_WwiseProject.wxtal.validationcache
+++ b/ichni Official_WwiseProject/ichni Official_WwiseProject.wxtal.validationcache
@@ -15,7 +15,7 @@
-
+
diff --git a/ichni Official_WwiseProject/ichni Official_WwiseProject.wxtal.wsettings b/ichni Official_WwiseProject/ichni Official_WwiseProject.wxtal.wsettings
index 83174a67..fbda3c45 100644
--- a/ichni Official_WwiseProject/ichni Official_WwiseProject.wxtal.wsettings
+++ b/ichni Official_WwiseProject/ichni Official_WwiseProject.wxtal.wsettings
@@ -34,10 +34,12 @@
+
+
@@ -48,9 +50,9 @@
-
+
-
+
@@ -263,7 +265,7 @@
-
+