Предыстория.
Решил я внедрить в свой проект кастомный мультишот, да такой чтобы с правильным уроном, орбами и прочим. Нашел хорошую систему за авторством WereElf. Проверил код на возможные утечки, явных не нашел, написано толково. Однако HandleCounter с каждым выстрелом давал ясно понять, что на долгую катку с большим количеством стрелков можно не рассчитывать. С каждым снарядом дамми-юниты создавались, умирали, очищались и оставляли за собой хвосты. Мистика? Призраки? -_-)"
-Ghost-хэндлы. Сборщик мусора JASS забирать их не торопился, и я стал думать. Много думать, сильно думать. И пришел к решению, которое в той или иной степени по разному уже было кем-то реализовано. Использовать многоразовых дамми. Один дамик для мультишота не годится, значит нужно использовать нескольких. Но сколько их нужно? Тест надо было автоматизировать, и пошло-поехало.
-Ghost-хэндлы. Сборщик мусора JASS забирать их не торопился, и я стал думать. Много думать, сильно думать. И пришел к решению, которое в той или иной степени по разному уже было кем-то реализовано. Использовать многоразовых дамми. Один дамик для мультишота не годится, значит нужно использовать нескольких. Но сколько их нужно? Тест надо было автоматизировать, и пошло-поехало.
В итоге родилась библиотека, реализующая "каршеринг" дамми-юнитов. Взял, покатался, поставил на место. Позволяет использовать свой пулл дамми юнитов для каждой задачи используя всего 3 простых, но эффективных метода.
- call DPM_Create("PoolName", size, LifeTime, RawCode) - Создает и регистрирует новый пул.
- set u = DPM_Acquire("FLAMEARROWS", Owner) - Арендуем свободного дамика для указанного игрока на время заданное по умолчанию при создании пула, а дальше перемещаем к кастеру и делаем свои дела. По истечении времени дамик вернется обратно в точку указанную в настройках. При парковке свободные дамики теряют
совестьпроходимость и в ожидании тусуются строго в одной точке, при надобности можно запарковать в темной непроходимой части карты.
- call DPM_LifeTime(u, "FLAMEARROWS") - При необходимости использовать другое время аренды устанавливаем через сколько этот арендованный юнит припаркуется, станет нейтральным и снова свободным для аренды.
В отличии от метода создания+удаления и UnitApplyTimedLife, дамики будут кушать фиксированное количество памяти и не терять хвосты-хэндлы по всей памяти. Для систем с множеством дамми-юнитов мастхэв.
Библиотека самодостаточна, инициализирует сама себя, просто вставь и пользуйся. Код сопровожден комментариями с инструкцией по применению.
Код библиотеки:
Открыть
// =========================================================================================================
// *********************************************************************************************************
// ** [LIBRARY] DPM (Dammy Pool Manager) - Менеджер Мульти-Пулов Dammy-юнитов **
// ** ------------------------------------------------------------------------------- **
// ** АВТОР: Animo Mori
// ** ВЕРСИЯ: 2.0 (Автономная инициализация и чистый API)
// ** ------------------------------------------------------------------------------- **
// ** ОПИСАНИЕ: Автоматически создает и управляет пулами Dammy-юнитов для устранения утечек.
// ** Использует хэш-таблицы для хранения данных и переиспользования ресурсов.
// ** ------------------------------------------------------------------------------- **
// ** ПУБЛИЧНЫЙ API (Вызов извне: DPM_FunctionName):
// ** 1. DPM_Create(poolName, size, lifeTime, rawCode) -- Создает и регистрирует новый пул.
// ** 2. DPM_Acquire(poolName, player) -- Получает свободный Dammy-юнит из пула.
// ** 3. DPM_LifeTime(unit, poolName) -- Запускает таймер, возвращающий юнит в пул.
// ** ------------------------------------------------------------------------------- **
// *********************************************************************************************************
// =========================================================================================================
library DPM initializer InitDPM // Инициализируется автоматически при старте карты
globals
private hashtable PoolManagerHash // Хэш-таблица для хранения ID пулов по имени
private integer NextPoolId // ID для следующего нового пула
public hashtable DPHash // Публичная хэш-таблица для внутренних нужд других систем
// Массивы для хранения данных о пулах (доступ по PoolId)
private unit array Pool_Stack[8192] // Стек свободных юнитов
private integer array Pool_FreeCount[8192] // Количество свободных юнитов в стеке
private real array Pool_LifeTime[8192] // Время жизни юнита (до возврата в пул)
private integer array Pool_UnitId[8192] // RawCode юнита для данного пула
private constant real BaseX = 0.0 // укажите где парковать дамиков
private constant real BaseY = 0.0
endglobals
private function InitDPM takes nothing returns nothing
set PoolManagerHash = InitHashtable()
set DPHash = InitHashtable()
set NextPoolId = 1
endfunction
// 1. Создание и регистрация нового пула (PUBLIC API: DPM_Create)
public function Create takes string poolName, integer size, real lifeTime, integer rawCode returns boolean
local integer poolKey = StringHash(poolName)
local integer poolId
local integer count = size
if HaveSavedInteger(PoolManagerHash, poolKey, 0) then
return false // Пул уже существует
endif
set poolId = NextPoolId
set NextPoolId = NextPoolId + 1
if poolId >= 8192 then
return false // Превышен лимит пулов
endif
call SaveInteger(PoolManagerHash, poolKey, 0, poolId)
set Pool_FreeCount[poolId] = size
set Pool_LifeTime[poolId] = lifeTime
set Pool_UnitId[poolId] = rawCode
loop // Создание юнитов и помещение их в стек
exitwhen count <= 0
set count = count - 1
set Pool_Stack[poolId*8192 + count] = CreateUnit(Player(PLAYER_NEUTRAL_PASSIVE), rawCode, BaseX, BaseY, 0.0)
call SetUnitPathing(Pool_Stack[poolId*8192 + count], false)
endloop
return true
endfunction
// 2. Получить свободный даммик из пула и установить владельца (PUBLIC API: DPM_Acquire)
public function Acquire takes string poolName, player p returns unit
local integer poolKey = StringHash(poolName)
local integer poolId = LoadInteger(PoolManagerHash, poolKey, 0)
local integer count
local unit u
if poolId == 0 then
return null
endif
set count = Pool_FreeCount[poolId]
if count > 0 then
set Pool_FreeCount[poolId] = count - 1
set u = Pool_Stack[poolId*8192 + count - 1]
call SetUnitOwner(u, p, false)
call SetUnitX(u, 0.0)
call SetUnitY(u, 0.0)
return u
endif
return null // Пул пуст
endfunction
// ПРИВАТНЫЕ ФУНКЦИИ
private function ReturnUnitToStack takes unit u, integer poolId returns nothing
local integer count
call SetUnitOwner(u, Player(PLAYER_NEUTRAL_PASSIVE), false)
call UnitRemoveAbility(u, 'Amrf')
call SetUnitPathing(u, false)
call SetUnitX(u, BaseX)
call SetUnitY(u, BaseY)
set count = Pool_FreeCount[poolId]
set Pool_Stack[poolId*8192 + count] = u
set Pool_FreeCount[poolId] = count + 1
endfunction
private function TimerCallback takes nothing returns nothing
local timer t = GetExpiredTimer()
local integer pk = GetHandleId(t)
local unit u = LoadUnitHandle(DPHash, pk, 0)
local integer poolId = LoadInteger(DPHash, pk, 1)
if u != null and poolId > 0 then
call ReturnUnitToStack(u, poolId)
endif
call FlushChildHashtable(DPHash, pk)
call DestroyTimer(t)
set t = null
set u = null
endfunction
// 3. Запуск таймера для возврата (PUBLIC API: DPM_LifeTime)
public function LifeTime takes unit u, string poolName returns nothing
local integer poolKey = StringHash(poolName)
local integer poolId = LoadInteger(PoolManagerHash, poolKey, 0)
if poolId == 0 then
return
endif
local timer t = CreateTimer()
local integer pk = GetHandleId(t)
call SaveUnitHandle(DPHash, pk, 0, u)
call SaveInteger(DPHash, pk, 1, poolId)
call TimerStart(t, Pool_LifeTime[poolId], false, function TimerCallback)
set t = null
endfunction
endlibrary
WC3




Этот метод позволил добиться стабильности и производительности нескольких систем в которых дамми-юнитов требовалось много, без всяких пересчетов-перепроверок и добиваний того, что и так должно было быть добито.
Ред. DiZzicH