171 lines
4.9 KiB
Lua
171 lines
4.9 KiB
Lua
|
local rawget = rawget
|
||
|
local rawset = rawset
|
||
|
local getmetatable = getmetatable
|
||
|
local setmetatable = setmetatable
|
||
|
|
||
|
XBindTool = XBindTool or {}
|
||
|
|
||
|
local oldPairs = pairs
|
||
|
|
||
|
local pairs = function(arr)
|
||
|
local meta_t = getmetatable(arr)
|
||
|
if meta_t and meta_t.__pairs then
|
||
|
return meta_t.__pairs(arr)
|
||
|
end
|
||
|
return oldPairs(arr)
|
||
|
end
|
||
|
|
||
|
local function InitBind(obj)
|
||
|
if rawget(obj, "___isBinded") then return end
|
||
|
|
||
|
local store = {}
|
||
|
for key, _ in pairs(obj) do
|
||
|
local v = rawget(obj, key)
|
||
|
if v ~= nil then
|
||
|
store[key] = v
|
||
|
obj[key] = nil
|
||
|
end
|
||
|
end
|
||
|
|
||
|
local meta_t = getmetatable(obj)
|
||
|
if meta_t then setmetatable(store, meta_t) end
|
||
|
|
||
|
setmetatable(obj, {
|
||
|
__index = function(_, index)
|
||
|
local ret = rawget(obj, index)
|
||
|
if ret ~= nil then return ret end
|
||
|
return store[index]
|
||
|
end,
|
||
|
__newindex = function(_, index, v)
|
||
|
local event = rawget(obj, "___bind_event")
|
||
|
local old_v = store[index]
|
||
|
store[index] = v
|
||
|
if old_v ~= v then
|
||
|
if event and event[index] then
|
||
|
event[index].running = true
|
||
|
for key, func in pairs(event[index].callList) do
|
||
|
if not event[index].removeList[key] then
|
||
|
func(v, old_v)
|
||
|
end
|
||
|
end
|
||
|
event[index].running = nil
|
||
|
if next(event[index].removeList) then
|
||
|
for removeIndex, _ in pairs(event[index].removeList) do
|
||
|
event[index].callList[removeIndex] = nil
|
||
|
end
|
||
|
event[index].removeList = {}
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
end,
|
||
|
__pairs = function(_)
|
||
|
return oldPairs(store)
|
||
|
end
|
||
|
})
|
||
|
|
||
|
rawset(obj, "___isBinded", true)
|
||
|
rawset(obj, "___bind_store", store)
|
||
|
rawset(obj, "___bind_event", {})
|
||
|
rawset(obj, "___bind_id", 0)
|
||
|
end
|
||
|
|
||
|
function XBindTool.BindAttr(obj, attr, callback)
|
||
|
InitBind(obj)
|
||
|
|
||
|
local event = rawget(obj, "___bind_event")
|
||
|
local id = rawget(obj, "___bind_id")
|
||
|
event[attr] = event[attr] or { callList = {}, removeList = {} }
|
||
|
id = id + 1
|
||
|
rawset(obj, "___bind_id", id)
|
||
|
event[attr].callList[id] = callback
|
||
|
|
||
|
local value = obj[attr]
|
||
|
if value ~= nil then
|
||
|
callback(value)
|
||
|
end
|
||
|
return { obj = obj, attr = attr, id = id }
|
||
|
end
|
||
|
|
||
|
function XBindTool.GetBindInfo(val)
|
||
|
if type(val) ~= "table" then return val, false end
|
||
|
if not rawget(val, "___isBinded") then return val, false end
|
||
|
return rawget(val, "___bind_store"), true
|
||
|
end
|
||
|
|
||
|
function XBindTool.UnBind(handle)
|
||
|
local event = rawget(handle.obj, "___bind_event")
|
||
|
if event and event[handle.attr] then
|
||
|
if event[handle.attr].running then
|
||
|
event[handle.attr].removeList[handle.id] = true
|
||
|
else
|
||
|
event[handle.attr].callList[handle.id] = nil
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
|
||
|
function XBindTool.UnBindObj(obj)
|
||
|
local event = rawget(obj, "___bind_event")
|
||
|
if event then
|
||
|
for _, attrListener in pairs(event) do
|
||
|
if attrListener.running then
|
||
|
for key, _ in pairs(attrListener.callList) do
|
||
|
attrListener.removeList[key] = true
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
rawset(obj, "___bind_event", {})
|
||
|
end
|
||
|
end
|
||
|
|
||
|
local NodeBindInfoRecord = {}
|
||
|
|
||
|
function XBindTool.BindNode(node, obj, attr, func, unbindFunc)
|
||
|
if not NodeBindInfoRecord[node] then
|
||
|
NodeBindInfoRecord[node] = {}
|
||
|
end
|
||
|
local bindInfo = NodeBindInfoRecord[node]
|
||
|
bindInfo[obj] = bindInfo[obj] or { length = 0, record = {} }
|
||
|
local checkExist
|
||
|
if node.Exist then
|
||
|
checkExist = function() return node:Exist() end
|
||
|
else
|
||
|
local gameObject = node.GameObject or node.gameObject or node.Transform or node.transform
|
||
|
if gameObject and gameObject.Exist then
|
||
|
checkExist = function() return gameObject:Exist() end
|
||
|
end
|
||
|
|
||
|
|
||
|
end
|
||
|
local handle
|
||
|
if checkExist then
|
||
|
handle = XBindTool.BindAttr(obj, attr, function(...)
|
||
|
if not checkExist() then
|
||
|
XBindTool.UnBindNode(node)
|
||
|
if unbindFunc then
|
||
|
unbindFunc()
|
||
|
end
|
||
|
else
|
||
|
func(...)
|
||
|
end
|
||
|
end)
|
||
|
else
|
||
|
handle = XBindTool.BindAttr(obj, attr, func)
|
||
|
end
|
||
|
|
||
|
bindInfo[obj].record[handle.id] = handle
|
||
|
bindInfo[obj].length = bindInfo[obj].length + 1
|
||
|
return handle
|
||
|
end
|
||
|
|
||
|
function XBindTool.UnBindNode(node)
|
||
|
local bindInfo = NodeBindInfoRecord[node]
|
||
|
if bindInfo then
|
||
|
for key, val in pairs(bindInfo) do
|
||
|
for _, item in pairs(val.record) do
|
||
|
XBindTool.UnBind(item)
|
||
|
end
|
||
|
bindInfo[key] = nil
|
||
|
end
|
||
|
NodeBindInfoRecord[node] = nil
|
||
|
end
|
||
|
end
|