找回密码
 点一下
查看: 1123|回复: 5

关于替换单位

[复制链接]
发表于 2013-3-11 11:28:07 | 显示全部楼层 |阅读模式
本帖最后由 冷漠 于 2013-3-12 06:28 编辑

忽然有点纠结一个问题

老狼的UI注释写着替换单位会造成泄露

那个是指只有金矿才会引起或是该动作都会引起泄露?
发表于 2013-3-11 12:55:39 | 显示全部楼层
必定会泄露

因为其实不存在替换单位这个原生函数。

触发器里的替换单位其实是个jass自定义函数。简单来说就是干掉原单位,创建新单位,设置好血量。然后把新单位赋值给“最后替换的单位”


问题在于,在这个函数中,oldUnit和newUnit都没有set null,而旧单位却被删除了。所以肯定会造成泄漏。
[jass]
function ReplaceUnitBJ takes unit whichUnit, integer newUnitId, integer unitStateMethod returns unit
    local unit    oldUnit = whichUnit
    local unit    newUnit
    local boolean wasHidden
    local integer index
    local item    indexItem
    local real    oldRatio

    // If we have bogus data, don't attempt the replace.
    if (oldUnit == null) then
        set bj_lastReplacedUnit = oldUnit
        return oldUnit
    endif

    // Hide the original unit.
    set wasHidden = IsUnitHidden(oldUnit)
    call ShowUnit(oldUnit, false)

    // Create the replacement unit.
    if (newUnitId == 'ugol') then
        set newUnit = CreateBlightedGoldmine(GetOwningPlayer(oldUnit), GetUnitX(oldUnit), GetUnitY(oldUnit), GetUnitFacing(oldUnit))
    else
        set newUnit = CreateUnit(GetOwningPlayer(oldUnit), newUnitId, GetUnitX(oldUnit), GetUnitY(oldUnit), GetUnitFacing(oldUnit))
    endif

    // Set the unit's life and mana according to the requested method.
    if (unitStateMethod == bj_UNIT_STATE_METHOD_RELATIVE) then
        // Set the replacement's current/max life ratio to that of the old unit.
        // If both units have mana, do the same for mana.
        if (GetUnitState(oldUnit, UNIT_STATE_MAX_LIFE) > 0) then
            set oldRatio = GetUnitState(oldUnit, UNIT_STATE_LIFE) / GetUnitState(oldUnit, UNIT_STATE_MAX_LIFE)
            call SetUnitState(newUnit, UNIT_STATE_LIFE, oldRatio * GetUnitState(newUnit, UNIT_STATE_MAX_LIFE))
        endif

        if (GetUnitState(oldUnit, UNIT_STATE_MAX_MANA) > 0) and (GetUnitState(newUnit, UNIT_STATE_MAX_MANA) > 0) then
            set oldRatio = GetUnitState(oldUnit, UNIT_STATE_MANA) / GetUnitState(oldUnit, UNIT_STATE_MAX_MANA)
            call SetUnitState(newUnit, UNIT_STATE_MANA, oldRatio * GetUnitState(newUnit, UNIT_STATE_MAX_MANA))
        endif
    elseif (unitStateMethod == bj_UNIT_STATE_METHOD_ABSOLUTE) then
        // Set the replacement's current life to that of the old unit.
        // If the new unit has mana, do the same for mana.
        call SetUnitState(newUnit, UNIT_STATE_LIFE, GetUnitState(oldUnit, UNIT_STATE_LIFE))
        if (GetUnitState(newUnit, UNIT_STATE_MAX_MANA) > 0) then
            call SetUnitState(newUnit, UNIT_STATE_MANA, GetUnitState(oldUnit, UNIT_STATE_MANA))
        endif
    elseif (unitStateMethod == bj_UNIT_STATE_METHOD_DEFAULTS) then
        // The newly created unit should already have default life and mana.
    elseif (unitStateMethod == bj_UNIT_STATE_METHOD_MAXIMUM) then
        // Use max life and mana.
        call SetUnitState(newUnit, UNIT_STATE_LIFE, GetUnitState(newUnit, UNIT_STATE_MAX_LIFE))
        call SetUnitState(newUnit, UNIT_STATE_MANA, GetUnitState(newUnit, UNIT_STATE_MAX_MANA))
    else
        // Unrecognized unit state method - ignore the request.
    endif

    // Mirror properties of the old unit onto the new unit.
    //call PauseUnit(newUnit, IsUnitPaused(oldUnit))
    call SetResourceAmount(newUnit, GetResourceAmount(oldUnit))

    // If both the old and new units are heroes, handle their hero info.
    if (IsUnitType(oldUnit, UNIT_TYPE_HERO) and IsUnitType(newUnit, UNIT_TYPE_HERO)) then
        call SetHeroXP(newUnit, GetHeroXP(oldUnit), false)

        set index = 0
        loop
            set indexItem = UnitItemInSlot(oldUnit, index)
            if (indexItem != null) then
                call UnitRemoveItem(oldUnit, indexItem)
                call UnitAddItem(newUnit, indexItem)
            endif

            set index = index + 1
            exitwhen index >= bj_MAX_INVENTORY
        endloop
    endif

    // Remove or kill the original unit.  It is sometimes unsafe to remove
    // hidden units, so kill the original unit if it was previously hidden.
    if wasHidden then
        call KillUnit(oldUnit)
        call RemoveUnit(oldUnit)
    else
        call RemoveUnit(oldUnit)
    endif

    set bj_lastReplacedUnit = newUnit
    return newUnit
endfunction
[/jass]

点评

原来如此,虽然看不懂代码(= =b),但还是明白了,感谢头目。 顺便问另一个问题,最近做了一个类似被动的无光之盾技能 但有玩家发现在盾破时最大生命值会减少 排查后发现是增加生命值的技能引起的 如果增加  详情 回复 发表于 2013-3-12 06:28
回复

使用道具 举报

发表于 2013-3-11 13:29:37 | 显示全部楼层
不是吧,我弄了个操作死尸保留生物原技能,就是利用替换单位的……
YD编辑器好像也没新增一个替换的函数
回复

使用道具 举报

发表于 2013-3-11 15:18:00 | 显示全部楼层
替换单位必然会导致泄漏。
如果要实现效果请用删除新建单位。
回复

使用道具 举报

 楼主| 发表于 2013-3-12 06:28:12 | 显示全部楼层
麦德三世 发表于 2013-3-11 12:55
必定会泄露

因为其实不存在替换单位这个原生函数。

原来如此,虽然看不懂代码(= =b),但还是明白了,感谢头目。


顺便问另一个问题,最近做了一个类似被动的无光之盾技能
但有玩家发现在盾破时最大生命值会减少
排查后发现是增加生命值的技能引起的
如果增加的生命值的数值为“99999”,那么触发会正常运行
但我用Shift键设置为“1000000000”的时候便会扣取最大生命值
这个Bug似乎以前没有出现过,是新版本的原因还是一直就有这个问题了?
回复

使用道具 举报

发表于 2013-3-12 21:32:51 | 显示全部楼层
一直存在,可以简单的理解成是因为生命上限溢出了,解决办法么,在确保地图正常伤害会小于某个值的情况下,把这个增加生命上限的技能的数值改小
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 点一下

本版积分规则

Archiver|移动端|小黑屋|地精研究院

GMT+8, 2024-12-23 19:23 , Processed in 0.209472 second(s), 27 queries .

Powered by Discuz! X3.5

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表