TH1/Unity/Assets/Scripts/TH1_Logic/CrashSight/CrashSightManager.cs
2026-06-08 11:50:03 +08:00

283 lines
10 KiB
C#

/*
* @Author: 白哉
* @Description:
* @Date: 2025年07月03日 星期四 10:07:49
* @Modify:
*/
using System.Text;
using Logic.Config;
using RuntimeData;
using TH1_Core.Managers;
using TH1_Logic.Core;
using TH1_Logic.Net;
using UnityEngine;
namespace Logic.CrashSight
{
public class CrashSightManager
{
public static CrashSightManager Instance => new CrashSightManager();
private const string CrashSightDeviceIdFallbackKey = "TH1_CrashSightDeviceId";
private static string _runtimeFallbackDeviceId;
private static ulong _reportedSteamUserId;
private CrashSightManager() { }
public void Initialize()
{
CrashSightAgent.ConfigCrashReporter(1);
// 设置上报的目标域名,请根据项目需求进行填写。(必填)
CrashSightAgent.ConfigCrashServerUrl("pc.crashsight.qq.com");
// 设置上报所指向的APP ID, 并进行初始化。APPID可以在管理端更多->产品设置->产品信息中找到。
CrashSightAgent.InitWithAppId("01076c49ce");
var deviceId = GetCrashSightDeviceId();
CrashSightAgent.SetDeviceId(deviceId);
CrashSightAgent.SetUserValue("DeviceId", deviceId);
}
public static void UpdateSteamUserId(ulong steamUserId)
{
if (steamUserId == 0 || !CrashSightAgent.IsInitialized || _reportedSteamUserId == steamUserId) return;
try
{
var value = steamUserId.ToString();
CrashSightAgent.SetUserId(value);
CrashSightAgent.SetUserValue("SteamId", value);
CrashSightAgent.SetUserValue("MemberId", value);
_reportedSteamUserId = steamUserId;
}
catch (System.Exception e)
{
Debug.LogWarning($"CrashSight SetSteamUserId failed: {e.Message}");
}
}
public static string GetCrashSightDeviceId()
{
try
{
var deviceId = SystemInfo.deviceUniqueIdentifier;
if (!string.IsNullOrEmpty(deviceId) && deviceId != SystemInfo.unsupportedIdentifier)
return deviceId;
var cachedId = PlayerPrefs.GetString(CrashSightDeviceIdFallbackKey, "");
if (!string.IsNullOrEmpty(cachedId))
return cachedId;
cachedId = $"th1-{System.Guid.NewGuid():N}";
PlayerPrefs.SetString(CrashSightDeviceIdFallbackKey, cachedId);
PlayerPrefs.Save();
return cachedId;
}
catch
{
if (string.IsNullOrEmpty(_runtimeFallbackDeviceId))
_runtimeFallbackDeviceId = $"th1-device-id-unavailable-{System.Guid.NewGuid():N}";
return _runtimeFallbackDeviceId;
}
}
}
public static class BoatUnitOnLandDiagnostic
{
private static bool _diagnosticFailedLogged;
public static void ReportIfNeeded(
MapData mapData,
UnitData unitData,
GridData gridData,
string source,
UnitFullType? previousType = null,
UnitFullType? requestedType = null)
{
try
{
if (mapData != Main.MapData) return;
if (unitData == null || gridData == null) return;
if (gridData.Terrain != TerrainType.Land) return;
if (mapData.UnitMap == null || mapData.GridMap == null) return;
if (!mapData.UnitMap.GetUnitDataByUnitId(unitData.Id, out var currentUnit) || currentUnit == null) return;
var landType = currentUnit.GetLandType();
if (landType != LandType.WaterAndAshore && landType != LandType.WaterOnly) return;
mapData.GetGridIdByUnitId(currentUnit.Id, out var boundGridId);
mapData.GetCityIdByUnitId(currentUnit.Id, out var cityId);
mapData.GetPlayerIdByUnitId(currentUnit.Id, out var playerId);
var sb = new StringBuilder(1536);
sb.AppendLine("[BoatUnitOnLandState] 船形态Unit停留在陆地格-源头诊断");
sb.Append("Source=").Append(source ?? "null")
.Append(", MapId=").Append(mapData.MapID)
.Append(", ActionIndex=").Append(mapData.Net?.Actions?.Count ?? 0)
.Append(", PresentationBusy=").Append(PresentationManager.Busy)
.Append(", BusyType=").Append(PresentationManager.BusyType ?? "null")
.AppendLine();
AppendFullType(sb, "PreviousType", previousType);
sb.Append(", ");
AppendFullType(sb, "RequestedType", requestedType);
sb.Append(", ");
AppendFullType(sb, "CurrentType", currentUnit.UnitFullType);
sb.AppendLine();
sb.Append("Unit: id=").Append(currentUnit.Id)
.Append(", hp=").Append(currentUnit.Health)
.Append(", alive=").Append(currentUnit.IsAlive())
.Append(", validOnMap=").Append(currentUnit.IsValidOnMap(mapData))
.Append(", landType=").Append(landType)
.Append(", carry=");
AppendFullType(sb, currentUnit.CarryUnitFullType);
sb.Append(", boundGrid=").Append(boundGridId)
.Append(", city=").Append(cityId)
.Append(", player=").Append(playerId)
.AppendLine();
sb.Append("Grid: id=").Append(gridData.Id)
.Append(", terrain=").Append(gridData.Terrain)
.Append(", resource=").Append(gridData.Resource)
.Append(", feature=").Append(gridData.Feature)
.Append(", vegetation=").Append(gridData.Vegetation)
.Append(", pos=(").Append(gridData.Pos.X).Append(",").Append(gridData.Pos.Y).Append(")")
.AppendLine();
AppendRecentActions(sb, mapData, 3);
LogSystem.LogError(sb.ToString());
}
catch (System.Exception e)
{
if (_diagnosticFailedLogged) return;
_diagnosticFailedLogged = true;
LogSystem.LogWarning($"BoatUnitOnLandState diagnostic failed: {e}");
}
}
private static void AppendRecentActions(StringBuilder sb, MapData mapData, int maxCount)
{
var actions = mapData.Net?.Actions;
if (actions == null || actions.Count == 0)
{
sb.AppendLine("RecentActions: 无");
return;
}
var count = System.Math.Min(actions.Count, maxCount);
sb.Append("RecentActions(count=").Append(count).AppendLine("):");
for (var i = 0; i < count; i++)
{
var actionIndex = actions.Count - 1 - i;
var actionData = actions[actionIndex];
sb.Append("RecentAction[").Append(actionIndex).AppendLine("]:");
if (actionData == null)
{
sb.AppendLine("null");
continue;
}
sb.Append("Version=").Append(actionData.Version)
.Append(", MapHash=").Append(actionData.MapHash)
.AppendLine();
if (actionData.ActionId != null)
sb.AppendLine(actionData.ActionId.GetStringLog());
if (actionData.Param != null)
{
sb.AppendLine("Param:");
sb.AppendLine(actionData.Param.GetStringLog());
}
}
}
private static void AppendFullType(StringBuilder sb, string label, UnitFullType? fullType)
{
sb.Append(label).Append("=");
if (!fullType.HasValue)
{
sb.Append("null");
return;
}
AppendFullType(sb, fullType.Value);
}
private static void AppendFullType(StringBuilder sb, UnitFullType fullType)
{
sb.Append(fullType.UnitType)
.Append("/")
.Append(fullType.GiantType)
.Append("/")
.Append(fullType.UnitLevel);
}
}
public class LogSystem
{
public static string Record = string.Empty;
private static string GenerateHashCode()
{
string deviceId = SystemInfo.deviceUniqueIdentifier;
string timestamp = System.DateTime.UtcNow.Ticks.ToString();
string combined = deviceId + timestamp;
using (var md5 = System.Security.Cryptography.MD5.Create())
{
byte[] inputBytes = System.Text.Encoding.UTF8.GetBytes(combined);
byte[] hashBytes = md5.ComputeHash(inputBytes);
// Convert the byte array to hexadecimal string
System.Text.StringBuilder sb = new System.Text.StringBuilder();
for (int i = 0; i < hashBytes.Length; i++)
{
sb.Append(hashBytes[i].ToString("x2"));
}
return sb.ToString();
}
}
public static void LogError(string message, Object context = null)
{
#if !UNITY_EDITOR
CrashSightAgent.PrintLog(CSLogSeverity.LogError, message + $"({GetSelfMemberIdSafe()})");
# endif
if (context!=null) Debug.LogError(message, context);
else Debug.LogError(message);
}
public static void LogWarning(string message, Object context = null)
{
#if !UNITY_EDITOR
CrashSightAgent.PrintLog(CSLogSeverity.LogWarning, message);
# endif
if (context!=null) Debug.LogWarning(message, context);
else Debug.LogWarning(message);
}
public static void LogInfo(string message, Object context = null)
{
#if !UNITY_EDITOR
CrashSightAgent.PrintLog(CSLogSeverity.LogInfo, message);
# endif
if (context!=null) Debug.Log(message, context);
else Debug.Log(message);
}
private static ulong GetSelfMemberIdSafe()
{
try
{
return LobbyManager.Instance?.Lobby?.GetSelfMemberId() ?? 0UL;
}
catch
{
return 0UL;
}
}
}
}