XGM Forum
Сайт - Статьи - Проекты - Ресурсы - Блоги

Форуме в режиме ТОЛЬКО ЧТЕНИЕ. Вы можете задать вопросы в Q/A на сайте, либо создать свой проект или ресурс.
Вернуться   XGM Forum > Warcraft> Академия: форум для вопросов> Jass
Ник
Пароль
Войти через VK в один клик
Сайт использует только имя.

Ответ
 
FREEZE_ball
Cataclysm => жара
offline
Опыт: 15,247
Активность:
Оптимизировать?
Сделал систему сбора аггро, как в мморпг. Суть системы в том, что она должна заставлять мобов, входящих в бой, каждые две секунды проверять свой аггро лист на приоритетные цели. Суть проблемы же в том, что один игрок играет в карту 2+ часа без каких-либо утечек. Но когда игроков двое, и, тем паче, трое, утечки начинаются буквально через пятнадцать минут. Прошу помочь мне оптимизировать код.

Система использует XAT.
» стена текста

Код:
library AggroSystem initializer AggroSystemInit uses XAT
globals
    private trigger asi
    private player agres //игрок 12 (нейтрально-враждебный)
endglobals

struct AS //структура, создаваемая для каждого вошедшего в бой моба.
    unit u //моб, вошедший в бой.
    unit array target[50] //массив возможных целей моба.
    real array aggro[50] //массив агрессии целей моба в соответствии с предыдущей переменной.
    timer check //таймер, каждые две секунды проверяющий приоритетные цели моба.
endstruct

public function GetAggro takes unit whichMob, unit whichAggro returns real //функция возвращает аггро моба к юниту.
    local AS as = AS(GetUnitData(whichMob))
    local integer i = 0
    if as != null then
      loop
        exitwhen i == 26
        if as.target[i] == whichAggro then
          return as.aggro[i]
        endif
        set i = i+1
      endloop
    endif
    return 0.00
endfunction

struct EBSE //маленькая структура (и две следующих функции) на эффект, который создаётся для каждого моба, вступившего в бой.
    effect e
endstruct
private function SETimer takes nothing returns nothing
    local EBSE this = EBSE(GetDataBX(GetExpiredTimer()))
    call DestroyEffect(this.e)
    call RemoveDataBX(GetExpiredTimer())
    call this.destroy()
    call DestroyTimer(GetExpiredTimer())
endfunction
private function EnterBattleSE takes unit u returns nothing
    local EBSE this = EBSE.create()
    local timer lt = CreateTimer()
    set this.e = AddSpecialEffectTarget("Abilities\\Spells\\Other\\TalkToMe\\TalkToMe.mdl", u, "overhead")
    call SetDataBX(lt, integer(this))
    call TimerStart(lt, 0.3, false, function SETimer)
endfunction

private function CheckAggroList takes nothing returns nothing //функция на проверку аггро-листа.
    local timer tr = GetExpiredTimer()
    local AS as = AS(GetAggroTimer(tr))
    local boolean b = false
    local integer i = 0
    local integer max = 0
    local real cmax = 0
    loop
      exitwhen i == 51 or b == true
        if as.target[i] == null then
          set b = true
        else
        if as.aggro[i] < 0 then 
          set as.aggro[i] = 0
        endif
          if cmax < as.aggro[i] and GetUnitState(as.target[i], UNIT_STATE_LIFE) > 0 then
            set cmax = as.aggro[i]
            set max = i
          endif
        endif
      set i = i+1
    endloop
    if cmax != 0 then
      //call BJDebugMsg(GetUnitName(as.u)+"`s highiest aggro on "+GetUnitName(as.target[max])+" is "+R2S(cmax))
      call IssueTargetOrder(as.u, "attack", as.target[max])
    endif
endfunction

private function CreateNewAggroList takes unit whichMob returns nothing //создание нового аггро листа.
    local AS as = AS.create()
    set as.u = whichMob
    set as.check = CreateTimer()
    call SetAggroTimer(as.check, integer(as))
    call TimerStart(as.check, 2, true, function CheckAggroList)
    call SetUnitData(whichMob, integer(as))
endfunction

private function IsMobHasAggroList takes unit whichMob returns boolean //проверка, есть ли аггро лист у моба.
    local AS as = AS(GetUnitData(whichMob))
    if as == null then
      return false
    endif
    return true
endfunction

private function SetAggro takes unit whichMob, unit whichAggro, real whichNum returns nothing  //установка аггро листа для моба, если у него ещё нет.
    local AS as = AS(GetUnitData(whichMob))
    local integer i = 0
    local boolean bb = false
    if IsMobHasAggroList(whichMob) == false then
      call CreateNewAggroList(whichMob)
    endif
    set as = AS(GetUnitData(whichMob))
    loop
      exitwhen i == 51 or bb == true
      if as.target[i] == null then
        set as.target[i] = whichAggro
        set bb = true
        set as.aggro[i] = whichNum
      else
        if as.target[i] == whichAggro then
          set bb = true
          set as.aggro[i] = whichNum
        endif
      endif
      set i = i+1
    endloop
