2016-05-06 10:56:20 +00:00
|
|
|
-- This file contains a set of miscellanous functions that don't fit in any other place
|
|
|
|
-- TODO nico : could be useful outside r2 -> export this
|
|
|
|
|
|
|
|
|
|
|
|
---------------
|
|
|
|
-- FUNCTIONS --
|
|
|
|
---------------
|
|
|
|
|
|
|
|
|
|
|
|
------------------------------------------------------------------------------------------------------------
|
|
|
|
-- equivalent of the ? : C operator, execpt that the 2 sides are evaluated before assignement
|
|
|
|
function select(cond, valueForTrue, valueForFalse)
|
|
|
|
if cond then
|
|
|
|
return valueForTrue
|
|
|
|
else
|
|
|
|
return valueForFalse
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
------------------------------------------------------------------------------------------------------------
|
|
|
|
-- execute a function for each key pair in a table
|
|
|
|
function forEach(table, fn)
|
|
|
|
local i, v = next(table,nil) -- get first index of "o" and its value
|
|
|
|
while i do
|
|
|
|
fn(i, v)
|
|
|
|
i, v = next(table,i) -- get next index and its value
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2016-10-14 11:11:34 +00:00
|
|
|
|
|
|
|
------------------------------------------------------------------------------------------------------------
|
|
|
|
-- whatever
|
|
|
|
table.setn = function(table, n)
|
|
|
|
assert(table)
|
|
|
|
local mt = getmetatable(table)
|
|
|
|
if mt ~= nil then
|
|
|
|
if mt.__next ~= nil then
|
|
|
|
table.Size = n
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2016-05-06 10:56:20 +00:00
|
|
|
------------------------------------------------------------------------------------------------------------
|
|
|
|
-- extension to table library : remove all content of a table without deleting the table object
|
|
|
|
function table.clear(tbl)
|
|
|
|
while next(tbl) do
|
|
|
|
tbl[next(tbl)] = nil
|
|
|
|
end
|
|
|
|
table.setn(tbl, 0)
|
|
|
|
end
|
|
|
|
|
|
|
|
------------------------------------------------------------------------------------------------------------
|
|
|
|
-- extension to table library : merge the content of two table remove the element, remove fields with duplicated keys (except for number)
|
|
|
|
function table.merge(tbl1, tbl2)
|
|
|
|
local k, v = next(tbl2)
|
|
|
|
while k do
|
|
|
|
if (type(k) == "number") then
|
|
|
|
table.insert(tbl1, v)
|
|
|
|
else
|
|
|
|
tbl1[k] = v
|
|
|
|
end
|
|
|
|
k, v = next(tbl2, k)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
------------------------------------------------------------------------------------------------------------
|
|
|
|
-- Addtion to the string library : test wether a string match with the given pattern (returns true is so)
|
|
|
|
function string.match(str, pattern)
|
|
|
|
assert( type(str) == "string")
|
|
|
|
if (str == nil) then
|
|
|
|
debugInfo(debug.traceback())
|
|
|
|
assert(0)
|
|
|
|
end
|
|
|
|
local startPos, endPos = string.find(str, pattern)
|
|
|
|
if startPos == nil then return false end
|
|
|
|
return startPos == 1 and endPos == string.len(str)
|
|
|
|
end
|
|
|
|
|
|
|
|
------------------------------------------------------------------------------------------------------------
|
|
|
|
-- clone content of a table
|
|
|
|
function clone(t)
|
|
|
|
local new = {}
|
|
|
|
local i, v = next(t, nil)
|
|
|
|
while i do
|
|
|
|
if (type(v)=="table") then v= clone(v) end
|
|
|
|
new[i] = v
|
|
|
|
i, v = next(t, i)
|
|
|
|
end
|
|
|
|
return new
|
|
|
|
end
|
|
|
|
|
|
|
|
------------------------------------------------------------------------------------------------------------
|
|
|
|
-- Test if 2 values are equal
|
|
|
|
-- If values are table, then a member wise comparison is done
|
|
|
|
function isEqual(lhs, rhs)
|
|
|
|
if type(lhs) ~= type(rhs) then return false end
|
|
|
|
if type(lhs) == "table" then
|
|
|
|
local lk, lv = next(lhs) -- keys
|
|
|
|
local rk, rv = next(rhs) -- values
|
|
|
|
while lk and rk do
|
|
|
|
if not isEqual(lk, rk) then
|
|
|
|
return false
|
|
|
|
end
|
|
|
|
if not isEqual(lv, rv) then
|
|
|
|
return false
|
|
|
|
end
|
|
|
|
lk, lv = next(lhs, lk)
|
|
|
|
rk, rv = next(rhs, rk)
|
|
|
|
end
|
|
|
|
if lk ~= nil or rk ~= nil then
|
|
|
|
return false
|
|
|
|
-- not same table length
|
|
|
|
end
|
|
|
|
return true
|
|
|
|
else
|
|
|
|
return lhs == rhs
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
------------------------------------------------------------------------------------------------------------
|
|
|
|
-- Test if 2 values are equal
|
|
|
|
-- If values are table, then a member wise comparison is done
|
|
|
|
-- special : function pointer are ignored and considered equals
|
|
|
|
function isEqualIgnoreFunctions(lhs, rhs)
|
|
|
|
if type(lhs) ~= type(rhs) then return false end
|
|
|
|
if type(lhs) == "table" then
|
|
|
|
local lk, lv = next(lhs) -- keys
|
|
|
|
local rk, rv = next(rhs) -- values
|
|
|
|
while lk and rk do
|
|
|
|
if not isEqualIgnoreFunctions(lk, rk) then
|
|
|
|
return false
|
|
|
|
end
|
|
|
|
if not isEqualIgnoreFunctions(lv, rv) then
|
|
|
|
return false
|
|
|
|
end
|
|
|
|
lk, lv = next(lhs, lk)
|
|
|
|
rk, rv = next(rhs, rk)
|
|
|
|
end
|
|
|
|
if lk ~= nil or rk ~= nil then
|
|
|
|
return false
|
|
|
|
-- not same table length
|
|
|
|
end
|
|
|
|
return true
|
|
|
|
elseif type(lhs) == "function" then
|
|
|
|
return true
|
|
|
|
else
|
|
|
|
return lhs == rhs
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
------------------------------------------------------------------------------------------------------------
|
|
|
|
-- clone of a table, but with a depth of 1 ...
|
|
|
|
function shallowClone(t)
|
|
|
|
local new = {}
|
|
|
|
local i, v = next(t, nil)
|
|
|
|
while i do
|
|
|
|
new[i] = v
|
|
|
|
i, v = next(t, i)
|
|
|
|
end
|
|
|
|
return new
|
|
|
|
end
|
|
|
|
|
|
|
|
-------------------------------------------------------------------------------------------------
|
|
|
|
-- If args 'value' is nil then the arg 'default' is returned, else the actual 'value' is return
|
|
|
|
function defaulting(value, default)
|
|
|
|
if value == nil then
|
|
|
|
return default
|
|
|
|
else
|
|
|
|
return value
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
-------------------------------------------------------------------------------------------------
|
|
|
|
-- return clamped value. Min and/or max are ignotred if null
|
|
|
|
function clamp(value, min, max)
|
|
|
|
local result = value
|
|
|
|
if min then result = math.max(min, result) end
|
|
|
|
if max then result = math.min(max, result) end
|
|
|
|
return result
|
|
|
|
end
|
|
|
|
|
|
|
|
-------------------------------------------------------------------------------------------------
|
|
|
|
-- enclose a string by double quotes
|
|
|
|
function strify(str)
|
|
|
|
return [["]] .. tostring(str) .. [["]]
|
|
|
|
end
|
|
|
|
|
2016-10-14 11:11:34 +00:00
|
|
|
-------------------------------------------------------------------------------------------------
|
|
|
|
-- enclose a string by double quotes
|
|
|
|
function strifyXml(str)
|
|
|
|
local strxml = string.gsub(tostring(str), ">", ">")
|
|
|
|
strxml = string.gsub(strxml, "<", "<")
|
|
|
|
strxml = string.gsub(strxml, "&", "&")
|
|
|
|
strxml = string.gsub(strxml, "'", "'")
|
|
|
|
strxml = string.gsub(strxml, '"', """)
|
|
|
|
return [["]] .. strxml .. [["]]
|
|
|
|
end
|
|
|
|
|
2016-05-06 10:56:20 +00:00
|
|
|
------------------------------------------------------------------------------------------------------------
|
|
|
|
-- snap a position to ground, returning the z snapped coordinate
|
|
|
|
function r2:snapZToGround(x, y)
|
|
|
|
local x1, y1, z1 = r2:snapPosToGround(x, y)
|
|
|
|
return z1
|
|
|
|
end
|
|
|
|
|
|
|
|
-------------------------------------------------------------------------------------------------
|
|
|
|
--
|
|
|
|
--built an ordered table from a table whose index are strings
|
|
|
|
--example :
|
|
|
|
--
|
|
|
|
--table =
|
|
|
|
--{
|
|
|
|
--"bar" = test(),
|
|
|
|
--"foo" = { "hello" },
|
|
|
|
--"abc" = 10,
|
|
|
|
--}
|
|
|
|
--
|
|
|
|
--result = sortAlphabeticaly(table)
|
|
|
|
--
|
|
|
|
--
|
|
|
|
--result is an integer indexed table :
|
|
|
|
--{
|
|
|
|
-- -- index = { sorted key, value }
|
|
|
|
-- 1 = { "abc", 10 },
|
|
|
|
-- 2 = { "bar", test() },
|
|
|
|
-- 3 = { "foo", { "hello" } }
|
|
|
|
--}
|
|
|
|
--
|
|
|
|
|
|
|
|
function sortAlphabetically(src)
|
|
|
|
local sortedTable = {}
|
|
|
|
local index = 1
|
|
|
|
for k, v in pairs(src) do
|
|
|
|
sortedTable[index] = { key = k, value = v }
|
|
|
|
index = index + 1
|
|
|
|
end
|
|
|
|
local function comp(val1, val2)
|
|
|
|
return val1.key < val2.key
|
|
|
|
end
|
|
|
|
table.sort(sortedTable, comp)
|
|
|
|
return sortedTable
|
|
|
|
end
|
|
|
|
|
|
|
|
----------
|
|
|
|
-- INIT --
|
|
|
|
----------
|
|
|
|
|
|
|
|
-- redefine the 'next' function of lua to use a "__next" function in the metatable
|
|
|
|
-- useful to traverse C++ objects that are exposed to lua through the use of the metatable
|
|
|
|
assert(next ~= nil) -- default lib should have been opened
|
|
|
|
|
|
|
|
if oldNextFunction == nil then
|
|
|
|
oldNextFunction = next
|
|
|
|
end
|
|
|
|
next = function(table, key)
|
|
|
|
assert(table)
|
|
|
|
local mt = getmetatable(table)
|
|
|
|
if mt ~= nil then
|
|
|
|
if mt.__next ~= nil then
|
|
|
|
return mt.__next(table, key)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
-- tmp
|
|
|
|
--if type(table) ~= "table" then
|
|
|
|
-- debugInfo(debug.traceback())
|
|
|
|
-- debugInfo("'next' expect a table (or user data with __next metamethod) as its first parameter")
|
|
|
|
-- return
|
|
|
|
--end
|
|
|
|
-- else use default 'next' function
|
|
|
|
return oldNextFunction(table, key)
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
|
2016-10-14 11:11:34 +00:00
|
|
|
-- assert(table.getn ~= nil) -- default lib should have been opened
|
|
|
|
|
|
|
|
--if oldTableGetnFunction == nil then
|
|
|
|
-- oldTableGetnFunction = table.getn
|
|
|
|
--end
|
|
|
|
--
|
|
|
|
--table.getn = function(table)
|
|
|
|
-- assert(table)
|
|
|
|
-- local mt = getmetatable(table)
|
|
|
|
-- if mt ~= nil then
|
|
|
|
-- if mt.__next ~= nil then
|
|
|
|
-- return table.Size
|
|
|
|
-- end
|
|
|
|
-- end
|
|
|
|
-- return oldTableGetnFunction(table)
|
|
|
|
--end
|
2016-05-06 10:56:20 +00:00
|
|
|
|
|
|
|
|
|
|
|
table.getn = function(table)
|
|
|
|
assert(table)
|
|
|
|
local mt = getmetatable(table)
|
|
|
|
if mt ~= nil then
|
|
|
|
if mt.__next ~= nil then
|
2016-10-14 11:11:34 +00:00
|
|
|
return table.Size
|
2016-05-06 10:56:20 +00:00
|
|
|
end
|
|
|
|
end
|
2016-10-14 11:11:34 +00:00
|
|
|
return #table
|
2016-05-06 10:56:20 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
-- redefine the hardcoded 'pairs' function to use the redefined 'next'
|
|
|
|
-- hardcoded version uses the C version of next, not the lua one if it has been redefined
|
|
|
|
|
|
|
|
if oldPairsFunction ~= nil then
|
|
|
|
pairs = oldPairsFunction
|
|
|
|
end
|
|
|
|
|
|
|
|
if oldPairsFunction == nil then
|
|
|
|
oldPairsFunction = pairs
|
|
|
|
end
|
|
|
|
|
|
|
|
if true then
|
|
|
|
-- TODO nico : bad init of editor if I name this 'pairs' directly (don't know why), so named it 'specPairs' and used
|
|
|
|
-- 'specPairs' when I must iterate over C++ objects ...
|
|
|
|
specPairs = function(table)
|
|
|
|
local function iterFunc(table, key)
|
|
|
|
return next(table, key)
|
|
|
|
end
|
|
|
|
return iterFunc, table
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
function r2.assert (param)
|
|
|
|
if not param then assert(nil) end
|
|
|
|
return param
|
|
|
|
end
|
|
|
|
|
|
|
|
function r2.isTable(node)
|
|
|
|
if not node then return false end
|
|
|
|
|
|
|
|
if type(node) == "table" then
|
|
|
|
return true
|
|
|
|
elseif type(node) == "userdata" then
|
|
|
|
local mt = getmetatable(node)
|
|
|
|
if mt~= nil and mt.__next ~= nil then
|
|
|
|
return true
|
|
|
|
end
|
|
|
|
end
|
|
|
|
return false
|
|
|
|
end
|