Skip to content

Buff 系统 ​

Buff 加属性后看起来无变化时,先按完整链路排查检查启用、叠层、已应用修改及最终属性。Modifications 自动维护应用与撤销,不需要普遍改为手动 AddFixed;增加最大生命不等于回血。

Buff 系统管理单位上的临时效果(增益/减益),包括持续时间、层数叠加、周期效果、属性修改和状态变更。

核心类型 ​

类型说明
GameDataBuffBuff 数编配置(静态数据)
BuffBuff 运行时实例
BuffManager管理单位上所有 Buff(继承自 ObjectManager<Buff, GameDataBuff>)
GameDataEffectBuffAdd效果树中添加 Buff 的效果节点
GameDataEffectBuffRemove效果树中移除 Buff 的效果节点

GameDataBuff 配置 ​

csharp
public partial class GameDataBuff
{
    // 显示信息
    public LocalizedString? DisplayName { get; set; }
    public LocalizedString? Description { get; set; }
    public Icon? Icon { get; set; }

    // 同步和分类
    public SyncType SyncType { get; set; } = SyncType.Sight;
    public BuffPolarity Polarity { get; set; }            // Neutral / Positive / Negative
    public List<BuffCategory> Categories { get; set; }    // CanBeDisabled, CanBeDispelled(可扩展)
    public BuffFlags BuffFlags { get; set; }

    // 叠加配置
    public uint StackStart { get; set; } = 1;             // 初始层数
    public uint? InstanceMax { get; set; }                // 最大实例数
    public FuncUIntEffect? StackMax { get; set; }         // 最大层数

    // 时间配置
    public FuncTimeEffect? Duration { get; set; }         // 持续时间(null 为永久)
    public BuffDurationSyncMode DurationSyncMode { get; set; } = BuffDurationSyncMode.Owner;
    public FuncTimeEffect? Period { get; set; }           // 周期效果间隔

    // 生命周期效果
    public IGameLink<GameDataEffect>? InitialEffect { get; set; }   // 首次附加时执行
    public IGameLink<GameDataEffect>? PeriodicEffect { get; set; }  // 每个周期执行
    public IGameLink<GameDataEffect>? RefreshEffect { get; set; }   // 同施法者重复施加时执行
    public IGameLink<GameDataEffect>? ExpireEffect { get; set; }    // 自然到期时执行
    public IGameLink<GameDataEffect>? FinalEffect { get; set; }     // 被移除时执行(任何原因)

    // 属性修改和状态变更
    public List<UnitPropertyModification> Modifications { get; set; }
    public List<UnitState> AddStates { get; set; }        // 附加时添加的状态
    public List<UnitState> RemoveStates { get; set; }     // 附加时移除的状态
    public List<UnitState> ImmuneStates { get; set; }     // 附加期间免疫的状态

    // 验证器
    public ValidatorEffect? EnableValidator { get; set; }  // 控制 Buff 启用/禁用
    public ValidatorEffect? PersistValidator { get; set; } // 验证失败时销毁 Buff

    // 响应(Behavior 系统)
    public List<IGameLink<GameDataResponse>?>? Responses { get; set; }

    // 启用/禁用其他 Buff 和技能
    public List<IGameLink<GameDataBuff>> BuffsEnable { get; set; }
    public List<IGameLink<GameDataBuff>> BuffsDisable { get; set; }
    public List<BuffCategory> BuffCategoriesEnable { get; set; }
    public List<BuffCategory> BuffCategoriesDisable { get; set; }
    public List<IGameLink<GameDataAbility>> AbilitiesEnable { get; set; }
    public List<IGameLink<GameDataAbility>> AbilitiesDisable { get; set; }
    public List<AbilityCategory> AbilityCategoriesEnable { get; set; }
    public List<AbilityCategory> AbilityCategoriesDisable { get; set; }

