Files
Continentis/Assets/Scripts/MainGame/Combat/CombatLogs.cs
SoulliesOfficial c3b1561375 更新
2026-04-01 12:23:27 -04:00

211 lines
8.5 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using System;
using System.Collections.Generic;
using System.Text;
using Continentis.MainGame.Card;
using Continentis.MainGame.Character;
using SLSFramework.General;
using UnityEngine;
namespace Continentis.MainGame.Combat
{
public enum CombatLogType
{
RoundStart,
ActionStart,
Attack,
BuffApply,
BuffRemove,
CardPlay,
Death
}
public class CombatLogEntry
{
public int round;
public int actionIndex;
public float timestamp;
public CombatLogType type;
public string message;
public Dictionary<string, object> metadata;
public CombatLogEntry(int round, int actionIndex, CombatLogType type, string message)
{
this.round = round;
this.actionIndex = actionIndex;
this.timestamp = Time.time;
this.type = type;
this.message = message;
this.metadata = new Dictionary<string, object>();
}
}
/// <summary>
/// 战斗日志系统:记录战斗中的关键事件,支持查询与格式化输出。
/// 挂载在战斗场景的 CombatMainManager 同级或子对象上。
/// </summary>
public class CombatLogs : Singleton<CombatLogs>
{
private const string LogPrefix = "[CombatLog]";
private readonly List<CombatLogEntry> allEntries = new List<CombatLogEntry>();
private CombatMainManager combatManager;
// ── 初始化与事件订阅 ──────────────────────────────────────────────
/// <summary>
/// 由 CombatMainManager.StartCombat() 调用,订阅全局及各角色事件。
/// </summary>
public void Initialize(CombatMainManager manager)
{
allEntries.Clear();
combatManager = manager;
// 订阅全局回合开始事件
manager.eventCollection.onRoundStart.InsertByPriority(
"CombatLogs_RoundStart",
new PrioritizedAction(() => LogRoundStart(manager.currentRound), 0));
// 订阅角色攻击完成事件
foreach (CharacterBase character in manager.characterController.characters)
{
SubscribeCharacterEvents(character);
}
// 订阅死亡事件
manager.eventCollection.onCharacterDeath.InsertByPriority(
"CombatLogs_Death",
new PrioritizedAction<CharacterBase>(LogDeath, 0));
}
/// <summary>为单个角色订阅攻击完成事件(可供动态加入战场的角色调用)。</summary>
public void SubscribeCharacterEvents(CharacterBase character)
{
CharacterBase captured = character;
character.eventSubmodule.onFinishAttack.InsertByPriority(
"CombatLogs_FinishAttack",
new PrioritizedAction<CharacterBase, AttackResult>(
(target, result) => LogAttack(result), 0));
}
// ── 日志写入 API ──────────────────────────────────────────────────
/// <summary>记录攻击结果。</summary>
public void LogAttack(AttackResult result)
{
string msg = result.isDodged
? $"{result.attacker.data.displayName} 攻击 {result.target.data.displayName}(闪避)"
: $"{result.attacker.data.displayName} 攻击 {result.target.data.displayName}" +
$"起始伤害={result.startDamage}, 格挡={result.blockedDamage}, " +
$"护盾={result.shieldedDamage}, 实际={result.hurtDamage}";
var entry = new CombatLogEntry(
combatManager.currentRound, combatManager.currentActionIndex,
CombatLogType.Attack, msg);
entry.metadata["attacker"] = result.attacker.data.displayName;
entry.metadata["target"] = result.target.data.displayName;
entry.metadata["hurtDamage"] = result.hurtDamage;
entry.metadata["isDodged"] = result.isDodged;
WriteEntry(entry);
}
/// <summary>记录 Buff 施加事件。</summary>
public void LogBuffApply(CharacterCombatBuffBase buff, CharacterBase target)
{
string msg = $"Buff 施加:{buff.GetType().Name} → {target.data.displayName}";
var entry = new CombatLogEntry(
combatManager.currentRound, combatManager.currentActionIndex,
CombatLogType.BuffApply, msg);
entry.metadata["buffType"] = buff.GetType().Name;
entry.metadata["target"] = target.data.displayName;
WriteEntry(entry);
}
/// <summary>记录 Buff 移除事件。</summary>
public void LogBuffRemove(CharacterCombatBuffBase buff)
{
string msg = $"Buff 移除:{buff.GetType().Name} ← {buff.attachedCharacter?.data.displayName}";
var entry = new CombatLogEntry(
combatManager.currentRound, combatManager.currentActionIndex,
CombatLogType.BuffRemove, msg);
entry.metadata["buffType"] = buff.GetType().Name;
WriteEntry(entry);
}
/// <summary>记录卡牌使用事件。</summary>
public void LogCardPlay(CardInstance card, List<CharacterBase> targets)
{
StringBuilder targetNames = new StringBuilder();
foreach (CharacterBase t in targets)
{
if (targetNames.Length > 0) targetNames.Append(", ");
targetNames.Append(t.data.displayName);
}
string msg = $"卡牌使用:{card.cardData.displayName} → [{targetNames}]";
var entry = new CombatLogEntry(
combatManager.currentRound, combatManager.currentActionIndex,
CombatLogType.CardPlay, msg);
entry.metadata["cardName"] = card.cardData.displayName;
WriteEntry(entry);
}
/// <summary>记录角色死亡事件。</summary>
public void LogDeath(CharacterBase character)
{
string msg = $"{character.data.displayName} 死亡(回合 {combatManager.currentRound}";
var entry = new CombatLogEntry(
combatManager.currentRound, combatManager.currentActionIndex,
CombatLogType.Death, msg);
entry.metadata["character"] = character.data.displayName;
entry.metadata["fraction"] = character.fraction.ToString();
WriteEntry(entry);
}
/// <summary>记录回合开始事件。</summary>
public void LogRoundStart(int round)
{
string msg = $"── 第 {round} 回合开始 ──";
var entry = new CombatLogEntry(round, 0, CombatLogType.RoundStart, msg);
WriteEntry(entry);
}
// ── 查询 API ──────────────────────────────────────────────────────
/// <summary>按类型和数量查询日志条目。</summary>
public List<CombatLogEntry> Query(CombatLogType type, int lastN = 10)
{
var result = new List<CombatLogEntry>();
for (int i = allEntries.Count - 1; i >= 0 && result.Count < lastN; i--)
{
if (allEntries[i].type == type)
result.Add(allEntries[i]);
}
result.Reverse();
return result;
}
/// <summary>获取所有日志条目。</summary>
public IReadOnlyList<CombatLogEntry> GetAllEntries() => allEntries;
// ── 格式化 ────────────────────────────────────────────────────────
/// <summary>将条目格式化为人类可读字符串。</summary>
public string FormatEntry(CombatLogEntry entry)
{
return $"[R{entry.round:D2}|A{entry.actionIndex:D2}|{entry.timestamp:F2}s] {entry.type}: {entry.message}";
}
// ── 内部写入 ──────────────────────────────────────────────────────
private void WriteEntry(CombatLogEntry entry)
{
allEntries.Add(entry);
Debug.Log($"{LogPrefix} {FormatEntry(entry)}");
}
}
}