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
Попрошу воздержаться от неадекватных комментариев, типа "твой код грязное уг, ничего не оптимизированнее я в жизни не видел". Я сам знаю, что код с большими утечками, поэтому прошу вас помочь мне его оптимизировать. Заранее спасибо.
|