    // 表现层
    public List<IGameLink<GameDataActor>?>? ActorArray { get; set; }  // Actor 模型/特效
    public BuffUISettings UISettings { get; set; }                     // UI 显示配置
    public DebugDrawSettings? DebugDrawSettings { get; set; }
}

持续时间同步方式 ​

GameDataBuff.DurationSyncMode 同时控制运行时 Buff.Duration 和 Buff.RemainingTime 的同步范围。默认值为 Owner,未填写该字段的 Buff 也采用此默认值。

配置值数据编辑器选项行为
BuffDurationSyncMode.None不同步服务端照常计时,所有客户端均不接收计时信息
BuffDurationSyncMode.Owner仅同步给Buff持有者仅所挂单位的所属玩家接收计时信息,且不超出 Buff 本体的同步范围
BuffDurationSyncMode.Inherit继承Buff同步方式计时信息跟随 GameDataBuff.SyncType;例如 Sight 会向视野内玩家公开倒计时

在 PvP 游戏中,可使用 SyncType.Sight 配合默认的 Owner:敌方玩家能看到 Buff 及其表现,但读不到它的持续时间和剩余秒数。需要公开倒计时的 Buff 再显式选择 Inherit。这里的“持有者”指受 Buff 影响的单位所属玩家,与施法者无关。

客户端没有收到计时信息时,运行时 Duration 和 RemainingTime 返回 null。此时 UI 应隐藏倒计时,不应根据数编配置或首次看见 Buff 的时间推算剩余时间;null 也不能用来判断 Buff 是否永久。设置持续时间同步方式不影响服务端到期、暂停和续时逻辑。

BuffFlags ​

控制 Buff 的行为标志,只有 4 个字段:

csharp
public class BuffFlags
{
    // 同一施法者对同一目标只能有一个实例。
    // 重复施加时合并层数并刷新持续时间。
    public bool SingleInstancePerCaster { get; set; }

    // 永久效果:不会因变身、死亡等条件消失。
    // 注意:这不是"持续时间无限"的意思。
    public bool Permanent { get; set; }

    // 单位死亡时是否禁用此 Buff(默认 true)。
    // 设为 false 可让 Buff 在死亡后继续生效(需配合 Permanent = true 使用)。
    public bool DisableWhenDead { get; set; } = true;

    // 引导效果:施法者引导被打断时,此 Buff 也会被移除。
    public bool Channeling { get; set; }
}

BuffPolarity ​

csharp
public enum BuffPolarity
{
    Neutral,   // 中性
    Positive,  // 增益
    Negative   // 减益
}

BuffCategory ​

可扩展枚举,内置两个值:

csharp
BuffCategory.CanBeDisabled   // 可被禁用
BuffCategory.CanBeDispelled  // 可被驱散

游戏开发者可通过 [EnumExtension(Extends = typeof(EBuffCategory))] 自定义分类。

BuffUISettings ​

csharp
public class BuffUISettings
{
    public bool ShowStackCount { get; set; } = true;
    public UIDurationFormat DurationFormat { get; set; } = UIDurationFormat.CircularProgress;
    public bool CombineInstances { get; set; } = true;          // 合并同类实例为一个 UI 条目
    public TimeSpan? BlinkThreshold { get; set; } = TimeSpan.FromSeconds(2); // 即将过期时闪烁
}

public enum UIDurationFormat { None, Numeric, CircularProgress }

Buff 运行时实例 ​

属性 ​

属性类型可用端说明
LinkIGameLink<GameDataBuff>双端数编 Link
CacheGameDataBuff双端数编缓存(Link.Data 快捷访问)
Stackuint服务端读写,客户端只读当前层数
StackMaxuint?仅服务端最大层数
DurationTimeSpan?双端总持续时间
RemainingTimeTimeSpan?双端剩余时间
ManagerBuffManager双端所属管理器
StackParamEffect仅服务端创建此 Buff 的 EffectBuffAdd 效果
IsLinkEnabledbool双端当前 Link 是否启用
DisableOnDeathbool双端死亡时是否禁用
RemoveOnDeathbool双端死亡时是否移除

