refactor(debug-log): 优化全模块调试日志格式与默认开关

1.  将BuffManager的静态DEBUG开关改为运行时可配置的debug属性,默认开启
2.  统一所有模块的调试日志输出格式,增加技能/ buff名称、UUID、目标信息和判定详情
3.  为HeroAtkSystem的概率判定添加统一日志,修复击退判定逻辑并补充日志
4.  开启SkillView和HeroAtkSystem的默认调试模式
This commit is contained in:
pan
2026-09-08 10:03:40 +08:00
parent 2cc9678f74
commit 4d7e54f833
4 changed files with 38 additions and 22 deletions

View File

@@ -13,9 +13,6 @@ import { BuffCategory, BuffList } from "../common/config/BuffSet";
import { BuffComp, ActiveBuff } from "./BuffComp"; import { BuffComp, ActiveBuff } from "./BuffComp";
import { mLogger } from "../common/Logger"; import { mLogger } from "../common/Logger";
/** Buff 模块调试日志开关 */
const DEBUG = false;
/** applyBuff 的覆盖参数(预留按需覆写持续时间 / 修饰数值) */ /** applyBuff 的覆盖参数(预留按需覆写持续时间 / 修饰数值) */
export interface BuffApplyOverrides { export interface BuffApplyOverrides {
duration?: number; duration?: number;
@@ -26,6 +23,9 @@ export interface BuffApplyOverrides {
} }
class BuffManagerImpl { class BuffManagerImpl {
/** 调试日志开关:运行时可通过 buffManager.debug = false 关闭(测试期默认开启) */
public debug: boolean = true;
/** /**
* 对目标施加一个 buff 实例。 * 对目标施加一个 buff 实例。
* *
@@ -46,7 +46,7 @@ class BuffManagerImpl {
mLogger.warn(true, "BuffManager", `applyBuff: buffId=${buffId} 配置不存在,跳过`); mLogger.warn(true, "BuffManager", `applyBuff: buffId=${buffId} 配置不存在,跳过`);
return; return;
} }
mLogger.log(DEBUG, "BuffManager", `applyBuff: buff=${cfg.name}(${buffId}) target_eid=${target.eid} duration=${overrides?.duration ?? cfg.duration} value_override=${overrides?.value} source_ap=${sourceAp}`); mLogger.log(this.debug, "BuffManager", `[挂buff] 「${cfg.name}」(buffId:${buffId}) -> target_eid:${target.eid} duration:${overrides?.duration ?? cfg.duration} value:${overrides?.value ?? "-"} source_ap:${sourceAp}`);
const buffComp = this.ensureBuffComp(target); const buffComp = this.ensureBuffComp(target);
const duration = overrides?.duration ?? cfg.duration; const duration = overrides?.duration ?? cfg.duration;

View File

@@ -47,7 +47,7 @@ interface FinalData {
@ecs.register('HeroAtkSystem') @ecs.register('HeroAtkSystem')
export class HeroAtkSystem extends ecs.ComblockSystem implements ecs.ISystemUpdate { export class HeroAtkSystem extends ecs.ComblockSystem implements ecs.ISystemUpdate {
private debugMode: boolean = false; // 是否启用调试模式 private debugMode: boolean = true; // 是否启用调试模式
/** /**
* 过滤器:处理拥有伤害队列的实体 * 过滤器:处理拥有伤害队列的实体
@@ -145,7 +145,7 @@ export class HeroAtkSystem extends ecs.ComblockSystem implements ecs.ISystemUpda
// 暴击判定 // 暴击判定
// 使用施法者的暴击率属性(damageEvent.Attrs 快照)- 被攻击者的暴击抗性 + 目标出血层数附加的被暴击率 // 使用施法者的暴击率属性(damageEvent.Attrs 快照)- 被攻击者的暴击抗性 + 目标出血层数附加的被暴击率
const criticalChance = (damageEvent.Attrs[Attrs.critical] || 0) - TAttrsComp.getFinalCriticalRes() + this.getBleedCritBonus(target); const criticalChance = (damageEvent.Attrs[Attrs.critical] || 0) - TAttrsComp.getFinalCriticalRes() + this.getBleedCritBonus(target);
const isCrit = this.checkChance(criticalChance); const isCrit = this.checkChance(criticalChance, `暴击->${TAttrsComp.hero_name}`);
// 计算基础伤害:DoT 直接用固定 tick 值,普攻走 dmgCount 公式 // 计算基础伤害:DoT 直接用固定 tick 值,普攻走 dmgCount 公式
let damage = isDot ? (damageEvent.dot_dmg ?? 0) : this.dmgCount(damageEvent, TAttrsComp); let damage = isDot ? (damageEvent.dot_dmg ?? 0) : this.dmgCount(damageEvent, TAttrsComp);
@@ -214,15 +214,15 @@ export class HeroAtkSystem extends ecs.ComblockSystem implements ecs.ISystemUpda
// 冰冻判定 // 冰冻判定
const freezeChance = (damageEvent.Attrs[Attrs.freeze_chance] || 0) - (TAttrsComp.freeze_res || 0); const freezeChance = (damageEvent.Attrs[Attrs.freeze_chance] || 0) - (TAttrsComp.freeze_res || 0);
const isFrost = !TAttrsComp.isFrost() && this.checkChance(freezeChance); const isFrost = !TAttrsComp.isFrost() && this.checkChance(freezeChance, `冰冻->${TAttrsComp.hero_name}`);
// 击晕判定 // 击晕判定
const stunChance = (damageEvent.Attrs[Attrs.stun_chance] || 0) - TAttrsComp.getFinalStunRes(); const stunChance = (damageEvent.Attrs[Attrs.stun_chance] || 0) - TAttrsComp.getFinalStunRes();
const isStun = !TAttrsComp.isStun() && this.checkChance(stunChance); const isStun = !TAttrsComp.isStun() && this.checkChance(stunChance, `击晕->${TAttrsComp.hero_name}`);
// 麻痹判定(无麻痹抗性,仅按概率) // 麻痹判定(无麻痹抗性,仅按概率)
const paralyzeChance = damageEvent.Attrs[Attrs.paralyze_chance] || 0; const paralyzeChance = damageEvent.Attrs[Attrs.paralyze_chance] || 0;
const isParalyze = !TAttrsComp.isParalyze() && this.checkChance(paralyzeChance); const isParalyze = !TAttrsComp.isParalyze() && this.checkChance(paralyzeChance, `麻痹->${TAttrsComp.hero_name}`);
// ✅ 触发视图层表现(伤害数字、受击动画、冰冻、击晕、击退) // ✅ 触发视图层表现(伤害数字、受击动画、冰冻、击晕、击退)
if (targetView) { if (targetView) {
@@ -234,7 +234,11 @@ export class HeroAtkSystem extends ecs.ComblockSystem implements ecs.ISystemUpda
// 击退概率判定:概率来自技能配置 bck_chance(heroSet overrides 可覆写),未配置视为 0 不击退。 // 击退概率判定:概率来自技能配置 bck_chance(heroSet overrides 可覆写),未配置视为 0 不击退。
// 不复用 checkChance:其 70% 上限封顶会把 100% 击退(近战普攻 6004)削成 70% // 不复用 checkChance:其 70% 上限封顶会把 100% 击退(近战普攻 6004)削成 70%
const knockbackChance = damageEvent.Attrs[Attrs.knockback_skill_chance] || 0; const knockbackChance = damageEvent.Attrs[Attrs.knockback_skill_chance] || 0;
const isKnockback = knockbackChance >= 100 || (knockbackChance > 0 && Math.random() * 100 < knockbackChance); const knockbackRand = knockbackChance >= 100 ? 0 : Math.random() * 100;
const isKnockback = knockbackChance >= 100 || (knockbackChance > 0 && knockbackRand < knockbackChance);
if (knockbackChance > 0) {
mLogger.log(this.debugMode, 'HeroAtkSystem', `[概率判定] 击退->${TAttrsComp.hero_name} 概率:${knockbackChance.toFixed(1)}% 随机:${knockbackRand.toFixed(1)} -> ${isKnockback ? "✔成功" : "✘失败"}`);
}
// 击退距离增量 = 施法者击退强化(原击退概率)- 被攻击者击退抗性 + 击退距离强化(仅命中击退时生效) // 击退距离增量 = 施法者击退强化(原击退概率)- 被攻击者击退抗性 + 击退距离强化(仅命中击退时生效)
const knockbackBonus = (damageEvent.Attrs[Attrs.knockback_chance] || 0) - (TAttrsComp.getFinalKnockbackRes() || 0); const knockbackBonus = (damageEvent.Attrs[Attrs.knockback_chance] || 0) - (TAttrsComp.getFinalKnockbackRes() || 0);
@@ -279,13 +283,18 @@ export class HeroAtkSystem extends ecs.ComblockSystem implements ecs.ISystemUpda
// 施法者 ap/完整属性快照取自伤害事件,供 BuffSystem tick 缩放与暴击/冰冻/击晕判定 // 施法者 ap/完整属性快照取自伤害事件,供 BuffSystem tick 缩放与暴击/冰冻/击晕判定
if (!isDot && skillConf.timed_buff_id) { if (!isDot && skillConf.timed_buff_id) {
const buffChance = skillConf.buff_chance ?? 100; const buffChance = skillConf.buff_chance ?? 100;
if (buffChance >= 100 || Math.random() * 100 < buffChance) { const buffRand = buffChance >= 100 ? 0 : Math.random() * 100;
if (buffChance >= 100 || buffRand < buffChance) {
const buffOverrides: BuffApplyOverrides = { source_attrs: damageEvent.Attrs }; const buffOverrides: BuffApplyOverrides = { source_attrs: damageEvent.Attrs };
if (skillConf.buff_value !== undefined) buffOverrides.value = skillConf.buff_value; if (skillConf.buff_value !== undefined) buffOverrides.value = skillConf.buff_value;
if (skillConf.buff_duration !== undefined) buffOverrides.duration = skillConf.buff_duration; if (skillConf.buff_duration !== undefined) buffOverrides.duration = skillConf.buff_duration;
for (const buffTarget of this.resolveBuffTargets(target, casterEid, TAttrsComp.fac, skillConf.buff_target)) { const buffTargets = this.resolveBuffTargets(target, casterEid, TAttrsComp.fac, skillConf.buff_target);
mLogger.log(this.debugMode, 'HeroAtkSystem', `[概率判定] 附带buff「${BuffList[skillConf.timed_buff_id]?.name ?? "?"}」 概率:${buffChance.toFixed(1)}% 随机:${buffRand.toFixed(1)} -> ✔成功(技能「${skillConf.name}」命中 ${TAttrsComp.hero_name},${buffTargets.length} 个目标)`);
for (const buffTarget of buffTargets) {
buffManager.applyBuff(buffTarget, skillConf.timed_buff_id, casterEid, damageEvent.Attrs[Attrs.ap] || 0, buffOverrides); buffManager.applyBuff(buffTarget, skillConf.timed_buff_id, casterEid, damageEvent.Attrs[Attrs.ap] || 0, buffOverrides);
} }
} else {
mLogger.log(this.debugMode, 'HeroAtkSystem', `[概率判定] 附带buff「${BuffList[skillConf.timed_buff_id]?.name ?? "?"}」 概率:${buffChance.toFixed(1)}% 随机:${buffRand.toFixed(1)} -> ✘失败(技能「${skillConf.name}」命中 ${TAttrsComp.hero_name})`);
} }
} }
@@ -295,16 +304,20 @@ export class HeroAtkSystem extends ecs.ComblockSystem implements ecs.ISystemUpda
if (!isDot && damageEvent.proc_skill) { if (!isDot && damageEvent.proc_skill) {
const proc = damageEvent.proc_skill; const proc = damageEvent.proc_skill;
const procChance = proc.chance ?? 100; const procChance = proc.chance ?? 100;
if (procChance >= 100 || Math.random() * 100 < procChance) { const procRand = procChance >= 100 ? 0 : Math.random() * 100;
if (procChance >= 100 || procRand < procChance) {
const caster = ecs.getEntityByEid(casterEid); const caster = ecs.getEntityByEid(casterEid);
if (caster) { if (caster) {
const casterAttrs = caster.get(HeroAttrsComp); const casterAttrs = caster.get(HeroAttrsComp);
const casterView = caster.get(HeroViewComp); const casterView = caster.get(HeroViewComp);
if (casterAttrs && casterView && !casterAttrs.is_dead && !casterAttrs.is_reviving) { if (casterAttrs && casterView && !casterAttrs.is_dead && !casterAttrs.is_reviving) {
mLogger.log(this.debugMode, 'HeroAtkSystem', `[概率判定] 额外技能「${SkillSet[proc.s_uuid]?.name ?? "?"}」 概率:${procChance.toFixed(1)}% 随机:${procRand.toFixed(1)} -> ✔成功(技能「${skillConf.name}」命中 ${TAttrsComp.hero_name},由 ${casterAttrs.hero_name} 释放)`);
// proc_skill.overrides 透传给被触发技能(如自定义 ap 伤害),与被触发技能自身 overrides 叠加(本次传入优先) // proc_skill.overrides 透传给被触发技能(如自定义 ap 伤害),与被触发技能自身 overrides 叠加(本次传入优先)
SkillTriggerHelper.dispatchSinglePublic(proc.s_uuid, casterAttrs, casterView, SkillTriggerType.Atking, proc.overrides); SkillTriggerHelper.dispatchSinglePublic(proc.s_uuid, casterAttrs, casterView, SkillTriggerType.Atking, proc.overrides);
} }
} }
} else {
mLogger.log(this.debugMode, 'HeroAtkSystem', `[概率判定] 额外技能「${SkillSet[proc.s_uuid]?.name ?? "?"}」 概率:${procChance.toFixed(1)}% 随机:${procRand.toFixed(1)} -> ✘失败(技能「${skillConf.name}」命中 ${TAttrsComp.hero_name})`);
} }
} }
@@ -507,11 +520,15 @@ export class HeroAtkSystem extends ecs.ComblockSystem implements ecs.ISystemUpda
* *
* @important 概率为0或负数时直接返回false,避免不必要的随机数计算 * @important 概率为0或负数时直接返回false,避免不必要的随机数计算
*/ */
private checkChance(rate: number): boolean { private checkChance(rate: number, label?: string): boolean {
if (rate <= 0) return false; if (rate <= 0) return false;
if (rate >= 70) rate = 70 const capped = Math.min(rate, 70); // 70% 概率封顶
const r = Math.random() * 100; const r = Math.random() * 100;
return r < rate; const ok = r < capped;
if (label !== undefined) {
mLogger.log(this.debugMode, 'HeroAtkSystem', `[概率判定] ${label} 概率:${rate.toFixed(1)}%(封顶${capped}%) 随机:${r.toFixed(1)} -> ${ok ? "✔成功" : "✘失败"}`);
}
return ok;
} }
@@ -546,7 +563,7 @@ export class HeroAtkSystem extends ecs.ComblockSystem implements ecs.ISystemUpda
private checkDodge(damageEvent: DamageEvent, TAttrsComp: HeroAttrsComp): boolean { private checkDodge(damageEvent: DamageEvent, TAttrsComp: HeroAttrsComp): boolean {
const dodgeChance = TAttrsComp.getFinalDodge() - (damageEvent.Attrs[Attrs.accuracy] || 0); const dodgeChance = TAttrsComp.getFinalDodge() - (damageEvent.Attrs[Attrs.accuracy] || 0);
if (dodgeChance <= 0) return false; if (dodgeChance <= 0) return false;
return this.checkChance(dodgeChance); return this.checkChance(dodgeChance, `闪避:${TAttrsComp.hero_name}`);
} }
/** /**

View File

@@ -531,7 +531,7 @@ export class SCastSystem extends ecs.ComblockSystem implements ecs.ISystemUpdate
if (!target.ent) return; if (!target.ent) return;
const model = target.ent.get(HeroAttrsComp); const model = target.ent.get(HeroAttrsComp);
if (!model || model.is_dead) return; if (!model || model.is_dead) return;
mLogger.log(this.debugMode, "SCastSystem", `applyActualFriendlyEffect: skill=${config.uuid} kind=${kind} buff_type=${config.buff_type} timed_buff_id=${config.timed_buff_id} buff_value=${config.buff_value} target=${model.hero_name}`); mLogger.log(this.debugMode, "SCastSystem", `[友方效果] 技能「${config.name}」(s_uuid:${config.uuid}) -> ${model.hero_name} kind:${kind} buff_type:${config.buff_type ?? "-"} timed_buff_id:${config.timed_buff_id ?? "-"} buff_value:${config.buff_value ?? "-"}`);
if (config.endAnm && config.endAnm !== "") { if (config.endAnm && config.endAnm !== "") {
target.playEnd(config.endAnm); target.playEnd(config.endAnm);

View File

@@ -58,7 +58,7 @@ export class SkillView extends CCComp {
@property({ type: CCFloat, slide: true, range: [0, 500, 5], tooltip: "抛射物高度增量(叠加到贝塞尔弹道中点高度)" }) @property({ type: CCFloat, slide: true, range: [0, 500, 5], tooltip: "抛射物高度增量(叠加到贝塞尔弹道中点高度)" })
height_offset: number = 0; height_offset: number = 0;
private debugMode: boolean = false; private debugMode: boolean = true;
anim: Animation = null; anim: Animation = null;
group: number = 0; group: number = 0;
@@ -135,10 +135,9 @@ export class SkillView extends CCComp {
this.sData.max_hit_count++; this.sData.max_hit_count++;
// 概率衰减(减去固定的 PUNCTURE_DOWN 值,比如 50) // 概率衰减(减去固定的 PUNCTURE_DOWN 值,比如 50)
this.sData.Attrs[Attrs.puncture_chance] = Math.max(0, punctureChance - FightSet.PUNCTURE_DOWN); this.sData.Attrs[Attrs.puncture_chance] = Math.max(0, punctureChance - FightSet.PUNCTURE_DOWN);
if (this.debugMode) { mLogger.log(this.debugMode, 'SkillView', `[概率判定] 穿透 概率:${punctureChance.toFixed(1)}% 随机:${rand.toFixed(1)} -> ✔成功(衰减后剩余:${this.sData.Attrs[Attrs.puncture_chance]}%)`);
mLogger.log(this.debugMode, 'SkillView', `[SkillView] 触发穿透!剩余概率: ${this.sData.Attrs[Attrs.puncture_chance]}%`);
}
} else { } else {
mLogger.log(this.debugMode, 'SkillView', `[概率判定] 穿透 概率:${punctureChance.toFixed(1)}% 随机:${rand.toFixed(1)} -> ✘失败,投射物销毁`);
// 未触发穿透,正常销毁 // 未触发穿透,正常销毁
this.handle_collision_limit(); this.handle_collision_limit();
} }