Bergi_Bear, принтов там выходит 4-5 строк.
Есть класс Action с методом public:run(...). Для всех колбеков во всех системах использую его.
Похожую задачу решаю 3мя классами.
Action
------=========
-- Include
--=========
local lib_path = Lib.curPath()
local lib_dep = Lib.curDepencies()
local Class = lib_dep.Class or error('')
---@type UtilsFunctions
local Functions = require(lib_path..'Functions') or error('')
local isTypeErr = Functions.isTypeErr or error('')
---@type UtilsSettings
local Settings = require(lib_path..'Settings') or error('')
local Log = Settings.default_logger or error('')
--=======
-- Class
--=======
local Action = Class.new('Action')
---@class Action
local public = Action.public
---@class ActionClass
local static = Action.static
---@type ActionClass
local override = Action.override
local private = {}
--========
-- Static
--========
---@alias Callback fun(vararg:any[]):any
---@param callback Callback
---@param owner any
---@param child Action | nil
---@return Action
function override.new(callback, owner, child)
isTypeErr(callback, 'function', 'callback')
if child then isTypeErr(child, 'Action', 'child') end
local list = private.callback2list[callback]
if list and list[owner] then
return list[owner]
end
local instance = child or Class.allocate(Action)
private.newData(instance, callback, owner)
return instance
end
--========
-- Public
--========
---@return any
function public:run(...)
if Settings.isDebug() then
local success, result = pcall(private.data[self].callback, ...)
if success then
return result
else
Log:err(result)
end
else
return private.data[self].callback(...)
end
end
---@return any
function public:getOwner()
return private.data[self].owner
end
--=========
-- Private
--=========
private.data = setmetatable({}, {__mode = 'k'})
private.callback2list = setmetatable({}, {__mode = 'v'})
---@param self Action
---@param callback Callback
---@param owner any
function private.newData(self, callback, owner)
local priv = {
callback = callback,
owner = owner
}
private.data[self] = priv
if not private.callback2list[callback] then
private.callback2list[callback] = setmetatable({}, {__mode = 'v'})
end
local list = private.callback2list[callback]
list[owner or ''] = self
end
return static
ActionList
--=========
-- Include
--=========
local lib_path = Lib.curPath()
local lib_dep = Lib.curDepencies()
local Class = lib_dep.Class or error('')
---@type ActionClass
local Action = require(lib_path..'Action') or error('')
---@type UtilsFunctions
local Functions = require(lib_path..'Functions') or error('')
local isTypeErr = Functions.isTypeErr or error('')
--=======
-- Class
--=======
local ActionList = Class.new('ActionList')
---@class ActionList : Handle
local public = ActionList.public
---@class ActionListClass : HandleClass
local static = ActionList.static
---@type ActionListClass
local override = ActionList.override
local private = {}
--========
-- Static
--========
---@param owner any
---@param child ActionList | nil
---@return ActionList
function override.new(owner, child)
if child then isTypeErr(child, ActionList, 'child') end
local instance = child or Class.allocate(ActionList)
private.newData(instance, owner)
return instance
end
--========
-- Public
--========
---@param callback Callback
---@return Action
function public:add(callback)
isTypeErr(callback, 'function', 'callback')
local priv = private.data[self]
local action = Action.new(callback, priv.owner)
table.insert(priv.actions, action)
return action
end
---@param action Action
---@return boolean
function public:remove(action)
isTypeErr(action, Action, 'action')
local priv = private.data[self]
if action:getOwner() ~= priv.owner then return false end
for i = 1, #priv.actions do
if priv.actions[i] == action then
table.remove(priv.actions, i)
return true
end
end
return false
end
---@param pos number
---@return Action | nil
function public:get(pos)
return private.data[self].actions[pos]
end
---@return number
function public:count()
return #private.data[self].actions
end
--- Remove all actions from list.
function public:clear()
private.data[self].actions = {}
end
--- Run all actions.
---@return table<Action, any>
function public:run(...)
local priv = private.data[self]
local res = {}
for i = 1, #priv.actions do
res[priv.actions[i]] = priv.actions[i]:run(...)
end
return res
end
--=========
-- Private
--=========
private.data = setmetatable({}, {__mode = 'k'})
---@param self ActionList
---@param owner any
function private.newData(self, owner)
local priv = {
owner = owner,
actions = {}
}
private.data[self] = priv
end
return static
Trigger
--=========
-- Include
--=========
local lib_path = Lib.curPath()
local lib_dep = Lib.curDepencies()
local Class = lib_dep.Class or error('')
---@type UtilsLib
local UtilsLib = lib_dep.Utils or error('')
local ActionList = UtilsLib.ActionList or error('')
local isTypeErr = UtilsLib.isTypeErr or error('')
---@type HandleClass
local Handle = require(lib_path..'Base') or error('')
--=======
-- Class
--=======
local Trigger = Class.new('Trigger', Handle)
---@class Trigger : Handle
local public = Trigger.public
---@class TriggerClass : HandleClass
local static = Trigger.static
---@type TriggerClass
local override = Trigger.override
local private = {}
--========
-- Static
--========
---@param child Trigger | nil
---@return Trigger
function override.new(child)
if child then isTypeErr(child, Trigger, 'child') end
local instance = child or Class.allocate(Trigger)
instance = Handle.new(CreateTrigger(), DestroyTrigger, instance)
private.newData(instance)
return instance
end
--========
-- Public
--========
---@param callback Callback
---@return Action
function public:addAction(callback)
return private.data[self].action_list:add(callback)
end
---@param action Action
---@return boolean
function public:removeAction(action)
return private.data[self].action_list:remove(action)
end
---@return number
function public:countActions()
return private.data[self].action_list:count()
end
---Function removes all actions from trigger without removing trigger.
function public:clearActions()
private.data[self].action_list:clear()
end
---Function executes trigger like event do.
function public:execute()
TriggerExecute(self:getData())
end
---@param var_name string
---@param opcode limitop
---@param limitval number
function public:addVariableEvent(var_name, opcode, limitval)
isTypeErr(var_name, 'string', 'var_name')
isTypeErr(opcode, 'limitop', 'opcode')
isTypeErr(limitval, 'number', 'limitval')
TriggerRegisterVariableEvent(self:getData(), var_name, opcode, limitval)
end
---@param timeout number
---@param periodic boolean
function public:addTimerEvent(timeout, periodic)
TriggerRegisterTimerEvent(self:getData(), timeout, periodic)
end
---@param timer timer
function public:addTimerExpireEvent(timer)
TriggerRegisterTimerExpireEvent(self:getData(), timer)
end
---@param game_state gamestate
---@param opcode limitop
---@param limitval number
function public:addGameStateEvent(game_state, opcode, limitval)
TriggerRegisterGameStateEvent(self:getData(), game_state, opcode, limitval)
end
---@param dialog dialog
function public:addDialogEvent(dialog)
TriggerRegisterDialogEvent(self:getData(), dialog)
end
---@param button button
function public:addDialogButtonEvent(button)
TriggerRegisterDialogButtonEvent(self:getData(), button)
end
---@param game_event gameevent
function public:addGameEvent(game_event)
TriggerRegisterGameEvent(self:getData(), game_event)
end
---@param region region
function public:addEnterRegion(region)
TriggerRegisterEnterRegion(self:getData(), region)
end
---@param region region
function public:addLeaveRegion(region)
TriggerRegisterLeaveRegion(self:getData(), region)
end
---@param trackable trackable
function public:addTrackableHitEvent(trackable)
TriggerRegisterTrackableHitEvent(self:getData(), trackable)
end
---@param trackable trackable
function public:addTrackableTrackEvent(trackable)
TriggerRegisterTrackableTrackEvent(self:getData(), trackable)
end
---@param player_event_type playerevent
---@param player player
function public:addPlayerEvent(player_event_type, player)
TriggerRegisterPlayerEvent(self:getData(), player, player_event_type)
end
---@param player_unit_event playerunitevent
---@param player player
function public:addPlayerUnitEvent(player_unit_event, player)
TriggerRegisterPlayerUnitEvent(self:getData(), player, player_unit_event, nil)
end
---@param player player
---@param alliancetype alliancetype
function public:addPlayerAllianceChange(player, alliancetype)
TriggerRegisterPlayerAllianceChange(self:getData(), player, alliancetype)
end
---@param player player
---@param player_state playerstate
---@param opcode limitop
---@param limitval number
function public:addPlayerStateEvent(player, player_state, opcode, limitval)
TriggerRegisterPlayerStateEvent(self:getData(), player, player_state, opcode, limitval)
end
---@param player player
---@param message string
---@param exact_match boolean
function public:addPlayerChatEvent(player, message, exact_match)
TriggerRegisterPlayerChatEvent(self:getData(), player, message, exact_match)
end
---@param widget widget
function public:addDeathEvent(widget)
TriggerRegisterDeathEvent(self:getData(), widget)
end
---@param unit unit
---@param unit_state unitstate
---@param opcode limitop
---@param limitval number
function public:addUnitStateEvent(unit, unit_state, opcode, limitval)
TriggerRegisterUnitStateEvent(self:getData(), unit, unit_state, opcode, limitval)
end
---@param unit_event unitevent
---@param unit unit
function public:addUnitEvent(unit_event, unit)
TriggerRegisterUnitEvent(self:getData(), unit_event, unit)
end
---@param unit unit
---@param range number
function public:addUnitInRange(unit, range)
TriggerRegisterUnitInRange(self:getData(), unit, range)
end
---@param frame framehandle
---@param frame_event frameeventtype
function public:addFrameEvent(frame, frame_event)
BlzTriggerRegisterFrameEvent(self:getData(), frame, frame_event)
end
---@param player player
---@param prefix string
---@param from_server boolean
function public:addPlayerSyncEvent(player, prefix, from_server)
BlzTriggerRegisterPlayerSyncEvent(self:getData(), player, prefix, from_server)
end
---@param player player
---@param key oskeytype
---@param meta_key integer
---@param key_down boolean
function public:addPlayerKeyEvent(player, key, meta_key, key_down)
BlzTriggerRegisterPlayerKeyEvent(self:getData(), player, key, meta_key, key_down)
end
--=========
-- Private
--=========
private.data = setmetatable({}, {__mode = 'k'})
---@param self Trigger
function private.newData(self)
local priv = {
action_list = ActionList.new()
}
private.data[self] = priv
TriggerAddAction(self:getData(), function() priv.action_list:run() end)
end
return static
Но тут ничего не понятно стороннему человеку, как мне кажется.
Bergi_Bear, Да будет молчать, но pcall требует накладных расходов. Я ее использую немного по-другому, и заметил, что достаточно сильно пролагивает при выдаче ошибки с вложенностью больше 3. А значит функция не бесплатная.
1, 2. Утечки бывают разные, какие-то более тяжелые, какие-то менее. Стоит попробовать потестить на слабом компе, например в VirtualBox. А стоит ли это фиксить зависит от длительности сессии игры.
Насколько знаю - нет.
Хендл - ССЫЛКА на почти любой объект на карте: юниты, декорации и даже элементы интерфейса, в т.ч. стандартные. Счетчик лишь показывает количество этих ссылок. Утечками же можно считать только необоснованное увеличение их количества. Чаще всего это вызвано тем, что остались ссылки на пустые объекты.
Теоретически в плюс к хостботу можно сделать генерацию .bat файла ( с накоплением статистики по всем играть с участием данного игрока) и просить игроков его запустить для отправки статистики и/или для заявки на бан игрока.
Можно заполнить этот "овал" регионами с пересечениями. При входе в регион добавлять к счетчику для юнита +1, при выходе -1. Тогда если юнит не находится ни в одном регионе, его счетчик равен 0. А пронумеровав регионы степенями двойки и прибавляя/вычитая эти номера из счетчика можно еще и определить последний регион в котором был юнит.
Если твоя арена имеет форму близкую к овалу, можно использовать формулу для эллипса. Точно не припомню, но надо найти константы двух его фокусов и его "радиус", а условием пребывания юнита внутри эллипса будет что сумма расстояний до этих фокусов меньше, чем "радиус" эллипса.
Pashka5, немного упростил. Для того чтобы протестировать функцию, нужно вызвать savetyRun(функция, ее аргументы), тогда при получении ошибки она будет напечатана в чат. Если в последних патчах попробовать вызвать функцию collectgarbage, то получишь однозначный ответ, что ее не существует.
P.S. внутри pcall удобно использовать функцию error, про нее можно почитать в мануалах к луа
NazarPunk, да, ООП ради ООП. Да он только создает лишнюю нагрузку и да в wc3 можно спокойно жить без него. Вообще ООП нахер не нужен и иногда только усложняет. Мне так проще видеть структуру проекта и определять необходимый функционал, плюс это ограничивает некоторые мои ошибки. Зачем используется, например, glib? Который вообще весьма уродлив, на мой взгляд.
ScorpioT1000, в луа это можно решить либами на основе таблиц. Тут больше в мировоззрении дело и в поставленной задаче. Где-то удобнее ООП, где-то функциональное...
ScorpioT1000, да, было бы неплохо всю инфу по lua разжевать и залить в одно место. А я только пару дней назад узнал, что у функции error есть второй параметр, который крайне необходим в реалиях wc3
Bergi_Bear, действительно, не пришло в голову... Можно попробовать на фреймы кнопок абилок повесить скрытие зарядов, а на кнопку 11 скрытие/показ в зависимости от текущего состояния. Но все эти навороты приводят к тому что через замену иконок проще, правда нужно много иконок.
» WarCraft 3 / Как "запаузить" любые действия с юнитом. (Не в прямом смысле)
» WarCraft 3 / Как "запаузить" любые действия с юнитом. (Не в прямом смысле)
Ред. Nelloy
» WarCraft 3 / Дебаггер Lua
Есть класс Action с методом public:run(...). Для всех колбеков во всех системах использую его.
Похожую задачу решаю 3мя классами.
Ред. Nelloy
» WarCraft 3 / Дебаггер Lua
» WarCraft 3 / Дебаггер Lua
» WarCraft 3 / [Lua] Совместная работа над WC3 проектами
» WarCraft 3 / [lua] Каст бар
» WarCraft 3 / Несколько вопросов об утечках
Ред. Nelloy
» WarCraft 3 / Цикл от 1 до 5 не всегда до 5-ти
» WarCraft 3 / Экспорт/импорт информации между картой и сервером
» WarCraft 3 / Дребезг при движении юнита
Ред. Nelloy
» WarCraft 3 / Какая проверка будет наиболее подходящей выхода юнита из круга
Если твоя арена имеет форму близкую к овалу, можно использовать формулу для эллипса. Точно не припомню, но надо найти константы двух его фокусов и его "радиус", а условием пребывания юнита внутри эллипса будет что сумма расстояний до этих фокусов меньше, чем "радиус" эллипса.
Ред. Nelloy
» WarCraft 3 / что то не так с LUA
P.S. внутри pcall удобно использовать функцию error, про нее можно почитать в мануалах к луа
Ред. Nelloy
» WarCraft 3 / что то не так с LUA
Ред. Nelloy
» WarCraft 3 / lua переменная и таблица
» WarCraft 3 / Проверка приближения даммика
» WarCraft 3 / Релиз Reforged, оценки метакритиков, блогеры не могут ошибаться
» WarCraft 3 / Релиз Reforged, оценки метакритиков, блогеры не могут ошибаться
» WarCraft 3 / garbagecollect
» WarCraft 3 / Новые туториалы
» WarCraft 3 / ООП lua
Ред. Nelloy
» WarCraft 3 / ООП lua
Ред. Nelloy
» WarCraft 3 / ООП lua
» WarCraft 3 / Заряды способности
Ред. Nelloy
» WarCraft 3 / Заряды способности