服务端方法 ​

csharp
uint AddStack(int stack);                         // 增减层数,返回新层数
uint SetStack(uint stack);                        // 设置层数
bool SetRemainingTime(TimeSpan? newRemainingTime); // 设置剩余时间(null 移除计时器)
void Pause(bool on);                              // 暂停/恢复生命周期和周期计时器
void Disable();                                   // 禁用 Buff(AddState(Disabled))
void Destroy();                                   // 销毁 Buff(触发 FinalEffect)

通过 IExecutionContext 访问上下文 ​

服务端的 Buff 实现了 IExecutionContext,可访问创建时的施法者、目标等信息:

csharp
#if SERVER
var caster = ((IExecutionContext)buff).Caster;     // 施法者
var ability = ((IExecutionContext)buff).Ability;    // 关联技能
var item = ((IExecutionContext)buff).Item;          // 关联物品
#endif

BuffManager ​

通过 entity.GetComponent<BuffManager>() 获取,通过 entity.GetOrCreateComponent<BuffManager>() 获取或创建。

继承自 ObjectManager 的方法 ​

csharp
Buff? Get(IGameLink<GameDataBuff> link);                    // 获取第一个匹配的 Buff
HashSet<Buff> GetAll();                                     // 获取所有 Buff(复制集合)
ReadOnlySet<Buff>? GetAll(IGameLink<GameDataBuff> link);    // 获取同一 Link 的所有实例
IEnumerable<Buff> Get(Func<Buff, bool> condition);          // 按条件筛选
Buff? GetOne(Func<Buff, bool> condition);                   // 按条件查找一个
IEnumerable<Buff> YieldAll();                               // 惰性遍历所有 Buff
bool IsEnabled(IGameLink<GameDataBuff> link);               // 检查 Link 是否启用

BuffManager 自有方法 ​

csharp
// 查询
bool HasBuff(IGameLink<GameDataBuff> buffLink);
bool HasAnyBuff(params IGameLink<GameDataBuff>[] buffLinks);
bool HasAllBuffs(params IGameLink<GameDataBuff>[] buffLinks);
bool HasState(UnitState state);
IEnumerable<UnitState> GetCurrentStates();

// 按极性查询
IEnumerable<Buff> GetBuffsByPolarity(BuffPolarity polarity);
IEnumerable<Buff> GetPositiveBuffs();
IEnumerable<Buff> GetNegativeBuffs();
IEnumerable<Buff> GetDispellableBuffs();

// 统计
int CountBuffs(Func<Buff, bool> predicate);
int CountBuffsByPolarity(BuffPolarity polarity);
int CountPositiveBuffs();
int CountNegativeBuffs();

// 移除和驱散
int RemoveByPredicate(Func<Buff, bool> predicate);          // 内部调用 Destroy()
int DispelBuffs(BuffPolarity polarity, bool onlyDispellable = true);
int DispelPositiveBuffs(bool onlyDispellable = true);
int DispelNegativeBuffs(bool onlyDispellable = true);
int ClearAllDispellableBuffs();

> 注意:BuffManager.Add() 和 BuffManager.Remove() 是 internal 方法,不可直接调用。要添加 Buff 请使用便利方法或效果树,要移除 Buff 请调用 buff.Destroy() 或使用 RemoveByPredicate。

事件 ​

事件说明
OnLinkActivated某个 Link 从无激活实例变为有激活实例
OnLinkDeactivated某个 Link 从有激活实例变为无激活实例
OnObjectAttached任何 Buff 实例被附加到管理器
OnObjectRefresh任何 Buff 实例被刷新(包括合并时)

此外,Buff 系统通过事件发布器发布以下事件(可通过 EventAggregator 订阅):

事件类型触发时机
EventBuffAttachedBuff 附加到单位时
EventBuffRemovedBuff 从单位移除时(在 FinalEffect 之前)
EventBuffPropertyChangeBuff 属性变化时(如层数、持续时间)