endfunction

public function RemoveAggro takes unit whichMob returns nothing //очищение аггро листа моба.
    local AS as = AS(GetUnitData(whichMob))
    local integer i = 0
    //call BJDebugMsg(GetUnitName(as.u)+"`s aggro is cleared!")
    set as.u = null
    call RemoveAggroTimer(as.check)
    call DestroyTimer(as.check)
    call RemoveUnitData(whichMob)
    loop
      exitwhen i == 51
      set as.target[i] = null
      set as.aggro[i] = 0
      set i = i+1
    endloop
endfunction

public function ModifyAggro takes unit whichMob, unit whichAggro, real whichNum returns nothing //модификация аггро (добавление числа к аггро)
    local AS as = AS(GetUnitData(whichMob))
    if IsMobHasAggroList(whichMob) == false then
      call CreateNewAggroList(whichMob)
    endif
    set as = AS(GetUnitData(whichMob))
    //! textmacro InitHeroAggroModifier takes Type, Mod
    if GetUnitTypeId(whichAggro) == $Type$ then
      set whichNum = whichNum*$Mod$
    endif
    //! endtextmacro
    //! runtextmacro InitHeroAggroModifier("'h00E'","3") //Militia   (эти тестмакро модифицируют получаемый аггро)
    //! runtextmacro InitHeroAggroModifier("'h00H'","1") //Patroiler
    //! runtextmacro InitHeroAggroModifier("'h00F'","0.3") //Village Priest
    //! runtextmacro InitHeroAggroModifier("'n00V'","0.9") //Archer
    //! runtextmacro InitHeroAggroModifier("'n00W'","0") //Tower Archer
    //! runtextmacro InitHeroAggroModifier("'E000'","0.9") //Faerie Dragon
    //! runtextmacro InitHeroAggroModifier("'H00K'","3") //Druid Bear
    //! runtextmacro InitHeroAggroModifier("'H00A'","4") //Captain
    //! runtextmacro InitHeroAggroModifier("'H00I'","0.9") //Priest
    //! runtextmacro InitHeroAggroModifier("'O009'","0.7") //Rogue
    //! runtextmacro InitHeroAggroModifier("'O00A'","0.9") //Shadow Priest
    //! runtextmacro InitHeroAggroModifier("'O000'","0.9") //Witch Doctor
    //! runtextmacro InitHeroAggroModifier("'U000'","0.7") //Death Knight
    //! runtextmacro InitHeroAggroModifier("'h00D'","0") //Dummy1
    //! runtextmacro InitHeroAggroModifier("'h009'","0") //Dummy2
    //! runtextmacro InitHeroAggroModifier("'h00B'","0") //Shield Bash Dummy
    //! runtextmacro InitHeroAggroModifier("'u002'","2") //Ghoul 1
    //! runtextmacro InitHeroAggroModifier("'u003'","2") //Ghoul 2
    //! runtextmacro InitHeroAggroModifier("'u004'","2") //Ghoul 3
    //! runtextmacro InitHeroAggroModifier("'u005'","2") //Ghoul 4
    //! runtextmacro InitHeroAggroModifier("'u001'","2") //Ghoul 5
    //! runtextmacro InitHeroAggroModifier("'u00V'","2") //Ghoul 6
    //! runtextmacro InitHeroAggroModifier("'u007'","0") //Gargoyle 1
    //! runtextmacro InitHeroAggroModifier("'u008'","0") //Gargoyle 2
    //! runtextmacro InitHeroAggroModifier("'u006'","0") //Gargoyle 3
    if whichNum != 0 then
      call SetAggro(whichMob, whichAggro, GetAggro(whichMob, whichAggro)+whichNum)
    endif
endfunction

public function AOEAggroModify takes unit whichAttacker, real whichDamage, real x, real y returns nothing //добавление аггро аое.
    local group gr = CreateGroup()
    local location loc = Location(x, y)
    local unit u = null
    call GroupEnumUnitsInRangeOfLoc(gr, loc, 700, null)
    loop
      set u = FirstOfGroup(gr)
      exitwhen u == null
      if GetOwningPlayer(u) == Player(12) and GetUnitState(u, UNIT_STATE_LIFE) >= 0 then
        call ModifyAggro(u, whichAttacker, whichDamage)
      endif
      call GroupRemoveUnit(gr, u)
    endloop
    call RemoveLocation(loc)
    call DestroyGroup(gr)
