diff --git a/res/modules/internal/deprecated.lua b/res/modules/internal/deprecated.lua new file mode 100644 index 00000000..0be82795 --- /dev/null +++ b/res/modules/internal/deprecated.lua @@ -0,0 +1,48 @@ +-- --------- Deprecated functions ------ -- +local function wrap_deprecated(func, name, alternatives) + return function (...) + on_deprecated_call(name, alternatives) + return func(...) + end +end + +block_index = wrap_deprecated(block.index, "block_index", "block.index") +block_name = wrap_deprecated(block.name, "block_name", "block.name") +blocks_count = wrap_deprecated(block.defs_count, "blocks_count", "block.defs_count") +is_solid_at = wrap_deprecated(block.is_solid_at, "is_solid_at", "block.is_solid_at") +is_replaceable_at = wrap_deprecated(block.is_replaceable_at, "is_replaceable_at", "block.is_replaceable_at") +set_block = wrap_deprecated(block.set, "set_block", "block.set") +get_block = wrap_deprecated(block.get, "get_block", "block.get") +get_block_X = wrap_deprecated(block.get_X, "get_block_X", "block.get_X") +get_block_Y = wrap_deprecated(block.get_Y, "get_block_Y", "block.get_Y") +get_block_Z = wrap_deprecated(block.get_Z, "get_block_Z", "block.get_Z") +get_block_states = wrap_deprecated(block.get_states, "get_block_states", "block.get_states") +set_block_states = wrap_deprecated(block.set_states, "set_block_states", "block.set_states") +get_block_rotation = wrap_deprecated(block.get_rotation, "get_block_rotation", "block.get_rotation") +set_block_rotation = wrap_deprecated(block.set_rotation, "set_block_rotation", "block.set_rotation") +get_block_user_bits = wrap_deprecated(block.get_user_bits, "get_block_user_bits", "block.get_user_bits") +set_block_user_bits = wrap_deprecated(block.set_user_bits, "set_block_user_bits", "block.set_user_bits") + +function load_script(path, nocache) + on_deprecated_call("load_script", "require or loadstring") + return __load_script(path, nocache) +end + +_dofile = dofile +-- Replaces dofile('*/content/packid/*') with load_script('packid:*') +function dofile(path) + on_deprecated_call("dofile", "require or loadstring") + local index = string.find(path, "/content/") + if index then + local newpath = string.sub(path, index+9) + index = string.find(newpath, "/") + if index then + local label = string.sub(newpath, 1, index-1) + newpath = label..':'..string.sub(newpath, index+1) + if file.isfile(newpath) then + return __load_script(newpath, true) + end + end + end + return _dofile(path) +end diff --git a/res/modules/internal/extensions/file.lua b/res/modules/internal/extensions/file.lua new file mode 100644 index 00000000..0f104012 --- /dev/null +++ b/res/modules/internal/extensions/file.lua @@ -0,0 +1,45 @@ +function file.name(path) + return path:match("([^:/\\]+)$") +end + +function file.stem(path) + local name = file.name(path) + return name:match("(.+)%.[^%.]+$") or name +end + +function file.ext(path) + return path:match("%.([^:/\\]+)$") +end + +function file.prefix(path) + return path:match("^([^:]+)") +end + +function file.parent(path) + local dir = path:match("(.*)/") + if not dir then + return file.prefix(path)..":" + end + return dir +end + +function file.path(path) + local pos = path:find(':') + return path:sub(pos + 1) +end + +function file.join(a, b) + if a[#a] == ':' then + return a .. b + end + return a .. "/" .. b +end + +function file.readlines(path) + local str = file.read(path) + local lines = {} + for s in str:gmatch("[^\r\n]+") do + table.insert(lines, s) + end + return lines +end diff --git a/res/modules/internal/extensions/inventory.lua b/res/modules/internal/extensions/inventory.lua new file mode 100644 index 00000000..799eecb0 --- /dev/null +++ b/res/modules/internal/extensions/inventory.lua @@ -0,0 +1,71 @@ +function inventory.get_uses(invid, slot) + local uses = inventory.get_data(invid, slot, "uses") + if uses == nil then + return item.uses(inventory.get(invid, slot)) + end + return uses +end + +function inventory.use(invid, slot) + local itemid, count = inventory.get(invid, slot) + if itemid == nil then + return + end + local item_uses = inventory.get_uses(invid, slot) + if item_uses == nil then + return + end + if item_uses == 1 then + inventory.set(invid, slot, itemid, count - 1) + elseif item_uses > 1 then + inventory.set_data(invid, slot, "uses", item_uses - 1) + end +end + +function inventory.decrement(invid, slot, count) + count = count or 1 + local itemid, itemcount = inventory.get(invid, slot) + if itemcount <= count then + inventory.set(invid, slot, 0) + else + inventory.set_count(invid, slot, itemcount - count) + end +end + +function inventory.get_caption(invid, slot) + local item_id, count = inventory.get(invid, slot) + local caption = inventory.get_data(invid, slot, "caption") + if not caption then return item.caption(item_id) end + + return caption +end + +function inventory.set_caption(invid, slot, caption) + local itemid, itemcount = inventory.get(invid, slot) + if itemid == 0 then + return + end + if caption == nil or type(caption) ~= "string" then + caption = "" + end + inventory.set_data(invid, slot, "caption", caption) +end + +function inventory.get_description(invid, slot) + local item_id, count = inventory.get(invid, slot) + local description = inventory.get_data(invid, slot, "description") + if not description then return item.description(item_id) end + + return description +end + +function inventory.set_description(invid, slot, description) + local itemid, itemcount = inventory.get(invid, slot) + if itemid == 0 then + return + end + if description == nil or type(description) ~= "string" then + description = "" + end + inventory.set_data(invid, slot, "description", description) +end diff --git a/res/modules/internal/extensions/math.lua b/res/modules/internal/extensions/math.lua new file mode 100644 index 00000000..d906e94a --- /dev/null +++ b/res/modules/internal/extensions/math.lua @@ -0,0 +1,37 @@ +function math.clamp(_in, low, high) + return math.min(math.max(_in, low), high) +end + +function math.rand(low, high) + return low + (high - low) * math.random() +end + +function math.normalize(num, conf) + conf = conf or 1 + + return (num / conf) % 1 +end + +function math.round(num, places) + places = places or 0 + + local mult = 10 ^ places + return math.floor(num * mult + 0.5) / mult +end + +function math.sum(...) + local numbers = nil + local sum = 0 + + if type(...) == "table" then + numbers = ... + else + numbers = {...} + end + + for _, v in ipairs(numbers) do + sum = sum + v + end + + return sum +end diff --git a/res/modules/internal/extensions/pack.lua b/res/modules/internal/extensions/pack.lua new file mode 100644 index 00000000..c43c1203 --- /dev/null +++ b/res/modules/internal/extensions/pack.lua @@ -0,0 +1,13 @@ +function pack.is_installed(packid) + return file.isfile(packid..":package.json") +end + +function pack.data_file(packid, name) + file.mkdirs("world:data/"..packid) + return "world:data/"..packid.."/"..name +end + +function pack.shared_file(packid, name) + file.mkdirs("config:"..packid) + return "config:"..packid.."/"..name +end diff --git a/res/modules/internal/extensions/string.lua b/res/modules/internal/extensions/string.lua new file mode 100644 index 00000000..f76470df --- /dev/null +++ b/res/modules/internal/extensions/string.lua @@ -0,0 +1,126 @@ +local pattern_escape_replacements = { + ["("] = "%(", + [")"] = "%)", + ["."] = "%.", + ["%"] = "%%", + ["+"] = "%+", + ["-"] = "%-", + ["*"] = "%*", + ["?"] = "%?", + ["["] = "%[", + ["]"] = "%]", + ["^"] = "%^", + ["$"] = "%$", + ["\0"] = "%z" +} + +function string.pattern_safe(str) + return string.gsub(str, ".", pattern_escape_replacements) +end + +local string_sub = string.sub +local string_find = string.find +local string_len = string.len +function string.explode(separator, str, withpattern) + if (withpattern == nil) then withpattern = false end + + local ret = {} + local current_pos = 1 + + for i = 1, string_len(str) do + local start_pos, end_pos = string_find( + str, separator, current_pos, not withpattern) + if (not start_pos) then break end + ret[i] = string_sub(str, current_pos, start_pos - 1) + current_pos = end_pos + 1 + end + + ret[#ret + 1] = string_sub(str, current_pos) + + return ret +end + +function string.split(str, delimiter) + return string.explode(delimiter, str) +end + +function string.formatted_time(seconds, format) + if (not seconds) then seconds = 0 end + local hours = math.floor(seconds / 3600) + local minutes = math.floor((seconds / 60) % 60) + local millisecs = (seconds - math.floor(seconds)) * 1000 + seconds = math.floor(seconds % 60) + + if (format) then + return string.format(format, minutes, seconds, millisecs) + else + return { h = hours, m = minutes, s = seconds, ms = millisecs } + end +end + +function string.replace(str, tofind, toreplace) + local tbl = string.explode(tofind, str) + if (tbl[1]) then return table.concat(tbl, toreplace) end + return str +end + +function string.trim(s, char) + if char then char = string.pattern_safe(char) else char = "%s" end + return string.match(s, "^" .. char .. "*(.-)" .. char .. "*$") or s +end + +function string.trim_right(s, char) + if char then char = string.pattern_safe(char) else char = "%s" end + return string.match(s, "^(.-)" .. char .. "*$") or s +end + +function string.trim_left(s, char) + if char then char = string.pattern_safe(char) else char = "%s" end + return string.match(s, "^" .. char .. "*(.+)$") or s +end + +function string.pad(str, size, char) + char = char == nil and " " or char + + local padding = math.floor((size - #str) / 2) + local extra_padding = (size - #str) % 2 + + return string.rep(char, padding) .. str .. string.rep(char, padding + extra_padding) +end + +function string.left_pad(str, size, char) + char = char == nil and " " or char + + local left_padding = size - #str + return string.rep(char, left_padding) .. str +end + +function string.right_pad(str, size, char) + char = char == nil and " " or char + + local right_padding = size - #str + return str .. string.rep(char, right_padding) +end + +string.lower = utf8.lower +string.upper = utf8.upper +string.escape = utf8.escape + +local meta = getmetatable("") + +function meta:__index(key) + local val = string[key] + if (val ~= nil) then + return val + elseif (tonumber(key)) then + return string.sub(self, key, key) + end +end + +function string.starts_with(str, start) + return string.sub(str, 1, string.len(start)) == start +end + +function string.ends_with(str, endStr) + return endStr == "" or string.sub(str, -string.len(endStr)) == endStr +end diff --git a/res/modules/internal/extensions/table.lua b/res/modules/internal/extensions/table.lua new file mode 100644 index 00000000..33047df3 --- /dev/null +++ b/res/modules/internal/extensions/table.lua @@ -0,0 +1,179 @@ +function table.copy(t) + local copied = {} + + for k, v in pairs(t) do + copied[k] = v + end + + return copied +end + +function table.deep_copy(t) + local copied = {} + + for k, v in pairs(t) do + if type(v) == "table" then + copied[k] = table.deep_copy(v) + else + copied[k] = v + end + end + + return setmetatable(copied, getmetatable(t)) +end + +function table.count_pairs(t) + local count = 0 + + for k, v in pairs(t) do + count = count + 1 + end + + return count +end + +function table.random(t) + return t[math.random(1, #t)] +end + +function table.shuffle(t) + for i = #t, 2, -1 do + local j = math.random(i) + t[i], t[j] = t[j], t[i] + end + + return t +end + +function table.merge(t1, t2) + for i, v in pairs(t2) do + if type(i) == "number" then + t1[#t1 + 1] = v + elseif t1[i] == nil then + t1[i] = v + end + end + + return t1 +end + +function table.map(t, func) + for i, v in pairs(t) do + t[i] = func(i, v) + end + + return t +end + +function table.filter(t, func) + + for i = #t, 1, -1 do + if not func(i, t[i]) then + table.remove(t, i) + end + end + + local size = #t + + for i, v in pairs(t) do + local i_type = type(i) + if i_type == "number" then + if i < 1 or i > size then + if not func(i, v) then + t[i] = nil + end + end + else + if not func(i, v) then + t[i] = nil + end + end + end + + return t +end + +function table.set_default(t, key, default) + if t[key] == nil then + t[key] = default + return default + end + + return t[key] +end + +function table.flat(t) + local flat = {} + + for _, v in pairs(t) do + if type(v) == "table" then + table.merge(flat, v) + else + table.insert(flat, v) + end + end + + return flat +end + +function table.deep_flat(t) + local flat = {} + + for _, v in pairs(t) do + if type(v) == "table" then + table.merge(flat, table.deep_flat(v)) + else + table.insert(flat, v) + end + end + + return flat +end + +function table.sub(arr, start, stop) + local res = {} + start = start or 1 + stop = stop or #arr + + for i = start, stop do + table.insert(res, arr[i]) + end + + return res +end + +function table.has(t, x) + for i,v in ipairs(t) do + if v == x then + return true + end + end + return false +end + +function table.index(t, x) + for i,v in ipairs(t) do + if v == x then + return i + end + end + return -1 +end + +function table.remove_value(t, x) + local index = table.index(t, x) + if index ~= -1 then + table.remove(t, index) + end +end + +function table.tostring(t) + local s = '[' + for i,v in ipairs(t) do + s = s..tostring(v) + if i < #t then + s = s..', ' + end + end + return s..']' +end diff --git a/res/modules/internal/rules.lua b/res/modules/internal/rules.lua new file mode 100644 index 00000000..a1a5a8c3 --- /dev/null +++ b/res/modules/internal/rules.lua @@ -0,0 +1,70 @@ +local rules = {nexid = 1, rules = {}} + +function rules.get_rule(name) + local rule = rules.rules[name] + if rule == nil then + rule = {listeners={}} + rules.rules[name] = rule + end + return rule +end + +function rules.get(name) + local rule = rules.rules[name] + if rule == nil then + return nil + end + return rule.value +end + +function rules.set(name, value) + local rule = rules.get_rule(name) + rule.value = value + for _, handler in pairs(rule.listeners) do + handler(value) + end +end + +function rules.reset(name) + local rule = rules.get_rule(name) + rules.set(rule.default) +end + +function rules.listen(name, handler) + local rule = rules.get_rule(name) + local id = rules.nexid + rules.nextid = rules.nexid + 1 + rule.listeners[utf8.encode(id)] = handler + return id +end + +function rules.create(name, value, handler) + local rule = rules.get_rule(name) + rule.default = value + + local handlerid + if handler ~= nil then + handlerid = rules.listen(name, handler) + end + if rules.get(name) == nil then + rules.set(name, value) + elseif handler then + handler(rules.get(name)) + end + return handlerid +end + +function rules.unlisten(name, id) + local rule = rules.rules[name] + if rule == nil then + return + end + rule.listeners[utf8.encode(id)] = nil +end + +function rules.clear() + rules.rules = {} + rules.nextid = 1 +end + +return rules diff --git a/res/scripts/stdlib.lua b/res/scripts/stdlib.lua index d0077b6f..71a8256e 100644 --- a/res/scripts/stdlib.lua +++ b/res/scripts/stdlib.lua @@ -105,81 +105,10 @@ elseif __vc_app then complete_app_lib(__vc_app) end -function inventory.get_uses(invid, slot) - local uses = inventory.get_data(invid, slot, "uses") - if uses == nil then - return item.uses(inventory.get(invid, slot)) - end - return uses -end - -function inventory.use(invid, slot) - local itemid, count = inventory.get(invid, slot) - if itemid == nil then - return - end - local item_uses = inventory.get_uses(invid, slot) - if item_uses == nil then - return - end - if item_uses == 1 then - inventory.set(invid, slot, itemid, count - 1) - elseif item_uses > 1 then - inventory.set_data(invid, slot, "uses", item_uses - 1) - end -end - -function inventory.decrement(invid, slot, count) - count = count or 1 - local itemid, itemcount = inventory.get(invid, slot) - if itemcount <= count then - inventory.set(invid, slot, 0) - else - inventory.set_count(invid, slot, itemcount - count) - end -end - -function inventory.get_caption(invid, slot) - local item_id, count = inventory.get(invid, slot) - local caption = inventory.get_data(invid, slot, "caption") - if not caption then return item.caption(item_id) end - - return caption -end - -function inventory.set_caption(invid, slot, caption) - local itemid, itemcount = inventory.get(invid, slot) - if itemid == 0 then - return - end - if caption == nil or type(caption) ~= "string" then - caption = "" - end - inventory.set_data(invid, slot, "caption", caption) -end - -function inventory.get_description(invid, slot) - local item_id, count = inventory.get(invid, slot) - local description = inventory.get_data(invid, slot, "description") - if not description then return item.description(item_id) end - - return description -end - -function inventory.set_description(invid, slot, description) - local itemid, itemcount = inventory.get(invid, slot) - if itemid == 0 then - return - end - if description == nil or type(description) ~= "string" then - description = "" - end - inventory.set_data(invid, slot, "description", description) -end - require "core:internal/maths_inline" require "core:internal/debugging" require "core:internal/audio_input" +require "core:internal/extensions/inventory" asserts = require "core:internal/asserts" events = require "core:internal/events" @@ -306,86 +235,20 @@ else os.pid = ffi.C.getpid() end -ffi = nil -__vc_lock_internal_modules() - math.randomseed(time.uptime() * 1536227939) -rules = {nexid = 1, rules = {}} +rules = require "core:internal/rules" local _rules = rules -function _rules.get_rule(name) - local rule = _rules.rules[name] - if rule == nil then - rule = {listeners={}} - _rules.rules[name] = rule - end - return rule -end - -function _rules.get(name) - local rule = _rules.rules[name] - if rule == nil then - return nil - end - return rule.value -end - -function _rules.set(name, value) - local rule = _rules.get_rule(name) - rule.value = value - for _, handler in pairs(rule.listeners) do - handler(value) - end -end - -function _rules.reset(name) - local rule = _rules.get_rule(name) - _rules.set(rule.default) -end - -function _rules.listen(name, handler) - local rule = _rules.get_rule(name) - local id = _rules.nexid - _rules.nextid = _rules.nexid + 1 - rule.listeners[utf8.encode(id)] = handler - return id -end - -function _rules.create(name, value, handler) - local rule = _rules.get_rule(name) - rule.default = value - - local handlerid - if handler ~= nil then - handlerid = _rules.listen(name, handler) - end - if _rules.get(name) == nil then - _rules.set(name, value) - elseif handler then - handler(_rules.get(name)) - end - return handlerid -end - -function _rules.unlisten(name, id) - local rule = _rules.rules[name] - if rule == nil then - return - end - rule.listeners[utf8.encode(id)] = nil -end - -function _rules.clear() - _rules.rules = {} - _rules.nextid = 1 -end - function __vc_on_hud_open() + local _hud_is_content_access = hud._is_content_access + local _hud_set_content_access = hud._set_content_access + local _hud_set_debug_cheats = hud._set_debug_cheats + _rules.create("allow-cheats", true) - _rules.create("allow-content-access", hud._is_content_access(), function(value) - hud._set_content_access(value) + _rules.create("allow-content-access", _hud_is_content_access(), function(value) + _hud_set_content_access(value) end) _rules.create("allow-flight", true, function(value) input.set_enabled("player.flight", value) @@ -406,7 +269,7 @@ function __vc_on_hud_open() input.set_enabled("player.fast_interaction", value) end) _rules.create("allow-debug-cheats", true, function(value) - hud._set_debug_cheats(value) + _hud_set_debug_cheats(value) end) input.add_callback("devtools.console", function() if menu.page ~= "" then @@ -605,6 +468,7 @@ local _getinfo = debug.getinfo for i, name in ipairs(removed_names) do debug[name] = nil end + debug.getinfo = function(lvl, fields) if type(lvl) == "number" then lvl = lvl + 1 @@ -614,51 +478,7 @@ debug.getinfo = function(lvl, fields) return debuginfo end --- --------- Deprecated functions ------ -- -local function wrap_deprecated(func, name, alternatives) - return function (...) - on_deprecated_call(name, alternatives) - return func(...) - end -end +require "core:internal/deprecated" -block_index = wrap_deprecated(block.index, "block_index", "block.index") -block_name = wrap_deprecated(block.name, "block_name", "block.name") -blocks_count = wrap_deprecated(block.defs_count, "blocks_count", "block.defs_count") -is_solid_at = wrap_deprecated(block.is_solid_at, "is_solid_at", "block.is_solid_at") -is_replaceable_at = wrap_deprecated(block.is_replaceable_at, "is_replaceable_at", "block.is_replaceable_at") -set_block = wrap_deprecated(block.set, "set_block", "block.set") -get_block = wrap_deprecated(block.get, "get_block", "block.get") -get_block_X = wrap_deprecated(block.get_X, "get_block_X", "block.get_X") -get_block_Y = wrap_deprecated(block.get_Y, "get_block_Y", "block.get_Y") -get_block_Z = wrap_deprecated(block.get_Z, "get_block_Z", "block.get_Z") -get_block_states = wrap_deprecated(block.get_states, "get_block_states", "block.get_states") -set_block_states = wrap_deprecated(block.set_states, "set_block_states", "block.set_states") -get_block_rotation = wrap_deprecated(block.get_rotation, "get_block_rotation", "block.get_rotation") -set_block_rotation = wrap_deprecated(block.set_rotation, "set_block_rotation", "block.set_rotation") -get_block_user_bits = wrap_deprecated(block.get_user_bits, "get_block_user_bits", "block.get_user_bits") -set_block_user_bits = wrap_deprecated(block.set_user_bits, "set_block_user_bits", "block.set_user_bits") - -function load_script(path, nocache) - on_deprecated_call("load_script", "require or loadstring") - return __load_script(path, nocache) -end - -_dofile = dofile --- Replaces dofile('*/content/packid/*') with load_script('packid:*') -function dofile(path) - on_deprecated_call("dofile", "require or loadstring") - local index = string.find(path, "/content/") - if index then - local newpath = string.sub(path, index+9) - index = string.find(newpath, "/") - if index then - local label = string.sub(newpath, 1, index-1) - newpath = label..':'..string.sub(newpath, index+1) - if file.isfile(newpath) then - return __load_script(newpath, true) - end - end - end - return _dofile(path) -end +ffi = nil +__vc_lock_internal_modules() diff --git a/res/scripts/stdmin.lua b/res/scripts/stdmin.lua index 30343d7d..7e8678e5 100644 --- a/res/scripts/stdmin.lua +++ b/res/scripts/stdmin.lua @@ -42,6 +42,26 @@ end -- may be reused one global ffi buffer per lua_State local canvas_ffi_buffer local canvas_ffi_buffer_size = 0 +local _ffi = ffi +function __vc_Canvas_set_data(self, data) + if type(data) == "cdata" then + self:_set_data(tostring(_ffi.cast("uintptr_t", data))) + end + local width = self.width + local height = self.height + + local size = width * height * 4 + if size > canvas_ffi_buffer_size then + canvas_ffi_buffer = _ffi.new( + string.format("unsigned char[%s]", size) + ) + canvas_ffi_buffer_size = size + end + for i=0, size - 1 do + canvas_ffi_buffer[i] = data[i + 1] + end + self:_set_data(tostring(_ffi.cast("uintptr_t", canvas_ffi_buffer))) +end local ipairs_mt_supported = false for i, _ in ipairs(setmetatable({l={1}}, { @@ -72,42 +92,6 @@ function await(co) return res, err end -local _ffi = ffi -function __vc_Canvas_set_data(self, data) - if type(data) == "cdata" then - self:_set_data(tostring(_ffi.cast("uintptr_t", data))) - end - local width = self.width - local height = self.height - - local size = width * height * 4 - if size > canvas_ffi_buffer_size then - canvas_ffi_buffer = _ffi.new( - string.format("unsigned char[%s]", size) - ) - canvas_ffi_buffer_size = size - end - for i=0, size - 1 do - canvas_ffi_buffer[i] = data[i + 1] - end - self:_set_data(tostring(_ffi.cast("uintptr_t", canvas_ffi_buffer))) -end - -function pack.is_installed(packid) - return file.isfile(packid..":package.json") -end - -function pack.data_file(packid, name) - file.mkdirs("world:data/"..packid) - return "world:data/"..packid.."/"..name -end - -function pack.shared_file(packid, name) - file.mkdirs("config:"..packid) - return "config:"..packid.."/"..name -end - - function timeit(iters, func, ...) local tm = os.clock() for i=1,iters do @@ -118,364 +102,6 @@ end ---------------------------------------------- -function math.clamp(_in, low, high) - return math.min(math.max(_in, low), high) -end - -function math.rand(low, high) - return low + (high - low) * math.random() -end - -function math.normalize(num, conf) - conf = conf or 1 - - return (num / conf) % 1 -end - -function math.round(num, places) - places = places or 0 - - local mult = 10 ^ places - return math.floor(num * mult + 0.5) / mult -end - -function math.sum(...) - local numbers = nil - local sum = 0 - - if type(...) == "table" then - numbers = ... - else - numbers = {...} - end - - for _, v in ipairs(numbers) do - sum = sum + v - end - - return sum -end - ----------------------------------------------- - -function table.copy(t) - local copied = {} - - for k, v in pairs(t) do - copied[k] = v - end - - return copied -end - -function table.deep_copy(t) - local copied = {} - - for k, v in pairs(t) do - if type(v) == "table" then - copied[k] = table.deep_copy(v) - else - copied[k] = v - end - end - - return setmetatable(copied, getmetatable(t)) -end - -function table.count_pairs(t) - local count = 0 - - for k, v in pairs(t) do - count = count + 1 - end - - return count -end - -function table.random(t) - return t[math.random(1, #t)] -end - -function table.shuffle(t) - for i = #t, 2, -1 do - local j = math.random(i) - t[i], t[j] = t[j], t[i] - end - - return t -end - -function table.merge(t1, t2) - for i, v in pairs(t2) do - if type(i) == "number" then - t1[#t1 + 1] = v - elseif t1[i] == nil then - t1[i] = v - end - end - - return t1 -end - -function table.map(t, func) - for i, v in pairs(t) do - t[i] = func(i, v) - end - - return t -end - -function table.filter(t, func) - - for i = #t, 1, -1 do - if not func(i, t[i]) then - table.remove(t, i) - end - end - - local size = #t - - for i, v in pairs(t) do - local i_type = type(i) - if i_type == "number" then - if i < 1 or i > size then - if not func(i, v) then - t[i] = nil - end - end - else - if not func(i, v) then - t[i] = nil - end - end - end - - return t -end - -function table.set_default(t, key, default) - if t[key] == nil then - t[key] = default - return default - end - - return t[key] -end - -function table.flat(t) - local flat = {} - - for _, v in pairs(t) do - if type(v) == "table" then - table.merge(flat, v) - else - table.insert(flat, v) - end - end - - return flat -end - -function table.deep_flat(t) - local flat = {} - - for _, v in pairs(t) do - if type(v) == "table" then - table.merge(flat, table.deep_flat(v)) - else - table.insert(flat, v) - end - end - - return flat -end - -function table.sub(arr, start, stop) - local res = {} - start = start or 1 - stop = stop or #arr - - for i = start, stop do - table.insert(res, arr[i]) - end - - return res -end - ----------------------------------------------- - -local pattern_escape_replacements = { - ["("] = "%(", - [")"] = "%)", - ["."] = "%.", - ["%"] = "%%", - ["+"] = "%+", - ["-"] = "%-", - ["*"] = "%*", - ["?"] = "%?", - ["["] = "%[", - ["]"] = "%]", - ["^"] = "%^", - ["$"] = "%$", - ["\0"] = "%z" -} - -function string.pattern_safe(str) - return string.gsub(str, ".", pattern_escape_replacements) -end - -local string_sub = string.sub -local string_find = string.find -local string_len = string.len -function string.explode(separator, str, withpattern) - if (withpattern == nil) then withpattern = false end - - local ret = {} - local current_pos = 1 - - for i = 1, string_len(str) do - local start_pos, end_pos = string_find( - str, separator, current_pos, not withpattern) - if (not start_pos) then break end - ret[i] = string_sub(str, current_pos, start_pos - 1) - current_pos = end_pos + 1 - end - - ret[#ret + 1] = string_sub(str, current_pos) - - return ret -end - -function string.split(str, delimiter) - return string.explode(delimiter, str) -end - -function string.formatted_time(seconds, format) - if (not seconds) then seconds = 0 end - local hours = math.floor(seconds / 3600) - local minutes = math.floor((seconds / 60) % 60) - local millisecs = (seconds - math.floor(seconds)) * 1000 - seconds = math.floor(seconds % 60) - - if (format) then - return string.format(format, minutes, seconds, millisecs) - else - return { h = hours, m = minutes, s = seconds, ms = millisecs } - end -end - -function string.replace(str, tofind, toreplace) - local tbl = string.explode(tofind, str) - if (tbl[1]) then return table.concat(tbl, toreplace) end - return str -end - -function string.trim(s, char) - if char then char = string.pattern_safe(char) else char = "%s" end - return string.match(s, "^" .. char .. "*(.-)" .. char .. "*$") or s -end - -function string.trim_right(s, char) - if char then char = string.pattern_safe(char) else char = "%s" end - return string.match(s, "^(.-)" .. char .. "*$") or s -end - -function string.trim_left(s, char) - if char then char = string.pattern_safe(char) else char = "%s" end - return string.match(s, "^" .. char .. "*(.+)$") or s -end - -function string.pad(str, size, char) - char = char == nil and " " or char - - local padding = math.floor((size - #str) / 2) - local extra_padding = (size - #str) % 2 - - return string.rep(char, padding) .. str .. string.rep(char, padding + extra_padding) -end - -function string.left_pad(str, size, char) - char = char == nil and " " or char - - local left_padding = size - #str - return string.rep(char, left_padding) .. str -end - -function string.right_pad(str, size, char) - char = char == nil and " " or char - - local right_padding = size - #str - return str .. string.rep(char, right_padding) -end - -string.lower = utf8.lower -string.upper = utf8.upper -string.escape = utf8.escape - -local meta = getmetatable("") - -function meta:__index(key) - local val = string[key] - if (val ~= nil) then - return val - elseif (tonumber(key)) then - return string.sub(self, key, key) - end -end - -function string.starts_with(str, start) - return string.sub(str, 1, string.len(start)) == start -end - -function string.ends_with(str, endStr) - return endStr == "" or string.sub(str, -string.len(endStr)) == endStr -end - -function table.has(t, x) - for i,v in ipairs(t) do - if v == x then - return true - end - end - return false -end - -function table.index(t, x) - for i,v in ipairs(t) do - if v == x then - return i - end - end - return -1 -end - -function table.remove_value(t, x) - local index = table.index(t, x) - if index ~= -1 then - table.remove(t, index) - end -end - -function table.tostring(t) - local s = '[' - for i,v in ipairs(t) do - s = s..tostring(v) - if i < #t then - s = s..', ' - end - end - return s..']' -end - -function file.readlines(path) - local str = file.read(path) - local lines = {} - for s in str:gmatch("[^\r\n]+") do - table.insert(lines, s) - end - return lines -end - function debug.count_frames() local frames = 1 while true do @@ -634,43 +260,11 @@ function __vc_warning(msg, detail, n) end end -function file.name(path) - return path:match("([^:/\\]+)$") -end - -function file.stem(path) - local name = file.name(path) - return name:match("(.+)%.[^%.]+$") or name -end - -function file.ext(path) - return path:match("%.([^:/\\]+)$") -end - -function file.prefix(path) - return path:match("^([^:]+)") -end - -function file.parent(path) - local dir = path:match("(.*)/") - if not dir then - return file.prefix(path)..":" - end - return dir -end - -function file.path(path) - local pos = path:find(':') - return path:sub(pos + 1) -end - -function file.join(a, b) - if a[#a] == ':' then - return a .. b - end - return a .. "/" .. b -end - +require "core:internal/extensions/pack" +require "core:internal/extensions/math" +require "core:internal/extensions/file" +require "core:internal/extensions/table" +require "core:internal/extensions/string" bit.compile = require "core:bitwise/compiler" bit.execute = require "core:bitwise/executor"