添加 Buff ​

方式一:效果树(推荐) ​

在技能或效果树中使用 GameDataEffectBuffAdd,保持完整的效果树上下文:

csharp
var buffAddEffect = new GameDataEffectBuffAdd(myLink)
{
    Buff = myBuffLink,                                    // 要添加的 Buff 类型
    Stack = new FuncUIntConstant(2),                      // 可选:层数覆盖
    Duration = new FuncTimeConstant(TimeSpan.FromSeconds(10)) // 可选:持续时间覆盖
};

方式二:便利方法(TriggerEncapsulation) ​

在没有效果树环境的脚本中直接添加 Buff:

csharp
#if SERVER
// Unit 扩展方法(最常用)
Buff? buff = unit.AddBuff(myBuffLink, caster);

// 带参数
Buff? buff = unit.AddBuff(myBuffLink, caster, stack: 3, duration: TimeSpan.FromSeconds(30));

// 静态方法
Buff? buff = BuffUtility.AddBuff(target, myBuffLink, caster);

// 在执行上下文中添加(保持效果树父子关系)
Buff? buff = BuffUtility.AddBuff(executionContext, myBuffLink, target);
// 或扩展方法:
Buff? buff = executionContext.AddBuff(myBuffLink, target);
#endif

> 注意:便利方法内部创建虚拟的 EffectBuffAdd 来记录施法者,但会丢失完整的效果树信息。在技能效果树中应使用 GameDataEffectBuffAdd。

BuffManager 扩展方法 ​

csharp
#if SERVER
var buffManager = unit.GetOrCreateComponent<BuffManager>();

// 单个添加
Buff? buff = buffManager.AddBuff(myBuffLink, caster, stack: 2);

// 批量添加
List<Buff> buffs = buffManager.AddBuffs(new[] { buffLink1, buffLink2 }, caster);

// 添加或刷新(已存在则更新剩余时间)
Buff? buff = buffManager.AddOrRefreshBuff(myBuffLink, caster, duration: TimeSpan.FromSeconds(30));
#endif

移除 Buff ​

csharp
#if SERVER
// 直接销毁 Buff 实例
buff.Destroy();

// 通过 BuffManager 按条件移除
var buffManager = unit.GetComponent<BuffManager>();
if (buffManager != null)
{
    // 移除所有减益
    buffManager.DispelNegativeBuffs();

    // 按条件移除
    int removed = buffManager.RemoveByPredicate(b => b.Cache.Polarity == BuffPolarity.Negative);

    // 清除所有可驱散 Buff
    buffManager.ClearAllDispellableBuffs();
}
#endif

效果树中可使用 GameDataEffectBuffRemove:

csharp
var removeEffect = new GameDataEffectBuffRemove(myLink)
{
    Buff = targetBuffLink,                       // 指定类型(null 不限类型)
    Stack = new FuncUIntConstant(1),             // 移除层数(null 全部移除)
    CategoryFilter = new HashSetFilter<BuffCategory>   // 按分类筛选
    {
        BuffCategory.CanBeDispelled
    },
    BuffValidator = (buff) =>                    // 自定义验证
    {
        return buff.Cache.Polarity == BuffPolarity.Negative ? CmdResult.Ok : CmdResult.Fail;
    }
};

Buff 生命周期 ​

创建 Buff
  │
  ├── OnAttached → 初始化响应、状态修改、启动计时器
  │     │
  │     └── OnLinkAttached → 执行 InitialEffect,应用启用/禁用配置
  │
  ├── 周期触发 → Period 计时器到期 → 执行 PeriodicEffect → 重新启动计时器
  │
  ├── 刷新(同施法者重复施加 + SingleInstancePerCaster)
  │     └── 合并层数 + 延长剩余时间 → 执行 RefreshEffect
  │
  ├── 验证器检查(每帧 Think)
  │     ├── PersistValidator 失败 → Destroy()
  │     └── EnableValidator 切换 → Disable() / Enable()
  │
  ├── 自然到期 → Duration 计时器到期 → 执行 ExpireEffect → Destroy()
  │
  └── Destroy()
        ├── 发布 EventBuffRemoved
        ├── 执行 FinalEffect
        ├── 停止引导
        └── 从 BuffManager 移除 → OnLinkDetached

