This commit is contained in:
2026-07-29 22:59:26 +08:00
parent 61f490c4b4
commit b5ff32c7e1
19 changed files with 535 additions and 209 deletions
+103 -25
View File
@@ -23,6 +23,10 @@ public class GameManager : MonoSingleton<GameManager>
[Tooltip("是否使用后端下发的 BotConfig。false=用 Inspector 本地配置(默认,方便测试);true=用后端 GameConfig 返回的 botConfig 覆盖本地")]
public bool useRemoteBotConfig = false;
[Header("日志文件")]
[Tooltip("运行时开关:是否实际生成日志文件。需要同时启用 ENABLE_LOG_FILE 预编译指令才生效。\ntrue=生成日志文件;false=不生成(运行时关闭)")]
public bool enableLogFile = true;
public GameConfig gameConfig;
public ActivityConfig activityConfig;
public Dictionary<string, FishTypeConfig> dic_fishTypeConfigs = new Dictionary<string, FishTypeConfig>();
@@ -209,8 +213,12 @@ public class GameManager : MonoSingleton<GameManager>
// ⭐ 防止手机屏幕自动黑屏休眠
Screen.sleepTimeout = SleepTimeout.NeverSleep;
#if ENABLE_LOG_FILE
// ⭐ 启动日志文件自动保存:把所有 Debug.Log/Warning/Error 写入 persistentDataPath/Logs/
InitLogFileWriter();
// 需要在 Player Settings → Scripting Define Symbols 中添加 ENABLE_LOG_FILE 才会编译
// 运行时可通过 Inspector 的 enableLogFile 勾选框关闭
if (enableLogFile) InitLogFileWriter();
#endif
AudioResourcesData audioResourcesData = new AudioResourcesData();
InItLoad();
@@ -244,8 +252,15 @@ public class GameManager : MonoSingleton<GameManager>
}
// ⭐ 日志文件写入器:把 Application.logMessageReceived 的日志实时写入文件
#if ENABLE_LOG_FILE
// ============================ 日志文件系统 ============================
// 启用方法: Player Settings → Other Settings → Scripting Define Symbols 添加 ENABLE_LOG_FILE
// 关闭方法: 删除该符号,或 Inspector 中 enableLogFile 取消勾选
// 说明: LogGoldFlow 用 [Conditional] 标记,未定义 ENABLE_LOG_FILE 时所有调用点会被编译器自动移除,零开销
private StreamWriter _logFileWriter;
private StreamWriter _goldFlowWriter;
private void InitLogFileWriter()
{
try
@@ -257,7 +272,6 @@ public class GameManager : MonoSingleton<GameManager>
Application.logMessageReceived += OnLogMessageReceived;
Debug.Log($"[GameManager] 日志文件已创建: {logPath}");
// 同时初始化金币流水日志文件
InitGoldFlowWriter(logDir);
}
catch (Exception e)
@@ -266,17 +280,23 @@ public class GameManager : MonoSingleton<GameManager>
}
}
// ⭐ 金币流水日志写入器:单独写入"金币流水"文件,格式对齐后端日志
private StreamWriter _goldFlowWriter;
private void InitGoldFlowWriter(string logDir)
{
try
{
string goldLogPath = Path.Combine(logDir, "金币流水_" + DateTime.Now.ToString("yyyy-MM-dd_HH-mm-ss") + ".log");
_goldFlowWriter = new StreamWriter(goldLogPath, true) { AutoFlush = true };
// ===== 文件头:只记录当前玩家自己(进游戏前可能 user 还没拉到,做 null 保护) =====
string userName = user?.BaseInfo?.userName ?? "未登录";
string userId = user?.id ?? "未登录";
_goldFlowWriter.WriteLine($"# 金币流水日志 - 启动于 {DateTime.Now:yyyy-MM-dd HH:mm:ss}");
_goldFlowWriter.WriteLine($"# 格式: 时间|service=client|INFO|GoldFlow|[金币流水] 玩家=名称(ID) 事件=xxx {描述}");
_goldFlowWriter.WriteLine($"# 当前玩家: {userName}({userId})");
_goldFlowWriter.WriteLine($"# 说明: 只记录当前玩家自己的金币变动,不记录其他玩家");
_goldFlowWriter.WriteLine($"# 格式: 时间|service=client|INFO|GoldFlow|[分类] 玩家=名称(ID) 事件=target 描述");
_goldFlowWriter.WriteLine($"# 分类: 收到加钱/已加钱/收到扣钱/已扣钱/金币流水(通用)");
_goldFlowWriter.WriteLine(new string('-', 80));
Debug.Log($"[GameManager] 金币流水日志文件已创建: {goldLogPath}");
}
catch (Exception e)
@@ -285,24 +305,6 @@ public class GameManager : MonoSingleton<GameManager>
}
}
/// <summary>
/// 记录金币流水(供全项目调用)
/// 用法: GameManager.LogGoldFlow("KillFish", $"击中鱼原有金币={oldGold} 增加金币=+{addGold} 剩余金币={newGold} 房间={roomId}");
/// </summary>
public static void LogGoldFlow(string eventName, string description)
{
var inst = Instance;
if (inst == null || inst._goldFlowWriter == null) return;
try
{
string userName = inst.user?.BaseInfo?.userName ?? "未知";
string userId = inst.user?.id ?? "未知";
string timeStr = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff");
inst._goldFlowWriter.WriteLine($"{timeStr}|service=client|INFO|GoldFlow|[金币流水] 玩家={userName}({userId}) 事件={eventName} {description}");
}
catch { /* 写日志失败不影响游戏运行 */ }
}
private void OnLogMessageReceived(string condition, string stackTrace, LogType type)
{
if (_logFileWriter == null) return;
@@ -323,7 +325,7 @@ public class GameManager : MonoSingleton<GameManager>
_logFileWriter.WriteLine($" Stack: {stackTrace}");
}
}
catch { /* 写日志失败不影响游戏运行 */ }
catch { }
}
private void OnDestroy()
@@ -340,6 +342,82 @@ public class GameManager : MonoSingleton<GameManager>
_goldFlowWriter = null;
}
}
#endif
// ============================ 金币流水日志(与后端逐条对比) ============================
// 拆成4类,方便和后端日志逐行对比:
// - 收到扣钱信息(推送): 后端发来扣钱通知,客户端尚未执行
// - 已扣钱(本地执行): 客户端本地已扣完金币
// - 收到加钱信息(推送): 后端发来加钱通知,客户端尚未执行
// - 已加钱(本地执行): 客户端本地已加完金币
//
// 控制方式:
// 1. 编译时: 未定义 ENABLE_LOG_FILE 符号时,所有调用被编译器自动移除([Conditional]特性),零开销
// 2. 运行时: 即使编译了,Inspector 中 enableLogFile=false 也不会写入文件
//
// 通用记录(无关扣/加,如退出房间)继续用 LogGoldFlow
/// <summary>记录"收到扣钱信息"(后端推送,尚未执行)。如:后端推送 SyncPlayerGold 差值为负</summary>
[System.Diagnostics.Conditional("ENABLE_LOG_FILE")]
public static void LogGoldFlowReceiveCost(string eventName, string description)
{
#if ENABLE_LOG_FILE
WriteGoldFlow("收到扣钱", eventName, description);
#endif
}
/// <summary>记录"已扣钱"(本地已执行扣金币)。如:开火 ConsumeGold 扣完</summary>
[System.Diagnostics.Conditional("ENABLE_LOG_FILE")]
public static void LogGoldFlowAppliedCost(string eventName, string description)
{
#if ENABLE_LOG_FILE
WriteGoldFlow("已扣钱", eventName, description);
#endif
}
/// <summary>记录"收到加钱信息"(后端推送,尚未执行)。如:RoomJoinNotice/RoomInfo 推送金币</summary>
[System.Diagnostics.Conditional("ENABLE_LOG_FILE")]
public static void LogGoldFlowReceiveGain(string eventName, string description)
{
#if ENABLE_LOG_FILE
WriteGoldFlow("收到加钱", eventName, description);
#endif
}
/// <summary>记录"已加钱"(本地已执行加金币)。如:杀鱼 KillFish 加完、进房 JoinGame 设置初始金币</summary>
[System.Diagnostics.Conditional("ENABLE_LOG_FILE")]
public static void LogGoldFlowAppliedGain(string eventName, string description)
{
#if ENABLE_LOG_FILE
WriteGoldFlow("已加钱", eventName, description);
#endif
}
/// <summary>通用金币流水记录(无关扣/加,如退出房间)。需要明确分类时请用上面4个方法</summary>
[System.Diagnostics.Conditional("ENABLE_LOG_FILE")]
public static void LogGoldFlow(string eventName, string description)
{
#if ENABLE_LOG_FILE
WriteGoldFlow("金币流水", eventName, description);
#endif
}
#if ENABLE_LOG_FILE
/// <summary>金币流水核心写入(私有)。所有公开 LogGoldFlow* 方法最终都走这里</summary>
private static void WriteGoldFlow(string category, string eventName, string description)
{
var inst = Instance;
if (inst == null || !inst.enableLogFile || inst._goldFlowWriter == null) return;
try
{
string userName = inst.user?.BaseInfo?.userName ?? "未知";
string userId = inst.user?.id ?? "未知";
string timeStr = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff");
inst._goldFlowWriter.WriteLine($"{timeStr}|service=client|INFO|GoldFlow|[{category}] 玩家={userName}({userId}) 事件={eventName} {description}");
}
catch { }
}
#endif
public async Task InItLoad()
{