local BuffComponent = class("BuffComponent") local BuffStates = require "Battle/Logic/Buff/BuffData/BuffStates" local LuaConst=LuaConst local ipairs=ipairs local private = {} function BuffComponent:initialize(entity) self.entity = entity --标志类型buff self.CurrentBuffStates = BuffStates:new() --当前受击类型 self.CurrentBuffHitType = LuaConst.BuffHitType.None --Entity身上存在的Buff数据 -- { [buffid] = buffObject} self.CurBuffObjectList = {} -- 元素是buffObject self.CurBuffObjectLinkedListHead = nil -- buffObject链表头,用于遍历,可以直接拿链表遍历,节约一些gc --BuffObject字典,仅用于传入单个key来查询,不可用于遍历 self.CurBuffObjectDic = {} --key是BuffID,元素是BuffObject。 这个字典要跟CurBuffObjectList存放的元素完全一致,这里多存一个字典,减少查询时的耗时。因为修改比较低频,查询非常高频。 self.dotBuffOverrideCallFrequencyDic = {} --key是BuffID,val是定点数。 用于存放dotBuff的CallFrequency字段的覆盖值。 self.RecoverWhenExclusiveOffBuffDatas = {} --一些被其他Buff互斥删除的,且需要在其他Buff结束时恢复的Buff --↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓ self.HasBuffOfInvicibleGroup = false --为了性能,HasBuffOfGroup的一些查询会添加缓存,目前增加Invicible组的(LuaConst.BuffGroupType.Invincible)缓存 end function BuffComponent:GetBuffUpdateDataSourced(buffId, sourceEntityID) local buffObject = self:GetBuffObjectByBuffId(buffId) if not buffObject then return nil,-1 end local buffUpdateData = buffObject.BuffUpdateData if buffUpdateData then return buffUpdateData.BuffLayer > 0 and buffUpdateData or nil,-1 end local buffUpdateList = buffObject.BuffUpdateList for i,updateData in ipairs(buffUpdateList) do local sid = -1 if updateData.SourceEntity then sid = updateData.SourceEntity._logicInitData.EntityID end if sid == sourceEntityID then return updateData.BuffLayer > 0 and updateData or nil,i end end return nil,-1 end --可能返回空 function BuffComponent:GetBuffObjectByBuffId(buffId) -- old↓ 遍历list查询,消耗比较大,需要遍历 -- for i,buffObject in ipairs(self.CurBuffObjectList) do -- if buffObject.BuffID == buffId then -- return buffObject, i -- end -- end -- old↑ -- new↓ 直接kv查询,消耗小一点。依赖于额外储存的一份BuffObject字典,内存换时间 return self.CurBuffObjectDic[buffId] end -- 返回BuffObject和它在CurBuffObjectList里的index,可能返回空 function BuffComponent:GetBuffObjectAndIndexByBuffId(buffId) for i,buffObject in ipairs(self.CurBuffObjectList) do if buffObject.BuffID == buffId then return buffObject, i end end end function BuffComponent:CanRecvDebuff() return not self:HasBuff(LuaConst.SpecialBuffs.SafeZoneBuff) end function BuffComponent:RemoveBuffOnLinkedList(buffObject) local node = self.CurBuffObjectLinkedListHead local count = 0 while node do if node == buffObject then if node.lastBuffObject then node.lastBuffObject.nextBuffObject = node.nextBuffObject end if node.nextBuffObject then node.nextBuffObject.lastBuffObject = node.lastBuffObject if node.nextBuffObject.lastBuffObject == nil then self.CurBuffObjectLinkedListHead = node.nextBuffObject end else if not node.lastBuffObject then --无next也无last,则直接置空head self.CurBuffObjectLinkedListHead = nil end end break else node = node.nextBuffObject end count = count + 1 if count > 999 then logging.error(LTAG.ERROR, "HYW : 代码哪写错了,无限循环了! @BuffComponent:RemoveBuffOnLinkedList") break end end end --↓ 另一种恢复机制的代码,更科学,但是因为现在策划不太好用表来描述Buff之间的恢复传递,所以注掉了。(恢复传递异常: A互斥Buff M,添加A时顶掉M。A结束时添加Buff B。Buff B免疫M。B结束时,如果B没有配置互斥M,则M不会被加回来。并且策划很多情况下不能配置B互斥M) -- function BuffComponent:OnExclusiveDelete(buffData) -- if buffData.RecoverWhenExclusiveOff then -- table.insert(self.RecoverWhenExclusiveOffBuffDatas, buffData) -- end -- end -- function BuffComponent:OnExclusiveRecover(buffData) -- for i,_buffData in ipairs(self.RecoverWhenExclusiveOffBuffDatas) do -- if _buffData == buffData then -- table.remove(self.RecoverWhenExclusiveOffBuffDatas, i) -- return -- end -- end -- logging.error(LTAG.ERROR, "HYW : 警告!!! OnExclusiveRecover 删除记录失败了(程序调试用,不影响游戏正常运行)") -- end -- function BuffComponent:GetRecoverWhenExclusiveOffBuffDatas() -- return self.RecoverWhenExclusiveOffBuffDatas -- end --↑ function BuffComponent:OnBuffObjectAllDelete(buffObject) local buffData = buffObject:GetData() -- 可能在DeadQuit 后还进入 ,此时buffData为nil if buffData and buffData.BuffGroup == LuaConst.BuffGroupType.Invincible then self.HasBuffOfInvicibleGroup = self:HasBuffOfGroup(LuaConst.BuffGroupType.Invincible) end end function BuffComponent:SetBuffObject(buffObject) local oldBuffObject, index = self:GetBuffObjectAndIndexByBuffId(buffObject.BuffID) if oldBuffObject then --如果已经存在了,就删掉老的这个buffObject table.remove(self.CurBuffObjectList, index) self.CurBuffObjectDic[buffObject.BuffID] = nil --更新链表 self:RemoveBuffOnLinkedList(oldBuffObject) oldBuffObject:Dispose() end table.insert(self.CurBuffObjectList, buffObject) self.CurBuffObjectDic[buffObject.BuffID] = buffObject --更新链表 buffObject.nextBuffObject = self.CurBuffObjectLinkedListHead --前插链表 buffObject.lastBuffObject = nil if self.CurBuffObjectLinkedListHead then self.CurBuffObjectLinkedListHead.lastBuffObject = buffObject end self.CurBuffObjectLinkedListHead = buffObject local allDeleteCallback = function(buffObject) self:OnBuffObjectAllDelete(buffObject) end buffObject:SetAllDeleteCallback(allDeleteCallback) end function BuffComponent:OnBuffSetData(buffObject, updateData, index) if buffObject:GetData().BuffGroup == LuaConst.BuffGroupType.Invincible then self.HasBuffOfInvicibleGroup = true end end function BuffComponent:ClearAllBuff() for i=1,#self.CurBuffObjectList do self.CurBuffObjectList[i]:Dispose() self.CurBuffObjectList[i] = nil end for k,v in pairs(self.CurBuffObjectDic) do self.CurBuffObjectDic[k] = nil end self.CurBuffObjectLinkedListHead = nil self.HasBuffOfInvicibleGroup = false end function BuffComponent:DeleteBuffOfGroup(buffGroup) local buffObject = nil for i=#self.CurBuffObjectList, 1, -1 do buffObject = self.CurBuffObjectList[i] if buffObject:GetData().BuffGroup == buffGroup then -- require "Battle/Logic/Buff/BuffStatistic".DeleteOneBuff(buffObject.BuffID, self.entity) self.CurBuffObjectDic[buffObject.BuffID] = nil table.remove(self.CurBuffObjectList, i) if buffObject:GetData().BuffGroup == LuaConst.BuffGroupType.Invincible then self.HasBuffOfInvicibleGroup = self:HasBuffOfGroup(LuaConst.BuffGroupType.Invincible) end self:RemoveBuffOnLinkedList(buffObject) buffObject:Dispose() end end end function BuffComponent:RemoveNonValidBuff(buffObject, index) self:RemoveBuffOnLinkedList(buffObject) table.remove(self.CurBuffObjectList, index) self.CurBuffObjectDic[buffObject.BuffID] = nil end --如果buffId对应的updateData层数为0,则会返回nil function BuffComponent:GetBuffUpdateData(buffId, sourceEntity) local buffObject = self.CurBuffObjectDic[buffId] --内联以提升性能 之前是 self:GetBuffObjectByBuffId(buffId) if not buffObject then return nil end local buffUpdateData = buffObject.BuffUpdateData if buffUpdateData then return buffUpdateData.BuffLayer > 0 and buffUpdateData or nil end for i,updateData in ipairs(buffObject.BuffUpdateList) do if updateData.BuffLayer > 0 and (sourceEntity == nil or sourceEntity == updateData.SourceEntity) then return updateData end end return nil end function BuffComponent:GetAllBuffUpdateData(buffId ,outList) local buffObject = self:GetBuffObjectByBuffId(buffId) if not buffObject then return end local buffUpdateData = buffObject.BuffUpdateData if buffUpdateData and buffUpdateData.BuffLayer > 0 then table.insert(outList , buffUpdateData) end local buffUpdateList = buffObject.BuffUpdateList if buffUpdateList then for i,updateData in ipairs(buffUpdateList) do if updateData.BuffLayer > 0 then table.insert(outList , updateData) end end end end function BuffComponent:CheckHasBuffState(buffId) return self.CurrentBuffStates:Get(buffId) end --是否挂着硬控buff function BuffComponent:HasHardControlBuff() return self:HasBuffOfGroup(LuaConst.BuffGroupType.HardControl) or self:HasBuffOfGroup(LuaConst.BuffGroupType.SystemHardControl) or self:HasBuffOfGroup(LuaConst.BuffGroupType.LoseControl) end --是否有指定BuffGroup的buff function BuffComponent:HasBuffOfGroup(buffGroup) local result = false for i,buff in ipairs(self.CurBuffObjectList) do if buff:GetData().BuffGroup == buffGroup then if buff.BuffUpdateData and buff.BuffUpdateData.BuffLayer > 0 then result = true end if buff.BuffUpdateList then for i,updateData in ipairs(buff.BuffUpdateList) do if updateData.BuffLayer > 0 then result = true break end end end if result then break end end end return result end function BuffComponent:HasBuff(buffId) local result = false local buffObject = self.CurBuffObjectDic[buffId] if buffObject and buffObject.BuffID == buffId and buffObject:GetBuffLayer() > 0 then result = true end return result end function BuffComponent:HasBuffOfSourceEntity(buffId, sourceEntity) local result = false local buffObject = self.CurBuffObjectDic[buffId] if buffObject and buffObject.BuffID == buffId and buffObject:GetBuffLayer() > 0 then if buffObject.BuffUpdateList then for i,buffUpdateData in ipairs(buffObject.BuffUpdateList) do if sourceEntity == buffUpdateData.SourceEntity then if buffUpdateData.BuffLayer > 0 then result = true end break end end else --此处的else等价于不记录来源,直接返回true result = true end end return result end --获取Buff列表副本(已弃用,因为性能太差,改用链表了) -- function BuffComponent:GetBuffObjectListCopy(container) -- container = container or {} -- for i,buffObject in ipairs(self.CurBuffObjectList) do -- table.insert(container, buffObject) -- end -- return container -- end function BuffComponent:PauseBuffListener() for i,buffObject in ipairs(self.CurBuffObjectList) do buffObject:PauseListener() end end function BuffComponent:ResumeBuffListener() for i,buffObject in ipairs(self.CurBuffObjectList) do buffObject:ResumeListener() end end function BuffComponent:AfterGrabOther(target, buffId) if self.grabBuffId ~= nil and self.grabBuffId ~= buffId then logging.error(LTAG.ERROR, "HYW : 警告!! 多次抓取叠加,会出bug!!") end self.grabBuffId = buffId end --buffId:这个release是哪个buff发动的。存在buffId为nil的情况,表示这个release不来自buff,此时需要删除buff function BuffComponent:AfterRealseGrabOther(target, buffId) if buffId == nil then if self.grabBuffId then local grabbedEntity = self.entity.components.base.GrabbedEntity if grabbedEntity then --这种情况是self.grabBuffId发动的grab被其他机制打断了,此时要删除self.grabBuffId SystemManager.DeleteBuff(grabbedEntity, self.grabBuffId, self.entity) else logging.error(LTAG.ERROR, "HYW : 警告!想要释放抓取的单位不存在!") end end --else --如果是buff自己发动,则由buff自己删除self.grabBuffId,这里不做任何处理 end self.grabBuffId = nil end -- callFrequency是定点数-毫秒 function BuffComponent:SetDotBuffCallFrequency(buffId, callFrequency) self.dotBuffOverrideCallFrequencyDic[buffId] = callFrequency end function BuffComponent:GetDotBuffCallFrequency(buffData) local result = self.dotBuffOverrideCallFrequencyDic[buffData.BuffID] if result == nil then result = buffData.CallFrequency end return result end return BuffComponent