生命周期效果说明 ​

效果字段触发时机典型用途
InitialEffectBuff 首次附加时播放添加特效、应用一次性效果
PeriodicEffect每个 Period 间隔持续伤害、持续治疗
RefreshEffect同施法者重复施加(合并时)播放刷新特效
ExpireEffect持续时间自然到期到期时的一次性效果
FinalEffectBuff 被移除时(包括手动销毁、到期、驱散)清理效果、结束特效

叠加机制 ​

SingleInstancePerCaster ​

当 BuffFlags.SingleInstancePerCaster = true 时,同一施法者对同一目标重复施加同一 Buff:

  • 合并层数(新旧实例的 Stack 相加,不超过 StackMax)
  • 延长剩余时间(取新旧的较大值)
  • 触发 RefreshEffect

不同施法者的 Buff 实例独立存在,受 InstanceMax 限制。

InstanceMax ​

当同一 Link 的 Buff 实例数超过 InstanceMax 时,最后一个实例被销毁。

层数操作 ​

csharp
#if SERVER
buff.AddStack(2);    // 增加 2 层
buff.AddStack(-1);   // 减少 1 层(注意参数是 int,可以为负)
buff.SetStack(5);    // 直接设置为 5 层
// 层数变化后自动刷新属性修改和状态
#endif

属性修改 ​

通过 Modifications 列表配置,Buff 激活时自动应用到单位属性系统:

csharp
var buff = new GameDataBuff(myLink)
{
    Modifications = new List<UnitPropertyModification>
    {
        new()
        {
            Property = UnitProperty.AttackDamage,
            Value = (_) => 10  // 固定增加 10 点攻击力
        },
        new()
        {
            Property = UnitProperty.MovementSpeed,
            SubType = MyPropertySubType.Percentage, // 自定义子属性(需在属性公式中实现逻辑)
            Value = (_) => 20  // 20%
        }
    }
};

属性修改随 Buff 的启用/禁用/销毁自动生效和移除,无需手动管理。

状态管理 ​

csharp
var stunBuff = new GameDataBuff(myLink)
{
    Polarity = BuffPolarity.Negative,
    Categories = [BuffCategory.CanBeDispelled],
    Duration = new FuncTimeConstant(TimeSpan.FromSeconds(3)),
    AddStates = [UnitState.Stunned, UnitState.Uncommandable]
};

var immuneBuff = new GameDataBuff(myLink)
{
    Polarity = BuffPolarity.Positive,
    Duration = new FuncTimeConstant(TimeSpan.FromSeconds(5)),
    RemoveStates = [UnitState.Stunned, UnitState.Silenced],   // 附加时移除这些状态
    ImmuneStates = [UnitState.Stunned, UnitState.Silenced]    // 附加期间免疫这些状态
};

查询状态:

csharp
var buffManager = unit.GetComponent<BuffManager>();
if (buffManager != null)
{
    bool isStunned = buffManager.HasState(UnitState.Stunned);
    var allStates = buffManager.GetCurrentStates(); // 所有 Buff 添加的状态
}

验证器 ​

PersistValidator ​

每帧检查,验证失败时立即销毁 Buff:

csharp
PersistValidator = myValidator  // ValidatorEffect 委托,返回 CmdResult
// 当 PersistValidator(StackParam) != CmdResult.Ok 时,Buff 被 Destroy()

EnableValidator ​

每帧检查,控制 Buff 启用/禁用状态(不销毁):

