541 lines
15 KiB
Lua
541 lines
15 KiB
Lua
--[[
|
|
|
|
Copyright (c) 2011-2014 chukong-inc.com
|
|
|
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
of this software and associated documentation files (the "Software"), to deal
|
|
in the Software without restriction, including without limitation the rights
|
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
copies of the Software, and to permit persons to whom the Software is
|
|
furnished to do so, subject to the following conditions:
|
|
|
|
The above copyright notice and this permission notice shall be included in
|
|
all copies or substantial portions of the Software.
|
|
|
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
THE SOFTWARE.
|
|
|
|
]]
|
|
local function dump_value_(v)
|
|
if type(v) == "string" then
|
|
v = "\"" .. v .. "\""
|
|
end
|
|
return tostring(v)
|
|
end
|
|
|
|
function dump(value, desciption, nesting)
|
|
if type(nesting) ~= "number" then nesting = 3 end
|
|
|
|
local lookupTable = {}
|
|
local result = {}
|
|
|
|
local traceback = string.split(debug.traceback("", 2), "\n")
|
|
print("dump from: " .. string.trim(traceback[3]))
|
|
|
|
local function dump_(value, desciption, indent, nest, keylen)
|
|
desciption = desciption or "<var>"
|
|
local spc = ""
|
|
if type(keylen) == "number" then
|
|
spc = string.rep(" ", keylen - string.len(dump_value_(desciption)))
|
|
end
|
|
if type(value) ~= "table" then
|
|
result[#result +1 ] = string.format("%s%s%s = %s", indent, dump_value_(desciption), spc, dump_value_(value))
|
|
elseif lookupTable[tostring(value)] then
|
|
result[#result +1 ] = string.format("%s%s%s = *REF*", indent, dump_value_(desciption), spc)
|
|
else
|
|
lookupTable[tostring(value)] = true
|
|
if nest > nesting then
|
|
result[#result +1 ] = string.format("%s%s = *MAX NESTING*", indent, dump_value_(desciption))
|
|
else
|
|
result[#result +1 ] = string.format("%s%s = {", indent, dump_value_(desciption))
|
|
local indent2 = indent.." "
|
|
local keys = {}
|
|
local keylen = 0
|
|
local values = {}
|
|
for k, v in pairs(value) do
|
|
keys[#keys + 1] = k
|
|
local vk = dump_value_(k)
|
|
local vkl = string.len(vk)
|
|
if vkl > keylen then keylen = vkl end
|
|
values[k] = v
|
|
end
|
|
table.sort(keys, function(a, b)
|
|
if type(a) == "number" and type(b) == "number" then
|
|
return a < b
|
|
else
|
|
return tostring(a) < tostring(b)
|
|
end
|
|
end)
|
|
for i, k in ipairs(keys) do
|
|
dump_(values[k], k, indent2, nest + 1, keylen)
|
|
end
|
|
result[#result +1] = string.format("%s}", indent)
|
|
end
|
|
end
|
|
end
|
|
dump_(value, desciption, "- ", 1)
|
|
|
|
for i, line in ipairs(result) do
|
|
print(line)
|
|
end
|
|
end
|
|
|
|
function checknumber(value, base)
|
|
return tonumber(value, base) or 0
|
|
end
|
|
|
|
function checkint(value)
|
|
return math.round(checknumber(value))
|
|
end
|
|
|
|
function checkbool(value)
|
|
return (value ~= nil and value ~= false)
|
|
end
|
|
|
|
function checktable(value)
|
|
if type(value) ~= "table" then value = {} end
|
|
return value
|
|
end
|
|
|
|
function isset(hashtable, key)
|
|
local t = type(hashtable)
|
|
return (t == "table" or t == "userdata") and hashtable[key] ~= nil
|
|
end
|
|
|
|
local setmetatableindex_
|
|
setmetatableindex_ = function(t, index)
|
|
if type(t) == "userdata" then
|
|
--@TODO: no tolua here
|
|
--[[
|
|
local peer = tolua.getpeer(t)
|
|
if not peer then
|
|
peer = {}
|
|
tolua.setpeer(t, peer)
|
|
end
|
|
setmetatableindex_(peer, index)
|
|
]]
|
|
else
|
|
local mt = getmetatable(t)
|
|
if not mt then mt = {} end
|
|
if not mt.__index then
|
|
mt.__index = index
|
|
setmetatable(t, mt)
|
|
elseif mt.__index ~= index then
|
|
setmetatableindex_(mt, index)
|
|
end
|
|
end
|
|
end
|
|
setmetatableindex = setmetatableindex_
|
|
|
|
function clone(object,shallow)
|
|
local lookup_table = {}
|
|
local function _copy(object)
|
|
if type(object) ~= "table" then
|
|
return object
|
|
elseif lookup_table[object] then
|
|
return lookup_table[object]
|
|
end
|
|
local new_table = {}
|
|
lookup_table[object] = new_table
|
|
for key, value in pairs(object) do
|
|
new_table[_copy(key)] = _copy(value)
|
|
end
|
|
if shallow then
|
|
return new_table
|
|
else
|
|
return setmetatable(new_table, getmetatable(object))
|
|
end
|
|
end
|
|
return _copy(object)
|
|
end
|
|
|
|
local classTb,hotswap = {},true
|
|
local function _unpack(t,i)
|
|
i = i or 1
|
|
if i <= #t then
|
|
return t[i],_unpack(t,i+1)
|
|
end
|
|
end
|
|
local function _pack(...)
|
|
local n = select('#', ...)
|
|
local t = {}
|
|
for i = 1, n do
|
|
t[i] = select(i, ...)
|
|
end
|
|
return t
|
|
end
|
|
|
|
local function class(module, classname, super)
|
|
if classname == nil and super == nil then
|
|
module , classname = nil , module
|
|
end
|
|
local superType = type(super)
|
|
local class
|
|
|
|
if superType ~= "function" and superType ~= "table" then
|
|
superType = nil
|
|
super = nil
|
|
end
|
|
|
|
if superType == "function" or (super and super.__ctype == 1) then
|
|
-- inherited from native C++ Object
|
|
class = {}
|
|
|
|
if superType == "table" then
|
|
-- copy fields from super
|
|
for k,v in pairs(super) do class[k] = v end
|
|
class.__create = super.__create
|
|
class.super = super
|
|
else
|
|
class.__create = super
|
|
end
|
|
|
|
class.ctor = function() end
|
|
class.__cname = classname
|
|
class.__ctype = 1
|
|
|
|
function class.new(...)
|
|
local instance = class.__create(...)
|
|
-- copy fields from class to native object
|
|
for k,v in pairs(class) do instance[k] = v end
|
|
instance.class = class
|
|
instance:ctor(...)
|
|
return instance
|
|
end
|
|
|
|
else
|
|
-- inherited from Lua Object
|
|
if super then
|
|
-- class = clone(super)
|
|
class = setmetatable({}, {__index = super})
|
|
class.super = super
|
|
else
|
|
class = {ctor = function() end}
|
|
end
|
|
|
|
class.__cname = classname
|
|
class.__ctype = 2 -- lua
|
|
class.__index = class
|
|
|
|
function class.new(...)
|
|
local instance = setmetatable({}, class)
|
|
-- local instance = clone(class)
|
|
-- instance = setmetatable(instance, instance.super)
|
|
instance.class = class
|
|
instance:ctor(...)
|
|
return instance
|
|
end
|
|
end
|
|
|
|
if module ~= nil then
|
|
module[classname] = class
|
|
end
|
|
return class
|
|
end
|
|
|
|
function isKindofClass(obj, class)
|
|
local t = type(obj)
|
|
if t ~= "table" then return false end
|
|
|
|
local mt = obj.class
|
|
while mt do
|
|
if mt == class then
|
|
return true
|
|
else
|
|
mt = mt.super
|
|
end
|
|
end
|
|
return false
|
|
end
|
|
|
|
function class_new(classname, ...)
|
|
local class = {__cname = classname}
|
|
|
|
local supers = {...}
|
|
for _, super in ipairs(supers) do
|
|
local superType = type(super)
|
|
assert(superType == "nil" or superType == "table" or superType == "function",
|
|
string.format("class() - create class \"%s\" with invalid super class type \"%s\"",
|
|
classname, superType))
|
|
|
|
if superType == "function" then
|
|
assert(class.__create == nil,
|
|
string.format("class() - create class \"%s\" with more than one creating function",
|
|
classname));
|
|
-- if super is function, set it to __create
|
|
class.__create = super
|
|
elseif superType == "table" then
|
|
if super[".isclass"] then
|
|
-- super is native class
|
|
assert(class.__create == nil,
|
|
string.format("class() - create class \"%s\" with more than one creating function or native class",
|
|
classname));
|
|
class.__create = function() return super:create() end
|
|
else
|
|
-- super is pure lua class
|
|
class.__supers = class.__supers or {}
|
|
class.__supers[#class.__supers + 1] = super
|
|
if not class.super then
|
|
-- set first super pure lua class as class.super
|
|
class.super = super
|
|
end
|
|
end
|
|
else
|
|
error(string.format("class() - create class \"%s\" with invalid super type",
|
|
classname), 0)
|
|
end
|
|
end
|
|
|
|
class.__index = class
|
|
if not class.__supers or #class.__supers == 1 then
|
|
setmetatable(class, {__index = class.super})
|
|
else
|
|
setmetatable(class, {__index = function(_, key)
|
|
local supers = class.__supers
|
|
for i = 1, #supers do
|
|
local super = supers[i]
|
|
if super[key] then return super[key] end
|
|
end
|
|
end})
|
|
end
|
|
|
|
if not class.ctor then
|
|
-- add default constructor
|
|
class.ctor = function() end
|
|
end
|
|
class.new = function(...)
|
|
local instance
|
|
if class.__create then
|
|
instance = class.__create(...)
|
|
else
|
|
instance = {}
|
|
end
|
|
setmetatableindex(instance, class)
|
|
instance.class = class
|
|
instance:ctor(...)
|
|
return instance
|
|
end
|
|
class.create = function(_, ...)
|
|
return class.new(...)
|
|
end
|
|
|
|
return class
|
|
end
|
|
|
|
local iskindof_
|
|
iskindof_ = function(class, name)
|
|
local __index = rawget(class, "__index")
|
|
if type(__index) == "table" and rawget(__index, "__cname") == name then return true end
|
|
|
|
if rawget(class, "__cname") == name then return true end
|
|
local __supers = rawget(class, "__supers")
|
|
if not __supers then return false end
|
|
for _, super in ipairs(__supers) do
|
|
if iskindof_(super, name) then return true end
|
|
end
|
|
return false
|
|
end
|
|
|
|
function iskindof(obj, classname)
|
|
local t = type(obj)
|
|
if t ~= "table" and t ~= "userdata" then return false end
|
|
|
|
local mt
|
|
if t == "userdata" then
|
|
-- TODO: reg a typeof method from slua
|
|
--[[
|
|
if tolua.iskindof(obj, classname) then return true end
|
|
mt = tolua.getpeer(obj)
|
|
]]
|
|
else
|
|
mt = getmetatable(obj)
|
|
end
|
|
if mt then
|
|
return iskindof_(mt, classname)
|
|
end
|
|
return false
|
|
end
|
|
|
|
function handler(obj, method)
|
|
return function(...)
|
|
return method(obj, ...)
|
|
end
|
|
end
|
|
|
|
function io.exists(path)
|
|
local file = io.open(path, "r")
|
|
if file then
|
|
io.close(file)
|
|
return true
|
|
end
|
|
return false
|
|
end
|
|
|
|
function io.readfile(path)
|
|
local file = io.open(path, "r")
|
|
if file then
|
|
local content = file:read("*a")
|
|
io.close(file)
|
|
return content
|
|
end
|
|
return nil
|
|
end
|
|
|
|
function io.writefile(path, content, mode)
|
|
mode = mode or "w+b"
|
|
local file = io.open(path, mode)
|
|
if file then
|
|
if file:write(content) == nil then return false end
|
|
io.close(file)
|
|
return true
|
|
else
|
|
return false
|
|
end
|
|
end
|
|
|
|
function io.pathinfo(path)
|
|
local pos = string.len(path)
|
|
local extpos = pos + 1
|
|
while pos > 0 do
|
|
local b = string.byte(path, pos)
|
|
if b == 46 then -- 46 = char "."
|
|
extpos = pos
|
|
elseif b == 47 then -- 47 = char "/"
|
|
break
|
|
end
|
|
pos = pos - 1
|
|
end
|
|
|
|
local dirname = string.sub(path, 1, pos)
|
|
local filename = string.sub(path, pos + 1)
|
|
extpos = extpos - pos
|
|
local basename = string.sub(filename, 1, extpos - 1)
|
|
local extname = string.sub(filename, extpos)
|
|
return {
|
|
dirname = dirname,
|
|
filename = filename,
|
|
basename = basename,
|
|
extname = extname
|
|
}
|
|
end
|
|
|
|
function io.filesize(path)
|
|
local size = false
|
|
local file = io.open(path, "r")
|
|
if file then
|
|
local current = file:seek()
|
|
size = file:seek("end")
|
|
file:seek("set", current)
|
|
io.close(file)
|
|
end
|
|
return size
|
|
end
|
|
|
|
-- @Nullptr and null UObject.
|
|
function isValid(_object)
|
|
if _object then
|
|
--@strange that this method often causes an exception when using PreviewLine.
|
|
--local kismet = LoadClass("KismetSystemLibrary")
|
|
--return kismet:IsValid(_object)
|
|
return true
|
|
else
|
|
return false
|
|
end
|
|
end
|
|
|
|
local unpack = table.unpack
|
|
function toDelegate(func, ...)
|
|
local args = {...}
|
|
local function callback(...)
|
|
if select('#', ...) == 0 then
|
|
func(unpack(args))
|
|
else
|
|
local len = #args
|
|
if len == 0 then
|
|
func(...)
|
|
elseif len == 1 then
|
|
func(args[1], ...)
|
|
else
|
|
local new_args = {}
|
|
for i,v in pairs(args) do
|
|
table.insert(new_args,v)
|
|
end
|
|
for i,v in pairs({...}) do
|
|
table.insert(new_args,v)
|
|
end
|
|
func(unpack(new_args))
|
|
end
|
|
end
|
|
end
|
|
return callback
|
|
end
|
|
|
|
--------------------------------------------------------------------------------
|
|
-- 序列化为字符串 ...
|
|
--------------------------------------------------------------------------------
|
|
function serialize(obj)
|
|
local lua = ""
|
|
local t = type(obj)
|
|
if t == "number" then
|
|
lua = lua .. obj
|
|
elseif t == "boolean" then
|
|
lua = lua .. tostring(obj)
|
|
elseif t == "string" then
|
|
lua = lua .. string.format("%q", obj)
|
|
elseif t == "table" then
|
|
lua = lua .. "{\n"
|
|
for k, v in pairs(obj) do
|
|
lua = lua .. "[" .. serialize(k) .. "]=" .. serialize(v) .. ",\n"
|
|
end
|
|
local metatable = getmetatable(obj)
|
|
if metatable ~= nil and type(metatable.__index) == "table" then
|
|
for k, v in pairs(metatable.__index) do
|
|
lua = lua .. "[" .. serialize(k) .. "]=" .. serialize(v) .. ",\n"
|
|
end
|
|
end
|
|
lua = lua .. "}"
|
|
elseif t == "nil" then
|
|
return nil
|
|
else
|
|
error("can not serialize a " .. t .. " type.")
|
|
end
|
|
return lua
|
|
end
|
|
|
|
--------------------------------------------------------------------------------
|
|
-- 从字符串反序列化 ...
|
|
--------------------------------------------------------------------------------
|
|
function unserialize(lua)
|
|
local t = type(lua)
|
|
if t == "nil" or lua == "" then
|
|
return nil
|
|
elseif t == "number" or t == "string" or t == "boolean" then
|
|
lua = tostring(lua)
|
|
else
|
|
error("can not unserialize a " .. t .. " type.")
|
|
end
|
|
lua = "return " .. lua
|
|
-- 5.3 replaced loadstring with load
|
|
local func = load(lua)
|
|
if func == nil then
|
|
return nil
|
|
end
|
|
return func()
|
|
end
|
|
|
|
-- @Note: this is only a simplicity to avoid writing if-else, while
|
|
-- taking no responsibility to call a interrupt and return to parent stack.
|
|
-- The reason lua assert is not recommanded to use is that it has a chance leading
|
|
-- to memory leak in our project.
|
|
function check(condition, msg)
|
|
if not condition then
|
|
logE(msg)
|
|
end
|
|
end
|
|
|
|
_G.class = class |