mirror of
https://github.com/mehah/otclient
synced 2026-08-15 16:29:06 -04:00
483 lines
No EOL
11 KiB
Lua
483 lines
No EOL
11 KiB
Lua
-- @docfuncs @{
|
|
function print(...)
|
|
local msg = ''
|
|
local args = { ... }
|
|
local appendSpace = #args > 1
|
|
for i, v in ipairs(args) do
|
|
msg = msg .. tostring(v)
|
|
if appendSpace and i < #args then
|
|
msg = msg .. ' '
|
|
end
|
|
end
|
|
g_logger.log(LogInfo, msg)
|
|
end
|
|
|
|
function pinfo(msg)
|
|
g_logger.log(LogInfo, msg)
|
|
end
|
|
|
|
function perror(msg)
|
|
g_logger.log(LogError, msg)
|
|
end
|
|
|
|
function pwarning(msg)
|
|
g_logger.log(LogWarning, msg)
|
|
end
|
|
|
|
function pdebug(msg)
|
|
g_logger.log(LogDebug, msg)
|
|
end
|
|
|
|
function fatal(msg)
|
|
g_logger.log(LogFatal, msg)
|
|
end
|
|
|
|
function exit()
|
|
g_app.exit()
|
|
end
|
|
|
|
function quit()
|
|
g_app.quit()
|
|
end
|
|
|
|
function connect(object, arg1, arg2, arg3)
|
|
if not object then
|
|
return
|
|
end
|
|
|
|
local signalsAndSlots
|
|
local pushFront
|
|
if type(arg1) == 'string' then
|
|
signalsAndSlots = {
|
|
[arg1] = arg2
|
|
}
|
|
pushFront = arg3
|
|
else
|
|
signalsAndSlots = arg1
|
|
pushFront = arg2
|
|
end
|
|
|
|
for signal, slot in pairs(signalsAndSlots) do
|
|
if not object[signal] then
|
|
local mt = getmetatable(object)
|
|
if mt and type(object) == 'userdata' then
|
|
object[signal] = function(...)
|
|
return signalcall(mt[signal], ...)
|
|
end
|
|
end
|
|
end
|
|
|
|
if not object[signal] then
|
|
object[signal] = slot
|
|
elseif type(object[signal]) == 'function' then
|
|
object[signal] = { object[signal] }
|
|
end
|
|
|
|
if type(slot) ~= 'function' then
|
|
perror(debug.traceback('unable to connect a non function value'))
|
|
end
|
|
|
|
if type(object[signal]) == 'table' then
|
|
if pushFront then
|
|
table.insert(object[signal], 1, slot)
|
|
else
|
|
table.insert(object[signal], #object[signal] + 1, slot)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
function disconnect(object, arg1, arg2)
|
|
local signalsAndSlots
|
|
if type(arg1) == 'string' then
|
|
if arg2 == nil then
|
|
object[arg1] = nil
|
|
return
|
|
end
|
|
signalsAndSlots = {
|
|
[arg1] = arg2
|
|
}
|
|
elseif type(arg1) == 'table' then
|
|
signalsAndSlots = arg1
|
|
else
|
|
perror(debug.traceback('unable to disconnect'))
|
|
end
|
|
|
|
for signal, slot in pairs(signalsAndSlots) do
|
|
if not object[signal] then
|
|
elseif type(object[signal]) == 'function' then
|
|
if object[signal] == slot then
|
|
object[signal] = nil
|
|
end
|
|
elseif type(object[signal]) == 'table' then
|
|
for k, func in pairs(object[signal]) do
|
|
if func == slot then
|
|
table.remove(object[signal], k)
|
|
|
|
if #object[signal] == 1 then
|
|
object[signal] = object[signal][1]
|
|
end
|
|
break
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
function newclass(name)
|
|
if not name then
|
|
perror(debug.traceback('new class has no name.'))
|
|
end
|
|
|
|
local class = {}
|
|
function class.internalCreate()
|
|
local instance = {}
|
|
for k, v in pairs(class) do
|
|
instance[k] = v
|
|
end
|
|
return instance
|
|
end
|
|
|
|
class.create = class.internalCreate
|
|
class.__class = name
|
|
class.getClassName = function()
|
|
return name
|
|
end
|
|
return class
|
|
end
|
|
|
|
function extends(base, name)
|
|
if not name then
|
|
perror(debug.traceback('extended class has no name.'))
|
|
end
|
|
|
|
local derived = {}
|
|
function derived.internalCreate()
|
|
local instance = base.create()
|
|
for k, v in pairs(derived) do
|
|
instance[k] = v
|
|
end
|
|
return instance
|
|
end
|
|
|
|
derived.create = derived.internalCreate
|
|
derived.__class = name
|
|
derived.getClassName = function()
|
|
return name
|
|
end
|
|
return derived
|
|
end
|
|
|
|
function runinsandbox(func, ...)
|
|
if type(func) == 'string' then
|
|
func, err = loadfile(resolvepath(func, 2))
|
|
if not func then
|
|
error(err)
|
|
end
|
|
end
|
|
local env = {}
|
|
local oldenv = getfenv(0)
|
|
setmetatable(env, {
|
|
__index = oldenv
|
|
})
|
|
setfenv(0, env)
|
|
func(...)
|
|
setfenv(0, oldenv)
|
|
return env
|
|
end
|
|
|
|
function loadasmodule(name, file)
|
|
file = file or resolvepath(name, 2)
|
|
if package.loaded[name] then
|
|
return package.loaded[name]
|
|
end
|
|
local env = runinsandbox(file)
|
|
package.loaded[name] = env
|
|
return env
|
|
end
|
|
|
|
local function module_loader(modname)
|
|
local module = g_modules.getModule(modname)
|
|
if not module then
|
|
return '\n\tno module \'' .. modname .. '\''
|
|
end
|
|
return function()
|
|
if not module:load() then
|
|
error('unable to load required module ' .. modname)
|
|
end
|
|
return module:getSandbox()
|
|
end
|
|
end
|
|
table.insert(package.loaders, 1, module_loader)
|
|
|
|
function import(table)
|
|
assert(type(table) == 'table')
|
|
local env = getfenv(2)
|
|
for k, v in pairs(table) do
|
|
env[k] = v
|
|
end
|
|
end
|
|
|
|
function export(what, key)
|
|
if key ~= nil then
|
|
_G[key] = what
|
|
else
|
|
for k, v in pairs(what) do
|
|
_G[k] = v
|
|
end
|
|
end
|
|
end
|
|
|
|
function unexport(key)
|
|
if type(key) == 'table' then
|
|
for _k, v in pairs(key) do
|
|
_G[v] = nil
|
|
end
|
|
else
|
|
_G[key] = nil
|
|
end
|
|
end
|
|
|
|
function getfsrcpath(depth)
|
|
depth = depth or 2
|
|
local info = debug.getinfo(1 + depth, 'Sn')
|
|
local path
|
|
if info.short_src then
|
|
path = info.short_src:match('(.*)/.*')
|
|
end
|
|
if not path then
|
|
path = '/'
|
|
elseif path:sub(0, 1) ~= '/' then
|
|
path = '/' .. path
|
|
end
|
|
return path
|
|
end
|
|
|
|
function resolvepath(filePath, depth)
|
|
if not filePath then
|
|
return nil
|
|
end
|
|
depth = depth or 1
|
|
if filePath then
|
|
if filePath:sub(0, 1) ~= '/' then
|
|
local basepath = getfsrcpath(depth + 1)
|
|
if basepath:sub(#basepath) ~= '/' then
|
|
basepath = basepath .. '/'
|
|
end
|
|
return basepath .. filePath
|
|
else
|
|
return filePath
|
|
end
|
|
else
|
|
local basepath = getfsrcpath(depth + 1)
|
|
if basepath:sub(#basepath) ~= '/' then
|
|
basepath = basepath .. '/'
|
|
end
|
|
return basepath
|
|
end
|
|
end
|
|
|
|
function toboolean(v)
|
|
if type(v) == 'string' then
|
|
v = v:trim():lower()
|
|
if v == '1' or v == 'true' then
|
|
return true
|
|
end
|
|
elseif type(v) == 'number' then
|
|
if v == 1 then
|
|
return true
|
|
end
|
|
elseif type(v) == 'boolean' then
|
|
return v
|
|
end
|
|
return false
|
|
end
|
|
|
|
function fromboolean(boolean)
|
|
if boolean then
|
|
return 'true'
|
|
else
|
|
return 'false'
|
|
end
|
|
end
|
|
|
|
function booleantonumber(boolean)
|
|
if boolean then
|
|
return 1
|
|
else
|
|
return 0
|
|
end
|
|
end
|
|
|
|
function numbertoboolean(number)
|
|
if number ~= 0 then
|
|
return true
|
|
else
|
|
return false
|
|
end
|
|
end
|
|
|
|
function protectedcall(func, ...)
|
|
local status, ret = pcall(func, ...)
|
|
if status then
|
|
return ret
|
|
end
|
|
|
|
perror(ret)
|
|
return false
|
|
end
|
|
|
|
function signalcall(param, ...)
|
|
if type(param) == 'function' then
|
|
local status, ret = pcall(param, ...)
|
|
if status then
|
|
return ret
|
|
else
|
|
perror(ret)
|
|
end
|
|
elseif type(param) == 'table' then
|
|
for k, v in pairs(param) do
|
|
local status, ret = pcall(v, ...)
|
|
if status then
|
|
if ret then
|
|
return true
|
|
end
|
|
else
|
|
perror(ret)
|
|
end
|
|
end
|
|
elseif param ~= nil then
|
|
error('attempt to call a non function value')
|
|
end
|
|
return false
|
|
end
|
|
|
|
function tr(s, ...)
|
|
return string.format(s, ...)
|
|
end
|
|
|
|
function getOppositeAnchor(anchor)
|
|
if anchor == AnchorLeft then
|
|
return AnchorRight
|
|
elseif anchor == AnchorRight then
|
|
return AnchorLeft
|
|
elseif anchor == AnchorTop then
|
|
return AnchorBottom
|
|
elseif anchor == AnchorBottom then
|
|
return AnchorTop
|
|
elseif anchor == AnchorVerticalCenter then
|
|
return AnchorHorizontalCenter
|
|
elseif anchor == AnchorHorizontalCenter then
|
|
return AnchorVerticalCenter
|
|
end
|
|
return anchor
|
|
end
|
|
|
|
function makesingleton(obj)
|
|
local singleton = {}
|
|
if obj.getClassName then
|
|
for key, value in pairs(_G[obj:getClassName()]) do
|
|
if type(value) == 'function' then
|
|
singleton[key] = function(...)
|
|
return value(obj, ...)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
return singleton
|
|
end
|
|
|
|
-- TFS compliant Lua debugging:
|
|
-- https://github.com/otland/forgottenserver/blob/b23850046a2aec05636761c49d296c755865288a/data/lib/debugging/dump.lua
|
|
|
|
-- recursive dump function
|
|
function dumpLevel(input, level)
|
|
local indent = ''
|
|
|
|
for i = 1, level do
|
|
indent = indent .. ' '
|
|
end
|
|
|
|
if type(input) == 'table' then
|
|
local str = '{ \n'
|
|
local lines = {}
|
|
|
|
for k, v in pairs(input) do
|
|
if type(k) ~= 'number' then
|
|
k = '"' .. k .. '"'
|
|
end
|
|
|
|
if type(v) == 'string' then
|
|
v = '"' .. v .. '"'
|
|
end
|
|
|
|
table.insert(lines, indent .. ' [' .. k .. '] = ' .. dumpLevel(v, level + 1))
|
|
end
|
|
return str .. table.concat(lines, ',\n') .. '\n' .. indent .. '}'
|
|
end
|
|
|
|
return tostring(input)
|
|
end
|
|
|
|
-- Return a string representation of input for debugging purposes
|
|
function dump(input)
|
|
return dumpLevel(input, 0)
|
|
end
|
|
|
|
-- Call the dump function and print it to console
|
|
function pdump(input)
|
|
local dump_str = dump(input)
|
|
print(dump_str)
|
|
return dump_str
|
|
end
|
|
|
|
-- Call the dump function with a title and print it beautifully to the console
|
|
function tdump(title, input)
|
|
local title_fill = ''
|
|
for i = 1, title:len() do
|
|
title_fill = title_fill .. '='
|
|
end
|
|
|
|
local header_str = '\n====' .. title_fill .. '====\n'
|
|
header_str = header_str .. '=== ' .. title .. ' ===\n'
|
|
header_str = header_str .. '====' .. title_fill .. '====\n'
|
|
|
|
local dump_str = dump(input)
|
|
local footer_str = '\n====' .. title_fill .. '====\n'
|
|
|
|
print(header_str .. dump_str .. footer_str)
|
|
|
|
return dump_str
|
|
end
|
|
|
|
-- @}
|
|
|
|
io.content = function(path)
|
|
return g_resources.readFileContents('/' .. path)
|
|
end
|
|
|
|
function pdumpWidgetId(widget, indent)
|
|
indent = indent or ""
|
|
local children = widget:getChildren()
|
|
for i, child in ipairs(children) do
|
|
local prefix = (i == #children) and "`-- " or "|-- "
|
|
print(indent .. prefix .. child:getId())
|
|
local newIndent = (i == #children) and (indent .. " ") or (indent .. "| ")
|
|
pdumpWidgetId(child, newIndent)
|
|
end
|
|
end
|
|
|
|
function translateVocation(id)
|
|
if id == 1 or id == 11 then
|
|
return 8 -- ek
|
|
elseif id == 2 or id == 12 then
|
|
return 7 -- rp
|
|
elseif id == 3 or id == 13 then
|
|
return 5 -- ms
|
|
elseif id == 4 or id == 14 then
|
|
return 6 -- ed
|
|
elseif id == 5 or id == 15 then
|
|
return 9 -- em
|
|
end
|
|
return 0
|
|
end |