csharp
EnableValidator = myValidator  // ValidatorEffect 委托,返回 bool
// 返回 true → 启用 Buff(移除 Disabled 状态)
// 返回 false → 禁用 Buff(添加 Disabled 状态)

禁用的 Buff 仍然存在且计时继续,但属性修改和状态变更不生效。

启用/禁用其他 Buff 和技能 ​

GameDataBuff 可以在附加时启用或禁用其他 Buff 和技能:

csharp
var buff = new GameDataBuff(myLink)
{
    // Buff 存在期间启用指定的 Buff 和技能
    BuffsEnable = [otherBuffLink],
    AbilitiesEnable = [abilityLink],
    BuffCategoriesEnable = [myCategory],

    // Buff 存在期间禁用指定的 Buff 和技能
    BuffsDisable = [someBuffLink],
    AbilitiesDisable = [someAbilityLink],
    BuffCategoriesDisable = [someCategory],
    AbilityCategoriesDisable = [someAbilityCategory]
};

附加时应用配置,移除时自动反转。使用引用计数机制,多个 Buff 同时禁用同一目标时不会冲突。

引导 Buff ​

设置 BuffFlags.Channeling = true 使 Buff 成为引导效果。引导 Buff 与施法者的引导状态绑定——当施法者的引导被打断时,Buff 自动销毁。

csharp
var channeledBuff = new GameDataBuff(myLink)
{
    BuffFlags = new BuffFlags { Channeling = true },
    Duration = new FuncTimeConstant(TimeSpan.FromSeconds(8)),
    Period = new FuncTimeConstant(TimeSpan.FromSeconds(1)),
    PeriodicEffect = healEffectLink
};

注意:引导 Buff 不会与 SingleInstancePerCaster 合并(源码中特别排除了 Channeling Buff 的合并逻辑)。

死亡处理 ​

PermanentDisableWhenDead行为
false任意死亡时移除 Buff
truetrue(默认)死亡时禁用(暂停周期计时器),复活后恢复
truefalse死亡后继续生效

客户端表现 ​

Actor 表现 ​

ActorArray 配置 Buff 关联的 Actor(模型/特效),由框架的 IActorScopeOwner 机制自动管理生命周期。

UI 组件 ​

框架提供 BuffBar 和 BuffIcon 控件(在 GameSystemUI.BuffSystemUI.Advanced 命名空间):

csharp
#if CLIENT
// 创建 BuffBar 并绑定单位
var buffBar = BuffBar.Create(unit);
buffBar.Parent = myPanel;

// 或手动设置
var buffBar = BuffBar.Create();
buffBar.SetUnit(unit);
buffBar.Parent = myPanel;

// 单独的 BuffIcon
var icon = BuffIcon.Create(buff);
icon.Parent = myPanel;
#endif

GameDataControlBuffBar 配置 BuffBar 的过滤和样式:

csharp
var barConfig = new GameDataControlBuffBar(myLink)
{
    BuffWidth = 32,
    BuffHeight = 32,
    BuffMargin = 2,
    BuffCategoryFilter = BuffCategoryFilter.All,
    BuffPolarityFilter = BuffPolarityFilter.All
};

BuffIcon 提供详细的显示控制:

csharp
#if CLIENT
var icon = BuffIcon.Create(buff);
icon.SetPolarity(BuffPolarity.Positive);
icon.SetIcon("path/to/icon");
icon.SetCooldown(remaining, total, UIDurationFormat.CircularProgress);
icon.SetStack(3);
icon.SetBlink(); // 即将过期时闪烁
#endif

BuffDisplayData 封装了 Buff 的显示信息,可通过 BuffIcon.CreateBuffDisplayData(buff) 创建。

完整示例 ​

定义 Buff 数编 ​

csharp
// 攻击力增益
public static readonly GameLink<GameDataBuff, GameDataBuff> StrengthBuffLink = new("StrengthBuff");