endfunction
public function MassAggroNull takes unit whichAttacker returns nothing //обнуление всей агрессии мобов против одной цели (цель умерла, к примеру). Он пикает сразу всю карту, но действует только в случае смерти героя.
    local group gr = CreateGroup()
    local location loc = Location(0, 0)
    local unit u = null
    call GroupEnumUnitsInRangeOfLoc(gr, loc, 900000, null)
    loop
      set u = FirstOfGroup(gr)
      exitwhen u == null
      if GetOwningPlayer(u) == Player(12) and GetUnitState(u, UNIT_STATE_LIFE) >= 0 then
        call ModifyAggro(u, whichAttacker, -255555)
      endif
      call GroupRemoveUnit(gr, u)
    endloop
    call RemoveLocation(loc)
    call DestroyGroup(gr)
endfunction

public function AggroAtDamage takes unit whichAttacker, unit whichMob, real whichDamage returns nothing //функция, идущая от триггера - улавливателя урона.
    call ModifyAggro(whichMob, whichAttacker, whichDamage)
endfunction

public function RegisterBattleEnter takes nothing returns nothing //регистрирует вход юнита в бой.
    local unit u = GetTriggerUnit()
    call EnterBattleSE(u)
    call DestroyTrigger(GetTriggeringTrigger())
    call CreateNewAggroList(u)
endfunction
private function AggroSystemInit takes nothing returns nothing //инициализация системы.
    local group gr = CreateGroup()
    local integer i = 0
    local unit u = null
    set agres  = Player(12)
    call GroupEnumUnitsOfPlayer(gr, agres, null)
    loop
      set i = CountUnitsInGroup(gr)
      exitwhen i == 0
      set u = FirstOfGroup(gr)
      set asi = CreateTrigger() //как я думаю, дело вот в этом.
      call TriggerRegisterUnitEvent(asi, u, EVENT_UNIT_TARGET_IN_RANGE)
      call TriggerRegisterUnitEvent(asi, u, EVENT_UNIT_DAMAGED)
      call TriggerRegisterUnitEvent(asi, u, EVENT_UNIT_ACQUIRED_TARGET)
      call TriggerRegisterUnitEvent(asi, u, EVENT_UNIT_SPELL_CAST)
      call TriggerAddAction(asi, function RegisterBattleEnter)
      call GroupRemoveUnit(gr, u)
    endloop
    call DestroyGroup(gr)
    set u = null
endfunction
endlibrary



Попрошу воздержаться от неадекватных комментариев, типа "твой код грязное уг, ничего не оптимизированнее я в жизни не видел". Я сам знаю, что код с большими утечками, поэтому прошу вас помочь мне его оптимизировать. Заранее спасибо.
Старый 26.07.2009, 12:06
ToChilo
■□□□□
offline
Опыт: 356
Активность:
ну для начала нужно обнулять все хендловые переменные
и лучше не использовать локации если возможно тогда и не нужно будет их удалять
Код:
GroupEnumUnitsInRange takes group whichGroup, real x, real y, real radius, boolexpr filter returns nothing
Старый 26.07.2009, 21:33
FREEZE_ball
Cataclysm => жара
offline
Опыт: 15,247
Активность:
ToChilo, переменные я обнуляю, а вот за функцию спс. Я её найти не смог ^^.

Но всё это ещё цветочки.
Старый 27.07.2009, 02:07
ToChilo
■□□□□
offline
Опыт: 356
Активность:
Цитата:
переменные я обнуляю

где же ты их обнуляешь
возьмем твою функцию EnterBattleSE
ты создаёшь таймер
Код:
local timer lt = CreateTimer()

и в конце этой функции не обнуляешь его действием
Код:
set lt = null

обнулять нужно в каждой функии
Цитата:
а вот за функцию спс. Я её найти не смог ^^.

как несмог она же выше строчкой от использованной табою
надеюсь юзаешь common.j
Старый 27.07.2009, 02:45
FREEZE_ball
Cataclysm => жара
offline
Опыт: 15,247
Активность:
ToChilo, ладно, брось эти переменные, и скажи, что ещё можно оптимизировать. Переменные - ну слишком уж маленькая проблема, тогда как утечки возникают в чём-то другом. Моя оперативная память - 1.5 Гб, пятнадцать минут создания таких переменных она выдержать может. К тому же, я это уже сделал по твоему совету, но ничего не изменилось. А функция используется не больше раза минуты в три-четыре.
Старый 27.07.2009, 12:34
Ответ

Опции темы Поиск в этой теме
Поиск в этой теме:

Расширенный поиск

Ваши права в разделе
Вы не можете создавать темы
Вы не можете отвечать на сообщения
Вы не можете прикреплять файлы
Вы можете скачивать файлы

BB-коды Вкл.
[IMG] код Вкл.
HTML код Выкл.
Быстрый переход



Часовой пояс GMT +3, время: 00:49.