static MyBuffs()
{
    _ = new GameDataBuff(StrengthBuffLink)
    {
        DisplayName = new LocalizedString("力量增益"),
        Polarity = BuffPolarity.Positive,
        Categories = [BuffCategory.CanBeDispelled],
        Duration = new FuncTimeConstant(TimeSpan.FromSeconds(30)),
        StackStart = 1,
        StackMax = new FuncUIntConstant(5),
        BuffFlags = new BuffFlags { SingleInstancePerCaster = true },
        Modifications =
        [
            new() { Property = UnitProperty.AttackDamage, Value = (_) => 10 }
        ]
    };
}

定义 DOT(持续伤害)Buff ​

csharp
public static readonly GameLink<GameDataBuff, GameDataBuff> PoisonBuffLink = new("PoisonBuff");

static MyBuffs()
{
    _ = new GameDataBuff(PoisonBuffLink)
    {
        DisplayName = new LocalizedString("中毒"),
        Polarity = BuffPolarity.Negative,
        Categories = [BuffCategory.CanBeDispelled],
        Duration = new FuncTimeConstant(TimeSpan.FromSeconds(12)),
        Period = new FuncTimeConstant(TimeSpan.FromSeconds(3)),
        PeriodicEffect = poisonDamageEffectLink,
        StackStart = 1,
        StackMax = new FuncUIntConstant(3)
    };
}

定义控制类 Buff ​

csharp
public static readonly GameLink<GameDataBuff, GameDataBuff> StunBuffLink = new("StunBuff");

static MyBuffs()
{
    _ = new GameDataBuff(StunBuffLink)
    {
        DisplayName = new LocalizedString("眩晕"),
        Polarity = BuffPolarity.Negative,
        Categories = [BuffCategory.CanBeDispelled],
        Duration = new FuncTimeConstant(TimeSpan.FromSeconds(3)),
        AddStates = [UnitState.Stunned, UnitState.Uncommandable]
    };
}

添加和查询 Buff ​

csharp
#if SERVER
public static void OnGameTriggerInitialization()
{
    Game.OnGameStart += OnGameStart;
}

private static async Task OnGameStart()
{
    // 示例:给所有玩家英雄添加增益 Buff
    foreach (var player in Player.AllPlayers)
    {
        var hero = player.Hero;
        if (hero == null) continue;

        var buff = hero.AddBuff(StrengthBuffLink);
        if (buff != null)
        {
            Game.Logger.LogInformation("已为 {Player} 的英雄添加力量 Buff", player.Id);
        }
    }

    // 等待一段时间后检查 Buff 状态
    await Game.Delay(TimeSpan.FromSeconds(10));

    foreach (var player in Player.AllPlayers)
    {
        var hero = player.Hero;
        if (hero == null) continue;

        var buffManager = hero.GetComponent<BuffManager>();
        if (buffManager == null) continue;

        // 检查是否有增益 Buff
        if (buffManager.HasBuff(StrengthBuffLink))
        {
            var buff = buffManager.Get(StrengthBuffLink);
            Game.Logger.LogInformation("力量 Buff 剩余时间: {Time}", buff?.RemainingTime);
        }

        // 统计
        Game.Logger.LogInformation("增益数: {Count}, 减益数: {Debuffs}",
            buffManager.CountPositiveBuffs(), buffManager.CountNegativeBuffs());
    }
}
#endif

驱散逻辑 ​

csharp
#if SERVER
public static void DispelTarget(Unit caster, Unit target)
{
    var buffManager = target.GetComponent<BuffManager>();
    if (buffManager == null) return;

    if (target.IsAllyWith(caster))
    {
        // 友方:驱散减益
        int removed = buffManager.DispelNegativeBuffs();
        Game.Logger.LogInformation("驱散了 {Count} 个减益", removed);
    }
    else
    {
        // 敌方:驱散增益
        int removed = buffManager.DispelPositiveBuffs();
        Game.Logger.LogInformation("驱散了 {Count} 个增益", removed);
    }
}
#endif

相关文档 ​