From e1b8faeb6b7d68213d9404e2f14424c8f800b6ef Mon Sep 17 00:00:00 2001 From: TheEt1234 Date: Sun, 21 Sep 2025 13:52:21 +0200 Subject: [PATCH 01/28] Made space movement not interfere with the jetpack --- mods/sbz_base/init.lua | 5 +- mods/sbz_base/space_movement.lua | 6 +- mods/sbz_instatube/init.lua | 2 +- mods/sbz_pipeworks/basic_tubes.lua | 285 ++++---- mods/sbz_pipeworks/item_transport.lua | 811 +++++++++++----------- mods/sbz_progression/quests/Chemistry.md | 27 +- mods/sbz_resources/jetpack.lua | 102 ++- mods/stubes/README.md | 26 + mods/stubes/basic_tubes.lua | 0 mods/stubes/entity.lua | 0 mods/stubes/init.lua | 20 + mods/stubes/mod.conf | 2 + mods/stubes/place.lua | 288 ++++++++ mods/stubes/register.lua | 320 +++++++++ mods/stubes/textures/stube_basic_tube.png | Bin 0 -> 517 bytes mods/stubes/transport.lua | 195 ++++++ types/core.d.lua | 1 + 17 files changed, 1469 insertions(+), 621 deletions(-) create mode 100644 mods/stubes/README.md create mode 100644 mods/stubes/basic_tubes.lua create mode 100644 mods/stubes/entity.lua create mode 100644 mods/stubes/init.lua create mode 100644 mods/stubes/mod.conf create mode 100644 mods/stubes/place.lua create mode 100644 mods/stubes/register.lua create mode 100644 mods/stubes/textures/stube_basic_tube.png create mode 100644 mods/stubes/transport.lua diff --git a/mods/sbz_base/init.lua b/mods/sbz_base/init.lua index f7d188f2..92b5ee9a 100644 --- a/mods/sbz_base/init.lua +++ b/mods/sbz_base/init.lua @@ -408,10 +408,9 @@ end https://github.com/mt-mods/technic/blob/379bedc20d7ab11c758afa52d5916b23dced5354/technic/helpers.lua#L102 to line 107 ]] -local get_or_load_node_node function sbz_api.get_or_load_node(pos) - get_or_load_node_node = core.get_node_or_nil(pos) - if get_or_load_node_node then return get_or_load_node_node end + local node = core.get_node_or_nil(pos) + if node then return node end core.load_area(pos) return core.get_node(pos) end diff --git a/mods/sbz_base/space_movement.lua b/mods/sbz_base/space_movement.lua index 7870969b..f82dcf68 100644 --- a/mods/sbz_base/space_movement.lua +++ b/mods/sbz_base/space_movement.lua @@ -5,9 +5,11 @@ local function space_movement_step() for _, player in pairs(core.get_connected_players()) do local controls = player:get_player_control() if controls.jump and controls.aux1 then - player_monoids.gravity:add_change(player, 0, 'sbz_api:???') + if not sbz_api.jetpack_users[player:get_player_name()] then + player_monoids.gravity:add_change(player, 0, 'sbz_api:space_movement') + end else - player_monoids.gravity:del_change(player, 'sbz_api:???') + player_monoids.gravity:del_change(player, 'sbz_api:space_movement') end end end diff --git a/mods/sbz_instatube/init.lua b/mods/sbz_instatube/init.lua index 1a56b2a3..333d4a24 100644 --- a/mods/sbz_instatube/init.lua +++ b/mods/sbz_instatube/init.lua @@ -243,7 +243,7 @@ local instatube_insert_object = function(pos, _, stack, _, owner, ordering) if machine.tube.insert_object then stack = machine.tube.insert_object(mpos, mnode, stack, { x = 0, y = 0, z = 0, speed = 1 }, owner) end - else -- its a tupe, dump the stack in + else -- its a tube, dump the stack in local entity = pipeworks.tube_inject_item( mpos, vector.subtract(mpos, machine.dir), diff --git a/mods/sbz_pipeworks/basic_tubes.lua b/mods/sbz_pipeworks/basic_tubes.lua index 90d886f9..06a35fa4 100644 --- a/mods/sbz_pipeworks/basic_tubes.lua +++ b/mods/sbz_pipeworks/basic_tubes.lua @@ -1,53 +1,57 @@ -pipeworks.register_tube("pipeworks:tube", { - description = "Basic Tube", - plain = { { name = "basic_tube_plain.png", backface_culling = pipeworks.tube_backface_culling } }, - noctr = { { name = "basic_tube_noctr.png", backface_culling = pipeworks.tube_backface_culling } }, +pipeworks.register_tube('pipeworks:tube', { + description = 'Basic Tube', + plain = { { name = 'basic_tube_plain.png', backface_culling = pipeworks.tube_backface_culling } }, + noctr = { { name = 'basic_tube_noctr.png', backface_culling = pipeworks.tube_backface_culling } }, }) -minetest.register_craft({ - output = "pipeworks:tube_1 8", +minetest.register_craft { + output = 'pipeworks:tube_1 8', recipe = { - { "sbz_chem:aluminum_ingot", "", "sbz_chem:aluminum_ingot" }, - { "", "", "" }, - { "sbz_chem:aluminum_ingot", "", "sbz_chem:aluminum_ingot" }, - } -}) + { 'sbz_chem:aluminum_ingot', '', 'sbz_chem:aluminum_ingot' }, + { '', '', '' }, + { 'sbz_chem:aluminum_ingot', '', 'sbz_chem:aluminum_ingot' }, + }, +} -pipeworks.register_tube("pipeworks:accelerator_tube", { - description = "Accelerating Tube", - plain = { { name = "basic_tube_plain.png", backface_culling = pipeworks.tube_backface_culling, color = "springgreen" } }, - noctr = { { name = "basic_tube_noctr.png", backface_culling = pipeworks.tube_backface_culling, color = "springgreen" } }, +pipeworks.register_tube('pipeworks:accelerator_tube', { + description = 'Accelerating Tube', + plain = { + { name = 'basic_tube_plain.png', backface_culling = pipeworks.tube_backface_culling, color = 'springgreen' }, + }, + noctr = { + { name = 'basic_tube_noctr.png', backface_culling = pipeworks.tube_backface_culling, color = 'springgreen' }, + }, node_def = { tube = { can_go = function(pos, node, velocity, stack) velocity.speed = velocity.speed + 1 return pipeworks.notvel(pipeworks.meseadjlist, velocity) - end - } + end, + }, }, }) -local ch_pa = "sbz_resources:charged_particle" -minetest.register_craft({ - output = "pipeworks:accelerator_tube_1 1", +local ch_pa = 'sbz_resources:charged_particle' +minetest.register_craft { + output = 'pipeworks:accelerator_tube_1 1', recipe = { - { ch_pa, ch_pa, ch_pa }, - { ch_pa, "pipeworks:tube_1", ch_pa }, - { ch_pa, ch_pa, ch_pa }, - } -}) + { ch_pa, ch_pa, ch_pa }, + { ch_pa, 'pipeworks:tube_1', ch_pa }, + { ch_pa, ch_pa, ch_pa }, + }, +} -pipeworks.register_tube("pipeworks:one_direction_tube", { - description = "One Direction Tube", - plain = { { name = "basic_tube_plain.png", backface_culling = pipeworks.tube_backface_culling, color = "#45283c" } }, - noctr = { { name = "basic_tube_noctr.png", backface_culling = pipeworks.tube_backface_culling, color = "#45283c" } }, +pipeworks.register_tube('pipeworks:one_direction_tube', { + description = 'One Direction Tube', + plain = { { name = 'basic_tube_plain.png', backface_culling = pipeworks.tube_backface_culling, color = '#45283c' } }, + noctr = { { name = 'basic_tube_noctr.png', backface_culling = pipeworks.tube_backface_culling, color = '#45283c' } }, node_def = { on_construct = function(pos) local likely_dir = nil iterate_around_pos(pos, function(ipos) - if core.get_node(ipos).name:find("pipeworks:one_direction_tube") then - local dir = core.get_meta(ipos):get_int("dir") + if core.get_node(ipos).name:find 'pipeworks:one_direction_tube' then + local dir = core.get_meta(ipos):get_int 'dir' likely_dir = dir end end) @@ -55,39 +59,42 @@ pipeworks.register_tube("pipeworks:one_direction_tube", { if likely_dir == nil then likely_dir = core.dir_to_wallmounted(vector.new(0, -1, 0)) end local meta = core.get_meta(pos) - meta:set_int("dir", likely_dir) + meta:set_int('dir', likely_dir) end, -- gets repeated every half second sbz_on_hover = function(pointed_thing, player) local pos = pointed_thing.under local meta = core.get_meta(pos) - local dir = core.wallmounted_to_dir(meta:get_int("dir")) + local dir = core.wallmounted_to_dir(meta:get_int 'dir') - core.add_particle({ - pos = vector.add( - pointed_thing.under, - vector.divide(dir, 2)), + core.add_particle { + pos = vector.add(pointed_thing.under, vector.divide(dir, 2)), expirationtime = 1, size = 4, - texture = "star.png", + texture = 'star.png', playername = player:get_player_name(), glow = 2, - velocity = vector.divide(dir, 5) - }) + velocity = vector.divide(dir, 5), + } end, on_punch = function(pos, node, puncher, pointed_thing) - if puncher and not puncher.is_fake_player and puncher:is_player() and not core.is_protected(pos, puncher:get_player_name()) then + if + puncher + and not puncher.is_fake_player + and puncher:is_player() + and not core.is_protected(pos, puncher:get_player_name()) + then local controls = puncher:get_player_control() if controls.sneak then local face = vector.subtract(pointed_thing.above, pointed_thing.under) local dir = core.dir_to_wallmounted(face) - core.get_meta(pos):set_int("dir", dir) + core.get_meta(pos):set_int('dir', dir) end end end, tube = { can_go = function(pos, node, velocity, stack) - local dir = core.wallmounted_to_dir(core.get_meta(pos):get_int("dir")) + local dir = core.wallmounted_to_dir(core.get_meta(pos):get_int 'dir') return { dir } end, --[[ @@ -96,71 +103,83 @@ pipeworks.register_tube("pipeworks:one_direction_tube", { return vector.equals(dir, direction) end, ]] - } + }, }, }) -minetest.register_craft({ - output = "pipeworks:one_direction_tube_1", - type = "shapeless", - recipe = { "pipeworks:one_way_tube", "pipeworks:tube_1" } -}) +minetest.register_craft { + output = 'pipeworks:one_direction_tube_1', + type = 'shapeless', + recipe = { 'pipeworks:one_way_tube', 'pipeworks:tube_1' }, +} -pipeworks.register_tube("pipeworks:high_priority_tube", { - description = "High Priority Tube", - plain = { { name = "basic_tube_plain.png", backface_culling = pipeworks.tube_backface_culling, color = "tomato" } }, - noctr = { { name = "basic_tube_noctr.png", backface_culling = pipeworks.tube_backface_culling, color = "tomato" } }, +pipeworks.register_tube('pipeworks:high_priority_tube', { + description = 'High Priority Tube', + plain = { { name = 'basic_tube_plain.png', backface_culling = pipeworks.tube_backface_culling, color = 'tomato' } }, + noctr = { { name = 'basic_tube_noctr.png', backface_culling = pipeworks.tube_backface_culling, color = 'tomato' } }, node_def = { tube = { priority = 150, - } - } + }, + }, }) -minetest.register_craft({ - output = "pipeworks:high_priority_tube_1 1", - type = "shapeless", - recipe = { "pipeworks:tube_1", "sbz_resources:matter_dust" } -}) +minetest.register_craft { + output = 'pipeworks:high_priority_tube_1 1', + type = 'shapeless', + recipe = { 'pipeworks:tube_1', 'sbz_resources:matter_dust' }, +} -pipeworks.register_tube("pipeworks:low_priority_tube", { - description = "Low Priority Tube", - plain = { { name = "basic_tube_plain.png", backface_culling = pipeworks.tube_backface_culling, color = "lightgreen" } }, - noctr = { { name = "basic_tube_noctr.png", backface_culling = pipeworks.tube_backface_culling, color = "lightgreen" } }, +pipeworks.register_tube('pipeworks:low_priority_tube', { + description = 'Low Priority Tube', + plain = { + { name = 'basic_tube_plain.png', backface_culling = pipeworks.tube_backface_culling, color = 'lightgreen' }, + }, + noctr = { + { name = 'basic_tube_noctr.png', backface_culling = pipeworks.tube_backface_culling, color = 'lightgreen' }, + }, node_def = { tube = { priority = 1, - } - } -}) - -minetest.register_craft({ - output = "pipeworks:low_priority_tube_1 1", - type = "shapeless", - recipe = { "pipeworks:tube_1", "sbz_resources:antimatter_dust" } + }, + }, }) +minetest.register_craft { + output = 'pipeworks:low_priority_tube_1 1', + type = 'shapeless', + recipe = { 'pipeworks:tube_1', 'sbz_resources:antimatter_dust' }, +} -minetest.register_node("pipeworks:one_way_tube", { - description = "One-Way Tube", +minetest.register_node('pipeworks:one_way_tube', { + description = 'One-Way Tube', tiles = { - { name = "one_way_tube_top.png", backface_culling = pipeworks.tube_backface_culling }, - { name = "one_way_tube_top.png", backface_culling = pipeworks.tube_backface_culling }, - { name = "basic_tube_plain.png", backface_culling = pipeworks.tube_backface_culling }, - { name = "basic_tube_plain.png", backface_culling = pipeworks.tube_backface_culling }, - { name = "one_way_tube_top.png^[transformFX", backface_culling = pipeworks.tube_backface_culling }, - { name = "one_way_tube_top.png", backface_culling = pipeworks.tube_backface_culling }, + { name = 'one_way_tube_top.png', backface_culling = pipeworks.tube_backface_culling }, + { name = 'one_way_tube_top.png', backface_culling = pipeworks.tube_backface_culling }, + { name = 'basic_tube_plain.png', backface_culling = pipeworks.tube_backface_culling }, + { name = 'basic_tube_plain.png', backface_culling = pipeworks.tube_backface_culling }, + { name = 'one_way_tube_top.png^[transformFX', backface_culling = pipeworks.tube_backface_culling }, + { name = 'one_way_tube_top.png', backface_culling = pipeworks.tube_backface_culling }, }, - use_texture_alpha = "clip", - paramtype2 = "facedir", - drawtype = "nodebox", - paramtype = "light", + use_texture_alpha = 'clip', + paramtype2 = 'facedir', + drawtype = 'nodebox', + paramtype = 'light', node_box = { - type = "fixed", - fixed = pipeworks.tube_long + type = 'fixed', + fixed = pipeworks.tube_long, + }, + groups = { + matter = 2, + snappy = 2, + choppy = 2, + oddly_breakable_by_hand = 2, + tubedevice = 1, + axey = 1, + handy = 1, + pickaxey = 1, }, - groups = { matter = 2, snappy = 2, choppy = 2, oddly_breakable_by_hand = 2, tubedevice = 1, axey = 1, handy = 1, pickaxey = 1 }, is_ground_content = false, tube = { connect_sides = { left = 1, right = 1 }, @@ -171,52 +190,60 @@ minetest.register_node("pipeworks:one_way_tube", { local dir = pipeworks.facedir_to_right_dir(node.param2) return vector.equals(dir, direction) end, - priority = 75 -- Higher than normal tubes, but lower than receivers + priority = 75, -- Higher than normal tubes, but lower than receivers }, after_place_node = pipeworks.after_place, after_dig_node = pipeworks.after_dig, on_rotate = pipeworks.on_rotate, }) -minetest.register_craft({ - output = "pipeworks:one_way_tube", +minetest.register_craft { + output = 'pipeworks:one_way_tube', recipe = { - { "", "sbz_resources:matter_dust", "" }, - { "", "pipeworks:tube_1", "" }, - { "", "sbz_resources:matter_dust", "" } - } -}) + { '', 'sbz_resources:matter_dust', '' }, + { '', 'pipeworks:tube_1', '' }, + { '', 'sbz_resources:matter_dust', '' }, + }, +} -pipeworks.register_tube("pipeworks:crossing_tube", { - description = "Crossing tube", - plain = { "crossing_tube_plain.png" }, - noctr = { "crossing_tube_noctr.png" }, +pipeworks.register_tube('pipeworks:crossing_tube', { + description = 'Crossing tube', + plain = { 'crossing_tube_plain.png' }, + noctr = { 'crossing_tube_noctr.png' }, node_def = { - tube = { can_go = function(pos, node, velocity, stack) return { velocity } end } + tube = { + can_go = function(pos, node, velocity, stack) + return { velocity } + end, + }, }, }) -minetest.register_craft({ - output = "pipeworks:crossing_tube_1 5", +minetest.register_craft { + output = 'pipeworks:crossing_tube_1 5', recipe = { - { "", "pipeworks:tube_1", "" }, - { "pipeworks:tube_1", "pipeworks:tube_1", "pipeworks:tube_1" }, - { "", "pipeworks:tube_1", "" } - } -}) + { '', 'pipeworks:tube_1', '' }, + { 'pipeworks:tube_1', 'pipeworks:tube_1', 'pipeworks:tube_1' }, + { '', 'pipeworks:tube_1', '' }, + }, +} -pipeworks.register_tube("pipeworks:broken_tube", { - description = "Broken Tube", - plain = { { name = "pipeworks_broken_tube_plain.png", backface_culling = pipeworks.tube_backface_culling, color = "red" } }, - noctr = { { name = "pipeworks_broken_tube_plain.png", backface_culling = pipeworks.tube_backface_culling, color = "red" } }, +pipeworks.register_tube('pipeworks:broken_tube', { + description = 'Broken Tube', + plain = { + { name = 'pipeworks_broken_tube_plain.png', backface_culling = pipeworks.tube_backface_culling, color = 'red' }, + }, + noctr = { + { name = 'pipeworks_broken_tube_plain.png', backface_culling = pipeworks.tube_backface_culling, color = 'red' }, + }, node_def = { - drop = "pipeworks:tube_1", + drop = 'pipeworks:tube_1', groups = { not_in_creative_inventory = 1, tubedevice_receiver = 1 }, is_ground_content = false, tube = { insert_object = function(pos, node, stack, direction) minetest.item_drop(stack, nil, pos) - return ItemStack("") + return ItemStack '' end, can_insert = function(pos, node, stack, direction) return true @@ -227,40 +254,38 @@ pipeworks.register_tube("pipeworks:broken_tube", { local itemstack = puncher:get_wielded_item() local wieldname = itemstack:get_name() local playername = puncher:get_player_name() - local log_msg = playername .. " struck a broken tube at " .. minetest.pos_to_string(pos) .. "\n " + local log_msg = playername .. ' struck a broken tube at ' .. minetest.pos_to_string(pos) .. '\n ' local meta = minetest.get_meta(pos) - local was_node = minetest.deserialize(meta:get_string("the_tube_was")) + local was_node = minetest.deserialize(meta:get_string 'the_tube_was') if not was_node then pipeworks.logger(log_msg .. "but it can't be repaired.") return end if not pipeworks.check_and_wear_hammer(puncher) then - if wieldname == "" then - minetest.chat_send_player(playername, - ("Broken tubes may be a bit sharp. Maybe try hitting it with a robotic arm?")) - if minetest.settings:get_bool("enable_damage") then - puncher:set_hp(puncher:get_hp() - 1) - end + if wieldname == '' then + minetest.chat_send_player( + playername, + 'Broken tubes may be a bit sharp. Maybe try hitting it with a robotic arm?' + ) + if minetest.settings:get_bool 'enable_damage' then puncher:set_hp(puncher:get_hp() - 1) end end return end - log_msg = log_msg .. "with " .. wieldname .. " to repair it" + log_msg = log_msg .. 'with ' .. wieldname .. ' to repair it' local nodedef = minetest.registered_nodes[was_node.name] if nodedef then - pipeworks.logger(log_msg .. ".") + pipeworks.logger(log_msg .. '.') if nodedef.tube and nodedef.tube.on_repair then nodedef.tube.on_repair(pos, was_node) else minetest.swap_node(pos, { name = was_node.name, param2 = was_node.param2 }) pipeworks.scan_for_tube_objects(pos) end - if meta:get_string("infotext") == "Broken Tube" then - meta:set_string("infotext", "") - end - meta:set_string("the_tube_was", "") + if meta:get_string 'infotext' == 'Broken Tube' then meta:set_string('infotext', '') end + meta:set_string('the_tube_was', '') else - pipeworks.logger(log_msg .. " but original node " .. was_node.name .. " is not registered anymore.") - minetest.chat_send_player(playername, ("This tube cannot be repaired.")) + pipeworks.logger(log_msg .. ' but original node ' .. was_node.name .. ' is not registered anymore.') + minetest.chat_send_player(playername, 'This tube cannot be repaired.') end end, allow_metadata_inventory_put = function() @@ -272,5 +297,5 @@ pipeworks.register_tube("pipeworks:broken_tube", { allow_metadata_inventory_take = function() return 0 end, - } + }, }) diff --git a/mods/sbz_pipeworks/item_transport.lua b/mods/sbz_pipeworks/item_transport.lua index f40a353a..ac62c1a5 100644 --- a/mods/sbz_pipeworks/item_transport.lua +++ b/mods/sbz_pipeworks/item_transport.lua @@ -1,32 +1,32 @@ local luaentity = pipeworks.luaentity -local enable_max_limit = minetest.settings:get_bool("pipeworks_enable_items_per_tube_limit") -local max_tube_limit = tonumber(minetest.settings:get("pipeworks_max_items_per_tube")) or 30 +local enable_max_limit = minetest.settings:get_bool 'pipeworks_enable_items_per_tube_limit' +local max_tube_limit = tonumber(minetest.settings:get 'pipeworks_max_items_per_tube') or 30 if enable_max_limit == nil then enable_max_limit = true end function pipeworks.tube_inject_item(pos, start_pos, velocity, item, owner) - -- Take item in any format - local stack = ItemStack(item) - local obj = luaentity.add_entity(pos, "pipeworks:tubed_item") - obj:set_item(stack:to_string()) - obj.start_pos = vector.copy(start_pos) - obj:set_velocity(velocity) - obj.owner = owner - obj.tags = {} - return obj + -- Take item in any format + local stack = ItemStack(item) + local obj = luaentity.add_entity(pos, 'pipeworks:tubed_item') + obj:set_item(stack:to_string()) + obj.start_pos = vector.copy(start_pos) + obj:set_velocity(velocity) + obj.owner = owner + obj.tags = {} + return obj end -function pipeworks.tube_inject_direct(pos, start_pos, to_pos, velocity, item, owner) -- function needed because monitoring pipeworks.tube_inject_item - local node = sbz_api.get_or_load_node(to_pos) - local stack = ItemStack(item) - if node and core.registered_nodes[node.name] then - local def = core.registered_nodes[node.name] - if def.tube and def.tube.insert_object then - local leftover = def.tube.insert_object(to_pos, node, stack, velocity, owner) - stack = leftover - if stack:is_empty() then return false end - end - end - return pipeworks.tube_inject_item(pos, start_pos, velocity, stack, owner) -- leftover +function pipeworks.tube_inject_direct(pos, start_pos, to_pos, velocity, item, owner) -- function needed because monitoring monitors pipeworks.tube_inject_item + local node = sbz_api.get_or_load_node(to_pos) + local stack = ItemStack(item) + if node and core.registered_nodes[node.name] then + local def = core.registered_nodes[node.name] + if def.tube and def.tube.insert_object then + local leftover = def.tube.insert_object(to_pos, node, stack, velocity, owner) + stack = leftover + if stack:is_empty() then return false end + end + end + return pipeworks.tube_inject_item(pos, start_pos, velocity, stack, owner) -- leftover end -- adding two tube functions @@ -34,156 +34,150 @@ end -- remove_items(pos,node,stack,dir,count) removes count items and returns them -- both optional w/ sensible defaults and fallback to normal allow_* function -local default_adjlist = { { x = 0, y = 0, z = 1 }, { x = 0, y = 0, z = -1 }, { x = 0, y = 1, z = 0 }, { x = 0, y = -1, z = 0 }, { x = 1, y = 0, z = 0 }, { x = -1, y = 0, z = 0 } } +local default_adjlist = { + { x = 0, y = 0, z = 1 }, + { x = 0, y = 0, z = -1 }, + { x = 0, y = 1, z = 0 }, + { x = 0, y = -1, z = 0 }, + { x = 1, y = 0, z = 0 }, + { x = -1, y = 0, z = 0 }, +} function pipeworks.notvel(tbl, vel) - local tbl2 = {} - for _, val in ipairs(tbl) do - if val.x ~= -vel.x or val.y ~= -vel.y or val.z ~= -vel.z then table.insert(tbl2, val) end - end - return tbl2 + local tbl2 = {} + for _, val in ipairs(tbl) do + if val.x ~= -vel.x or val.y ~= -vel.y or val.z ~= -vel.z then table.insert(tbl2, val) end + end + return tbl2 end local tube_item_count = {} minetest.register_globalstep(function(dtime) - if not luaentity.entities then - return - end - tube_item_count = {} - - -- start removing entities after there are too much - local too_many_entities = 1000 - - local count = 0 - for _, entity in pairs(luaentity.entities) do - if entity.name == "pipeworks:tubed_item" then - local h = minetest.hash_node_position(vector.round(entity._pos)) - if h ~= nil and not minetest.is_nan(h) then - count = count + 1 - tube_item_count[h] = (tube_item_count[h] or 0) + 1 - else - entity:remove() - end - end - end - if count > too_many_entities then - local to_remove = (count - too_many_entities) - local removed = 0 - for _, entity in pairs(luaentity.entities) do - if entity.name == "pipeworks:tubed_item" then - entity:remove() - end - removed = removed + 1 - if removed >= to_remove then - break - end - end - end + if not luaentity.entities then return end + tube_item_count = {} + + -- start removing entities after there are too much + local too_many_entities = 1000 + + local count = 0 + for _, entity in pairs(luaentity.entities) do + if entity.name == 'pipeworks:tubed_item' then + local h = minetest.hash_node_position(vector.round(entity._pos)) + if h ~= nil and not minetest.is_nan(h) then + count = count + 1 + tube_item_count[h] = (tube_item_count[h] or 0) + 1 + else + entity:remove() + end + end + end + if count > too_many_entities then + local to_remove = (count - too_many_entities) + local removed = 0 + for _, entity in pairs(luaentity.entities) do + if entity.name == 'pipeworks:tubed_item' then entity:remove() end + removed = removed + 1 + if removed >= to_remove then break end + end + end end) - - -- tube overload mechanism: -- when the tube's item count (tracked in the above tube_item_count table) -- exceeds the limit configured per tube, replace it with a broken one. function pipeworks.break_tube(pos) - local node = minetest.get_node(pos) - local meta = minetest.get_meta(pos) - meta:set_string("the_tube_was", minetest.serialize(node)) - minetest.swap_node(pos, { name = "pipeworks:broken_tube_1" }) - core.get_meta(pos):set_string("infotext", "Broken Tube") - pipeworks.scan_for_tube_objects(pos) + local node = minetest.get_node(pos) + local meta = minetest.get_meta(pos) + meta:set_string('the_tube_was', minetest.serialize(node)) + minetest.swap_node(pos, { name = 'pipeworks:broken_tube_1' }) + core.get_meta(pos):set_string('infotext', 'Broken Tube') + pipeworks.scan_for_tube_objects(pos) end local crunch_tube = function(pos, cnode, cmeta) - if enable_max_limit then - local h = minetest.hash_node_position(pos) - local itemcount = tube_item_count[h] or 0 - if itemcount > max_tube_limit then - pipeworks.logger("Warning - a tube at " .. - minetest.pos_to_string(pos) .. " broke due to too many items (" .. itemcount .. ")") - pipeworks.break_tube(pos) - end - end + if enable_max_limit then + local h = minetest.hash_node_position(pos) + local itemcount = tube_item_count[h] or 0 + if itemcount > max_tube_limit then + pipeworks.logger( + 'Warning - a tube at ' + .. minetest.pos_to_string(pos) + .. ' broke due to too many items (' + .. itemcount + .. ')' + ) + pipeworks.break_tube(pos) + end + end end - - local adjlist_cache = {} -- compatibility behaviour for the existing can_go() callbacks, -- which can only specify a list of possible positions. -- the fact that minetest.deserialize used to be in this function just not cached hurts my soul local function go_next_compat(pos, cnode, cmeta, cycledir, vel, stack, owner, tags) - local next_positions = {} - local max_priority = 0 - local can_go - - local def = minetest.registered_nodes[cnode.name] - if def and def.tube and def.tube.can_go then - can_go = def.tube.can_go(pos, cnode, vel, stack, tags) - else - local adjlist_string = minetest.get_meta(pos):get_string("adjlist") - local adjlist - if adjlist_string ~= "" then - adjlist = adjlist_cache[adjlist_string] - if not adjlist then - adjlist_cache[adjlist_string] = core.deserialize(adjlist_string) - adjlist = adjlist_cache[adjlist_string] - end - else - adjlist = default_adjlist - end - if not adjlist then - adjlist = default_adjlist - end - - can_go = pipeworks.notvel(adjlist, vel) - end - -- can_go() is expected to return an array-like table of candidate offsets. - -- for each one, look at the node at that offset and determine if it can accept the item. - -- also note the prioritisation: - -- if any tube is found with a greater priority than previously discovered, - -- then the valid positions are reset and and subsequent positions under this are skipped. - -- this has the effect of allowing only equal priorities to co-exist. - for _, vect in ipairs(can_go) do - local npos = vector.add(pos, vect) - pipeworks.load_position(npos) - local node = minetest.get_node(npos) - local reg_node = minetest.registered_nodes[node.name] - if reg_node then - local tube_def = reg_node.tube - local tubedevice = minetest.get_item_group(node.name, "tubedevice") - local tube_priority = (tube_def and tube_def.priority) or 100 - if tubedevice > 0 and tube_priority >= max_priority then - if not tube_def or not tube_def.can_insert or - tube_def.can_insert(npos, node, stack, vect, owner) then - if tube_priority > max_priority then - max_priority = tube_priority - next_positions = {} - end - next_positions[#next_positions + 1] = { pos = npos, vect = vect } - end - end - end - end - - -- indicate not found if no valid rules were picked up, - -- and don't change the counter. - if not next_positions[1] then - return cycledir, false, nil, nil - end - - -- otherwise rotate to the next output direction and return that - local n = (cycledir % (#next_positions)) + 1 - local new_velocity = vector.multiply(next_positions[n].vect, vel.speed) - return n, true, new_velocity, nil + local next_positions = {} + local max_priority = 0 + local can_go + + local def = minetest.registered_nodes[cnode.name] + if def and def.tube and def.tube.can_go then + can_go = def.tube.can_go(pos, cnode, vel, stack, tags) + else + local adjlist_string = minetest.get_meta(pos):get_string 'adjlist' + local adjlist + if adjlist_string ~= '' then + adjlist = adjlist_cache[adjlist_string] + if not adjlist then + adjlist_cache[adjlist_string] = core.deserialize(adjlist_string) + adjlist = adjlist_cache[adjlist_string] + end + else + adjlist = default_adjlist + end + if not adjlist then adjlist = default_adjlist end + + can_go = pipeworks.notvel(adjlist, vel) + end + -- can_go() is expected to return an array-like table of candidate offsets. + -- for each one, look at the node at that offset and determine if it can accept the item. + -- also note the prioritisation: + -- if any tube is found with a greater priority than previously discovered, + -- then the valid positions are reset and and subsequent positions under this are skipped. + -- this has the effect of allowing only equal priorities to co-exist. + for _, vect in ipairs(can_go) do + local npos = vector.add(pos, vect) + pipeworks.load_position(npos) + local node = minetest.get_node(npos) + local reg_node = minetest.registered_nodes[node.name] + if reg_node then + local tube_def = reg_node.tube + local tubedevice = minetest.get_item_group(node.name, 'tubedevice') + local tube_priority = (tube_def and tube_def.priority) or 100 + if tubedevice > 0 and tube_priority >= max_priority then + if not tube_def or not tube_def.can_insert or tube_def.can_insert(npos, node, stack, vect, owner) then + if tube_priority > max_priority then + max_priority = tube_priority + next_positions = {} + end + next_positions[#next_positions + 1] = { pos = npos, vect = vect } + end + end + end + end + + -- indicate not found if no valid rules were picked up, + -- and don't change the counter. + if not next_positions[1] then return cycledir, false, nil, nil end + + -- otherwise rotate to the next output direction and return that + local n = (cycledir % #next_positions) + 1 + local new_velocity = vector.multiply(next_positions[n].vect, vel.speed) + return n, true, new_velocity, nil end - - - -- function called by the on_step callback of the pipeworks tube luaentity. -- the routine is passed the current node position, velocity, itemstack, -- and owner name. @@ -194,64 +188,56 @@ end -- if this is not nil, the luaentity spawns new tubed items for each new fragment stack, -- then deletes itself (i.e. the original item stack). local function go_next(pos, velocity, stack, owner, tags) - local cnode = minetest.get_node(pos) - if cnode.name == "ignore" then - return false, velocity, nil - end - local cmeta = minetest.get_meta(pos) - local speed = math.abs(velocity.x + velocity.y + velocity.z) - if speed == 0 then - speed = 1 - end - local vel = { x = velocity.x / speed, y = velocity.y / speed, z = velocity.z / speed, speed = speed } - if speed >= 4.1 then - speed = 4 - elseif speed >= 1.1 then - speed = speed - 0.1 - else - speed = 1 - end - vel.speed = speed - - crunch_tube(pos, cnode, cmeta) - -- cycling of outputs: - -- an integer counter is kept in each pipe's metadata, - -- which allows tracking which output was previously chosen. - -- note reliance on get_int returning 0 for uninitialised. - local cycledir = cmeta:get_int("tubedir") - - -- pulled out and factored out into go_next_compat() above. - -- n is the new value of the cycle counter. - local n, found, new_velocity, multimode = go_next_compat(pos, cnode, cmeta, cycledir, vel, stack, owner, tags) - - -- if not using output cycling, - -- don't update the field so it stays the same for the next item. - if pipeworks.enable_cyclic_mode then - cmeta:set_int("tubedir", n) - end - return found, new_velocity, multimode + local cnode = minetest.get_node(pos) + if cnode.name == 'ignore' then return false, velocity, nil end + local cmeta = minetest.get_meta(pos) + local speed = math.abs(velocity.x + velocity.y + velocity.z) + if speed == 0 then speed = 1 end + local vel = { x = velocity.x / speed, y = velocity.y / speed, z = velocity.z / speed, speed = speed } + if speed >= 4.1 then + speed = 4 + elseif speed >= 1.1 then + speed = speed - 0.1 + else + speed = 1 + end + vel.speed = speed + + crunch_tube(pos, cnode, cmeta) + -- cycling of outputs: + -- an integer counter is kept in each pipe's metadata, + -- which allows tracking which output was previously chosen. + -- note reliance on get_int returning 0 for uninitialised. + local cycledir = cmeta:get_int 'tubedir' + + -- pulled out and factored out into go_next_compat() above. + -- n is the new value of the cycle counter. + local n, found, new_velocity, multimode = go_next_compat(pos, cnode, cmeta, cycledir, vel, stack, owner, tags) + + -- if not using output cycling, + -- don't update the field so it stays the same for the next item. + if pipeworks.enable_cyclic_mode then cmeta:set_int('tubedir', n) end + return found, new_velocity, multimode end - - -minetest.register_entity("pipeworks:tubed_item", { - initial_properties = { - hp_max = 1, - physical = false, - collisionbox = { 0.1, 0.1, 0.1, 0.1, 0.1, 0.1 }, - visual = "wielditem", - visual_size = { x = pipeworks.tube_size, y = pipeworks.tube_size }, - textures = { "" }, - spritediv = { x = 1, y = 1 }, - initial_sprite_basepos = { x = 0, y = 0 }, - is_visible = false, - }, - - physical_state = false, - - from_data = function(self, itemstring) - local stack = ItemStack(itemstring) - --[[ +minetest.register_entity('pipeworks:tubed_item', { + initial_properties = { + hp_max = 1, + physical = false, + collisionbox = { 0.1, 0.1, 0.1, 0.1, 0.1, 0.1 }, + visual = 'wielditem', + visual_size = { x = pipeworks.tube_size, y = pipeworks.tube_size }, + textures = { '' }, + spritediv = { x = 1, y = 1 }, + initial_sprite_basepos = { x = 0, y = 0 }, + is_visible = false, + }, + + physical_state = false, + + from_data = function(self, itemstring) + local stack = ItemStack(itemstring) + --[[ local itemtable = stack:to_table() local itemname = nil if itemtable then @@ -264,231 +250,218 @@ minetest.register_entity("pipeworks:tubed_item", { item_type = minetest.registered_items[itemname].type end --]] - self.object:set_properties({ - is_visible = true, - textures = { stack:get_name() } - }) - - local def = stack:get_definition() - self.object:set_yaw((def and def.type == "node") and 0 or math.pi * 0.25) - end, - - get_staticdata = luaentity.get_staticdata, - on_activate = function(self, staticdata) -- Legacy code, should be replaced later by luaentity.on_activate - if staticdata == "" or staticdata == nil then - return - end - if staticdata == "toremove" then - self.object:remove() - return - end - local item = minetest.deserialize(staticdata) - pipeworks.tube_inject_item(self.object:get_pos(), item.start_pos, item.velocity, item.itemstring) - self.object:remove() - end, + self.object:set_properties { + is_visible = true, + textures = { stack:get_name() }, + } + + local def = stack:get_definition() + self.object:set_yaw((def and def.type == 'node') and 0 or math.pi * 0.25) + end, + + get_staticdata = luaentity.get_staticdata, + on_activate = function(self, staticdata) -- Legacy code, should be replaced later by luaentity.on_activate + if staticdata == '' or staticdata == nil then return end + if staticdata == 'toremove' then + self.object:remove() + return + end + local item = minetest.deserialize(staticdata) + pipeworks.tube_inject_item(self.object:get_pos(), item.start_pos, item.velocity, item.itemstring) + self.object:remove() + end, }) -minetest.register_entity("pipeworks:color_entity", { - initial_properties = { - hp_max = 1, - physical = false, - collisionbox = { 0.1, 0.1, 0.1, 0.1, 0.1, 0.1 }, - visual = "cube", - visual_size = { x = 3.5, y = 3.5, z = 3.5 }, -- todo: find correct size - textures = { "" }, - is_visible = false, - }, - - physical_state = false, - - from_data = function(self, color) - local t = "pipeworks_color_" .. color .. ".png" - local prop = { - is_visible = true, - visual = "cube", - textures = { t, t, t, t, t, t } -- todo: textures - } - self.object:set_properties(prop) - end, - - get_staticdata = luaentity.get_staticdata, - on_activate = luaentity.on_activate, +minetest.register_entity('pipeworks:color_entity', { + initial_properties = { + hp_max = 1, + physical = false, + collisionbox = { 0.1, 0.1, 0.1, 0.1, 0.1, 0.1 }, + visual = 'cube', + visual_size = { x = 3.5, y = 3.5, z = 3.5 }, -- todo: find correct size + textures = { '' }, + is_visible = false, + }, + + physical_state = false, + + from_data = function(self, color) + local t = 'pipeworks_color_' .. color .. '.png' + local prop = { + is_visible = true, + visual = 'cube', + textures = { t, t, t, t, t, t }, -- todo: textures + } + self.object:set_properties(prop) + end, + + get_staticdata = luaentity.get_staticdata, + on_activate = luaentity.on_activate, }) -- see below for usage: -- determine if go_next returned a multi-mode set. local is_multimode = function(v) - return (type(v) == "table") and (v.__multimode) + return (type(v) == 'table') and v.__multimode end -luaentity.register_entity("pipeworks:tubed_item", { - itemstring = '', - item_entity = nil, - color_entity = nil, - color = nil, - start_pos = nil, - tags = nil, - - set_item = function(self, item) - local itemstring = ItemStack(item):to_string() -- Accept any input format - if self.itemstring == itemstring then - return - end - if self.item_entity then - self:remove_attached_entity(self.item_entity) - end - self.itemstring = itemstring - self.item_entity = self:add_attached_entity("pipeworks:tubed_item", itemstring) - end, - - set_color = function(self, color) - if self.color == color then - return - end - self.color = color - if self.color_entity then - self:remove_attached_entity(self.color_entity) - end - if color then - self.color_entity = self:add_attached_entity("pipeworks:color_entity", color) - else - self.color_entity = nil - end - end, - - on_step = function(self, dtime) - local pos = self:get_pos() - if self.start_pos == nil then - self.start_pos = vector.round(pos) - self:set_pos(pos) - end - - local velocity = self:get_velocity() - - local moved = false - local speed = math.abs(velocity.x + velocity.y + velocity.z) - if speed == 0 then - speed = 1 - moved = true - end - local vel = { x = velocity.x / speed, y = velocity.y / speed, z = velocity.z / speed, speed = speed } - local moved_by = vector.distance(pos, self.start_pos) - - if moved_by >= 1 then - self.start_pos = vector.add(self.start_pos, vel) - moved = true - end - - if not moved then - return - end - - local stack = ItemStack(self.itemstring) - - pipeworks.load_position(self.start_pos) - local node = minetest.get_node(self.start_pos) - if minetest.get_item_group(node.name, "tubedevice_receiver") == 1 then - local oldstack = stack - local leftover - local def = minetest.registered_nodes[node.name] - if def.tube and def.tube.insert_object then - leftover = def.tube.insert_object(self.start_pos, node, stack, vel, self.owner) - else - leftover = stack - end - if leftover:is_empty() then - self:remove() - return - end - velocity = vector.multiply(velocity, -1) - -- this is to prevent massive amounts of tubed entities with wielders, added in sbz - local to_return = vector.add(self.start_pos, velocity) - local to_return_node = core.get_node(to_return) - local to_return_def = core.registered_nodes[to_return_node.name] - if to_return_def.tube and to_return_def.tube.can_insert and oldstack:equals(leftover) then - local can_insert = to_return_def.tube.can_insert(to_return, to_return_node, stack, velocity, self.owner) - if not can_insert then -- drop itself - local dropped_item = minetest.add_item(self.start_pos, stack) - if dropped_item then - dropped_item:set_velocity(vector.multiply(velocity, 2)) - self:remove() - end - return - end - end - - self:set_pos(vector.subtract(self.start_pos, vector.multiply(vel, moved_by - 1))) - self:set_velocity(velocity) - self:set_item(leftover:to_string()) - return - end - - local tags - if pipeworks.enable_item_tags then - tags = self.tags or {} - end - local found_next, new_velocity, multimode = go_next(self.start_pos, velocity, stack, self.owner, tags) -- todo: color - if pipeworks.enable_item_tags then - self.tags = #tags > 0 and tags or nil - end - local rev_vel = vector.multiply(velocity, -1) - local rev_dir = vector.direction(self.start_pos, vector.add(self.start_pos, rev_vel)) - local rev_node = minetest.get_node(vector.round(vector.add(self.start_pos, rev_dir))) - local tube_present = minetest.get_item_group(rev_node.name, "tubedevice") == 1 - if not found_next then - if pipeworks.drop_on_routing_fail or not tube_present or - minetest.get_item_group(rev_node.name, "tube") ~= 1 then - -- Using add_item instead of item_drop since this makes pipeworks backward - -- compatible with Minetest 0.4.13. - -- Using item_drop here makes Minetest 0.4.13 crash. - local dropped_item = minetest.add_item(self.start_pos, stack) - if dropped_item then - dropped_item:set_velocity(vector.multiply(velocity, 5)) - self:remove() - end - return - else - velocity = vector.multiply(velocity, -1) - self:set_pos(vector.subtract(self.start_pos, vector.multiply(vel, moved_by - 1))) - self:set_velocity(velocity) - end - elseif is_multimode(multimode) then - -- create new stacks according to returned data. - local s = self.start_pos - for _, split in ipairs(multimode) do - pipeworks.tube_inject_item(s, s, split.velocity, split.itemstack, self.owner) - end - -- remove ourself now the splits are sent - self:remove() - return - end - - if new_velocity and not vector.equals(velocity, new_velocity) then - local nvelr = math.abs(new_velocity.x + new_velocity.y + new_velocity.z) - self:set_pos(vector.add(self.start_pos, vector.multiply(new_velocity, (moved_by - 1) / nvelr))) - self:set_velocity(new_velocity) - end - end +luaentity.register_entity('pipeworks:tubed_item', { + itemstring = '', + item_entity = nil, + color_entity = nil, + color = nil, + start_pos = nil, + tags = nil, + + set_item = function(self, item) + local itemstring = ItemStack(item):to_string() -- Accept any input format + if self.itemstring == itemstring then return end + if self.item_entity then self:remove_attached_entity(self.item_entity) end + self.itemstring = itemstring + self.item_entity = self:add_attached_entity('pipeworks:tubed_item', itemstring) + end, + + set_color = function(self, color) + if self.color == color then return end + self.color = color + if self.color_entity then self:remove_attached_entity(self.color_entity) end + if color then + self.color_entity = self:add_attached_entity('pipeworks:color_entity', color) + else + self.color_entity = nil + end + end, + + on_step = function(self, dtime) + local pos = self:get_pos() + if self.start_pos == nil then + self.start_pos = vector.round(pos) + self:set_pos(pos) + end + + local velocity = self:get_velocity() + + local moved = false + local speed = math.abs(velocity.x + velocity.y + velocity.z) + if speed == 0 then + speed = 1 + moved = true + end + local vel = { x = velocity.x / speed, y = velocity.y / speed, z = velocity.z / speed, speed = speed } + local moved_by = vector.distance(pos, self.start_pos) + + if moved_by >= 1 then + self.start_pos = vector.add(self.start_pos, vel) + moved = true + end + + if not moved then return end + + local stack = ItemStack(self.itemstring) + + pipeworks.load_position(self.start_pos) + local node = minetest.get_node(self.start_pos) + if minetest.get_item_group(node.name, 'tubedevice_receiver') == 1 then + local oldstack = stack + local leftover + local def = minetest.registered_nodes[node.name] + if def.tube and def.tube.insert_object then + leftover = def.tube.insert_object(self.start_pos, node, stack, vel, self.owner) + else + leftover = stack + end + if leftover:is_empty() then + self:remove() + return + end + velocity = vector.multiply(velocity, -1) + -- this is to prevent massive amounts of tubed entities with wielders, added in sbz + local to_return = vector.add(self.start_pos, velocity) + local to_return_node = core.get_node(to_return) + local to_return_def = core.registered_nodes[to_return_node.name] + if to_return_def.tube and to_return_def.tube.can_insert and oldstack:equals(leftover) then + local can_insert = to_return_def.tube.can_insert(to_return, to_return_node, stack, velocity, self.owner) + if not can_insert then -- drop itself + local dropped_item = minetest.add_item(self.start_pos, stack) + if dropped_item then + dropped_item:set_velocity(vector.multiply(velocity, 2)) + self:remove() + end + return + end + end + + self:set_pos(vector.subtract(self.start_pos, vector.multiply(vel, moved_by - 1))) + self:set_velocity(velocity) + self:set_item(leftover:to_string()) + return + end + + local tags + if pipeworks.enable_item_tags then tags = self.tags or {} end + local found_next, new_velocity, multimode = go_next(self.start_pos, velocity, stack, self.owner, tags) -- todo: color + if pipeworks.enable_item_tags then self.tags = #tags > 0 and tags or nil end + local rev_vel = vector.multiply(velocity, -1) + local rev_dir = vector.direction(self.start_pos, vector.add(self.start_pos, rev_vel)) + local rev_node = minetest.get_node(vector.round(vector.add(self.start_pos, rev_dir))) + local tube_present = minetest.get_item_group(rev_node.name, 'tubedevice') == 1 + if not found_next then + if + pipeworks.drop_on_routing_fail + or not tube_present + or minetest.get_item_group(rev_node.name, 'tube') ~= 1 + then + -- Using add_item instead of item_drop since this makes pipeworks backward + -- compatible with Minetest 0.4.13. + -- Using item_drop here makes Minetest 0.4.13 crash. + local dropped_item = minetest.add_item(self.start_pos, stack) + if dropped_item then + dropped_item:set_velocity(vector.multiply(velocity, 5)) + self:remove() + end + return + else + velocity = vector.multiply(velocity, -1) + self:set_pos(vector.subtract(self.start_pos, vector.multiply(vel, moved_by - 1))) + self:set_velocity(velocity) + end + elseif is_multimode(multimode) then + -- create new stacks according to returned data. + local s = self.start_pos + for _, split in ipairs(multimode) do + pipeworks.tube_inject_item(s, s, split.velocity, split.itemstack, self.owner) + end + -- remove ourself now the splits are sent + self:remove() + return + end + + if new_velocity and not vector.equals(velocity, new_velocity) then + local nvelr = math.abs(new_velocity.x + new_velocity.y + new_velocity.z) + self:set_pos(vector.add(self.start_pos, vector.multiply(new_velocity, (moved_by - 1) / nvelr))) + self:set_velocity(new_velocity) + end + end, }) -if minetest.get_modpath("mesecons_mvps") then - mesecon.register_mvps_unmov("pipeworks:tubed_item") - mesecon.register_mvps_unmov("pipeworks:color_entity") - mesecon.register_on_mvps_move(function(moved_nodes) - local moved = {} - for _, n in ipairs(moved_nodes) do - moved[minetest.hash_node_position(n.oldpos)] = vector.subtract(n.pos, n.oldpos) - end - for _, entity in pairs(luaentity.entities) do - if entity.name == "pipeworks:tubed_item" then - local pos = entity:get_pos() - local rpos = vector.round(pos) - local dir = moved[minetest.hash_node_position(rpos)] - if dir then - entity:set_pos(vector.add(pos, dir)) - entity.start_pos = vector.add(entity.start_pos, dir) - end - end - end - end) +if minetest.get_modpath 'mesecons_mvps' then + mesecon.register_mvps_unmov 'pipeworks:tubed_item' + mesecon.register_mvps_unmov 'pipeworks:color_entity' + mesecon.register_on_mvps_move(function(moved_nodes) + local moved = {} + for _, n in ipairs(moved_nodes) do + moved[minetest.hash_node_position(n.oldpos)] = vector.subtract(n.pos, n.oldpos) + end + for _, entity in pairs(luaentity.entities) do + if entity.name == 'pipeworks:tubed_item' then + local pos = entity:get_pos() + local rpos = vector.round(pos) + local dir = moved[minetest.hash_node_position(rpos)] + if dir then + entity:set_pos(vector.add(pos, dir)) + entity.start_pos = vector.add(entity.start_pos, dir) + end + end + end + end) end diff --git a/mods/sbz_progression/quests/Chemistry.md b/mods/sbz_progression/quests/Chemistry.md index 00283403..a6f1a8a3 100644 --- a/mods/sbz_progression/quests/Chemistry.md +++ b/mods/sbz_progression/quests/Chemistry.md @@ -53,28 +53,31 @@ Congratulations, Commander! You've just unlocked the Bronze Age, because nothing Requires: Simple Alloy Furnace, Crusher -## Compressor +## Centrifuge ### Text -Have you ever wanted to turn your metals into blocks? Now you can! -Craft this wonderful compressor, insert 9 powder, or 9 ingots, and watch as it makes blocks out of them. - -Blocks made from metals cannot be dug with matter annihilators, you must use the robotic arm or the drill instead. +In the centrifuge you can get: +- sand -> silicon, gold, white sand +- gravel -> titanium, lithium, cobalt, pebbles +- white sand/dark sand -> silver, darker variation of said sand ### Meta -Requires: Crusher, Simple Alloy Furnace +Requires: Crusher, Simple Alloy Furnace -## Centrifuge +## Compressor ### Text -In the centrifuge you can get gold, silicon and white sand from normal sand, silver from some sand shades, and rare metals (titanium, lithium and cobalt) from gravel. +Have you ever wanted to turn your metals into blocks? Now you can! +Craft this wonderful compressor, insert 9 powder, or 9 ingots, and watch as it makes blocks out of them. +Blocks made from metals cannot be dug with matter annihilators, you must use the robotic arm or the drill instead. ### Meta -Requires: Crusher, Simple Alloy Furnace +Requires: Crusher, Simple Alloy Furnace + ## Advanced Batteries @@ -90,7 +93,7 @@ Requires: Batteries, Furnace, Centrifuge ### Text -If you have lots of metals this is the battery for you! +If you have **lots of metals** this is the battery for you! If you don't, then those metals can be put into better uses. ### Meta @@ -165,7 +168,6 @@ Requires: Furnace ### Text The elecric drill has 500 uses and is powered by electricity. -What does that mean? If you "place" it on a battery (sneak+right click), it will take power from the battery and charge the drill! (Just like the jetpack) It needs 1 power per 1 use. @@ -358,10 +360,11 @@ Requires: Crusher Small protectors protect a decently sized area. Unwanted people won't be able to take items from machines or modify filter injectors or... like... do anything in your land... if the area is protected. Also this can't be placed anywhere near cores. -Special names ("owners") that you can add to protectors (no player can name themselvs these): +Special names ("owners") that you can add to protectors (no player can name themselves these): **.meteorite** - meteorites will now explode in your area **.strange_blob_spread** - strange blobs will spread in your area + ### Meta Requires: Concrete Plan, Furnace diff --git a/mods/sbz_resources/jetpack.lua b/mods/sbz_resources/jetpack.lua index b7ff31e8..329e87b9 100644 --- a/mods/sbz_resources/jetpack.lua +++ b/mods/sbz_resources/jetpack.lua @@ -1,45 +1,43 @@ -- this doesn't use any code from techage -local jetpack_durability_s = 60 * 5 -- jetpack durability, in seconds +local jetpack_durability_s = 60 * 5 -- jetpack durability, in seconds local jetpack_velocity = vector.new(0, 15, 0) -- multiplied by dtime -local jetpack_full_charge = 20000 -- 20kcj power needed for a jetpack +local jetpack_full_charge = 20000 -- 20kcj power needed for a jetpack local jetpack_durability_save_during_sneak_flight = 2 local default_number_of_particles = 20 local jetpack_boost = 3 local jetpack_users = {} +sbz_api.jetpack_users = jetpack_users local jetpack_charge_per_1_wear = (jetpack_full_charge / 65535) - local function edit_stack_image(user, stack) - if stack:get_name() == "sbz_resources:jetpack" then + if stack:get_name() == 'sbz_resources:jetpack' then if jetpack_users[user] then - stack:get_meta():set_string("inventory_image", "jetpack_on.png") + stack:get_meta():set_string('inventory_image', 'jetpack_on.png') else - stack:get_meta():set_string("inventory_image", "jetpack_off.png") + stack:get_meta():set_string('inventory_image', 'jetpack_off.png') end end end -minetest.register_tool("sbz_resources:jetpack", { - description = "Jetpack", - info_extra = "Idea originated from techage", - inventory_image = "jetpack_off.png", +minetest.register_tool('sbz_resources:jetpack', { + description = 'Jetpack', + info_extra = 'Idea originated from techage', + inventory_image = 'jetpack_off.png', stack_max = 1, tool_capabilities = {}, -- No specific tool capabilities, as it's not meant for digging wear_color = { - blend = "constant", + blend = 'constant', color_stops = { - [0] = "lime" - } + [0] = 'lime', + }, }, groups = { disable_repair = 1, power_tool = 1 }, - wear_represents = "power", + wear_represents = 'power', on_use = function(itemstack, user, pointed_thing) -- Check if user is valid - if not user or user.is_fake_player then - return itemstack - end + if not user or user.is_fake_player then return itemstack end local wear = itemstack:get_wear() local username = user:get_player_name() if wear < 65535 then @@ -49,7 +47,7 @@ minetest.register_tool("sbz_resources:jetpack", { jetpack_users[username] = user:get_wield_index() end else - minetest.chat_send_player(user:get_player_name(), "Jetpack ran out of charge") + minetest.chat_send_player(user:get_player_name(), 'Jetpack ran out of charge') end edit_stack_image(username, itemstack) return itemstack @@ -59,84 +57,80 @@ minetest.register_tool("sbz_resources:jetpack", { end), }) - - local speed = player_monoids.speed minetest.register_globalstep(function(dtime) for player in pairs(jetpack_users) do local real_player = minetest.get_player_by_name(player) if real_player and real_player:is_valid() then local slot = jetpack_users[player] - local jetpack_item = real_player:get_inventory():get_stack("main", slot) - if jetpack_item:get_name() ~= "sbz_resources:jetpack" then - jetpack_users[player] = nil - end - if jetpack_item:get_wear() >= 65535 then - jetpack_users[player] = nil - end + local jetpack_item = real_player:get_inventory():get_stack('main', slot) + if jetpack_item:get_name() ~= 'sbz_resources:jetpack' then jetpack_users[player] = nil end + if jetpack_item:get_wear() >= 65535 then jetpack_users[player] = nil end local controls = real_player:get_player_control() local num_particles = 0 if (controls.sneak or controls.aux1) and controls.jump and jetpack_users[player] then - speed:add_change(real_player, jetpack_boost, "sbz_resources:jetpack_boost") + speed:add_change(real_player, jetpack_boost, 'sbz_resources:jetpack_boost') real_player:add_velocity((jetpack_velocity / 2) * dtime) - jetpack_item:set_wear(math.min(65535, - jetpack_item:get_wear() + - 65535 * - ((jetpack_durability_s * (1 / jetpack_durability_save_during_sneak_flight)) ^ -1) - * dtime)) -- this works, do not question it + jetpack_item:set_wear( + math.min( + 65535, + jetpack_item:get_wear() + + 65535 + * ((jetpack_durability_s * (1 / jetpack_durability_save_during_sneak_flight)) ^ -1) + * dtime + ) + ) -- this works, do not question it num_particles = default_number_of_particles / 5 elseif controls.jump and jetpack_users[player] then - speed:add_change(real_player, jetpack_boost, "sbz_resources:jetpack_boost") + speed:add_change(real_player, jetpack_boost, 'sbz_resources:jetpack_boost') real_player:add_velocity(jetpack_velocity * dtime) - jetpack_item:set_wear(math.min(65535, - jetpack_item:get_wear() + ((65535 * (jetpack_durability_s ^ -1))) * dtime)) -- this works, do not question it + jetpack_item:set_wear( + math.min(65535, jetpack_item:get_wear() + (65535 * (jetpack_durability_s ^ -1)) * dtime) + ) -- this works, do not question it num_particles = default_number_of_particles else - speed:del_change(real_player, "sbz_resources:jetpack_boost") + speed:del_change(real_player, 'sbz_resources:jetpack_boost') end edit_stack_image(player, jetpack_item) - real_player:get_inventory():set_stack("main", slot, jetpack_item) + real_player:get_inventory():set_stack('main', slot, jetpack_item) if num_particles ~= 0 then -- make a effect local vel = real_player:get_velocity() vel = vector.subtract(vector.zero(), vel) - minetest.add_particlespawner({ + minetest.add_particlespawner { amount = num_particles, time = dtime, - texture = "star.png", + texture = 'star.png', texpool = { - "star.png^[colorize:red", - "star.png^[colorize:blue", - "star.png^[colorize:green", + 'star.png^[colorize:red', + 'star.png^[colorize:blue', + 'star.png^[colorize:green', }, exptime = { min = 1, max = 2 }, vel = { min = vector.new(-2, -2, -2), max = vector.new(2, 2, 2) }, acc = { min = vel, max = vel * 5 }, radius = { min = 0.1, max = 0.3, bias = 1 }, glow = 14, - pos = real_player:get_pos() - }) + pos = real_player:get_pos(), + } end else jetpack_users[player] = nil end end for k, v in ipairs(minetest.get_connected_players()) do - if not jetpack_users[v:get_player_name()] then - speed:del_change(v, "sbz_resources:jetpack_boost") - end + if not jetpack_users[v:get_player_name()] then speed:del_change(v, 'sbz_resources:jetpack_boost') end end end) - minetest.register_craft { - output = "sbz_resources:jetpack", + output = 'sbz_resources:jetpack', recipe = { - { "sbz_resources:emittrium_circuit", "sbz_power:battery", "sbz_resources:emittrium_circuit" }, - { "sbz_resources:angels_wing", "sbz_meteorites:neutronium", "sbz_resources:angels_wing" }, - { "sbz_resources:emittrium_circuit", "", "sbz_resources:emittrium_circuit" } - } + { 'sbz_resources:emittrium_circuit', 'sbz_power:battery', 'sbz_resources:emittrium_circuit' }, + { 'sbz_resources:angels_wing', 'sbz_meteorites:neutronium', 'sbz_resources:angels_wing' }, + { 'sbz_resources:emittrium_circuit', '', 'sbz_resources:emittrium_circuit' }, + }, } diff --git a/mods/stubes/README.md b/mods/stubes/README.md new file mode 100644 index 00000000..4029514e --- /dev/null +++ b/mods/stubes/README.md @@ -0,0 +1,26 @@ +# Stubes + +Attempting to be luanti's best tubes. +Though, they are in a weird stage of still being dependant on pipeworks. + +I am using 32x32 textures for the tubes, because i could not fit a recognizable arrow into a 32x32 texture without making the node bigger. + +A lot of the aproaches were from pipeworks. + +# Docs +## Groups +- `stube=1` - if it's an stube +- `stube_input=1` - if it can input into an stube +- `tubedevice`/`tubedevice_receiver` - these are groups from pipeworks +## Functions +### Registration +- `stube.register_tube(name, def)` + - It's the same as `core.register_node`, but there are a few special fields you need to put: + - `tube_textures` - a table of `{ plain = , noctr = , ends = , plain_up = , noctr_up = }` + - You can use `stube.make_tube_textures_from(filename)` to generate this, it needs to be a 3x2 texture sheet, check `textures/` directory for examples +### Placement +- `stube.place_tube(pos, dir)` - places a tube properly +- `stube.update_placement(pos)` - Use with `after_dig`/`after_place`, it updates the tube connections, useful if something got removed/placed + - Does not get rid of connections that were manually removed/made by a user +### Weird internals +- `stube.parse_tube_name(tube_name)` - Parses the `:_` into `{ dir (0 to 5), xc, yc, zc, nxc, nyc, nzc }` where, for example `xc` means if it's connected to the west, and `nxc` means if it's connected to the east (-X direction), and for the dir, see wallmounted param2 diff --git a/mods/stubes/basic_tubes.lua b/mods/stubes/basic_tubes.lua new file mode 100644 index 00000000..e69de29b diff --git a/mods/stubes/entity.lua b/mods/stubes/entity.lua new file mode 100644 index 00000000..e69de29b diff --git a/mods/stubes/init.lua b/mods/stubes/init.lua new file mode 100644 index 00000000..b83709c2 --- /dev/null +++ b/mods/stubes/init.lua @@ -0,0 +1,20 @@ +local mp = core.get_modpath(core.get_current_modname()) + +---@diagnostic disable-next-line: lowercase-global +---@class stube +stube = { + debug = true, -- pollutes the creative inventory + + get_or_load_node = function(pos) + local get_or_load_node_node = core.get_node_or_nil(pos) + if get_or_load_node_node then return get_or_load_node_node end + core.load_area(pos) + return core.get_node(pos) + end, +} + +dofile(mp .. '/place.lua') +dofile(mp .. '/register.lua') +dofile(mp .. '/transport.lua') +dofile(mp .. '/entity.lua') +dofile(mp .. '/basic_tubes.lua') diff --git a/mods/stubes/mod.conf b/mods/stubes/mod.conf new file mode 100644 index 00000000..0db7cdcc --- /dev/null +++ b/mods/stubes/mod.conf @@ -0,0 +1,2 @@ +name = stubes +depends = pipeworks diff --git a/mods/stubes/place.lua b/mods/stubes/place.lua new file mode 100644 index 00000000..403ac325 --- /dev/null +++ b/mods/stubes/place.lua @@ -0,0 +1,288 @@ +local function has_no_connections(connections) + for i = 1, 6 do + if connections[i] == 1 then return false end + end + return true +end + +-- the order in which i chose the connections was kinda stupid, because it isn't the wallmounted direction +-- so i have to do this sort of thing instead of just doing connections[dir]=1 +stube.wallmounted_to_connections_index = { + [0] = 2, + [1] = 5, + [2] = 1, + [3] = 4, + [4] = 3, + [5] = 6, +} + +local connections_to_wallmounted = table.key_value_swap(table.copy(stube.wallmounted_to_connections_index)) + +local function make_connection(connections, wallmounted_dir, remove_connection) + local set_to = 1 + if remove_connection then set_to = 0 end + connections[stube.wallmounted_to_connections_index[wallmounted_dir]] = set_to +end + +function stube.connect_tubes_to(pos, dir, pointed_thing, sneaking) + pos = vector.copy(pos) -- guaranteed to be a vector + + -- Connect to our tube if it is pointing to it + for idir = 0, 5 do + local neighbor_dir_from_origin = core.wallmounted_to_dir(idir) + local neighbor_pos = pos + neighbor_dir_from_origin + local neighbor_node = stube.get_or_load_node(neighbor_pos) + + if core.get_item_group(neighbor_node.name, 'stube') == 1 then + local split = stube.split_tube_name(neighbor_node.name) + local pointing_to = (core.wallmounted_to_dir(split.dir) + neighbor_pos) + + if pointing_to == pos or has_no_connections(split.connections) then + local connection_dir = core.dir_to_wallmounted(pos - neighbor_pos) + + if has_no_connections(split.connections) then split.dir = connection_dir end + make_connection(split.connections, connection_dir) + + core.set_node(neighbor_pos, { name = stube.join_tube_name(split) }) + end + end + end + + -- Switch the direction of the position under + -- Makes making turns actually possible + if pointed_thing then + local node = stube.get_or_load_node(pointed_thing.under) + + if core.get_item_group(node.name, 'stube') == 1 then + local split = stube.split_tube_name(node.name) + split.dir = dir + make_connection(split.connections, dir) + core.set_node(pointed_thing.under, { name = stube.join_tube_name(split) }) + end + end + + -- make the tube that is in front of us, point to us + -- This makes connecting tubes with multiple inputs possible, after they have already been placed + if dir and not sneaking then + local vdir = core.wallmounted_to_dir(dir) + local front_pos = pos + vdir + local front_node = stube.get_or_load_node(front_pos) + + if core.get_item_group(front_node.name, 'stube') == 1 then + local split = stube.split_tube_name(front_node.name) + + make_connection(split.connections, split.dir) + make_connection(split.connections, core.dir_to_wallmounted(pos - front_pos)) + core.set_node(front_pos, { name = stube.join_tube_name(split) }) + end + end +end + +function stube.place_tube(name, pos, tube_dir, under_pos, sneaking) + stube.connect_tubes_to(pos, tube_dir, under_pos, sneaking) + + local connections = { + -- X, Y, Z + 0, + 0, + 0, + -- -X, -Y, -Z + 0, + 0, + 0, + } + + -- Need to connect to the proper places, so, it needs input from: + -- - Tubes pointing to pos + -- - Pipeworks tubes + -- - Actually, any machine has the power to input, so anything that has the `stube_input=1` group + -- - Filter injecetors are in this group + -- FIXME: Pipeworks tubes and add that group to filter injectors + + for neighbor_dir_number = 0, 5 do + local neighbor_dir = core.wallmounted_to_dir(neighbor_dir_number) + local neighbor_pos = vector.add(pos, neighbor_dir) + local neighbor_node = stube.get_or_load_node(neighbor_pos) + + if core.get_item_group(neighbor_node.name, 'stube') == 1 then + local tube_params = stube.get_tube_name_info(neighbor_node.name) + if vector.equals(vector.add(core.wallmounted_to_dir(tube_params[1]), neighbor_pos), pos) then -- If the tube is pointing to ours + make_connection(connections, neighbor_dir_number) + end + elseif core.get_item_group(neighbor_node.name, 'stube_input') == 1 then + make_connection(connections, neighbor_dir_number) + end + end + + local no_connections = true + local amount_of_connections = 0 + for i = 1, 6 do + if connections[i] == 1 then + no_connections = false + amount_of_connections = amount_of_connections + 1 + end + end + + -- the square tube + if no_connections then tube_dir = 0 end + + -- if a tube is not straight, make a connection + -- Basically, makes short tubes whenever possible + -- Also maintain a connection to tubedevices, that sounds important + + local tube_pointing_to = vector.add(pos, core.wallmounted_to_dir(tube_dir)) + local tube_pointing_to_node = stube.get_or_load_node(tube_pointing_to) + + local straight_tube_index = (stube.wallmounted_to_connections_index[tube_dir] + 3) % 6 + if straight_tube_index == 0 then straight_tube_index = 6 end + if + not ( + ((amount_of_connections == 1 and connections[straight_tube_index] == 1) or amount_of_connections == 0) -- if the tube is straight or a box + and core.get_item_group(tube_pointing_to_node.name, 'tubedevice_receiver') == 0 + ) + then + make_connection(connections, tube_dir) + end + + -- if there is a tube in the front of us, point to it + -- This makes connecting tubes with multiple inputs possible, after they have already been placed + if not sneaking then + local vdir = core.wallmounted_to_dir(tube_dir) + local front_pos = pos + vdir + local front_node = stube.get_or_load_node(front_pos) + if core.get_item_group(front_node.name, 'stube') == 1 then make_connection(connections, tube_dir) end + end + + core.set_node(pos, { name = stube.get_prefix_tube_name(name) .. '_' .. tube_dir .. table.concat(connections) }) +end + +-- When an stube is broken, or something near it was, this should get called +-- It cleans up garbage connections (e.g. connection to nowhere, that isn't needed) +function stube.update_placement(pos) + -- All the cases of garbage connections: + -- - When a connection is pointing to air/incompatible node + -- - When a connection is pointing to a tube, which is not connected to it -> weird visual + -- - When a tube could be a short tube instead + + -- So, this function will iterate over the neighboring tubes of this position + pos = vector.copy(pos) -- ensure pos is a vector + stube.update_placement_single(pos) + for i = 0, 5 do + stube.update_placement_single(pos + core.wallmounted_to_dir(i)) + end +end + +---@see stube.update +function stube.update_placement_single(pos) + local node = stube.get_or_load_node(pos) + if core.get_item_group(node.name, 'stube') ~= 1 then return end + + local split = stube.split_tube_name(node.name) + + for i = 1, 6 do + local connection = split.connections[i] + local connection_dir = connections_to_wallmounted[i] + local connection_dirv = core.wallmounted_to_dir(connection_dir) + local connection_pos = pos + connection_dirv + + local connection_node = stube.get_or_load_node(connection_pos) + + local ig = core.get_item_group + + if connection == 1 then + -- first case: pointing to air/incompatible node + if + not ( + ig(connection_node.name, 'stube') == 1 + or ig(connection_node.name, 'stube_input') == 1 + or ig(connection_node.name, 'tubedevice') == 1 + or ig(connection_node.name, 'tubedevice_receiver') == 1 + ) + then + split.connections[i] = 0 + end + + -- second case: connection is pointing to a tube that is not connected to it (=> a weird/out of place connection) + if ig(connection_node.name, 'stube') == 1 then + local other_tube_split = stube.split_tube_name(connection_node.name) + + local other_connection_index = (i + 3) % 6 + if other_connection_index == 0 then other_connection_index = 6 end + if other_tube_split.connections[other_connection_index] == 0 then split.connections[i] = 0 end + + -- another case: The tube wants nothing to do with us (manifests as arrows pointing away from eachother), should disconnect + -- so all connected tubes should point to us, if not disconnect + if + connection_dir ~= split.dir + and not vector.equals((core.wallmounted_to_dir(other_tube_split.dir) + connection_pos), pos) + then + split.connections[i] = 0 + end + end + end + end + + -- third case: it could be a short tube instead, if not, check if there is a tube in our direction, and check if it is properly connected + + local amount_of_connections = 0 + for i = 1, 6 do + if split.connections[i] == 1 then amount_of_connections = amount_of_connections + 1 end + end + + local straight_tube_index = (stube.wallmounted_to_connections_index[split.dir] + 3) % 6 + if straight_tube_index == 0 then straight_tube_index = 6 end + if + not ((amount_of_connections == 1 and split.connections[straight_tube_index] == 1) or amount_of_connections == 0) + then -- not a short tube + make_connection(split.connections, split.dir) + + local next_pos = pos + core.wallmounted_to_dir(split.dir) + local next_node = stube.get_or_load_node(next_pos) + -- also make sure the neighboring tube is properly connected, this must not occur with short tubes + if core.get_item_group(next_node.name, 'stube') == 1 then + local next_tube_split = stube.split_tube_name(next_node.name) + make_connection(next_tube_split.connections, core.dir_to_wallmounted(pos - next_pos)) + + -- small complication: if next_node is a short tube, this could make an invalid tube, crashing the game.. ugh + -- if short tubes were just not a thing, this mod's source code would be substantially smaller + -- but the alternative is really ugly (as in, in-game looks, not source code) soo gotta deal with it + + local set_to = stube.join_tube_name(next_tube_split) + if not core.registered_nodes[set_to] then -- okay this is the extremely lazy way, how did i not think of this earlier + make_connection(next_tube_split.connections, next_tube_split.dir) + set_to = stube.join_tube_name(next_tube_split) + end + + core.set_node(next_pos, { name = set_to }) + end + end + + if amount_of_connections == 0 then split.dir = 0 end + + core.set_node(pos, { name = stube.join_tube_name(split) }) +end + +function stube.tube_after_place(pos, placer, stack, pointed) + if not placer then return end + if not placer:is_valid() then return end + if pointed.type ~= 'node' then return end + + local face = vector.subtract(pointed.above, pointed.under) + local dir = core.dir_to_wallmounted(face) + + local sneaking = placer:get_player_control().sneak + stube.place_tube(stack:get_name(), pos, dir, pointed, sneaking) + stube.update_placement(pos) +end + +-- Change the direction to the one we are pointing to +-- Needs sneak+punch +function stube.default_tube_punch(pos, node, puncher, pointed_thing) + if puncher and puncher:get_player_control().sneak then + local split = stube.split_tube_name(node.name) + split.dir = core.dir_to_wallmounted(pointed_thing.above - pointed_thing.under) + split.connections[stube.wallmounted_to_connections_index[split.dir]] = 1 + core.set_node(pos, { name = stube.join_tube_name(split) }) + end + stube.update_placement(pos) +end diff --git a/mods/stubes/register.lua b/mods/stubes/register.lua new file mode 100644 index 00000000..9579b656 --- /dev/null +++ b/mods/stubes/register.lua @@ -0,0 +1,320 @@ +---@class stube.TubeDef +---@field textures table +---@field speed number +---@field capacity integer The amount of ItemStacks that can fit +---@field should_update fun(tube_hpos:integer, tube_state:stube.TubeState, node:node):boolean +---@field get_next_pos_and_node fun(tube_hpos:integer, tube_state:stube.TubeState, dir:integer):vector, node + +---@type {[string]: stube.TubeDef } +stube.registered_tubes = {} + +local function tube_nodebox(len, stretch_to) + local full = 0.5 + local base_box = { -len, -len, -len, len, len, len } + if stretch_to == 'top' then + base_box[5] = full + elseif stretch_to == 'bottom' then + base_box[2] = -full + elseif stretch_to == 'front' then + base_box[3] = -full + elseif stretch_to == 'back' then + base_box[6] = full + elseif stretch_to == 'right' then + base_box[4] = full + elseif stretch_to == 'left' then + base_box[1] = -full + end + return base_box +end +local tube_size = 3 / 16 + +--- e* -> expected +--- so edir = expected dir +local function short_check(dir, xc, yc, zc, nxc, nyc, nzc, edir, exc, eyc, ezc, enxc, enyc, enzc) + return dir == edir and xc == exc and yc == eyc and zc == ezc and nxc == enxc and nyc == enyc and nzc == enzc +end + +local function change_tile_dir(arranged_connections, tiles, tube_textures, id, transform) + if arranged_connections[id] == 1 then + tiles[id] = tube_textures.noctr_up .. transform + else + tiles[id] = tube_textures.plain_up .. transform + end +end + +local function register_single_tube(name, def, tubedef, dir, xc, yc, zc, nxc, nyc, nzc) + local is_short = false -- Shorts are tubes that lead to nowhere, so they are the "endings" + local visible = false -- If it's visible in the inventory, the _000000 tube + if + dir == 0 and yc ~= 1 + or dir == 1 and nyc ~= 1 + or dir == 2 and xc ~= 1 + or dir == 3 and nxc ~= 1 + or dir == 4 and zc ~= 1 + or dir == 5 and nzc ~= 1 + then + -- i am horrible at working with large amounts of variables xD + -- good luck understanding this hehe + if + short_check(dir, xc, yc, zc, nxc, nyc, nzc, 0, 0, 0, 0, 0, 1, 0) + or short_check(dir, xc, yc, zc, nxc, nyc, nzc, 1, 0, 1, 0, 0, 0, 0) + or short_check(dir, xc, yc, zc, nxc, nyc, nzc, 2, 0, 0, 0, 1, 0, 0) + or short_check(dir, xc, yc, zc, nxc, nyc, nzc, 3, 1, 0, 0, 0, 0, 0) + or short_check(dir, xc, yc, zc, nxc, nyc, nzc, 4, 0, 0, 0, 0, 0, 1) + or short_check(dir, xc, yc, zc, nxc, nyc, nzc, 5, 0, 0, 1, 0, 0, 0) + then + is_short = true + elseif short_check(dir, xc, yc, zc, nxc, nyc, nzc, 0, 0, 0, 0, 0, 0, 0) then + visible = true + else + return -- invalid tubes, so only 224 nodes should get registered thanks to this + end + end + + name = name .. '_' .. dir .. xc .. yc .. zc .. nxc .. nyc .. nzc + if visible == false then + def.description = def.description + .. table.concat { ', state: ', '\n' } + .. table.concat { 'short: ', tostring(is_short), '\n' } + .. table.concat { 'dir: ', dir, '\n' } + .. table.concat { 'xc: ', xc, '\n' } + .. table.concat { 'yc: ', yc, '\n' } + .. table.concat { 'zc: ', zc, '\n' } + .. table.concat { 'nxc: ', nxc, '\n' } + .. table.concat { 'nyc: ', nyc, '\n' } + .. table.concat { 'nzc: ', nzc, '\n' } + end + + local nodebox = { type = 'fixed', fixed = {} } + local fixed = nodebox.fixed + + if yc == 1 then table.insert(fixed, tube_nodebox(tube_size, 'top')) end + if nyc == 1 then table.insert(fixed, tube_nodebox(tube_size, 'bottom')) end + + if xc == 1 then table.insert(fixed, tube_nodebox(tube_size, 'right')) end + if nxc == 1 then table.insert(fixed, tube_nodebox(tube_size, 'left')) end + + if zc == 1 then table.insert(fixed, tube_nodebox(tube_size, 'back')) end + if nzc == 1 then table.insert(fixed, tube_nodebox(tube_size, 'front')) end + if visible then table.insert(fixed, { -tube_size, -tube_size, -tube_size, tube_size, tube_size, tube_size }) end + def.node_box = nodebox + + -- okay...... now the textures + -- Each side that is connected to, will have the texture be `noctr` + -- Each side that isn't connected to, will have the texture be `plain` + -- On *short* tubes, the ending texture will be `ends` + + -- These connections are arranged in {+Y, -Y, +X, -X, +Z, -Z} - the same order that tiles are + -- This makes some seemingly complicated things trivial + local arranged_connections = { yc, nyc, xc, nxc, zc, nzc } + + def.tiles = {} + for i = 1, 6 do + if arranged_connections[i] == 1 then -- if its a connection, use noctr, if we didn't there would be an annoying glitchy effect + def.tiles[i] = tubedef.textures.noctr + else + def.tiles[i] = tubedef.textures.plain + end + end + + if is_short then + -- wallmounted dir -> tile conversion + def.tiles[dir + 1] = tubedef.textures.ends + else + -- Need to correctly apply the direction + -- Short tubes have it always be correct, so no need to change anything there + -- All we have to do is change one arrow basically + -- I don't know if there is a better way to do this than these if statements, possibly/ + -- + -- If you are asking how i figured out all of this, it's called "brute forcing" (at least it felt like it, but was fun?) + if dir == 0 then + change_tile_dir(arranged_connections, def.tiles, tubedef.textures, 3, '') + change_tile_dir(arranged_connections, def.tiles, tubedef.textures, 4, '') + change_tile_dir(arranged_connections, def.tiles, tubedef.textures, 5, '') + change_tile_dir(arranged_connections, def.tiles, tubedef.textures, 6, '') + elseif dir == 1 then + change_tile_dir(arranged_connections, def.tiles, tubedef.textures, 3, '^[transformFY') + change_tile_dir(arranged_connections, def.tiles, tubedef.textures, 4, '^[transformFY') + change_tile_dir(arranged_connections, def.tiles, tubedef.textures, 5, '^[transformFY') + change_tile_dir(arranged_connections, def.tiles, tubedef.textures, 6, '^[transformFY') + elseif dir == 2 then + change_tile_dir(arranged_connections, def.tiles, tubedef.textures, 1, '^[transformR270') + change_tile_dir(arranged_connections, def.tiles, tubedef.textures, 2, '^[transformR270') + change_tile_dir(arranged_connections, def.tiles, tubedef.textures, 5, '^[transformR90') + change_tile_dir(arranged_connections, def.tiles, tubedef.textures, 6, '^[transformR270') + elseif dir == 3 then + change_tile_dir(arranged_connections, def.tiles, tubedef.textures, 1, '^[transformR90') + change_tile_dir(arranged_connections, def.tiles, tubedef.textures, 2, '^[transformR90') + change_tile_dir(arranged_connections, def.tiles, tubedef.textures, 5, '^[transformR270') + change_tile_dir(arranged_connections, def.tiles, tubedef.textures, 6, '^[transformR90') + elseif dir == 4 then + change_tile_dir(arranged_connections, def.tiles, tubedef.textures, 1, '') + change_tile_dir(arranged_connections, def.tiles, tubedef.textures, 2, '^[transformFY') + change_tile_dir(arranged_connections, def.tiles, tubedef.textures, 3, '^[transformR270') + change_tile_dir(arranged_connections, def.tiles, tubedef.textures, 4, '^[transformR90') + elseif dir == 5 then + change_tile_dir(arranged_connections, def.tiles, tubedef.textures, 1, '^[transformFY') + change_tile_dir(arranged_connections, def.tiles, tubedef.textures, 2, '') + change_tile_dir(arranged_connections, def.tiles, tubedef.textures, 3, '^[transformR90') + change_tile_dir(arranged_connections, def.tiles, tubedef.textures, 4, '^[transformR270') + end + end + + if not stube.debug then def.groups.not_in_creative_inventory = visible and 0 or 1 end + if visible then def.after_place_node = stube.tube_after_place end + + core.register_node(name, def) +end + +---@param name string +---@param def table +---@param tubedef stube.TubeDef +function stube.register_tube(name, def, tubedef) + stube.registered_tubes[name] = tubedef + def.groups = def.groups or {} + def.groups.stube = 1 + + -- pipeworks -> stube compatibility + -- i love when an api isn't documented at all + --- FIXME: Implement insert_object/can_insert functions + def.groups.tubedevice = 1 + def.groups.tubedevice_receiver = 1 + def.tube = { + insert_object = function(pos, node, stack, dir) end, + can_insert = function(pos, node, stack, dir) end, + connect_sides = { back = 1 }, + } + + -- Alias + core.register_alias('stubes:test_tube', 'stubes:test_tube_0000000') + def.drop = 'stubes:test_tube' + + -- pipeworks compat ends + + -- i saw what pipeworks was doing, so i think i am going with whatever this "old aproach" is https://github.com/mt-mods/pipeworks/blob/6e11868d1b32d316d60061c78460d260ac92ed6a/tubes/registration.lua#L176 + -- because it mentioned something about "the textures must be rotated" with the "new aproach", and uh i think that will complicate things, and i don't want to deal with rotating them. + -- + -- also tubes are *directional*... so it won't just be 64 tubes + -- so, 384 tubes at maximum, of which some are invalid + -- I calculated there to be about 160 tubes which are invalid, so i will have to register about 224 nodes + + -- naming scheme: + -- c - if that direction is connected + -- nc - if that "negative" direction is connected (e.g. Z+ is north, Z- is south, so nzc would be if its connected from the south) + -- example: + -- 1. assume tube in the shape of "|", and that the direction that "^" is pointing in, is the y axis + -- then yc=1, nyc=1, all else is zero + -- 2. assume tube in the shape of "+", and the direction that ">" is pointing in, is the x axis + -- then yc=1, nyc=1, xc=1, nxc = 1, all else is zero + -- Does this make sense? + -- And also `direction` is just a wallmounted param2 + -- + for direction = 0, 5 do + for xc = 0, 1 do + for yc = 0, 1 do + for zc = 0, 1 do + for nxc = 0, 1 do + for nyc = 0, 1 do + for nzc = 0, 1 do + register_single_tube( + name, + table.copy(def), + tubedef, + direction, + xc, + yc, + zc, + nxc, + nyc, + nzc + ) + end + end + end + end + end + end + end +end + +--- Assumes one tube texture is 64x32 +-- See textures/ directory for how this is done, alternatively you can do this manually and split into 4 files (bad, horrible, ew) +function stube.make_tube_textures_from(filename) + return { + plain = filename .. '^[sheet:3x2:0,0', + noctr = filename .. '^[sheet:3x2:1,0', + ends = filename .. '^[sheet:3x2:2,0', + plain_up = filename .. '^[sheet:3x2:0,1', + noctr_up = filename .. '^[sheet:3x2:1,1', + } +end + +-- name = name .. '_' .. dir .. xc .. yc .. zc .. nxc .. nyc .. nzc +-- so last 7 characters +function stube.get_tube_name_info(name) + local str_params = name:sub(-7, -1) + local ret = {} + for i = 1, 7 do + ret[i] = assert( + tonumber(string.sub(str_params, i, i)), + 'Something went very wrong, please check relevant line of code and report this' + ) + end + return ret +end + +function stube.get_prefix_tube_name(name) + return name:sub(1, -9) +end + +function stube.get_tube_dir(name) + return assert(tonumber(name:sub(-7, -7)), '!? report this as a bug') +end + +function stube.split_tube_name(name) + local ret = {} + + ret.prefix = stube.get_prefix_tube_name(name) + ret.connections = stube.get_tube_name_info(name) + ret.dir = table.remove(ret.connections, 1) + + return ret +end + +function stube.join_tube_name(split) + return split.prefix .. '_' .. split.dir .. table.concat(split.connections, '') +end + +function stube.default_should_update(tube_hpos, tube_state, node) + -- Don't update if its a short tube + local split = stube.split_tube_name(node.name) + local amount_of_connections = 0 + for i = 1, 6 do + if split.connections[i] == 1 then amount_of_connections = amount_of_connections + 1 end + end + if amount_of_connections == 0 then return false end + if amount_of_connections == 1 and split.connections[stube.wallmounted_to_connections_index[split.dir]] == 0 then -- if its a short tube + return false + end + return true +end + +stube.register_tube('stubes:test_tube', { + description = 'Test Tube', + drawtype = 'nodebox', + sunlight_propagates = true, + use_texture_alpha = 'blend', + groups = { matter = 1 }, + after_dig_node = stube.update_placement, + on_punch = stube.default_tube_punch, +}, { + textures = stube.make_tube_textures_from 'stube_basic_tube.png', + speed = 1, -- 1 stack/s + capacity = 3, + should_update = stube.default_should_update, + get_next_pos_and_node = function(tube_hpos, tube_state, tube_dir) + local cdir = core.wallmounted_to_dir(tube_dir) + local pos = core.get_position_from_hash(tube_hpos) + cdir + return pos, stube.get_or_load_node(pos) + end, +}) diff --git a/mods/stubes/textures/stube_basic_tube.png b/mods/stubes/textures/stube_basic_tube.png new file mode 100644 index 0000000000000000000000000000000000000000..673af81b04d7b0818a7df4bc00a6e780ebb9dcd5 GIT binary patch literal 517 zcmeAS@N?(olHy`uVBq!ia0vp^2|(yU#;t9s^A>-ml)PnQJ*+^^4Vbuy3L`bF}NsOC#29Y*1~_vfTM`>n9rr)ZMQ z`to-L$0fY4tlk{e0Cr98WJkUv#c6Z<1^OKMeyJoHN+_@~A4zDKacW!E@1LdGdh_KTJv-iiK76_K zvK4K?4lErT|Ap#`&psxRyl)@B`TC8r=B9drU;mZ;-a0S-Tw}WQ#{YsB!sC`N@LnDA zch~zP0*~~bA6sTW`~B)~4_DVuWe%!inO!}7nZJ-&ajL_quc9DM{C#PIBhEg7|4Z(e zzC9ei|DE;3Npr4!cK*7u<>-W#irQhw3Sy&wY$6)w|UjRe_g9FL}QqHPAsyty&Zp~lc y#v#zm2r*-!p*K%&WKzZ%A?M_25|cK}uosD)!#(3$;B;WTGI+ZBxvX Not an array +---@field updated_at integer +---@field to_remove? boolean + +---@type table> +local stubes = {} -- A table of all the tubed items, t[tube_name][h(tube_pos)] = TubeState +stube.all_stubes = stubes +stube.current_update_time = 0 -- used in tubed items + +local timers = {} +for name, def in pairs(stube.registered_tubes) do + timers[name] = { current = 0, max = def.speed } + stubes[name] = {} +end + +local IG = core.get_item_group + +--- Transfer items to foreign nodes (anything not part of STubes), The owner field in pipeworks isn't tracked +function stube.transfer_items(tube_state, tube_def, transfer_to_node, transfer_to_pos, tube_dir) + local next_node_def = core.registered_nodes[transfer_to_node.name] + if next_node_def.tube and next_node_def.tube.insert_object then + for i = tube_def.capacity, 1, -1 do + local stack = tube_state.items[i] + local vel = table.copy(core.wallmounted_to_dir(tube_dir)) + vel.speed = 1 + if stack then + stack = next_node_def.tube.insert_object(transfer_to_pos, transfer_to_node, stack, vel, '') + if stack == nil or stack:is_empty() then + tube_state.items[i] = nil + else + tube_state.items[i] = stack + end + end + end + end +end + +--- Problem: can't trust table length or table.insert, so uh... umm +--- yeah... +local function insert_item(t, v, c) + for i = 1, c do + if t[i] == nil then + t[i] = v + return true + end + end + return false +end + +local function push_items_to_next_tube(next_node, next_pos, tube_def, tube_state) + local prefix = stube.get_prefix_tube_name(next_node.name) + local next_tube_def = stube.registered_tubes[prefix] + local next_tube_hpos = core.hash_node_position(next_pos) + local next_tube_state = stubes[prefix][next_tube_hpos] + local is_empty = next_tube_state == nil -- i love how cheap this is + local can_insert = is_empty and next_tube_def.capacity or 0 + + if next_tube_state then + -- actually check how much we can insert, not just if its empty + local items = next_tube_state.items + + for i = 1, next_tube_def.capacity do + if items[i] then can_insert = can_insert + 1 end + end + end + + if is_empty then + -- uhh, guess we will have to make an entry? since we are inserting stuff, and it needs to be there + stubes[prefix][next_tube_hpos] = { + items = {}, + updated_at = stube.current_update_time, + } + next_tube_state = stubes[prefix][next_tube_hpos] + end + + if can_insert > 0 then + local inserted = 0 + for i = tube_def.capacity, 1, -1 do + local item = tube_state.items[i] + if item then + inserted = inserted + 1 + if inserted > can_insert then break end + + insert_item(next_tube_state.items, item, tube_def.capacity) + tube_state.items[i] = nil + end + end + else + return false, next_tube_hpos, next_tube_def, stubes[prefix], prefix + end +end + +local function delete_if_empty_state(tube_hpos, tube_def, tube_state, tubes_array) + local empty = true + for i = tube_def.capacity, 1, -1 do + if tube_state.items[i] ~= nil then + empty = false + break + end + end + if empty then tube_state.to_remove = true end + + if tube_state.to_remove then tubes_array[tube_hpos] = nil end +end + +--- This is a very recursive function +function stube.update_tube(tube_hpos, tube_def, tube_state, prefix) + if tube_state.updated_at == stube.current_update_time then return end + tube_state.updated_at = stube.current_update_time + if + not tube_def.should_update( + tube_hpos, + tube_state, + sbz_api.get_or_load_node(core.get_position_from_hash(tube_hpos)) + ) + then + return + end -- In cases like short tubes you don't want to update the tube, as there is nowhere that items can go, there basically wouldn't be a next node + + local tube_vpos = uh(tube_hpos) + + local this_node = stube.get_or_load_node(tube_vpos) + if stube.get_prefix_tube_name(this_node.name) ~= prefix then -- innacurate state, as node has changed, get rid of it + tube_state.to_remove = true + return + end + local tube_dir = stube.get_tube_dir(this_node.name) + + local next_pos, next_node = tube_def.get_next_pos_and_node(tube_hpos, tube_state, tube_dir) + + if IG(next_node.name, 'stube') == 1 then -- Worst case: another tube, oh no xD + core.debug 'TRANSFERRING TO ANOTHER STUBE' + -- Need to: + -- 1) If the tube next to it has space + -- 2) If not, repeat step 1 from the tube next to it + -- If you encounter a loop (**checkable by TubeState.updated_at**), or if there just isn't space anywhere, job is done + local success, next_tube_hpos, next_tube_def, next_tube_prefix, next_tube_type_array = + push_items_to_next_tube(next_node, next_pos, tube_def, tube_state) + + if success == false then + core.debug 'NOT SUCCESSFUL' + stube.update_tube(next_tube_hpos, next_tube_def, next_tube_type_array[next_tube_hpos], next_tube_prefix) + delete_if_empty_state(tube_hpos, tube_def, tube_state) + push_items_to_next_tube(next_node, next_pos, tube_def, tube_state) + end + elseif IG(next_node.name, 'tubedevice_receiver') == 1 then + core.debug 'TRANSFERING TO FOREIGN NODE' + stube.transfer_items(tube_state, tube_def, next_node, next_pos, tube_dir) + end + core.debug 'PASSED' +end + +function stube.process_tube_type(tube_name, tube_def) + local tubes = stubes[tube_name] + for tube_hpos, tube_state in pairs(tubes) do + if tube_state.updated_at == stube.current_update_time then return end + stube.update_tube(tube_hpos, tube_def, tube_state, tube_name) + delete_if_empty_state(tube_hpos, tube_def, tube_state, tubes) + end +end + +function stube.globalstep(dtime) + stube.current_update_time = stube.current_update_time + 1 + for name, timer in pairs(timers) do + timer.current = timer.current + dtime + if timer.current >= timer.max then + stube.process_tube_type(name, stube.registered_tubes[name]) + timer.current = 0 + end + end +end +core.register_globalstep(stube.globalstep) + +---@return boolean Success Returns false if it can't +function stube.add_tubed_item(pos, stack) + local hpos = core.hash_node_position(pos) + local node = stube.get_or_load_node(pos) + if core.get_item_group(node.name, 'stube') == 0 then return false end + + local prefix = stube.get_prefix_tube_name(node.name) + local tube_state = stubes[prefix][hpos] + if not tube_state then + stubes[prefix][hpos] = { + items = {}, + updated_at = stube.current_update_time, + } + tube_state = stubes[prefix][hpos] + end + + return insert_item(tube_state.items, stack, stube.registered_tubes[prefix].capacity) +end diff --git a/types/core.d.lua b/types/core.d.lua index 80e8ec2f..ceb44836 100644 --- a/types/core.d.lua +++ b/types/core.d.lua @@ -241,6 +241,7 @@ core.registered_nodes = {} ---@param itemname string ---@param groupname string +---@nodiscard ---@return integer function core.get_item_group(itemname, groupname) end From 603df32918b6f1d1f3c17fba715bde239c1bac81 Mon Sep 17 00:00:00 2001 From: TheEt1234 Date: Sun, 21 Sep 2025 18:35:42 +0200 Subject: [PATCH 02/28] Basic working STubes --- mods/sbz_pipeworks/filter_injector.lua | 4 +- mods/stubes/README.md | 5 +- mods/stubes/basic_tubes.lua | 19 ++++ mods/stubes/place.lua | 129 ++++++++++++++++++++----- mods/stubes/register.lua | 30 +----- mods/stubes/transport.lua | 37 +++++-- 6 files changed, 157 insertions(+), 67 deletions(-) diff --git a/mods/sbz_pipeworks/filter_injector.lua b/mods/sbz_pipeworks/filter_injector.lua index be4de258..e98247b0 100644 --- a/mods/sbz_pipeworks/filter_injector.lua +++ b/mods/sbz_pipeworks/filter_injector.lua @@ -42,7 +42,7 @@ local animation_def = { minetest.register_node('pipeworks:automatic_filter_injector', { description = 'Automatic Filter-Injector', - info_extra = 'Pushes items out of blocks... and into tubes or other blocks', + info_extra = 'Pushes items out of containers.', tiles = { { name = 'filter_side.png^[transformFX', animation = animation_def }, { name = 'filter_side.png^[transformFX', animation = animation_def }, @@ -117,7 +117,7 @@ minetest.register_node('pipeworks:automatic_filter_injector', { local fromnode = sbz_api.get_or_load_node(frompos) if not fromnode then - meta:set_string('infotext', "Can't pull from that node - there is no node there?") + meta:set_string('infotext', "Can't pull from that node, there is no node there???") return 1 end diff --git a/mods/stubes/README.md b/mods/stubes/README.md index 4029514e..46ee48fd 100644 --- a/mods/stubes/README.md +++ b/mods/stubes/README.md @@ -5,12 +5,11 @@ Though, they are in a weird stage of still being dependant on pipeworks. I am using 32x32 textures for the tubes, because i could not fit a recognizable arrow into a 32x32 texture without making the node bigger. -A lot of the aproaches were from pipeworks. +This mod was heavily inspired by pipeworks. -# Docs +# Docs - TODO: THEY ARE INACCURATE CURRENTLY ## Groups - `stube=1` - if it's an stube -- `stube_input=1` - if it can input into an stube - `tubedevice`/`tubedevice_receiver` - these are groups from pipeworks ## Functions ### Registration diff --git a/mods/stubes/basic_tubes.lua b/mods/stubes/basic_tubes.lua index e69de29b..687c6291 100644 --- a/mods/stubes/basic_tubes.lua +++ b/mods/stubes/basic_tubes.lua @@ -0,0 +1,19 @@ +stube.register_tube('stubes:test_tube', { + description = 'Test Tube', + drawtype = 'nodebox', + sunlight_propagates = true, + use_texture_alpha = 'blend', + groups = { matter = 1 }, + after_dig_node = stube.update_placement, + on_punch = stube.default_tube_punch, +}, { + textures = stube.make_tube_textures_from 'stube_basic_tube.png', + speed = 1, -- speed*capacity stacks/s + capacity = 3, + should_update = stube.default_should_update_tube, + get_next_pos_and_node = function(tube_hpos, tube_state, tube_dir) + local cdir = core.wallmounted_to_dir(tube_dir) + local pos = core.get_position_from_hash(tube_hpos) + cdir + return pos, stube.get_or_load_node(pos) + end, +}) diff --git a/mods/stubes/place.lua b/mods/stubes/place.lua index 403ac325..09cf7167 100644 --- a/mods/stubes/place.lua +++ b/mods/stubes/place.lua @@ -1,3 +1,30 @@ +--- If it's a tube device, and is NOT an stube +function stube.is_tubedevice(node_name) + local reg = core.registered_nodes[node_name] + if reg == nil then return false end + if reg.tube == nil then return false end + if core.get_item_group(node_name, 'stube') == 1 then return false end + return true +end + +function stube.process_pipeworks_connect_sides(connect_sides, neighbor_dir, neighbor_node) + local neighbor_facedir = neighbor_node.param2 + local neighbor_facedir_dir = core.facedir_to_dir(neighbor_facedir) + if neighbor_facedir > 23 then neighbor_facedir = 0 end + local rotate_by = -vector.dir_to_rotation(neighbor_facedir_dir) + if rotate_by.y < -1 then rotate_by.x = -90 end -- HACK, that i am not going to fix, this was derived from brute force, it allows placing tubes to tubedevices from above work, specifically filter injectors + local correct_dir = vector.rotate(neighbor_dir, rotate_by) + local wallmounted_dir = core.dir_to_wallmounted(correct_dir) + + local index = (wallmounted_dir == 0 and 'top') + or (wallmounted_dir == 1 and 'bottom') + or (wallmounted_dir == 2 and 'right') + or (wallmounted_dir == 3 and 'left') + or (wallmounted_dir == 4 and 'front') + or (wallmounted_dir == 5 and 'back') + return connect_sides[index] == 1 or connect_sides[index] == true +end + local function has_no_connections(connections) for i = 1, 6 do if connections[i] == 1 then return false end @@ -78,8 +105,8 @@ function stube.connect_tubes_to(pos, dir, pointed_thing, sneaking) end end -function stube.place_tube(name, pos, tube_dir, under_pos, sneaking) - stube.connect_tubes_to(pos, tube_dir, under_pos, sneaking) +function stube.place_tube(name, pos, tube_dir, pointed_thing, sneaking) + stube.connect_tubes_to(pos, tube_dir, pointed_thing, sneaking) local connections = { -- X, Y, Z @@ -92,13 +119,6 @@ function stube.place_tube(name, pos, tube_dir, under_pos, sneaking) 0, } - -- Need to connect to the proper places, so, it needs input from: - -- - Tubes pointing to pos - -- - Pipeworks tubes - -- - Actually, any machine has the power to input, so anything that has the `stube_input=1` group - -- - Filter injecetors are in this group - -- FIXME: Pipeworks tubes and add that group to filter injectors - for neighbor_dir_number = 0, 5 do local neighbor_dir = core.wallmounted_to_dir(neighbor_dir_number) local neighbor_pos = vector.add(pos, neighbor_dir) @@ -109,8 +129,41 @@ function stube.place_tube(name, pos, tube_dir, under_pos, sneaking) if vector.equals(vector.add(core.wallmounted_to_dir(tube_params[1]), neighbor_pos), pos) then -- If the tube is pointing to ours make_connection(connections, neighbor_dir_number) end - elseif core.get_item_group(neighbor_node.name, 'stube_input') == 1 then - make_connection(connections, neighbor_dir_number) + end + end + + --- Automatically connect any tubedevices + if not sneaking then + for i = 0, 5 do + local neighbor_dir = core.wallmounted_to_dir(i) + local neighbor_pos = vector.add(pos, neighbor_dir) + local neighbor_node = stube.get_or_load_node(neighbor_pos) + + if stube.is_tubedevice(neighbor_node.name) == true then + local connect_sides = core.registered_nodes[neighbor_node.name].tube.connect_sides + local should_connect = true + if connect_sides then + should_connect = stube.process_pipeworks_connect_sides(connect_sides, -neighbor_dir, neighbor_node) + end + if should_connect then make_connection(connections, i) end + end + end + else -- Only connect the tubedevice we are sneaking at + local under_node = stube.get_or_load_node(pointed_thing.under) + local under_dir = vector.subtract(pointed_thing.above, pointed_thing.under) + + if stube.is_tubedevice(under_node.name) == true then + local connect_sides = core.registered_nodes[under_node.name].tube.connect_sides + local should_connect = true + if connect_sides then + should_connect = stube.process_pipeworks_connect_sides(connect_sides, under_dir, under_node) + end + if should_connect then + make_connection( + connections, + core.dir_to_wallmounted(vector.subtract(pointed_thing.under, pointed_thing.above)) + ) + end end end @@ -123,12 +176,12 @@ function stube.place_tube(name, pos, tube_dir, under_pos, sneaking) end end - -- the square tube + -- the square/no connections tube if no_connections then tube_dir = 0 end -- if a tube is not straight, make a connection -- Basically, makes short tubes whenever possible - -- Also maintain a connection to tubedevices, that sounds important + -- and maintain a connection to things which interact with tubes, that is important local tube_pointing_to = vector.add(pos, core.wallmounted_to_dir(tube_dir)) local tube_pointing_to_node = stube.get_or_load_node(tube_pointing_to) @@ -138,14 +191,15 @@ function stube.place_tube(name, pos, tube_dir, under_pos, sneaking) if not ( ((amount_of_connections == 1 and connections[straight_tube_index] == 1) or amount_of_connections == 0) -- if the tube is straight or a box - and core.get_item_group(tube_pointing_to_node.name, 'tubedevice_receiver') == 0 + and stube.is_tubedevice(tube_pointing_to_node.name) == false ) then make_connection(connections, tube_dir) end -- if there is a tube in the front of us, point to it - -- This makes connecting tubes with multiple inputs possible, after they have already been placed + -- This makes connecting tubes with multiple inputs possible, after they have already been placed, but sometimes you may not want this behavior + if not sneaking then local vdir = core.wallmounted_to_dir(tube_dir) local front_pos = pos + vdir @@ -191,14 +245,7 @@ function stube.update_placement_single(pos) if connection == 1 then -- first case: pointing to air/incompatible node - if - not ( - ig(connection_node.name, 'stube') == 1 - or ig(connection_node.name, 'stube_input') == 1 - or ig(connection_node.name, 'tubedevice') == 1 - or ig(connection_node.name, 'tubedevice_receiver') == 1 - ) - then + if not (ig(connection_node.name, 'stube') == 1 or stube.is_tubedevice(connection_node.name) == true) then split.connections[i] = 0 end @@ -222,15 +269,34 @@ function stube.update_placement_single(pos) end end - -- third case: it could be a short tube instead, if not, check if there is a tube in our direction, and check if it is properly connected - local amount_of_connections = 0 for i = 1, 6 do if split.connections[i] == 1 then amount_of_connections = amount_of_connections + 1 end end - local straight_tube_index = (stube.wallmounted_to_connections_index[split.dir] + 3) % 6 + local straight_tube_index = (stube.wallmounted_to_connections_index[split.dir] + 3) % 6 -- the index opposite to the dir, if that makes sense if straight_tube_index == 0 then straight_tube_index = 6 end + + -- case 2.5: "We could totally be connected to that tubedevice right now actually, we don't need to be a short tube" + if amount_of_connections == 1 and split.connections[straight_tube_index] == 1 then + local dir = core.wallmounted_to_dir(split.dir) + local next_pos = pos + dir + local next_node = stube.get_or_load_node(next_pos) + if stube.is_tubedevice(next_node.name) then + local connect_sides = core.registered_nodes[next_node.name].tube.connect_sides + local should_connect = true + if connect_sides then + should_connect = stube.process_pipeworks_connect_sides( + core.registered_nodes[next_node.name].tube.connect_sides, + dir, + next_node + ) + end + if should_connect then make_connection(split.connections, split.dir) end + end + end + + -- third case: it could be a short tube instead, if not, check if there is a tube in our direction, and check if it is properly connected if not ((amount_of_connections == 1 and split.connections[straight_tube_index] == 1) or amount_of_connections == 0) then -- not a short tube @@ -286,3 +352,14 @@ function stube.default_tube_punch(pos, node, puncher, pointed_thing) end stube.update_placement(pos) end + +if core.global_exists 'pipeworks' then -- hijack pipeworks for our benefit nyehehe + local old_scan_for_tube_objects = pipeworks.scan_for_tube_objects + local pipeworks = pipeworks + + ---@diagnostic disable-next-line: duplicate-set-field + function pipeworks.scan_for_tube_objects(pos) + stube.update_placement(pos) + return old_scan_for_tube_objects(pos) + end +end diff --git a/mods/stubes/register.lua b/mods/stubes/register.lua index 9579b656..cc3ee35a 100644 --- a/mods/stubes/register.lua +++ b/mods/stubes/register.lua @@ -1,6 +1,6 @@ ---@class stube.TubeDef ---@field textures table ----@field speed number +---@field speed number The amount of time between updates, lower is faster ---@field capacity integer The amount of ItemStacks that can fit ---@field should_update fun(tube_hpos:integer, tube_state:stube.TubeState, node:node):boolean ---@field get_next_pos_and_node fun(tube_hpos:integer, tube_state:stube.TubeState, dir:integer):vector, node @@ -175,14 +175,12 @@ function stube.register_tube(name, def, tubedef) def.groups.stube = 1 -- pipeworks -> stube compatibility - -- i love when an api isn't documented at all --- FIXME: Implement insert_object/can_insert functions def.groups.tubedevice = 1 def.groups.tubedevice_receiver = 1 def.tube = { - insert_object = function(pos, node, stack, dir) end, - can_insert = function(pos, node, stack, dir) end, - connect_sides = { back = 1 }, + insert_object = stube.tube_input_insert_object, + can_insert = stube.tube_input_can_insert, } -- Alias @@ -285,7 +283,7 @@ function stube.join_tube_name(split) return split.prefix .. '_' .. split.dir .. table.concat(split.connections, '') end -function stube.default_should_update(tube_hpos, tube_state, node) +function stube.default_should_update_tube(tube_hpos, tube_state, node) -- Don't update if its a short tube local split = stube.split_tube_name(node.name) local amount_of_connections = 0 @@ -298,23 +296,3 @@ function stube.default_should_update(tube_hpos, tube_state, node) end return true end - -stube.register_tube('stubes:test_tube', { - description = 'Test Tube', - drawtype = 'nodebox', - sunlight_propagates = true, - use_texture_alpha = 'blend', - groups = { matter = 1 }, - after_dig_node = stube.update_placement, - on_punch = stube.default_tube_punch, -}, { - textures = stube.make_tube_textures_from 'stube_basic_tube.png', - speed = 1, -- 1 stack/s - capacity = 3, - should_update = stube.default_should_update, - get_next_pos_and_node = function(tube_hpos, tube_state, tube_dir) - local cdir = core.wallmounted_to_dir(tube_dir) - local pos = core.get_position_from_hash(tube_hpos) + cdir - return pos, stube.get_or_load_node(pos) - end, -}) diff --git a/mods/stubes/transport.lua b/mods/stubes/transport.lua index 9ea8126a..37d6252a 100644 --- a/mods/stubes/transport.lua +++ b/mods/stubes/transport.lua @@ -3,6 +3,7 @@ local h, uh = core.hash_node_position, core.get_position_from_hash --- The state of an active tube, doesn't update if the node does, so things like `dir` should not be there ---@class stube.TubeState ---@field items table Not an array +---@field entities? table Not an array ---@field updated_at integer ---@field to_remove? boolean @@ -12,14 +13,16 @@ stube.all_stubes = stubes stube.current_update_time = 0 -- used in tubed items local timers = {} -for name, def in pairs(stube.registered_tubes) do - timers[name] = { current = 0, max = def.speed } - stubes[name] = {} -end +core.register_on_mods_loaded(function() + for name, def in pairs(stube.registered_tubes) do + timers[name] = { current = 0, max = def.speed } + stubes[name] = {} + end +end) local IG = core.get_item_group ---- Transfer items to foreign nodes (anything not part of STubes), The owner field in pipeworks isn't tracked +--- Transfer items to foreign nodes (pipeworks receivers), The owner field in pipeworks isn't tracked function stube.transfer_items(tube_state, tube_def, transfer_to_node, transfer_to_pos, tube_dir) local next_node_def = core.registered_nodes[transfer_to_node.name] if next_node_def.tube and next_node_def.tube.insert_object then @@ -39,8 +42,8 @@ function stube.transfer_items(tube_state, tube_def, transfer_to_node, transfer_t end end ---- Problem: can't trust table length or table.insert, so uh... umm ---- yeah... +--- Problem: can't trust table length or table.insert with tables that have holes +--- so this has to be the solution, does not seem to be a good one though local function insert_item(t, v, c) for i = 1, c do if t[i] == nil then @@ -64,12 +67,11 @@ local function push_items_to_next_tube(next_node, next_pos, tube_def, tube_state local items = next_tube_state.items for i = 1, next_tube_def.capacity do - if items[i] then can_insert = can_insert + 1 end + if items[i] == nil then can_insert = can_insert + 1 end end end if is_empty then - -- uhh, guess we will have to make an entry? since we are inserting stuff, and it needs to be there stubes[prefix][next_tube_hpos] = { items = {}, updated_at = stube.current_update_time, @@ -85,7 +87,7 @@ local function push_items_to_next_tube(next_node, next_pos, tube_def, tube_state inserted = inserted + 1 if inserted > can_insert then break end - insert_item(next_tube_state.items, item, tube_def.capacity) + insert_item(next_tube_state.items, item, next_tube_def.capacity) tube_state.items[i] = nil end end @@ -193,3 +195,18 @@ function stube.add_tubed_item(pos, stack) return insert_item(tube_state.items, stack, stube.registered_tubes[prefix].capacity) end + +function stube.tube_input_insert_object(pos, node, stack, vel, owner) + local prefix = stube.get_prefix_tube_name(node.name) + local all_stubes_of_our_type = stubes[prefix] + local hpos = h(pos) + local tube_state = all_stubes_of_our_type[hpos] + if not tube_state then + all_stubes_of_our_type[hpos] = { + items = {}, + updated_at = stube.current_update_time, + } + tube_state = all_stubes_of_our_type[hpos] + end + if insert_item(tube_state.items, stack, stube.registered_tubes[prefix].capacity) == false then return stack end +end From 17a6a49f4c570f30875781baf938d727d1323489 Mon Sep 17 00:00:00 2001 From: TheEt1234 Date: Sat, 27 Sep 2025 18:34:55 +0200 Subject: [PATCH 03/28] Fully working stubes --- mods/sbz_pipeworks/init.lua | 49 ++-- mods/sbz_power/infinite_storinator.lua | 153 +----------- mods/stubes/README.md | 4 + mods/stubes/basic_tubes.lua | 10 +- mods/stubes/entity.lua | 94 ++++++++ mods/stubes/hud.lua | 67 ++++++ mods/stubes/init.lua | 49 ++-- mods/stubes/place.lua | 17 +- mods/stubes/register.lua | 64 +++--- mods/stubes/stube_transport.lua | 307 +++++++++++++++++++++++++ mods/stubes/transport.lua | 212 ----------------- 11 files changed, 591 insertions(+), 435 deletions(-) create mode 100644 mods/stubes/hud.lua create mode 100644 mods/stubes/stube_transport.lua delete mode 100644 mods/stubes/transport.lua diff --git a/mods/sbz_pipeworks/init.lua b/mods/sbz_pipeworks/init.lua index 8105e30a..b25c65ae 100644 --- a/mods/sbz_pipeworks/init.lua +++ b/mods/sbz_pipeworks/init.lua @@ -3,34 +3,33 @@ -- This mod supplies various steel pipes and plastic pneumatic tubes -- and devices that they can connect to. - +---@class pipeworks pipeworks = { - worldpath = minetest.get_worldpath(), - modpath = minetest.get_modpath("pipeworks"), - logger = function(msg) - minetest.log("action", "[pipeworks] " .. msg) - end, - entity_update_interval = 0.1, - use_real_entities = true, - enable_cyclic_mode = true, - tube_backface_culling = core.settings:get_bool("sbz_pipe_backface_culling", true), + worldpath = minetest.get_worldpath(), + modpath = minetest.get_modpath 'pipeworks', + logger = function(msg) + minetest.log('action', '[pipeworks] ' .. msg) + end, + entity_update_interval = 0.1, + use_real_entities = true, + enable_cyclic_mode = true, + tube_backface_culling = core.settings:get_bool('sbz_pipe_backface_culling', true), } - -- Load the various other parts of the mod -dofile(pipeworks.modpath .. "/common.lua") -dofile(pipeworks.modpath .. "/models.lua") -dofile(pipeworks.modpath .. "/autoplace_tubes.lua") -dofile(pipeworks.modpath .. "/luaentity.lua") -dofile(pipeworks.modpath .. "/item_transport.lua") -dofile(pipeworks.modpath .. "/tube_register.lua") +dofile(pipeworks.modpath .. '/common.lua') +dofile(pipeworks.modpath .. '/models.lua') +dofile(pipeworks.modpath .. '/autoplace_tubes.lua') +dofile(pipeworks.modpath .. '/luaentity.lua') +dofile(pipeworks.modpath .. '/item_transport.lua') +dofile(pipeworks.modpath .. '/tube_register.lua') -dofile(pipeworks.modpath .. "/filter_injector.lua") -dofile(pipeworks.modpath .. "/basic_tubes.lua") -dofile(pipeworks.modpath .. "/basic_blocks.lua") +dofile(pipeworks.modpath .. '/filter_injector.lua') +dofile(pipeworks.modpath .. '/basic_tubes.lua') +dofile(pipeworks.modpath .. '/basic_blocks.lua') -dofile(pipeworks.modpath .. "/wielder.lua") -dofile(pipeworks.modpath .. "/autocrafter.lua") -dofile(pipeworks.modpath .. "/teleport_tube.lua") -dofile(pipeworks.modpath .. "/pattern_storinator.lua") -minetest.log("info", "Pipeworks loaded!") +dofile(pipeworks.modpath .. '/wielder.lua') +dofile(pipeworks.modpath .. '/autocrafter.lua') +dofile(pipeworks.modpath .. '/teleport_tube.lua') +dofile(pipeworks.modpath .. '/pattern_storinator.lua') +minetest.log('info', 'Pipeworks loaded!') diff --git a/mods/sbz_power/infinite_storinator.lua b/mods/sbz_power/infinite_storinator.lua index b9d0fc37..37e01e8e 100644 --- a/mods/sbz_power/infinite_storinator.lua +++ b/mods/sbz_power/infinite_storinator.lua @@ -1,153 +1,10 @@ --- License for the function make_scrollbaroptions_for_scroll_container: ---[[ -License of minetest: https://github.com/minetest/minetest/blob/master/LICENSE.txt - -Minetest -Copyright (C) 2022 rubenwardy - -This program is free software; you can redistribute it and/or modify -it under the terms of the GNU Lesser General Public License as published by -the Free Software Foundation; either version 2.1 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public License along -with this program; if not, write to the Free Software Foundation, Inc., -51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - -Only applies to the function below, everything else is licensed normally as in LICENSE.txt -]] ---- Creates a scrollbaroptions for a scroll_container --- --- @param visible_l the length of the scroll_container and scrollbar --- @param total_l length of the scrollable area --- @param scroll_factor as passed to scroll_container -local function make_scrollbaroptions_for_scroll_container(visible_l, total_l, scroll_factor) - assert(total_l >= visible_l) - local max = total_l - visible_l - local thumb_size = (visible_l / total_l) * max - return ("scrollbaroptions[min=0;max=%f;thumbsize=%f]"):format(max / scroll_factor, thumb_size / scroll_factor) -end - -local max_slots = 5000 - -local M = minetest.get_meta - -local slots_per_1_power = 8 - -sbz_api.register_machine("sbz_power:infinite_storinator", { - description = "Infinite Storinator (deprecated)", - info_extra = { - "If you loose power you will need to re-power it to get your items back", - "For one power you can get " .. slots_per_1_power .. " slots" - }, - tiles = { - "infinite_storinator_side.png", - "infinite_storinator_side.png", - "infinite_storinator_side.png", - "infinite_storinator_side.png", - "infinite_storinator_side.png", - { name = "infinite_storinator_front.png", animation = { type = "vertical_frames", length = 2 } } - }, - paramtype2 = "facedir", - on_construct = function(pos) - local meta = minetest.get_meta(pos) - local inv = meta:get_inventory() - inv:set_size("inv", max_slots) - meta:set_int("visible_slots", 0) - meta:set_int("slots_set", 8) - end, +sbz_api.register_machine('sbz_power:infinite_storinator', { + description = 'Infinite Storinator (deprecated)', + paramtype2 = 'facedir', groups = { matter = 1, not_in_creative_inventory = 1 }, + drop = '', action = function(pos, node, meta, supply, demand) - -- time to nuke supply :D - if supply <= demand then return 0 end - - local slots = 0 - local max_slots_allowed = math.floor((supply - demand) * slots_per_1_power) - local slots_set = math.floor(meta:get_int("slots_set")) - if max_slots_allowed < slots_set then - slots = max_slots_allowed - else - slots = slots_set - end - local power_consumed = slots / slots_per_1_power - - meta:set_int("visible_slots", slots) - meta:set_string("infotext", string.format("Infinite storinator, slots: %s, consuming: %s", slots, power_consumed)) - - local max_width = 8 - - local list_inv_w = max_width - local list_inv_h = math.floor(slots / max_width) - - - - meta:set_string("formspec", string.format([[ - formspec_version[7] - size[10.6,15.2] - %s - style_type[list;noclip=false;size=1,1;spacing=0.25,0.25] - scrollbar[10,0.2;0.4,8.6;vertical;scrollbar;0] - scroll_container[0.2,0.2;9.8,8.6;scrollbar;vertical;1] - list[context;inv;0,0;%s,%s] - scroll_container_end[] - list[current_player;main;0.2,9;8,4;] - field[0.2,14.4;3,0.5;set_slots;Amount of rows;%s] - listring[] - ]], make_scrollbaroptions_for_scroll_container(7.6, math.max(8, list_inv_h + list_inv_h / 4), 1), list_inv_w, - list_inv_h, - slots_set / 8)) - return power_consumed - end, - on_receive_fields = function(pos, _, fields) - local meta = minetest.get_meta(pos) - if fields.set_slots then - local n_slots = math.abs(math.floor(tonumber(fields.set_slots) or 8)) * 8 - if n_slots > max_slots then - n_slots = max_slots - end - meta:set_int("slots_set", n_slots) - end - end, - allow_metadata_inventory_move = function(pos, from_list, from_index, to_list, to_index, count, player) - local meta = M(pos) - if (from_index <= meta:get_int("visible_slots") and to_index <= meta:get_int("visible_slots")) or (from_list == to_list == "main") then - return count - end - return 0 - end, - - allow_metadata_inventory_put = function(pos, listname, index, stack, player) - local meta = M(pos) - if index <= meta:get_int("visible_slots") or listname == "main" then - return stack:get_count() - end - return 0 - end, - allow_metadata_inventory_take = function(pos, listname, index, stack, player) - local meta = M(pos) - if index <= meta:get_int("visible_slots") or listname == "main" then return stack:get_count() end return 0 end, - output_inv = "inv", - input_inv = "inv", - - - control_action_raw = true, - disallow_pipeworks = false, -}) - ---[[ -minetest.register_craft({ - output = "sbz_power:infinite_storinator", - recipe = { - { "sbz_resources:storinator", "sbz_resources:emittrium_circuit", "sbz_resources:storinator" }, - { "sbz_resources:storinator", "sbz_meteorites:neutronium", "sbz_resources:storinator" }, - { "sbz_resources:storinator", "sbz_resources:emittrium_circuit", "sbz_resources:storinator" } - } + disallow_pipeworks = true, }) ---]] diff --git a/mods/stubes/README.md b/mods/stubes/README.md index 46ee48fd..8917c690 100644 --- a/mods/stubes/README.md +++ b/mods/stubes/README.md @@ -7,6 +7,10 @@ I am using 32x32 textures for the tubes, because i could not fit a recognizable This mod was heavily inspired by pipeworks. +## Performance +- Tubed item visuals which aren't near the player aren't shown (so that gets rid of the need to perform costly `move_to` calls) +- It should be able to handle 10 000 items quite easily + # Docs - TODO: THEY ARE INACCURATE CURRENTLY ## Groups - `stube=1` - if it's an stube diff --git a/mods/stubes/basic_tubes.lua b/mods/stubes/basic_tubes.lua index 687c6291..e5a7e3da 100644 --- a/mods/stubes/basic_tubes.lua +++ b/mods/stubes/basic_tubes.lua @@ -1,15 +1,17 @@ stube.register_tube('stubes:test_tube', { description = 'Test Tube', - drawtype = 'nodebox', - sunlight_propagates = true, use_texture_alpha = 'blend', groups = { matter = 1 }, after_dig_node = stube.update_placement, on_punch = stube.default_tube_punch, + + -- Needed or it will be buggy + drawtype = 'nodebox', + sunlight_propagates = true, + paramtype = 'light', }, { textures = stube.make_tube_textures_from 'stube_basic_tube.png', - speed = 1, -- speed*capacity stacks/s - capacity = 3, + speed = 1, -- seconds/stack should_update = stube.default_should_update_tube, get_next_pos_and_node = function(tube_hpos, tube_state, tube_dir) local cdir = core.wallmounted_to_dir(tube_dir) diff --git a/mods/stubes/entity.lua b/mods/stubes/entity.lua index e69de29b..383eecc0 100644 --- a/mods/stubes/entity.lua +++ b/mods/stubes/entity.lua @@ -0,0 +1,94 @@ +core.register_entity('stubes:item_visual', { + initial_properties = { + physical = false, + textures = { '' }, + static_save = false, + + pointable = false, + visual = 'wielditem', + visual_size = { x = stube.tube_size, y = stube.tube_size }, + glow = 1, + }, + on_activate = function(self, staticdata) + local stack = ItemStack(staticdata) + self.object:set_properties { + textures = { stack:get_name() }, + } + end, +}) + +local function create_visual(pos, stack) + return core.add_entity(pos, 'stubes:item_visual', stack:to_string()) +end + +---@param pos vector +---@param tubestate stube.TubeState +function stube.add_visuals_to_tubestate(pos, tubestate) + for dir, connection in pairs(tubestate.connections) do + local vdir = core.wallmounted_to_dir(dir) + if dir == 6 then vdir = vector.zero() end + if not connection.entity then connection.entity = create_visual(vector.add(pos, vdir / 3), connection.stack) end + end +end + +---@param tubestate stube.TubeState +function stube.remove_visuals_from_tubestate(tubestate) + for _, connection in pairs(tubestate.connections) do + if connection.entity then + connection.entity:remove() + connection.entity = nil + end + end +end + +local function get_player_positions() + local ret = {} + for _, player in pairs(core.get_connected_players()) do + ret[#ret + 1] = player:get_pos() + end + return ret +end + +--- Adds/removes tubestate visuals depending on if they are actually needed +--- Time complexity: O(amount_of_tubes*amount_of_players) i think, not great +---@param tubestate stube.TubeState +---@param pos vector +---@param player_positions vector[]? +function stube.add_or_remove_tubestate_visuals(pos, tubestate, player_positions) + if stube.enable_entities == false then return stube.remove_visuals_from_tubestate(tubestate) end + + if not player_positions then player_positions = get_player_positions() end + local should_add = false + for i = 1, #player_positions do + local player_position = player_positions[i] + if vector.distance(pos, player_position) <= stube.entity_radius then + should_add = true + break + end + end + + if should_add then + stube.add_visuals_to_tubestate(pos, tubestate) + else + stube.remove_visuals_from_tubestate(tubestate) + end +end + +local timer = 0 +local timer_max = stube.entity_creation_globalstep_time +-- stube.update updates visuals, this is responsible for adding/deleting them +function stube.visual_globalstep(dtime) + timer = timer + dtime + if timer < timer_max then return end + timer = 0 + + local player_positions = get_player_positions() + + for tube_type, tubes_array in pairs(stube.all_stubes) do + for hpos, tube_state in pairs(tubes_array) do + stube.add_or_remove_tubestate_visuals(core.get_position_from_hash(hpos), tube_state, get_player_positions()) + end + end +end + +core.register_globalstep(stube.visual_globalstep) diff --git a/mods/stubes/hud.lua b/mods/stubes/hud.lua new file mode 100644 index 00000000..ffd5e0b8 --- /dev/null +++ b/mods/stubes/hud.lua @@ -0,0 +1,67 @@ +-- Display how many items are inside a tube with a HUD +-- ... wow HUDs are dogsh#t + +--- { [player name] = id[] } +---@type table +local ids = {} + +local timer = 0 +local timer_max = 0.25 + +function stube.hud_update(player) + local player_name = player:get_player_name() + local tube_pos, tube_node + + local look_dir = player:get_look_dir() + local eye_pos = player:get_pos() + eye_pos.y = eye_pos.y + (player:get_properties().eye_height or 0) + + local ray = core.raycast(eye_pos, vector.add(eye_pos, vector.multiply(look_dir, 5)), false, false) + for pointed_thing in ray do + if pointed_thing.type == 'node' then + local node = core.get_node(pointed_thing.under) + if core.get_item_group(node.name, 'stube') == 1 then + tube_pos, tube_node = pointed_thing.under, node + break + end + end + end + + if ids[player_name] then + for _, id in pairs(ids[player_name]) do + player:hud_remove(id) + end + ids[player_name] = nil + end + + if not tube_pos then return end + local tube_state = stube.all_stubes[stube.get_prefix_tube_name(tube_node.name)][core.hash_node_position(tube_pos)] + if not tube_state then return end + + ids[player_name] = {} + for dir, connection in pairs(tube_state.connections) do + table.insert( + ids[player_name], + player:hud_add { + type = 'waypoint', + precision = 0, + name = tostring(connection.stack:get_count()), + number = (connection.stack:get_count() / connection.stack:get_stack_max()) * 0xFFFFFF, -- i love the not at all confusing HUD api + world_pos = stube.get_precise_connection_pos(tube_pos, dir), + } + ) + end +end + +---@param dtime number +function stube.hud_globalstep(dtime) + timer = timer + dtime + if timer < timer_max then return end + timer = 0 + + for _, player in pairs(core.get_connected_players()) do + stube.hud_update(player) + end +end + +core.register_globalstep(stube.hud_globalstep) diff --git a/mods/stubes/init.lua b/mods/stubes/init.lua index b83709c2..4892b719 100644 --- a/mods/stubes/init.lua +++ b/mods/stubes/init.lua @@ -1,20 +1,41 @@ -local mp = core.get_modpath(core.get_current_modname()) - ----@diagnostic disable-next-line: lowercase-global +--- Configuration in init.lua ---@class stube stube = { - debug = true, -- pollutes the creative inventory + -- The debug mode for STubes + -- Currently, it just pollutes the creative inventory with tube variants + debug = false, + + -- This is mostly an option for testing, there is no actual reason to disable them (You can just set entity_radius to something low if you don't like them) + enable_entities = true, + + -- Item Entities will be shown when the player is this many nodes near to them + -- Set to a huge value to almost always have item entities (Why would you do that?) + -- This feature has been shown to help, as it skips laggy entity move_to calls + entity_radius = 16, - get_or_load_node = function(pos) - local get_or_load_node_node = core.get_node_or_nil(pos) - if get_or_load_node_node then return get_or_load_node_node end - core.load_area(pos) - return core.get_node(pos) - end, + -- The globalstep for creating/removing entities will be run every seconds + entity_creation_globalstep_time = 1, } -dofile(mp .. '/place.lua') -dofile(mp .. '/register.lua') -dofile(mp .. '/transport.lua') -dofile(mp .. '/entity.lua') +--- Creating a utils file is silly, so i am putting it here +--- ALSO: This is a trick from the mt-mods/technic luanti mod +---@param pos vector +---@return node +stube.get_or_load_node = function(pos) + local get_or_load_node_node = core.get_node_or_nil(pos) + if get_or_load_node_node then return get_or_load_node_node end + core.load_area(pos) + return core.get_node(pos) +end + +local mp = core.get_modpath(core.get_current_modname()) + +--- Library: +dofile(mp .. '/place.lua') -- Placement of tubes (kinda complicated) +dofile(mp .. '/register.lua') -- Registering all the variants +dofile(mp .. '/stube_transport.lua') -- Moving tubed items and their entities, named "stube_transport.lua" for easier debugging (As there may be multiple transpurt.luas) +dofile(mp .. '/entity.lua') -- Only for defining the entity, and spawning/despawning them when needed +dofile(mp .. '/hud.lua') -- When hovering over a tube with items you can see the counts + +--- Content: dofile(mp .. '/basic_tubes.lua') diff --git a/mods/stubes/place.lua b/mods/stubes/place.lua index 09cf7167..e719874f 100644 --- a/mods/stubes/place.lua +++ b/mods/stubes/place.lua @@ -1,3 +1,7 @@ +-- Okay so this code is kinda messy? probably better than pipeworks +-- just uh be aware +-- if you don't understand it thats fine, message me (frog) and i could make a comment explaining + --- If it's a tube device, and is NOT an stube function stube.is_tubedevice(node_name) local reg = core.registered_nodes[node_name] @@ -7,12 +11,13 @@ function stube.is_tubedevice(node_name) return true end +-- pipeworks has a better solution im not doing for the sake of licensing function stube.process_pipeworks_connect_sides(connect_sides, neighbor_dir, neighbor_node) local neighbor_facedir = neighbor_node.param2 local neighbor_facedir_dir = core.facedir_to_dir(neighbor_facedir) if neighbor_facedir > 23 then neighbor_facedir = 0 end local rotate_by = -vector.dir_to_rotation(neighbor_facedir_dir) - if rotate_by.y < -1 then rotate_by.x = -90 end -- HACK, that i am not going to fix, this was derived from brute force, it allows placing tubes to tubedevices from above work, specifically filter injectors + if math.floor(neighbor_facedir / 4) ~= 0 and rotate_by.y < -1 then rotate_by.x = -(math.pi / 2) end -- HACK, that i am not going to fix, this was derived from brute force, it allows placing tubes to tubedevices from above work, specifically filter injectors local correct_dir = vector.rotate(neighbor_dir, rotate_by) local wallmounted_dir = core.dir_to_wallmounted(correct_dir) @@ -33,7 +38,8 @@ local function has_no_connections(connections) end -- the order in which i chose the connections was kinda stupid, because it isn't the wallmounted direction --- so i have to do this sort of thing instead of just doing connections[dir]=1 +-- so i have to do this sort of thing instead of just doing connections[wallmounted]=1 +-- This table is {[wallmounted] = STube connection} stube.wallmounted_to_connections_index = { [0] = 2, [1] = 5, @@ -344,6 +350,10 @@ end -- Change the direction to the one we are pointing to -- Needs sneak+punch function stube.default_tube_punch(pos, node, puncher, pointed_thing) + if core.is_protected(pos, puncher) then + core.record_protection_violation(pos, puncher) + return + end if puncher and puncher:get_player_control().sneak then local split = stube.split_tube_name(node.name) split.dir = core.dir_to_wallmounted(pointed_thing.above - pointed_thing.under) @@ -354,8 +364,7 @@ function stube.default_tube_punch(pos, node, puncher, pointed_thing) end if core.global_exists 'pipeworks' then -- hijack pipeworks for our benefit nyehehe - local old_scan_for_tube_objects = pipeworks.scan_for_tube_objects - local pipeworks = pipeworks + local old_scan_for_tube_objects = pipeworks.scan_for_tube_objects -- this runs when ANY PIPEWORKS TUBE OR TUBEDEVICE GETS PLACED, really convenient ---@diagnostic disable-next-line: duplicate-set-field function pipeworks.scan_for_tube_objects(pos) diff --git a/mods/stubes/register.lua b/mods/stubes/register.lua index cc3ee35a..6fc16b47 100644 --- a/mods/stubes/register.lua +++ b/mods/stubes/register.lua @@ -1,7 +1,7 @@ +--- Tube capacity is always +1 ---@class stube.TubeDef ---@field textures table ---@field speed number The amount of time between updates, lower is faster ----@field capacity integer The amount of ItemStacks that can fit ---@field should_update fun(tube_hpos:integer, tube_state:stube.TubeState, node:node):boolean ---@field get_next_pos_and_node fun(tube_hpos:integer, tube_state:stube.TubeState, dir:integer):vector, node @@ -26,7 +26,7 @@ local function tube_nodebox(len, stretch_to) end return base_box end -local tube_size = 3 / 16 +stube.tube_size = 3 / 16 --- e* -> expected --- so edir = expected dir @@ -88,15 +88,20 @@ local function register_single_tube(name, def, tubedef, dir, xc, yc, zc, nxc, ny local nodebox = { type = 'fixed', fixed = {} } local fixed = nodebox.fixed - if yc == 1 then table.insert(fixed, tube_nodebox(tube_size, 'top')) end - if nyc == 1 then table.insert(fixed, tube_nodebox(tube_size, 'bottom')) end + if yc == 1 then table.insert(fixed, tube_nodebox(stube.tube_size, 'top')) end + if nyc == 1 then table.insert(fixed, tube_nodebox(stube.tube_size, 'bottom')) end - if xc == 1 then table.insert(fixed, tube_nodebox(tube_size, 'right')) end - if nxc == 1 then table.insert(fixed, tube_nodebox(tube_size, 'left')) end + if xc == 1 then table.insert(fixed, tube_nodebox(stube.tube_size, 'right')) end + if nxc == 1 then table.insert(fixed, tube_nodebox(stube.tube_size, 'left')) end - if zc == 1 then table.insert(fixed, tube_nodebox(tube_size, 'back')) end - if nzc == 1 then table.insert(fixed, tube_nodebox(tube_size, 'front')) end - if visible then table.insert(fixed, { -tube_size, -tube_size, -tube_size, tube_size, tube_size, tube_size }) end + if zc == 1 then table.insert(fixed, tube_nodebox(stube.tube_size, 'back')) end + if nzc == 1 then table.insert(fixed, tube_nodebox(stube.tube_size, 'front')) end + if visible then + table.insert( + fixed, + { -stube.tube_size, -stube.tube_size, -stube.tube_size, stube.tube_size, stube.tube_size, stube.tube_size } + ) + end def.node_box = nodebox -- okay...... now the textures @@ -175,20 +180,17 @@ function stube.register_tube(name, def, tubedef) def.groups.stube = 1 -- pipeworks -> stube compatibility - --- FIXME: Implement insert_object/can_insert functions def.groups.tubedevice = 1 def.groups.tubedevice_receiver = 1 def.tube = { insert_object = stube.tube_input_insert_object, - can_insert = stube.tube_input_can_insert, + --can_insert = stube.tube_input_can_insert, NYI: TODO:? maybe? i mean who will use this with pipeworks tubes wtf } -- Alias core.register_alias('stubes:test_tube', 'stubes:test_tube_0000000') def.drop = 'stubes:test_tube' - -- pipeworks compat ends - -- i saw what pipeworks was doing, so i think i am going with whatever this "old aproach" is https://github.com/mt-mods/pipeworks/blob/6e11868d1b32d316d60061c78460d260ac92ed6a/tubes/registration.lua#L176 -- because it mentioned something about "the textures must be rotated" with the "new aproach", and uh i think that will complicate things, and i don't want to deal with rotating them. -- @@ -250,17 +252,32 @@ end -- name = name .. '_' .. dir .. xc .. yc .. zc .. nxc .. nyc .. nzc -- so last 7 characters function stube.get_tube_name_info(name) - local str_params = name:sub(-7, -1) local ret = {} + local start = #name - 7 for i = 1, 7 do - ret[i] = assert( - tonumber(string.sub(str_params, i, i)), - 'Something went very wrong, please check relevant line of code and report this' - ) + ret[i] = tonumber(string.sub(name, start + i, start + i)) end return ret end +local is_short_tube_memo = {} + +function stube.is_short_tube(name) + if is_short_tube_memo[name] ~= nil then return is_short_tube_memo[name] end + + local info = stube.get_tube_name_info(name) + local amount_of_connections = 0 + for i = 2, 7 do -- info[1] is direction + if info[i] == 1 then amount_of_connections = amount_of_connections + 1 end + end + + local straight_tube_index = (stube.wallmounted_to_connections_index[info[1]] + 3) % 6 -- the index opposite to the dir, if that makes sense + if straight_tube_index == 0 then straight_tube_index = 6 end + + is_short_tube_memo[name] = amount_of_connections == 1 and info[1 + straight_tube_index] == 1 + return is_short_tube_memo[name] +end + function stube.get_prefix_tube_name(name) return name:sub(1, -9) end @@ -285,14 +302,5 @@ end function stube.default_should_update_tube(tube_hpos, tube_state, node) -- Don't update if its a short tube - local split = stube.split_tube_name(node.name) - local amount_of_connections = 0 - for i = 1, 6 do - if split.connections[i] == 1 then amount_of_connections = amount_of_connections + 1 end - end - if amount_of_connections == 0 then return false end - if amount_of_connections == 1 and split.connections[stube.wallmounted_to_connections_index[split.dir]] == 0 then -- if its a short tube - return false - end - return true + return not stube.is_short_tube(node.name) end diff --git a/mods/stubes/stube_transport.lua b/mods/stubes/stube_transport.lua new file mode 100644 index 00000000..3131d11b --- /dev/null +++ b/mods/stubes/stube_transport.lua @@ -0,0 +1,307 @@ +-- Items are transferred 1 item/update + +local h, uh = core.hash_node_position, core.get_position_from_hash + +---@class stube.TubedItem +---@field stack ItemStack +---@field owner? string +---@field entity? userdata + +--- The state of any active tube +--- The node underneeth a tube state can be anything, and it can change at any time +--- Therefore it is wise not to store things like direction +---@class stube.TubeState +---@field connections table items[wallmounted_dir]=item, items[6] = item at the center +---@field updated_at integer +---@field to_remove? boolean + +---@type table> +local stubes = {} -- A table of all the tubed items, t[tube_name][h(tube_pos)] = TubeState +stube.all_stubes = stubes +stube.current_update_time = 0 -- used in tubed items + +local timers = {} +core.register_on_mods_loaded(function() + for name, def in pairs(stube.registered_tubes) do + timers[name] = { current = 0, max = def.speed } + stubes[name] = {} + end +end) + +local function opposite_wallmounted(wallmounted) + return core.dir_to_wallmounted(-core.wallmounted_to_dir(wallmounted)) -- efficiency :D (joke) +end + +function stube.tube_state_connection_to_dir(connection) + if connection == 6 then + return vector.zero() -- The center + end + return core.wallmounted_to_dir(connection) +end + +function stube.get_precise_connection_pos(pos, connection) + return vector.add(pos, stube.tube_state_connection_to_dir(connection) / 3) +end + +---@param dir number|nil +local function move_entity(ent, pos, dir) + ent:move_to(stube.get_precise_connection_pos(pos, dir), true) +end + +local function move_connection(tube_state, dir1, dir2, pos) + if dir1 ~= dir2 then -- if it is equal, you are just moving the entity + assert( + not tube_state.connections[dir2], + '[stubes]Tried overriding with `local function move_connection(...)` in stubes/transport.lua, report this is a bug' + ) + tube_state.connections[dir2] = tube_state.connections[dir1] + tube_state.connections[dir1] = nil + end + + local ent = tube_state.connections[dir2].entity + if ent then move_entity(ent, pos, dir2) end +end + +local function delete_connection(tube_state, dir) + local ent = tube_state.connections[dir].entity + tube_state.connections[dir] = nil + if ent then ent:remove() end +end + +local IG = core.get_item_group + +--- Transfer items to foreign nodes (pipeworks receivers) +function stube.transfer_items(tube_state, transfer_to_node, transfer_to_pos, tube_dir) + local next_node_def = core.registered_nodes[transfer_to_node.name] + if not (next_node_def.tube and next_node_def.tube.insert_object) then return false end + + local connection = tube_state.connections[tube_dir] + if not connection then return end + + local vel = table.copy(core.wallmounted_to_dir(tube_dir)) + vel.speed = 1 + + connection.stack = next_node_def.tube.insert_object( + transfer_to_pos, + transfer_to_node, + connection.stack, + vel, + connection.owner or '' + ) + if connection.stack == nil or connection.stack:is_empty() then delete_connection(tube_state, tube_dir) end +end + +-- Every item gets pushed to the center (in a set order, even if random would make more sense), center gets pushed to tube dir, tube dir item get transported +---@param tube_state stube.TubeState +local function inter_tube_transport(tube_state, tube_dir, tube_vpos, is_short, already_transported_to_center) + local connections = tube_state.connections + if connections[6] == nil then + for i = 0, 5 do + if i ~= tube_dir and connections[i] ~= nil then -- one non-empty item from all directions except tube dir gets put into the center + move_connection(tube_state, i, 6, tube_vpos) + break + end + end + elseif connections[tube_dir] == nil and connections[6] ~= nil and not already_transported_to_center then -- if center is empty, the item from the center will come to replace it.. + -- actually don't do this if it is a short tube + if is_short then return end + + move_connection(tube_state, 6, tube_dir, tube_vpos) + inter_tube_transport(tube_state, tube_dir, tube_vpos, is_short, true) -- May look worrysome to some, but makes sense if you think about it + end + + -- FIXME: Drop items which are in impossible places + -- Do that after verifying they can't get there naturally +end + +--- 1 item/update +---@param tube_state stube.TubeState +local function push_items_to_next_tube(next_node, next_pos, tube_state, tube_dir, tube_vpos) + local prefix = stube.get_prefix_tube_name(next_node.name) + local next_tube_def = stube.registered_tubes[prefix] + local next_tube_hpos = core.hash_node_position(next_pos) + local next_tube_state = stubes[prefix][next_tube_hpos] + local is_empty = next_tube_state == nil + local can_insert = true + local next_tube_dir = stube.get_tube_dir(next_node.name) + local opposite_tube_dir = opposite_wallmounted(tube_dir) + + if is_empty == false then + can_insert = next_tube_state.connections[opposite_tube_dir] == nil -- If there isn't an item in the way + end + can_insert = can_insert and next_tube_dir ~= opposite_tube_dir -- And the tube must not be pointing away from us + + if is_empty then + stubes[prefix][next_tube_hpos] = { + connections = {}, + updated_at = stube.current_update_time, + } + next_tube_state = stubes[prefix][next_tube_hpos] + end + + if can_insert then + local item = tube_state.connections[tube_dir] + if not item then return true, next_tube_hpos, next_tube_def, stubes[prefix], prefix end -- There is nothing to push, so don't bother with updating next tubes + + next_tube_state.connections[opposite_tube_dir] = item + tube_state.connections[tube_dir] = nil + + move_connection(next_tube_state, opposite_tube_dir, opposite_tube_dir, next_pos) -- just update entity + + return true, next_tube_hpos, next_tube_def, stubes[prefix], prefix + else + return false, next_tube_hpos, next_tube_def, stubes[prefix], prefix + end +end + +---@param tube_state stube.TubeState +function stube.delete_tube_state(tube_state, tubes_array, tube_hpos) + local tube_vpos = uh(tube_hpos) + for dir, connection in pairs(tube_state.connections) do + if connection.entity then connection.entity:remove() end + local pos = stube.get_precise_connection_pos(tube_vpos, dir) + core.add_item(pos, connection.stack) + end + tubes_array[tube_hpos] = nil +end + +---@param tube_state stube.TubeState +local function delete_if_empty_state(tube_hpos, tube_state, tubes_array) + local empty = true + for i = 0, 6 do + if tube_state.connections[i] ~= nil then + empty = false + break + end + end + if empty then tube_state.to_remove = true end + + if tube_state.to_remove then stube.delete_tube_state(tube_state, tubes_array, tube_hpos) end +end + +--- This is a very recursive function +---@param tube_state stube.TubeState +---@param tube_def stube.TubeDef +---@param tube_hpos integer +---@param prefix string +function stube.update_tube(tube_hpos, tube_def, tube_state, prefix) + if tube_state.updated_at == stube.current_update_time then return end + tube_state.updated_at = stube.current_update_time + + local tube_vpos = uh(tube_hpos) + core.debug('U:' .. tube_vpos.z .. ',' .. tube_state.updated_at .. ' ') + + local this_node = stube.get_or_load_node(tube_vpos) + if stube.get_prefix_tube_name(this_node.name) ~= prefix then + tube_state.to_remove = true + return + end + + if + not tube_def.should_update( + tube_hpos, + tube_state, + stube.get_or_load_node(core.get_position_from_hash(tube_hpos)) + ) + then + return + end -- In cases like short tubes you don't want to update the tube, as there is nowhere that items can go, there basically wouldn't be a next node + + local tube_dir = stube.get_tube_dir(this_node.name) + + if tube_state.connections[tube_dir] ~= nil then + local next_pos, next_node = tube_def.get_next_pos_and_node(tube_hpos, tube_state, tube_dir) + + if IG(next_node.name, 'stube') == 1 then -- Worst case: another tube, oh no xD + local success, next_tube_hpos, next_tube_def, next_tube_type_array, next_tube_prefix = + push_items_to_next_tube(next_node, next_pos, tube_state, tube_dir, tube_vpos) + if success == true then -- HACK: HACK: I don't know how this works but it does + -- So sometimes tubes were randomly going faster than they should??? and this fixed that? + next_tube_type_array[next_tube_hpos].updated_at = stube.current_update_time + end + + if success == false then + ---@diagnostic disable-next-line + stube.update_tube(next_tube_hpos, next_tube_def, next_tube_type_array[next_tube_hpos], next_tube_prefix) + push_items_to_next_tube(next_node, next_pos, tube_state, tube_dir, tube_vpos) + delete_if_empty_state(tube_hpos, tube_state, stubes[prefix]) + end + elseif IG(next_node.name, 'tubedevice_receiver') == 1 then + stube.transfer_items(tube_state, next_node, next_pos, tube_dir) + end + end + inter_tube_transport(tube_state, tube_dir, tube_vpos, stube.is_short_tube(this_node.name)) +end + +function stube.process_tube_type(tube_name, tube_def) + local tubes = stubes[tube_name] + for tube_hpos, tube_state in pairs(tubes) do + stube.update_tube(tube_hpos, tube_def, tube_state, tube_name) + delete_if_empty_state(tube_hpos, tube_state, tubes) + end +end + +---@param dtime number +---@return nil +function stube.globalstep(dtime) + stube.current_update_time = stube.current_update_time + 1 + for name, timer in pairs(timers) do + timer.current = timer.current + dtime + if timer.current >= timer.max then + stube.process_tube_type(name, stube.registered_tubes[name]) + timer.current = 0 + end + end +end +core.register_globalstep(stube.globalstep) + +---@return boolean Success Returns false if it can't +function stube.add_tubed_item(pos, stack) + local hpos = core.hash_node_position(pos) + local node = stube.get_or_load_node(pos) + if core.get_item_group(node.name, 'stube') == 0 then return false end + + local prefix = stube.get_prefix_tube_name(node.name) + local tube_state = stubes[prefix][hpos] + if not tube_state then + stubes[prefix][hpos] = { + connections = {}, + updated_at = stube.current_update_time, + } + tube_state = stubes[prefix][hpos] + end + + local tube_dir = stube.get_tube_dir(node.name) + if tube_state.connections[tube_dir] == nil then + tube_state.connections[tube_dir] = { stack = stack } + stube.add_or_remove_tubestate_visuals(pos, tube_state) + return true + else + return false + end +end + +function stube.tube_input_insert_object(pos, node, stack, vel, owner) + local prefix = stube.get_prefix_tube_name(node.name) + local all_stubes_of_our_type = stubes[prefix] + local hpos = h(pos) + local tube_state = all_stubes_of_our_type[hpos] + if not tube_state then + all_stubes_of_our_type[hpos] = { + connections = {}, + updated_at = stube.current_update_time, + } + tube_state = all_stubes_of_our_type[hpos] + end + + local insert_dir = core.dir_to_wallmounted( + vector.rotate(pipeworks.facedir_to_right_dir(node.param2), vector.new(0, math.pi / 2, 0)) + ) + if tube_state.connections[insert_dir] == nil then + tube_state.connections[insert_dir] = { stack = stack, owner = owner } + stube.add_or_remove_tubestate_visuals(pos, tube_state) + return + else + return stack + end +end diff --git a/mods/stubes/transport.lua b/mods/stubes/transport.lua deleted file mode 100644 index 37d6252a..00000000 --- a/mods/stubes/transport.lua +++ /dev/null @@ -1,212 +0,0 @@ -local h, uh = core.hash_node_position, core.get_position_from_hash - ---- The state of an active tube, doesn't update if the node does, so things like `dir` should not be there ----@class stube.TubeState ----@field items table Not an array ----@field entities? table Not an array ----@field updated_at integer ----@field to_remove? boolean - ----@type table> -local stubes = {} -- A table of all the tubed items, t[tube_name][h(tube_pos)] = TubeState -stube.all_stubes = stubes -stube.current_update_time = 0 -- used in tubed items - -local timers = {} -core.register_on_mods_loaded(function() - for name, def in pairs(stube.registered_tubes) do - timers[name] = { current = 0, max = def.speed } - stubes[name] = {} - end -end) - -local IG = core.get_item_group - ---- Transfer items to foreign nodes (pipeworks receivers), The owner field in pipeworks isn't tracked -function stube.transfer_items(tube_state, tube_def, transfer_to_node, transfer_to_pos, tube_dir) - local next_node_def = core.registered_nodes[transfer_to_node.name] - if next_node_def.tube and next_node_def.tube.insert_object then - for i = tube_def.capacity, 1, -1 do - local stack = tube_state.items[i] - local vel = table.copy(core.wallmounted_to_dir(tube_dir)) - vel.speed = 1 - if stack then - stack = next_node_def.tube.insert_object(transfer_to_pos, transfer_to_node, stack, vel, '') - if stack == nil or stack:is_empty() then - tube_state.items[i] = nil - else - tube_state.items[i] = stack - end - end - end - end -end - ---- Problem: can't trust table length or table.insert with tables that have holes ---- so this has to be the solution, does not seem to be a good one though -local function insert_item(t, v, c) - for i = 1, c do - if t[i] == nil then - t[i] = v - return true - end - end - return false -end - -local function push_items_to_next_tube(next_node, next_pos, tube_def, tube_state) - local prefix = stube.get_prefix_tube_name(next_node.name) - local next_tube_def = stube.registered_tubes[prefix] - local next_tube_hpos = core.hash_node_position(next_pos) - local next_tube_state = stubes[prefix][next_tube_hpos] - local is_empty = next_tube_state == nil -- i love how cheap this is - local can_insert = is_empty and next_tube_def.capacity or 0 - - if next_tube_state then - -- actually check how much we can insert, not just if its empty - local items = next_tube_state.items - - for i = 1, next_tube_def.capacity do - if items[i] == nil then can_insert = can_insert + 1 end - end - end - - if is_empty then - stubes[prefix][next_tube_hpos] = { - items = {}, - updated_at = stube.current_update_time, - } - next_tube_state = stubes[prefix][next_tube_hpos] - end - - if can_insert > 0 then - local inserted = 0 - for i = tube_def.capacity, 1, -1 do - local item = tube_state.items[i] - if item then - inserted = inserted + 1 - if inserted > can_insert then break end - - insert_item(next_tube_state.items, item, next_tube_def.capacity) - tube_state.items[i] = nil - end - end - else - return false, next_tube_hpos, next_tube_def, stubes[prefix], prefix - end -end - -local function delete_if_empty_state(tube_hpos, tube_def, tube_state, tubes_array) - local empty = true - for i = tube_def.capacity, 1, -1 do - if tube_state.items[i] ~= nil then - empty = false - break - end - end - if empty then tube_state.to_remove = true end - - if tube_state.to_remove then tubes_array[tube_hpos] = nil end -end - ---- This is a very recursive function -function stube.update_tube(tube_hpos, tube_def, tube_state, prefix) - if tube_state.updated_at == stube.current_update_time then return end - tube_state.updated_at = stube.current_update_time - if - not tube_def.should_update( - tube_hpos, - tube_state, - sbz_api.get_or_load_node(core.get_position_from_hash(tube_hpos)) - ) - then - return - end -- In cases like short tubes you don't want to update the tube, as there is nowhere that items can go, there basically wouldn't be a next node - - local tube_vpos = uh(tube_hpos) - - local this_node = stube.get_or_load_node(tube_vpos) - if stube.get_prefix_tube_name(this_node.name) ~= prefix then -- innacurate state, as node has changed, get rid of it - tube_state.to_remove = true - return - end - local tube_dir = stube.get_tube_dir(this_node.name) - - local next_pos, next_node = tube_def.get_next_pos_and_node(tube_hpos, tube_state, tube_dir) - - if IG(next_node.name, 'stube') == 1 then -- Worst case: another tube, oh no xD - core.debug 'TRANSFERRING TO ANOTHER STUBE' - -- Need to: - -- 1) If the tube next to it has space - -- 2) If not, repeat step 1 from the tube next to it - -- If you encounter a loop (**checkable by TubeState.updated_at**), or if there just isn't space anywhere, job is done - local success, next_tube_hpos, next_tube_def, next_tube_prefix, next_tube_type_array = - push_items_to_next_tube(next_node, next_pos, tube_def, tube_state) - - if success == false then - core.debug 'NOT SUCCESSFUL' - stube.update_tube(next_tube_hpos, next_tube_def, next_tube_type_array[next_tube_hpos], next_tube_prefix) - delete_if_empty_state(tube_hpos, tube_def, tube_state) - push_items_to_next_tube(next_node, next_pos, tube_def, tube_state) - end - elseif IG(next_node.name, 'tubedevice_receiver') == 1 then - core.debug 'TRANSFERING TO FOREIGN NODE' - stube.transfer_items(tube_state, tube_def, next_node, next_pos, tube_dir) - end - core.debug 'PASSED' -end - -function stube.process_tube_type(tube_name, tube_def) - local tubes = stubes[tube_name] - for tube_hpos, tube_state in pairs(tubes) do - if tube_state.updated_at == stube.current_update_time then return end - stube.update_tube(tube_hpos, tube_def, tube_state, tube_name) - delete_if_empty_state(tube_hpos, tube_def, tube_state, tubes) - end -end - -function stube.globalstep(dtime) - stube.current_update_time = stube.current_update_time + 1 - for name, timer in pairs(timers) do - timer.current = timer.current + dtime - if timer.current >= timer.max then - stube.process_tube_type(name, stube.registered_tubes[name]) - timer.current = 0 - end - end -end -core.register_globalstep(stube.globalstep) - ----@return boolean Success Returns false if it can't -function stube.add_tubed_item(pos, stack) - local hpos = core.hash_node_position(pos) - local node = stube.get_or_load_node(pos) - if core.get_item_group(node.name, 'stube') == 0 then return false end - - local prefix = stube.get_prefix_tube_name(node.name) - local tube_state = stubes[prefix][hpos] - if not tube_state then - stubes[prefix][hpos] = { - items = {}, - updated_at = stube.current_update_time, - } - tube_state = stubes[prefix][hpos] - end - - return insert_item(tube_state.items, stack, stube.registered_tubes[prefix].capacity) -end - -function stube.tube_input_insert_object(pos, node, stack, vel, owner) - local prefix = stube.get_prefix_tube_name(node.name) - local all_stubes_of_our_type = stubes[prefix] - local hpos = h(pos) - local tube_state = all_stubes_of_our_type[hpos] - if not tube_state then - all_stubes_of_our_type[hpos] = { - items = {}, - updated_at = stube.current_update_time, - } - tube_state = all_stubes_of_our_type[hpos] - end - if insert_item(tube_state.items, stack, stube.registered_tubes[prefix].capacity) == false then return stack end -end From e850c4a527d2c2e2c9522329bef25ffafd1b8883 Mon Sep 17 00:00:00 2001 From: TheEt1234 Date: Sun, 28 Sep 2025 19:24:06 +0200 Subject: [PATCH 04/28] STUBES --- mods/stubes/basic_tubes.lua | 55 +++++++++++++++--- mods/stubes/init.lua | 3 + mods/stubes/register.lua | 8 ++- mods/stubes/stube_transport.lua | 1 - mods/stubes/textures/stube_fast_tube.png | Bin 0 -> 519 bytes mods/stubes/textures/stube_very_fast_tube.png | Bin 0 -> 475 bytes 6 files changed, 57 insertions(+), 10 deletions(-) create mode 100644 mods/stubes/textures/stube_fast_tube.png create mode 100644 mods/stubes/textures/stube_very_fast_tube.png diff --git a/mods/stubes/basic_tubes.lua b/mods/stubes/basic_tubes.lua index e5a7e3da..3d5d8a14 100644 --- a/mods/stubes/basic_tubes.lua +++ b/mods/stubes/basic_tubes.lua @@ -1,5 +1,7 @@ -stube.register_tube('stubes:test_tube', { - description = 'Test Tube', +--- FIXME: Unified dyes support +stube.register_tube('stubes:basic_tube', { + paramtype2 = 'color', + description = 'Basic Item Tube', use_texture_alpha = 'blend', groups = { matter = 1 }, after_dig_node = stube.update_placement, @@ -13,9 +15,48 @@ stube.register_tube('stubes:test_tube', { textures = stube.make_tube_textures_from 'stube_basic_tube.png', speed = 1, -- seconds/stack should_update = stube.default_should_update_tube, - get_next_pos_and_node = function(tube_hpos, tube_state, tube_dir) - local cdir = core.wallmounted_to_dir(tube_dir) - local pos = core.get_position_from_hash(tube_hpos) + cdir - return pos, stube.get_or_load_node(pos) - end, + get_next_pos_and_node = stube.default_get_next_pos_and_node, }) + +--- Game design: This tube should be a lot more expensive than the basic tube +--- Because it's basically 3 basic tubes in one node +stube.register_tube('stubes:fast_tube', { + paramtype2 = 'color', + description = 'Fast Item Tube', + use_texture_alpha = 'blend', + groups = { matter = 1 }, + after_dig_node = stube.update_placement, + on_punch = stube.default_tube_punch, + + drawtype = 'nodebox', + sunlight_propagates = true, + paramtype = 'light', +}, { + textures = stube.make_tube_textures_from 'stube_fast_tube.png', + speed = 1 / 3, -- 3x faster!! + should_update = stube.default_should_update_tube, + get_next_pos_and_node = stube.default_get_next_pos_and_node, +}) + +--- Game design: Let the player have some fun, at a huge cost +--- Actually just kidding it's just 2x faster than pipeworks, and as fast as accelerator tubes +--- so not that fun +stube.register_tube('stubes:very_fast_tube', { + description = core.colorize('cyan', 'Very ') .. 'Fast Item Tube', + use_texture_alpha = 'blend', + groups = { matter = 1 }, + after_dig_node = stube.update_placement, + on_punch = stube.default_tube_punch, + + drawtype = 'nodebox', + sunlight_propagates = true, + paramtype = 'light', +}, { + textures = stube.make_tube_textures_from 'stube_very_fast_tube.png', + speed = 1 / 10, + should_update = stube.default_should_update_tube, + get_next_pos_and_node = stube.default_get_next_pos_and_node, +}) + +-- Excercise for the viewer: You can make your own TRULY FAST TUBE +-- Copy the definition for very_fast_tube, change the speed to zero, and change the name diff --git a/mods/stubes/init.lua b/mods/stubes/init.lua index 4892b719..ade362a7 100644 --- a/mods/stubes/init.lua +++ b/mods/stubes/init.lua @@ -15,6 +15,9 @@ stube = { -- The globalstep for creating/removing entities will be run every seconds entity_creation_globalstep_time = 1, + + -- For simplicity, each tube must be the same size (simplicity in: each tubed item has to be the same size) + tube_size = 3 / 16, } --- Creating a utils file is silly, so i am putting it here diff --git a/mods/stubes/register.lua b/mods/stubes/register.lua index 6fc16b47..6bb1fc79 100644 --- a/mods/stubes/register.lua +++ b/mods/stubes/register.lua @@ -26,7 +26,6 @@ local function tube_nodebox(len, stretch_to) end return base_box end -stube.tube_size = 3 / 16 --- e* -> expected --- so edir = expected dir @@ -188,7 +187,7 @@ function stube.register_tube(name, def, tubedef) } -- Alias - core.register_alias('stubes:test_tube', 'stubes:test_tube_0000000') + core.register_alias(name, name .. '_0000000') def.drop = 'stubes:test_tube' -- i saw what pipeworks was doing, so i think i am going with whatever this "old aproach" is https://github.com/mt-mods/pipeworks/blob/6e11868d1b32d316d60061c78460d260ac92ed6a/tubes/registration.lua#L176 @@ -304,3 +303,8 @@ function stube.default_should_update_tube(tube_hpos, tube_state, node) -- Don't update if its a short tube return not stube.is_short_tube(node.name) end +function stube.default_get_next_pos_and_node(tube_hpos, tube_state, tube_dir) + local cdir = core.wallmounted_to_dir(tube_dir) + local pos = core.get_position_from_hash(tube_hpos) + cdir + return pos, stube.get_or_load_node(pos) +end diff --git a/mods/stubes/stube_transport.lua b/mods/stubes/stube_transport.lua index 3131d11b..7f31c9e5 100644 --- a/mods/stubes/stube_transport.lua +++ b/mods/stubes/stube_transport.lua @@ -189,7 +189,6 @@ function stube.update_tube(tube_hpos, tube_def, tube_state, prefix) tube_state.updated_at = stube.current_update_time local tube_vpos = uh(tube_hpos) - core.debug('U:' .. tube_vpos.z .. ',' .. tube_state.updated_at .. ' ') local this_node = stube.get_or_load_node(tube_vpos) if stube.get_prefix_tube_name(this_node.name) ~= prefix then diff --git a/mods/stubes/textures/stube_fast_tube.png b/mods/stubes/textures/stube_fast_tube.png new file mode 100644 index 0000000000000000000000000000000000000000..3b6cf1c07c8553f8383738c8afe9edd51efc97b2 GIT binary patch literal 519 zcmV+i0{H!jP)Px$!AV3xRCt{2n?Y{FAP_~dln@o*A7lU+830BGfa!8%jXC)G{8+W& z)iN%508I3(@-u2_CdRg_4L`2)_xWwR%g@C*7eD@CnogIBtLIYq7WMn7Xo<6x(BQS| z`|pOou~xtL4=J5k%bd5htglTNrgv_BX6((}Olw)c_$GXRTsyBBx_eFfsY_L;KhQ_H z1pi52nJ|nt;aZ6Ox4%SHf+c-<0E`R(BLl$505F>ja6FtwvN+0uzDg5e{UigtD^4we zCH+lH(Au-`y|JLL(!^Tyt!AP$3PWKOhQcTeg;5v^qc9XkVJM95h`}ffg^>YZny-qW ztGML>wP5uuhNk)Z0d(}#{QZF3dQ0ej0E{+a7~Kzm>52OR{y99)C-igcEus4XFv^6L z35zJ`OqkZsg**U827r+PU}OLo6=uPxFbhV7SuiThf>B`>%r5}laoTJ=2(thH002ov JPDHLkV1jw%>>2<7 literal 0 HcmV?d00001 diff --git a/mods/stubes/textures/stube_very_fast_tube.png b/mods/stubes/textures/stube_very_fast_tube.png new file mode 100644 index 0000000000000000000000000000000000000000..f7a9afdfc51a83948dd3b1bdaba57710b20226e3 GIT binary patch literal 475 zcmeAS@N?(olHy`uVBq!ia0vp^2|(q-aZ3fBAwN}G3-%{4P#;yd@&<|QZC;uMu70<PZz2Ftvfke!&Cd0 zr|5?F+hfmcjM=heehj0k_?=Drd?nnN6HFL@#4efOWIj9ldugV7qpqd09&oV_eJuR- z{$z>j*xa7iRkii=_Pl%fQME;2|37b5ne)pR9x18xPG9>=ocY*6rRTmq|7}e@uPxgD ze*4|;@vHXPf{Zj_c;+t5r}*A|-OBGdxxbQ)=U(2k{^j@m{?DFGI~VnJZcE}D#;q5! zv>LB%XM#AwgduHXOu)-2PTIfJ9w+=gTI9HNa@N`xvwNDq<{mOQxqiV`!QZ-B@65He zLFUgvLOF*Fq!<=68m#try`Y(=y+G_mh|}sF_6*1VG8%kikl<~&$RP2Z{QyYB^M+@{ zq6O-SQTF0t3_WZIGC;%(?j}QVmSjDSV=)3fz7o&4ZDy^iU3|UvH!!vsJYD@<);T3K F0RW3O%AEiJ literal 0 HcmV?d00001 From fe52347902409a9a1e9e2c603b426d88467f23af Mon Sep 17 00:00:00 2001 From: TheEt1234 Date: Mon, 29 Sep 2025 20:25:05 +0200 Subject: [PATCH 05/28] Make stubes not in creative inventory --- mods/stubes/basic_tubes.lua | 7 ++++--- mods/stubes/register.lua | 4 +++- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/mods/stubes/basic_tubes.lua b/mods/stubes/basic_tubes.lua index 3d5d8a14..211e7263 100644 --- a/mods/stubes/basic_tubes.lua +++ b/mods/stubes/basic_tubes.lua @@ -1,9 +1,10 @@ +local testing = 1 --- FIXME: Unified dyes support stube.register_tube('stubes:basic_tube', { paramtype2 = 'color', description = 'Basic Item Tube', use_texture_alpha = 'blend', - groups = { matter = 1 }, + groups = { matter = 1, not_in_creative_inventory = testing }, after_dig_node = stube.update_placement, on_punch = stube.default_tube_punch, @@ -24,7 +25,7 @@ stube.register_tube('stubes:fast_tube', { paramtype2 = 'color', description = 'Fast Item Tube', use_texture_alpha = 'blend', - groups = { matter = 1 }, + groups = { matter = 1, not_in_creative_inventory = testing }, after_dig_node = stube.update_placement, on_punch = stube.default_tube_punch, @@ -44,7 +45,7 @@ stube.register_tube('stubes:fast_tube', { stube.register_tube('stubes:very_fast_tube', { description = core.colorize('cyan', 'Very ') .. 'Fast Item Tube', use_texture_alpha = 'blend', - groups = { matter = 1 }, + groups = { matter = 1, not_in_creative_inventory = testing }, after_dig_node = stube.update_placement, on_punch = stube.default_tube_punch, diff --git a/mods/stubes/register.lua b/mods/stubes/register.lua index 6bb1fc79..1198d25e 100644 --- a/mods/stubes/register.lua +++ b/mods/stubes/register.lua @@ -164,7 +164,9 @@ local function register_single_tube(name, def, tubedef, dir, xc, yc, zc, nxc, ny end end - if not stube.debug then def.groups.not_in_creative_inventory = visible and 0 or 1 end + if not stube.debug and not def.groups.not_in_creative_inventory then + def.groups.not_in_creative_inventory = visible and 0 or 1 + end if visible then def.after_place_node = stube.tube_after_place end core.register_node(name, def) From c91b6f5ca6b62888895493d5a8637647f583b659 Mon Sep 17 00:00:00 2001 From: TheEt1234 Date: Mon, 29 Sep 2025 21:03:41 +0200 Subject: [PATCH 06/28] Fix #189 --- mods/sbz_pipeworks/autocrafter.lua | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/mods/sbz_pipeworks/autocrafter.lua b/mods/sbz_pipeworks/autocrafter.lua index fde3705a..1174f630 100644 --- a/mods/sbz_pipeworks/autocrafter.lua +++ b/mods/sbz_pipeworks/autocrafter.lua @@ -306,6 +306,7 @@ local function on_output_change(pos, inventory, stack) else local input = minetest.get_craft_recipe(stack:get_name()) if not input.items or input.type ~= 'normal' then return end + local items, width = normalize(input.items), input.width local item_idx, width_idx = 1, 1 for i = 1, 9 do @@ -434,13 +435,16 @@ minetest.register_node('pipeworks:autocrafter', { if not slots[stack:get_name()] then return false end -- next up, check if we actually can insert local compare_stack = ItemStack(stack) + core.debug('first:' .. compare_stack:to_string()) for i = 1, 9 do if slots[i] == stack:get_name() then local that_stack = inv:get_stack('src', i) + if that_stack:get_name() == '' then that_stack:set_count(0) end -- FIX #189 local leftover = that_stack:add_item(stack):get_count() compare_stack:set_count(leftover) end end + core.debug('second:' .. compare_stack:get_count()) return compare_stack:get_count() == 0 end, From 39547f33378ae5684992fa4565132d79402a2ebd Mon Sep 17 00:00:00 2001 From: TheEt1234 Date: Wed, 1 Oct 2025 18:57:48 +0200 Subject: [PATCH 07/28] a commit --- mods/stubes/routing_blocks.lua | 20 ++++++++++++++++++++ mods/stubes/stube_transport.lua | 4 ++++ 2 files changed, 24 insertions(+) create mode 100644 mods/stubes/routing_blocks.lua diff --git a/mods/stubes/routing_blocks.lua b/mods/stubes/routing_blocks.lua new file mode 100644 index 00000000..b60b80c7 --- /dev/null +++ b/mods/stubes/routing_blocks.lua @@ -0,0 +1,20 @@ +-- Group: `stube_routing_node`=1 +-- Transport is handled in stube_transport.lua + +---@class stube.RoutingState: table +---@field items { [any]: stube.TubedItem } Routing nodes can organize items hovewer they like +---@field updated_at number +---@field to_remove? boolean + +---@class stube.RoutingNodeDef +---@field update fun(state:stube.RoutingState, hpos: number):nil +---@field accept fun(state:stube.RoutingState, tubed_item:stube.TubedItem, dir: table):boolean +---@field speed number Delay between updates, but routing nodes always update after tubes + +---@type { [string]: stube.RoutingNodeDef } +stube.registered_routing_node = {} + +function stube.register_routing_node(name, def, routing_def) + stube.registered_routing_node[name] = routing_def + core.register_node(name, def) +end diff --git a/mods/stubes/stube_transport.lua b/mods/stubes/stube_transport.lua index 7f31c9e5..19db7810 100644 --- a/mods/stubes/stube_transport.lua +++ b/mods/stubes/stube_transport.lua @@ -251,6 +251,7 @@ function stube.globalstep(dtime) timer.current = 0 end end + stube.routing_globalstep(dtime) end core.register_globalstep(stube.globalstep) @@ -304,3 +305,6 @@ function stube.tube_input_insert_object(pos, node, stack, vel, owner) return stack end end + +--- Called by stube.globalstep +function stube.routing_globalstep(dtime) end From 93747621e15c7d2895c0cf4a6cf087f3df34f7e2 Mon Sep 17 00:00:00 2001 From: TheEt1234 Date: Fri, 3 Oct 2025 19:51:05 +0200 Subject: [PATCH 08/28] Submodules experiment #01 --- .gitmodules | 3 + CHANGELOG.md | 43 +- mods/hotbar_switching | 1 + mods/hotbar_switching/LICENSE.txt | 13 - mods/hotbar_switching/README.md | 37 - mods/hotbar_switching/init.lua | 67 - mods/hotbar_switching/mod.conf | 2 - mods/sbz_base/init.lua | 15 +- mods/sbz_base/pick_block.lua | 51 + mods/sbz_multiblocks/large_liquid_storage.lua | 355 ++-- mods/sbz_pipeworks/autocrafter.lua | 24 +- types/core.d.lua | 836 -------- types/luanti_lsp_definitions/.cspell.json | 22 + types/luanti_lsp_definitions/.gitignore | 37 + types/luanti_lsp_definitions/.luarc.json | 4 + types/luanti_lsp_definitions/CHANGELOG.md | 0 types/luanti_lsp_definitions/LICENSE | 38 + types/luanti_lsp_definitions/MAINTENANCE.md | 141 ++ types/luanti_lsp_definitions/README.md | 135 ++ types/luanti_lsp_definitions/config.json | 21 + .../library/classes/AreaStore.lua | 301 +++ .../library/classes/AsyncJob.lua | 16 + .../library/classes/InvRef.lua | 156 ++ .../library/classes/ItemStack.lua | 268 +++ .../library/classes/ItemStackMetaRef.lua | 113 + .../library/classes/MetaDataRef.lua | 100 + .../library/classes/ModChannel.lua | 35 + .../library/classes/NodeMetaRef.lua | 118 ++ .../library/classes/NodeTimer.lua | 53 + .../library/classes/ObjectRef/EntityRef.lua | 176 ++ .../library/classes/ObjectRef/ObjectRef.lua | 373 ++++ .../library/classes/ObjectRef/PlayerRef.lua | 549 +++++ .../library/classes/ObjectRef/bones.lua | 150 ++ .../library/classes/ObjectRef/nametag.lua | 80 + .../classes/ObjectRef/player_clouds.lua | 107 + .../classes/ObjectRef/player_control.lua | 110 + .../classes/ObjectRef/player_flags.lua | 63 + .../classes/ObjectRef/player_hud_flags.lua | 112 + .../classes/ObjectRef/player_lighting.lua | 219 ++ .../classes/ObjectRef/player_minimap.lua | 71 + .../library/classes/ObjectRef/player_moon.lua | 66 + .../ObjectRef/player_physics_override.lua | 162 ++ .../classes/ObjectRef/player_skybox.lua | 368 ++++ .../library/classes/ObjectRef/player_star.lua | 89 + .../library/classes/ObjectRef/player_sun.lua | 82 + .../library/classes/PcgRandom.lua | 66 + .../library/classes/PlayerMetaRef.lua | 100 + .../library/classes/PseudoRandom.lua | 59 + .../library/classes/Raycast.lua | 177 ++ .../library/classes/SecureRandom.lua | 40 + .../LuantiSettings/LuantiSettings.lua | 266 +++ .../Settings/LuantiSettings/advanced.lua | 1398 ++++++++++++ .../LuantiSettings/client_and_server.lua | 490 +++++ .../Settings/LuantiSettings/controls.lua | 700 ++++++ .../LuantiSettings/graphics_and_audio.lua | 1032 +++++++++ .../Settings/LuantiSettings/mapgen.lua | 1888 +++++++++++++++++ .../LuantiSettings/settings_enums.lua | 60 + .../LuantiSettings/settings_flags.lua | 48 + .../library/classes/Settings/Settings.lua | 188 ++ .../library/classes/StorageRef.lua | 126 ++ .../library/classes/ValueNoise.lua | 171 ++ .../library/classes/ValueNoiseMap.lua | 169 ++ .../library/classes/VoxelArea.lua | 129 ++ .../library/classes/VoxelManip.lua | 325 +++ .../library/core/async_environment.lua | 38 + .../library/core/authentication.lua | 185 ++ .../library/core/ban.lua | 61 + .../library/core/chat.lua | 30 + .../library/core/core.lua | 24 + .../library/core/defaults.lua | 156 ++ .../library/core/environment/biome_data.lua | 33 + .../library/core/environment/emerge_area.lua | 75 + .../library/core/environment/environment.lua | 946 +++++++++ .../core/environment/mapgen_params.lua | 69 + .../library/core/escape_sequences.lua | 66 + .../library/core/formspec_functions.lua | 145 ++ .../library/core/global_tables.lua | 332 +++ .../library/core/http.lua | 66 + .../library/core/inventory.lua | 93 + .../library/core/ipc.lua | 69 + .../core/item_handling/craft_result.lua | 285 +++ .../core/item_handling/item_handling.lua | 167 ++ .../library/core/logging.lua | 35 + .../library/core/mapgen_environment.lua | 70 + .../library/core/misc/get_group.lua | 145 ++ .../core/misc/insecure_environment.lua | 26 + .../library/core/misc/misc.lua | 596 ++++++ .../library/core/mod_channels.lua | 11 + .../library/core/particles.lua | 72 + .../library/core/register/cheat.lua | 48 + .../library/core/register/environment.lua | 150 ++ .../library/core/register/gameplay.lua | 49 + .../library/core/register/global_callback.lua | 451 ++++ .../library/core/register/hpchange.lua | 155 ++ .../core/register/inventory_action.lua | 114 + .../core/register/player_receive_fields.lua | 73 + .../library/core/register/playerevent.lua | 28 + .../library/core/rollback.lua | 54 + .../library/core/schematics.lua | 168 ++ .../library/core/server/dynamic_media.lua | 69 + .../library/core/server/server.lua | 76 + .../library/core/settings.lua | 14 + .../library/core/sounds.lua | 48 + .../library/core/timing.lua | 32 + .../library/core/translations.lua | 87 + .../library/core/utilities/dig_params.lua | 54 + .../library/core/utilities/engine_version.lua | 48 + .../library/core/utilities/features.lua | 314 +++ .../library/core/utilities/game_info.lua | 35 + .../library/core/utilities/helpers.lua | 102 + .../library/core/utilities/hit_params.lua | 41 + .../core/utilities/player_information.lua | 131 ++ .../core/utilities/protocol_versions.lua | 89 + .../library/core/utilities/utilities.lua | 208 ++ .../library/defs/HTTPRequest.lua | 60 + .../library/defs/HTTPRequestResult.lua | 29 + .../library/defs/abm.lua | 76 + .../library/defs/aliases.lua | 71 + .../library/defs/authentication_handler.lua | 106 + .../library/defs/biome.lua | 143 ++ .../library/defs/chat_command.lua | 92 + .../library/defs/colors.lua | 208 ++ .../library/defs/crafting/cooking.lua | 60 + .../library/defs/crafting/crafting.lua | 58 + .../library/defs/crafting/fuel.lua | 54 + .../library/defs/crafting/shaped.lua | 65 + .../library/defs/crafting/shapeless.lua | 47 + .../library/defs/crafting/toolrepair.lua | 52 + .../library/defs/decoration/decoration.lua | 259 +++ .../library/defs/decoration/flags.lua | 96 + .../library/defs/detached_inventory.lua | 62 + .../library/defs/entity/collision.lua | 62 + .../library/defs/entity/entity.lua | 140 ++ .../library/defs/entity/moveresult.lua | 26 + .../library/defs/formspec.lua | 8 + .../library/defs/group.lua | 172 ++ .../library/defs/hud/compass.lua | 65 + .../library/defs/hud/hotbar.lua | 13 + .../library/defs/hud/hud.lua | 100 + .../library/defs/hud/image.lua | 21 + .../library/defs/hud/image_waypoint.lua | 24 + .../library/defs/hud/inventory.lua | 25 + .../library/defs/hud/minimap.lua | 17 + .../library/defs/hud/statbar.lua | 33 + .../library/defs/hud/text.lua | 46 + .../library/defs/hud/waypoint.lua | 25 + .../library/defs/inventory.lua | 83 + .../library/defs/item/item.lua | 70 + .../library/defs/item/itemdef.lua | 282 +++ .../library/defs/item/pointabilities.lua | 43 + .../library/defs/item/sound.lua | 34 + .../library/defs/item/touch_interaction.lua | 55 + .../library/defs/lbm.lua | 96 + .../library/defs/lsystem.lua | 126 ++ .../library/defs/mapgen_objects.lua | 158 ++ .../library/defs/metadata/item.lua | 120 ++ .../library/defs/metadata/metadata.lua | 50 + .../library/defs/metadata/node.lua | 87 + .../library/defs/metadata/player.lua | 61 + .../library/defs/metadata/storage.lua | 61 + .../library/defs/node/drawtype.lua | 37 + .../library/defs/node/drop.lua | 61 + .../library/defs/node/node.lua | 155 ++ .../library/defs/node/nodebox.lua | 182 ++ .../library/defs/node/nodedef.lua | 821 +++++++ .../library/defs/node/paramtype.lua | 72 + .../library/defs/node/sounds.lua | 42 + .../library/defs/node/tiles.lua | 85 + .../library/defs/noiseparams.lua | 209 ++ .../library/defs/object_properties/box.lua | 109 + .../object_properties/object_properties.lua | 300 +++ .../partial/backface_clling.lua | 17 + .../defs/object_properties/partial/shaded.lua | 19 + .../object_properties/partial/spritesheet.lua | 33 + .../object_properties/player_properties.lua | 111 + .../defs/object_properties/types/cube.lua | 85 + .../defs/object_properties/types/item.lua | 19 + .../defs/object_properties/types/mesh.lua | 55 + .../defs/object_properties/types/node.lua | 33 + .../defs/object_properties/types/sprite.lua | 64 + .../types/upright_sprite.lua | 69 + .../object_properties/types/wielditem.lua | 66 + .../library/defs/ore/blob.lua | 43 + .../library/defs/ore/ore.lua | 58 + .../library/defs/ore/puff.lua | 92 + .../library/defs/ore/scatter.lua | 55 + .../library/defs/ore/sheet.lua | 45 + .../library/defs/ore/stratum.lua | 35 + .../library/defs/ore/vein.lua | 31 + .../library/defs/particle/ParticleSpawner.lua | 197 ++ .../library/defs/particle/attract.lua | 57 + .../library/defs/particle/particle.lua | 115 + .../library/defs/particle/texture.lua | 58 + .../library/defs/particle/type.lua | 133 ++ .../library/defs/pointed_thing.lua | 99 + .../library/defs/privilege.lua | 152 ++ .../library/defs/schematics.lua | 155 ++ .../library/defs/sound.lua | 81 + .../library/defs/textures.lua | 8 + .../library/defs/tile.lua | 134 ++ .../library/defs/tool_capabilities.lua | 96 + .../library/defs/wear_bar_color.lua | 23 + .../library/helpers.lua | 203 ++ types/luanti_lsp_definitions/library/misc.lua | 66 + .../library/vector/vec.lua | 95 + .../library/vector/vector.lua | 35 + .../library/vector/vectorlib.lua | 377 ++++ .../utils/.cspell-luanti.txt | 40 + .../utils/.cspell-misc.txt | 7 + .../utils/LGPLv2.1..txt | 501 +++++ 210 files changed, 27753 insertions(+), 1170 deletions(-) create mode 160000 mods/hotbar_switching delete mode 100644 mods/hotbar_switching/LICENSE.txt delete mode 100644 mods/hotbar_switching/README.md delete mode 100644 mods/hotbar_switching/init.lua delete mode 100644 mods/hotbar_switching/mod.conf create mode 100644 mods/sbz_base/pick_block.lua delete mode 100644 types/core.d.lua create mode 100644 types/luanti_lsp_definitions/.cspell.json create mode 100644 types/luanti_lsp_definitions/.gitignore create mode 100644 types/luanti_lsp_definitions/.luarc.json create mode 100644 types/luanti_lsp_definitions/CHANGELOG.md create mode 100644 types/luanti_lsp_definitions/LICENSE create mode 100644 types/luanti_lsp_definitions/MAINTENANCE.md create mode 100644 types/luanti_lsp_definitions/README.md create mode 100644 types/luanti_lsp_definitions/config.json create mode 100644 types/luanti_lsp_definitions/library/classes/AreaStore.lua create mode 100644 types/luanti_lsp_definitions/library/classes/AsyncJob.lua create mode 100644 types/luanti_lsp_definitions/library/classes/InvRef.lua create mode 100644 types/luanti_lsp_definitions/library/classes/ItemStack.lua create mode 100644 types/luanti_lsp_definitions/library/classes/ItemStackMetaRef.lua create mode 100644 types/luanti_lsp_definitions/library/classes/MetaDataRef.lua create mode 100644 types/luanti_lsp_definitions/library/classes/ModChannel.lua create mode 100644 types/luanti_lsp_definitions/library/classes/NodeMetaRef.lua create mode 100644 types/luanti_lsp_definitions/library/classes/NodeTimer.lua create mode 100644 types/luanti_lsp_definitions/library/classes/ObjectRef/EntityRef.lua create mode 100644 types/luanti_lsp_definitions/library/classes/ObjectRef/ObjectRef.lua create mode 100644 types/luanti_lsp_definitions/library/classes/ObjectRef/PlayerRef.lua create mode 100644 types/luanti_lsp_definitions/library/classes/ObjectRef/bones.lua create mode 100644 types/luanti_lsp_definitions/library/classes/ObjectRef/nametag.lua create mode 100644 types/luanti_lsp_definitions/library/classes/ObjectRef/player_clouds.lua create mode 100644 types/luanti_lsp_definitions/library/classes/ObjectRef/player_control.lua create mode 100644 types/luanti_lsp_definitions/library/classes/ObjectRef/player_flags.lua create mode 100644 types/luanti_lsp_definitions/library/classes/ObjectRef/player_hud_flags.lua create mode 100644 types/luanti_lsp_definitions/library/classes/ObjectRef/player_lighting.lua create mode 100644 types/luanti_lsp_definitions/library/classes/ObjectRef/player_minimap.lua create mode 100644 types/luanti_lsp_definitions/library/classes/ObjectRef/player_moon.lua create mode 100644 types/luanti_lsp_definitions/library/classes/ObjectRef/player_physics_override.lua create mode 100644 types/luanti_lsp_definitions/library/classes/ObjectRef/player_skybox.lua create mode 100644 types/luanti_lsp_definitions/library/classes/ObjectRef/player_star.lua create mode 100644 types/luanti_lsp_definitions/library/classes/ObjectRef/player_sun.lua create mode 100644 types/luanti_lsp_definitions/library/classes/PcgRandom.lua create mode 100644 types/luanti_lsp_definitions/library/classes/PlayerMetaRef.lua create mode 100644 types/luanti_lsp_definitions/library/classes/PseudoRandom.lua create mode 100644 types/luanti_lsp_definitions/library/classes/Raycast.lua create mode 100644 types/luanti_lsp_definitions/library/classes/SecureRandom.lua create mode 100644 types/luanti_lsp_definitions/library/classes/Settings/LuantiSettings/LuantiSettings.lua create mode 100644 types/luanti_lsp_definitions/library/classes/Settings/LuantiSettings/advanced.lua create mode 100644 types/luanti_lsp_definitions/library/classes/Settings/LuantiSettings/client_and_server.lua create mode 100644 types/luanti_lsp_definitions/library/classes/Settings/LuantiSettings/controls.lua create mode 100644 types/luanti_lsp_definitions/library/classes/Settings/LuantiSettings/graphics_and_audio.lua create mode 100644 types/luanti_lsp_definitions/library/classes/Settings/LuantiSettings/mapgen.lua create mode 100644 types/luanti_lsp_definitions/library/classes/Settings/LuantiSettings/settings_enums.lua create mode 100644 types/luanti_lsp_definitions/library/classes/Settings/LuantiSettings/settings_flags.lua create mode 100644 types/luanti_lsp_definitions/library/classes/Settings/Settings.lua create mode 100644 types/luanti_lsp_definitions/library/classes/StorageRef.lua create mode 100644 types/luanti_lsp_definitions/library/classes/ValueNoise.lua create mode 100644 types/luanti_lsp_definitions/library/classes/ValueNoiseMap.lua create mode 100644 types/luanti_lsp_definitions/library/classes/VoxelArea.lua create mode 100644 types/luanti_lsp_definitions/library/classes/VoxelManip.lua create mode 100644 types/luanti_lsp_definitions/library/core/async_environment.lua create mode 100644 types/luanti_lsp_definitions/library/core/authentication.lua create mode 100644 types/luanti_lsp_definitions/library/core/ban.lua create mode 100644 types/luanti_lsp_definitions/library/core/chat.lua create mode 100644 types/luanti_lsp_definitions/library/core/core.lua create mode 100644 types/luanti_lsp_definitions/library/core/defaults.lua create mode 100644 types/luanti_lsp_definitions/library/core/environment/biome_data.lua create mode 100644 types/luanti_lsp_definitions/library/core/environment/emerge_area.lua create mode 100644 types/luanti_lsp_definitions/library/core/environment/environment.lua create mode 100644 types/luanti_lsp_definitions/library/core/environment/mapgen_params.lua create mode 100644 types/luanti_lsp_definitions/library/core/escape_sequences.lua create mode 100644 types/luanti_lsp_definitions/library/core/formspec_functions.lua create mode 100644 types/luanti_lsp_definitions/library/core/global_tables.lua create mode 100644 types/luanti_lsp_definitions/library/core/http.lua create mode 100644 types/luanti_lsp_definitions/library/core/inventory.lua create mode 100644 types/luanti_lsp_definitions/library/core/ipc.lua create mode 100644 types/luanti_lsp_definitions/library/core/item_handling/craft_result.lua create mode 100644 types/luanti_lsp_definitions/library/core/item_handling/item_handling.lua create mode 100644 types/luanti_lsp_definitions/library/core/logging.lua create mode 100644 types/luanti_lsp_definitions/library/core/mapgen_environment.lua create mode 100644 types/luanti_lsp_definitions/library/core/misc/get_group.lua create mode 100644 types/luanti_lsp_definitions/library/core/misc/insecure_environment.lua create mode 100644 types/luanti_lsp_definitions/library/core/misc/misc.lua create mode 100644 types/luanti_lsp_definitions/library/core/mod_channels.lua create mode 100644 types/luanti_lsp_definitions/library/core/particles.lua create mode 100644 types/luanti_lsp_definitions/library/core/register/cheat.lua create mode 100644 types/luanti_lsp_definitions/library/core/register/environment.lua create mode 100644 types/luanti_lsp_definitions/library/core/register/gameplay.lua create mode 100644 types/luanti_lsp_definitions/library/core/register/global_callback.lua create mode 100644 types/luanti_lsp_definitions/library/core/register/hpchange.lua create mode 100644 types/luanti_lsp_definitions/library/core/register/inventory_action.lua create mode 100644 types/luanti_lsp_definitions/library/core/register/player_receive_fields.lua create mode 100644 types/luanti_lsp_definitions/library/core/register/playerevent.lua create mode 100644 types/luanti_lsp_definitions/library/core/rollback.lua create mode 100644 types/luanti_lsp_definitions/library/core/schematics.lua create mode 100644 types/luanti_lsp_definitions/library/core/server/dynamic_media.lua create mode 100644 types/luanti_lsp_definitions/library/core/server/server.lua create mode 100644 types/luanti_lsp_definitions/library/core/settings.lua create mode 100644 types/luanti_lsp_definitions/library/core/sounds.lua create mode 100644 types/luanti_lsp_definitions/library/core/timing.lua create mode 100644 types/luanti_lsp_definitions/library/core/translations.lua create mode 100644 types/luanti_lsp_definitions/library/core/utilities/dig_params.lua create mode 100644 types/luanti_lsp_definitions/library/core/utilities/engine_version.lua create mode 100644 types/luanti_lsp_definitions/library/core/utilities/features.lua create mode 100644 types/luanti_lsp_definitions/library/core/utilities/game_info.lua create mode 100644 types/luanti_lsp_definitions/library/core/utilities/helpers.lua create mode 100644 types/luanti_lsp_definitions/library/core/utilities/hit_params.lua create mode 100644 types/luanti_lsp_definitions/library/core/utilities/player_information.lua create mode 100644 types/luanti_lsp_definitions/library/core/utilities/protocol_versions.lua create mode 100644 types/luanti_lsp_definitions/library/core/utilities/utilities.lua create mode 100644 types/luanti_lsp_definitions/library/defs/HTTPRequest.lua create mode 100644 types/luanti_lsp_definitions/library/defs/HTTPRequestResult.lua create mode 100644 types/luanti_lsp_definitions/library/defs/abm.lua create mode 100644 types/luanti_lsp_definitions/library/defs/aliases.lua create mode 100644 types/luanti_lsp_definitions/library/defs/authentication_handler.lua create mode 100644 types/luanti_lsp_definitions/library/defs/biome.lua create mode 100644 types/luanti_lsp_definitions/library/defs/chat_command.lua create mode 100644 types/luanti_lsp_definitions/library/defs/colors.lua create mode 100644 types/luanti_lsp_definitions/library/defs/crafting/cooking.lua create mode 100644 types/luanti_lsp_definitions/library/defs/crafting/crafting.lua create mode 100644 types/luanti_lsp_definitions/library/defs/crafting/fuel.lua create mode 100644 types/luanti_lsp_definitions/library/defs/crafting/shaped.lua create mode 100644 types/luanti_lsp_definitions/library/defs/crafting/shapeless.lua create mode 100644 types/luanti_lsp_definitions/library/defs/crafting/toolrepair.lua create mode 100644 types/luanti_lsp_definitions/library/defs/decoration/decoration.lua create mode 100644 types/luanti_lsp_definitions/library/defs/decoration/flags.lua create mode 100644 types/luanti_lsp_definitions/library/defs/detached_inventory.lua create mode 100644 types/luanti_lsp_definitions/library/defs/entity/collision.lua create mode 100644 types/luanti_lsp_definitions/library/defs/entity/entity.lua create mode 100644 types/luanti_lsp_definitions/library/defs/entity/moveresult.lua create mode 100644 types/luanti_lsp_definitions/library/defs/formspec.lua create mode 100644 types/luanti_lsp_definitions/library/defs/group.lua create mode 100644 types/luanti_lsp_definitions/library/defs/hud/compass.lua create mode 100644 types/luanti_lsp_definitions/library/defs/hud/hotbar.lua create mode 100644 types/luanti_lsp_definitions/library/defs/hud/hud.lua create mode 100644 types/luanti_lsp_definitions/library/defs/hud/image.lua create mode 100644 types/luanti_lsp_definitions/library/defs/hud/image_waypoint.lua create mode 100644 types/luanti_lsp_definitions/library/defs/hud/inventory.lua create mode 100644 types/luanti_lsp_definitions/library/defs/hud/minimap.lua create mode 100644 types/luanti_lsp_definitions/library/defs/hud/statbar.lua create mode 100644 types/luanti_lsp_definitions/library/defs/hud/text.lua create mode 100644 types/luanti_lsp_definitions/library/defs/hud/waypoint.lua create mode 100644 types/luanti_lsp_definitions/library/defs/inventory.lua create mode 100644 types/luanti_lsp_definitions/library/defs/item/item.lua create mode 100644 types/luanti_lsp_definitions/library/defs/item/itemdef.lua create mode 100644 types/luanti_lsp_definitions/library/defs/item/pointabilities.lua create mode 100644 types/luanti_lsp_definitions/library/defs/item/sound.lua create mode 100644 types/luanti_lsp_definitions/library/defs/item/touch_interaction.lua create mode 100644 types/luanti_lsp_definitions/library/defs/lbm.lua create mode 100644 types/luanti_lsp_definitions/library/defs/lsystem.lua create mode 100644 types/luanti_lsp_definitions/library/defs/mapgen_objects.lua create mode 100644 types/luanti_lsp_definitions/library/defs/metadata/item.lua create mode 100644 types/luanti_lsp_definitions/library/defs/metadata/metadata.lua create mode 100644 types/luanti_lsp_definitions/library/defs/metadata/node.lua create mode 100644 types/luanti_lsp_definitions/library/defs/metadata/player.lua create mode 100644 types/luanti_lsp_definitions/library/defs/metadata/storage.lua create mode 100644 types/luanti_lsp_definitions/library/defs/node/drawtype.lua create mode 100644 types/luanti_lsp_definitions/library/defs/node/drop.lua create mode 100644 types/luanti_lsp_definitions/library/defs/node/node.lua create mode 100644 types/luanti_lsp_definitions/library/defs/node/nodebox.lua create mode 100644 types/luanti_lsp_definitions/library/defs/node/nodedef.lua create mode 100644 types/luanti_lsp_definitions/library/defs/node/paramtype.lua create mode 100644 types/luanti_lsp_definitions/library/defs/node/sounds.lua create mode 100644 types/luanti_lsp_definitions/library/defs/node/tiles.lua create mode 100644 types/luanti_lsp_definitions/library/defs/noiseparams.lua create mode 100644 types/luanti_lsp_definitions/library/defs/object_properties/box.lua create mode 100644 types/luanti_lsp_definitions/library/defs/object_properties/object_properties.lua create mode 100644 types/luanti_lsp_definitions/library/defs/object_properties/partial/backface_clling.lua create mode 100644 types/luanti_lsp_definitions/library/defs/object_properties/partial/shaded.lua create mode 100644 types/luanti_lsp_definitions/library/defs/object_properties/partial/spritesheet.lua create mode 100644 types/luanti_lsp_definitions/library/defs/object_properties/player_properties.lua create mode 100644 types/luanti_lsp_definitions/library/defs/object_properties/types/cube.lua create mode 100644 types/luanti_lsp_definitions/library/defs/object_properties/types/item.lua create mode 100644 types/luanti_lsp_definitions/library/defs/object_properties/types/mesh.lua create mode 100644 types/luanti_lsp_definitions/library/defs/object_properties/types/node.lua create mode 100644 types/luanti_lsp_definitions/library/defs/object_properties/types/sprite.lua create mode 100644 types/luanti_lsp_definitions/library/defs/object_properties/types/upright_sprite.lua create mode 100644 types/luanti_lsp_definitions/library/defs/object_properties/types/wielditem.lua create mode 100644 types/luanti_lsp_definitions/library/defs/ore/blob.lua create mode 100644 types/luanti_lsp_definitions/library/defs/ore/ore.lua create mode 100644 types/luanti_lsp_definitions/library/defs/ore/puff.lua create mode 100644 types/luanti_lsp_definitions/library/defs/ore/scatter.lua create mode 100644 types/luanti_lsp_definitions/library/defs/ore/sheet.lua create mode 100644 types/luanti_lsp_definitions/library/defs/ore/stratum.lua create mode 100644 types/luanti_lsp_definitions/library/defs/ore/vein.lua create mode 100644 types/luanti_lsp_definitions/library/defs/particle/ParticleSpawner.lua create mode 100644 types/luanti_lsp_definitions/library/defs/particle/attract.lua create mode 100644 types/luanti_lsp_definitions/library/defs/particle/particle.lua create mode 100644 types/luanti_lsp_definitions/library/defs/particle/texture.lua create mode 100644 types/luanti_lsp_definitions/library/defs/particle/type.lua create mode 100644 types/luanti_lsp_definitions/library/defs/pointed_thing.lua create mode 100644 types/luanti_lsp_definitions/library/defs/privilege.lua create mode 100644 types/luanti_lsp_definitions/library/defs/schematics.lua create mode 100644 types/luanti_lsp_definitions/library/defs/sound.lua create mode 100644 types/luanti_lsp_definitions/library/defs/textures.lua create mode 100644 types/luanti_lsp_definitions/library/defs/tile.lua create mode 100644 types/luanti_lsp_definitions/library/defs/tool_capabilities.lua create mode 100644 types/luanti_lsp_definitions/library/defs/wear_bar_color.lua create mode 100644 types/luanti_lsp_definitions/library/helpers.lua create mode 100644 types/luanti_lsp_definitions/library/misc.lua create mode 100644 types/luanti_lsp_definitions/library/vector/vec.lua create mode 100644 types/luanti_lsp_definitions/library/vector/vector.lua create mode 100644 types/luanti_lsp_definitions/library/vector/vectorlib.lua create mode 100644 types/luanti_lsp_definitions/utils/.cspell-luanti.txt create mode 100644 types/luanti_lsp_definitions/utils/.cspell-misc.txt create mode 100644 types/luanti_lsp_definitions/utils/LGPLv2.1..txt diff --git a/.gitmodules b/.gitmodules index e69de29b..e58e8e7b 100644 --- a/.gitmodules +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "mods/hotbar_switching"] + path = mods/hotbar_switching + url = https://github.com/TheEt1234/hotbar_switching diff --git a/CHANGELOG.md b/CHANGELOG.md index fc412d22..e9df0cba 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,7 @@ -## Release 38 +# Release 40 + + +# Release 38 ### The main stuff: - Large Liquid Storage - another multiblock, you won't guess what it does - Fixed meteorite attractor entities sometimes just multiplying @@ -29,7 +32,7 @@ - In the various lag statues, switched away from using `core.get_us_time`, and instead using `os.clock`, i don't know if this is actually better -Release 37 - sorry for the long wait :) - the "Oh UI looks decent now... and what's that? it's not a buggy mess anymore?" +# Release 37 - sorry for the long wait :) - the "Oh UI looks decent now... and what's that? it's not a buggy mess anymore?" - Fixed instatubes sometimes not working - Added bricks and wooden planks - Fixed one pixel of pebble being transparent (Yes, you weren't crazy!) @@ -53,7 +56,7 @@ Release 37 - sorry for the long wait :) - the "Oh UI looks decent now... and wha - Made drawers undiggable when filled with anything - Changed questbooks -Release 36 - "Oh no... there is stuff to fix actually, oops" Update +# Release 36 - "Oh no... there is stuff to fix actually, oops" Update - Fixed a bug with instatubes that made them behave really strangely, when a server restarted - Added the height limit for emitters back - Added a command that removes all pipeworks tube entities @@ -69,7 +72,7 @@ Release 36 - "Oh no... there is stuff to fix actually, oops" Update - Made antimatter platforms explody - Fixed one way instatube textures being in the wrong direction -Release 35 - "Optimization update" +# Release 35 - "Optimization update" - made pipes and tubes smaller (1/4th of a node => 3/16th of a node) - fixed some bugs - made fluid pipe look better @@ -86,7 +89,7 @@ Release 35 - "Optimization update" - Made copytool copy filter injector "exact match mode" -Release 34 +# Release 34 - Added a recipe to memory controller - Added an info page "Overflow Handling" - Added an "Items destroyed: " infotext to item voids @@ -94,7 +97,7 @@ Release 34 - Made burners store co2 - Fixed rare bugs with filter injectors -Release 33 +# Release 33 - Fixed a bug where filter injectors didn't work with one way tubes - Added one direction tube - A tube that accepts items from all directions, but sends them to only one direction @@ -141,11 +144,11 @@ Release 33 - Fixed the default editor's disk menu being weird sometimes -Release 32 +# Release 32 - Fix the bug with filter injectors crashing the game when directly outputting to accelerator tubes - Fix background music being at 0% volume by default -Release 31 +# Release 31 - Make the data disk description more accurate - they can only hold 20 kilobytes, not 1 megabyte - Re-worked how meteorite attractors/repulsors attract players when holding neutronium - You now no longer can move yourself, and experience zero gravity - This allows for making orbits if you are skilled @@ -176,11 +179,11 @@ Release 31 - Changed the behavior of filter injectors so that they don't try to push stuff out when the inventory they are trying to push stuff to is clearly full - Re-worked and fixed bugs with logic item transport -Release 30 +# Release 30 - Fixed crash bugs with jumpdrive and moving nodes with luacontrollers - Added lead shielding -Release 29 +# Release 29 - Notice: Releases may be really small like this one, or HUGE like release 28 - Started doing changelogs again - Added more "info sections" to the questbook, told people that you can hold right click to the core in the questbook @@ -195,7 +198,7 @@ Release 29 - Fixed a bug with ladders, where they refused to go in certain directions - Compressed images, lossy compressed the background to 200kb -Release 10 +# Release 10 - Completely recode energy system to use "Cosmic Joules" instead of "Global Power" - Pipe-based energy system - Removed quest "Global Power" @@ -206,7 +209,7 @@ Release 10 - added Starlight Collectors - Stopped doing changelogs -Release 9 +# Release 9 - New questline "Decorator" - Moved "Emitter Immitators" to the Decorator questline - New quest: "Photon Lamps" in Decorator Questline @@ -214,7 +217,7 @@ Release 9 - Fixed a bug reported by @theidealist (ty) - Secret quests now show up in the questbook as ??? -Release 8 +# Release 8 - Questbook now has questlines - Primitive Questbook API documentation added (see docs folder) - Questbook has new types of quests @@ -222,7 +225,7 @@ Release 8 - Added secret quest "Emptiness" - Improved indicators on quests -Release 7 +# Release 7 - fix the questbook reminders - player is now invisible, replaced by a white particle trail - removed players hand @@ -232,7 +235,7 @@ Release 7 - Add Dirt, Soil and Stone Nodes - Add 'Raw Emittrium' and 'Pebble' Items -Release 6 +# Release 6 - 'Emitter Immitator' now gives off twice as much light - Introduced the Quest Book instead of the Guide (which has been removed) - Ported 7 Quests over from the old quest system @@ -241,16 +244,16 @@ Release 6 - use /qb to get the questbook on old worlds - Custom hotbar textures -Release 5 +# Release 5 - Fixed an issue with infinite negative energy reported by @fgaz -Release 4 +# Release 4 - Fixed sneaking being insanely fast for no reason - Fixed bugs with Generator where it would give infinite energy / take infinite energy - Added conversion chamber craftitem - Added Organic Converter (not usable so far) -Release 3 +# Release 3 - Fixed power not getting removed when removing a running generator - Added space-like physics - Added a sound when placing a machine @@ -260,7 +263,7 @@ Release 3 - Added Simple Circuit and Retaining Circuit - Added Matter Plate -Release 2 +# Release 2 - Added Advanced Matter Extractor - Made Emitters display a message when clicked - Added "Advanced Extractors" Optional Quest / Achievement @@ -268,5 +271,5 @@ Release 2 - Added Simple Charge Generator - Added Emitter Immitator -Release 1 +# Release 1 - First release diff --git a/mods/hotbar_switching b/mods/hotbar_switching new file mode 160000 index 00000000..2ff96c52 --- /dev/null +++ b/mods/hotbar_switching @@ -0,0 +1 @@ +Subproject commit 2ff96c5288853b2c294b76b6c9c892b5350805eb diff --git a/mods/hotbar_switching/LICENSE.txt b/mods/hotbar_switching/LICENSE.txt deleted file mode 100644 index d3061a37..00000000 --- a/mods/hotbar_switching/LICENSE.txt +++ /dev/null @@ -1,13 +0,0 @@ -Zero-Clause BSD -============= - -Permission to use, copy, modify, and/or distribute this software for -any purpose with or without fee is hereby granted. - -THE SOFTWARE IS PROVIDED “AS IS” AND THE AUTHOR DISCLAIMS ALL -WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES -OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE -FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY -DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN -AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT -OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. diff --git a/mods/hotbar_switching/README.md b/mods/hotbar_switching/README.md deleted file mode 100644 index 698f772a..00000000 --- a/mods/hotbar_switching/README.md +++ /dev/null @@ -1,37 +0,0 @@ -# Hotbar Switching - -Implements a way to switch your hotbar to another row. Inspired by [better than adventure](https://www.betterthanadventure.net/) (it has a feature where if you press `tab`, it will change the hotbar like this mod, but doesn't change your inventory). - -## Defaults - requires the `controls` mod -- `sneak` + `aux1` + `left mouse button` - cycle -- `sneak` + `aux1` + `right mouse button` - cycle backwards - -## Mobile - -I believe this would be best done with a custom button, which i think isn't possible in luanti, or there should at least something in the inventory menu. -There are a lot of inventory mods, i think it would be very difficult to support them all. - -## How does it work? - -There is no way to actually decide which slots are part of your hotbar in luanti. So this just shifts items items in your inventory. - -The width of the inventory is assumed to be your hotbar size. - -## Why `controls` mod isn't optional - -ContentDB doesn't allow you to have some sort of "strongly suggested dependancies", so i think it would be best for this mod to work out of the box, instead of not doing anything by default like a library. You may change this in games that use this mod. - -Also i didn't want to reinvent the wheel again. - -## API -- `hotbar_switching` - a table, contains everything -- `hotbar_switching.default_controls = true` - enable default controls -- `hotbar_switching.can_player_switch(player)` - Can the player switch their hotbar to another row - - `player` is an ObjectRef (player) - - returns a boolean, by default always returns `true` - - Override the function if you need to decide -- `hotbar_switching.switch(player, row)` - Actually perform the action of switching the hotbar to that row - - `player` - ObjectRef (player) - - `row` - integer (Usually `-1` or `1`) - - The inventory list being manipulated will be from `player:get_wield_list()` - - You may override this function to change what happens at the end of it (example: sending a message saying you did that action) diff --git a/mods/hotbar_switching/init.lua b/mods/hotbar_switching/init.lua deleted file mode 100644 index 91c37c01..00000000 --- a/mods/hotbar_switching/init.lua +++ /dev/null @@ -1,67 +0,0 @@ ----@diagnostic disable: undefined-global, lowercase-global, unused-local --- any of these functions are designed to be overriden by mods/games - -_G.hotbar_switching = { - default_controls = true, -} - ---- If your mod implements a situation where hotbar switching is not acceptable, you can modify this function ---- do something like: ---- ```lua ---- local old_player_can_switch = hotbar_switching.can_player_switch ---- function hotbar_switching.can_player_switch(player) ---- ---- return hotbar_switching.can_player_switch(player) ---- end ---- ``` ----@param player userdata|table ----@return boolean -function hotbar_switching.can_player_switch(player) - return true -end - ---- You can override to specify what should happen after switching ---- You can use this to make a fancy UI i guess, but that is an excercise for the viewer ----@param player userdata|table ----@param row integer -function hotbar_switching.switch(player, row) - local listname = player:get_wield_list() - local inv = player:get_inventory() - local hotbar_size = player:hud_get_hotbar_itemcount() - local list = inv:get_list(listname) - local list_size = #list - - -- suppose hotbar size is 17 items (why) and inv size was 32 - -- this mod can't really handle that, so just silently fail - if hotbar_size * 2 > list_size then return end - if row < 0 then row = (list_size / hotbar_size) + row end - - local from_index = row * hotbar_size - - local new_list = {} - - for i = 1, list_size do - new_list[i] = list[(i + from_index) % list_size] - end - - inv:set_list(listname, new_list) -end - --- core.get_modpath over core.global_exists in this case because `controls` is a super generic name -if core.get_modpath 'controls' then - controls.register_on_press(function(player, key) - local c = player:get_player_control() - local activated = c.sneak and c.aux1 - if - _G.hotbar_switching.default_controls == true - and hotbar_switching.can_player_switch(player) - and activated - then - if key == 'LMB' then - hotbar_switching.switch(player, 1) - elseif key == 'RMB' then - hotbar_switching.switch(player, -1) - end - end - end) -end diff --git a/mods/hotbar_switching/mod.conf b/mods/hotbar_switching/mod.conf deleted file mode 100644 index 8b83ed51..00000000 --- a/mods/hotbar_switching/mod.conf +++ /dev/null @@ -1,2 +0,0 @@ -name = hotbar_switching -depends = controls diff --git a/mods/sbz_base/init.lua b/mods/sbz_base/init.lua index 2f732aea..13d212a0 100644 --- a/mods/sbz_base/init.lua +++ b/mods/sbz_base/init.lua @@ -1,7 +1,7 @@ ---@diagnostic disable-next-line: lowercase-global sbz_api = { version = 39, - is_version_dev = false, + is_version_dev = true, gravity = 9.8 / 2, server_optimizations = (core.settings:get 'sbz_server_mode' or 'auto'), deg2rad = math.pi / 180, @@ -252,10 +252,7 @@ core.register_on_joinplayer(function(player) player:get_player_name(), '‼ reminder: If you fall off, use /core to teleport back to the core.' ) - core.chat_send_player( - player:get_player_name(), - '‼ reminder: If lose your Quest Book, use /qb to get it back.' - ) + core.chat_send_player(player:get_player_name(), '‼ reminder: If lose your Quest Book, use /qb to get it back.') -- core.chat_send_player(player:get_player_name(), -- "‼ Also, you can hold right click on the core, instead of having to spam your mouse, on mobile you might need to just hold tap") -- play bgm @@ -391,8 +388,11 @@ function sbz_api.on_place_precedence(on_place) if under then local node = core.get_node(under) local def = core.registered_nodes[node.name] - if def and def.on_rightclick and - not (placer and placer:is_player() and placer:get_player_control().sneak) then + if + def + and def.on_rightclick + and not (placer and placer:is_player() and placer:get_player_control().sneak) + then return def.on_rightclick(under, node, placer, itemstack, pointed_thing) or itemstack end end @@ -455,6 +455,7 @@ dofile(MP .. '/recipe.lua') dofile(MP .. '/serialize.lua') dofile(MP .. '/serialize_benchmark.lua') dofile(MP .. '/space_movement.lua') +dofile(MP .. '/pick_block.lua') -- yeah you actually have to do this -- definition copied from mtg diff --git a/mods/sbz_base/pick_block.lua b/mods/sbz_base/pick_block.lua new file mode 100644 index 00000000..262c76e0 --- /dev/null +++ b/mods/sbz_base/pick_block.lua @@ -0,0 +1,51 @@ +-- Common problem: "I want to have this node in my hand right now" +-- Alternative: Hotbar switching (implemented) +-- +-- Keys: zoom+rmb/lmb to pick + +local function get_pointed_node_type(player) + local lookdir = player:get_look_dir() + local eyepos = sbz_api.get_pos_with_eye_height(player) + local ray = core.raycast(eyepos, vector.add(eyepos, vector.multiply(lookdir, 30)), false, false) + for pointed_thing in ray do + if pointed_thing.type == 'node' then + local node = core.get_node(pointed_thing.under) + local def = core.registered_nodes[node.name] + if def then return node.name end + end + end + return nil +end + +local function pick_block(player, node_name) + local inv = player:get_inventory() + if not inv:contains_item('main', node_name) then return end + + local item_index + + local list = inv:get_list 'main' + for i = 1, #list do + local stack = list[i] + if stack:get_name() == node_name then + item_index = i + break + end + end + + if not item_index then return end + local wielded_item = player:get_wielded_item() + local wield_index = player:get_wield_index() + list[wield_index] = list[item_index] + list[item_index] = wielded_item + inv:set_list('main', list) + core.chat_send_player( + player:get_player_name(), + '[sbz] Picked ' .. node_name .. ' to wielded slot. (Use zoom+rmb/lmb to pick a node.)' + ) +end + +controls.register_on_press(function(player, key) + if not (key == 'LMB' or key == 'RMB') then return end + local node_name = get_pointed_node_type(player) + if node_name then pick_block(player, node_name) end +end) diff --git a/mods/sbz_multiblocks/large_liquid_storage.lua b/mods/sbz_multiblocks/large_liquid_storage.lua index 4456ed66..a84d96a8 100644 --- a/mods/sbz_multiblocks/large_liquid_storage.lua +++ b/mods/sbz_multiblocks/large_liquid_storage.lua @@ -3,15 +3,17 @@ local storage_per_node = 200 -- 5x5x5 25000 liquid sources local function get_llsc_formspec(pos) local meta = core.get_meta(pos) - local storage_size = meta:get_int("storage_size") + local storage_size = meta:get_int 'storage_size' if storage_size == 0 then storage_size = 2 - meta:set_int("storage_size", 2) + meta:set_int('storage_size', 2) end - if meta:get_int("set_up") == 1 then - core.registered_nodes[sbz_api.get_node_force(pos).name].on_liquid_inv_update(pos, - core.deserialize(meta:get_string("liquid_inv"))) - return "" + if meta:get_int 'set_up' == 1 then + core.registered_nodes[sbz_api.get_node_force(pos).name].on_liquid_inv_update( + pos, + core.deserialize(meta:get_string 'liquid_inv') + ) + return '' else local fs = ([[ formspec_version[7] @@ -26,12 +28,14 @@ label[3.2,3.3;3] label[4.7,3.3;4] label[6.25,3.3;5] ]]):format(storage_size) - if #meta:get_string("errmsg") ~= 0 then - fs = fs .. - string.format("textarea[0.5,4;8,2;;Error message when trying to form multiblock:;%s]", - meta:get_string("errmsg")) + if #meta:get_string 'errmsg' ~= 0 then + fs = fs + .. string.format( + 'textarea[0.5,4;8,2;;Error message when trying to form multiblock:;%s]', + meta:get_string 'errmsg' + ) else - fs = fs .. ("label[0.5,4;=> %s liquid source(s)]"):format(storage_size ^ 3 * storage_per_node) + fs = fs .. ('label[0.5,4;=> %s liquid source(s)]'):format(storage_size ^ 3 * storage_per_node) end return fs end @@ -40,9 +44,9 @@ end local cached_schems = {} local h = core.hash_node_position local function make_schem(pos, meta, node) - local storage_size = (meta and meta.storage_size) or core.get_meta(pos):get_int("storage_size") + local storage_size = (meta and meta.storage_size) or core.get_meta(pos):get_int 'storage_size' local param2 = (node and node.param2) or sbz_api.get_or_load_node(pos).param2 - local orientation = core.facedir_to_dir(param2 - (core.strip_param2_color(param2, "colorfacedir") or 0)) + local orientation = core.facedir_to_dir(param2 - (core.strip_param2_color(param2, 'colorfacedir') or 0)) if cached_schems[storage_size] and cached_schems[storage_size][h(orientation)] then return cached_schems[storage_size][h(orientation)] end @@ -56,58 +60,47 @@ local function make_schem(pos, meta, node) -- most boring code ever local vn = vector.new - local edge = "sbz_multiblocks:large_liquid_storage_casing_edge" + local edge = 'sbz_multiblocks:large_liquid_storage_casing_edge' -- there is at least 1 redundant loop here definitely xD - for _, x in ipairs({ 0, storage_size + 1 }) do - for _, y in ipairs({ 0, storage_size + 1 }) do + for _, x in ipairs { 0, storage_size + 1 } do + for _, y in ipairs { 0, storage_size + 1 } do for z = 0, storage_size + 1 do - if not (y == 0 and z == 0 and x == 0) then - schemdata[h(vn(x, y, z))] = edge - end + if not (y == 0 and z == 0 and x == 0) then schemdata[h(vn(x, y, z))] = edge end end end end - for _, y in ipairs({ 0, storage_size + 1 }) do - for _, z in ipairs({ 0, storage_size + 1 }) do + for _, y in ipairs { 0, storage_size + 1 } do + for _, z in ipairs { 0, storage_size + 1 } do for x = 0, storage_size + 1 do - if not (y == 0 and z == 0 and x == 0) then - schemdata[h(vn(x, y, z))] = edge - end + if not (y == 0 and z == 0 and x == 0) then schemdata[h(vn(x, y, z))] = edge end end end end - for _, z in ipairs({ 0, storage_size + 1 }) do - for _, y in ipairs({ 0, storage_size + 1 }) do + for _, z in ipairs { 0, storage_size + 1 } do + for _, y in ipairs { 0, storage_size + 1 } do for x = 0, storage_size + 1 do - if not (y == 0 and z == 0 and x == 0) then - schemdata[h(vn(x, y, z))] = edge - end + if not (y == 0 and z == 0 and x == 0) then schemdata[h(vn(x, y, z))] = edge end end end end - for _, z in ipairs({ 0, storage_size + 1 }) do - for _, x in ipairs({ 0, storage_size + 1 }) do + for _, z in ipairs { 0, storage_size + 1 } do + for _, x in ipairs { 0, storage_size + 1 } do for y = 0, storage_size + 1 do - if not (y == 0 and z == 0 and x == 0) then - schemdata[h(vn(x, y, z))] = edge - end + if not (y == 0 and z == 0 and x == 0) then schemdata[h(vn(x, y, z))] = edge end end end end - for _, x in ipairs({ 0, storage_size + 1 }) do - for _, z in ipairs({ 0, storage_size + 1 }) do + for _, x in ipairs { 0, storage_size + 1 } do + for _, z in ipairs { 0, storage_size + 1 } do for y = 0, storage_size + 1 do - if not (y == 0 and z == 0 and x == 0) then - schemdata[h(vn(x, y, z))] = edge - end + if not (y == 0 and z == 0 and x == 0) then schemdata[h(vn(x, y, z))] = edge end end end end - - local side = "sbz_multiblocks:large_liquid_storage_casing" - for _, z in ipairs({ 0, storage_size + 1 }) do + local side = 'sbz_multiblocks:large_liquid_storage_casing' + for _, z in ipairs { 0, storage_size + 1 } do for x = 1, storage_size do for y = 1, storage_size do schemdata[h(vn(x, y, z))] = side @@ -115,7 +108,7 @@ local function make_schem(pos, meta, node) end end - for _, x in ipairs({ 0, storage_size + 1 }) do + for _, x in ipairs { 0, storage_size + 1 } do for z = 1, storage_size do for y = 1, storage_size do schemdata[h(vn(x, y, z))] = side @@ -123,7 +116,7 @@ local function make_schem(pos, meta, node) end end - for _, y in ipairs({ 0, storage_size + 1 }) do + for _, y in ipairs { 0, storage_size + 1 } do for z = 1, storage_size do for x = 1, storage_size do schemdata[h(vn(x, y, z))] = side @@ -132,150 +125,164 @@ local function make_schem(pos, meta, node) end schem = sbz_api.multiblocks.rotate_schematic(schem, orientation) - if not cached_schems[storage_size] then - cached_schems[storage_size] = {} - end + if not cached_schems[storage_size] then cached_schems[storage_size] = {} end cached_schems[storage_size][h(orientation)] = schem return schem end -local default_inv = minetest.serialize({ +local default_inv = minetest.serialize { max_count_in_each_stack = 0, [1] = { - name = "any", + name = 'any', count = 0, can_change_name = true, }, -}) +} -core.register_node("sbz_multiblocks:large_liquid_storage_controller", unifieddyes.def { - description = "Large Liquid Storage Controller", - groups = { - matter = 1, - multiblock_controller = 1, - fluid_pipe_connects = 1, fluid_pipe_stores = 1, ui_fluid = 1 - }, - paramtype2 = "colorfacedir", - tiles = { - "large_liquid_storage_controller_top.png", - "large_liquid_storage_controller_top.png", - "large_liquid_storage_controller_sides.png", - "large_liquid_storage_controller_sides.png", - "large_liquid_storage_controller_sides.png", - "large_liquid_storage_controller_back.png", - }, - light_source = 3, - on_construct = function(pos) - local meta = core.get_meta(pos) - meta:set_string("formspec", get_llsc_formspec(pos)) - meta:set_string("liquid_inv", default_inv) - end, - on_receive_fields = function(pos, _, fields, sender) - local meta = core.get_meta(pos) - local is_multiblock = meta:get_int("set_up") == 1 - if not is_multiblock then - if fields.storage_size then - local scrollbar_event = core.explode_scrollbar_event(fields.storage_size) - if scrollbar_event.type == "CHG" and scrollbar_event.value <= 5 and scrollbar_event.value >= 2 then - meta:set_int("storage_size", scrollbar_event.value) +core.register_node( + 'sbz_multiblocks:large_liquid_storage_controller', + unifieddyes.def { + description = 'Large Liquid Storage Controller', + groups = { + matter = 1, + multiblock_controller = 1, + fluid_pipe_connects = 1, + fluid_pipe_stores = 1, + ui_fluid = 1, + }, + paramtype2 = 'colorfacedir', + tiles = { + 'large_liquid_storage_controller_top.png', + 'large_liquid_storage_controller_top.png', + 'large_liquid_storage_controller_sides.png', + 'large_liquid_storage_controller_sides.png', + 'large_liquid_storage_controller_sides.png', + 'large_liquid_storage_controller_back.png', + }, + light_source = 3, + on_construct = function(pos) + local meta = core.get_meta(pos) + meta:set_string('formspec', get_llsc_formspec(pos)) + meta:set_string('liquid_inv', default_inv) + end, + on_receive_fields = function(pos, _, fields, sender) + local meta = core.get_meta(pos) + local is_multiblock = meta:get_int 'set_up' == 1 + if not is_multiblock then + if fields.storage_size then + local scrollbar_event = core.explode_scrollbar_event(fields.storage_size) + if scrollbar_event.type == 'CHG' and scrollbar_event.value <= 5 and scrollbar_event.value >= 2 then + meta:set_int('storage_size', scrollbar_event.value) + end end - end - if fields.show_ghosts then - local default_expiration = 8 - local last_used = meta:get_int("last_used_build_helper") - if os.difftime(os.time(), last_used) >= default_expiration then + if fields.show_ghosts then + local default_expiration = 8 + local last_used = meta:get_int 'last_used_build_helper' + if os.difftime(os.time(), last_used) >= default_expiration then + local schem = make_schem(pos) + sbz_api.multiblocks.draw_schematic(pos, schem) + meta:set_int('last_used_build_helper', os.time()) + else + core.chat_send_player( + sender:get_player_name(), + 'You need to wait ' + .. (default_expiration - os.difftime(os.time(), last_used)) + .. ' seconds before showing build plan again.' + ) + end + end + if fields.form_multiblock then local schem = make_schem(pos) - sbz_api.multiblocks.draw_schematic(pos, schem) - meta:set_int("last_used_build_helper", os.time()) - else - core.chat_send_player(sender:get_player_name(), - "You need to wait " .. - (default_expiration - os.difftime(os.time(), last_used)) .. - " seconds before showing build plan again.") + local result = sbz_api.multiblocks.form_multiblock(pos, schem) + if result.success == false then + meta:set_string('errmsg', result.errmsg) + else + meta:set_int('set_up', 1) + meta:set_string( + 'liquid_inv', + core.serialize { + max_count_in_each_stack = meta:get_int 'storage_size' ^ 3 * storage_per_node, + [1] = { + name = 'any', + count = 0, + can_change_name = true, + }, + } + ) + meta:set_string('infotext', 'Waiting for a liquid...') + end end end - if fields.form_multiblock then - local schem = make_schem(pos) - local result = sbz_api.multiblocks.form_multiblock(pos, schem) - if result.success == false then - meta:set_string("errmsg", result.errmsg) - else - meta:set_int("set_up", 1) - meta:set_string("liquid_inv", core.serialize { - max_count_in_each_stack = meta:get_int("storage_size") ^ 3 * storage_per_node, - [1] = { - name = "any", - count = 0, - can_change_name = true, - } - }) - meta:set_string("infotext", "Waiting for a liquid...") - end + local newfs = get_llsc_formspec(pos) + if newfs ~= '' then meta:set_string('formspec', newfs) end + end, + on_multiblock_break = function(pos, meta) + meta:set_int('set_up', 0) + meta:set_string('formspec', get_llsc_formspec(pos)) + meta:set_string('liquid_inv', default_inv) + end, + get_schematic = make_schem, + after_dig_node = sbz_api.multiblocks.after_dig_controller 'sbz_multiblocks:large_liquid_storage_controller', + before_movenode = sbz_api.multiblocks.before_movenode, + on_liquid_inv_update = function(pos, lqinv) + local meta = minetest.get_meta(pos) + if lqinv[1].name == 'any' then + meta:set_string('infotext', 'Waiting for a liquid...') + return end - end - local newfs = get_llsc_formspec(pos) - if newfs ~= "" then - meta:set_string("formspec", newfs) - end - end, - on_multiblock_break = function(pos, meta) - meta:set_int("set_up", 0) - meta:set_string("formspec", get_llsc_formspec(pos)) - meta:set_string("liquid_inv", default_inv) - core.debug(dump(debug.traceback())) - end, - get_schematic = make_schem, - after_dig_node = sbz_api.multiblocks.after_dig_controller("sbz_multiblocks:large_liquid_storage_controller"), - before_movenode = sbz_api.multiblocks.before_movenode, - on_liquid_inv_update = function(pos, lqinv) - local meta = minetest.get_meta(pos) - if lqinv[1].name == "any" then - meta:set_string("infotext", "Waiting for a liquid...") - return; - end - local def = minetest.registered_nodes[lqinv[1].name] - local desc = string.gsub(def.short_description or def.description or lqinv[1].name, " Source", "") - meta:set_string("infotext", ("Storing %s : %s/%s"):format(desc, lqinv[1].count, lqinv.max_count_in_each_stack)) - meta:set_string("formspec", sbz_api.liquid_storage_fs(lqinv[1].count, lqinv.max_count_in_each_stack)) - end, -}) + local def = minetest.registered_nodes[lqinv[1].name] + local desc = string.gsub(def.short_description or def.description or lqinv[1].name, ' Source', '') + meta:set_string( + 'infotext', + ('Storing %s : %s/%s'):format(desc, lqinv[1].count, lqinv.max_count_in_each_stack) + ) + meta:set_string('formspec', sbz_api.liquid_storage_fs(lqinv[1].count, lqinv.max_count_in_each_stack)) + end, + } +) -core.register_node("sbz_multiblocks:large_liquid_storage_casing", unifieddyes.def { - description = "Large Liquid Storage Casing", - groups = { - matter = 1, - wallsharing = 1, - ui_fluid = 1, - }, - info_extra = "Or \"Dark Stained Colorium Glass\" If you are into decorating", - drawtype = "glasslike_framed", - paramtype = "light", - paramtype2 = "color", - tiles = { - "large_liquid_storage_casing.png", - "large_liquid_storage_casing_inner.png", - }, - use_texture_alpha = "blend", - light_source = 3, - after_dig_node = sbz_api.multiblocks.after_dig, - before_movenode = sbz_api.multiblocks.before_movenode, -}) +core.register_node( + 'sbz_multiblocks:large_liquid_storage_casing', + unifieddyes.def { + description = 'Large Liquid Storage Casing', + groups = { + matter = 1, + wallsharing = 1, + ui_fluid = 1, + }, + info_extra = 'Or "Dark Stained Colorium Glass" If you are into decorating', + drawtype = 'glasslike_framed', + paramtype = 'light', + paramtype2 = 'color', + tiles = { + 'large_liquid_storage_casing.png', + 'large_liquid_storage_casing_inner.png', + }, + use_texture_alpha = 'blend', + light_source = 3, + after_dig_node = sbz_api.multiblocks.after_dig, + before_movenode = sbz_api.multiblocks.before_movenode, + } +) -core.register_node("sbz_multiblocks:large_liquid_storage_casing_edge", unifieddyes.def { - description = "Large Liquid Storage Edge Casing ", - groups = { - matter = 1, - wallsharing = 1, - ui_fluid = 1 - }, - drawtype = "glasslike_framed", - paramtype = "light", - paramtype2 = "color", - tiles = { - "large_liquid_storage_casing_edge.png", - "large_liquid_storage_casing_edge_inner.png", - }, - light_source = 3, - after_dig_node = sbz_api.multiblocks.after_dig, - before_movenode = sbz_api.multiblocks.before_movenode, -}) +core.register_node( + 'sbz_multiblocks:large_liquid_storage_casing_edge', + unifieddyes.def { + description = 'Large Liquid Storage Edge Casing ', + groups = { + matter = 1, + wallsharing = 1, + ui_fluid = 1, + }, + drawtype = 'glasslike_framed', + paramtype = 'light', + paramtype2 = 'color', + tiles = { + 'large_liquid_storage_casing_edge.png', + 'large_liquid_storage_casing_edge_inner.png', + }, + light_source = 3, + after_dig_node = sbz_api.multiblocks.after_dig, + before_movenode = sbz_api.multiblocks.before_movenode, + } +) diff --git a/mods/sbz_pipeworks/autocrafter.lua b/mods/sbz_pipeworks/autocrafter.lua index 01681308..299d1894 100644 --- a/mods/sbz_pipeworks/autocrafter.lua +++ b/mods/sbz_pipeworks/autocrafter.lua @@ -353,8 +353,8 @@ local function update_meta(pos, meta) if output:is_empty() then -- doesn't matter if paused or not meta:set_string('infotext', S 'unconfigured Autocrafter') return false - elseif processor:is_empty() then - meta:set_string("infotext", S 'No crafting processor.') + elseif processor:is_empty() then + meta:set_string('infotext', S 'No crafting processor.') return false end @@ -371,11 +371,11 @@ local list_cache = sbz_api.make_cache('list_cache', 0, true) -- crafting processors & stats -- might want to introduce a register_crafting_processor function sometime local processor_stats_map = { - ["sbz_resources:simple_crafting_processor"] = { crafts = 1, power = 10 }, - ["sbz_resources:quick_crafting_processor"] = { crafts = 2, power = 25 }, - ["sbz_resources:fast_crafting_processor"] = { crafts = 4, power = 50 }, - ["sbz_resources:accelerated_silicon_crafting_processor"] = { crafts = 8, power = 100 }, - ["sbz_resources:nuclear_crafting_processor"] = { crafts = 16, power = 175 }, + ['sbz_resources:simple_crafting_processor'] = { crafts = 1, power = 10 }, + ['sbz_resources:quick_crafting_processor'] = { crafts = 2, power = 25 }, + ['sbz_resources:fast_crafting_processor'] = { crafts = 4, power = 50 }, + ['sbz_resources:accelerated_silicon_crafting_processor'] = { crafts = 8, power = 100 }, + ['sbz_resources:nuclear_crafting_processor'] = { crafts = 16, power = 175 }, } minetest.register_node('pipeworks:autocrafter', { @@ -447,7 +447,6 @@ minetest.register_node('pipeworks:autocrafter', { if not slots[stack:get_name()] then return false end -- next up, check if we actually can insert local compare_stack = ItemStack(stack) - core.debug('first:' .. compare_stack:to_string()) for i = 1, 9 do if slots[i] == stack:get_name() then local that_stack = inv:get_stack('src', i) @@ -456,7 +455,6 @@ minetest.register_node('pipeworks:autocrafter', { compare_stack:set_count(leftover) end end - core.debug('second:' .. compare_stack:get_count()) return compare_stack:get_count() == 0 end, @@ -577,7 +575,7 @@ minetest.register_node('pipeworks:autocrafter', { info_extra = 'Requires a crafting processor to work.', action = function(pos, node, meta, supply, demand) local inv = meta:get_inventory() - local processor_stack = inv:get_stack("processor", 1) + local processor_stack = inv:get_stack('processor', 1) if processor_stack:is_empty() then meta:set_string('infotext', 'No crafting processor.') @@ -621,12 +619,10 @@ minetest.register_node('pipeworks:autocrafter', { end local usage_percent = 0 - if max_crafts > 0 then - usage_percent = math.floor((crafts_succeeded / max_crafts) * 100) - end + if max_crafts > 0 then usage_percent = math.floor((crafts_succeeded / max_crafts) * 100) end local infotext = string.format( - "Active, consuming %d power. | CPU Usage: %d%% (%d/%d)", + 'Active, consuming %d power. | CPU Usage: %d%% (%d/%d)', power_demand, usage_percent, crafts_succeeded, diff --git a/types/core.d.lua b/types/core.d.lua deleted file mode 100644 index ceb44836..00000000 --- a/types/core.d.lua +++ /dev/null @@ -1,836 +0,0 @@ ----@meta ----@version 5.1|JIT - --- This work is marked with CC0 1.0 - https://creativecommons.org/publicdomain/zero/1.0/ --- by frog :D --- Types for luanti - ----@class vector ----@field x number ----@field y number ----@field z number -vector = {} - ----@alias vectorT table|vector - ----@param x number ----@param y number ----@param z number ----@return vector -function vector.new(x, y, z) end - ----@return vector -function vector.zero() end - ----@param v vectorT ----@return vector -function vector.copy(v) end - ----Returns v, np, where v is a vector read from the given string s and np is the next position in the string after the vector. ----Returns nil on failure. ---- s: Has to begin with a substring of the form "(x, y, z)". Additional spaces, leaving away commas and adding an additional comma to the end is allowed. ----@return vector ----@param init integer? ----@param s string -function vector.from_string(s, init) end - ----@param v vectorT ----@return string -function vector.to_string(v) end - ----@param p1 vectorT ----@param p2 vectorT ----@return vector -function vector.direction(p1, p2) end - ----@param p1 vectorT ----@param p2 vectorT ----@return number -function vector.distance(p1, p2) end - ----@param v vectorT ----@return number -function vector.length(v) end - ----@param v vectorT ----@return vectorT -function vector.normalize(v) end - ----@param v vectorT ----@return vectorT -function vector.floor(v) end - ----@param v vectorT ----@return vectorT -function vector.round(v) end - ----@param v vectorT ----@param func function ----@return vector -function vector.round(v, func) end - ----@param v vectorT ----@param w vectorT ----@param func function ----@return vector -function vector.combine(v, w, func) end - ----@param v1 vectorT ----@param v2 vectorT ----@return boolean -function vector.equals(v1, v2) end - ----@param v1 vectorT ----@param v2 vectorT ----@return vector -function vector.sort(v1, v2) end - ----@param v1 vectorT ----@param v2 vectorT ----@return vector -function vector.angle(v1, v2) end - ----@param v1 vectorT ----@param v2 vectorT ----@return vector -function vector.dot(v1, v2) end - ----@param v1 vectorT ----@param v2 vectorT ----@return vector -function vector.cross(v1, v2) end - ----@param v1 vectorT ----@param v2 vectorT ----@return vector -function vector.offset(v1, v2) end - ----@param v any ----@return boolean -function vector.check(v) end - ----@param v number|vectorT ----@param x number|vectorT ----@return vector -function vector.add(v, x) end - ----@param v vectorT ----@param x number|vectorT ----@return vector -function vector.subtract(v, x) end - ----@param v vectorT ----@param x number ----@return vector -function vector.multiply(v, x) end - ----@param v vectorT ----@param x number|vectorT ----@return vector -function vector.divide(v, x) end - ----@param x vectorT ----@param min vectorT ----@param max vectorT ----@return boolean -function vector.in_area(x, min, max) end - ----@param pos vectorT ----@return number -function core.hash_node_position(pos) end - ----@class node ----@field name string ----@field param2 integer ----@field param1 integer - ----@class ObjectRef - -core = {} - ----@deprecated -minetest = core - ----@alias alias "mapgen_stone" | "mapgen_water_source" | "mapgen_river_water_source" | "mapgen_lava_source" | "mapgen_cobble" | "mapgen_singlenode" | string - ----@param alias alias ----@param original_name string ----@return nil -function core.register_alias(alias, original_name) end - ---- The only difference between core.register_alias and core.register_alias_force is that if an item named alias already exists, core.register_alias will do nothing while core.register_alias_force will unregister it. ----@param alias alias ----@param original_name string ----@return nil -function core.register_alias_force(alias, original_name) end - ----@class vector - ----@class sound_def ----@field gain number ----@field pitch number ----@field fade number ----@field start_time number ----@field loop boolean ----@field pos vector ----@field object ObjectRef ----@field to_player string ----@field exclude_player string ----@field max_hear_distance number - ----@class node_def: any - ----@type table -core.registered_nodes = {} - ---- x1, y1, z1, x2, y2, z2 ----@alias box table | nil ----@alias box_or_boxes box | table | nil - ----@class nodebox ----@field type string ----@field fixed box_or_boxes ----@field wall_top box ----@field wall_bottom box ----@field wall_side box ----@field connect_top box_or_boxes ----@field connect_bottom box_or_boxes ----@field connect_front box_or_boxes ----@field connect_left box_or_boxes ----@field connect_back box_or_boxes ----@field connect_right box_or_boxes ----@field disconnected_top box_or_boxes ----@field disconnected_bottom box_or_boxes ----@field disconnected_front box_or_boxes ----@field disconnected_left box_or_boxes ----@field disconnected_back box_or_boxes ----@field disconnected_right box_or_boxes ---- When there is *no* neighbour ----@field disconnected box_or_boxes ---- when there are *no* neighbours to the sides ----@field disconnected_sides box_or_boxes - ----@alias pointed_thing { type: "nothing" } | { type: "node", under: vector, above: vector, intersection_point: vector | nil, box_id: integer, intersection_normal: vector | nil} | { type: "object", ref: ObjectRef, intersection_point: vector | nil, box_id: integer, intersection_normal: vector | nil } - ----@class ItemStack_table ----@field name string ----@field count integer | nil ----@field wear integer | nil ----@field metadata string | nil - ----@alias group_type integer | nil - ----@class groups: { [string]: group_type } ----@field attached_node group_type ----@field bouncy group_type ----@field connect_to_raillike group_type ----@field dig_immediate group_type ----@field disable_jump group_type ----@field disable_descent group_type ----@field fall_damage_add_percent group_type ----@field falling_node group_type ----@field float group_type ----@field level group_type ----@field slippery group_type ----@field disable_repair group_type - ----@class armor_groups: { [string]: group_type } ----@field immortal group_type ----@field fall_damage_add_percent group_type ----@field punch_operable group_type - ----@param itemname string ----@param groupname string ----@nodiscard ----@return integer -function core.get_item_group(itemname, groupname) end - ----@class ItemStack:userdata - ---- #RGB defines a color in hexadecimal format. ----#RGBA defines a color in hexadecimal format and alpha channel. ----#RRGGBB defines a color in hexadecimal format. ----#RRGGBBAA defines a color in hexadecimal format and alpha channel. ----Named colors are also supported and are equivalent to CSS Color Module Level 4. To specify the value of the alpha channel, append #A or #AA to the end of the color name (e.g. colorname#08). ----@class ColorString:string - ----A ColorSpec specifies a 32-bit color. It can be written in any of the following forms: ---- table form: Each element ranging from 0..255 (a, if absent, defaults to 255): ---- colorspec = {a=255, r=0, g=255, b=0} ---- numerical form: The raw integer value of an ARGB8 quad: ---- colorspec = 0xFF00FF00 ---- string form: A ColorString (defined above): ---- colorspec = "green" ----@alias ColorSpec string|table|integer - ----@param color ColorString ----@return string -function core.get_color_escape_sequence(color) end - ----@param color ColorString ----@param message string ----@return string -function core.colorize(color, message) end - ----@param color ColorString ----@return string -function core.get_background_escape_sequence(color) end - ----@param str string ----@return string -function core.strip_foreground_colors(str) end - ----@param str string ----@return string -function core.strip_background_colors(str) end - ----@param str string ----@return string -function core.strip_colors(str) end - ----@param obj any ----@param name string? ----@param dumped table? ----@return string -function dump2(obj, name, dumped) end - ----@param obj any ----@param dumped table? ----@return string -function dump(obj, dumped) end - ----@param x number ----@param y number ----@return number -function math.hypot(x, y) end - ----@param x number ----@param tolerance number | nil ----@return number -function math.sign(x, tolerance) end - ----@param x number ----@return number -function math.factorial(x) end - ----@param x number ----@return number -function math.round(x) end - ----@param str string ----@param separator string | nil ----@param include_empty boolean|nil ----@param max_splits integer|nil ----@param sep_is_pattern boolean|nil ----@return table -function string.split(str, separator, include_empty, max_splits, sep_is_pattern) end - ----@return string -function string:trim() end - ----@param str string ----@param limit integer | nil ----@param as_table boolean | nil ----@return string | table -function core.wrap_text(str, limit, as_table) end - ----@param pos vector ----@param decimal_places integer | nil ----@return string -function core.pos_to_string(pos, decimal_places) end - ----@param relative_to vector | nil ----@param str string ----@return [vector, vector] -function core.string_to_area(str, relative_to) end - ----@param string string ----@return string -function core.formspec_escape(string) end - ----@param arg string ----@return string -function core.is_yes(arg) end - ----@param arg number ----@return boolean -function core.is_nan(arg) end - ----@return number -function core.get_us_time() end - ----@param table table ----@return table -function table.copy(table) end - ----@param list table ----@param val number ----@return integer -function table.indexof(list, val) end - ----@param table table ----@param other_table table -function table.insert_all(table, other_table) end - ----@param t table ----@return table -function table.key_value_swap(t) end - ----@param t table ----@param from integer? ----@param to integer? ----@param random_func function? -function table.shuffle(t, from, to, random_func) end - ----@param pointed_thing pointed_thing ----@param placer ObjectRef ----@return vector -function core.pointed_thing_to_face_pos(placer, pointed_thing) end - ----@param uses integer ----@param initial_wear integer? ----@return integer -function core.get_tool_wear_after_use(uses, initial_wear) end - ---- TEMPORARY CLASSES YO HEY ----@class tool_capabilities: table ----@class dig_params: table ----@class hit_params: table ----@class item_def: table ----@class abm_def: table ----@class lbm_def: table ----@class biome_def: table ----@class luaentity_def: table ----@class ore_def: table ----@class deco_def: table ----@class recipe_def: table ----@class priv_def: table ----@class chatcommand_def: table ----@class schem_def: table - ----@param tool_capabilities tool_capabilities ----@param groups table no its not the groups type for a reason ----@param wear integer? ----@return dig_params -function core.get_dig_params(groups, tool_capabilities, wear) end - ----@param groups table ----@param tool_capabilities tool_capabilities ----@param time_from_last_punch integer? ----@param wear integer? ----@return hit_params -function core.get_hit_params(groups, tool_capabilities, time_from_last_punch, wear) end - ----@param textdomain string? ----@return fun(str: string, ...:string ): string -function core.get_translator(textdomain) end - ----@param textdomain string? ----@param str string ----@vararg string -function core.translate(textdomain, str, ...) end - ----@param lang_code string ----@param string string -function core.get_translated_string(lang_code, string) end - ----@class NoiseParams ----@field offset integer ----@field scale integer ----@field spread vector ----@field seed integer ----@field octaves integer ----@field persistence integer ----@field lacunarity integer ----@field flags table|string|nil - ----@param p1 vector? ----@param p2 vector? ----@return VoxelManip -function core.get_voxel_manip(p1, p2) end - ----@class VoxelManip ----@operator call:fun(p1, p2):VoxelManip -VoxelManip = {} - ----returns actual emerged pmin, actual emerged pmax ----@param p1 vector ----@param p2 vector ----@return [vector, vector] -function VoxelManip:read_from_map(p1, p2) end - ----@param light boolean? -function VoxelManip:write_to_map(light) end - ----@param pos vector ----@return node -function VoxelManip:get_node_at(pos) end - ----@param pos vector ----@param node node -function VoxelManip:set_node_at(pos, node) end - ----@class content_ids:integer - ----@param buffer table? ----@return table -function VoxelManip:get_data(buffer) end - ----@param data table -function VoxelManip:set_data(data) end - ----Does literally nothing lmao ----@deprecated ----@return nil -function VoxelManip:update_map() end - ---- day = 0...15, night = 0...15 ----@alias vmanip_light { day: integer, night: integer } - ----@param light vmanip_light ----@param p1 vector? ----@param p2 vector? -function VoxelManip:set_lighting(light, p1, p2) end - ----@param buffer table? ----@return table? -function VoxelManip:get_light_data(buffer) end - ----@param param2_data table ----@return nil -function VoxelManip:set_param2_data(param2_data) end - ----@param p1 vector? ----@param p2 vector? ----@param propagate_shadow boolean? -function VoxelManip:calc_lighting(p1, p2, propagate_shadow) end - ----@return nil -function VoxelManip:update_liquids() end - ----@return boolean -function VoxelManip:was_modified() end - ----@return [vector, vector] -function VoxelManip:get_emerged_area() end - ----@class VoxelArea -VoxelArea = {} ----@operator call:fun(pmin, pmax):VoxelArea|fun(edges: { MinEdge: vector, MaxEdge: vector }):VoxelArea - ----@param pmin vector ----@param pmax vector ----@return VoxelArea -function VoxelArea:new(pmin, pmax) end - ----@param t { MinEdge: vector, MaxEdge: vector } ----@return VoxelArea -function VoxelArea:new(t) end - ----@return vector -function VoxelArea:getExtent() end - ----@return vector -function VoxelArea:getVolume() end - ----@param x number ----@param y number ----@param z number ----@return integer -function VoxelArea:index(x, y, z) end - ----@param p number ----@return integer -function VoxelArea:indexp(p) end - ----@param i integer ----@return vector -function VoxelArea:position(i) end - ----@param x number ----@param y number ----@param z number ----@return boolean -function VoxelArea:contains(x, y, z) end - ----@param p vector ----@return boolean -function VoxelArea:containsp(p) end - ----@param i integer ----@return boolean -function VoxelArea:containsi(i) end - ----@param minx number ----@param miny number ----@param minz number ----@param maxx number ----@param maxy number ----@param maxz number ----@nodiscard -function VoxelArea:iter(minx, miny, minz, maxx, maxy, maxz) end - ----@param minp vector ----@param maxp vector ----@nodiscard -function VoxelArea:interp(minp, maxp) end - ----@class l_system_tree_def ----@field axiom string ----@field rules_a string|nil ----@field rules_b string|nil ----@field rules_c string|nil ----@field rules_d string|nil ----@field trunk string ----@field leaves string ----@field leaves2 string ----@field leaves2_chance string ----@field angle number ----@field iterations number ----@field random_level number ----@field trunk_type "single"|"double"|"crossed" ----@field thin_branches boolean ----@field fruit string ----@field fruit_chance number ----@field seed number|nil - ----@return string -function core.get_current_modname() end - ----@param modname string ----@return string -function core.get_modpath(modname) end - ----@return string[] -function core.get_modnames() end - ----@return { id: string, title:string, author: string, path:string} -function core.get_game_info() end - ----@return string -function core.get_worldpath() end - ----@return string -function core.get_mod_data_path() end - ----@return boolean -function core.is_singleplayer() end - ---- no im not gonna type the entire thing out, NO, no chance ----@type table -core.features = {} - ----@param arg string | table ----@return boolean, table -function core.has_feature(arg) end - ----@class player_info_def ----@field address string, # IP address of client ----@field ip_version number, # IPv4 / IPv6 ----@field connection_uptime number, # seconds since client connected ----@field protocol_version number, # protocol version used by client ----@field formspec_version number, # supported formspec version ----@field lang_code string, # Language code used for translation ----@field min_rtt number? ----@field max_rtt number? ----@field avg_rtt number? ----@field min_jitter number? ----@field max_jitter number? ----@field avg_jitter number? - ----@alias vector2 { x: number, y:number } - ----@class window_info_def ----@field size vector2 ----@field max_formspec_size vector2 ----@field real_gui_scaling number ----@field real_hud_scaling number ----@field touch_controls boolean - ----@param player_name string ----@return player_info_def -function core.get_player_information(player_name) end - ----@param player_name string ----@return window_info_def -function core.get_player_window_information(player_name) end - ----@param path string ----@return boolean -function core.mkdir(path) end - ----@param path string ----@param recursive boolean ----@return boolean -function core.rmdir(path, recursive) end - ----@param source string ----@param destination string ----@return boolean -function core.cpdir(source, destination) end - ----@param source string ----@param destination string ----@return boolean -function core.mvdir(source, destination) end - ----@param is_dir boolean? ----@param path string ----@return string[] -function core.get_dir_list(path, is_dir) end - ----Replaces contents of file at path with new contents in a safe (atomic) way. Use this instead of below code when writing e.g. database files: local f = io.open(path, "wb"); f:write(content); f:close() ----@param path string ----@param content string ----@return boolean -function core.safe_file_write(path, content) end - ----@class mt_version_def ----@field project string ----@field string string ----@field proto_min integer ----@field proto_max integer ----@field hash string ----@field is_dev boolean - ----@return mt_version_def -function core.get_version() end - ----@param data string ----@param raw? boolean ----@return string -function core.sha1(data, raw) end - ----@return string ----@param data string ----@param raw boolean? -function core.sha256(data, raw) end - ----@param colorspec ColorSpec|any ----@return ColorString? -function core.colorspec_to_colorstring(colorspec) end - ----@param colorspec ColorSpec|any ----@return string? -function core.colorspec_to_bytes(colorspec) end - ----@return string ----@param width integer ----@param height integer ----@param data ColorSpec[]|string ----@param compression integer? -function core.encode_png(width, height, data, compression) end - ----@param str string ----@return string -function core.urlencode(str) end - ----@param ... any -function core.debug(...) end - ----@param level "none"|"error"|"warning"|"action"|"info"|"verbose" ----@param text string ----@return nil -function core.log(level, text) end - ----@param text string ----@return nil -function core.log(text) end - ----@param name string ----@param node_def node_def ----@return nil -function core.register_node(name, node_def) end - ----@param name string ----@param item_def item_def ----@return nil -function core.register_craftitem(name, item_def) end - ----@param name string ----@param item_def item_def ----@return nil -function core.register_tool(name, item_def) end - ----@param name string ----@param redefinition table ----@param del_fields table? ----@return nil -function core.override_item(name, redefinition, del_fields) end - ----@param name string ----@return nil -function core.unregister_item(name) end - ----@param name string ----@param luaentity_def luaentity_def ----@return nil -function core.register_entity(name, luaentity_def) end - ----@param abm_def abm_def ----@return nil -function core.register_abm(abm_def) end - ----@param lbm_def lbm_def ----@return nil -function core.register_lbm(lbm_def) end - ----@param ore_def ore_def ----@return nil -function core.register_ore(ore_def) end - ----@param biome_def biome_def ----@return nil -function core.register_biome(biome_def) end - ----@param name string ----@return nil -function core.unregister_biome(name) end - ----@param deco_def deco_def ----@return nil -function core.register_decoration(deco_def) end - ----@param schem_def schem_def ----@return nil -function core.register_schematic(schem_def) end - ----@return nil -function core.clear_registered_biomes() end - ----@return nil -function core.clear_registered_decorations() end - ----@return nil -function core.clear_registered_schematics() end - ----@param recipe recipe_def ----@return nil -function core.register_craft(recipe) end - ----@param recipe recipe_def ----@return nil -function core.clear_craft(recipe) end - ----@param chatcommand_def chatcommand_def ----@return nil -function core.register_chatcommand(cmd, chatcommand_def) end - ----@param redef table ----@param name string ----@return nil -function core.override_chatcommand(name, redef) end - ----@param name string ----@param redef table ----@return nil -function core.unregister_chatcommand(name, redef) end - ----@param def priv_def ----@param name string ----@return nil -function core.register_privilege(name, def) end - ---- this function is so absurdly uncommon im not going to bother ----@param auth_handler_def table -function core.register_authentication_handler(auth_handler_def) end diff --git a/types/luanti_lsp_definitions/.cspell.json b/types/luanti_lsp_definitions/.cspell.json new file mode 100644 index 00000000..7a31c11f --- /dev/null +++ b/types/luanti_lsp_definitions/.cspell.json @@ -0,0 +1,22 @@ +{ + "$schema": "https://raw.githubusercontent.com/streetsidesoftware/cspell/main/cspell.schema.json", + "allowCompoundWords": true, + "dictionaryDefinitions": [ + { + "name": "luanti", + "path": "utils/.cspell-luanti.txt", + "addWords": true + }, + { + "name": "misc", + "path": "utils/.cspell-misc.txt", + "addWords": true + } + ], + "dictionaries": ["lua", "luanti", "misc", "public-licenses"], + "ignorePaths": [ + "utils/.cspell-luanti.txt", + "utils/.cspell-misc.txt", + "LICENSE" + ], +} diff --git a/types/luanti_lsp_definitions/.gitignore b/types/luanti_lsp_definitions/.gitignore new file mode 100644 index 00000000..2f151ff8 --- /dev/null +++ b/types/luanti_lsp_definitions/.gitignore @@ -0,0 +1,37 @@ +*~ + +# vscode(ium) +.vscode/* +.vscode/settings.json +!.vscode/tasks.json +!.vscode/launch.json +!.vscode/extensions.json +!.vscode/*.code-snippets +!*.code-workspace + +# (neo)vim +[._]*.s[a-v][a-z] +!*.svg +[._]*.sw[a-p] +[._]s[a-rt-v][a-z] +[._]ss[a-gi-z] +[._]sw[a-p] +Session.vim +Sessionx.vim +.netrwhist +tags + +# emacs +*~ +\#*\# +/.emacs.desktop +/.emacs.desktop.lock +*.elc +auto-save-list +tramp +.\#* +.org-id-locations +*_archive +*_flymake.* +.projectile +.dir-locals.el \ No newline at end of file diff --git a/types/luanti_lsp_definitions/.luarc.json b/types/luanti_lsp_definitions/.luarc.json new file mode 100644 index 00000000..7c60475b --- /dev/null +++ b/types/luanti_lsp_definitions/.luarc.json @@ -0,0 +1,4 @@ +{ + "$schema": "https://raw.githubusercontent.com/LuaLS/vscode-lua/master/setting/schema.json", + "runtime.version": "LuaJIT" +} diff --git a/types/luanti_lsp_definitions/CHANGELOG.md b/types/luanti_lsp_definitions/CHANGELOG.md new file mode 100644 index 00000000..e69de29b diff --git a/types/luanti_lsp_definitions/LICENSE b/types/luanti_lsp_definitions/LICENSE new file mode 100644 index 00000000..13749ff4 --- /dev/null +++ b/types/luanti_lsp_definitions/LICENSE @@ -0,0 +1,38 @@ +For parts original in Luanti_lsp_definitions: +--------------------------------------------- + +Copyright (C) 2025 + corpserot a.k.a Acorp <@corpserot on github> + TheEt1234 a.k.a frog <@TheEt1234 on github> +and contributors (see version control log for their names and contact details) + +Licensed under the GNU Lesser General Public License, version 2.1 (or later). +--- + +For parts from Luanti: +---------------------- + +Copyright (C) 2010-2025 + celeron55, Perttu Ahola +and contributors (see respective project source file comments and the version control log) + +Licensed under the GNU Lesser General Public License, version 2.1 (or later). +--- + +LGPLv2.1 license notice: +------------------------ + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation; either version 2.1 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License along +with this program; if not, write to the Free Software Foundation, Inc., +51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +--- diff --git a/types/luanti_lsp_definitions/MAINTENANCE.md b/types/luanti_lsp_definitions/MAINTENANCE.md new file mode 100644 index 00000000..82e497c5 --- /dev/null +++ b/types/luanti_lsp_definitions/MAINTENANCE.md @@ -0,0 +1,141 @@ +# Guidelines +You should try to get new information merged into the following places first. These are considered *primary sources*. e.g. You want to clarify that object rotations are actually right-handed. You should make a PR to these repos first. +- , usually something within `doc` directory. +- + +This project represents yet another place to document Luanti API . This time, through annotation. It is expected that this project will have some extra information not suitable for inclusion in the primary sources. + +Contributors should get familiar with [LuaCATS, the annotation & type system](https://luals.github.io/wiki/annotations) used in this project. Please read this document in full \:D + +## Annotation conventions +### Annotation flavours +These are the main annotation flavours used by other Lua library definition projects: +1. LuaCATS: currently the most popular annotation flavour. Product of the [LuaLS project](https://luals.github.io/) +2. EmmyLua: renewed annotation flavour now fully supporting LuaCATS. Product of the [EmmyLua project](https://github.com/EmmyLuaLs/emmylua-analyzer-rust) + +For compatibility with both great projects, the subset of both is used which currently means that annotations are written in LuaCATS. In the future, this may change as EmmyLua development outpaces LuaLS. + +### `@class` and inheritance +LuaCATS' `@class` allows us to create plain table types, or perhaps better known in Luanti as *definition tables*. + +Next, inheritance refers to how these `@class` types can mix together into one. This is useful to split up fields and methods to reduce duplication. The following describes the conventions used in this library definition: + +- `*.__base`: Designates the main base type, usually acting as the sub-`@class` to a multitude of variant types. + +- `*.__partial`: Designates a sub-`@class` with extra fields and functions unique to a subset of variant types + +- `*.fmt`: Designates a sub-type in the format of that `` + - `tablefmt` is the most common sub-type format, followed by `stringfmt` + +### Field limitations +Many annotation keywords just don't work with fields, so it's placed inside the documentation text. + +```lua +--[[ +This is my field + +* @default `false` for players, `true` for entities +* @deprecated 5.12 Consider doing Y instead +* @see [lua_api.md > 'core' namespace reference > section](https://api.luanti.org/core-namespace-reference/#section) > `core.function` +]] +---@field my_field boolean? +``` + +Not supported: +- `@default` +- `@deprecated` +- `@see` + +### Aliases +LuaCATS' `@alias`se are used in many ways in this library definition. Any special values will be suggested by the language server, so it's useful from that perspective too. Common techniques are listed below: + +- Used to annotate [nominal types](#nominal-types). + +- Used to create non-table enums also known as special values. This is *very* common in Luanti API. Table enums annotated with `@enum` are very rare in comparison. Sometimes, it's actually a primitive type with handling for a few special values.\ + Sometimes indicated by `*.special` + +- Used to create table key enums. In absence of `keyof` like in typescript, this is implemented by the error-prone approach of just writing it like a non-table enum.\ + Sometimes indicated by `*.keys` + +### Nominal types +Some types derived from primitive types have no differences whatsoever in the annotation type system. In some cases however, it is useful to give these types names even if it's not possible to express its true restrictions and rules. We call these types *nominal types*\ + +To qualify as a *Nominal types*, it must have special restrictions, rules or contents that is not expressible through the annotation type system. This rule is to prevent flooding the library definition with too many useless verbose types. The following lists specifics about this rule: +- Built-in special values satisfies this rule. A different interpretation is that a nominal type is needed to suggest special values such as table keys or enums. + - e.g. Item names violates some subrules below. However, it has special values `"air"`, `"ignore"` and others. So, it is granted a `string` nominal type `core.Item.name`. +- Name syntax/specification does not satisfy this rule. + - e.g. LBM names (should) have a special syntax `:`. But, it isn't granted a `string` nominal type `core.LBMDef.name` +- General integer/number range limitations does not satisfy this rule. + - e.g. world units in nodes are limited to within [-31000,31000]. But, it isn't granted a `number` or `integer` nominal type `core.WorldUnit` + - e.g. Node params has special meanings and conversion rules, not just a [0,255] range. So, it is granted an `integer` nominal type `core.Param2` +- General units does not satisfy this rule. + - e.g. `ObjectRef` health does not use a unit, or could be interpreted as a very general unit used everywhere. So, it isn't granted an `integer` nominal type `core.ObjectRef.hp` + - e.g. Tool wear uses a unit unique to Luanti with some special rules in how to interpret it. So, it is granted an `integer` nominal type `core.Tool.wear` + +### Other conventions + +- Use `--[[ ... ]]` comment blocks to indicate the documentation text. + - Requirements below are loose, but consider using `@see` to defer information to the primary sources. + - It may be up to 32 lines long and at most 80 characters long, not including the brackets. + - Do not include examples in annotations if it is too long (>8 lines). Use `@see`\ + e.g. `core.LSystemTreeDef` has a 15 line example, thusly it is excluded. + +- Mark deprecated or discouraged practices with `@deprecated`.\ + e.g. using `minetest` namespace. + +- Implementation details can be intentionally opaque or hidden where useful.\ + e.g. the `number` handle returned by `core.sound_play(...)` is instead annotated as `core.SoundHandle`. + +- While it is *preferred* to maintain the primary sources text verbatim, it's usually too lengthy to be included as-is or would create a confusing amalgamation. This library definition *derives* from the primary sources, not simply copy it. + +- Naming conventions: + - All type names must be under the `core.*` namespace. The immediate name must be in `PascalCase` while the rest are in `snake_case`\ + e.g. `core.ParticleSpawner.tween.float_range` + - `vector` types are considered to be a "primitive" and are exempt. + - General purpose helper types are exempt. + - If a name is not explicitly provided in the primary sources, please derive a sensible name + +- Do not annotate implicit typecasting as valid practice.\ + e.g. (*Rejected*) `number` to `string` automatic casting for `MetaDataRef:set_string(...)` because it uses `luaL_checklstring(...)` + +- Do not discard useful return values by annotating `@nodiscard` + +- Do not annotate undocumented `builtin/*.lua` APIs. These APIs shouldn't be exposed in this project as it is out of scope. + - There's exceptions for common builtins spotted in (usually older) mods and games. It's expected that this would shrink as more internal symbols get documented in `lua_api.md` + +# Maintenance +## Update checklist +Every time the definition files are updated please check through this list: +1. [Check and test](#checking-and-testing) your modifications. +2. Run through the [`cspell` checker](#spell-checking). +3. Update the commit hash at the top of the `README.md`. +4. Is there a Luanti stable release update? grep for the last release version and update wherever necessary. + +## Checking and testing +After updating or adding more complicated symbols, you should test if your annotation appears correctly. Make a temporary Lua project outside of the library definition and play around with related symbols, you don't need to run it in Luanti. You may need to restart LuaLS as you modify annotations. + +Another way of checking whether your annotation is correct is to try it out with existing mods and games. This is a bit advanced since you're expected to know how to create your own `.luarc.json` file for that project if it doesn't have one (very common). Perhaps even make a custom definition file for that project due to meddling with engine APIs. + +## Looking up the implementation and use of a symbol +Sometimes, the primary sources does not really document the API very well leading to confusion, or that you felt that the primary sources missed something. You will need to search through Luanti's source code for mentions of that symbol. You may use `find`, `grep`, `fzf`, your built-in editor project-wide search, LSP symbols search, etc to ease the work. You'll become more familiar with the codebase as you do this more often, so don't get discouraged! + +**EXAMPLE** Let's say you vaguely remember seeing shaped craft recipes passed to `core.register_craft(recipe)` accepting `core.ItemStack`s. Here are some searches you could try to check its implementation: +- `^//.*register_craft` regex in C++ source code files +- `"registered_craft"` regex in C++ source code files +- `function.*register_craft` regex in Lua files under `builtin/*` +- `registered_craft` regex in Lua files under `builtin/*` +- Or any other more specific searches. Reading the code surrounding the results will lead you to a better understanding of the codebase. + +## Tracking new Luanti changes +For lazier maintenance, you can check Luanti's `doc` directory git history when tracking down new changes. You should also use the commit from that directory's git history when accounting for *last Luanti commit* instead of the repository as a whole. + +Sometimes, there could be API and implementation details outside of `doc` important to annotate. Feel free to defer that work to whoever spots that mistake. + +It's recommended that you get familiar with Git, or have tools to help you. + +## Spell Checking +For spell checking, [`cspell`](https://cspell.org/) is used. You are encouraged to set it up for your editor or use it as-is. + +- With npm, you can run it simply like so `npx cspell path/to/repo` +- For VSCode users, you can use [Code Spell Checker](https://marketplace.visualstudio.com/items?itemName=streetsidesoftware.code-spell-checker) +- For Neovim users, you can use [cspell.nvim](https://github.com/davidmh/cspell.nvim). It depend on null-ls/none-ls however. \ No newline at end of file diff --git a/types/luanti_lsp_definitions/README.md b/types/luanti_lsp_definitions/README.md new file mode 100644 index 00000000..0237a425 --- /dev/null +++ b/types/luanti_lsp_definitions/README.md @@ -0,0 +1,135 @@ +# Luanti LuaLS Definitions +- **Status:** DRAFT 2 WIP (see [this issue tracker](https://github.com/corpserot/luanti_lsp_definitions/issues/6)) +- **Luanti commit coverage:** `421835a3` (`5.14.X`) +- **Target projects when testing:** + - [Minetest Game (MTG)](https://github.com/luanti-org/minetest_game) commit `0ebe46e4`\ + With a custom LuaLS config (To be published). +- **Scheduled breaking changes**: Anytime, still in development. + + +# Why to use +This enables a lua language server to operate with Luanti APIs and types. This in turn allows for IDE-like capabilities including but not limited to: +- Typed annotation system called LuaCATS a la JSDoc annotations. Has definition files like Typescript `.d.ts` files. +- Diagnostics through semantic analysis, replacing [luacheck](https://github.com/mpeterv/luacheck) completely +- Autocompletion and hover information for API symbols, types, fields and more. + +# How to use +- Install [Lua Language Server, LuaLS](https://luals.github.io/) or [EmmyLua](https://github.com/EmmyLuaLs/emmylua-analyzer-rust) for your favourite text editor. Make sure it works first! ^v^ + - For VSCode users, you get first-class support with extra features enabled. So, please visit relevant first-party guides. + - For Neovim users, you have many ways to configure your language server. As of 2025-08-25 there isn't any (easy and simple) setup that interactively asks you whether to enable an addon for a workspace/project. +- Manual setup for single library definitions (Recommended for one-off uses): + - Git clone this repository. + - In your personal project config, add entries below. Optionally, manually inject whatever is inside `config.json` > `"settings"` into your LuaLS config. That entry contains recommended settings for Luanti game and mod development. + ```json + { + "workspace.library": ["/path/to/luanti-lsp-definitions/library"], + // e.g. selecting this specifically from "settings.Lua" entry in config.json: + "diagnostics.disable": [ + "lowercase-global" + ], + } + ``` +- Manual setup for collection of library definitions (Recommended for multiple library definition uses): + - Git clone this repository into this file structure: `luals_addons/luanti-lsp-definitions`. This allows you to add more addons under the same directory, e.g. `luals_addons/busted` for the testing suite. + - in your config, add entries below. The `Apply` value allows the LSP to read library definitions without asking, provided you matched the criteria to enable it. + ```json + { + "workspace.checkThirdParty": "Apply", + "workspace.userThirdParty": ["/path/to/luals_addons"] + } + ``` +- Automatic setup: WIP as this project is still in development. + +## Using this as a Luanti game/mod developer +After following the above instructions, in the context of annotations, you are left with two types of dependencies for your game/mod: Annotated dependencies and Un-annotated dependencies + +- *Annotated dependencies* and *Un-annotated dependencies* as-is: + - Game developers simply just include them in their project without any further additions. + + - Mod developers should put them inside a `.gitignore`d directory where you can safely fetch/clone your dependencies without distributing them. `.git/info/exclude` is an alternative choice. + + - You may notice errors due to how language server configurations are applied project-wide instead of scoped to the dependencies. Unfortunately, this approach means that you need to apply the same project-wide diagnostics configuration. + - Please do not rely on setting project-wide diagnostics in your game/mod. Instead use file-scoped or line diagnostics directives.\ + e.g `---@diagnostic disable-next-line: lowercase-global` + +- *Un-annotated dependencies* and you wish to annotate it: + - There's two ways of approaching this: + 1. (*Simple, recommended*) Annotate the dependency's code. + 2. (*Complicated, niche needs*) Annotate a separate library definition. This is the approach used by this Luanti library definition. + - There are benefits to either or both approaches, however the usual approach is to annotate the dependency's code. + + +### Namespace reservation +If you use this library definition, you acknowledge that it reserves the following type namespaces +- `_.*` +- `core.*` +- `corelib.*` +- vector "primitive" types. + +Helper types are listed below. More may be added. +- `OneOrMany` +- `SparseList` + +It's recommended that you own annotations sit inside a namespace i.e. `.MyType` + +# File Structure +- `.luarc.json` is the default LuaLS project configuration. You're expected to override it with your editor's personal project configuration. +- (NYI) `.emmyrc.json` is the default EmmyLua project configuration. You're expected to override it with your editor's personal project configuration. +- `config.json` is this library definition's configuration file. The `"settings"` portion should be minimal to encourage the developer to decide their own language server configurations. +- `MAINTAINENCE.md` is the guide for maintaining this project. Please read it if you would like to contribute. +- `library/` has definition files related to engine API. There is a short description at the top of each file. The contents are arranged following `lua_api.md` + - `library/classes/` has definition files related to classes. + - `library/core/` has definition files related to the `core` namespace. + - `library/vector` has definition files related to vectors + - `library/defs/` has definition files catching the rest of the `lua_api.md` contents. + +# Questions and Answers +## If i use this, do i have to use a LGPL-compliant license for my game/mod? +***Disclaimer: I am not a lawyer, and nothing in this material should be taken as legal advice. It may even be inaccurate. No attorney–client relationship is created by your use of this information provided for informative purposes. You should not act or rely on any information provided here without seeking the advice of a qualified attorney licensed in your jurisdiction. I disclaim all liability for actions you take or fail to take based on any content provided.*** + +You may skip this if you're well-informed about copyleft software licenses. + +The answer is probably not... well, it depends. You can embed or use this library definition alongside your game/mod. However, please don't copy-paste contents of this library definition straight into your code. Particularly, the documentation text itself has to be treated a bit more carefully. + +**Example:** Person A wrote a mod with a permissive license like MIT or 0BSD. If person A carelessly include content of this library definition into the mod's `init.lua`, then a portion of that file is at risk of being subjected to LGPL terms due to documentation text. + +If you would like to modify or derive contents of this library definition, it's recommended to treat your derived work like a separate module from your game/mod. It could be simply a separate directory or file. + +**Example:** Person A, being careful this time, copy-pastes parts of this library definition into a separate definition file `.defs.lua`. This would help isolate where LGPL terms apply. + +## How do i extend types? +You can extend existing classes like so: +```lua +---@class core.ItemDef +---@field _mymod_rarity integer + +--- Sometimes, you'll have to work with internal classes +---@class _.ObjectProperties.__base +---@field _mymod_power integer +``` + +However, it's expected that you need delve into this project's definitions as you're likely to extend the wrong type or an alias (cannot be extended using this technique). + +Be on the lookout for scheduled breaking changes. + +## I think this primitive type should get a name, like how `core.Formspec` is just a `string`! +Please open an issue for discusssion. In particular, you're encouraged to read about [*Nominal types*](https://github.com/corpserot/luanti_lsp_definitions/blob/master/MAINTENANCE.md#nominal-types) to help you justify why it should get a name. You should also search in this repo's issues if it's already discussed or not. + +## Why not contribute to [`luanti-lls-definitions by @fgaz`](https://codeberg.org/fgaz/luanti-lls-definitions)? +For context, that is the existing solution before this library definition was conceived. + +(by @frog) So i tried to use luanti-lls-definitions but those were really incomplete, and i didn't feel like contributing back to them\ +And i felt like it would be easier to start from scratch than to attempt to complete them. + +(by @corpserot) Well, there's a couple of reasons: +1. first and foremost that project uses an unreliable method to extract information from `lua_api.md` using TCL (seriously??) +2. @fgaz is very inactive in updating the definition files (check commits since project inception). It's very incomplete. +3. It uses EUPL license, which overcomplicates matters as it resembles closer to AGPLv3.0 than LGPLv2.1. Yet, it won't deter people that are already set on violating FOSS licenses. We don't use any definitions from that project, obviously. +4. I don't think @fgaz actually uses the definitions themself (dogfooding). + +## Why not contribute to [luanti-api by @archie](https://git.minetest.land/archie/luanti-api/)? +See this issue: [luanti-api#21](https://git.minetest.land/archie/luanti-api/issues/21) \ No newline at end of file diff --git a/types/luanti_lsp_definitions/config.json b/types/luanti_lsp_definitions/config.json new file mode 100644 index 00000000..56b58a91 --- /dev/null +++ b/types/luanti_lsp_definitions/config.json @@ -0,0 +1,21 @@ +{ + "$schema": "https://raw.githubusercontent.com/LuaLS/LLS-Addons/main/schemas/addon_config.schema.json", + "words": [ + "luanti", + "minetest", + "formspec", + "luaentity", + "core%.get_current_modname", + "core%.get_modpath" + ], + "settings": { + "Lua" : { + "diagnostics.disable": [ + "lowercase-global" + ], + "diagnostics.severity": { + "duplicate-set-field": "Information!" + } + } + } +} \ No newline at end of file diff --git a/types/luanti_lsp_definitions/library/classes/AreaStore.lua b/types/luanti_lsp_definitions/library/classes/AreaStore.lua new file mode 100644 index 00000000..f0b78549 --- /dev/null +++ b/types/luanti_lsp_definitions/library/classes/AreaStore.lua @@ -0,0 +1,301 @@ +---@meta _ +-- DRAFT 1 DONE +-- luanti/doc/lua_api.md: Class reference > `AreaStore` + +--[[ +WIPDOC +]] +---@class core.AreaStoreID : integer + +-- ----------------------------- AreaStore.area ----------------------------- -- + +--[[ +WIPDOC +]] +---@class core.AreaStore.area.include_corners +--[[ +WIPDOC +]] +---@field min ivec +--[[ +WIPDOC +]] +---@field max ivec + + +--[[ +WIPDOC +]] +---@class core.AreaStore.area.include_data +--[[ +WIPDOC +]] +---@field data string + +--[[ +WIPDOC +]] +---@class core.AreaStore.area.include_all : core.AreaStore.area.include_corners, core.AreaStore.area.include_data + +-- ------------------------- AreaStore.cache_params ------------------------- -- + +--[[ +WIPDOC +]] +---@class core.AreaStore.cache_params +--[[ +WIPDOC +]] +---@field enabled boolean? +--[[ +WIPDOC +]] +---@field block_radius integer? +--[[ +WIPDOC +]] +---@field limit integer? + +-- ------------------------------- constructor ------------------------------ -- + +--[[ +Unofficial note: I am aware that "Luanti" isn't a valid AreaStore type, but that makes it default to Luanti functions so, is it not accurate? +* `AreaStore(type_name)` + * Returns a new AreaStore instance + * `type_name`: optional, forces the internally used API. + * Possible values: `"LibSpatial"` (default). + * When other values are specified, or SpatialIndex is not available, + the custom Luanti functions are used. +]] +---@nodiscard +---@param type "LibSpatial"|string? +---@return core.AreaStore +function AreaStore(type) end + +-- -------------------------------- AreaStore ------------------------------- -- + +--[[ +`AreaStore` +----------- + +AreaStore is a data structure to calculate intersections of 3D cuboid volumes +and points. The `data` field (string) may be used to store and retrieve any +mod-relevant information to the specified area. + +Despite its name, mods must take care of persisting AreaStore data. They may +use the provided load and write functions for this. + +]] +---@class core.AreaStore +AreaStore = {} + +--[[ +WIPDOC +]] +---@nodiscard +---@param id core.AreaStoreID +---@param include_corners false? +---@param include_data false? +---@return true? +function AreaStore:get_area(id, include_corners, include_data) end + +--[[ +WIPDOC +]] +---@nodiscard +---@param id core.AreaStoreID +---@param include_corners true +---@param include_data false? +---@return core.AreaStore.area.include_corners? +function AreaStore:get_area(id, include_corners, include_data) end + +--[[ +WIPDOC +]] +---@nodiscard +---@param id core.AreaStoreID +---@param include_corners false? +---@param include_data true +---@return core.AreaStore.area.include_data? +function AreaStore:get_area(id, include_corners, include_data) end + +--[[ +WIPDOC +]] +---@nodiscard +---@param id core.AreaStoreID +---@param include_corners true +---@param include_data true +---@return core.AreaStore.area.include_all? +function AreaStore:get_area(id, include_corners, include_data) end + +--[[ +WIPDOC +]] +---@nodiscard +---@param id core.AreaStoreID +---@param include_corners false? +---@param include_data false? +---@return table +function AreaStore:get_areas_for_pos(id, include_corners, include_data) end + +--[[ +WIPDOC +]] +---@nodiscard +---@param id core.AreaStoreID +---@param include_corners true +---@param include_data false? +---@return table +function AreaStore:get_areas_for_pos(id, include_corners, include_data) end + +--[[ +WIPDOC +]] +---@nodiscard +---@param id core.AreaStoreID +---@param include_corners false? +---@param include_data true +---@return table +function AreaStore:get_areas_for_pos(id, include_corners, include_data) end + +--[[ +WIPDOC +]] +---@nodiscard +---@param id core.AreaStoreID +---@param include_corners true +---@param include_data true +---@return table +function AreaStore:get_areas_for_pos(id, include_corners, include_data) end + +--[[ +WIPDOC +]] +---@nodiscard +---@param pos1 ivector +---@param pos2 ivector +---@param accept_overlap boolean +---@param include_corners false? +---@param include_data false? +---@return table +function AreaStore:get_areas_in_area(pos1, pos2, accept_overlap, include_corners, include_data) end + +--[[ +WIPDOC +]] +---@nodiscard +---@param pos1 ivector +---@param pos2 ivector +---@param accept_overlap boolean +---@param include_corners true +---@param include_data false? +---@return table +function AreaStore:get_areas_in_area(pos1, pos2, accept_overlap, include_corners, include_data) end + +--[[ +WIPDOC +]] +---@nodiscard +---@param pos1 ivector +---@param pos2 ivector +---@param accept_overlap boolean +---@param include_corners false? +---@param include_data true +---@return table +function AreaStore:get_areas_in_area(pos1, pos2, accept_overlap, include_corners, include_data) end + +--[[ +WIPDOC +]] +---@nodiscard +---@param pos1 ivector +---@param pos2 ivector +---@param accept_overlap boolean +---@param include_corners true +---@param include_data true +---@return table +function AreaStore:get_areas_in_area(pos1, pos2, accept_overlap, include_corners, include_data) end + +--[[ +* `insert_area(corner1, corner2, data, [id])`: inserts an area into the store. + * Returns the new area's ID, or nil if the insertion failed. + * The (inclusive) positions `corner1` and `corner2` describe the area. + * `data` is a string stored with the area. + * `id` (optional): will be used as the internal area ID if it is a unique + number between 0 and 2^32-2. +]] +---@nodiscard +---@param corner1 ivector +---@param corner2 ivector +---@param data string +---@param id core.AreaStoreID? +---@return core.AreaStoreID? +function AreaStore:insert_area(corner1, corner2, data, id) end + +--[[ +* `reserve(count)` + * Requires SpatialIndex, no-op function otherwise. + * Reserves resources for `count` many contained areas to improve + efficiency when working with many area entries. Additional areas can still + be inserted afterwards at the usual complexity. +]] +---@param count integer +function AreaStore:reserve(count) end + +--[[ +* `remove_area(id)`: removes the area with the given id from the store, returns + success. +]] +---@nodiscard +---@param id core.AreaStoreID +---@return boolean +function AreaStore:remove_area(id) end + +--[[ +* `set_cache_params(params)`: sets params for the included prefiltering cache. + Calling invalidates the cache, so that its elements have to be newly + generated. + * `params` is a table with the following fields: + ```lua + { + enabled = boolean, -- Whether to enable, default true + block_radius = int, -- The radius (in nodes) of the areas the cache + -- generates prefiltered lists for, minimum 16, + -- default 64 + limit = int, -- The cache size, minimum 20, default 1000 + } + ``` +]] +---@param params core.AreaStore.cache_params +function AreaStore:set_cache_params(params) end + +--[[ +* `to_string()`: Experimental. Returns area store serialized as a (binary) + string. +]] +---@nodiscard +---@return string +function AreaStore:to_string() end + +--[[ +* `to_file(filename)`: Experimental. Like `to_string()`, but writes the data to + a file. +]] +---@param filename core.Path +function AreaStore:to_file(filename) end + +--[[ +* `from_string(str)`: Experimental. Deserializes string and loads it into the + AreaStore. + Returns success and, optionally, an error message. +]] +---@param str string +function AreaStore:from_string(str) end + +--[[ +* `from_file(filename)`: Experimental. Like `from_string()`, but reads the data + from a file. +]] +---@param filename core.Path +function AreaStore:from_file(filename) end \ No newline at end of file diff --git a/types/luanti_lsp_definitions/library/classes/AsyncJob.lua b/types/luanti_lsp_definitions/library/classes/AsyncJob.lua new file mode 100644 index 00000000..bb0f919b --- /dev/null +++ b/types/luanti_lsp_definitions/library/classes/AsyncJob.lua @@ -0,0 +1,16 @@ +---@meta _ +-- DRAFT 1 DONE +-- luanti/doc/lua_api.md: Class reference > `AsyncJob` + +--[[ +WIPDOC +]] +---@class core.AsyncJob +local AsyncJob = {} + +--[[ +WIPDOC +]] +---@nodiscard +---@return boolean +function AsyncJob:cancel() end \ No newline at end of file diff --git a/types/luanti_lsp_definitions/library/classes/InvRef.lua b/types/luanti_lsp_definitions/library/classes/InvRef.lua new file mode 100644 index 00000000..6998692f --- /dev/null +++ b/types/luanti_lsp_definitions/library/classes/InvRef.lua @@ -0,0 +1,156 @@ +---@meta _ +-- DRAFT 1 DONE +-- luanti/doc/lua_api.md: Class reference > `InvRef` + +--[[ +WIPDOC +]] +---@class core.InvRef +local InvRef = {} + +--[[ +* `is_empty(listname)`: return `true` if list is empty +]] +---@nodiscard +---@param listname core.InventoryList +---@return boolean +function InvRef:is_empty(listname) end + +--[[ +* `get_size(listname)`: get size of a list +]] +---@nodiscard +---@param listname core.InventoryList +---@return integer size +function InvRef:get_size(listname) end + +--[[ +* `set_size(listname, size)`: set size of a list + * If `listname` is not known, a new list will be created + * Setting `size` to 0 deletes a list + * returns `false` on error (e.g. invalid `listname` or `size` +]] +---@nodiscard +---@param listname core.InventoryList +---@param size integer +---@return boolean +function InvRef:set_size(listname, size) end + +--[[ +* `get_width(listname)`: get width of a list +]] +---@nodiscard +---@param listname core.InventoryList +---@return integer width +function InvRef:get_width(listname) end + +--[[ +* `set_width(listname, width)`: set width of list; currently used for crafting + * returns `false` on error (e.g. invalid `listname` or `width` +]] +---@nodiscard +---@param listname core.InventoryList +---@param width integer +function InvRef:set_width(listname, width) end + +--[[ +* `get_stack(listname, i)`: get a copy of stack index `i` in list +]] +---@nodiscard +---@param listname core.InventoryList +---@param i integer +---@return core.ItemStack stack +function InvRef:get_stack(listname, i) end + +--[[ +* `set_stack(listname, i, stack)`: copy `stack` to index `i` in list +]] +---@param listname core.InventoryList +---@param i integer +---@param stack core.ItemStack +function InvRef:set_stack(listname, i, stack) end + +--[[ +* `get_list(listname)`: returns full list (list of `ItemStack`s + or `nil` if list doesn't exist (size 0 +]] +---@nodiscard +---@param listname core.InventoryList +---@return core.ItemList list +function InvRef:get_list(listname) end + +--[[ +* `set_list(listname, list)`: set full list (size will not change +]] +---@param listname core.InventoryList +---@param list core.ItemList +function InvRef:set_list(listname, list) end + +--[[ +* `get_lists()`: returns table that maps listnames to inventory lists +]] +---@nodiscard +---@return core.InventoryTable lists +function InvRef:get_lists() end + +--[[ +* `set_lists(lists)`: sets inventory lists (size will not change +]] +---@param lists core.InventoryTable +function InvRef:set_lists(lists) end + +--[[ +* `add_item(listname, stack)`: add item somewhere in list, returns leftover + `ItemStack`. +]] +---@param listname core.InventoryList +---@param stack core.Item +function InvRef:add_item(listname, stack) end + +--[[ +* `room_for_item(listname, stack):` returns `true` if the stack of items + can be fully added to the list +]] +---@nodiscard +---@param listname core.InventoryList +---@param stack core.Item +---@return boolean +function InvRef:room_for_item(listname, stack) end + +--[[ +* `contains_item(listname, stack, [match_meta])`: returns `true` if + the stack of items can be fully taken from the list. + * If `match_meta` is `true`, item metadata is also considered when comparing + items. Otherwise, only the items names are compared. Default: `false` + * The method ignores wear. +]] +---@nodiscard +---@param listname core.InventoryList +---@param stack core.Item +---@param match_meta boolean? +---@return boolean +function InvRef:contains_item(listname, stack, match_meta) end + +--[[ +* `remove_item(listname, stack, [match_meta])`: take as many items as specified from the + list, returns the items that were actually removed (as an `ItemStack`). + * If `match_meta` is `true` (available since feature `remove_item_match_meta`), + item metadata is also considered when comparing items. Otherwise, only the + items names are compared. Default: `false` + * The method ignores wear. +]] +---@nodiscard +---@param listname core.InventoryList +---@param stack core.Item +---@param match_meta boolean? +---@return core.ItemStack +function InvRef:remove_item(listname, stack, match_meta) end + +--[[ +* `get_location()`: returns a location compatible to + `core.get_inventory(location)`. + * returns `{type="undefined"}` in case location is not known +]] +---@nodiscard +---@return core.InventoryLocation|core.InventoryLocation.undefined +function InvRef:get_location() end diff --git a/types/luanti_lsp_definitions/library/classes/ItemStack.lua b/types/luanti_lsp_definitions/library/classes/ItemStack.lua new file mode 100644 index 00000000..84718229 --- /dev/null +++ b/types/luanti_lsp_definitions/library/classes/ItemStack.lua @@ -0,0 +1,268 @@ +---@meta _ +-- DRAFT 1 DONE +-- luanti/doc/lua_api.md: Class reference > `ItemStack` + +-- ------------------------------- constructor ------------------------------ -- + +--[[ +WIPDOC +]] +---@nodiscard +---@param any core.Item? +---@return core.ItemStack +function ItemStack(any) end + +-- -------------------------------- ItemStack ------------------------------- -- + +--[[ +WIPDOC +]] +---@class core.ItemStack +local ItemStack = {} + +--[[ +* `is_empty()`: returns `true` if stack is empty. +]] +---@nodiscard +---@return boolean +function ItemStack:is_empty() end + +--[[ +* `get_name()`: returns item name (e.g. `"default:stone"`). +]] +---@nodiscard +---@return core.Item.name item_name +function ItemStack:get_name() end + +--[[ +* `set_name(item_name)`: returns a boolean indicating whether the item was + cleared. +]] +---@nodiscard +---@param item_name core.Item.name +---@return boolean +function ItemStack:set_name(item_name) end + +--[[ +* `get_count()`: Returns number of items on the stack. +]] +---@nodiscard +---@return integer count +function ItemStack:get_count() end + +--[[ +* `set_count(count)`: returns a boolean indicating whether the item was cleared + * `count`: number, unsigned 16 bit integer +]] +---@nodiscard +---@param count integer +---@return boolean +function ItemStack:set_count(count) end + +--[[ +* `get_wear()`: returns tool wear (`0`-`65535`), `0` for non-tools. +]] +---@nodiscard +---@return core.Tool.wear wear +function ItemStack:get_wear() end + +--[[ +* `set_wear(wear)`: returns boolean indicating whether item was cleared + * `wear`: number, unsigned 16 bit integer +]] +---@nodiscard +---@param wear core.Tool.wear +---@return boolean +function ItemStack:set_wear(wear) end + +--[[ +`get_meta()`: returns ItemStackMetaRef. See section for more details +]] +---@nodiscard +---@return core.ItemStackMetaRef +function ItemStack:get_meta() end + +--[[ +* `get_metadata()`: **Deprecated.** Returns metadata (a string attached to an item stack). + * If you need to access this to maintain backwards compatibility, + use `stack:get_meta():get_string("")` instead. +]] +---@deprecated +---@nodiscard +---@return string metadata +function ItemStack:get_metadata() end + +--[[ +* `set_metadata(metadata)`: **Deprecated.** Returns true. + * If you need to set this to maintain backwards compatibility, + use `stack:get_meta():set_string("", metadata)` instead. +]] +---@deprecated +---@param metadata string +---@return true +function ItemStack:set_metadata(metadata) end + +--[[ +* `get_description()`: returns the description shown in inventory list tooltips. + * The engine uses this when showing item descriptions in tooltips. + * Fields for finding the description, in order: + * `description` in item metadata (See [Item Metadata]. + * `description` in item definition + * item name +]] +---@nodiscard +---@return string +function ItemStack:get_description() end + +--[[ +* `get_short_description()`: returns the short description or nil. + * Unlike the description, this does not include new lines. + * Fields for finding the short description, in order: + * `short_description` in item metadata (See [Item Metadata]. + * `short_description` in item definition + * first line of the description (From item meta or def, see `get_description()`. + * Returns nil if none of the above are set +]] +---@nodiscard +---@return string? +function ItemStack:get_short_description() end + +--[[ +* `clear()`: removes all items from the stack, making it empty. +]] +function ItemStack:clear() end + +--[[ +* `replace(item)`: replace the contents of this stack. + * `item` can also be an itemstring or table. +]] +---@param item core.Item +function ItemStack:replace(item) end + +--[[ +* `to_string()`: returns the stack in itemstring form. +]] +---@nodiscard +---@return core.Item.stringfmt +function ItemStack:to_string() end + +--[[ +* `to_table()`: returns the stack in Lua table form. +]] +---@nodiscard +---@return core.Item.tablefmt +function ItemStack:to_table() end + +--[[ +* `get_stack_max()`: returns the maximum size of the stack (depends on the + item). +]] +---@nodiscard +---@return integer +function ItemStack:get_stack_max() end + +--[[ +* `get_free_space()`: returns `get_stack_max() - get_count()`. +]] +---@nodiscard +---@return integer +function ItemStack:get_free_space() end + +--[[ +* `is_known()`: returns `true` if the item name refers to a defined item type. +]] +---@nodiscard +---@return boolean +function ItemStack:is_known() end + +--[[ +* `get_definition()`: returns the item definition table. +]] +---@nodiscard +---@return core.ItemDef +function ItemStack:get_definition() end + +--[[ +* `get_tool_capabilities()`: returns the digging properties of the item, + or those of the hand if none are defined for this item type +]] +---@nodiscard +---@return core.ToolCapabilities +function ItemStack:get_tool_capabilities() end + +--[[ +* `add_wear(amount)` + * Increases wear by `amount` if the item is a tool, otherwise does nothing + * Valid `amount` range is [0,65536] + * `amount`: number, integer +]] +---@param amount core.Tool.wear +function ItemStack:add_wear(amount) end + +--[[ +* `add_wear_by_uses(max_uses)` + * Increases wear in such a way that, if only this function itself called, + the item breaks after `max_uses` times + * Valid `max_uses` range is [0,65536] + * Does nothing if item is not a tool or if `max_uses` is 0 +]] +---@param max_uses core.Tool.wear +function ItemStack:add_wear_by_uses(max_uses) end + +--[[ +* `get_wear_bar_params()`: returns the wear bar parameters of the item, + or nil if none are defined for this item type or in the stack's meta +]] +---@nodiscard +---@return core.WearBarColor? +function ItemStack:get_wear_bar_params() end + +--[[ +* `add_item(item)`: returns leftover `ItemStack` + * Put some item or stack onto this stack +]] +---@param item core.Item +function ItemStack:add_item(item) end + +--[[ +* `item_fits(item)`: returns `true` if item or stack can be fully added to + this one. +]] +---@nodiscard +---@param item core.Item +---@return boolean +function ItemStack:item_fits(item) end + +--[[ +* `take_item(n)`: returns taken `ItemStack` + * Take (and remove) up to `n` items from this stack + * `n`: number, default: `1` +]] +---@nodiscard +---@param n integer? +---@return core.ItemStack +function ItemStack:take_item(n) end + +--[[ +* `peek_item(n)`: returns taken `ItemStack` + * Copy (don't remove) up to `n` items from this stack + * `n`: number, default: `1` +]] +---@nodiscard +---@param n integer? +---@return core.ItemStack +function ItemStack:peek_item(n) end + +--[[ +* `equals(other)`: + * returns `true` if this stack is identical to `other`. + * Note: `stack1:to_string() == stack2:to_string()` is not reliable, + as stack metadata can be serialized in arbitrary order. + * Note: if `other` is an itemstring or table representation of an + ItemStack, this will always return false, even if it is + "equivalent". +]] +---@nodiscard +---@param other core.ItemStack +---@return boolean +function ItemStack:equals(other) end diff --git a/types/luanti_lsp_definitions/library/classes/ItemStackMetaRef.lua b/types/luanti_lsp_definitions/library/classes/ItemStackMetaRef.lua new file mode 100644 index 00000000..eb3faf3d --- /dev/null +++ b/types/luanti_lsp_definitions/library/classes/ItemStackMetaRef.lua @@ -0,0 +1,113 @@ +---@meta _ +-- DRAFT 1 DONE +-- luanti/doc/lua_api.md: Class reference > `ItemStackMetaRef` + +-- NOTE: changes are linked to MetaDataRef, ItemStackMetaRef, NodeMetaRef, +-- PlayerMetaRef and StorageRef + +--[[ +WIPDOC +]] +---@class core.ItemStackMetaRef: core.MetaDataRef +local ItemStackMetaRef = {} + +--[[ +* `contains(key)`: Returns true if key present, otherwise false. + * Returns `nil` when the MetaData is inexistent. +]] +---@nodiscard +---@param key core.MetadataTable.fields.item.keys +---@return boolean? +function ItemStackMetaRef:contains(key) end + +--[[ +* `get(key)`: Returns `nil` if key not present, else the stored string. +]] +---@nodiscard +---@param key core.MetadataTable.fields.item.keys +---@return string? value +function ItemStackMetaRef:get(key) end + +--[[ +* `set_string(key, value)`: Value of `""` will delete the key. +]] +---@param key core.MetadataTable.fields.item.keys +---@param value string +function ItemStackMetaRef:set_string(key, value) end + +--[[ +* `get_string(key)`: Returns `""` if key not present. +]] +---@nodiscard +---@param key core.MetadataTable.fields.item.keys +---@return string value +function ItemStackMetaRef:get_string(key) end + +--[[ +* `set_int(key, value)` + * The range for the value is system-dependent (usually 32 bits). + The value will be converted into a string when stored. +]] +---@param key core.MetadataTable.fields.item.keys.integer +---@param value integer +function ItemStackMetaRef:set_int(key, value) end + +--[[ +* `get_int(key)`: Returns `0` if key not present. +]] +---@nodiscard +---@param key core.MetadataTable.fields.item.keys.integer +---@return integer value +function ItemStackMetaRef:get_int(key) end + +--[[ +* `set_float(key, value)` + * Store a number (a 64-bit float) exactly. + * The value will be converted into a string when stored. +]] +---@param key core.MetadataTable.fields.item.keys.number +---@param value number +function ItemStackMetaRef:set_float(key, value) end + +--[[ +WIPDOC +]] +---@nodiscard +---@param key core.MetadataTable.fields.item.keys.number +---@return number value +function ItemStackMetaRef:get_float(key) end + +--[[ +WIPDOC +]] +---@nodiscard +---@return core.MetadataTable.fields.item.keys[] keys +function ItemStackMetaRef:get_keys() end + +--[[ +WIPDOC +]] +---@nodiscard +---@param data core.MetadataTable.item +---@return boolean? +function ItemStackMetaRef:from_table(data) end + +--[[ +WIPDOC +]] +---@nodiscard +---@return core.MetadataTable.item +function ItemStackMetaRef:to_table() end + + +--[[ +WIPDOC +]] +---@param tool_capabilities core.ToolCapabilities? +function ItemStackMetaRef:set_tool_capabilities(tool_capabilities) end + +--[[ +WIPDOC +]] +---@param wear_bar_params core.WearBarColor? +function ItemStackMetaRef:set_wear_bar_params(wear_bar_params) end diff --git a/types/luanti_lsp_definitions/library/classes/MetaDataRef.lua b/types/luanti_lsp_definitions/library/classes/MetaDataRef.lua new file mode 100644 index 00000000..46e4f2e8 --- /dev/null +++ b/types/luanti_lsp_definitions/library/classes/MetaDataRef.lua @@ -0,0 +1,100 @@ +---@meta _ +-- DRAFT 1 DONE +-- luanti/doc/lua_api.md: Class reference > `MetaDataRef` + +-- NOTE: changes are linked to MetaDataRef, ItemStackMetaRef, NodeMetaRef, +-- PlayerMetaRef and StorageRef + +--[[ +will return the value associated with key `k`. There is a low recursion limit. +]] +---@class core.MetaDataRef +local MetaDataRef = {} + +--[[ +* `contains(key)`: Returns true if key present, otherwise false. + * Returns `nil` when the MetaData is inexistent. +]] +---@nodiscard +---@param key core.MetadataTable.fields.keys +---@return boolean? +function MetaDataRef:contains(key) end + +--[[ +* `get(key)`: Returns `nil` if key not present, else the stored string. +]] +---@nodiscard +---@param key core.MetadataTable.fields.keys +---@return string? value +function MetaDataRef:get(key) end + +--[[ +* `set_string(key, value)`: Value of `""` will delete the key. +]] +---@param key core.MetadataTable.fields.keys +---@param value string +function MetaDataRef:set_string(key, value) end + +--[[ +* `get_string(key)`: Returns `""` if key not present. +]] +---@nodiscard +---@param key core.MetadataTable.fields.keys +---@return string value +function MetaDataRef:get_string(key) end + +--[[ +* `set_int(key, value)` + * The range for the value is system-dependent (usually 32 bits). + The value will be converted into a string when stored. +]] +---@param key core.MetadataTable.fields.keys.integer +---@param value integer +function MetaDataRef:set_int(key, value) end + +--[[ +* `get_int(key)`: Returns `0` if key not present. +]] +---@nodiscard +---@param key core.MetadataTable.fields.keys.integer +---@return integer value +function MetaDataRef:get_int(key) end + +--[[ +* `set_float(key, value)` + * Store a number (a 64-bit float) exactly. + * The value will be converted into a string when stored. +]] +---@param key core.MetadataTable.fields.keys.number +---@param value number +function MetaDataRef:set_float(key, value) end + +--[[ +WIPDOC +]] +---@nodiscard +---@param key core.MetadataTable.fields.keys.number +---@return number value +function MetaDataRef:get_float(key) end + +--[[ +WIPDOC +]] +---@nodiscard +---@return core.MetadataTable.fields.keys[] keys +function MetaDataRef:get_keys() end + +--[[ +WIPDOC +]] +---@nodiscard +---@param data core.MetadataTable.set +---@return boolean? +function MetaDataRef:from_table(data) end + +--[[ +WIPDOC +]] +---@nodiscard +---@return core.MetadataTable.get +function MetaDataRef:to_table() end diff --git a/types/luanti_lsp_definitions/library/classes/ModChannel.lua b/types/luanti_lsp_definitions/library/classes/ModChannel.lua new file mode 100644 index 00000000..a3835769 --- /dev/null +++ b/types/luanti_lsp_definitions/library/classes/ModChannel.lua @@ -0,0 +1,35 @@ +---@meta _ +-- DRAFT 1 DONE +-- luanti/doc/lua_api.md: Class reference > `ModChannel` + +--[[ +WIPDOC +]] +---@class core.ModChannel +local ModChannel = {} + +--[[ +* `leave()`: leave the mod channel. + * Server leaves channel `channel_name`. + * No more incoming or outgoing messages can be sent to this channel from + server mods. + * This invalidate all future object usage. + * Ensure you set ModChannel to nil after that to free Lua resources. +]] +function ModChannel:leave() end + +--[[ +* `is_writeable()`: returns true if channel is writeable and mod can send over + it. +]] +---@nodiscard +---@return boolean +function ModChannel:is_writeable() end + +--[[ +* `send_all(message)`: Send `message` though the mod channel. + * If mod channel is not writeable or invalid, message will be dropped. + * Message size is limited to 65535 characters by protocol. +]] +---@param message string +function ModChannel:send_all(message) end diff --git a/types/luanti_lsp_definitions/library/classes/NodeMetaRef.lua b/types/luanti_lsp_definitions/library/classes/NodeMetaRef.lua new file mode 100644 index 00000000..234751db --- /dev/null +++ b/types/luanti_lsp_definitions/library/classes/NodeMetaRef.lua @@ -0,0 +1,118 @@ +---@meta _ +-- DRAFT 1 DONE +-- luanti/doc/lua_api.md: Class reference > `NodeMetaRef` + +-- NOTE: changes are linked to MetaDataRef, ItemStackMetaRef, NodeMetaRef, +-- PlayerMetaRef and StorageRef + +--[[ +WIPDOC +]] +---@class core.NodeMetaRef : core.MetaDataRef +local NodeMetaRef = {} + +--[[ +* `contains(key)`: Returns true if key present, otherwise false. + * Returns `nil` when the MetaData is inexistent. +]] +---@nodiscard +---@param key core.MetadataTable.fields.node.keys +---@return boolean? +function NodeMetaRef:contains(key) end + +--[[ +* `get(key)`: Returns `nil` if key not present, else the stored string. +]] +---@nodiscard +---@param key core.MetadataTable.fields.node.keys +---@return string? value +function NodeMetaRef:get(key) end + +--[[ +* `set_string(key, value)`: Value of `""` will delete the key. +]] +---@param key core.MetadataTable.fields.node.keys +---@param value string +function NodeMetaRef:set_string(key, value) end + +--[[ +* `get_string(key)`: Returns `""` if key not present. +]] +---@nodiscard +---@param key core.MetadataTable.fields.node.keys +---@return string value +function NodeMetaRef:get_string(key) end + +--[[ +* `set_int(key, value)` + * The range for the value is system-dependent (usually 32 bits). + The value will be converted into a string when stored. +]] +---@param key core.MetadataTable.fields.node.keys.integer +---@param value integer +function NodeMetaRef:set_int(key, value) end + +--[[ +* `get_int(key)`: Returns `0` if key not present. +]] +---@nodiscard +---@param key core.MetadataTable.fields.node.keys.integer +---@return integer value +function NodeMetaRef:get_int(key) end + +--[[ +* `set_float(key, value)` + * Store a number (a 64-bit float) exactly. + * The value will be converted into a string when stored. +]] +---@param key core.MetadataTable.fields.node.keys.number +---@param value number +function NodeMetaRef:set_float(key, value) end + +--[[ +WIPDOC +]] +---@nodiscard +---@param key core.MetadataTable.fields.node.keys.number +---@return number value +function NodeMetaRef:get_float(key) end + +--[[ +WIPDOC +]] +---@nodiscard +---@return core.MetadataTable.fields.node.keys[] keys +function NodeMetaRef:get_keys() end + +--[[ +WIPDOC +]] +---@nodiscard +---@param data core.MetadataTable.node.set +---@return boolean? +function NodeMetaRef:from_table(data) end + +--[[ +WIPDOC +]] +---@nodiscard +---@return core.MetadataTable.node.get +function NodeMetaRef:to_table() end + + +--[[ +WIPDOC +]] +---@nodiscard +---@return core.InvRef +function NodeMetaRef:get_inventory() end + +--[[ +* `mark_as_private(name or {name1, name2, ...})`: Mark specific vars as private + This will prevent them from being sent to the client. Note that the "private" + status will only be remembered if an associated key-value pair exists, + meaning it's best to call this when initializing all other meta (e.g. + `on_construct`). +]] +---@param fields OneOrMany +function NodeMetaRef:mark_as_private(fields) end diff --git a/types/luanti_lsp_definitions/library/classes/NodeTimer.lua b/types/luanti_lsp_definitions/library/classes/NodeTimer.lua new file mode 100644 index 00000000..82d41410 --- /dev/null +++ b/types/luanti_lsp_definitions/library/classes/NodeTimer.lua @@ -0,0 +1,53 @@ +---@meta _ +-- DRAFT 1 DONE +-- luanti/doc/lua_api.md: Class reference > `NodeTimerRef` + +--[[ +WIPDOC +]] +---@class core.NodeTimerRef +local NodeTimerRef = {} + +--[[ +* `set(timeout,elapsed)` + * set a timer's state + * `timeout` is in seconds, and supports fractional values (0.1 etc) + * `elapsed` is in seconds, and supports fractional values (0.1 etc) + * will trigger the node's `on_timer` function after `(timeout - elapsed)` + seconds. +]] +---@param timeout number +---@param elapsed number +function NodeTimerRef:set(timeout, elapsed) end + +--[[ +WIPDOC +]] +---@param timeout number +function NodeTimerRef:start(timeout) end + +--[[ +WIPDOC +]] +function NodeTimerRef:stop() end + +--[[ +WIPDOC +]] +---@nodiscard +---@return number +function NodeTimerRef:get_timeout() end + +--[[ +WIPDOC +]] +---@nodiscard +---@return number +function NodeTimerRef:get_elapsed() end + +--[[ +WIPDOC +]] +---@nodiscard +---@return boolean +function NodeTimerRef:is_started() end \ No newline at end of file diff --git a/types/luanti_lsp_definitions/library/classes/ObjectRef/EntityRef.lua b/types/luanti_lsp_definitions/library/classes/ObjectRef/EntityRef.lua new file mode 100644 index 00000000..40944d93 --- /dev/null +++ b/types/luanti_lsp_definitions/library/classes/ObjectRef/EntityRef.lua @@ -0,0 +1,176 @@ +---@meta _ +-- DRAFT 1 DONE +-- luanti/doc/lua_api.md: Class reference > `ObjectRef` + +--[[ +WIPDOC +]] +---@class core.EntityRef : _.ObjectRef.__base +local EntityRef = {} + +-- ----------------------------- entity lifetime ---------------------------- -- + +--[[ +* `remove()`: remove object + * The object is removed after returning from Lua. However the `ObjectRef` + itself instantly becomes unusable with all further method calls having + no effect and returning `nil`. +]] +function EntityRef:remove() end + +-- ---------------------- entity position and movement ---------------------- -- + +--[[ +* `set_velocity(vel)` + * Sets the velocity + * `vel` is a vector, e.g. `{x=0.0, y=2.3, z=1.0}` +]] +---@param vel vector +function EntityRef:set_velocity(vel) end + +--[[ +* `set_acceleration(acc)` + * Sets the acceleration + * `acc` is a vector +]] +---@param acc vector +function EntityRef:set_acceleration(acc) end + +--[[ +* `get_acceleration()`: returns the acceleration, a vector +]] +---@nodiscard +---@return vec? acc +function EntityRef:get_acceleration() end + +-- --------------------- entity rotation and orientation -------------------- -- + +--[[ +* `set_rotation(rot)` + * Sets the rotation + * `rot` is a vector (radians). X is pitch (elevation), Y is yaw (heading + and Z is roll (bank). + * Does not reset rotation incurred through `automatic_rotate`. + Remove & re-add your objects to force a certain rotation. +]] +---@param rot vector +function EntityRef:set_rotation(rot) end + +--[[ +* `get_rotation()`: returns the rotation, a vector (radians) +]] +---@nodiscard +---@return vec? rot +function EntityRef:get_rotation() end + +--[[ +* `set_yaw(yaw)`: sets the yaw in radians (heading). +]] +---@param yaw number +function EntityRef:set_yaw(yaw) end + +--[[ +* `get_yaw()`: returns number in radians +]] +---@nodiscard +---@return number yaw +function EntityRef:get_yaw() end + +-- ----------------------------- entity texture ----------------------------- -- + +--[[ +* `set_texture_mod(mod)` + * Set a texture modifier to the base texture, for sprites and meshes. + * When calling `set_texture_mod` again, the previous one is discarded. + * `mod` the texture modifier. See [Texture modifiers]. +]] +---@param mod core.Texture +function EntityRef:set_texture_mod(mod) end + +--[[ +* `get_texture_mod()` returns current texture modifier +]] +---@nodiscard +---@return core.Texture? mod +function EntityRef:get_texture_mod() end + +--[[ +WIPDOC +]] +---@class core.EntityRef.select_x_by_camera.strict +--[[ +WIPDOC +]] +---@field [1] integer +--[[ +WIPDOC +]] +---@field [2] integer +--[[ +WIPDOC +]] +---@field [3] integer +--[[ +WIPDOC +]] +---@field [4] integer +--[[ +WIPDOC +]] +---@field [5] integer +--[[ +WIPDOC +]] +---@field [6] integer + +--[[ +WIPDOC +]] +---@alias core.EntityRef.select_x_by_camera +--- | core.EntityRef.select_x_by_camera.strict +--- | string[] + +--[[ +* `set_sprite(start_frame, num_frames, framelength, select_x_by_camera)` + * Specifies and starts a sprite animation + * Only used by `sprite` and `upright_sprite` visuals + * Animations iterate along the frame `y` position. + * `start_frame`: {x=column number, y=row number}, the coordinate of the + first frame, default: `{x=0, y=0}` + * `num_frames`: Total frames in the texture, default: `1` + * `framelength`: Time per animated frame in seconds, default: `0.2` + * `select_x_by_camera`: Only for visual = `sprite`. Changes the frame `x` + position according to the view direction. default: `false`. + * First column: subject facing the camera + * Second column: subject looking to the left + * Third column: subject backing the camera + * Fourth column: subject looking to the right + * Fifth column: subject viewed from above + * Sixth column: subject viewed from below +]] +---@param start_frame vec2.xy? +---@param num_frames integer? +---@param framelength number? +---@param select_x_by_camera core.EntityRef.select_x_by_camera|boolean? +function EntityRef:set_sprite(start_frame, num_frames, framelength, select_x_by_camera) end + +-- ------------------------------- entity misc ------------------------------ -- + +--[[ +* `get_luaentity()`: + * Returns the object's associated luaentity table, if there is one + * Otherwise returns `nil` (e.g. for players +]] +---@nodiscard +---@return core.Entity +function EntityRef:get_luaentity() end + +--[[ +* `get_entity_name()`: + * **Deprecated**: Will be removed in a future version, + use `:get_luaentity().name` instead. +]] +---@nodiscard +---@deprecated +---@return core.Entity.name +function EntityRef:get_entity_name() end diff --git a/types/luanti_lsp_definitions/library/classes/ObjectRef/ObjectRef.lua b/types/luanti_lsp_definitions/library/classes/ObjectRef/ObjectRef.lua new file mode 100644 index 00000000..c773841d --- /dev/null +++ b/types/luanti_lsp_definitions/library/classes/ObjectRef/ObjectRef.lua @@ -0,0 +1,373 @@ +---@meta _ +-- DRAFT 1 DONE +-- luanti/doc/lua_api.md: Class reference > `ObjectRef` + +-- INTERPRETATION: EntityRef does not override ObjectRef, merely supplies +-- ObjectRef with exclusive entity methods. This is because of the relationship +-- where PlayerRef overrides ObjectRef's methods. This is seen in how some +-- ObjectRef methods assumes it's an entity and not a player. + +--[[ +WIPDOC +]] +---@class _.ObjectRef.__base +local ObjectRefBase = {} + +--[[ +WIPDOC +]] +---@alias core.ObjectRef +--- | core.PlayerRef +--- | core.EntityRef + +-- -------------------------------- is valid -------------------------------- -- + +--[[ +* `is_valid()`: returns whether the object is valid. +]] +---@nodiscard +---@return boolean +function ObjectRefBase:is_valid() end + +-- -------------------------- position and movement ------------------------- -- + +--[[ +* `get_pos()`: returns position as vector `{x=num, y=num, z=num}` +]] +---@nodiscard +---@return vec pos +function ObjectRefBase:get_pos() end + +--[[ +* `set_pos(pos)`: + * Sets the position of the object. + * No-op if object is attached. + * `pos` is a vector `{x=num, y=num, z=num}` +]] +---@param pos vector +function ObjectRefBase:set_pos(pos) end + +--[[ +* `add_pos(pos)`: + * Changes position by adding to the current position. + * No-op if object is attached. + * `pos` is a vector `{x=num, y=num, z=num}`. + * In comparison to using `set_pos`, `add_pos` will avoid synchronization problems. +]] +---@param pos vector +function ObjectRefBase:add_pos(pos) end + +--[[ +* `get_velocity()`: returns the velocity, a vector. +]] +---@nodiscard +---@return vec vel +function ObjectRefBase:get_velocity() end + +--[[ +* `add_velocity(vel)` + * Changes velocity by adding to the current velocity. + * `vel` is a vector, e.g. `{x=0.0, y=2.3, z=1.0}` + * In comparison to using `get_velocity`, adding the velocity and then using + `set_velocity`, `add_velocity` is supposed to avoid synchronization problems. + Additionally, players also do not support `set_velocity`. + * If object is a player: + * Does not apply during `free_move`. + * Note that since the player speed is normalized at each move step, + increasing e.g. Y velocity beyond what would usually be achieved + (see: physics overrides) will cause existing X/Z velocity to be reduced. + * Example: `add_velocity({x=0, y=6.5, z=0})` is equivalent to + pressing the jump key (assuming default settings) +]] +---@param vel vector +function ObjectRefBase:add_velocity(vel) end + +--[[ +* `move_to(pos, continuous=false)` + * Does an interpolated move for Lua entities for visually smooth transitions. + * If `continuous` is true, the Lua entity will not be moved to the current + position before starting the interpolated move. + * For players this does the same as `set_pos`,`continuous` is ignored. + * no-op if object is attached +]] +---@param pos vector +---@param continuous boolean? +function ObjectRefBase:move_to(pos, continuous) end + +-- --------------------------------- actions -------------------------------- -- + +--[[ +* `punch(puncher, time_from_last_punch, tool_capabilities, dir)` + * punches the object, triggering all consequences a normal punch would have + * Other arguments: See `on_punch` for entities + * Arguments `time_from_last_punch`, `tool_capabilities`, and `dir` + will be replaced with a default value when the caller sets them to `nil`. +]] +---@param puncher core.ObjectRef +---@param time_from_last_punch number +---@param tool_capabilities core.ToolCapabilities +---@param dir vector +---@return core.Tool.wear wear +function ObjectRefBase:punch(puncher, time_from_last_punch, tool_capabilities, dir) end + +--[[ +* `right_click(clicker)`: + * simulates using the 'place/use' key on the object + * triggers all consequences as if a real player had done this + * `clicker` is another `ObjectRef` which has clicked + * note: this is called `right_click` for historical reasons only +]] +---@param clicker core.ObjectRef +function ObjectRefBase:right_click(clicker) end + +-- --------------------------------- health --------------------------------- -- + +--[[ +* `get_hp()`: returns number of health points +]] +---@nodiscard +---@return integer hp +function ObjectRefBase:get_hp() end + +--[[ +* `set_hp(hp, reason)`: set number of health points + * See reason in register_on_player_hpchange + * Is limited to the range of 0 ... 65535 (2^16 - 1) + * For players: HP are also limited by `hp_max` specified in object properties +]] +---@param hp integer +---@param reason core.PlayerHPChangeReason? +function ObjectRefBase:set_hp(hp, reason) end + +-- ------------------------- inventory and wielding ------------------------- -- + +--[[ +* `get_inventory()`: returns an `InvRef` for players, otherwise returns `nil` +]] +---@nodiscard +---@return nil +function ObjectRefBase:get_inventory() end + +--[[ +* `get_wield_list()`: returns the name of the inventory list the wielded item + is in. +]] +---@nodiscard +---@return core.InventoryList +function ObjectRefBase:get_wield_list() end + +--[[ +* `get_wield_index()`: returns the wield list index of the wielded item (starting with 1) +]] +---@nodiscard +---@return integer +function ObjectRefBase:get_wield_index() end + +--[[ +* `get_wielded_item()`: returns a copy of the wielded item as an `ItemStack` +]] +---@nodiscard +---@return core.ItemStack item +function ObjectRefBase:get_wielded_item() end + +--[[ +* `set_wielded_item(item)`: replaces the wielded item, returns `true` if + successful. +]] +---@param item core.Item +function ObjectRefBase:set_wielded_item(item) end + +-- ---------------------------------- armor --------------------------------- -- + +--[[ +* `get_armor_groups()`: + * returns a table with all of the object's armor group ratings + * syntax: the table keys are the armor group names, + the table values are the corresponding group ratings + * see section '`ObjectRef` armor groups' for details +]] +---@nodiscard +---@return core.Groups.armor groups +function ObjectRefBase:get_armor_groups() end + +--[[ +* `set_armor_groups({group1=rating, group2=rating, ...})` + * sets the object's full list of armor groups + * same table syntax as for `get_armor_groups` + * note: all armor groups not in the table will be removed +]] +---@param groups core.Groups.armor +function ObjectRefBase:set_armor_groups(groups) end + +-- -------------------------------- animation ------------------------------- -- + +--[[ +* `set_animation(frame_range, frame_speed, frame_blend, frame_loop)` + * Sets the object animation parameters and (re)starts the animation + * Animations only work with a `"mesh"` visual + * `frame_range`: Beginning and end frame (as specified in the mesh file). + * Syntax: `{x=start_frame, y=end_frame}` + * Animation interpolates towards the end frame but stops when it is reached + * If looped, there is no interpolation back to the start frame + * If looped, the model should look identical at start and end + * default: `{x=1.0, y=1.0}` + * `frame_speed`: How fast the animation plays, in frames per second (number) + * default: `15.0` + * `frame_blend`: number, default: `0.0` + * `frame_loop`: If `true`, animation will loop. If false, it will play once + * default: `true` +]] +---@param frame_range vec2.xy? +---@param frame_speed number? +---@param frame_blend number? +---@param frame_loop boolean? +function ObjectRefBase:set_animation(frame_range, frame_speed, frame_blend, frame_loop) end + +--[[ +* `get_animation()`: returns current animation parameters set by `set_animation`: + * `frame_range`, `frame_speed`, `frame_blend`, `frame_loop`. +]] +---@nodiscard +---@return vec2.xy frame_range, number frame_speed, number frame_blend, boolean frame_loop +function ObjectRefBase:get_animation() end + +--[[ +* `set_animation_frame_speed(frame_speed)` + * Sets the frame speed of the object's animation + * Unlike `set_animation`, this will not restart the animation + * `frame_speed`: See `set_animation` +]] +---@param frame_speed number +function ObjectRefBase:set_animation_frame_speed(frame_speed) end + +-- ------------------------------- attachment ------------------------------- -- + +--[[ +* `set_attach(parent[, bone, position, rotation, forced_visible])` + * Attaches object to `parent` + * See 'Attachments' section for details + * `parent`: `ObjectRef` to attach to + * `bone`: Bone to attach to. Default is `""` (the root bone) + * `position`: relative position, default `{x=0, y=0, z=0}` + * `rotation`: relative rotation in degrees, default `{x=0, y=0, z=0}` + * `forced_visible`: Boolean to control whether the attached entity + should appear in first person, default `false`. + * This command may fail silently (do nothing) when it would result + in circular attachments. +]] +---@param parent core.ObjectRef +---@param bone string? +---@param position vector? +---@param rotation vector? +---@param forced_visible boolean? +function ObjectRefBase:set_attach(parent, bone, position, rotation, forced_visible) end + +--[[ +* `get_attach()`: + * returns current attachment parameters or nil if it isn't attached + * If attached, returns `parent`, `bone`, `position`, `rotation`, `forced_visible` +]] +---@nodiscard +---@return core.ObjectRef? parent, string? bones, vector? positions, vector? rotation, boolean? forced_visible +function ObjectRefBase:get_attach() end + +--[[ +* `get_children()`: returns a list of ObjectRefs that are attached to the + object. +]] +---@nodiscard +---@return core.ObjectRef[] +function ObjectRefBase:get_children() end + +--[[ +* `set_detach()`: Detaches object. No-op if object was not attached.]] +function ObjectRefBase:set_detach() end + +-- ---------------------------------- bones --------------------------------- -- + +--[[ ObjectRef:set_bone_position() .. ObjectRef:get_bone_overrides() split off into ./bones.lua ]]-- + +-- ----------------------------- object property ---------------------------- -- + +--[[ +* `set_properties(object property table)` +]] +---@param objprops core.ObjectProperties.set +function ObjectRefBase:set_properties(objprops) end + +--[[ +* `get_properties()`: returns a table of all object properties +]] +---@nodiscard +---@return core.ObjectProperties.get +function ObjectRefBase:get_properties() end + +-- -------------------------------- observer -------------------------------- -- + +--[[ +* `set_observers(observers)`: sets observers (players this object is sent to) + * If `observers` is `nil`, the object's observers are "unmanaged": + The object is sent to all players as governed by server settings. This is the default. + * `observers` is a "set" of player names: `{name1 = true, name2 = true, ...}` + * A set is a table where the keys are the elements of the set + (in this case, *valid* player names) and the values are all `true`. + * Attachments: The *effective observers* of an object are made up of + all players who can observe the object *and* are also effective observers + of its parent object (if there is one). + * Players are automatically added to their own observer sets. + Players **must** effectively observe themselves. + * Object activation and deactivation are unaffected by observability. + * Attached sounds do not work correctly and thus should not be used + on objects with managed observers yet. +]] +---@param observers table? +function ObjectRefBase:set_observers(observers) end + +--[[ +* `get_observers()`: + * throws an error if the object is invalid + * returns `nil` if the observers are unmanaged + * returns a table with all observer names as keys and `true` values (a "set") otherwise +]] +---@nodiscard +---@return table? observers +function ObjectRefBase:get_observers() end + +--[[ +* `get_effective_observers()`: + * Like `get_observers()`, but returns the "effective" observers, taking into account attachments + * Time complexity: O(nm) + * n: number of observers of the involved entities + * m: number of ancestors along the attachment chain +]] +---@nodiscard +---@return table +function ObjectRefBase:get_effective_observers() end + +-- -------------------------------- is player ------------------------------- -- + +--[[ +* `is_player()`: returns true for players, false otherwise +]] +---@nodiscard +---@return false +function ObjectRefBase:is_player() end + +-- --------------------------------- nametag -------------------------------- -- + +--[[ ObjectRef:get_nametag_attributes() .. ObjectRef:set_nametag_attributes() split off into ./nametag.lua ]]-- + +-- ---------------------------------- GUID ---------------------------------- -- + +--[[ +* `get_guid()`: returns a global unique identifier (a string) + * For players, this is a player name. + * For Lua entities, this is a uniquely generated string, guaranteed not to collide with player names. + * example: `@bGh3p2AbRE29Mb4biqX6OA` + * GUIDs only use printable ASCII characters. + * GUIDs persist between object reloads, and their format is guaranteed not to change. + Thus you can use the GUID to identify an object in a particular world online and offline. +]] +---@nodiscard +---@return string +function ObjectRefBase:get_guid() end \ No newline at end of file diff --git a/types/luanti_lsp_definitions/library/classes/ObjectRef/PlayerRef.lua b/types/luanti_lsp_definitions/library/classes/ObjectRef/PlayerRef.lua new file mode 100644 index 00000000..fb03baf7 --- /dev/null +++ b/types/luanti_lsp_definitions/library/classes/ObjectRef/PlayerRef.lua @@ -0,0 +1,549 @@ +---@meta _ +-- DRAFT 1 DONE +-- luanti/doc/lua_api.md: Class reference > `ObjectRef` + +--[[ +WIPDOC +]] +---@class core.PlayerRef : _.ObjectRef.__base +local PlayerRef = {} + +-- --------------------------- ObjectRef overrides -------------------------- -- + +--[[ +* `add_velocity(vel)` + * Changes velocity by adding to the current velocity. + * `vel` is a vector, e.g. `{x=0.0, y=2.3, z=1.0}` + * In comparison to using `get_velocity`, adding the velocity and then using + `set_velocity`, `add_velocity` is supposed to avoid synchronization problems. + Additionally, players also do not support `set_velocity`. + * If object is a player: + * Does not apply during `free_move`. + * Note that since the player speed is normalized at each move step, + increasing e.g. Y velocity beyond what would usually be achieved + (see: physics overrides) will cause existing X/Z velocity to be reduced. + * Example: `add_velocity({x=0, y=6.5, z=0})` is equivalent to + pressing the jump key (assuming default settings) +]] +---@param vel vector +function PlayerRef:add_velocity(vel) end + +--[[ +* `move_to(pos, continuous=false)` + * Does an interpolated move for Lua entities for visually smooth transitions. + * If `continuous` is true, the Lua entity will not be moved to the current + position before starting the interpolated move. + * For players this does the same as `set_pos`,`continuous` is ignored. + * no-op if object is attached +]] +---@param pos vector +---@param continuous boolean? +function PlayerRef:move_to(pos, continuous) end + +--[[ +* `set_hp(hp, reason)`: set number of health points + * See reason in register_on_player_hpchange + * Is limited to the range of 0 ... 65535 (2^16 - 1) + * For players: HP are also limited by `hp_max` specified in object properties +]] +---@param hp integer +---@param reason core.PlayerHPChangeReason? +function PlayerRef:set_hp(hp, reason) end + +--[[ +* `get_inventory()`: returns an `InvRef` for players, otherwise returns `nil` +]] +---@nodiscard +---@return core.InvRef +function PlayerRef:get_inventory() end + +--[[ +* `set_properties(object property table)` +]] +---@param objprops core.PlayerProperties.set +function PlayerRef:set_properties(objprops) end + +--[[ +* `get_properties()`: returns a table of all object properties +]] +---@nodiscard +---@return core.PlayerProperties.get objprops +function PlayerRef:get_properties() end + +--[[ +* `is_player()`: returns true for players, false otherwise +]] +---@nodiscard +---@return true +function PlayerRef:is_player() end + +--[[ +* `get_guid()`: returns a global unique identifier (a string) + * For players, this is a player name. + * For Lua entities, this is a uniquely generated string, guaranteed not to collide with player names. + * example: `@bGh3p2AbRE29Mb4biqX6OA` + * GUIDs only use printable ASCII characters. + * GUIDs persist between object reloads, and their format is guaranteed not to change. + Thus you can use the GUID to identify an object in a particular world online and offline. +]] +---@nodiscard +---@return string +function PlayerRef:get_guid() end + +-- ------------------------------- player name ------------------------------ -- + +--[[ +* `get_player_name()`: Returns player name or `""` if is not a player +]] +---@nodiscard +---@return string +function PlayerRef:get_player_name() end + +-- ---------------------- player position and movement ---------------------- -- + +--[[ +* `get_player_velocity()`: **DEPRECATED**, use get_velocity() instead. + table {x, y, z} representing the player's instantaneous velocity in nodes/s +]] +---@deprecated +---@nodiscard +---@return vec vel +function PlayerRef:get_player_velocity() end + +--[[ +* `add_player_velocity(vel)`: **DEPRECATED**, use add_velocity(vel) instead. +]] +---@deprecated +---@param vel vector +function PlayerRef:add_player_velocity(vel) end + +-- ------------------------------ player camera ----------------------------- -- + +--[[ +* `get_look_dir()`: get camera direction as a unit vector +]] +---@nodiscard +---@return vector radians +function PlayerRef:get_look_dir() end + +--[[ +* `get_look_vertical()`: pitch in radians + * Angle ranges between -pi/2 and pi/2, which are straight up and down + respectively. +]] +---@nodiscard +---@return number radians +function PlayerRef:get_look_vertical() end + +--[[ +* `get_look_horizontal()`: yaw in radians + * Angle is counter-clockwise from the +z direction. +]] +---@nodiscard +---@return number radians +function PlayerRef:get_look_horizontal() end + +--[[ +* `set_look_vertical(radians)`: sets look pitch + * radians: Angle from looking forward, where positive is downwards. +]] +---@param radians number +function PlayerRef:set_look_vertical(radians) end + +--[[ +* `get_look_horizontal()`: yaw in radians + * Angle is counter-clockwise from the +z direction. +]] +---@param radians number +function PlayerRef:set_look_horizontal(radians) end + +--[[ +* `get_look_pitch()`: pitch in radians - Deprecated as broken. Use + `get_look_vertical`. +]] +---@deprecated +---@nodiscard +---@return number radians +function PlayerRef:get_look_pitch() end + +--[[ +* `get_look_yaw()`: yaw in radians - Deprecated as broken. Use + `get_look_horizontal`. +]] +---@deprecated +---@nodiscard +---@return number radians +function PlayerRef:get_look_yaw() end + +--[[ +* `set_look_pitch(radians)`: sets look pitch - Deprecated. Use + `set_look_vertical`. +]] +---@deprecated +---@param radians number +function PlayerRef:set_look_pitch(radians) end + +--[[ +* `set_look_yaw(radians)`: sets look yaw - Deprecated. Use + `set_look_horizontal`. +]] +---@deprecated +---@param radians number +function PlayerRef:set_look_yaw(radians) end + +-- ------------------------------ player breath ----------------------------- -- + +--[[ +* `get_breath()`: returns player's breath +]] +---@nodiscard +---@return integer value +function PlayerRef:get_breath() end + +--[[ +* `set_breath(value)`: sets player's breath + * values: + * `0`: player is drowning + * Is limited to range 0 ... 65535 (2^16 - 1) +]] +---@nodiscard +---@param value integer +function PlayerRef:set_breath(value) end + +-- ------------------------------- player fov ------------------------------- -- + +--[[ +* `set_fov(fov, is_multiplier, transition_time)`: Sets player's FOV + * `fov`: Field of View (FOV) value. + * `is_multiplier`: Set to `true` if the FOV value is a multiplier. + Defaults to `false`. + * `transition_time`: If defined, enables smooth FOV transition. + Interpreted as the time (in seconds) to reach target FOV. + If set to 0, FOV change is instantaneous. Defaults to 0. + * Set `fov` to 0 to clear FOV override. +]] +---@param fov number +---@param is_multiplier boolean? +---@param transition_time number? +function PlayerRef:set_fov(fov, is_multiplier, transition_time) end + +--[[ +* `get_fov()`: Returns the following: + * Server-sent FOV value. Returns 0 if an FOV override doesn't exist. + * Boolean indicating whether the FOV value is a multiplier. + * Time (in seconds) taken for the FOV transition. Set by `set_fov`. +]] +---@nodiscard +---@return number fov, boolean is_multiplier, number transition_time +function PlayerRef:get_fov() end + +-- ----------------------------- player metadata ---------------------------- -- + +--[[ +* `set_attribute(attribute, value)`: DEPRECATED, use get_meta() instead + * Sets an extra attribute with value on player. + * `value` must be a string, or a number which will be converted to a + string. + * If `value` is `nil`, remove attribute from player. +]] +---@deprecated +---@param attribute string +---@param value string|number? +function PlayerRef:set_attribute(attribute, value) end + +--[[ +* `get_attribute(attribute)`: DEPRECATED, use get_meta() instead + * Returns value (a string) for extra attribute. + * Returns `nil` if no attribute found. +]] +---@deprecated +---@nodiscard +---@param attribute string +---@return string? +function PlayerRef:get_attribute(attribute) end + +--[[ +* `get_meta()`: Returns metadata associated with the player (a PlayerMetaRef). +]] +---@nodiscard +---@return core.PlayerMetaRef +function PlayerRef:get_meta() end + +-- ----------------------------- player formspec ---------------------------- -- + +--[[ +* `set_inventory_formspec(formspec)` + * Redefines the player's inventory formspec. + * Should usually be called at least once in the `on_joinplayer` callback. + * If `formspec` is `""`, the player's inventory is disabled. + * If the inventory formspec is currently open on the client, it is + updated immediately. + * See also: `core.register_on_player_receive_fields` +]] +---@param formspec core.Formspec +function PlayerRef:set_inventory_formspec(formspec) end + +--[[ +* `get_inventory_formspec()`: returns a formspec string +]] +---@nodiscard +---@return core.Formspec? formspec +function PlayerRef:get_inventory_formspec() end + +--[[ +* `set_formspec_prepend(formspec)`: + * the formspec string will be added to every formspec shown to the user, + except for those with a no_prepend[] tag. + * This should be used to set style elements such as background[] and + bgcolor[], any non-style elements (eg: label) may result in weird behavior. + * Only affects formspecs shown after this is called. +]] +---@param formspec core.Formspec +function PlayerRef:set_formspec_prepend(formspec) end + +--[[ +* `get_formspec_prepend()`: returns a formspec string. +]] +---@nodiscard +---@return core.Formspec? formspec +function PlayerRef:get_formspec_prepend() end + +-- ----------------------------- player control ----------------------------- -- + +--[[ PlayerRef:get_player_control() .. PlayerRef:get_player_control_bits() split off into ./player_control.lua ]]-- + +-- ------------------------- player physics override ------------------------ -- + +--[[ PlayerRef:set_physics_override() .. PlayerRef:get_physics_override() splits off into ./player_physics_override.lua ]]-- + +-- ------------------------------- player hud ------------------------------- -- + +--[[ +* `hud_add(hud definition)`: add a HUD element described by HUD def, returns ID + number on success +]] +---@nodiscard +---@param hud_definition core.HUDDef +---@return core.HUDID? id +function PlayerRef:hud_add(hud_definition) end + +--[[ +* `hud_remove(id)`: remove the HUD element of the specified id +]] +---@param id core.HUDID +function PlayerRef:hud_remove(id) end + +--[[ +* `hud_change(id, stat, value)`: change a value of a previously added HUD + element. + * `stat` supports the same keys as in the hud definition table except for + `"type"` (or the deprecated `"hud_elem_type"`). +]] +---@param id core.HUDID +---@param stat core.HUDDef.keys +---@param value number|string|core.Texture|vec2.xy|vec? +function PlayerRef:hud_change(id, stat, value) end + +--[[ +* `hud_get(id)`: gets the HUD element definition structure of the specified ID +]] +---@nodiscard +---@param id core.HUDID +---@return core.HUDDef? hud_definition +function PlayerRef:hud_get(id) end + +--[[ +* `hud_get_all()`: + * Returns a table in the form `{ [id] = HUD definition, [id] = ... }`. + * A mod should keep track of its introduced IDs and only use this to access foreign elements. + * It is discouraged to change foreign HUD elements. +]] +---@nodiscard +---@return table +function PlayerRef:hud_get_all() end + +--[[ PlayerRef:hud_set_flags() .. PlayerRef:hud_get_flags() split off into ./player_hud_flags.lua ]]-- + +--[[ +* `hud_set_hotbar_itemcount(count)`: sets number of items in builtin hotbar + * `count`: number of items, must be between `1` and `32` + * If `count` exceeds the `"main"` list size, the list size will be used instead. +]] +---@param count integer +function PlayerRef:hud_set_hotbar_itemcount(count) end + +--[[ +* `hud_get_hotbar_itemcount()`: returns number of visible items + * This value is also clamped by the `"main"` list size. +]] +---@nodiscard +---@return integer count +function PlayerRef:hud_get_hotbar_itemcount() end + +--[[ +* `hud_set_hotbar_image(texturename)` + * sets background image for hotbar +]] +---@param texturename core.Texture +function PlayerRef:hud_set_hotbar_image(texturename) end + +--[[ +* `hud_get_hotbar_image()`: returns texturename +]] +---@nodiscard +---@return core.Texture texturename +function PlayerRef:hud_get_hotbar_image() end + +--[[ +* `hud_set_hotbar_selected_image(texturename)` + * sets image for selected item of hotbar +]] +---@param texturename core.Texture +function PlayerRef:hud_set_hotbar_selected_image(texturename) end + +--[[ +* `hud_get_hotbar_selected_image()`: returns texturename +]] +---@nodiscard +---@return core.Texture texturename +function PlayerRef:hud_get_hotbar_selected_image() end + +-- ----------------------------- player minimap ----------------------------- -- + +--[[ PlayerRef:set_minimap_modes() split off into ./player_minimap.lua ]]-- + +-- ------------------------------- player sky ------------------------------- -- + +--[[ PlayerRef:set_sky() .. PlayerRef:get_sky_color() split off into ./player_skybox.lua ]]-- +--[[ PlayerRef:set_sun() .. PlayerRef:get_sun() split off into ./player_sun.lua ]]-- +--[[ PlayerRef:set_moon() .. PlayerRef:get_moon() split off into ./player_moon.lua ]]-- +--[[ PlayerRef:set_stars() .. PlayerRef:get_stars() split off into ./player_stars.lua ]]-- +--[[ PlayerRef:set_clouds() .. PlayerRef:get_clouds() split off into ./player_clouds.lua ]]-- + +--[[ +* `override_day_night_ratio(ratio or nil)` + * `0`...`1`: Overrides day-night ratio, controlling sunlight to a specific + amount. + * Passing no arguments disables override, defaulting to sunlight based on day-night cycle + * See also `core.time_to_day_night_ratio`, +]] +---@param ratio number? +function PlayerRef:override_day_night_ratio(ratio) end + +--[[ +* `get_day_night_ratio()`: returns the ratio or nil if it isn't overridden +]] +---@nodiscard +---@return number? ratio +function PlayerRef:get_day_night_ratio() end + +-- ---------------------------- player animation ---------------------------- -- + +--[[ +* `set_local_animation(idle, walk, dig, walk_while_dig, frame_speed)`: + set animation for player model in third person view. + * Every animation equals to a `{x=starting frame, y=ending frame}` table. + * `frame_speed` sets the animations frame speed. Default is 30. +]] +---@param idle vec2.xy +---@param walk vec2.xy +---@param dig vec2.xy +---@param walk_while_dig vec2.xy +---@param frame_speed number +function PlayerRef:set_local_animation(idle, walk, dig, walk_while_dig, frame_speed) end + +--[[ +* `get_local_animation()`: returns idle, walk, dig, walk_while_dig tables and + `frame_speed`. +]] +---@nodiscard +---@return vec2.xy idle, vec2.xy walk, vec2.xy dig +function PlayerRef:get_local_animation() end + +-- ------------------------------ player camera ----------------------------- -- + +--[[ +* `set_eye_offset([firstperson, thirdperson_back, thirdperson_front])`: Sets camera offset vectors. + * `firstperson`: Offset in first person view. + Defaults to `vector.zero()` if unspecified. + * `thirdperson_back`: Offset in third person back view. + Clamped between `vector.new(-10, -10, -5)` and `vector.new(10, 15, 5)`. + Defaults to `vector.zero()` if unspecified. + * `thirdperson_front`: Offset in third person front view. + Same limits as for `thirdperson_back` apply. + Defaults to `thirdperson_back` if unspecified. +]] +---@param firstperson vector? +---@param thirdperson_back vector? +---@param thirdperson_front vector? +function PlayerRef:set_eye_offset(firstperson, thirdperson_back, thirdperson_front) end + +--[[ +* `get_eye_offset()`: Returns camera offset vectors as set via `set_eye_offset`. +]] +---@nodiscard +---@return vec firstperson, vec thirdperson_back, vec thirdperson_front +function PlayerRef:get_eye_offset() end + +--[[ +WIPDOC +]] +---@alias core.PlayerCameraParams.mode +--- | "any" +--- | "first" +--- | "third" +--- | "third_front" + +--[[ +WIPDOC +]] +---@class core.PlayerCameraParams +--[[ +WIPDOC +]] +---@field mode core.PlayerCameraParams.mode + +--[[ +* `set_camera(params)`: Sets camera parameters. + * `mode`: Defines the camera mode used + - `any`: free choice between all modes (default) + - `first`: first-person camera + - `third`: third-person camera + - `third_front`: third-person camera, looking opposite of movement direction + * Supported by client since 5.12.0. +]] +---@param params core.PlayerCameraParams +function PlayerRef:set_camera(params) end + +--[[ +* `get_camera()`: Returns the camera parameters as a table as above. +]] +---@nodiscard +---@return core.PlayerCameraParams params +function PlayerRef:get_camera() end + +-- ---------------------- player mapblock and lighting ---------------------- -- + +--[[ +* `send_mapblock(blockpos)`: + * Sends an already loaded mapblock to the player. + * Returns `false` if nothing was sent (note that this can also mean that + the client already has the block) + * Resource intensive - use sparsely +]] +---@nodiscard +---@param blockpos vector +---@return boolean? +function PlayerRef:send_mapblock(blockpos) end + +--[[ PlayerRef:set_lighting() .. PlayerRef:get_lighting() split off into ./player_lighting.lua ]]-- + +-- ------------------------------- player misc ------------------------------ -- + +--[[ +* `respawn()`: Respawns the player using the same mechanism as the death screen, + including calling `on_respawnplayer` callbacks. +]] +function PlayerRef:respawn() end + +--[[ PlayerRef:get_flags() .. PlayerRef:set_flags() split off into ./player_flags.lua ]]-- \ No newline at end of file diff --git a/types/luanti_lsp_definitions/library/classes/ObjectRef/bones.lua b/types/luanti_lsp_definitions/library/classes/ObjectRef/bones.lua new file mode 100644 index 00000000..37d8fb2e --- /dev/null +++ b/types/luanti_lsp_definitions/library/classes/ObjectRef/bones.lua @@ -0,0 +1,150 @@ +---@meta _ +-- DRAFT 1 DONE +-- luanti/doc/lua_api.md: Class reference > `ObjectRef` + +-- -------------------------- BoneOverride.property ------------------------- -- + +--[[ +WIPDOC +]] +---@class core.BoneOverride.property.set +--[[ +WIPDOC +]] +---@field vec vector? +--[[ +WIPDOC +]] +---@field interpolation number? +--[[ +WIPDOC +]] +---@field absolute boolean? + +--[[ +WIPDOC +]] +---@class core.BoneOverride.property.get +--[[ +WIPDOC +]] +---@field vec vector +--[[ +WIPDOC +]] +---@field interpolation number +--[[ +WIPDOC +]] +---@field absolute boolean + + +-- ------------------------------ BoneOverride ------------------------------ -- + +--[[ +WIPDOC +]] +---@class core.BoneOverride.set +--[[ +WIPDOC +]] +---@field position core.BoneOverride.property.set? +--[[ +WIPDOC +]] +---@field rotation core.BoneOverride.property.set? +--[[ +WIPDOC +]] +---@field scale core.BoneOverride.property.set? + +--[[ +WIPDOC +]] +---@class core.BoneOverride.get +--[[ +WIPDOC +]] +---@field position core.BoneOverride.property.get +--[[ +WIPDOC +]] +---@field rotation core.BoneOverride.property.get +--[[ +WIPDOC +]] +---@field scale core.BoneOverride.property.get + + +-- ---------------------------- ObjectRef methods --------------------------- -- + +---@class _.ObjectRef.__base +local ObjectRefBase + +--[[ +* `set_bone_position([bone, position, rotation])` + * Sets absolute bone overrides, e.g. it is equivalent to + ```lua + obj:set_bone_override(bone, { + position = {vec = position, absolute = true}, + ``` + * **Note:** Rotation is in degrees, not radians. + * **Deprecated:** Use `set_bone_override` instead. +]] +---@deprecated +---@param bone string +---@param position vector +---@param rotation vector +function ObjectRefBase:set_bone_position(bone, position, rotation) end + +--[[ +* `get_bone_position(bone)`: returns the previously set position and rotation of the bone + * Shorthand for `get_bone_override(bone).position.vec, get_bone_override(bone).rotation.vec:apply(math.deg)`. + * **Note:** Returned rotation is in degrees, not radians. + * **Deprecated:** Use `get_bone_override` instead. +]] +---@nodiscard +---@deprecated +---@param bone string +---@return vec position, vec rotation +function ObjectRefBase:get_bone_position(bone) end + +--[[ +* `set_bone_override(bone, override)` + * `bone`: string + * `override`: `{ position = property, rotation = property, scale = property }` or `nil` + * `override = nil` (including omission) is shorthand for `override = {}` which clears the override + * Each `property` is a table of the form + `{ vec = vector, interpolation = 0, absolute = false }` or `nil` + * `vec` is in the same coordinate system as the model, and in radians for rotation. + It defaults to `vector.zero()` for translation and rotation and `vector.new(1, 1, 1)` for scale. + * `interpolation`: The old and new overrides are interpolated over this timeframe (in seconds). + * `absolute`: If set to `false` (which is the default), + the override will be relative to the animated property: + * Translation in the case of `position`; + * Composition in the case of `rotation`; + * Per-axis multiplication in the case of `scale` + * `property = nil` is equivalent to no override on that property + * **Note:** Unlike `set_bone_position`, the rotation is in radians, not degrees. + * Compatibility note: Clients prior to 5.9.0 only support absolute position and rotation. + All values are treated as absolute and are set immediately (no interpolation). +]] +---@param bone string +---@param override core.BoneOverride.set? +function ObjectRefBase:set_bone_override(bone, override) end + +--[[ +* `get_bone_override(bone)`: returns `override` in the above format + * **Note:** Unlike `get_bone_position`, the returned rotation is in radians, not degrees. +]] +---@nodiscard +---@param bone string +---@return core.BoneOverride.get +function ObjectRefBase:get_bone_override(bone) end + +--[[ +* `get_bone_overrides()`: returns all bone overrides as table `{[bonename] = override, ...}` +]] +---@nodiscard +---@return table +function ObjectRefBase:get_bone_overrides() end \ No newline at end of file diff --git a/types/luanti_lsp_definitions/library/classes/ObjectRef/nametag.lua b/types/luanti_lsp_definitions/library/classes/ObjectRef/nametag.lua new file mode 100644 index 00000000..2359dfb5 --- /dev/null +++ b/types/luanti_lsp_definitions/library/classes/ObjectRef/nametag.lua @@ -0,0 +1,80 @@ +---@meta _ +-- DRAFT 1 DONE +-- luanti/doc/lua_api.md: Class reference > `ObjectRef` + +-- ---------------------------- NametagAttributes --------------------------- -- + +--[[ +WIPDOC +]] +---@class core.NametagAttributes.get +--[[ +WIPDOC +]] +---@field text string +--[[ +WIPDOC +]] +---@field color core.ColorSpec.tablefmt +--[[ +WIPDOC +]] +---@field bgcolor core.ColorSpec.tablefmt + +--[[ +WIPDOC +]] +---@class core.NametagAttributes.set +--[[ +WIPDOC +]] +---@field text string +--[[ +WIPDOC +]] +---@field color core.ColorSpec +--[[ +WIPDOC +]] +---@field bgcolor core.ColorSpec | false | nil + + +-- ---------------------------- ObjectRef methods --------------------------- -- + +---@class _.ObjectRef.__base +local ObjectRefBase + +--[[ +* `get_nametag_attributes()` + * returns a table with the attributes of the nametag of an object + * a nametag is a HUD text rendered above the object + * ```lua + { + text = "", + color = {a=0..255, r=0..255, g=0..255, b=0..255}, + bgcolor = {a=0..255, r=0..255, g=0..255, b=0..255}, + } + ``` +]] +---@nodiscard +---@return core.NametagAttributes.get attributes +function ObjectRefBase:get_nametag_attributes() end + +--[[ +* `set_nametag_attributes(attributes)` + * sets the attributes of the nametag of an object + * `attributes`: + ```lua + { + text = "My Nametag", + color = ColorSpec, + -- ^ Text color + bgcolor = ColorSpec or false, + -- ^ Sets background color of nametag + -- `false` will cause the background to be set automatically based on user settings + -- Default: false + } + ``` +]] +---@param attributes core.NametagAttributes.set +function ObjectRefBase:set_nametag_attributes(attributes) end \ No newline at end of file diff --git a/types/luanti_lsp_definitions/library/classes/ObjectRef/player_clouds.lua b/types/luanti_lsp_definitions/library/classes/ObjectRef/player_clouds.lua new file mode 100644 index 00000000..38b1bce1 --- /dev/null +++ b/types/luanti_lsp_definitions/library/classes/ObjectRef/player_clouds.lua @@ -0,0 +1,107 @@ +---@meta _ +-- DRAFT 1 DONE +-- luanti/doc/lua_api.md: Class reference > `ObjectRef` + + +-- -------------------------- PlayerCloudParameters ------------------------- -- + +--[[ +WIPDOC +]] +---@class core.PlayerCloudParameters.set +--[[ +WIPDOC +]] +---@field density number? +--[[ +WIPDOC +]] +---@field color core.ColorSpec? +--[[ +WIPDOC +]] +---@field ambient core.ColorSpec? +--[[ +WIPDOC +]] +---@field height integer? +--[[ +WIPDOC +]] +---@field thickness integer? +--[[ +WIPDOC +]] +---@field speed vec2.xy? +--[[ +WIPDOC +]] +---@field shadow core.ColorSpec? + +--[[ +WIPDOC +]] +---@class core.PlayerCloudParameters.get +--[[ +WIPDOC +]] +---@field density number +--[[ +WIPDOC +]] +---@field color core.ColorSpec +--[[ +WIPDOC +]] +---@field ambient core.ColorSpec +--[[ +WIPDOC +]] +---@field height integer +--[[ +WIPDOC +]] +---@field thickness integer +--[[ +WIPDOC +]] +---@field speed vec2.xy +--[[ +WIPDOC +]] +---@field shadow core.ColorSpec + +-- ---------------------------- PlayerRef methods --------------------------- -- + +---@class core.PlayerRef +local PlayerRef + + +--[[ +* `set_clouds(cloud_parameters)`: set cloud parameters + * Passing no arguments resets clouds to their default values. + * `cloud_parameters` is a table with the following optional fields: + * `density`: from `0` (no clouds) to `1` (full clouds) (default `0.4`) + * `color`: basic cloud color with alpha channel, ColorSpec + (default `#fff0f0e5`). + * `ambient`: cloud color lower bound, use for a "glow at night" effect. + ColorSpec (alpha ignored, default `#000000`) + * `height`: cloud height, i.e. y of cloud base (default per conf, + usually `120`) + * `thickness`: cloud thickness in nodes (default `16`). + if set to zero the clouds are rendered flat. + * `speed`: 2D cloud speed + direction in nodes per second + (default `{x=0, z=-2}`). + * `shadow`: shadow color, applied to the base of the cloud + (default `#cccccc`). +]] +---@param cloud_parameters core.PlayerCloudParameters.set +function PlayerRef:set_clouds(cloud_parameters) end + +--[[ +* `get_clouds()`: returns a table with the current cloud parameters as in + `set_clouds`. +]] +---@nodiscard +---@return core.PlayerCloudParameters.get cloud_parameters +function PlayerRef:get_clouds() end \ No newline at end of file diff --git a/types/luanti_lsp_definitions/library/classes/ObjectRef/player_control.lua b/types/luanti_lsp_definitions/library/classes/ObjectRef/player_control.lua new file mode 100644 index 00000000..f40b027f --- /dev/null +++ b/types/luanti_lsp_definitions/library/classes/ObjectRef/player_control.lua @@ -0,0 +1,110 @@ +---@meta _ +-- DRAFT 1 DONE +-- luanti/doc/lua_api.md: Class reference > `ObjectRef` + +-- ------------------------------ PlayerControl ----------------------------- -- + +--[[ +WIPDOC +]] +---@class core.PlayerControl +--[[ +WIPDOC +]] +---@field up boolean +--[[ +WIPDOC +]] +---@field down boolean +--[[ +WIPDOC +]] +---@field left boolean +--[[ +WIPDOC +]] +---@field right boolean +--[[ +WIPDOC +]] +---@field jump boolean +--[[ +WIPDOC +]] +---@field aux1 boolean +--[[ +WIPDOC +]] +---@field sneak boolean +--[[ +WIPDOC +]] +---@field dig boolean +--[[ +WIPDOC +]] +---@field place boolean +--[[ +WIPDOC +]] +---@field LMB boolean +--[[ +WIPDOC +]] +---@field RMB boolean +--[[ +WIPDOC +]] +---@field zoom boolean +--[[ +WIPDOC +]] +---@field movement_x number +--[[ +WIPDOC +]] +---@field movement_y number + +-- ---------------------------- PlayerRef methods --------------------------- -- + +---@class core.PlayerRef +local PlayerRef + +--[[ +* `get_player_control()`: returns table with player input + * The table contains the following boolean fields representing the pressed + keys: `up`, `down`, `left`, `right`, `jump`, `aux1`, `sneak`, `dig`, + `place`, `LMB`, `RMB` and `zoom`. + * The fields `LMB` and `RMB` are equal to `dig` and `place` respectively, + and exist only to preserve backwards compatibility. + * The table also contains the fields `movement_x` and `movement_y`. + * They represent the movement of the player. Values are numbers in the + range [-1.0,+1.0]. + * They take both keyboard and joystick input into account. + * You should prefer them over `up`, `down`, `left` and `right` to + support different input methods correctly. + * Returns an empty table `{}` if the object is not a player. +]] +---@nodiscard +---@return core.PlayerControl +function PlayerRef:get_player_control() end + +--[[ +* `get_player_control_bits()`: returns integer with bit packed player pressed + keys. + * Bits: + * 0 - up + * 1 - down + * 2 - left + * 3 - right + * 4 - jump + * 5 - aux1 + * 6 - sneak + * 7 - dig + * 8 - place + * 9 - zoom + * Returns `0` (no bits set) if the object is not a player. +]] +---@nodiscard +---@return integer +function PlayerRef:get_player_control_bits() end \ No newline at end of file diff --git a/types/luanti_lsp_definitions/library/classes/ObjectRef/player_flags.lua b/types/luanti_lsp_definitions/library/classes/ObjectRef/player_flags.lua new file mode 100644 index 00000000..f74b9843 --- /dev/null +++ b/types/luanti_lsp_definitions/library/classes/ObjectRef/player_flags.lua @@ -0,0 +1,63 @@ +---@meta _ +-- DRAFT 1 DONE +-- luanti/doc/lua_api.md: Class reference > `ObjectRef` + +-- ------------------------------- PlayerFlags ------------------------------ -- + +--[[ +WIPDOC +]] +---@class core.PlayerFlags.get +--[[ +WIPDOC +]] +---@field breathing boolean +--[[ +WIPDOC +]] +---@field drowning boolean +--[[ +WIPDOC +]] +---@field node_damage boolean + +--[[ +WIPDOC +]] +---@class core.PlayerFlags.set +--[[ +WIPDOC +]] +---@field breathing boolean? +--[[ +WIPDOC +]] +---@field drowning boolean? +--[[ +WIPDOC +]] +---@field node_damage boolean? + + +-- ---------------------------- PlayerRef methods --------------------------- -- + +---@class core.PlayerRef +local PlayerRef + +--[[ +* `get_flags()`: returns a table of player flags (the following boolean fields): + * `breathing`: Whether breathing (regaining air) is enabled, default `true`. + * `drowning`: Whether drowning (losing air) is enabled, default `true`. + * `node_damage`: Whether the player takes damage from nodes, default `true`. +]] +---@nodiscard +---@return core.PlayerFlags.get flags +function PlayerRef:get_flags() end + +--[[ +* `set_flags(flags)`: sets flags + * takes a table in the same format as returned by `get_flags` + * absent fields are left unchanged +]] +---@param flags core.PlayerFlags.set +function PlayerRef:set_flags(flags) end \ No newline at end of file diff --git a/types/luanti_lsp_definitions/library/classes/ObjectRef/player_hud_flags.lua b/types/luanti_lsp_definitions/library/classes/ObjectRef/player_hud_flags.lua new file mode 100644 index 00000000..e13f351f --- /dev/null +++ b/types/luanti_lsp_definitions/library/classes/ObjectRef/player_hud_flags.lua @@ -0,0 +1,112 @@ +---@meta _ +-- DRAFT 1 DONE +-- luanti/doc/lua_api.md: Class reference > `ObjectRef` + +-- ----------------------------- PlayerHudFlags ----------------------------- -- + +--[[ +WIPDOC +]] +---@class core.PlayerHudFlags.set +--[[ +WIPDOC +]] +---@field hotbar boolean? +--[[ +WIPDOC +]] +---@field healthbar boolean? +--[[ +WIPDOC +]] +---@field crosshair boolean? +--[[ +WIPDOC +]] +---@field wielditem boolean? +--[[ +WIPDOC +]] +---@field breathbar boolean? +--[[ +WIPDOC +]] +---@field minimap boolean? +--[[ +WIPDOC +]] +---@field minimap_radar boolean? +--[[ +WIPDOC +]] +---@field basic_debug boolean? + +--[[ +WIPDOC +]] +---@class core.PlayerHudFlags.get +--[[ +WIPDOC +]] +---@field hotbar boolean +--[[ +WIPDOC +]] +---@field healthbar boolean +--[[ +WIPDOC +]] +---@field crosshair boolean +--[[ +WIPDOC +]] +---@field wielditem boolean +--[[ +WIPDOC +]] +---@field breathbar boolean +--[[ +WIPDOC +]] +---@field minimap boolean +--[[ +WIPDOC +]] +---@field minimap_radar boolean +--[[ +WIPDOC +]] +---@field basic_debug boolean + + +-- ---------------------------- PlayerRef methods --------------------------- -- + +---@class core.PlayerRef +local PlayerRef + +--[[ +* `hud_set_flags(flags)`: sets specified HUD flags of player. + * `flags`: A table with the following fields set to boolean values + * `hotbar` + * `healthbar` + * `crosshair` + * `wielditem` + * `breathbar` + * `minimap`: Modifies the client's permission to view the minimap. + The client may locally elect to not view the minimap. + * `minimap_radar`: is only usable when `minimap` is true + * `basic_debug`: Allow showing basic debug info that might give a gameplay advantage. + This includes map seed, player position, look direction, the pointed node and block bounds. + Does not affect players with the `debug` privilege. + * If a flag equals `nil`, the flag is not modified +]] +---@param flags core.PlayerHudFlags.set +function PlayerRef:hud_set_flags(flags) end + +--[[ +* `hud_get_flags()`: returns a table of player HUD flags with boolean values. + * See `hud_set_flags` for a list of flags that can be toggled. +]] +---@nodiscard +---@return core.PlayerHudFlags.get flags +function PlayerRef:hud_get_flags() end \ No newline at end of file diff --git a/types/luanti_lsp_definitions/library/classes/ObjectRef/player_lighting.lua b/types/luanti_lsp_definitions/library/classes/ObjectRef/player_lighting.lua new file mode 100644 index 00000000..546ecee9 --- /dev/null +++ b/types/luanti_lsp_definitions/library/classes/ObjectRef/player_lighting.lua @@ -0,0 +1,219 @@ +---@meta _ +-- DRAFT 1 DONE +-- luanti/doc/lua_api.md: Class reference > `ObjectRef` + +-- -------------------------- PlayerLightDef.shadow ------------------------- -- + +--[[ +WIPDOC +]] +---@class core.PlayerLightDef.shadow.set +--[[ +WIPDOC +]] +---@field intensity number? +--[[ +WIPDOC +]] +---@field tint core.ColorSpec? + +--[[ +WIPDOC +]] +---@class core.PlayerLightDef.shadow.get +--[[ +WIPDOC +]] +---@field intensity number? +--[[ +WIPDOC +]] +---@field tint core.ColorSpec? + +-- ------------------------- PlayerLightDef.exposure ------------------------ -- + +--[[ +WIPDOC +]] +---@class core.PlayerLightDef.exposure.set +--[[ +WIPDOC +]] +---@field luminescence_min number? +--[[ +WIPDOC +]] +---@field luminescence_max number? +--[[ +WIPDOC +]] +---@field exposure_correction number? +--[[ +WIPDOC +]] +---@field speed_dark_bright number? +--[[ +WIPDOC +]] +---@field speed_bright_dark number? +--[[ +WIPDOC +]] +---@field center_weight_power number? + +--[[ +WIPDOC +]] +---@class core.PlayerLightDef.exposure.get +--[[ +WIPDOC +]] +---@field luminescence_min number +--[[ +WIPDOC +]] +---@field luminescence_max number +--[[ +WIPDOC +]] +---@field exposure_correction number +--[[ +WIPDOC +]] +---@field speed_dark_bright number +--[[ +WIPDOC +]] +---@field speed_bright_dark number +--[[ +WIPDOC +]] +---@field center_weight_power number + +-- -------------------------- PlayerLightDef.bloom -------------------------- -- + +--[[ +WIPDOC +]] +---@class core.PlayerLightDef.bloom.set +--[[ +WIPDOC +]] +---@field intensity number? +--[[ +WIPDOC +]] +---@field strength_factor number? +--[[ +WIPDOC +]] +---@field radius number? + +--[[ +WIPDOC +]] +---@class core.PlayerLightDef.bloom.get +--[[ +WIPDOC +]] +---@field intensity number +--[[ +WIPDOC +]] +---@field strength_factor number +--[[ +WIPDOC +]] +---@field radius number + +-- --------------------- PlayerLightDef.volumetric_light -------------------- -- + +--[[ +WIPDOC +]] +---@class core.PlayerLightDef.volumetric_light.set +--[[ +WIPDOC +]] +---@field strength number? + +--[[ +WIPDOC +]] +---@class core.PlayerLightDef.volumetric_light.get +--[[ +WIPDOC +]] +---@field strength number + + +-- ----------------------------- PlayerLightDef ----------------------------- -- + +--[[ +WIPDOC +]] +---@class core.PlayerLightDef.set +--[[ +WIPDOC +]] +---@field saturation number? +--[[ +WIPDOC +]] +---@field shadows core.PlayerLightDef.shadow.set? +--[[ +WIPDOC +]] +---@field exposure core.PlayerLightDef.exposure.set? +--[[ +WIPDOC +]] +---@field bloom core.PlayerLightDef.bloom.set? +--[[ +WIPDOC +]] +---@field volumetric_light core.PlayerLightDef.volumetric_light.set? + +--[[ +WIPDOC +]] +---@class core.PlayerLightDef.get +--[[ +WIPDOC +]] +---@field saturation number +--[[ +WIPDOC +]] +---@field shadows core.PlayerLightDef.shadow.get +--[[ +WIPDOC +]] +---@field exposure core.PlayerLightDef.exposure.get +--[[ +WIPDOC +]] +---@field bloom core.PlayerLightDef.bloom.get +--[[ +WIPDOC +]] +---@field volumetric_light core.PlayerLightDef.volumetric_light.get + +-- ---------------------------- PlayerRef methods --------------------------- -- + +---@class core.PlayerRef +local PlayerRef + +--[[ +WIPDOC +]] +---@param light_definition core.PlayerLightDef.set +function PlayerRef:set_lighting(light_definition) end + +--[[ +* `get_lighting()`: returns the current state of lighting for the player. + * Result is a table with the same fields as `light_definition` in `set_lighting`. +]] +---@nodiscard +---@return core.PlayerLightDef.get light_definition +function PlayerRef:get_lighting() end \ No newline at end of file diff --git a/types/luanti_lsp_definitions/library/classes/ObjectRef/player_minimap.lua b/types/luanti_lsp_definitions/library/classes/ObjectRef/player_minimap.lua new file mode 100644 index 00000000..c2ad92d2 --- /dev/null +++ b/types/luanti_lsp_definitions/library/classes/ObjectRef/player_minimap.lua @@ -0,0 +1,71 @@ +---@meta _ +-- DRAFT 1 DONE +-- luanti/doc/lua_api.md: Class reference > `ObjectRef` + +-- ---------------------------- PlayreMinimapMode --------------------------- -- + +--[[ +WIPDOC +]] +---@alias core.PlayerMinimapMode.type +--- | "off" +--- | "surface" +--- | "radar" +--- | "texture" + +--[[ +WIPDOC +]] +---@class core.PlayerMinimapMode +--[[ +WIPDOC +]] +---@field type core.PlayerMinimapMode.type +--[[ +WIPDOC +]] +---@field label string? +--[[ +WIPDOC +]] +---@field size integer +--[[ +WIPDOC +]] +---@field texture core.Texture? +--[[ +WIPDOC +]] +---@field scale integer? + +-- ---------------------------- PlayerRef methods --------------------------- -- + +---@class core.PlayerRef +local PlayerRef + +--[[ +* `set_minimap_modes({mode, mode, ...}, selected_mode)` + * Overrides the available minimap modes (and toggle order), and changes the + selected mode. + * `mode` is a table consisting of up to four fields: + * `type`: Available type: + * `off`: Minimap off + * `surface`: Minimap in surface mode + * `radar`: Minimap in radar mode + * `texture`: Texture to be displayed instead of terrain map + (texture is centered around 0,0 and can be scaled). + Texture size is limited to 512 x 512 pixel. + * `label`: Optional label to display on minimap mode toggle + The translation must be handled within the mod. + * `size`: Sidelength or diameter, in number of nodes, of the terrain + displayed in minimap + * `texture`: Only for texture type, name of the texture to display + * `scale`: Only for texture type, scale of the texture map in nodes per + pixel (for example a `scale` of 2 means each pixel represents a 2x2 + nodes square) + * `selected_mode` is the mode index to be selected after modes have been changed + (0 is the first mode). +]] +---@param modes core.PlayerMinimapMode[] +---@param selected_mode integer +function PlayerRef:set_minimap_modes(modes, selected_mode) end \ No newline at end of file diff --git a/types/luanti_lsp_definitions/library/classes/ObjectRef/player_moon.lua b/types/luanti_lsp_definitions/library/classes/ObjectRef/player_moon.lua new file mode 100644 index 00000000..b788055f --- /dev/null +++ b/types/luanti_lsp_definitions/library/classes/ObjectRef/player_moon.lua @@ -0,0 +1,66 @@ +---@meta _ +-- DRAFT 1 DONE +-- luanti/doc/lua_api.md: Class reference > `ObjectRef` + +-- -------------------------- PlayerMoonParameters -------------------------- -- + +--[[ +WIPDOC +]] +---@class core.PlayerMoonParameters.set +--[[ +WIPDOC +]] +---@field visible boolean? +--[[ +WIPDOC +]] +---@field texture core.Texture? +--[[ +WIPDOC +]] +---@field tonemap core.Texture? +--[[ +WIPDOC +]] +---@field scale number? + +--[[ +WIPDOC +]] +---@class core.PlayerMoonParameters.get +--[[ +WIPDOC +]] +---@field visible boolean +--[[ +WIPDOC +]] +---@field texture core.Texture +--[[ +WIPDOC +]] +---@field tonemap core.Texture +--[[ +WIPDOC +]] +---@field scale number + +-- ---------------------------- PlayerRef methods --------------------------- -- + +---@class core.PlayerRef +local PlayerRef + +--[[ +WIPDOC +]] +---@param moon_parameters core.PlayerMoonParameters.set +function PlayerRef:set_moon(moon_parameters) end + +--[[ +* `get_moon()`: returns a table with the current moon parameters as in + `set_moon`. +]] +---@nodiscard +---@return core.PlayerMoonParameters.get moon_parameters +function PlayerRef:get_moon() end \ No newline at end of file diff --git a/types/luanti_lsp_definitions/library/classes/ObjectRef/player_physics_override.lua b/types/luanti_lsp_definitions/library/classes/ObjectRef/player_physics_override.lua new file mode 100644 index 00000000..b8d168e8 --- /dev/null +++ b/types/luanti_lsp_definitions/library/classes/ObjectRef/player_physics_override.lua @@ -0,0 +1,162 @@ +---@meta _ +-- DRAFT 1 DONE +-- luanti/doc/lua_api.md: Class reference > `ObjectRef` + +-- -------------------------- PlayerPhysicsOverride ------------------------- -- + +--[[ +WIPDOC +]] +---@class core.PlayerPhysicsOverride.set +--[[ +WIPDOC +]] +---@field speed number? +--[[ +WIPDOC +]] +---@field speed_walk number? +--[[ +WIPDOC +]] +---@field speed_climb number? +--[[ +WIPDOC +]] +---@field speed_crouch number? +--[[ +WIPDOC +]] +---@field speed_fast number? +--[[ +WIPDOC +]] +---@field jump number? +--[[ +WIPDOC +]] +---@field gravity number? +--[[ +WIPDOC +]] +---@field liquid_fluidity number? +--[[ +WIPDOC +]] +---@field liquid_fluidity_smooth number? +--[[ +WIPDOC +]] +---@field liquid_sink number? +--[[ +WIPDOC +]] +---@field acceleration_default number? +--[[ +WIPDOC +]] +---@field acceleration_air number? +--[[ +WIPDOC +]] +---@field acceleration_fast number? +--[[ +WIPDOC +]] +---@field sneak number? +--[[ +WIPDOC +]] +---@field sneak_glitch number? +--[[ +WIPDOC +]] +---@field new_move number? + +--[[ +WIPDOC +]] +---@class core.PlayerPhysicsOverride.get +--[[ +WIPDOC +]] +---@field speed number +--[[ +WIPDOC +]] +---@field speed_walk number +--[[ +WIPDOC +]] +---@field speed_climb number +--[[ +WIPDOC +]] +---@field speed_crouch number +--[[ +WIPDOC +]] +---@field speed_fast number +--[[ +WIPDOC +]] +---@field jump number +--[[ +WIPDOC +]] +---@field gravity number +--[[ +WIPDOC +]] +---@field liquid_fluidity number +--[[ +WIPDOC +]] +---@field liquid_fluidity_smooth number +--[[ +WIPDOC +]] +---@field liquid_sink number +--[[ +WIPDOC +]] +---@field acceleration_default number +--[[ +WIPDOC +]] +---@field acceleration_air number +--[[ +WIPDOC +]] +---@field acceleration_fast number +--[[ +WIPDOC +]] +---@field sneak number +--[[ +WIPDOC +]] +---@field sneak_glitch number +--[[ +WIPDOC +]] +---@field new_move number + + +-- ---------------------------- PlayerRef methods --------------------------- -- + +---@class core.PlayerRef +local PlayerRef + +--[[ +WIPDOC +]] +---@param override_table core.PlayerPhysicsOverride.set +function PlayerRef:set_physics_override(override_table) end + +--[[ +* `get_physics_override()`: returns the table given to `set_physics_override` +]] +---@nodiscard +---@return core.PlayerPhysicsOverride.get override_table +function PlayerRef:get_physics_override() end \ No newline at end of file diff --git a/types/luanti_lsp_definitions/library/classes/ObjectRef/player_skybox.lua b/types/luanti_lsp_definitions/library/classes/ObjectRef/player_skybox.lua new file mode 100644 index 00000000..778b6e02 --- /dev/null +++ b/types/luanti_lsp_definitions/library/classes/ObjectRef/player_skybox.lua @@ -0,0 +1,368 @@ +---@meta _ +-- DRAFT 1 DONE +-- luanti/doc/lua_api.md: Class reference > `ObjectRef` + +-- -------------------- PlayerSkyParameters.regular.color ------------------- -- + +--[[ +WIPDOC +]] +---@class core.PlayerSkyParameters.regular.color.set +--[[ +WIPDOC +]] +---@field day_sky core.ColorSpec? +--[[ +WIPDOC +]] +---@field day_horizon core.ColorSpec? +--[[ +WIPDOC +]] +---@field dawn_sky core.ColorSpec? +--[[ +WIPDOC +]] +---@field dawn_horizon core.ColorSpec? +--[[ +WIPDOC +]] +---@field night_sky core.ColorSpec? +--[[ +WIPDOC +]] +---@field night_horizon core.ColorSpec? +--[[ +WIPDOC +]] +---@field indoors core.ColorSpec? +--[[ +WIPDOC +]] +---@field fog_sun_tint core.ColorSpec? +--[[ +WIPDOC +]] +---@field fog_moon_tint core.ColorSpec? +--[[ +WIPDOC +]] +---@field fog_tint_type "custom"|"default"? + +--[[ +WIPDOC +]] +---@class core.PlayerSkyParameters.regular.color.get +--[[ +WIPDOC +]] +---@field day_sky core.ColorSpec +--[[ +WIPDOC +]] +---@field day_horizon core.ColorSpec +--[[ +WIPDOC +]] +---@field dawn_sky core.ColorSpec +--[[ +WIPDOC +]] +---@field dawn_horizon core.ColorSpec +--[[ +WIPDOC +]] +---@field night_sky core.ColorSpec +--[[ +WIPDOC +]] +---@field night_horizon core.ColorSpec +--[[ +WIPDOC +]] +---@field indoors core.ColorSpec +--[[ +WIPDOC +]] +---@field fog_sun_tint core.ColorSpec +--[[ +WIPDOC +]] +---@field fog_moon_tint core.ColorSpec +--[[ +WIPDOC +]] +---@field fog_tint_type "custom"|"default" + + +-- ------------------------- PlayerSkyParameters.fog ------------------------ -- + +--[[ +WIPDOC +]] +---@class core.PlayerSkyParameters.fog.set +--[[ +WIPDOC +]] +---@field fog_distance integer? +--[[ +WIPDOC +]] +---@field fog_start number? +--[[ +WIPDOC +]] +---@field fog_color core.ColorSpec? + +--[[ +WIPDOC +]] +---@class core.PlayerSkyParameters.fog.get +--[[ +WIPDOC +]] +---@field fog_distance integer +--[[ +WIPDOC +]] +---@field fog_start number +--[[ +WIPDOC +]] +---@field fog_color core.ColorSpec + + + +-- ----------------------- PlayerSkyParameters.__base ----------------------- -- + +--[[ +WIPDOC +]] +---@class _.PlayerSkyParameters.__base.set +--[[ +WIPDOC +]] +---@field base_color core.ColorSpec? +--[[ +WIPDOC +]] +---@field body_orbit_tilt number? +--[[ +WIPDOC +]] +---@field textures {}? +--[[ +WIPDOC +]] +---@field clouds boolean? +--[[ +WIPDOC +]] +---@field fog core.PlayerSkyParameters.fog.set? + +--[[ +WIPDOC +]] +---@class _.PlayerSkyParameters.__base.get +--[[ +WIPDOC +]] +---@field base_color core.ColorSpec +--[[ +WIPDOC +]] +---@field body_orbit_tilt number +--[[ +WIPDOC +]] +---@field textures {} +--[[ +WIPDOC +]] +---@field clouds boolean +--[[ +WIPDOC +]] +---@field fog core.PlayerSkyParameters.fog.get + +-- ----------------------- PlayerSkyParameters.regular ---------------------- -- + +--[[ +WIPDOC +]] +---@class core.PlayerSkyParameters.regular.set : _.PlayerSkyParameters.__base.set +--[[ +WIPDOC +]] +---@field type "regular" +--[[ +WIPDOC +]] +---@field sky_color core.PlayerSkyParameters.regular.color.set? + +--[[ +WIPDOC +]] +---@class core.PlayerSkyParameters.regular.get : _.PlayerSkyParameters.__base.get +--[[ +WIPDOC +]] +---@field type "regular" +--[[ +WIPDOC +]] +---@field sky_color core.PlayerSkyParameters.regular.color.get + +-- ----------------------- PlayerSkyParameters.skybox ----------------------- -- + +--[[ +WIPDOC +]] +---@class core.PlayerSkyParameters.skybox.textures.strict +--[[ +WIPDOC +]] +---@field [1] core.Texture +--[[ +WIPDOC +]] +---@field [2] core.Texture +--[[ +WIPDOC +]] +---@field [3] core.Texture +--[[ +WIPDOC +]] +---@field [4] core.Texture +--[[ +WIPDOC +]] +---@field [5] core.Texture +--[[ +WIPDOC +]] +---@field [6] core.Texture + +--[[ +WIPDOC +]] +---@alias core.PlayerSkyParameters.skybox.textures +--- | core.PlayerSkyParameters.skybox.textures.strict +--- | core.Texture[] + +--[[ +WIPDOC +]] +---@class core.PlayerSkyParameters.skybox.set : _.PlayerSkyParameters.__base.set +--[[ +WIPDOC +]] +---@field type "skybox" +--[[ +WIPDOC +]] +---@field textures core.PlayerSkyParameters.skybox.textures? + +--[[ +WIPDOC +]] +---@class core.PlayerSkyParameters.skybox.get : _.PlayerSkyParameters.__base.get +--[[ +WIPDOC +]] +---@field type "skybox" +--[[ +WIPDOC +]] +---@field textures core.PlayerSkyParameters.skybox.textures + +-- ------------------------ PlayerSkyParameters.plain ----------------------- -- + +--[[ +WIPDOC +]] +---@class core.PlayerSkyParameters.plain.set : _.PlayerSkyParameters.__base.set +--[[ +WIPDOC +]] +---@field type "plain" + +--[[ +WIPDOC +]] +---@class core.PlayerSkyParameters.plain.get : _.PlayerSkyParameters.__base.get +--[[ +WIPDOC +]] +---@field type "plain" + + +-- --------------------------- PlayerSkyParameters -------------------------- -- + +---@alias core.PlayerSkyParameters.set +--- | core.PlayerSkyParameters.regular.set +--- | core.PlayerSkyParameters.skybox.set +--- | core.PlayerSkyParameters.plain.set + +---@alias core.PlayerSkyParameters.get +--- | core.PlayerSkyParameters.regular.get +--- | core.PlayerSkyParameters.skybox.get +--- | core.PlayerSkyParameters.plain.get + +-- ---------------------------- PlayerRef methods --------------------------- -- + +---@class core.PlayerRef +local PlayerRef + +--[[ +WIPDOC +]] +---@param sky_parameters core.PlayerSkyParameters.set +function PlayerRef:set_sky(sky_parameters) end + +--[[ +* `get_sky(as_table)`: + * `as_table`: boolean that determines whether the deprecated version of this + function is being used. + * `true` returns a table containing sky parameters as defined in `set_sky(sky_parameters)`. + * Deprecated: `false` or `nil` returns base_color, type, table of textures, + clouds. +]] +---@nodiscard +---@param as_table true +---@return core.PlayerSkyParameters.get sky_parameters +function PlayerRef:get_sky(as_table) end + +--[[ +WIPDOC +]] +---@deprecated +---@param base_color core.ColorSpec +---@param type "regular"|"skybox"|"plain" +---@param textures core.Texture[] +---@param clouds boolean? +function PlayerRef:set_sky(base_color, type, textures, clouds) end + +--[[ +* `get_sky(as_table)`: + * `as_table`: boolean that determines whether the deprecated version of this + function is being used. + * `true` returns a table containing sky parameters as defined in `set_sky(sky_parameters)`. + * Deprecated: `false` or `nil` returns base_color, type, table of textures, + clouds. +]] +---@deprecated +---@nodiscard +---@return core.ColorSpec base_color, "regular"|"skybox"|"plain" type, core.Texture[] textures, boolean? clouds +function PlayerRef:get_sky(as_table) end + +--[[ +* `get_sky_color()`: + * Deprecated: Use `get_sky(as_table)` instead. + * returns a table with the `sky_color` parameters as in `set_sky`. +]] +---@deprecated +---@nodiscard +---@return core.PlayerSkyParameters.regular.color.get sky_color +function PlayerRef:get_sky_color() end \ No newline at end of file diff --git a/types/luanti_lsp_definitions/library/classes/ObjectRef/player_star.lua b/types/luanti_lsp_definitions/library/classes/ObjectRef/player_star.lua new file mode 100644 index 00000000..46174326 --- /dev/null +++ b/types/luanti_lsp_definitions/library/classes/ObjectRef/player_star.lua @@ -0,0 +1,89 @@ +---@meta _ +-- DRAFT 1 DONE +-- luanti/doc/lua_api.md: Class reference > `ObjectRef` + +-- -------------------------- PlayerStarParameters -------------------------- -- + +--[[ +WIPDOC +]] +---@class core.PlayerStarParameters.set +--[[ +WIPDOC +]] +---@field visible boolean? +--[[ +WIPDOC +]] +---@field day_opacity number? +--[[ +WIPDOC +]] +---@field count integer? +--[[ +WIPDOC +]] +---@field star_color core.ColorSpec? +--[[ +WIPDOC +]] +---@field scale number? + +--[[ +WIPDOC +]] +---@class core.PlayerStarParameters.get +--[[ +WIPDOC +]] +---@field visible boolean +--[[ +WIPDOC +]] +---@field day_opacity number +--[[ +WIPDOC +]] +---@field count integer +--[[ +WIPDOC +]] +---@field star_color core.ColorSpec +--[[ +WIPDOC +]] +---@field scale number + +-- ---------------------------- PlayerRef methods --------------------------- -- + +---@class core.PlayerRef +local PlayerRef + + +--[[ +* `set_stars(star_parameters)`: + * Passing no arguments resets stars to their default values. + * `star_parameters` is a table with the following optional fields: + * `visible`: Boolean for whether the stars are visible. + (default: `true`) + * `day_opacity`: Float for maximum opacity of stars at day. + No effect if `visible` is false. + (default: 0.0; maximum: 1.0; minimum: 0.0) + * `count`: Integer number to set the number of stars in + the skybox. Only applies to `"skybox"` and `"regular"` sky types. + (default: `1000`) + * `star_color`: ColorSpec, sets the colors of the stars, + alpha channel is used to set overall star brightness. + (default: `#ebebff69`) + * `scale`: Float controlling the overall size of the stars (default: `1`) +]] +---@param star_parameters core.PlayerStarParameters.set +function PlayerRef:set_stars(star_parameters) end + +--[[ +* `get_stars()`: returns a table with the current stars parameters as in + `set_stars`. +]] +---@nodiscard +---@return core.PlayerStarParameters.get star_parameters +function PlayerRef:get_stars() end \ No newline at end of file diff --git a/types/luanti_lsp_definitions/library/classes/ObjectRef/player_sun.lua b/types/luanti_lsp_definitions/library/classes/ObjectRef/player_sun.lua new file mode 100644 index 00000000..71d1acb5 --- /dev/null +++ b/types/luanti_lsp_definitions/library/classes/ObjectRef/player_sun.lua @@ -0,0 +1,82 @@ +---@meta _ +-- DRAFT 1 DONE +-- luanti/doc/lua_api.md: Class reference > `ObjectRef` + +-- --------------------------- PlayerSunParameters -------------------------- -- + +--[[ +WIPDOC +]] +---@class core.PlayerSunParameters.set +--[[ +WIPDOC +]] +---@field visible boolean? +--[[ +WIPDOC +]] +---@field texture core.Texture? +--[[ +WIPDOC +]] +---@field tonemap core.Texture? +--[[ +WIPDOC +]] +---@field sunrise core.Texture? +--[[ +WIPDOC +]] +---@field sunrise_visible boolean? +--[[ +WIPDOC +]] +---@field scale number? + +--[[ +WIPDOC +]] +---@class core.PlayerSunParameters.get +--[[ +WIPDOC +]] +---@field visible boolean +--[[ +WIPDOC +]] +---@field texture core.Texture +--[[ +WIPDOC +]] +---@field tonemap core.Texture +--[[ +WIPDOC +]] +---@field sunrise core.Texture +--[[ +WIPDOC +]] +---@field sunrise_visible boolean +--[[ +WIPDOC +]] +---@field scale number + +-- ---------------------------- PlayerRef methods --------------------------- -- + +---@class core.PlayerRef +local PlayerRef + +--[[ +WIPDOC +]] +---@param sun_parameters core.PlayerSunParameters.set +function PlayerRef:set_sun(sun_parameters) end + +--[[ +* `get_sun()`: returns a table with the current sun parameters as in + `set_sun`. +]] +---@nodiscard +---@return core.PlayerSunParameters.get sun_parameters +function PlayerRef:get_sun() end \ No newline at end of file diff --git a/types/luanti_lsp_definitions/library/classes/PcgRandom.lua b/types/luanti_lsp_definitions/library/classes/PcgRandom.lua new file mode 100644 index 00000000..85f694b6 --- /dev/null +++ b/types/luanti_lsp_definitions/library/classes/PcgRandom.lua @@ -0,0 +1,66 @@ +---@meta _ +-- DRAFT 1 DONE +-- luanti/doc/lua_api.md: Class reference > `PcgRandom` + +-- ------------------------------- constructor ------------------------------ -- + +--[[ +WIPDOC +]] +---@nodiscard +---@param seed integer +---@param seq integer[]? +---@return core.PcgRandom +function PcgRandom(seed, seq) end + +-- -------------------------------- PcgRandom ------------------------------- -- + +--[[ +WIPDOC +]] +---@class core.PcgRandom +PcgRandom = {} + +--[[ +* `next()`: return next integer random number [`-2147483648`...`2147483647`] +]] +---@nodiscard +---@return integer +function PcgRandom:next() end + +--[[ +* `next(min, max)`: return next integer random number [`min`...`max`] +]] +---@nodiscard +---@param min integer +---@param max integer +---@return integer +function PcgRandom:next(min, max) end + +--[[ +* `rand_normal_dist(min, max, num_trials=6)`: return normally distributed + random number [`min`...`max`]. + * This is only a rough approximation of a normal distribution with: + * `mean = (max - min) / 2`, and + * `variance = (((max - min + 1) ^ 2) - 1) / (12 * num_trials)` + * Increasing `num_trials` improves accuracy of the approximation +]] +---@nodiscard +---@param min integer +---@param max integer +---@param num_trials integer? +---@return integer +function PcgRandom:rand_normal_dist(min, max, num_trials) end + +--[[ +* `get_state()`: return generator state encoded in string +]] +---@nodiscard +---@return string state +function PcgRandom:get_state() end + +--[[ +* `set_state(state_string)`: restore generator state from encoded string +]] +---@param state string +function PcgRandom:set_state(state) end diff --git a/types/luanti_lsp_definitions/library/classes/PlayerMetaRef.lua b/types/luanti_lsp_definitions/library/classes/PlayerMetaRef.lua new file mode 100644 index 00000000..a22807ac --- /dev/null +++ b/types/luanti_lsp_definitions/library/classes/PlayerMetaRef.lua @@ -0,0 +1,100 @@ +---@meta _ +-- DRAFT 1 DONE +-- luanti/doc/lua_api.md: Class reference > `PlayerMetaRef` + +-- NOTE: changes are linked to MetaDataRef, ItemStackMetaRef, NodeMetaRef, +-- PlayerMetaRef and StorageRef + +--[[ +WIPDOC +]] +---@class core.PlayerMetaRef: core.MetaDataRef +local PlayerMetaRef = {} + +--[[ +* `contains(key)`: Returns true if key present, otherwise false. + * Returns `nil` when the MetaData is inexistent. +]] +---@nodiscard +---@param key core.MetadataTable.fields.player.keys +---@return boolean? +function PlayerMetaRef:contains(key) end + +--[[ +* `get(key)`: Returns `nil` if key not present, else the stored string. +]] +---@nodiscard +---@param key core.MetadataTable.fields.player.keys +---@return string? value +function PlayerMetaRef:get(key) end + +--[[ +* `set_string(key, value)`: Value of `""` will delete the key. +]] +---@param key core.MetadataTable.fields.player.keys +---@param value string +function PlayerMetaRef:set_string(key, value) end + +--[[ +* `get_string(key)`: Returns `""` if key not present. +]] +---@nodiscard +---@param key core.MetadataTable.fields.player.keys +---@return string value +function PlayerMetaRef:get_string(key) end + +--[[ +* `set_int(key, value)` + * The range for the value is system-dependent (usually 32 bits). + The value will be converted into a string when stored. +]] +---@param key core.MetadataTable.fields.player.keys.integer +---@param value integer +function PlayerMetaRef:set_int(key, value) end + +--[[ +* `get_int(key)`: Returns `0` if key not present. +]] +---@nodiscard +---@param key core.MetadataTable.fields.player.keys.integer +---@return integer value +function PlayerMetaRef:get_int(key) end + +--[[ +* `set_float(key, value)` + * Store a number (a 64-bit float) exactly. + * The value will be converted into a string when stored. +]] +---@param key core.MetadataTable.fields.player.keys.number +---@param value number +function PlayerMetaRef:set_float(key, value) end + +--[[ +WIPDOC +]] +---@nodiscard +---@param key core.MetadataTable.fields.player.keys.number +---@return number value +function PlayerMetaRef:get_float(key) end + +--[[ +WIPDOC +]] +---@nodiscard +---@return core.MetadataTable.fields.player.keys[] keys +function PlayerMetaRef:get_keys() end + +--[[ +WIPDOC +]] +---@nodiscard +---@param data core.MetadataTable.player +---@return boolean? +function PlayerMetaRef:from_table(data) end + +--[[ +WIPDOC +]] +---@nodiscard +---@return core.MetadataTable.player +function PlayerMetaRef:to_table() end diff --git a/types/luanti_lsp_definitions/library/classes/PseudoRandom.lua b/types/luanti_lsp_definitions/library/classes/PseudoRandom.lua new file mode 100644 index 00000000..c5cbbe1b --- /dev/null +++ b/types/luanti_lsp_definitions/library/classes/PseudoRandom.lua @@ -0,0 +1,59 @@ +---@meta _ +-- DRAFT 1 DONE +-- luanti/doc/lua_api.md: Class reference > `PseudoRandom` + +-- ------------------------------- constructor ------------------------------ -- + +--[[ +WIPDOC +]] +---@nodiscard +---@param seed integer +---@return core.PseudoRandom +function PseudoRandom(seed) end + +-- ------------------------------ PseudoRandom ------------------------------ -- + +--[[ +`PseudoRandom` +-------------- + +A 16-bit pseudorandom number generator. +Uses a well-known LCG algorithm introduced by K&R. + +**Note**: +`PseudoRandom` is slower and has worse random distribution than `PcgRandom`. +Use `PseudoRandom` only if you need output to match the well-known LCG algorithm introduced by K&R. +Otherwise, use `PcgRandom`. + +* constructor `PseudoRandom(seed)` + * `seed`: 32-bit signed number +]] +---@class core.PseudoRandom +local PseudoRandom = {} + +--[[ +* `next()`: return next integer random number [`0`...`32767`] +]] +---@nodiscard +---@return integer +function PseudoRandom:next() end + +--[[ +* `next(min, max)`: return next integer random number [`min`...`max`] + * Either `max - min == 32767` or `max - min <= 6553` must be true + due to the simple implementation making a bad distribution otherwise. +]] +---@nodiscard +---@param min integer +---@param max integer +---@return integer +function PseudoRandom:next(min, max) end + +--[[ +* `get_state()`: return state of pseudorandom generator as number + * use returned number as seed in PseudoRandom constructor to restore +]] +---@nodiscard +---@return integer +function PseudoRandom:get_state() end \ No newline at end of file diff --git a/types/luanti_lsp_definitions/library/classes/Raycast.lua b/types/luanti_lsp_definitions/library/classes/Raycast.lua new file mode 100644 index 00000000..a23af7b0 --- /dev/null +++ b/types/luanti_lsp_definitions/library/classes/Raycast.lua @@ -0,0 +1,177 @@ +---@meta _ +-- DRAFT 1 DONE +-- luanti/doc/lua_api.md: Representations of simple things +-- luanti/doc/lua_api.md: 'core' namespace reference > Environment access +-- luanti/doc/lua_api.md: Class reference > `Raycast` + +-- ------------------------------- constructor ------------------------------ -- + +--[[ +* `core.raycast(pos1, pos2, objects, liquids, pointabilities)`: returns `Raycast` + * Creates a `Raycast` object. + * `pos1`: start of the ray + * `pos2`: end of the ray + * `objects`: if false, only nodes will be returned. Default is `true`. + * `liquids`: if false, liquid nodes (`liquidtype ~= "none"`) won't be + returned. Default is `false`. + * `pointabilities`: Allows overriding the `pointable` property of + nodes and objects. Uses the same format as the `pointabilities` property + of item definitions. Default is `nil`. +]] +---@nodiscard +---@param pos1 vector +---@param pos2 vector +---@param objects false +---@param liquids boolean? +---@param pointabilities core.ItemDef.pointabilities? +---@return core.Raycast.nodes +function Raycast(pos1, pos2, objects, liquids, pointabilities) end + +--[[ +* `core.raycast(pos1, pos2, objects, liquids, pointabilities)`: returns `Raycast` + * Creates a `Raycast` object. + * `pos1`: start of the ray + * `pos2`: end of the ray + * `objects`: if false, only nodes will be returned. Default is `true`. + * `liquids`: if false, liquid nodes (`liquidtype ~= "none"`) won't be + returned. Default is `false`. + * `pointabilities`: Allows overriding the `pointable` property of + nodes and objects. Uses the same format as the `pointabilities` property + of item definitions. Default is `nil`. +]] +---@nodiscard +---@param pos1 vector +---@param pos2 vector +---@param objects true? +---@param liquids false? +---@param pointabilities core.ItemDef.pointabilities? +---@return core.Raycast.objects +function Raycast(pos1, pos2, objects, liquids, pointabilities) end + +--[[ +* `core.raycast(pos1, pos2, objects, liquids, pointabilities)`: returns `Raycast` + * Creates a `Raycast` object. + * `pos1`: start of the ray + * `pos2`: end of the ray + * `objects`: if false, only nodes will be returned. Default is `true`. + * `liquids`: if false, liquid nodes (`liquidtype ~= "none"`) won't be + returned. Default is `false`. + * `pointabilities`: Allows overriding the `pointable` property of + nodes and objects. Uses the same format as the `pointabilities` property + of item definitions. Default is `nil`. +]] +---@nodiscard +---@param pos1 vector +---@param pos2 vector +---@param objects true? +---@param liquids true +---@param pointabilities core.ItemDef.pointabilities? +---@return core.Raycast.all +function Raycast(pos1, pos2, objects, liquids, pointabilities) end + +--[[ +* `core.raycast(pos1, pos2, objects, liquids, pointabilities)`: returns `Raycast` + * Creates a `Raycast` object. + * `pos1`: start of the ray + * `pos2`: end of the ray + * `objects`: if false, only nodes will be returned. Default is `true`. + * `liquids`: if false, liquid nodes (`liquidtype ~= "none"`) won't be + returned. Default is `false`. + * `pointabilities`: Allows overriding the `pointable` property of + nodes and objects. Uses the same format as the `pointabilities` property + of item definitions. Default is `nil`. +]] +---@nodiscard +---@param pos1 vector +---@param pos2 vector +---@param objects false +---@param liquids boolean? +---@param pointabilities core.ItemDef.pointabilities? +---@return core.Raycast.nodes +function core.raycast(pos1, pos2, objects, liquids, pointabilities) end + +--[[ +* `core.raycast(pos1, pos2, objects, liquids, pointabilities)`: returns `Raycast` + * Creates a `Raycast` object. + * `pos1`: start of the ray + * `pos2`: end of the ray + * `objects`: if false, only nodes will be returned. Default is `true`. + * `liquids`: if false, liquid nodes (`liquidtype ~= "none"`) won't be + returned. Default is `false`. + * `pointabilities`: Allows overriding the `pointable` property of + nodes and objects. Uses the same format as the `pointabilities` property + of item definitions. Default is `nil`. +]] +---@nodiscard +---@param pos1 vector +---@param pos2 vector +---@param objects true? +---@param liquids false? +---@param pointabilities core.ItemDef.pointabilities? +---@return core.Raycast.objects +function core.raycast(pos1, pos2, objects, liquids, pointabilities) end + +--[[ +* `core.raycast(pos1, pos2, objects, liquids, pointabilities)`: returns `Raycast` + * Creates a `Raycast` object. + * `pos1`: start of the ray + * `pos2`: end of the ray + * `objects`: if false, only nodes will be returned. Default is `true`. + * `liquids`: if false, liquid nodes (`liquidtype ~= "none"`) won't be + returned. Default is `false`. + * `pointabilities`: Allows overriding the `pointable` property of + nodes and objects. Uses the same format as the `pointabilities` property + of item definitions. Default is `nil`. +]] +---@nodiscard +---@param pos1 vector +---@param pos2 vector +---@param objects true? +---@param liquids true +---@param pointabilities core.ItemDef.pointabilities? +---@return core.Raycast.all +function core.raycast(pos1, pos2, objects, liquids, pointabilities) end + +-- --------------------------------- Raycast -------------------------------- -- + +--[[ +WIPDOC +]] +---@class core.Raycast.nodes +---@operator call(): core.PointedThing.raycast.node +local RaycastNodes = {} + +--[[ +WIPDOC +]] +---@nodiscard +---@return core.PointedThing.raycast.node? +function RaycastNodes:next() end + +--[[ +WIPDOC +]] +---@class core.Raycast.objects +---@operator call(): core.PointedThing.raycast.object +local RaycastObjects = {} + +--[[ +WIPDOC +]] +---@nodiscard +---@return core.PointedThing.raycast.object? +function RaycastObjects:next() end + +--[[ +WIPDOC +]] +---@class core.Raycast.all +---@operator call(): core.PointedThing.raycast.all +local RaycastAll = {} + +--[[ +WIPDOC +]] +---@nodiscard +---@return core.PointedThing.raycast.all? +function RaycastAll:next() end \ No newline at end of file diff --git a/types/luanti_lsp_definitions/library/classes/SecureRandom.lua b/types/luanti_lsp_definitions/library/classes/SecureRandom.lua new file mode 100644 index 00000000..18acf5b7 --- /dev/null +++ b/types/luanti_lsp_definitions/library/classes/SecureRandom.lua @@ -0,0 +1,40 @@ +---@meta _ +-- DRAFT 1 DONE +-- luanti/doc/lua_api.md: Class reference > `SecureRandom` + +-- ------------------------------- constructor ------------------------------ -- + +--[[ +WIPDOC +]] +---@nodiscard +---@return core.SecureRandom +function SecureRandom() end + +-- ------------------------------ SecureRandom ------------------------------ -- + +--[[ +`SecureRandom` +-------------- + +Interface for the operating system's crypto-secure PRNG. + +It can be created via `SecureRandom()`. The constructor throws an error if a +secure random device cannot be found on the system. + +### Methods + +* `next_bytes([count])`: return next `count` (default 1, capped at 2048) many + random bytes, as a string. +]] +---@class core.SecureRandom +SecureRandom = {} + +--[[ +* `next_bytes([count])`: return next `count` (default 1, capped at 2048) many + random bytes, as a string. +]] +---@nodiscard +---@param count integer +---@return string +function SecureRandom:next_bytes(count) end diff --git a/types/luanti_lsp_definitions/library/classes/Settings/LuantiSettings/LuantiSettings.lua b/types/luanti_lsp_definitions/library/classes/Settings/LuantiSettings/LuantiSettings.lua new file mode 100644 index 00000000..2928771c --- /dev/null +++ b/types/luanti_lsp_definitions/library/classes/Settings/LuantiSettings/LuantiSettings.lua @@ -0,0 +1,266 @@ +---@meta _ +-- DRAFT 1 DONE +-- luanti/doc/lua_api.md: Class reference > `Settings` +-- builtin/settingtypes.txt +-- minetest.conf.example + +--[[ +WIPDOC +]] +---@type core.LuantiSettings +core.settings = nil + +--[[ +NOTE: types in a .conf settings file +- int -> integer +- string -> string +- bool -> boolean +- float -> number +- enum -> string +- path -> string +- filepath -> string +- key -> string +- flags -> flag table +- noise_params_2d -> noiseparams +- noise_params_3d -> noiseparams +- v3f -> vec +]] + +--[[ +WIPDOC +]] +---@class core.LuantiSettings.flags : string + +--[[ +WIPDOC +]] +---@alias core.LuantiSettings.path string + +-- --------------------------- LuantiSettings.keys -------------------------- -- + +--[[ +WIPDOC +]] +---@alias core.LuantiSettings.keys.boolean +--- | _.LuantiSettings.advanced.keys.boolean +--- | _.LuantiSettings.client_and_server.keys.boolean +--- | string + +--[[ +WIPDOC +]] +---@alias core.LuantiSettings.keys.noise_params.2d +--- | _.LuantiSettings.mapgen.keys.noise_params.2d +--- | string + +--[[ +WIPDOC +]] +---@alias core.LuantiSettings.keys.noise_params.3d +--- | _.LuantiSettings.mapgen.keys.noise_params.3d +--- | string + +--[[ +WIPDOC +]] +---@alias core.LuantiSettings.keys.vector +--- | _.LuantiSettings.mapgen.keys.vector +--- | string + +--[[ +WIPDOC +]] +---@alias core.LuantiSettings.keys +--- | _.LuantiSettings.advanced.keys +--- | _.LuantiSettings.client_and_server.keys +--- | _.LuantiSettings.mapgen.keys +--- | string + +-- ------------------------- LuantiSettings.tablefmt ------------------------ -- + +--[[ +WIPDOC +]] +---@class core.LuantiSettings.tablefmt : _.LuantiSettings.advanced.tablefmt, _.LuantiSettings.client_and_server.tablefmt, _.LuantiSettings.mapgen.tablefmt + +-- ----------------------------- LuantiSettings ----------------------------- -- + +--[[ +### Format + +The settings have the format `key = value`. Example: + + foo = example text + bar = """ + Multiline + value + """ +]] +---@class core.LuantiSettings +local LuantiSettings = {} + +--[[ LuantiSettings:get() split off into ./settings_enums.lua ]]-- + +--[[ +* `get(key)`: returns a value + * Returns `nil` if `key` is not found. +]] +---@nodiscard +---@param key core.LuantiSettings.keys +---@return string? value +function LuantiSettings:get(key) end + +--[[ +* `get_bool(key, [default])`: returns a boolean + * `default` is the value returned if `key` is not found. + * Returns `nil` if `key` is not found and `default` not specified. +]] +---@nodiscard +---@param key core.LuantiSettings.keys.boolean +---@return boolean? value +function LuantiSettings:get_bool(key) end + +--[[ +* `get_bool(key, [default])`: returns a boolean + * `default` is the value returned if `key` is not found. + * Returns `nil` if `key` is not found and `default` not specified. +]] +---@nodiscard +---@generic T +---@param key core.LuantiSettings.keys.boolean +---@param default T +---@return boolean|T value +function LuantiSettings:get_bool(key, default) end + +--[[ +* `get_np_group(key)`: returns a NoiseParams table + * Returns `nil` if `key` is not found. +]] +---@nodiscard +---@param key core.LuantiSettings.keys.noise_params.2d +---@return core.NoiseParams.2d? value +function LuantiSettings:get_np_group(key) end + +--[[ +* `get_np_group(key)`: returns a NoiseParams table + * Returns `nil` if `key` is not found. +]] +---@nodiscard +---@param key core.LuantiSettings.keys.noise_params.3d +---@return core.NoiseParams.3d? value +function LuantiSettings:get_np_group(key) end + +--[[ LuantiSettings:get_flags() split off into ./settings_flags.lua ]]-- + +--[[ +* `get_flags(key)`: + * Returns `{flag = true/false, ...}` according to the set flags. + * Is currently limited to mapgen flags `mg_flags` and mapgen-specific + flags like `mgv5_spflags`. + * Returns `nil` if `key` is not found. +]] +---@nodiscard +---@param key string +---@return table? value +function LuantiSettings:get_flags(key) end + +--[[ +* `get_pos(key)`: + * Returns a `vector` + * Returns `nil` if no value is found or parsing failed. +]] +---@nodiscard +---@param key core.LuantiSettings.keys.vector +---@return vec? value +function LuantiSettings:get_pos(key) end + +--[[ LuantiSettings:set() split off into ./settings_enums.lua ]]-- + +--[[ +* `set(key, value)` + * Setting names can't contain whitespace or any of `="{}#`. + * Setting values can't contain the sequence `\n"""`. + * Setting names starting with "secure." can't be set on the main settings + object (`core.settings`). +]] +---@param key core.LuantiSettings.keys +---@param value string +function LuantiSettings:set(key, value) end + +--[[ +* `set_bool(key, value)` + * See documentation for `set()` above. +]] +---@param key core.LuantiSettings.keys.boolean +---@param value boolean +function LuantiSettings:set_bool(key, value) end + +--[[ +* `set_np_group(key, value)` + * `value` is a NoiseParams table. + * Also, see documentation for `set()` above. +]] +---@param key core.LuantiSettings.keys.noise_params.2d +---@param value core.NoiseParams.2d +function LuantiSettings:set_np_group(key, value) end + +--[[ +* `set_np_group(key, value)` + * `value` is a NoiseParams table. + * Also, see documentation for `set()` above. +]] +---@param key core.LuantiSettings.keys.noise_params.3d +---@param value core.NoiseParams.3d +function LuantiSettings:set_np_group(key, value) end + +--[[ +* `set_pos(key, value)` + * `value` is a `vector`. + * Also, see documentation for `set()` above. +]] +---@param key core.LuantiSettings.keys.vector +---@param value vector +function LuantiSettings:set_pos(key, value) end + +--[[ +* `remove(key)`: returns a boolean (`true`) for success +]] +---@nodiscard +---@param key core.LuantiSettings.keys +---@return boolean +function LuantiSettings:remove(key) end + +--[[ +* `get_names()`: returns `{key1,...}` +]] +---@nodiscard +---@return core.LuantiSettings.keys[] keys +function LuantiSettings:get_names() end + +--[[ +* `has(key)`: + * Returns a boolean indicating whether `key` exists. + * In contrast to the various getter functions, `has()` doesn't consider + any default values. + * This means that on the main settings object (`core.settings`), + `get(key)` might return a value even if `has(key)` returns `false`. +]] +---@nodiscard +---@param key core.LuantiSettings.keys +---@return boolean +function LuantiSettings:has(key) end + +--[[ +* `write()`: returns a boolean (`true` for success + * Writes changes to file. +]] +---@nodiscard +---@return boolean +function LuantiSettings:write() end + +--[[ +* `to_table()`: returns `{[key1]=value1,...}` +]] +---@nodiscard +---@return core.LuantiSettings.tablefmt +function LuantiSettings:to_table() end diff --git a/types/luanti_lsp_definitions/library/classes/Settings/LuantiSettings/advanced.lua b/types/luanti_lsp_definitions/library/classes/Settings/LuantiSettings/advanced.lua new file mode 100644 index 00000000..91d0a54b --- /dev/null +++ b/types/luanti_lsp_definitions/library/classes/Settings/LuantiSettings/advanced.lua @@ -0,0 +1,1398 @@ +---@meta _ +-- DRAFT 1 DONE +-- builtin/settingtypes.txt +-- minetest.conf.example + +-- NOTE: because there's so much contexts used, it must be specified via ctx_* +-- Section context mapping: +-- * [Advanced] [*Developer options] [**Mod Security]: [server] +-- * [Advanced] [*Developer options] [**Mod Profiler]: [server] +-- * [Advanced] [*Developer options] [**Engine Profiler]: [common] +-- * [Advanced] [*Advanced] [**Graphics]: [client] +-- * [Advanced] [*Advanced] [**Sound]: [client] +-- * [Advanced] [*Advanced] [**Font]: [client] +-- * [Advanced] [*Advanced] [**Lighting]: [client] +-- * [Advanced] [*Advanced] [**Server]: [server] +-- * [Advanced] [*Advanced] [**Server/Env Performance]: [server] +-- * [Advanced] [*Advanced] [**Mapgen]: [server] +-- * [Advanced] [*Advanced] [**cURL]: [common] +-- * [Advanced] [*Advanced] [**Client Debugging]: [client] +-- * [Advanced] [*Gamepads]: [client] +-- * [Advanced] [*Hide: Temporary Settings]: [common] + +---@alias _.LuantiSettings.advanced.keys.boolean +--- | "secure.enable_security" +--- | "random_mod_load_order" +--- | "enable_mod_channels" +--- | "profiler.load" +--- | "instrument.entity" +--- | "instrument.abm" +--- | "instrument.lbm" +--- | "instrument.chatcommand" +--- | "instrument.global_callback" +--- | "instrument.builtin" +--- | "instrument.profiler" +--- | "enable_ipv6" +--- | "ask_reconnect_on_crash" +--- | "unlimited_player_transfer_distance" +--- | "server_side_occlusion_culling" +--- | "enable_mapgen_debug_info" +--- | "enable_console" +--- | "ignore_world_load_errors" +--- | "enable_remote_media_server" +--- | "enable_minimap" +--- | "minimap_shape_round" +--- | "enable_damage" +--- | "creative_mode" +--- | "enable_pvp" +--- | "free_move" +--- | "pitch_move" +--- | "fast_move" +--- | "noclip" +--- | "continuous_forward" +--- | "cinematic" +--- | "show_technical_names" +--- | "show_advanced" + +---@alias _.LuantiSettings.advanced.keys +--- | "secure.enable_security" +--- | "secure.trusted_mods" +--- | "secure.http_mods" +--- | "debug_log_level" +--- | "debug_log_size_max" +--- | "deprecated_lua_api_handling" +--- | "random_mod_load_order" +--- | "enable_mod_channels" +--- | "profiler.load" +--- | "profiler.default_report_format" +--- | "profiler.report_path" +--- | "instrument.entity" +--- | "instrument.abm" +--- | "instrument.lbm" +--- | "instrument.chatcommand" +--- | "instrument.global_callback" +--- | "instrument.builtin" +--- | "instrument.profiler" +--- | "profiler_print_interval" +--- | "enable_ipv6" +--- | "max_packets_per_iteration" +--- | "prometheus_listener_address" +--- | "max_simultaneous_block_sends_per_client" +--- | "full_block_send_enable_min_time_from_building" +--- | "map_compression_level_net" +--- | "chat_message_format" +--- | "chatcommand_msg_time_threshold" +--- | "kick_msg_shutdown" +--- | "kick_msg_crash" +--- | "ask_reconnect_on_crash" +--- | "dedicated_server_step" +--- | "unlimited_player_transfer_distance" +--- | "player_transfer_distance" +--- | "active_object_send_range_blocks" +--- | "active_block_range" +--- | "max_block_send_distance" +--- | "max_forceloaded_blocks" +--- | "server_map_save_interval" +--- | "server_unload_unused_data_timeout" +--- | "max_objects_per_block" +--- | "active_block_mgmt_interval" +--- | "abm_interval" +--- | "abm_time_budget" +--- | "nodetimer_interval" +--- | "liquid_loop_max" +--- | "liquid_queue_purge_time" +--- | "liquid_update" +--- | "block_send_optimize_distance" +--- | "server_side_occlusion_culling" +--- | "block_cull_optimize_distance" +--- | "chunksize" +--- | "enable_mapgen_debug_info" +--- | "emergequeue_limit_total" +--- | "emergequeue_limit_diskonly" +--- | "emergequeue_limit_generate" +--- | "num_emerge_threads" +--- | "curl_timeout" +--- | "curl_parallel_limit" +--- | "curl_file_download_timeout" +--- | "enable_console" +--- | "clickable_chat_weblinks" +--- | "display_density_factor" +--- | "ignore_world_load_errors" +--- | "max_clearobjects_extra_loaded_blocks" +--- | "map-dir" +--- | "sqlite_synchronous" +--- | "map_compression_level_disk" +--- | "enable_remote_media_server" +--- | "serverlist_file" +--- | "texture_path" +--- | "enable_minimap" +--- | "minimap_shape_round" +--- | "address" +--- | "remote_port" +--- | "enable_damage" +--- | "creative_mode" +--- | "enable_pvp" +--- | "free_move" +--- | "pitch_move" +--- | "fast_move" +--- | "noclip" +--- | "continuous_forward" +--- | "cinematic" +--- | "show_technical_names" +--- | "show_advanced" + +---@class _.LuantiSettings.advanced.tablefmt : _.LuantiSettings.advanced.developer_options.mod_security.ctx_server, _.LuantiSettings.advanced.developer_options.debugging.ctx_server, _.LuantiSettings.advanced.developer_options.mod_profiler.ctx_server, _.LuantiSettings.advanced.developer_options.engine_profiler.ctx_server, _.LuantiSettings.advanced.advanced.networking.ctx_server, _.LuantiSettings.advanced.advanced.server.ctx_server, _.LuantiSettings.advanced.advanced.server_env_performance.ctx_server, _.LuantiSettings.advanced.advanced.mappgen.ctx_server, _.LuantiSettings.advanced.advanced.cURL.ctx_server, _.LuantiSettings.advanced.advanced.miscellaneous.ctx_server, _.LuantiSettings.advanced.hide_temporary_settings.ctx_server + +-- ------------------------------- [Advanced] ------------------------------- -- + +-- --------------------- [Advanced] [*Developer Options] -------------------- -- + +---@class _.LuantiSettings.advanced.developer_options.ctx_client +--[[ +# Enable Lua modding support on client. +# This support is experimental and API can change. +[client] +(Client modding) false +]] +---@field enable_client_modding boolean? +--[[ +# Replaces the default main menu with a custom one. +[client] +(Main menu script) +]] +---@field main_menu_script string? + +-- ------------ [Advanced] [*Developer Options] [**Mod Security] ------------ -- + +---@class _.LuantiSettings.advanced.developer_options.mod_security.ctx_server +--[[ +# Prevent mods from doing insecure things like running shell commands. +[server] +(Enable mod security) true +]] +---@field ["secure.enable_security"] boolean? +--[[ +# Comma-separated list of trusted mods that are allowed to access insecure +# functions even when mod security is on (via request_insecure_environment()). +[server] +(Trusted mods) +]] +---@field ["secure.trusted_mods"] string? +--[[ +# Comma-separated list of mods that are allowed to access HTTP APIs, which +# allow them to upload and download data to/from the internet. +[server] +(HTTP mods) +]] +---@field ["secure.http_mods"] string? + +-- -------------- [Advanced] [*Developer Options] [**Debugging] ------------- -- + +--[[ +WIPDOC +]] +---@alias core.LuantiSettings.enums.debug_log_level +--- | "" +--- | "none" +--- | "error" +--- | "warning" +--- | "action" +--- | "info" +--- | "verbose" +--- | "trace" + +--[[ +WIPDOC +]] +---@alias core.LuantiSettings.enums.deprecated_lua_api_handling +--- | "none" +--- | "log" +--- | "error" + +---@class _.LuantiSettings.advanced.developer_options.debugging.ctx_common +--[[ +# Level of logging to be written to debug.txt: +# - (no logging) +# - none (messages with no level) +# - error +# - warning +# - action +# - info +# - verbose +# - trace +[common] +(Debug log level) action ,none,error,warning,action,info,verbose,trace +]] +---@field debug_log_level core.LuantiSettings.enums.debug_log_level? +--[[ +# If the file size of debug.txt exceeds the number of megabytes specified in +# this setting when it is opened, the file is moved to debug.txt.1, +# deleting an older debug.txt.1 if it exists. +# debug.txt is only moved if this setting is positive. +[common] +(Debug log file size threshold) 50 1 +]] +---@field debug_log_size_max integer? +--[[ +# Handling for deprecated Lua API calls: +# - none: Do not log deprecated calls +# - log: mimic and log backtrace of deprecated call (default). +# - error: abort on usage of deprecated call (suggested for mod developers). +[common] +(Deprecated Lua API handling) log none,log,error +]] +---@field deprecated_lua_api_handling core.LuantiSettings.enums.deprecated_lua_api_handling? + +--[[ +WIPDOC +]] +---@alias core.LuantiSettings.enums.chat_log_level +--- | "" +--- | "none" +--- | "error" +--- | "warning" +--- | "action" +--- | "info" +--- | "verbose" +--- | "trace" + +---@class _.LuantiSettings.advanced.developer_options.debugging.ctx_client : _.LuantiSettings.advanced.developer_options.debugging.ctx_common +--[[ +# Minimal level of logging to be written to chat. +[client] +(Chat log level) error ,none,error,warning,action,info,verbose,trace +]] +---@field chat_log_level core.LuantiSettings.enums.chat_log_level? +--[[ +# Enable random user input (only used for testing). +[client] +(Random input) false +]] +---@field random_input boolean? + + +---@class _.LuantiSettings.advanced.developer_options.debugging.ctx_server : _.LuantiSettings.advanced.developer_options.debugging.ctx_common +--[[ +# Enable random mod loading (mainly used for testing). +[server] +(Random mod load order) false +]] +---@field random_mod_load_order boolean? +--[[ +# Enable mod channels support. +[server] +(Mod channels) false +]] +---@field enable_mod_channels boolean? + +-- ------------ [Advanced] [*Developer Options] [**Mod Profiler] ------------ -- + +--[[ +WIPDOC +]] +---@alias core.LuantiSettings.enums.profiler.default_report_format +--- | "txt" +--- | "csv" +--- | "lua" +--- | "json" +--- | "json_pretty" + +---@class _.LuantiSettings.advanced.developer_options.mod_profiler.ctx_server +--[[ +# Load the game profiler to collect game profiling data. +# Provides a /profiler command to access the compiled profile. +# Useful for mod developers and server operators. +[server] +(Load the game profiler) false +]] +---@field ["profiler.load"] boolean? +--[[ +# The default format in which profiles are being saved, +# when calling `/profiler save [format]` without format. +[server] +(Default report format) txt txt,csv,lua,json,json_pretty +]] +---@field ["profiler.default_report_format"] core.LuantiSettings.enums.profiler.default_report_format? +--[[ +# The file path relative to your world path in which profiles will be saved to. +[server] +(Report path) +]] +---@field ["profiler.report_path"] string? +--[[ +# Instrument the methods of entities on registration. +[server] +(Entity methods) true +]] +---@field ["instrument.entity"] boolean? +--[[ +# Instrument the action function of Active Block Modifiers on registration. +[server] +(Active Block Modifiers) true +]] +---@field ["instrument.abm"] boolean? +--[[ +# Instrument the action function of Loading Block Modifiers on registration. +[server] +(Loading Block Modifiers) true +]] +---@field ["instrument.lbm"] boolean? +--[[ +# Instrument chat commands on registration. +[server] +(Chat commands) true +]] +---@field ["instrument.chatcommand"] boolean? +--[[ +# Instrument global callback functions on registration. +# (anything you pass to a core.register_*() function) +[server] +(Global callbacks) true +]] +---@field ["instrument.global_callback"] boolean? +--[[ +# Instrument builtin. +# This is usually only needed by core/builtin contributors +[server] +(Builtin) false +]] +---@field ["instrument.builtin"] boolean? +--[[ +# Have the profiler instrument itself: +# * Instrument an empty function. +# This estimates the overhead, that instrumentation is adding (+1 function call). +# * Instrument the sampler being used to update the statistics. +[server] +(Profiler) false +]] +---@field ["instrument.profiler"] boolean? + +-- ----------- [Advanced] [*Developer Options] [**Engine Profiler] ---------- -- + +---@class _.LuantiSettings.advanced.developer_options.engine_profiler.ctx_common +--[[ +# Print the engine's profiling data in regular intervals (in seconds). +# 0 = disable. Useful for developers. +[common] +(Engine profiling data print interval) 0 0 +]] +---@field profiler_print_interval integer? + +---@class _.LuantiSettings.advanced.developer_options.engine_profiler.ctx_client : _.LuantiSettings.advanced.developer_options.engine_profiler.ctx_common + +---@class _.LuantiSettings.advanced.developer_options.engine_profiler.ctx_server : _.LuantiSettings.advanced.developer_options.engine_profiler.ctx_common + +-- ------------------------- [Advanced] [*Advanced] ------------------------- -- + +-- ------------------- [Advanced] [*Advanced] [**Graphics] ------------------ -- + +--[[ +WIPDOC +]] +---@alias core.LuantiSettings.enums.video_driver +--- | "" +--- | "opengl" +--- | "opengl3" +--- | "ogles2" + +---@class _.LuantiSettings.advanced.advanced.graphics.ctx_client +--[[ +# Enables debug and error-checking in the OpenGL driver. +[client] +(OpenGL debug) false +]] +---@field opengl_debug boolean? +--[[ +# Path to shader directory. If no path is defined, default location will be used. +[client] +(Shader path) +]] +---@field shader_path core.LuantiSettings.path? +--[[ +# The rendering back-end. +# Note: A restart is required after changing this! +# OpenGL is the default for desktop, and OGLES2 for Android. +[client] +(Video driver) ,opengl,opengl3,ogles2 +]] +---@field video_driver core.LuantiSettings.enums.video_driver? +--[[ +# Distance in nodes at which transparency depth sorting is enabled. +# Use this to limit the performance impact of transparency depth sorting. +# Set to 0 to disable it entirely. +[client] +(Transparency Sorting Distance) 16 0 128 +]] +---@field transparency_sorting_distance integer? +--[[ +# Draw transparency sorted triangles grouped by their mesh buffers. +# This breaks transparency sorting between mesh buffers, but avoids situations +# where transparency sorting would be very slow otherwise. +[client] +(Transparency Sorting Group by Buffers) true +]] +---@field transparency_sorting_group_by_buffers boolean? +--[[ +# Radius of cloud area stated in number of 64 node cloud squares. +# Values larger than 26 will start to produce sharp cutoffs at cloud area corners. +[client] +(Cloud radius) 12 8 62 +]] +---@field cloud_radius integer? +--[[ +# Delay between mesh updates on the client in ms. Increasing this will slow +# down the rate of mesh updates, which can help reduce jitter. +[client] +(Mapblock mesh generation delay) 0 0 25 +]] +---@field mesh_generation_interval integer? +--[[ +# Number of threads to use for mesh generation. +# Value of 0 (default) will let Luanti automatically choose the number of threads. +[client] +(Mapblock mesh generation threads) 0 0 8 +]] +---@field mesh_generation_threads integer? +--[[ +# All mesh buffers with less than this number of vertices will be merged +# during map rendering. This improves rendering performance. +[client] +(Minimum vertex count for mesh buffers) 300 0 1000 +]] +---@field mesh_buffer_min_vertices integer? +--[[ +# True = 256 +# False = 128 +# Usable to make minimap smoother on slower machines. +[client] +(Minimap scan height) true +]] +---@field minimap_double_scan_height boolean? + +--[[ +WIPDOC +]] +---@alias core.LuantiSettings.enums.world_aligned_mode +--- | "disable" +--- | "enable" +--- | "force_solid" +--- | "force_nodebox" + +---@class _.LuantiSettings.advanced.advanced.graphics.ctx_client +--[[ +# Textures on a node may be aligned either to the node or to the world. +# The former mode suits better things like machines, furniture, etc., while +# the latter makes stairs and microblocks fit surroundings better. +# However, as this possibility is new, thus may not be used by older servers, +# this option allows enforcing it for certain node types. Note though that +# that is considered EXPERIMENTAL and may not work properly. +[client] +(World-aligned textures mode) enable disable,enable,force_solid,force_nodebox +]] +---@field world_aligned_mode core.LuantiSettings.enums.world_aligned_mode? + +--[[ +WIPDOC +]] +---@alias core.LuantiSettings.enums.autoscale_mode +--- | "disable" +--- | "enable" +--- | "force" + +---@class _.LuantiSettings.advanced.advanced.graphics.ctx_client +--[[ +# World-aligned textures may be scaled to span several nodes. However, +# the server may not send the scale you want, especially if you use +# a specially-designed texture pack; with this option, the client tries +# to determine the scale automatically based on the texture size. +# See also texture_min_size. +# Warning: This option is EXPERIMENTAL! +[client] +(Autoscaling mode) disable disable,enable,force +]] +---@field autoscale_mode core.LuantiSettings.enums.autoscale_mode? +--[[ +# When using bilinear/trilinear filtering, low-resolution textures +# can be blurred, so this option automatically upscales them to preserve +# crisp pixels. This defines the minimum texture size for the upscaled textures; +# higher values look sharper, but require more memory. +# This setting is ONLY applied if any of the mentioned filters are enabled. +# This is also used as the base node texture size for world-aligned +# texture autoscaling. +[client] +(Base texture size) 192 192 16384 +]] +---@field texture_min_size integer? +--[[ +# Side length of a cube of map blocks that the client will consider together +# when generating meshes. +# Larger values increase the utilization of the GPU by reducing the number of +# draw calls, benefiting especially high-end GPUs. +# Systems with a low-end GPU (or no GPU) would benefit from smaller values. +[client] +(Client Mesh Chunksize) 1 1 16 +]] +---@field client_mesh_chunk integer? + +--[[ +WIPDOC +]] +---@alias core.LuantiSettings.enums.post_processing_texture_bits +--- | "8" +--- | "10" +--- | "16" + +---@class _.LuantiSettings.advanced.advanced.graphics.ctx_client +--[[ +# Decide the color depth of the texture used for the post-processing pipeline. +# Reducing this can improve performance, but some effects (e.g. debanding) +# require more than 8 bits to work. +# +# Requires: enable_post_processing +[client] +(Color depth for post-processing texture) 16 8,10,16 +]] +---@field post_processing_texture_bits core.LuantiSettings.enums.post_processing_texture_bits? +--[[ +# Enable Poisson disk filtering. +# On true uses Poisson disk to make "soft shadows". Otherwise uses PCF filtering. +# +# Requires: enable_dynamic_shadows, opengl +[client] +(Poisson filtering) true +]] +---@field shadow_poisson_filter boolean? +--[[ +# Spread a complete update of the shadow map over a given number of frames. +# Higher values might make shadows laggy, lower values +# will consume more resources. +# +# Requires: enable_dynamic_shadows, opengl +[client] +(Map shadows update frames) 16 1 32 +]] +---@field shadow_update_frames integer? +--[[ +# Set to true to render debugging breakdown of the bloom effect. +# In debug mode, the screen is split into 4 quadrants: +# top-left - processed base image, top-right - final image +# bottom-left - raw base image, bottom-right - bloom texture. +# +# Requires: enable_post_processing, enable_bloom +[client] +(Enable Bloom Debug) false +]] +---@field enable_bloom_debug boolean? + +-- -------------------- [Advanced] [*Advanced] [**Sound] -------------------- -- + +---@class _.LuantiSettings.advanced.advanced.sound.ctx_client +--[[ +# Comma-separated list of AL and ALC extensions that should not be used. +# Useful for testing. See al_extensions.[h,cpp] for details. +[client] +(Sound Extensions Blacklist) +]] +---@field sound_extensions_blacklist string? + +-- --------------------- [Advanced] [*Advanced] [**Font] -------------------- -- + +---@class _.LuantiSettings.advanced.advanced.font.ctx_client +--[[ +[client] +(Font bold by default) false +]] +---@field font_bold boolean? +--[[ +[client] +(Font italic by default) false +]] +---@field font_italic boolean? +--[[ +# Shadow offset (in pixels) of the default font. If 0, then shadow will not be drawn. +[client] +(Font shadow) 1 0 65535 +]] +---@field font_shadow integer? +--[[ +# Opaqueness (alpha) of the shadow behind the default font, between 0 and 255. +[client] +(Font shadow alpha) 127 0 255 +]] +---@field font_shadow_alpha integer? +--[[ +# Font size of the default font where 1 unit = 1 pixel at 96 DPI +[client] +(Font size) 16 5 72 +]] +---@field font_size integer? +--[[ +# For pixel-style fonts that do not scale well, this ensures that font sizes used +# with this font will always be divisible by this value, in pixels. For instance, +# a pixel font 16 pixels tall should have this set to 16, so it will only ever be +# sized 16, 32, 48, etc., so a mod requesting a size of 25 will get 32. +[client] +(Font size divisible by) 1 1 +]] +---@field font_size_divisible_by integer? +--[[ +# Path to the default font. Must be a TrueType font. +# The fallback font will be used if the font cannot be loaded. +[client] +(Regular font path) fonts/Arimo-Regular.ttf +]] +---@field font_path core.LuantiSettings.path? +--[[ +# Path to the default bold font. Must be a TrueType font. +# The fallback font will be used if the font cannot be loaded. +[client] +(Bold font path) fonts/Arimo-Bold.ttf +]] +---@field font_path_bold core.LuantiSettings.path? +--[[ +# Path to the default italic font. Must be a TrueType font. +# The fallback font will be used if the font cannot be loaded. +[client] +(Italic font path) fonts/Arimo-Italic.ttf +]] +---@field font_path_italic core.LuantiSettings.path? +--[[ +# Path to the default bold italic font. Must be a TrueType font. +# The fallback font will be used if the font cannot be loaded. +[client] +(Bold and Italic font path) fonts/Arimo-BoldItalic.ttf +]] +---@field font_path_bold_italic core.LuantiSettings.path? +--[[ +# Font size of the monospace font where 1 unit = 1 pixel at 96 DPI +[client] +(Monospace font size) 16 5 72 +]] +---@field mono_font_size integer? +--[[ +# For pixel-style fonts that do not scale well, this ensures that font sizes used +# with this font will always be divisible by this value, in pixels. For instance, +# a pixel font 16 pixels tall should have this set to 16, so it will only ever be +# sized 16, 32, 48, etc., so a mod requesting a size of 25 will get 32. +[client] +(Monospace font size divisible by) 1 1 +]] +---@field mono_font_size_divisible_by integer? +--[[ +# Path to the monospace font. Must be a TrueType font. +# This font is used for e.g. the console and profiler screen. +[client] +(Monospace font path) fonts/Cousine-Regular.ttf +]] +---@field mono_font_path core.LuantiSettings.path? +--[[ +# Path to the bold monospace font. Must be a TrueType font. +# This font is used for e.g. the console and profiler screen. +[client] +(Bold monospace font path) fonts/Cousine-Bold.ttf +]] +---@field mono_font_path_bold core.LuantiSettings.path? +--[[ +# Path to the italic monospace font. Must be a TrueType font. +# This font is used for e.g. the console and profiler screen. +[client] +(Italic monospace font path) fonts/Cousine-Italic.ttf +]] +---@field mono_font_path_italic core.LuantiSettings.path? +--[[ +# Path to the bold italic monospace font. Must be a TrueType font. +# This font is used for e.g. the console and profiler screen. +[client] +(Bold and italic monospace font path) fonts/Cousine-BoldItalic.ttf +]] +---@field mono_font_path_bold_italic core.LuantiSettings.path? +--[[ +# Path of the fallback font. Must be a TrueType font. +# This font will be used for certain languages or if the default font is unavailable. +[client] +(Fallback font path) fonts/DroidSansFallbackFull.ttf +]] +---@field fallback_font_path core.LuantiSettings.path? + +-- ------------------- [Advanced] [*Advanced] [**Lighting] ------------------ -- + +---@class _.LuantiSettings.advanced.advanced.lighting.ctx_client +--[[ +# Gradient of light curve at minimum light level. +# Controls the contrast of the lowest light levels. +[client] +(Light curve low gradient) 0.0 0.0 3.0 +]] +---@field lighting_alpha number? +--[[ +# Gradient of light curve at maximum light level. +# Controls the contrast of the highest light levels. +[client] +(Light curve high gradient) 1.5 0.0 3.0 +]] +---@field lighting_beta number? +--[[ +# Strength of light curve boost. +# The 3 'boost' parameters define a range of the light +# curve that is boosted in brightness. +[client] +(Light curve boost) 0.2 0.0 0.4 +]] +---@field lighting_boost number? +--[[ +# Center of light curve boost range. +# Where 0.0 is minimum light level, 1.0 is maximum light level. +[client] +(Light curve boost center) 0.5 0.0 1.0 +]] +---@field lighting_boost_center number? +--[[ +# Spread of light curve boost range. +# Controls the width of the range to be boosted. +# Standard deviation of the light curve boost Gaussian. +[client] +(Light curve boost spread) 0.2 0.0 0.4 +]] +---@field lighting_boost_spread number? + +-- ------------------ [Advanced] [*Advanced] [**Networking] ----------------- -- + +---@class _.LuantiSettings.advanced.advanced.networking.ctx_common +--[[ +# Enable IPv6 support (for both client and server). +# Required for IPv6 connections to work at all. +[common] +(IPv6) true +]] +---@field enable_ipv6 boolean? +--[[ +# Maximum number of packets sent per send step in the low-level networking code. +# You generally don't need to change this, however busy servers may benefit from a higher number. +[common] +(Max. packets per iteration) 1024 1 65535 +]] +---@field max_packets_per_iteration integer? + +---@class _.LuantiSettings.advanced.advanced.networking.ctx_server : _.LuantiSettings.advanced.advanced.networking.ctx_common +--[[ +# Prometheus listener address. +# If Luanti is compiled with Prometheus support, this setting +# enables the metrics listener for Prometheus on that address. +# By default you can fetch metrics from http://127.0.0.1:30000/metrics. +# An empty value disables the metrics listener. +[server] +(Prometheus listener address) 127.0.0.1:30000 +]] +---@field prometheus_listener_address string? +--[[ +# Maximum number of blocks that are simultaneously sent per client. +# The maximum total count is calculated dynamically: +# max_total = ceil((#clients + max_users) * per_client / 4) +[server] +(Maximum simultaneous block sends per client) 40 1 4294967295 +]] +---@field max_simultaneous_block_sends_per_client integer? +--[[ +# To reduce lag, block transfers are slowed down when a player is building something. +# This determines how long they are slowed down after placing or removing a node. +[server] +(Delay in sending blocks after building) 2.0 0.0 +]] +---@field full_block_send_enable_min_time_from_building number? +--[[ +# Compression level to use when sending mapblocks to the client. +# -1 - use default compression level +# 0 - least compression, fastest +# 9 - best compression, slowest +[server] +(Map Compression Level for Network Transfer) -1 -1 9 +]] +---@field map_compression_level_net integer? + +---@class _.LuantiSettings.advanced.advanced.networking.ctx_client : _.LuantiSettings.advanced.advanced.networking.ctx_common +--[[ +# Maximum size of the client's outgoing chat queue. +# 0 to disable queueing and -1 to make the queue size unlimited. +[client] +(Maximum size of the client's outgoing chat queue) 20 -1 32767 +]] +---@field max_out_chat_queue_size integer? +--[[ +# Timeout for client to remove unused map data from memory, in seconds. +[client] +(Mapblock unload timeout) 600.0 0.0 +]] +---@field client_unload_unused_data_timeout number? +--[[ +# Maximum number of mapblocks for client to be kept in memory. +# Note that there is an internal dynamic minimum number of blocks that +# won't be deleted, depending on the current view range. +# Set to -1 for no limit. +[client] +(Mapblock limit) 7500 -1 2147483647 +]] +---@field client_mapblock_limit integer? + +-- -------------------- [Advanced] [*Advanced] [**Server] ------------------- -- + +---@class _.LuantiSettings.advanced.advanced.server.ctx_server +--[[ +# Format of player chat messages. The following strings are valid placeholders: +# @name, @message, @timestamp (optional) +[server] +(Chat message format) <@name> @message +]] +---@field chat_message_format string? +--[[ +# If the execution of a chat command takes longer than this specified time in +# seconds, add the time information to the chat command message +[server] +(Chat command time message threshold) 0.1 0.0 +]] +---@field chatcommand_msg_time_threshold number? +--[[ +# A message to be displayed to all clients when the server shuts down. +[server] +(Shutdown message) Server shutting down. +]] +---@field kick_msg_shutdown string? +--[[ +# A message to be displayed to all clients when the server crashes. +[server] +(Crash message) This server has experienced an internal error. You will now be disconnected. +]] +---@field kick_msg_crash string? +--[[ +# Whether to ask clients to reconnect after a (Lua) crash. +# Set this to true if your server is set up to restart automatically. +[server] +(Ask to reconnect after crash) false +]] +---@field ask_reconnect_on_crash boolean? + +-- ------------ [Advanced] [*Advanced] [**Server/Env Performance] ----------- -- + +---@class _.LuantiSettings.advanced.advanced.server_env_performance.ctx_server +--[[ +# Length of a server tick (the interval at which everything is generally updated), +# stated in seconds. +# Does not apply to sessions hosted from the client menu. +# This is a lower bound, i.e. server steps may not be shorter than this, but +# they are often longer. +[server] +(Dedicated server step) 0.09 0.0 1.0 +]] +---@field dedicated_server_step number? +--[[ +# Whether players are shown to clients without any range limit. +# Deprecated, use the setting player_transfer_distance instead. +[server] +(Unlimited player transfer distance) true +]] +---@field unlimited_player_transfer_distance boolean? +--[[ +# Defines the maximal player transfer distance in blocks (0 = unlimited). +[server] +(Player transfer distance) 0 0 65535 +]] +---@field player_transfer_distance integer? +--[[ +# From how far clients know about objects, stated in mapblocks (16 nodes). +# +# Setting this larger than active_block_range will also cause the server +# to maintain active objects up to this distance in the direction the +# player is looking. (This can avoid mobs suddenly disappearing from view) +[server] +(Active object send range) 8 1 65535 +]] +---@field active_object_send_range_blocks integer? +--[[ +# The radius of the volume of blocks around every player that is subject to the +# active block stuff, stated in mapblocks (16 nodes). +# In active blocks objects are loaded and ABMs run. +# This is also the minimum range in which active objects (mobs) are maintained. +# This should be configured together with active_object_send_range_blocks. +[server] +(Active block range) 4 1 65535 +]] +---@field active_block_range integer? +--[[ +# From how far blocks are sent to clients, stated in mapblocks (16 nodes). +[server] +(Max block send distance) 12 1 65535 +]] +---@field max_block_send_distance integer? +--[[ +# Default maximum number of forceloaded mapblocks. +# Set this to -1 to disable the limit. +[server] +(Maximum forceloaded blocks) 16 -1 +]] +---@field max_forceloaded_blocks integer? +--[[ +# Interval of saving important changes in the world, stated in seconds. +[server] +(Map save interval) 5.3 0.001 +]] +---@field server_map_save_interval number? +--[[ +# How long the server will wait before unloading unused mapblocks, stated in seconds. +# Higher value is smoother, but will use more RAM. +[server] +(Unload unused server data) 29 0 4294967295 +]] +---@field server_unload_unused_data_timeout integer? +--[[ +# Maximum number of statically stored objects in a block. +[server] +(Maximum objects per block) 256 256 65535 +]] +---@field max_objects_per_block integer? +--[[ +# Length of time between active block management cycles, stated in seconds. +[server] +(Active block management interval) 2.0 0.0 +]] +---@field active_block_mgmt_interval number? +--[[ +# Length of time between Active Block Modifier (ABM) execution cycles, stated in seconds. +[server] +(ABM interval) 1.0 0.1 30.0 +]] +---@field abm_interval number? +--[[ +# The time budget allowed for ABMs to execute on each step +# (as a fraction of the ABM Interval) +[server] +(ABM time budget) 0.2 0.1 0.9 +]] +---@field abm_time_budget number? +--[[ +# Length of time between NodeTimer execution cycles, stated in seconds. +[server] +(NodeTimer interval) 0.2 0.1 1.0 +]] +---@field nodetimer_interval number? +--[[ +# Max liquids processed per step. +[server] +(Liquid loop max) 100000 1 4294967295 +]] +---@field liquid_loop_max integer? +--[[ +# The time (in seconds) that the liquids queue may grow beyond processing +# capacity until an attempt is made to decrease its size by dumping old queue +# items. A value of 0 disables the functionality. +[server] +(Liquid queue purge time) 0 0 65535 +]] +---@field liquid_queue_purge_time integer? +--[[ +# Liquid update interval in seconds. +[server] +(Liquid update tick) 1.0 0.001 +]] +---@field liquid_update number? +--[[ +# At this distance the server will aggressively optimize which blocks are sent to +# clients. +# Small values potentially improve performance a lot, at the expense of visible +# rendering glitches (some blocks might not be rendered correctly in caves). +# Setting this to a value greater than max_block_send_distance disables this +# optimization. +# Stated in MapBlocks (16 nodes). +[server] +(Block send optimize distance) 4 2 2047 +]] +---@field block_send_optimize_distance integer? +--[[ +# If enabled, the server will perform map block occlusion culling based on +# on the eye position of the player. This can reduce the number of blocks +# sent to the client by 50-80%. Clients will no longer receive most +# invisible blocks, so that the utility of noclip mode is reduced. +[server] +(Server-side occlusion culling) true +]] +---@field server_side_occlusion_culling boolean? +--[[ +# At this distance the server will perform a simpler and cheaper occlusion check. +# Smaller values potentially improve performance, at the expense of temporarily visible +# rendering glitches (missing blocks). +# This is especially useful for very large viewing range (upwards of 500). +# Stated in MapBlocks (16 nodes). +[server] +(Block cull optimize distance) 25 2 2047 +]] +---@field block_cull_optimize_distance integer? + +-- -------------------- [Advanced] [*Advanced] [**Mapgen] ------------------- -- + +---@class _.LuantiSettings.advanced.advanced.mappgen.ctx_server +--[[ +# Size of mapchunks generated by mapgen, stated in mapblocks (16 nodes). +# WARNING: There is no benefit, and there are several dangers, in +# increasing this value above 5. +# Reducing this value increases cave and dungeon density. +# Altering this value is for special usage, leaving it unchanged is +# recommended. +[world_creation] +(Chunk size) 5 1 10 +]] +---@field chunksize integer? +--[[ +# Dump the mapgen debug information. +[server] +(Mapgen debug) false +]] +---@field enable_mapgen_debug_info boolean? +--[[ +# Maximum number of blocks that can be queued for loading. +[server] +(Absolute limit of queued blocks to emerge) 1024 1 1000000 +]] +---@field emergequeue_limit_total integer? +--[[ +# Maximum number of blocks to be queued that are to be loaded from file. +# This limit is enforced per player. +[server] +(Per-player limit of queued blocks load from disk) 128 1 1000000 +]] +---@field emergequeue_limit_diskonly integer? +--[[ +# Maximum number of blocks to be queued that are to be generated. +# This limit is enforced per player. +[server] +(Per-player limit of queued blocks to generate) 128 1 1000000 +]] +---@field emergequeue_limit_generate integer? +--[[ +# Number of emerge threads to use. +# Value 0: +# - Automatic selection. The number of emerge threads will be +# - 'number of processors - 2', with a lower limit of 1. +# Any other value: +# - Specifies the number of emerge threads, with a lower limit of 1. +# WARNING: Increasing the number of emerge threads increases engine mapgen +# speed, but this may harm game performance by interfering with other +# processes, especially in singleplayer and/or when running Lua code in +# 'on_generated'. For many users the optimum setting may be '1'. +[server] +(Number of emerge threads) 1 0 32767 +]] +---@field num_emerge_threads integer? + +-- --------------------- [Advanced] [*Advanced] [**cURL] -------------------- -- + +---@class _.LuantiSettings.advanced.advanced.cURL.ctx_common +--[[ +# Maximum time an interactive request (e.g. server list fetch) may take, stated in milliseconds. +[common] +(cURL interactive timeout) 20000 1000 2147483647 +]] +---@field curl_timeout integer? +--[[ +# Limits number of parallel HTTP requests. Affects: +# - Media fetch if server uses remote_media setting. +# - Serverlist download and server announcement. +# - Downloads performed by main menu (e.g. mod manager). +# Only has an effect if compiled with cURL. +[common] +(cURL parallel limit) 8 1 2147483647 +]] +---@field curl_parallel_limit integer? +--[[ +# Maximum time a file download (e.g. a mod download) may take, stated in milliseconds. +[common] +(cURL file download timeout) 300000 5000 2147483647 +]] +---@field curl_file_download_timeout integer? + +---@class _.LuantiSettings.advanced.advanced.cURL.ctx_server : _.LuantiSettings.advanced.advanced.cURL.ctx_common + +---@class _.LuantiSettings.advanced.advanced.cURL.ctx_client : _.LuantiSettings.advanced.advanced.cURL.ctx_common + +-- --------------- [Advanced] [*Advanced] [**Client Debugging] -------------- -- + +---@class _.LuantiSettings.advanced.advanced.client_debugging.ctx_client +--[[ +# Key for toggling the camera update. Only usable with 'debug' privilege. +[client] +(Toggle camera update) +]] +---@field keymap_toggle_update_camera _.LuantiSettings.key? +--[[ +# Key for switching to the previous entry in Quicktune. +[client] +(Quicktune: select previous entry) +]] +---@field keymap_quicktune_prev _.LuantiSettings.key? +--[[ +# Key for switching to the next entry in Quicktune. +[client] +(Quicktune: select next entry) +]] +---@field keymap_quicktune_next _.LuantiSettings.key? +--[[ +# Key for decrementing the selected value in Quicktune. +[client] +(Quicktune: decrement value) +]] +---@field keymap_quicktune_dec _.LuantiSettings.key? +--[[ +# Key for incrementing the selected value in Quicktune. +[client] +(Quicktune: increment value) +]] +---@field keymap_quicktune_inc _.LuantiSettings.key? + +-- ---------------- [Advanced] [*Advanced] [**Miscellaneous] ---------------- -- + +---@class _.LuantiSettings.advanced.advanced.miscellaneous.ctx_common +--[[ +# Windows systems only: Start Luanti with the command line window in the background. +# Contains the same information as the file debug.txt (default name). +[common] +(Enable console window) false +]] +---@field enable_console boolean? + +---@class _.LuantiSettings.advanced.advanced.miscellaneous.ctx_client : _.LuantiSettings.advanced.advanced.miscellaneous.ctx_common +--[[ +# Clickable weblinks (middle-click or Ctrl+left-click) enabled in chat console output. +[client] +(Chat weblinks) true +]] +---@field clickable_chat_weblinks boolean? +--[[ +# Adjust the detected display density, used for scaling UI elements. +[client] +(Display Density Scaling Factor) 1 0.5 5.0 +]] +---@field display_density_factor number? + +--[[ +WIPDOC +]] +---@alias core.LuantiSettings.enums.sqlite_synchronous +--- | "0" +--- | "1" +--- | "2" + +---@class _.LuantiSettings.advanced.advanced.miscellaneous.ctx_server : _.LuantiSettings.advanced.advanced.miscellaneous.ctx_common +--[[ +# If enabled, invalid world data won't cause the server to shut down. +# Only enable this if you know what you are doing. +[server] +(Ignore world errors) false +]] +---@field ignore_world_load_errors boolean? +--[[ +# Number of extra blocks that can be loaded by /clearobjects at once. +# This is a trade-off between SQLite transaction overhead and +# memory consumption (4096=100MB, as a rule of thumb). +[server] +(Max. clearobjects extra blocks) 4096 0 4294967295 +]] +---@field max_clearobjects_extra_loaded_blocks integer? +--[[ +# World directory (everything in the world is stored here). +# Not needed if starting from the main menu. +[server] +(Map directory) +]] +---@field ["map-dir"] core.LuantiSettings.path? +--[[ +# See https://www.sqlite.org/pragma.html#pragma_synchronous +[server] +(Synchronous SQLite) 2 0,1,2 +]] +---@field sqlite_synchronous core.LuantiSettings.enums.sqlite_synchronous? +--[[ +# Compression level to use when saving mapblocks to disk. +# -1 - use default compression level +# 0 - least compression, fastest +# 9 - best compression, slowest +[server] +(Map Compression Level for Disk Storage) -1 -1 9 +]] +---@field map_compression_level_disk integer? +--[[ +# Enable usage of remote media server (if provided by server). +# Remote servers offer a significantly faster way to download media (e.g. textures) +# when connecting to the server. +[client] +(Connect to external media server) true +]] +---@field enable_remote_media_server boolean? +--[[ +# File in client/serverlist/ that contains your favorite servers displayed in the +# Multiplayer Tab. +[client] +(Serverlist file) favoriteservers.json +]] +---@field serverlist_file string? + +-- ------------------------- [Advanced] [*Gamepads] ------------------------- -- + +--[[ +WIPDOC +]] +---@alias core.LuantiSettings.enums.joystick_type +--- | "auto" +--- | "generic" +--- | "xbox" +--- | "dragonrise_gamecube" + +---@class _.LuantiSettings.advanced.gamepads.ctx_client +--[[ +# Enable joysticks. Requires a restart to take effect +[client] +(Enable joysticks) false +]] +---@field enable_joysticks boolean? +--[[ +# The identifier of the joystick to use +[client] +(Joystick ID) 0 0 255 +]] +---@field joystick_id integer? +--[[ +# The type of joystick +[client] +(Joystick type) auto auto,generic,xbox,dragonrise_gamecube +]] +---@field joystick_type core.LuantiSettings.enums.joystick_type? +--[[ +# The time in seconds it takes between repeated events +# when holding down a joystick button combination. +[client] +(Joystick button repetition interval) 0.17 0.001 +]] +---@field repeat_joystick_button_time number? +--[[ +# The dead zone of the joystick +[client] +(Joystick dead zone) 2048 0 65535 +]] +---@field joystick_deadzone integer? +--[[ +# The sensitivity of the joystick axes for moving the +# in-game view frustum around. +[client] +(Joystick frustum sensitivity) 170.0 0.001 +]] +---@field joystick_frustum_sensitivity number? + +-- ----------------- [Advanced] [*Hide: Temporary Settings] ----------------- -- + +---@class _.LuantiSettings.advanced.hide_temporary_settings.ctx_common +--[[ +# Path to texture directory. All textures are first searched from here. +[common] +(Texture path) +]] +---@field texture_path core.LuantiSettings.path? +--[[ +# Enables minimap. +[common] +(Minimap) true +]] +---@field enable_minimap boolean? +--[[ +# Shape of the minimap. Enabled = round, disabled = square. +[common] +(Round minimap) true +]] +---@field minimap_shape_round boolean? +--[[ +# Address to connect to. +# Leave this blank to start a local server. +# Note that the address field in the main menu overrides this setting. +[common] +(Server address) +]] +---@field address string? +--[[ +# Port to connect to (UDP). +# Note that the port field in the main menu overrides this setting. +[common] +(Remote port) 30000 1 65535 +]] +---@field remote_port integer? +--[[ +# Enable players getting damage and dying. +[common] +(Damage) false +]] +---@field enable_damage boolean? +--[[ +# Enable creative mode for all players +[common] +(Creative) false +]] +---@field creative_mode boolean? +--[[ +# Whether to allow players to damage and kill each other. +[common] +(Player versus player) true +]] +---@field enable_pvp boolean? +--[[ +# Player is able to fly without being affected by gravity. +# This requires the "fly" privilege on the server. +[common] +(Flying) false +]] +---@field free_move boolean? +--[[ +# If enabled, makes move directions relative to the player's pitch when flying or swimming. +[common] +(Pitch move mode) false +]] +---@field pitch_move boolean? +--[[ +# Fast movement (via the "Aux1" key). +# This requires the "fast" privilege on the server. +[common] +(Fast movement) false +]] +---@field fast_move boolean? +--[[ +# If enabled together with fly mode, player is able to fly through solid nodes. +# This requires the "noclip" privilege on the server. +[common] +(Noclip) false +]] +---@field noclip boolean? +--[[ +# Continuous forward movement, toggled by autoforward key. +# Press the autoforward key again or the backwards movement to disable. +[common] +(Continuous forward) false +]] +---@field continuous_forward boolean? +--[[ +# This can be bound to a key to toggle camera smoothing when looking around. +# Useful for recording videos +[common] +(Cinematic mode) false +]] +---@field cinematic boolean? +--[[ +# Affects mods and texture packs in the Content and Select Mods menus, as well as +# setting names. +# Controlled by a checkbox in the settings menu. +[common] +(Show technical names) false +]] +---@field show_technical_names boolean? +--[[ +# Controlled by a checkbox in the settings menu. +[common] +(Show advanced settings) false +]] +---@field show_advanced boolean? + +---@class _.LuantiSettings.advanced.hide_temporary_settings.ctx_server : _.LuantiSettings.advanced.hide_temporary_settings.ctx_common + +---@class _.LuantiSettings.advanced.hide_temporary_settings.ctx_client : _.LuantiSettings.advanced.hide_temporary_settings.ctx_common \ No newline at end of file diff --git a/types/luanti_lsp_definitions/library/classes/Settings/LuantiSettings/client_and_server.lua b/types/luanti_lsp_definitions/library/classes/Settings/LuantiSettings/client_and_server.lua new file mode 100644 index 00000000..6a13bf97 --- /dev/null +++ b/types/luanti_lsp_definitions/library/classes/Settings/LuantiSettings/client_and_server.lua @@ -0,0 +1,490 @@ +---@meta _ +-- DRAFT 1 DONE +-- builtin/settingtypes.txt +-- minetest.conf.example + + +-- Section context mapping: +-- * [Client and Server] [*Client]: [client] +-- * [Client and Server] [*Server]: [server] +-- * [Client and Server] [*Server Security]: [server] +-- * [Client and Server] [*Server Gameplay]: [server] + +---@alias _.LuantiSettings.client_and_server.keys.boolean +--- | "server_announce" +--- | "server_announce_send_players" +--- | "strict_protocol_version_checking" +--- | "ipv6_server" +--- | "disallow_empty_password" +--- | "enable_rollback_recording" +--- | "strip_color_codes" + +---@alias _.LuantiSettings.client_and_server.keys +--- | "serverlist_url" +--- | "name" +--- | "serverlist_url" +--- | "server_name" +--- | "server_description" +--- | "server_address" +--- | "server_url" +--- | "server_announce" +--- | "server_announce_send_players" +--- | "motd" +--- | "max_users" +--- | "static_spawnpoint" +--- | "port" +--- | "bind_address" +--- | "strict_protocol_version_checking" +--- | "protocol_version_min" +--- | "remote_media" +--- | "ipv6_server" +--- | "default_password" +--- | "disallow_empty_password" +--- | "default_privs" +--- | "basic_privs" +--- | "anticheat_flags" +--- | "anticheat_movement_tolerance" +--- | "enable_rollback_recording" +--- | "csm_restriction_flags" +--- | "csm_restriction_noderange" +--- | "strip_color_codes" +--- | "chat_message_max_size" +--- | "chat_message_limit_per_10sec" +--- | "chat_message_limit_trigger_kick" +--- | "time_speed" +--- | "world_start_time" +--- | "item_entity_ttl" +--- | "default_stack_max" +--- | "movement_acceleration_default" +--- | "movement_acceleration_air" +--- | "movement_acceleration_fast" +--- | "movement_speed_walk" +--- | "movement_speed_crouch" +--- | "movement_speed_fast" +--- | "movement_speed_climb" +--- | "movement_speed_jump" +--- | "movement_liquid_fluidity" +--- | "movement_liquid_fluidity_smooth" +--- | "movement_liquid_sink" +--- | "movement_gravity" + +---@class _.LuantiSettings.client_and_server.tablefmt : _.LuantiSettings.client_and_server.client.ctx_server, _.LuantiSettings.client_and_server.server, _.LuantiSettings.client_and_server.server.serverlist_and_motd.ctx_server, _.LuantiSettings.client_and_server.server.networking, _.LuantiSettings.client_and_server.server_security, _.luantisettings.client_and_server.server_security.client_side_modding, _.luantisettings.client_and_server.server_security.chat, _.luantisettings.client_and_server.server_gameplay, _.luantisettings.client_and_server.server_gameplay.physics + +-- --------------------------- [Client and Server] -------------------------- -- + +-- ---------------------- [Client and Server] [*Client] --------------------- -- + +---@class _.LuantiSettings.client_and_server.client.ctx_common +--[[ +# URL to the server list displayed in the Multiplayer Tab. +[common] +(Serverlist URL) https://servers.luanti.org +]] +---@field serverlist_url string? + +---@class _.LuantiSettings.client_and_server.client.ctx_client : _.LuantiSettings.client_and_server.client.ctx_common +--[[ +# Save the map received by the client on disk. +[client] +(Saving map received from server) false +]] +---@field enable_local_map_saving boolean? +--[[ +# If enabled, server account registration is separate from login in the UI. +# If disabled, connecting to a server will automatically register a new account. +[client] +(Enable split login/register) true +]] +---@field enable_split_login_register boolean? +--[[ +# URL to JSON file which provides information about the newest Luanti release. +# If this is empty the engine will never check for updates. +[client] +(Update information URL) https://www.luanti.org/release_info.json +]] +---@field update_information_url string? + +---@class _.LuantiSettings.client_and_server.client.ctx_server : _.LuantiSettings.client_and_server.client.ctx_common + +-- ---------------------- [Client and Server] [*Server] --------------------- -- + +---@class _.LuantiSettings.client_and_server.server +--[[ +# Name of the player. +# When running a server, a client connecting with this name is admin. +# When starting from the main menu, this is overridden. +[server] +(Admin name) +]] +---@field name string? + + -- ---------- [Client and Server] [*Server] [**Serverlist and MOTD] --------- -- + +---@class _.LuantiSettings.client_and_server.server.serverlist_and_motd.ctx_common +--[[ +# Announce to this serverlist. +[common] +(Serverlist URL) https://servers.luanti.org +]] +---@field serverlist_url string? + +---@class _.LuantiSettings.client_and_server.server.serverlist_and_motd.ctx_server : _.LuantiSettings.client_and_server.server.serverlist_and_motd.ctx_common +--[[ +# Name of the server, to be displayed when players join and in the serverlist. +[server] +(Server name) Luanti server +]] +---@field server_name string? +--[[ +# Description of server, to be displayed when players join and in the serverlist. +[server] +(Server description) mine here +]] +---@field server_description string? +--[[ +# Domain name of server, to be displayed in the serverlist. +[server] +(Server address) game.example.net +]] +---@field server_address string? +--[[ +# Homepage of server, to be displayed in the serverlist. +[server] +(Server URL) https://game.example.net +]] +---@field server_url string? +--[[ +# Automatically report to the serverlist. +[server] +(Announce server) false +]] +---@field server_announce boolean? +--[[ +# Send names of online players to the serverlist. If disabled only the player count is revealed. +[server] +(Send player names to the server list) true +]] +---@field server_announce_send_players boolean? +--[[ +# Message of the day displayed to players connecting. +[server] +(Message of the day) +]] +---@field motd string? +--[[ +# Maximum number of players that can be connected simultaneously. +[server] +(Maximum users) 15 0 65535 +]] +---@field max_users integer? +--[[ +# If this is set, players will always (re)spawn at the given position. +[server] +(Static spawn point) +]] +---@field static_spawnpoint string? + +---@class _.LuantiSettings.client_and_server.server.serverlist_and_motd.ctx_client : _.LuantiSettings.client_and_server.server.serverlist_and_motd.ctx_common + + -- -------------- [Client and Server] [*Server] [**Networking] -------------- -- + +---@class _.LuantiSettings.client_and_server.server.networking +--[[ +# Network port to listen (UDP). +# This value will be overridden when starting from the main menu. +[server] +(Server port) 30000 1 65535 +]] +---@field port integer? +--[[ +# The network interface that the server listens on. +[server] +(Bind address) +]] +---@field bind_address string? +--[[ +# Enable to disallow old clients from connecting. +# Older clients are compatible in the sense that they will not crash when connecting +# to new servers, but they may not support all new features that you are expecting. +[server] +(Strict protocol checking) false +]] +---@field strict_protocol_version_checking boolean? +--[[ +# Define the oldest clients allowed to connect. +# Older clients are compatible in the sense that they will not crash when connecting +# to new servers, but they may not support all new features that you are expecting. +# This allows for more fine-grained control than strict_protocol_version_checking. +# Luanti still enforces its own internal minimum, and enabling +# strict_protocol_version_checking will effectively override this. +[server] +(Protocol version minimum) 1 1 65535 +]] +---@field protocol_version_min integer? +--[[ +# Specifies URL from which client fetches media instead of using UDP. +# $filename should be accessible from $remote_media$filename via cURL +# (obviously, remote_media should end with a slash). +# Files that are not present will be fetched the usual way. +[server] +(Remote media) +]] +---@field remote_media string? +--[[ +# Enable IPv6 support for server. +# Note that clients will be able to connect with both IPv4 and IPv6. +# Ignored if bind_address is set. +# +# Requires: enable_ipv6 +[server] +(IPv6 server) true +]] +---@field ipv6_server boolean? + +-- ----------------- [Client and Server] [*Server Security] ----------------- -- + +--[[ +WIPDOC +]] +---@class core.LuantiSettings.flags.anticheat_flags +--[[ +WIPDOC +]] +---@field digging boolean? +--[[ +WIPDOC +]] +---@field nodigging boolean? +--[[ +WIPDOC +]] +---@field interaction boolean? +--[[ +WIPDOC +]] +---@field nointeraction boolean? +--[[ +WIPDOC +]] +---@field movement boolean? +--[[ +WIPDOC +]] +---@field nomovement boolean? + +---@class _.LuantiSettings.client_and_server.server_security +--[[ +# New users need to input this password. +[server] +(Default password) +]] +---@field default_password string? +--[[ +# If enabled, players cannot join without a password or change theirs to an empty password. +[server] +(Disallow empty passwords) false +]] +---@field disallow_empty_password boolean? +--[[ +# The privileges that new users automatically get. +# See /privs in game for a full list on your server and mod configuration. +[server] +(Default privileges) interact, shout +]] +---@field default_privs string? +--[[ +# Privileges that players with basic_privs can grant +[server] +(Basic privileges) interact, shout +]] +---@field basic_privs string? +--[[ +# Server anticheat configuration. +# Flags are positive. Uncheck the flag to disable corresponding anticheat module. +[server] +(Anticheat flags) digging,interaction,movement digging,interaction,movement +]] +---@field anticheat_flags core.LuantiSettings.flags? +--[[ +# Tolerance of movement cheat detector. +# Increase the value if players experience stuttery movement. +[server] +(Anticheat movement tolerance) 1.0 1.0 +]] +---@field anticheat_movement_tolerance number? +--[[ +# If enabled, actions are recorded for rollback. +# This option is only read when server starts. +[server] +(Rollback recording) false +]] +---@field enable_rollback_recording boolean? + +-- ----- [Client and Server] [*Server Security] [**Client-side Modding] ----- -- + +---@class _.luantisettings.client_and_server.server_security.client_side_modding +--[[ +# Restricts the access of certain client-side functions on servers. +# Combine the byteflags below to restrict client-side features, or set to 0 +# for no restrictions: +# LOAD_CLIENT_MODS: 1 (disable loading client-provided mods) +# CHAT_MESSAGES: 2 (disable send_chat_message call client-side) +# READ_ITEMDEFS: 4 (disable get_item_def call client-side) +# READ_NODEDEFS: 8 (disable get_node_def call client-side) +# LOOKUP_NODES_LIMIT: 16 (limits get_node call client-side to +# csm_restriction_noderange) +# READ_PLAYERINFO: 32 (disable get_player_names call client-side) +[server] +(Client side modding restrictions) 62 0 63 +]] +---@field csm_restriction_flags integer? +--[[ +# If the CSM restriction for node range is enabled, get_node calls are limited +# to this distance from the player to the node. +[server] +(Client-side node lookup range restriction) 0 0 4294967295 +]] +---@field csm_restriction_noderange integer? + +-- ------------- [Client and Server] [*Server Security] [**Chat] ------------ -- + +---@class _.luantisettings.client_and_server.server_security.chat +--[[ +# Remove color codes from incoming chat messages +# Use this to stop players from being able to use color in their messages +[server] +(Strip color codes) false +]] +---@field strip_color_codes boolean? +--[[ +# Set the maximum length of a chat message (in characters) sent by clients. +[server] +(Chat message max length) 500 10 65535 +]] +---@field chat_message_max_size integer? +--[[ +# Number of messages a player may send per 10 seconds. +[server] +(Chat message count limit) 8.0 1.0 +]] +---@field chat_message_limit_per_10sec number? +--[[ +# Kick players who sent more than X messages per 10 seconds. +[server] +(Chat message kick threshold) 50 1 65535 +]] +---@field chat_message_limit_trigger_kick integer? + +-- ----------------- [Client and Server] [*Server Gameplay] ----------------- -- + +---@class _.luantisettings.client_and_server.server_gameplay +--[[ +# Controls length of day/night cycle. +# Examples: +# 72 = 20min, 360 = 4min, 1 = 24hour, 0 = day/night/whatever stays unchanged. +[server] +(Time speed) 72 0 +]] +---@field time_speed integer? +--[[ +# Time of day when a new world is started, in millihours (0-23999). +[world_creation] +(World start time) 6125 0 23999 +]] +---@field world_start_time integer? +--[[ +# Time in seconds for item entity (dropped items) to live. +# Setting it to -1 disables the feature. +[server] +(Item entity TTL) 900 -1 +]] +---@field item_entity_ttl integer? +--[[ +# Specifies the default stack size of nodes, items and tools. +# Note that mods or games may explicitly set a stack for certain (or all) items. +[server] +(Default stack size) 99 1 65535 +]] +---@field default_stack_max integer? + +-- ----------- [Client and Server] [*Server Gameplay] [**Physics] ----------- -- + +---@class _.luantisettings.client_and_server.server_gameplay.physics +--[[ +# Horizontal and vertical acceleration on ground or when climbing, +# in nodes per second per second. +[server] +(Default acceleration) 3.0 0.0 +]] +---@field movement_acceleration_default number? +--[[ +# Horizontal acceleration in air when jumping or falling, +# in nodes per second per second. +[server] +(Acceleration in air) 2.0 0.0 +]] +---@field movement_acceleration_air number? +--[[ +# Horizontal and vertical acceleration in fast mode, +# in nodes per second per second. +[server] +(Fast mode acceleration) 10.0 0.0 +]] +---@field movement_acceleration_fast number? +--[[ +# Walking and flying speed, in nodes per second. +[server] +(Walking speed) 4.0 0.0 +]] +---@field movement_speed_walk number? +--[[ +# Sneaking speed, in nodes per second. +[server] +(Sneaking speed) 1.35 0.0 +]] +---@field movement_speed_crouch number? +--[[ +# Walking, flying and climbing speed in fast mode, in nodes per second. +[server] +(Fast mode speed) 20.0 0.0 +]] +---@field movement_speed_fast number? +--[[ +# Vertical climbing speed, in nodes per second. +[server] +(Climbing speed) 3.0 0.0 +]] +---@field movement_speed_climb number? +--[[ +# Initial vertical speed when jumping, in nodes per second. +[server] +(Jumping speed) 6.5 0.0 +]] +---@field movement_speed_jump number? +--[[ +# How much you are slowed down when moving inside a liquid. +# Decrease this to increase liquid resistance to movement. +[server] +(Liquid fluidity) 1.0 0.001 +]] +---@field movement_liquid_fluidity number? +--[[ +# Maximum liquid resistance. Controls deceleration when entering liquid at +# high speed. +[server] +(Liquid fluidity smoothing) 0.5 +]] +---@field movement_liquid_fluidity_smooth number? +--[[ +# Controls sinking speed in liquid when idling. Negative values will cause +# you to rise instead. +[server] +(Liquid sinking) 10.0 +]] +---@field movement_liquid_sink number? +--[[ +# Acceleration of gravity, in nodes per second per second. +[server] +(Gravity) 9.81 +]] +---@field movement_gravity number? \ No newline at end of file diff --git a/types/luanti_lsp_definitions/library/classes/Settings/LuantiSettings/controls.lua b/types/luanti_lsp_definitions/library/classes/Settings/LuantiSettings/controls.lua new file mode 100644 index 00000000..e189bf5a --- /dev/null +++ b/types/luanti_lsp_definitions/library/classes/Settings/LuantiSettings/controls.lua @@ -0,0 +1,700 @@ +---@meta _ +-- DRAFT 1 DONE +-- builtin/settingtypes.txt +-- minetest.conf.example + +-- NOTE: key type is not a type mods and games will have to deal with +---@class _.LuantiSettings.key + +-- Section context mapping: +-- * [Controls]: [client] + +-- -------------------------- [Controls] [*General] ------------------------- -- + +---@class _.LuantiSettings.controls.general +--[[ +# Smooths rotation of camera, also called look or mouse smoothing. 0 to disable. +[client] +(Camera smoothing) 0.0 0.0 0.99 +]] +---@field camera_smoothing number? +--[[ +# Smooths rotation of camera when in cinematic mode, 0 to disable. Enter cinematic mode by using the key set in Controls. +# +# Requires: keyboard_mouse +[client] +(Camera smoothing in cinematic mode) 0.7 0.0 0.99 +]] +---@field cinematic_camera_smoothing number? +--[[ +# If enabled, you can place nodes at the position (feet + eye level) where you stand. +# This is helpful when working with nodeboxes in small areas. +[client] +(Build inside player) false +]] +---@field enable_build_where_you_stand boolean? +--[[ +# If enabled, "Aux1" key instead of "Sneak" key is used for climbing down and +# descending. +[client] +(Aux1 key for climbing/descending) false +]] +---@field aux1_descends boolean? +--[[ +# Double-tapping the jump key toggles fly mode. +[client] +(Double tap jump for fly) false +]] +---@field doubletap_jump boolean? +--[[ +# If disabled, "Aux1" key is used to fly fast if both fly and fast mode are +# enabled. +(Always fly fast) true +]] +---@field always_fly_fast boolean? +--[[ +# If enabled, the "Sneak" key will toggle when pressed. +# This functionality is ignored when fly is enabled. +[client] +(Toggle Sneak key) false +]] +---@field toggle_sneak_key boolean? +--[[ +# If enabled, the "Aux1" key will toggle when pressed. +[client] +(Toggle Aux1 key) false +]] +---@field toggle_aux1_key boolean? +--[[ +# The time in seconds it takes between repeated node placements when holding +# the place button. +# +# Requires: keyboard_mouse +[client] +(Place repetition interval) 0.25 0.16 2.0 +]] +---@field repeat_place_time number? +--[[ +# The minimum time in seconds it takes between digging nodes when holding +# the dig button. +[client] +(Minimum dig repetition interval) 0.0 0.0 2.0 +]] +---@field repeat_dig_time number? +--[[ +# Automatically jump up single-node obstacles. +[client] +(Automatic jumping) false +]] +---@field autojump boolean? +--[[ +# Prevent digging and placing from repeating when holding the respective buttons. +# Enable this when you dig or place too often by accident. +# On touchscreens, this only affects digging. +[client] +(Safe digging and placing) false +]] +---@field safe_dig_and_place boolean? + +-- -------------------- [Controls] [*Keyboard and Mouse] -------------------- -- + +---@class _.LuantiSettings.controls.keyboard_and_mouse +--[[ +# Invert vertical mouse movement. +# +# Requires: keyboard_mouse +[client] +(Invert mouse) false +]] +---@field invert_mouse boolean? +--[[ +# Mouse sensitivity multiplier. +# +# Requires: keyboard_mouse +[client] +(Mouse sensitivity) 0.2 0.001 10.0 +]] +---@field mouse_sensitivity number? +--[[ +# Enable mouse wheel (scroll) for item selection in hotbar. +# +# Requires: keyboard_mouse +[client] +(Hotbar: Enable mouse wheel for selection) true +]] +---@field enable_hotbar_mouse_wheel boolean? +--[[ +# Invert mouse wheel (scroll) direction for item selection in hotbar. +# +# Requires: keyboard_mouse +[client] +(Hotbar: Invert mouse wheel direction) false +]] +---@field invert_hotbar_mouse_wheel boolean? + +-- ------------ [Controls] [*Keyboard and Mouse] [**Keybindings] ------------ -- + +---@class _.LuantiSettings.controls.keyboard_and_mouse.keybindings +--[[ +# WIPDOC +[client] +(Move forward) SYSTEM_SCANCODE_26 +]] +---@field keymap_forward _.LuantiSettings.key? +--[[ +# Will also disable autoforward, when active. +[client] +(Move backward) SYSTEM_SCANCODE_22 +]] +---@field keymap_backward _.LuantiSettings.key? +--[[ +# WIPDOC +[client] +(Move left) SYSTEM_SCANCODE_4 +]] +---@field keymap_left _.LuantiSettings.key? +--[[ +# WIPDOC +[client] +(Move right) SYSTEM_SCANCODE_7 +]] +---@field keymap_right _.LuantiSettings.key? +--[[ +# WIPDOC +[client] +(Jump) SYSTEM_SCANCODE_44 +]] +---@field keymap_jump _.LuantiSettings.key? +--[[ +# Also used for climbing down and descending in water if aux1_descends is disabled. +[client] +(Sneak) SYSTEM_SCANCODE_225 +]] +---@field keymap_sneak _.LuantiSettings.key? +--[[ +# Key for digging, punching or using something. +# (Note: The actual meaning might vary on a per-game basis.) +[client] +(Dig/punch/use) KEY_LBUTTON +]] +---@field keymap_dig _.LuantiSettings.key? +--[[ +# Key for placing an item/block or for using something. +# (Note: The actual meaning might vary on a per-game basis.) +[client] +(Place/use) KEY_RBUTTON +]] +---@field keymap_place _.LuantiSettings.key? +--[[ +# WIPDOC +[client] +(Open inventory) SYSTEM_SCANCODE_12 +]] +---@field keymap_inventory _.LuantiSettings.key? +--[[ +# Key for moving fast in fast mode. +[client] +(Aux1) SYSTEM_SCANCODE_8 +]] +---@field keymap_aux1 _.LuantiSettings.key? +--[[ +# WIPDOC +[client] +(Open chat) SYSTEM_SCANCODE_23 +]] +---@field keymap_chat _.LuantiSettings.key? +--[[ +# Key for opening the chat window to type commands. +[client] +(Command) SYSTEM_SCANCODE_56 +]] +---@field keymap_cmd _.LuantiSettings.key? +--[[ +# Key for opening the chat window to type local commands. +[client] +(Local command) SYSTEM_SCANCODE_55 +]] +---@field keymap_cmd_local _.LuantiSettings.key? +--[[ +# WIPDOC +[client] +(Toggle unlimited view range) +]] +---@field keymap_rangeselect _.LuantiSettings.key? +--[[ +# WIPDOC +[client] +(Toggle fly) SYSTEM_SCANCODE_14 +]] +---@field keymap_freemove _.LuantiSettings.key? +--[[ +# WIPDOC +[client] +(Toggle pitchmove) +]] +---@field keymap_pitchmove _.LuantiSettings.key? +--[[ +# WIPDOC +[client] +(Toggle fast) SYSTEM_SCANCODE_13 +]] +---@field keymap_fastmove _.LuantiSettings.key? +--[[ +# WIPDOC +[client] +(Toggle noclip) SYSTEM_SCANCODE_11 +]] +---@field keymap_noclip _.LuantiSettings.key? +--[[ +# WIPDOC +[client] +(Hotbar: select next item) SYSTEM_SCANCODE_17 +]] +---@field keymap_hotbar_next _.LuantiSettings.key? +--[[ +# WIPDOC +[client] +(Hotbar: select previous item) SYSTEM_SCANCODE_5 +]] +---@field keymap_hotbar_previous _.LuantiSettings.key? +--[[ +# WIPDOC +[client] +(Mute) SYSTEM_SCANCODE_16 +]] +---@field keymap_mute _.LuantiSettings.key? +--[[ +# WIPDOC +[client] +(Increase volume) +]] +---@field keymap_increase_volume _.LuantiSettings.key? +--[[ +# WIPDOC +[client] +(Decrease volume) +]] +---@field keymap_decrease_volume _.LuantiSettings.key? +--[[ +# WIPDOC +[client] +(Toggle automatic forward) +]] +---@field keymap_autoforward _.LuantiSettings.key? +--[[ +# WIPDOC +[client] +(Toggle cinematic mode) +]] +---@field keymap_cinematic _.LuantiSettings.key? +--[[ +# WIPDOC +[client] +(Toggle minimap) SYSTEM_SCANCODE_25 +]] +---@field keymap_minimap _.LuantiSettings.key? +--[[ +# WIPDOC +[client] +(Screenshot) SYSTEM_SCANCODE_69 +]] +---@field keymap_screenshot _.LuantiSettings.key? +--[[ +# WIPDOC +[client] +(Toggle fullscreen) SYSTEM_SCANCODE_68 +]] +---@field keymap_fullscreen _.LuantiSettings.key? +--[[ +# WIPDOC +[client] +(Drop item) SYSTEM_SCANCODE_20 +]] +---@field keymap_drop _.LuantiSettings.key? +--[[ +# WIPDOC +[client] +(Zoom) SYSTEM_SCANCODE_29 +]] +---@field keymap_zoom _.LuantiSettings.key? +--[[ +# WIPDOC +[client] +(Toggle HUD) SYSTEM_SCANCODE_58 +]] +---@field keymap_toggle_hud _.LuantiSettings.key? +--[[ +# WIPDOC +[client] +(Toggle chat log) SYSTEM_SCANCODE_59 +]] +---@field keymap_toggle_chat _.LuantiSettings.key? +--[[ +# WIPDOC +[client] +(Toggle large chat console) SYSTEM_SCANCODE_67 +]] +---@field keymap_console _.LuantiSettings.key? +--[[ +# WIPDOC +[client] +(Toggle fog) SYSTEM_SCANCODE_60 +]] +---@field keymap_toggle_fog _.LuantiSettings.key? +--[[ +# WIPDOC +[client] +(Toggle debug info) SYSTEM_SCANCODE_62 +]] +---@field keymap_toggle_debug _.LuantiSettings.key? +--[[ +# Key for toggling the display of the profiler. Used for development. +[client] +(Toggle profiler) SYSTEM_SCANCODE_63 +]] +---@field keymap_toggle_profiler _.LuantiSettings.key? +--[[ +# Key for toggling the display of mapblock boundaries. +[client] +(Toggle block bounds) +]] +---@field keymap_toggle_block_bounds _.LuantiSettings.key? +--[[ +# WIPDOC +[client] +(Toggle camera mode) SYSTEM_SCANCODE_6 +]] +---@field keymap_camera_mode _.LuantiSettings.key? +--[[ +# WIPDOC +[client] +(Increase view range) SYSTEM_SCANCODE_46 +]] +---@field keymap_increase_viewing_range_min _.LuantiSettings.key? +--[[ +# WIPDOC +[client] +(Decrease view range) SYSTEM_SCANCODE_45 +]] +---@field keymap_decrease_viewing_range_min _.LuantiSettings.key? +--[[ +# Modifier key bind for closing your world. +# Requires ESC + the selected key to work. +[client] +(Return to Main Menu) +]] +---@field keymap_close_world _.LuantiSettings.key? +--[[ +# WIPDOC +[client] +(Hotbar slot 1) SYSTEM_SCANCODE_30 +]] +---@field keymap_slot1 _.LuantiSettings.key? +--[[ +# WIPDOC +[client] +(Hotbar slot 2) SYSTEM_SCANCODE_31 +]] +---@field keymap_slot2 _.LuantiSettings.key? +--[[ +# WIPDOC +[client] +(Hotbar slot 3) SYSTEM_SCANCODE_32 +]] +---@field keymap_slot3 _.LuantiSettings.key? +--[[ +# WIPDOC +[client] +(Hotbar slot 4) SYSTEM_SCANCODE_33 +]] +---@field keymap_slot4 _.LuantiSettings.key? +--[[ +# WIPDOC +[client] +(Hotbar slot 5) SYSTEM_SCANCODE_34 +]] +---@field keymap_slot5 _.LuantiSettings.key? +--[[ +# WIPDOC +[client] +(Hotbar slot 6) SYSTEM_SCANCODE_35 +]] +---@field keymap_slot6 _.LuantiSettings.key? +--[[ +# WIPDOC +[client] +(Hotbar slot 7) SYSTEM_SCANCODE_36 +]] +---@field keymap_slot7 _.LuantiSettings.key? +--[[ +# WIPDOC +[client] +(Hotbar slot 8) SYSTEM_SCANCODE_37 +]] +---@field keymap_slot8 _.LuantiSettings.key? +--[[ +# WIPDOC +[client] +(Hotbar slot 9) SYSTEM_SCANCODE_38 +]] +---@field keymap_slot9 _.LuantiSettings.key? +--[[ +# WIPDOC +[client] +(Hotbar slot 10) SYSTEM_SCANCODE_39 +]] +---@field keymap_slot10 _.LuantiSettings.key? +--[[ +# WIPDOC +[client] +(Hotbar slot 11) +]] +---@field keymap_slot11 _.LuantiSettings.key? +--[[ +# WIPDOC +[client] +(Hotbar slot 12) +]] +---@field keymap_slot12 _.LuantiSettings.key? +--[[ +# WIPDOC +[client] +(Hotbar slot 13) +]] +---@field keymap_slot13 _.LuantiSettings.key? +--[[ +# WIPDOC +[client] +(Hotbar slot 14) +]] +---@field keymap_slot14 _.LuantiSettings.key? +--[[ +# WIPDOC +[client] +(Hotbar slot 15) +]] +---@field keymap_slot15 _.LuantiSettings.key? +--[[ +# WIPDOC +[client] +(Hotbar slot 16) +]] +---@field keymap_slot16 _.LuantiSettings.key? +--[[ +# WIPDOC +[client] +(Hotbar slot 17) +]] +---@field keymap_slot17 _.LuantiSettings.key? +--[[ +# WIPDOC +[client] +(Hotbar slot 18) +]] +---@field keymap_slot18 _.LuantiSettings.key? +--[[ +# WIPDOC +[client] +(Hotbar slot 19) +]] +---@field keymap_slot19 _.LuantiSettings.key? +--[[ +# WIPDOC +[client] +(Hotbar slot 20) +]] +---@field keymap_slot20 _.LuantiSettings.key? +--[[ +# WIPDOC +[client] +(Hotbar slot 21) +]] +---@field keymap_slot21 _.LuantiSettings.key? +--[[ +# WIPDOC +[client] +(Hotbar slot 22) +]] +---@field keymap_slot22 _.LuantiSettings.key? +--[[ +# WIPDOC +[client] +(Hotbar slot 23) +]] +---@field keymap_slot23 _.LuantiSettings.key? +--[[ +# WIPDOC +[client] +(Hotbar slot 24) +]] +---@field keymap_slot24 _.LuantiSettings.key? +--[[ +# WIPDOC +[client] +(Hotbar slot 25) +]] +---@field keymap_slot25 _.LuantiSettings.key? +--[[ +# WIPDOC +[client] +(Hotbar slot 26) +]] +---@field keymap_slot26 _.LuantiSettings.key? +--[[ +# WIPDOC +[client] +(Hotbar slot 27) +]] +---@field keymap_slot27 _.LuantiSettings.key? +--[[ +# WIPDOC +[client] +(Hotbar slot 28) +]] +---@field keymap_slot28 _.LuantiSettings.key? +--[[ +# WIPDOC +[client] +(Hotbar slot 29) +]] +---@field keymap_slot29 _.LuantiSettings.key? +--[[ +# WIPDOC +[client] +(Hotbar slot 30) +]] +---@field keymap_slot30 _.LuantiSettings.key? +--[[ +# WIPDOC +[client] +(Hotbar slot 31) +]] +---@field keymap_slot31 _.LuantiSettings.key? +--[[ +# WIPDOC +[client] +(Hotbar slot 32) +]] +---@field keymap_slot32 _.LuantiSettings.key? + + +-- ------------------------ [Controls] [*Touchscreen] ----------------------- -- + +--[[ +WIPDOC +]] +---@alias core.LuantiSettings.enums.touch_controls +--- | "auto" +--- | "true" +--- | "false" + +---@class _.LuantiSettings.controls.touchscreen +--[[ +# Enables the touchscreen controls, allowing you to play the game with a touchscreen. +# "auto" means that the touchscreen controls will be enabled and disabled +# automatically depending on the last used input method. +# +# Requires: touch_support +[client] +(Touchscreen controls) auto auto,true,false +]] +---@field touch_controls core.LuantiSettings.enums.touch_controls? + +--[[ +WIPDOC +]] +---@alias core.LuantiSettings.enums.touch_interaction_style +--- | "tap" +--- | "tap_crosshair" +--- | "buttons_crosshair" + +---@class _.LuantiSettings.controls.touchscreen +--[[ +# The kind of digging/placing controls used. +# +# * Tap +# Long/short tap anywhere on the screen to interact. +# Interaction happens at finger position. +# +# * Tap with crosshair +# Long/short tap anywhere on the screen to interact. +# Interaction happens at crosshair position. +# +# * Buttons with crosshair +# Use dedicated dig/place buttons to interact. +# Interaction happens at crosshair position. +# +# Requires: touchscreen +[client] +(Interaction style) tap tap,tap_crosshair,buttons_crosshair +]] +---@field touch_interaction_style core.LuantiSettings.enums.touch_interaction_style? + +--[[ +WIPDOC +]] +---@alias core.LuantiSettings.enums.touch_punch_gesture +--- | "short_tap" +--- | "long_tap" + +---@class _.LuantiSettings.controls.touchscreen +--[[ +# The gesture for punching players/entities. +# This can be overridden by games and mods. +# +# * Short tap +# Easy to use and well-known from other games that shall not be named. +# +# * Long tap +# Known from the classic Luanti mobile controls. +# Combat is more or less impossible. +# +# Requires: touchscreen, touch_interaction_style_tap +[client] +(Punch gesture) short_tap short_tap,long_tap +]] +---@field touch_punch_gesture core.LuantiSettings.enums.touch_punch_gesture? + +---@class _.LuantiSettings.controls.touchscreen +--[[ +# Touchscreen sensitivity multiplier. +# +# Requires: touchscreen +[client] +(Touchscreen sensitivity) 0.2 0.001 10.0 +]] +---@field touchscreen_sensitivity number? +--[[ +# The length in pixels after which a touch interaction is considered movement. +# +# Requires: touchscreen +[client] +(Movement threshold) 20 0 100 +]] +---@field touchscreen_threshold integer? +--[[ +# The delay in milliseconds after which a touch interaction is considered a long tap. +# +# Requires: touchscreen +[client] +(Threshold for long taps) 400 100 1000 +]] +---@field touch_long_tap_delay integer? +--[[ +# Fixes the position of virtual joystick. +# If disabled, virtual joystick will center to first-touch's position. +# +# Requires: touchscreen +[client] +(Fixed virtual joystick) false +]] +---@field fixed_virtual_joystick boolean? +--[[ +# Use virtual joystick to trigger "Aux1" button. +# If enabled, virtual joystick will also tap "Aux1" button when out of main circle. +# +# Requires: touchscreen +[client] +(Virtual joystick triggers Aux1 button) false +]] +---@field virtual_joystick_triggers_aux1 boolean? \ No newline at end of file diff --git a/types/luanti_lsp_definitions/library/classes/Settings/LuantiSettings/graphics_and_audio.lua b/types/luanti_lsp_definitions/library/classes/Settings/LuantiSettings/graphics_and_audio.lua new file mode 100644 index 00000000..87cfcce5 --- /dev/null +++ b/types/luanti_lsp_definitions/library/classes/Settings/LuantiSettings/graphics_and_audio.lua @@ -0,0 +1,1032 @@ +---@meta _ +-- DRAFT 1 DONE +-- builtin/settingtypes.txt +-- minetest.conf.example + +-- Section context mapping: +-- * [Graphics and Audio]: [client] + + +-- -------------------- [Graphics and Audio] [*Graphics] -------------------- -- + +-- --------------- [Graphics and Audio] [*Graphics] [**Screen] -------------- -- + +---@class _.LuantiSettings.graphics_and_audio.graphics.screen +--[[ +# Width component of the initial window size. +# +# Requires: desktop +[client] +(Screen width) 1024 1 65535 +]] +---@field screen_w integer? +--[[ +# Height component of the initial window size. +# +# Requires: desktop +[client] +(Screen height) 600 1 65535 +]] +---@field screen_h integer? +--[[ +# Whether the window is maximized. +# +# Requires: desktop +[client] +(Window maximized) false +]] +---@field window_maximized boolean? +--[[ +# Save window size automatically when modified. +# If true, screen size is saved in screen_w and screen_h, and whether the window +# is maximized is stored in window_maximized. +# (Autosaving window_maximized only works if compiled with SDL.) +# +# Requires: desktop +[client] +(Remember screen size) true +]] +---@field autosave_screensize boolean? +--[[ +# Fullscreen mode. +# +# Requires: desktop +[client] +(Full screen) false +]] +---@field fullscreen boolean? +--[[ +# Open the pause menu when the window's focus is lost. Does not pause if a formspec is +# open. +# +# Requires: desktop +[client] +(Pause on lost window focus) false +]] +---@field pause_on_lost_focus boolean? + +-- ---------------- [Graphics and Audio] [*Graphics] [**FPS] ---------------- -- + +---@class _.LuantiSettings.graphics_and_audio.graphics.fps +--[[ +# If FPS would go higher than this, limit it by sleeping +# to not waste CPU power for no benefit. +[client] +(Maximum FPS) 60 1 4294967295 +]] +---@field fps_max integer? +--[[ +# Vertical screen synchronization. Your system may still force VSync on even if this is disabled. +[client] +(VSync) false +]] +---@field vsync boolean? +--[[ +# Maximum FPS when the window is not focused. +[client] +(FPS when unfocused) 10 1 4294967295 +]] +---@field fps_max_unfocused integer? +--[[ +# View distance in nodes. +[client] +(Viewing range) 190 20 4000 +]] +---@field viewing_range integer? +--[[ +# Undersampling is similar to using a lower screen resolution, but it applies +# to the game world only, keeping the GUI intact. +# It should give a significant performance boost at the cost of less detailed image. +# Higher values result in a less detailed image. +# Note: Undersampling is currently not supported if the "3d_mode" setting is set +# to a non-default value. +[client] +(Undersampling) 1 1 8 +]] +---@field undersampling integer? + +-- ----------------- [Graphics and Audio] [*Graphics] [**3D] ---------------- -- + +--[[ +WIPDOC +]] +---@alias core.LuantiSettings.enums.3d_mode +--- | "none" +--- | "anaglyph" +--- | "interlaced" +--- | "topbottom" +--- | "sidebyside" +--- | "crossview" + +---@class _.LuantiSettings.graphics_and_audio.graphics.3d +--[[ +# 3D support. +# Currently supported: +# - none: no 3d output. +# - anaglyph: cyan/magenta color 3d. +# - interlaced: odd/even line based polarization screen support. +# - topbottom: split screen top/bottom. +# - sidebyside: split screen side by side. +# - crossview: Cross-eyed 3d +[client] +(3D mode) none none,anaglyph,interlaced,topbottom,sidebyside,crossview +]] +---@field ["3d_mode"] core.LuantiSettings.enums.3d_mode? +--[[ +# Strength of 3D mode parallax. +[client] +(3D mode parallax strength) 0.025 -0.087 0.087 +]] +---@field ["3d_paralax_strength"] number? + +-- -------------- [Graphics and Audio] [*Graphics] [**Bobbing] -------------- -- + +---@class _.LuantiSettings.graphics_and_audio.graphics.bobbing +--[[ +# Arm inertia, gives a more realistic movement of +# the arm when the camera moves. +[client] +(Arm inertia) true +]] +---@field arm_inertia boolean? +--[[ +# Enable view bobbing and amount of view bobbing. +# For example: 0 for no view bobbing; 1.0 for normal; 2.0 for double. +[client] +(View bobbing factor) 1.0 0.0 7.9 +]] +---@field view_bobbing_amount number? + +-- --------------- [Graphics and Audio] [*Graphics] [**Camera] -------------- -- + +---@class _.LuantiSettings.graphics_and_audio.graphics.camera +--[[ +# Field of view in degrees. +[client] +(Field of view) 72 45 160 +]] +---@field fov integer? +--[[ +# Alters the light curve by applying 'gamma correction' to it. +# Higher values make middle and lower light levels brighter. +# Value '1.0' leaves the light curve unaltered. +# This only has significant effect on daylight and artificial +# light, it has very little effect on natural night light. +[client] +(Light curve gamma) 1.0 0.33 3.0 +]] +---@field display_gamma number? +--[[ +# The strength (darkness) of node ambient-occlusion shading. +# Lower is darker, Higher is lighter. The valid range of values for this +# setting is 0.25 to 4.0 inclusive. If the value is out of range it will be +# set to the nearest valid value. +[client] +(Ambient occlusion gamma) 1.8 0.25 4.0 +]] +---@field ambient_occlusion_gamma number? + +-- ------------ [Graphics and Audio] [*Graphics] [**Screenshots] ------------ -- + +--[[ +WIPDOC +]] +---@alias core.LuantiSettings.enums.screenshot_format +--- | "png" +--- | "jpg" + +---@class _.LuantiSettings.graphics_and_audio.graphics.screenshots +--[[ +# Path to save screenshots at. Can be an absolute or relative path. +# The folder will be created if it doesn't already exist. +# +# Requires: desktop +[client] +(Screenshot folder) screenshots +]] +---@field screenshot_path core.LuantiSettings.path? +--[[ +# Format of screenshots. +# +# Requires: desktop +[client] +(Screenshot format) png png,jpg +]] +---@field screenshot_format core.LuantiSettings.enums.screenshot_format? +--[[ +# Screenshot quality. Only used for JPEG format. +# 1 means worst quality; 100 means best quality. +# Use 0 for default quality. +# +# Requires: desktop +[client] +(Screenshot quality) 0 0 100 +]] +---@field screenshot_quality integer? + +-- ---- [Graphics and Audio] [*Graphics] [**Node and Entity Highlighting] --- -- + +--[[ +WIPDOC +]] +---@alias core.LuantiSettings.enums.node_highlighting +--- | "box" +--- | "halo" +--- | "none" + +---@class _.LuantiSettings.graphics_and_audio.graphics.node_and_entity_highlighting +--[[ +# Method used to highlight selected object. +[client] +(Node highlighting) box box,halo,none +]] +---@field node_highlighting core.LuantiSettings.enums.node_highlighting? +--[[ +# Show entity selection boxes +# A restart is required after changing this. +[client] +(Show entity selection boxes) false +]] +---@field show_entity_selectionbox boolean? +--[[ +# Selection box border color (R,G,B). +[client] +(Selection box color) (0,0,0) +]] +---@field selectionbox_color string? +--[[ +# Width of the selection box lines around nodes. +[client] +(Selection box width) 2 1 5 +]] +---@field selectionbox_width integer? +--[[ +# Crosshair color (R,G,B). +# Also controls the object crosshair color +[client] +(Crosshair color) (255,255,255) +]] +---@field crosshair_color string? +--[[ +# Crosshair alpha (opaqueness, between 0 and 255). +# This also applies to the object crosshair. +[client] +(Crosshair alpha) 255 0 255 +]] +---@field crosshair_alpha integer? + +-- ---------------- [Graphics and Audio] [*Graphics] [**Fog] ---------------- -- + +---@class _.LuantiSettings.graphics_and_audio.graphics.fog +--[[ +# Whether to fog out the end of the visible area. +[client] +(Fog) true +]] +---@field enable_fog boolean? +--[[ +# Make fog and sky colors depend on daytime (dawn/sunset) and view direction. +# +# Requires: enable_fog +[client] +(Colored fog) true +]] +---@field directional_colored_fog boolean? +--[[ +# Fraction of the visible distance at which fog starts to be rendered +# +# Requires: enable_fog +[client] +(Fog start) 0.4 0.0 0.99 +]] +---@field fog_start number? + +-- --------------- [Graphics and Audio] [*Graphics] [**Clouds] -------------- -- + +---@class _.LuantiSettings.graphics_and_audio.graphics.clouds +--[[ +# Allow clouds to look 3D instead of flat. +[client] +(3D clouds) true +]] +---@field enable_3d_clouds boolean? +--[[ +# Use smooth cloud shading. +# +# Requires: enable_3d_clouds +[client] +(Soft clouds) false +]] +---@field soft_clouds boolean? + +-- ----- [Graphics and Audio] [*Graphics] [**Filtering and Antialiasing] ---- -- + +---@class _.LuantiSettings.graphics_and_audio.graphics.filtering_and_antialiasing +--[[ +# Use mipmaps when scaling textures. May slightly increase performance, +# especially when using a high-resolution texture pack. +# Gamma-correct downscaling is not supported. +[client] +(Mipmapping) false +]] +---@field mip_map boolean? +--[[ +# Use bilinear filtering when scaling textures. +[client] +(Bilinear filtering) false +]] +---@field bilinear_filter boolean? +--[[ +# Use trilinear filtering when scaling textures. +# If both bilinear and trilinear filtering are enabled, trilinear filtering +# is applied. +[client] +(Trilinear filtering) false +]] +---@field trilinear_filter boolean? +--[[ +# Use anisotropic filtering when looking at textures from an angle. +# This provides a significant improvement when used together with mipmapping. +[client] +(Anisotropic filtering) false +]] +---@field anisotropic_filter boolean? + +--[[ +WIPDOC +]] +---@alias core.LuantiSettings.enums.antialiasing +--- | "none" +--- | "fsaa" +--- | "fxaa" +--- | "ssaa" + +---@class _.LuantiSettings.graphics_and_audio.graphics.filtering_and_antialiasing +--[[ +# Select the antialiasing method to apply. +# +# * None - No antialiasing (default) +# +# * FSAA - Hardware-provided full-screen antialiasing +# A.K.A multi-sample antialiasing (MSAA) +# Smoothens out block edges but does not affect the insides of textures. +# +# If Post Processing is disabled, changing FSAA requires a restart. +# Also, if Post Processing is disabled, FSAA will not work together with +# undersampling or a non-default "3d_mode" setting. +# +# * FXAA - Fast approximate antialiasing +# Applies a post-processing filter to detect and smoothen high-contrast edges. +# Provides balance between speed and image quality. +# +# * SSAA - Super-sampling antialiasing +# Renders higher-resolution image of the scene, then scales down to reduce +# the aliasing effects. This is the slowest and the most accurate method. +[client] +(Antialiasing method) none none,fsaa,fxaa,ssaa +]] +---@field antialiasing core.LuantiSettings.enums.antialiasing? + +--[[ +WIPDOC +]] +---@alias core.LuantiSettings.enums.fsaa +--- | "2" +--- | "4" +--- | "8" +--- | "16" + +---@class _.LuantiSettings.graphics_and_audio.graphics.filtering_and_antialiasing +--[[ +# Defines the size of the sampling grid for FSAA and SSAA antialiasing methods. +# Value of 2 means taking 2x2 = 4 samples. +[client] +(Anti-aliasing scale) 2 2,4,8,16 +]] +---@field fsaa core.LuantiSettings.enums.fsaa? + +-- --------- [Graphics and Audio] [*Graphics] [**Occlusion Culling] --------- -- + +--[[ +WIPDOC +]] +---@alias core.LuantiSettings.enums.occlusion_culler +--- | "bfs" +--- | "loops" + +--[[ +WIPDOC +]] +---@class _.LuantiSettings.graphics_and_audio.graphics.occlusion_culling +--[[ +# Type of occlusion_culler +# +# "loops" is the legacy algorithm with nested loops and O(n³) complexity +# "bfs" is the new algorithm based on breadth-first-search and side culling +# +# This setting should only be changed if you have performance problems. +[client] +(Occlusion Culler) bfs bfs,loops +]] +---@field occlusion_culler core.LuantiSettings.enums.occlusion_culler? +--[[ +# Use raytraced occlusion culling in the new culler. +# This flag enables use of raytraced occlusion culling test for +# client mesh sizes smaller than 4x4x4 map blocks. +[client] +(Enable Raytraced Culling) true +]] +---@field enable_raytraced_culling boolean? + +-- --------------------- [Graphics and Audio] [*Effects] -------------------- -- + +--[[ +WIPDOC +]] +---@alias core.LuantiSettings.enums.leaves_style +--- | "fancy" +--- | "simple" +--- | "opaque" + +--[[ +WIPDOC +]] +---@class _.LuantiSettings.graphics_and_audio.effects +--[[ +# Allows liquids to be translucent. +[client] +(Translucent liquids) true +]] +---@field translucent_liquids boolean? +--[[ +# Leaves style: +# - Fancy: all faces visible +# - Simple: only outer faces +# - Opaque: disable transparency +[client] +(Leaves style) fancy fancy,simple,opaque +]] +---@field leaves_style core.LuantiSettings.enums.leaves_style? +--[[ +# Connects glass if supported by node. +[client] +(Connect glass) false +]] +---@field connected_glass boolean? +--[[ +# Enable smooth lighting with simple ambient occlusion. +[client] +(Smooth lighting) true +]] +---@field smooth_lighting boolean? +--[[ +# Enables tradeoffs that reduce CPU load or increase rendering performance +# at the expense of minor visual glitches that do not impact game playability. +[client] +(Tradeoffs for performance) false +]] +---@field performance_tradeoffs boolean? + + +-- ------------ [Graphics and Audio] [*Effects] [**Waving Nodes] ------------ -- + + +--[[ +WIPDOC +]] +---@class _.LuantiSettings.graphics_and_audio.effects.waving_nodes +--[[ +# Set to true to enable waving leaves. +[client] +(Waving leaves) false +]] +---@field enable_waving_leaves boolean? +--[[ +# Set to true to enable waving plants. +[client] +(Waving plants) false +]] +---@field enable_waving_plants boolean? +--[[ +# Set to true to enable waving liquids (like water). +[client] +(Waving liquids) false +]] +---@field enable_waving_water boolean? +--[[ +# The maximum height of the surface of waving liquids. +# 4.0 = Wave height is two nodes. +# 0.0 = Wave doesn't move at all. +# Default is 1.0 (1/2 node). +# +# Requires: enable_waving_water +[client] +(Waving liquids wave height) 1.0 0.0 4.0 +]] +---@field water_wave_height number? +--[[ +# Length of liquid waves. +# +# Requires: enable_waving_water +[client] +(Waving liquids wavelength) 20.0 0.1 +]] +---@field water_wave_length number? +--[[ +# How fast liquid waves will move. Higher = faster. +# If negative, liquid waves will move backwards. +# +# Requires: enable_waving_water +[client] +(Waving liquids wave speed) 5.0 +]] +---@field water_wave_speed number? + +-- ----------- [Graphics and Audio] [*Effects] [**Dynamic shadows] ---------- -- + +--[[ +WIPDOC +]] +---@class _.LuantiSettings.graphics_and_audio.effects.dynamic_shadows +--[[ +# Set to true to enable Shadow Mapping. +# +# Requires: opengl +[client] +(Dynamic shadows) false +]] +---@field enable_dynamic_shadows boolean? +--[[ +# Set the shadow strength gamma. +# Adjusts the intensity of in-game dynamic shadows. +# Lower value means lighter shadows, higher value means darker shadows. +# +# Requires: enable_dynamic_shadows, opengl +[client] +(Shadow strength gamma) 1.0 0.1 10.0 +]] +---@field shadow_strength_gamma number? +--[[ +# Maximum distance to render shadows. +# +# Requires: enable_dynamic_shadows, opengl +[client] +(Shadow map max distance in nodes to render shadows) 140.0 10.0 1000.0 +]] +---@field shadow_map_max_distance number? +--[[ +# Texture size to render the shadow map on. +# This must be a power of two. +# Bigger numbers create better shadows but it is also more expensive. +# +# Requires: enable_dynamic_shadows, opengl +[client] +(Shadow map texture size) 2048 128 8192 +]] +---@field shadow_map_texture_size integer? +--[[ +# Sets shadow texture quality to 32 bits. +# On false, 16 bits texture will be used. +# This can cause much more artifacts in the shadow. +# +# Requires: enable_dynamic_shadows, opengl +[client] +(Shadow map texture in 32 bits) true +]] +---@field shadow_map_texture_32bit boolean? + +--[[ +WIPDOC +]] +---@alias core.LuantiSettings.enums.shadow_filters +--- | "0" +--- | "1" +--- | "2" + +---@class _.LuantiSettings.graphics_and_audio.effects.dynamic_shadows +--[[ +# Define shadow filtering quality. +# This simulates the soft shadows effect by applying a PCF or Poisson disk +# but also uses more resources. +# +# Requires: enable_dynamic_shadows, opengl +[client] +(Shadow filter quality) 1 0,1,2 +]] +---@field shadow_filters core.LuantiSettings.enums.shadow_filters? +--[[ +# Enable colored shadows for transculent nodes. +# This is expensive. +# +# Requires: enable_dynamic_shadows, opengl +[client] +(Colored shadows) false +]] +---@field shadow_map_color boolean? +--[[ +# Set the soft shadow radius size. +# Lower values mean sharper shadows, bigger values mean softer shadows. +# Minimum value: 1.0; maximum value: 15.0 +# +# Requires: enable_dynamic_shadows, opengl +[client] +(Soft shadow radius) 5.0 1.0 15.0 +]] +---@field shadow_soft_radius number? +--[[ +# Set the default tilt of Sun/Moon orbit in degrees. +# Games may change orbit tilt via API. +# Value of 0 means no tilt / vertical orbit. +# +# Requires: enable_dynamic_shadows, opengl +[client] +(Sky Body Orbit Tilt) 0.0 -60.0 60.0 +]] +---@field shadow_sky_body_orbit_tilt number? + +-- ----------- [Graphics and Audio] [*Effects] [**Post Processing] ---------- -- + +--[[ +WIPDOC +]] +---@class _.LuantiSettings.graphics_and_audio.effects.post_processing +--[[ +# Enables the post processing pipeline. +[client] +(Enable Post Processing) true +]] +---@field enable_post_processing boolean? +--[[ +# Enables Hable's 'Uncharted 2' filmic tone mapping. +# Simulates the tone curve of photographic film and how this approximates the +# appearance of high dynamic range images. Mid-range contrast is slightly +# enhanced, highlights and shadows are gradually compressed. +# +# Requires: enable_post_processing +[client] +(Filmic tone mapping) false +]] +---@field tone_mapping boolean? +--[[ +# Enable automatic exposure correction +# When enabled, the post-processing engine will +# automatically adjust to the brightness of the scene, +# simulating the behavior of human eye. +# +# Requires: enable_post_processing +[client] +(Enable Automatic Exposure) false +]] +---@field enable_auto_exposure boolean? +--[[ +# Set the exposure compensation in EV units. +# Value of 0.0 (default) means no exposure compensation. +# Range: from -1 to 1.0 +# +# Requires: enable_post_processing, enable_auto_exposure +[client] +(Exposure compensation) 0.0 -1.0 1.0 +]] +---@field exposure_compensation number? +--[[ +# Apply dithering to reduce color banding artifacts. +# Dithering significantly increases the size of losslessly-compressed +# screenshots and it works incorrectly if the display or operating system +# performs additional dithering or if the color channels are not quantized +# to 8 bits. +# With OpenGL ES, dithering only works if the shader supports high +# floating-point precision and it may have a higher performance impact. +# +# Requires: enable_post_processing +[client] +(Enable Debanding) true +]] +---@field debanding boolean? +--[[ +# Set to true to enable bloom effect. +# Bright colors will bleed over the neighboring objects. +# +# Requires: enable_post_processing +[client] +(Enable Bloom) false +]] +---@field enable_bloom boolean? +--[[ +# Set to true to enable volumetric lighting effect (a.k.a. "Godrays"). +# +# Requires: enable_post_processing, enable_bloom +[client] +(Volumetric lighting) false +]] +---@field enable_volumetric_lighting boolean? + +-- ------------ [Graphics and Audio] [*Effects] [**Other Effects] ----------- -- + +--[[ +WIPDOC +]] +---@class _.LuantiSettings.graphics_and_audio.effects.other_effects +--[[ +# Simulate translucency when looking at foliage in the sunlight. +# +# Requires: enable_dynamic_shadows +[client] +(Translucent foliage) false +]] +---@field enable_translucent_foliage boolean? +--[[ +# When enabled, liquid reflections are simulated. +# +# Requires: enable_waving_water, enable_dynamic_shadows +[client] +(Liquid reflections) false +]] +---@field enable_water_reflections boolean? + +-- ---------------------- [Graphics and Audio] [*Audio] --------------------- -- + +--[[ +WIPDOC +]] +---@class _.LuantiSettings.graphics_and_audio.audio +--[[ +# Volume of all sounds. +# Requires the sound system to be enabled. +[client] +(Volume) 0.8 0.0 1.0 +]] +---@field sound_volume number? +--[[ +# Volume multiplier when the window is unfocused. +[client] +(Volume when unfocused) 0.3 0.0 1.0 +]] +---@field sound_volume_unfocused number? +--[[ +# Whether to mute sounds. You can unmute sounds at any time. +# In-game, you can toggle the mute state with the mute key or by using the +# pause menu. +[client] +(Mute sound) false +]] +---@field mute_sound boolean? + +-- ----------------- [Graphics and Audio] [*User Interfaces] ---------------- -- + +--[[ +WIPDOC +]] +---@alias core.LuantiSettings.enums.language +--- | "be" +--- | "bg" +--- | "ca" +--- | "cs" +--- | "da" +--- | "de" +--- | "el" +--- | "en" +--- | "eo" +--- | "es" +--- | "et" +--- | "eu" +--- | "fi" +--- | "fr" +--- | "gd" +--- | "gl" +--- | "hu" +--- | "id" +--- | "it" +--- | "ja" +--- | "jbo" +--- | "kk" +--- | "ko" +--- | "lt" +--- | "lv" +--- | "ms" +--- | "nb" +--- | "nl" +--- | "nn" +--- | "pl" +--- | "pt" +--- | "pt_BR" +--- | "ro" +--- | "ru" +--- | "sk" +--- | "sl" +--- | "sr_Cyrl" +--- | "sr_Latn" +--- | "sv" +--- | "sw" +--- | "tr" +--- | "uk" +--- | "vi" +--- | "zh_CN" +--- | "zh_TW" + +--[[ +WIPDOC +]] +---@class _.LuantiSettings.graphics_and_audio.user_interface +--[[ +# Set the language. By default, the system language is used. +# A restart is required after changing this. +[client] +(Language) ,be,bg,ca,cs,da,de,el,en,eo,es,et,eu,fi,fr,gd,gl,hu,id,it,ja,jbo,kk,ko,lt,lv,ms,nb,nl,nn,pl,pt,pt_BR,ro,ru,sk,sl,sr_Cyrl,sr_Latn,sv,sw,tr,uk,vi,zh_CN,zh_TW +]] +---@field language core.LuantiSettings.enums.language? + +-- ------------- [Graphics and Audio] [*User Interface] [**GUI] ------------- -- + +--[[ +WIPDOC +]] +---@class _.LuantiSettings.graphics_and_audio.user_interface.gui +--[[ +# When enabled, the GUI is optimized to be more usable on touchscreens. +# Whether this is enabled by default depends on your hardware form-factor. +[client] +(Optimize GUI for touchscreens) false +]] +---@field touch_gui boolean? +--[[ +# Scale GUI by a user specified value. +# Use a nearest-neighbor-anti-alias filter to scale the GUI. +# This will smooth over some of the rough edges, and blend +# pixels when scaling down, at the cost of blurring some +# edge pixels when images are scaled by non-integer sizes. +[client] +(GUI scaling) 1.0 0.5 20 +]] +---@field gui_scaling number? +--[[ +# Enables smooth scrolling. +[client] +(Smooth scrolling) true +]] +---@field smooth_scrolling boolean? +--[[ +# Enables animation of inventory items. +[client] +(Inventory items animations) false +]] +---@field inventory_items_animations boolean? +--[[ +# Formspec full-screen background opacity (between 0 and 255). +[client] +(Formspec Full-Screen Background Opacity) 140 0 255 +]] +---@field formspec_fullscreen_bg_opacity integer? +--[[ +# Formspec full-screen background color (R,G,B). +[client] +(Formspec Full-Screen Background Color) (0,0,0) +]] +---@field formspec_fullscreen_bg_color string? +--[[ +# When gui_scaling_filter is true, all GUI images need to be +# filtered in software, but some images are generated directly +# to hardware (e.g. render-to-texture for nodes in inventory). +[client] +(GUI scaling filter) false +]] +---@field gui_scaling_filter boolean? +--[[ +# Delay showing tooltips, stated in milliseconds. +[client] +(Tooltip delay) 400 0 18446744073709551615 +]] +---@field tooltip_show_delay integer? +--[[ +# Append item name to tooltip. +[client] +(Append item name) false +]] +---@field tooltip_append_itemname boolean? +--[[ +# Use a cloud animation for the main menu background. +[client] +(Clouds in menu) true +]] +---@field menu_clouds boolean? + +-- ------------- [Graphics and Audio] [*User Interface] [**HUD] ------------- -- + +--[[ +WIPDOC +]] +---@class _.LuantiSettings.graphics_and_audio.user_interface.hud +--[[ +# Modifies the size of the HUD elements. +[client] +(HUD scaling) 1.0 0.5 20 +]] +---@field hud_scaling number? +--[[ +# Whether name tag backgrounds should be shown by default. +# Mods may still set a background. +[client] +(Show name tag backgrounds by default) true +]] +---@field show_nametag_backgrounds boolean? +--[[ +# Whether to show the client debug info (has the same effect as hitting F5). +[client] +(Show debug info) false +]] +---@field show_debug boolean? +--[[ +# Radius to use when the block bounds HUD feature is set to near blocks. +[client] +(Block bounds HUD radius) 4 0 1000 +]] +---@field show_block_bounds_radius_near integer? +--[[ +# Maximum proportion of current window to be used for hotbar. +# Useful if there's something to be displayed right or left of hotbar. +[client] +(Maximum hotbar width) 1.0 0.001 1.0 +]] +---@field hud_hotbar_max_width number? + +-- ------------- [Graphics and Audio] [*User Interface] [**Chat] ------------ -- + +--[[ +WIPDOC +]] +---@class _.LuantiSettings.graphics_and_audio.user_interface.chat +--[[ +# Maximum number of recent chat messages to show +[client] +(Recent Chat Messages) 6 2 20 +]] +---@field recent_chat_messages integer? +--[[ +# In-game chat console height, between 0.1 (10%) and 1.0 (100%). +[client] +(Console height) 0.6 0.1 1.0 +]] +---@field console_height number? +--[[ +# In-game chat console background color (R,G,B). +[client] +(Console color) (0,0,0) +]] +---@field console_color string? +--[[ +# In-game chat console background alpha (opaqueness, between 0 and 255). +[client] +(Console alpha) 200 0 255 +]] +---@field console_alpha integer? +--[[ +# Optional override for chat weblink color. +[client] +(Weblink color) #8888FF +]] +---@field chat_weblink_color string? +--[[ +# Font size of the recent chat text and chat prompt in point (pt). +# Value 0 will use the default font size. +[client] +(Chat font size) 0 0 72 +]] +---@field chat_font_size integer? + + +-- ------ [Graphics and Audio] [*User Interface] [**Content Repository] ----- -- + +--[[ +WIPDOC +]] +---@class _.LuantiSettings.graphics_and_audio.user_interfaces.content_repository +--[[ +# The URL for the content repository +[client] +(ContentDB URL) https://content.luanti.org +]] +---@field contentdb_url string? +--[[ +# If enabled and you have ContentDB packages installed, Luanti may contact ContentDB to +# check for package updates when opening the mainmenu. +[client] +(Enable updates available indicator on content tab) true +]] +---@field contentdb_enable_updates_indicator boolean? +--[[ +# Comma-separated list of flags to hide in the content repository. +# "nonfree" can be used to hide packages which do not qualify as 'free software', +# as defined by the Free Software Foundation. +# You can also specify content ratings. +# These flags are independent from Luanti versions, +# so see a full list at https://content.luanti.org/help/content_flags/ +[client] +(ContentDB Flag Blacklist) nonfree, desktop_default +]] +---@field contentdb_flag_blacklist string? +--[[ +# Maximum number of concurrent downloads. Downloads exceeding this limit will be queued. +# This should be lower than curl_parallel_limit. +[client] +(ContentDB Max Concurrent Downloads) 3 1 +]] +---@field contentdb_max_concurrent_downloads integer? \ No newline at end of file diff --git a/types/luanti_lsp_definitions/library/classes/Settings/LuantiSettings/mapgen.lua b/types/luanti_lsp_definitions/library/classes/Settings/LuantiSettings/mapgen.lua new file mode 100644 index 00000000..1998e7e9 --- /dev/null +++ b/types/luanti_lsp_definitions/library/classes/Settings/LuantiSettings/mapgen.lua @@ -0,0 +1,1888 @@ +---@meta _ +-- DRAFT 1 DONE +-- builtin/settingtypes.txt +-- minetest.conf.example + +-- Section context mapping: +-- * [Mapgen]: [world_creation] + +---@alias _.LuantiSettings.mapgen.keys.noise_params.2d +--- | "mg_biome_np_heat" +--- | "mg_biome_np_heat_blend" +--- | "mg_biome_np_humidity" +--- | "mg_biome_np_humidity_blend" +--- | "mgv5_np_filler_depth" +--- | "mgv5_np_factor" +--- | "mgv5_np_height" +--- | "mgv6_np_terrain_base" +--- | "mgv6_np_terrain_higher" +--- | "mgv6_np_steepness" +--- | "mgv6_np_height_select" +--- | "mgv6_np_mud" +--- | "mgv6_np_beach" +--- | "mgv6_np_biome" +--- | "mgv6_np_cave" +--- | "mgv6_np_humidity" +--- | "mgv6_np_trees" +--- | "mgv6_np_apple_trees" +--- | "mgv7_np_terrain_base" +--- | "mgv7_np_terrain_alt" +--- | "mgv7_np_terrain_persist" +--- | "mgv7_np_height_select" +--- | "mgv7_np_filler_depth" +--- | "mgv7_np_mount_height" +--- | "mgv7_np_ridge_uwater" +--- | "mgcarpathian_np_filler_depth" +--- | "mgcarpathian_np_height1" +--- | "mgcarpathian_np_height2" +--- | "mgcarpathian_np_height3" +--- | "mgcarpathian_np_height4" +--- | "mgcarpathian_np_hills_terrain" +--- | "mgcarpathian_np_ridge_terrain" +--- | "mgcarpathian_np_step_terrain" +--- | "mgcarpathian_np_hills" +--- | "mgcarpathian_np_ridge_mnt" +--- | "mgcarpathian_np_step_mnt" +--- | "mgcarpathian_np_rivers" +--- | "mgflat_np_terrain" +--- | "mgflat_np_filler_depth" +--- | "mgfractal_np_seabed" +--- | "mgfractal_np_filler_depth" +--- | "mgvalleys_np_filler_depth" +--- | "mgvalleys_np_rivers" +--- | "mgvalleys_np_terrain_height" +--- | "mgvalleys_np_valley_depth" +--- | "mgvalleys_np_valley_profile" +--- | "mgvalleys_np_inter_valley_slope" + +---@alias _.LuantiSettings.mapgen.keys.noise_params.3d +--- | "mgv5_np_cave1" +--- | "mgv5_np_cave2" +--- | "mgv5_np_cavern" +--- | "mgv5_np_ground" +--- | "mgv5_np_dungeons" +--- | "mgv7_np_mountain" +--- | "mgv7_np_ridge" +--- | "mgv7_np_floatland" +--- | "mgv7_np_cavern" +--- | "mgv7_np_cave1" +--- | "mgv7_np_cave2" +--- | "mgv7_np_dungeons" +--- | "mgcarpathian_np_mnt_var" +--- | "mgcarpathian_np_cave1" +--- | "mgcarpathian_np_cave2" +--- | "mgcarpathian_np_cavern" +--- | "mgcarpathian_np_dungeons" +--- | "mgflat_np_cave1" +--- | "mgflat_np_cave2" +--- | "mgflat_np_cavern" +--- | "mgflat_np_dungeons" +--- | "mgfractal_np_cave1" +--- | "mgfractal_np_cave2" +--- | "mgfractal_np_dungeons" +--- | "mgvalleys_np_cave1" +--- | "mgvalleys_np_cave2" +--- | "mgvalleys_np_cavern" +--- | "mgvalleys_np_inter_valley_fill" +--- | "mgvalleys_np_dungeons" + +---@alias _.LuantiSettings.mapgen.keys.vector +--- | "mgfractal_scale" +--- | "mgfractal_offset" + +---@alias _.LuantiSettings.mapgen.keys +--- | "fixed_map_seed" +--- | "mg_name" +--- | "water_level" +--- | "max_block_generate_distance" +--- | "mapgen_limit" +--- | "mg_flags" +--- | "mg_biome_np_heat" +--- | "mg_biome_np_heat_blend" +--- | "mg_biome_np_humidity" +--- | "mg_biome_np_humidity_blend" +--- | "mgv5_spflags" +--- | "mgv5_cave_width" +--- | "mgv5_large_cave_depth" +--- | "mgv5_small_cave_num_min" +--- | "mgv5_small_cave_num_max" +--- | "mgv5_large_cave_num_min" +--- | "mgv5_large_cave_num_max" +--- | "mgv5_large_cave_flooded" +--- | "mgv5_cavern_limit" +--- | "mgv5_cavern_taper" +--- | "mgv5_cavern_threshold" +--- | "mgv5_dungeon_ymin" +--- | "mgv5_dungeon_ymax" +--- | "mgv5_np_filler_depth" +--- | "mgv5_np_factor" +--- | "mgv5_np_height" +--- | "mgv5_np_cave1" +--- | "mgv5_np_cave2" +--- | "mgv5_np_cavern" +--- | "mgv5_np_ground" +--- | "mgv5_np_dungeons" +--- | "mgv6_spflags" +--- | "mgv6_freq_desert" +--- | "mgv6_freq_beach" +--- | "mgv6_dungeon_ymin" +--- | "mgv6_dungeon_ymax" +--- | "mgv6_np_terrain_base" +--- | "mgv6_np_terrain_higher" +--- | "mgv6_np_steepness" +--- | "mgv6_np_height_select" +--- | "mgv6_np_mud" +--- | "mgv6_np_beach" +--- | "mgv6_np_biome" +--- | "mgv6_np_cave" +--- | "mgv6_np_humidity" +--- | "mgv6_np_trees" +--- | "mgv6_np_apple_trees" +--- | "mgv7_spflags" +--- | "mgv7_mount_zero_level" +--- | "mgv7_floatland_ymin" +--- | "mgv7_floatland_ymax" +--- | "mgv7_floatland_taper" +--- | "mgv7_float_taper_exp" +--- | "mgv7_floatland_density" +--- | "mgv7_floatland_ywater" +--- | "mgv7_cave_width" +--- | "mgv7_large_cave_depth" +--- | "mgv7_small_cave_num_min" +--- | "mgv7_small_cave_num_max" +--- | "mgv7_large_cave_num_min" +--- | "mgv7_large_cave_num_max" +--- | "mgv7_large_cave_flooded" +--- | "mgv7_cavern_limit" +--- | "mgv7_cavern_taper" +--- | "mgv7_cavern_threshold" +--- | "mgv7_dungeon_ymin" +--- | "mgv7_dungeon_ymax" +--- | "mgv7_np_terrain_base" +--- | "mgv7_np_terrain_alt" +--- | "mgv7_np_terrain_persist" +--- | "mgv7_np_height_select" +--- | "mgv7_np_filler_depth" +--- | "mgv7_np_mount_height" +--- | "mgv7_np_ridge_uwater" +--- | "mgv7_np_mountain" +--- | "mgv7_np_ridge" +--- | "mgv7_np_floatland" +--- | "mgv7_np_cavern" +--- | "mgv7_np_cave1" +--- | "mgv7_np_cave2" +--- | "mgv7_np_dungeons" +--- | "mgcarpathian_spflags" +--- | "mgcarpathian_base_level" +--- | "mgcarpathian_river_width" +--- | "mgcarpathian_river_depth" +--- | "mgcarpathian_valley_width" +--- | "mgcarpathian_cave_width" +--- | "mgcarpathian_large_cave_depth" +--- | "mgcarpathian_small_cave_num_min" +--- | "mgcarpathian_small_cave_num_max" +--- | "mgcarpathian_large_cave_num_min" +--- | "mgcarpathian_large_cave_num_max" +--- | "mgcarpathian_large_cave_flooded" +--- | "mgcarpathian_cavern_limit" +--- | "mgcarpathian_cavern_taper" +--- | "mgcarpathian_cavern_threshold" +--- | "mgcarpathian_dungeon_ymin" +--- | "mgcarpathian_dungeon_ymax" +--- | "mgcarpathian_np_filler_depth" +--- | "mgcarpathian_np_height1" +--- | "mgcarpathian_np_height2" +--- | "mgcarpathian_np_height3" +--- | "mgcarpathian_np_height4" +--- | "mgcarpathian_np_hills_terrain" +--- | "mgcarpathian_np_ridge_terrain" +--- | "mgcarpathian_np_step_terrain" +--- | "mgcarpathian_np_hills" +--- | "mgcarpathian_np_ridge_mnt" +--- | "mgcarpathian_np_step_mnt" +--- | "mgcarpathian_np_rivers" +--- | "mgcarpathian_np_mnt_var" +--- | "mgcarpathian_np_cave1" +--- | "mgcarpathian_np_cave2" +--- | "mgcarpathian_np_cavern" +--- | "mgcarpathian_np_dungeons" +--- | "mgflat_spflags" +--- | "mgflat_ground_level" +--- | "mgflat_large_cave_depth" +--- | "mgflat_small_cave_num_min" +--- | "mgflat_small_cave_num_max" +--- | "mgflat_large_cave_num_min" +--- | "mgflat_large_cave_num_max" +--- | "mgflat_large_cave_flooded" +--- | "mgflat_cave_width" +--- | "mgflat_lake_threshold" +--- | "mgflat_lake_steepness" +--- | "mgflat_hill_threshold" +--- | "mgflat_hill_steepness" +--- | "mgflat_cavern_limit" +--- | "mgflat_cavern_taper" +--- | "mgflat_cavern_threshold" +--- | "mgflat_dungeon_ymin" +--- | "mgflat_dungeon_ymax" +--- | "mgflat_np_terrain" +--- | "mgflat_np_filler_depth" +--- | "mgflat_np_cave1" +--- | "mgflat_np_cave2" +--- | "mgflat_np_cavern" +--- | "mgflat_np_dungeons" +--- | "mgfractal_spflags" +--- | "mgfractal_cave_width" +--- | "mgfractal_large_cave_depth" +--- | "mgfractal_small_cave_num_min" +--- | "mgfractal_small_cave_num_max" +--- | "mgfractal_large_cave_num_min" +--- | "mgfractal_large_cave_num_max" +--- | "mgfractal_large_cave_flooded" +--- | "mgfractal_dungeon_ymin" +--- | "mgfractal_dungeon_ymax" +--- | "mgfractal_fractal" +--- | "mgfractal_iterations" +--- | "mgfractal_scale" +--- | "mgfractal_offset" +--- | "mgfractal_slice_w" +--- | "mgfractal_julia_x" +--- | "mgfractal_julia_y" +--- | "mgfractal_julia_z" +--- | "mgfractal_julia_w" +--- | "mgfractal_np_seabed" +--- | "mgfractal_np_filler_depth" +--- | "mgfractal_np_cave1" +--- | "mgfractal_np_cave2" +--- | "mgfractal_np_dungeons" +--- | "mgvalleys_spflags" +--- | "mgvalleys_altitude_chill" +--- | "mgvalleys_large_cave_depth" +--- | "mgvalleys_small_cave_num_min" +--- | "mgvalleys_small_cave_num_max" +--- | "mgvalleys_large_cave_num_min" +--- | "mgvalleys_large_cave_num_max" +--- | "mgvalleys_large_cave_flooded" +--- | "mgvalleys_cavern_limit" +--- | "mgvalleys_cavern_taper" +--- | "mgvalleys_cavern_threshold" +--- | "mgvalleys_river_depth" +--- | "mgvalleys_river_size" +--- | "mgvalleys_cave_width" +--- | "mgvalleys_dungeon_ymin" +--- | "mgvalleys_dungeon_ymax" +--- | "mgvalleys_np_cave1" +--- | "mgvalleys_np_cave2" +--- | "mgvalleys_np_filler_depth" +--- | "mgvalleys_np_cavern" +--- | "mgvalleys_np_rivers" +--- | "mgvalleys_np_terrain_height" +--- | "mgvalleys_np_valley_depth" +--- | "mgvalleys_np_inter_valley_fill" +--- | "mgvalleys_np_valley_profile" +--- | "mgvalleys_np_inter_valley_slope" +--- | "mgvalleys_np_dungeons" + +---@class _.LuantiSettings.mapgen.tablefmt : _.LuantiSettings.mapgen, _.LuantiSettings.mapgen.biome_api, _.LuantiSettings.mapgen.mapgen_v5, _.LuantiSettings.mapgen.mapgen_v5.noises, _.LuantiSettings.mapgen.mapgen_v6, _.LuantiSettings.mapgen.mapgen_v6.noises, _.LuantiSettings.mapgen.mapgen_v7, _.LuantiSettings.mapgen.mapgen_v7.noises, _.LuantiSettings.mapgen.mapgen_carpathian, _.LuantiSettings.mapgen.mapgen_carpathian.noises, _.LuantiSettings.mapgen.mapgen_flat, _.LuantiSettings.mapgen.mapgen_flat.noises, _.LuantiSettings.mapgen.mapgen_fractal, _.LuantiSettings.mapgen.mapgen_fractal.noises, _.LuantiSettings.mapgen.mapgen_valleys, _.LuantiSettings.mapgen.mapgen_valleys.noises + +-- -------------------------------- [Mapgen] -------------------------------- -- + +--[[ +WIPDOC +]] +---@alias core.LuantiSettings.enums.mg_name +--- | "v7" +--- | "valleys" +--- | "carpathian" +--- | "v5" +--- | "flat" +--- | "fractal" +--- | "singlenode" +--- | "v6" + +---@class _.LuantiSettings.mapgen +--[[ +# A chosen map seed for a new map, leave empty for random. +# Will be overridden when creating a new world in the main menu. +[world_creation] +(Fixed map seed) +]] +---@field fixed_map_seed string? +--[[ +# Name of map generator to be used when creating a new world. +# Creating a world in the main menu will override this. +# Current mapgens in a highly unstable state: +# - The optional floatlands of v7 (disabled by default). +[world_creation] +(Mapgen name) v7 v7,valleys,carpathian,v5,flat,fractal,singlenode,v6 +]] +---@field mg_name core.LuantiSettings.enums.mg_name? +--[[ +# Water surface level of the world. +[world_creation] +(Water level) 1 -31000 31000 +]] +---@field water_level integer? +--[[ +# From how far blocks are generated for clients, stated in mapblocks (16 nodes). +[world_creation] +(Max block generate distance) [server] 10 1 32767 +]] +---@field max_block_generate_distance integer? +--[[ +# Limit of map generation, in nodes, in all 6 directions from (0, 0, 0). +# Only mapchunks completely within the mapgen limit are generated. +# Value is stored per-world. +[world_creation] +(Map generation limit) 31007 0 31007 +]] +---@field mapgen_limit integer? + +--[[ +WIPDOC +]] +---@class core.LuantiSettings.flags.mg_flags +--[[ +WIPDOC +]] +---@field caves boolean? +--[[ +WIPDOC +]] +---@field nocaves boolean? +--[[ +WIPDOC +]] +---@field dungeons boolean? +--[[ +WIPDOC +]] +---@field nodungeons boolean? +--[[ +WIPDOC +]] +---@field light boolean? +--[[ +WIPDOC +]] +---@field nolight boolean? +--[[ +WIPDOC +]] +---@field decorations boolean? +--[[ +WIPDOC +]] +---@field nodecorations boolean? +--[[ +WIPDOC +]] +---@field biomes boolean? +--[[ +WIPDOC +]] +---@field nobiomes boolean? +--[[ +WIPDOC +]] +---@field ores boolean? +--[[ +WIPDOC +]] +---@field noores boolean? + +---@class _.LuantiSettings.mapgen +--[[ +# Global map generation attributes. +# In Mapgen v6 the 'decorations' flag controls all decorations except trees +# and jungle grass, in all other mapgens this flag controls all decorations. +[world_creation] +(Mapgen flags) caves,dungeons,light,decorations,biomes,ores caves,dungeons,light,decorations,biomes,ores +]] +---@field mg_flags core.LuantiSettings.flags? + +-- -------------------------- [Mapgen] [*Biome API] ------------------------- -- + +---@class _.LuantiSettings.mapgen.biome_api +--[[ +# Temperature variation for biomes. +[world_creation] +(Heat noise) 50, 50, (1000, 1000, 1000), 5349, 3, 0.5, 2.0, eased +]] +---@field mg_biome_np_heat core.NoiseParams.2d? +--[[ +# Small-scale temperature variation for blending biomes on borders. +[world_creation] +(Heat blend noise) 0, 1.5, (8, 8, 8), 13, 2, 1.0, 2.0, eased +]] +---@field mg_biome_np_heat_blend core.NoiseParams.2d? +--[[ +# Humidity variation for biomes. +[world_creation] +(Humidity noise) 50, 50, (1000, 1000, 1000), 842, 3, 0.5, 2.0, eased +]] +---@field mg_biome_np_humidity core.NoiseParams.2d? +--[[ +# Small-scale humidity variation for blending biomes on borders. +[world_creation] +(Humidity blend noise) 0, 1.5, (8, 8, 8), 90003, 2, 1.0, 2.0, eased +]] +---@field mg_biome_np_humidity_blend core.NoiseParams.2d? + +-- -------------------------- [Mapgen] [*Mapgen V5] ------------------------- -- + +--[[ +WIPDOC +]] +---@class core.LuantiSettings.flags.mgv5_spflags +--[[ +WIPDOC +]] +---@field caverns boolean? +--[[ +WIPDOC +]] +---@field nocaverns boolean? + +---@class _.LuantiSettings.mapgen.mapgen_v5 +--[[ +# Map generation attributes specific to Mapgen v5. +[world_creation] +(Mapgen V5 specific flags) caverns caverns +]] +---@field mgv5_spflags core.LuantiSettings.flags? +--[[ +# Controls width of tunnels, a smaller value creates wider tunnels. +# Value >= 10.0 completely disables generation of tunnels and avoids the +# intensive noise calculations. +[world_creation] +(Cave width) 0.09 +]] +---@field mgv5_cave_width number? +--[[ +# Y of upper limit of large caves. +[world_creation] +(Large cave depth) -256 -31000 31000 +]] +---@field mgv5_large_cave_depth integer? +--[[ +# Minimum limit of random number of small caves per mapchunk. +[world_creation] +(Small cave minimum number) 0 0 256 +]] +---@field mgv5_small_cave_num_min integer? +--[[ +# Maximum limit of random number of small caves per mapchunk. +[world_creation] +(Small cave maximum number) 0 0 256 +]] +---@field mgv5_small_cave_num_max integer? +--[[ +# Minimum limit of random number of large caves per mapchunk. +[world_creation] +(Large cave minimum number) 0 0 64 +]] +---@field mgv5_large_cave_num_min integer? +--[[ +# Maximum limit of random number of large caves per mapchunk. +[world_creation] +(Large cave maximum number) 2 0 64 +]] +---@field mgv5_large_cave_num_max integer? +--[[ +# Proportion of large caves that contain liquid. +[world_creation] +(Large cave proportion flooded) 0.5 0.0 1.0 +]] +---@field mgv5_large_cave_flooded number? +--[[ +# Y-level of cavern upper limit. +[world_creation] +(Cavern limit) -256 -31000 31000 +]] +---@field mgv5_cavern_limit integer? +--[[ +# Y-distance over which caverns expand to full size. +[world_creation] +(Cavern taper) 256 0 32767 +]] +---@field mgv5_cavern_taper integer? +--[[ +# Defines full size of caverns, smaller values create larger caverns. +[world_creation] +(Cavern threshold) 0.7 +]] +---@field mgv5_cavern_threshold number? +--[[ +# Lower Y limit of dungeons. +[world_creation] +(Dungeon minimum Y) -31000 -31000 31000 +]] +---@field mgv5_dungeon_ymin integer? +--[[ +# Upper Y limit of dungeons. +[world_creation] +(Dungeon maximum Y) 31000 -31000 31000 +]] +---@field mgv5_dungeon_ymax integer? + +-- -------------------- [Mapgen] [*Mapgen V5] [**Noises] -------------------- -- + +---@class _.LuantiSettings.mapgen.mapgen_v5.noises +--[[ +# Variation of biome filler depth. +[world_creation] +(Filler depth noise) 0, 1, (150, 150, 150), 261, 4, 0.7, 2.0, eased +]] +---@field mgv5_np_filler_depth core.NoiseParams.2d? +--[[ +# Variation of terrain vertical scale. +# When noise is < -0.55 terrain is near-flat. +[world_creation] +(Factor noise) 0, 1, (250, 250, 250), 920381, 3, 0.45, 2.0, eased +]] +---@field mgv5_np_factor core.NoiseParams.2d? +--[[ +# Y-level of average terrain surface. +[world_creation] +(Height noise) 0, 10, (250, 250, 250), 84174, 4, 0.5, 2.0, eased +]] +---@field mgv5_np_height core.NoiseParams.2d? +--[[ +# First of two 3D noises that together define tunnels. +[world_creation] +(Cave1 noise) 0, 12, (61, 61, 61), 52534, 3, 0.5, 2.0 +]] +---@field mgv5_np_cave1 core.NoiseParams.3d? +--[[ +# Second of two 3D noises that together define tunnels. +[world_creation] +(Cave2 noise) 0, 12, (67, 67, 67), 10325, 3, 0.5, 2.0 +]] +---@field mgv5_np_cave2 core.NoiseParams.3d? +--[[ +# 3D noise defining giant caverns. +[world_creation] +(Cavern noise) 0, 1, (384, 128, 384), 723, 5, 0.63, 2.0 +]] +---@field mgv5_np_cavern core.NoiseParams.3d? +--[[ +# 3D noise defining terrain. +[world_creation] +(Ground noise) 0, 40, (80, 80, 80), 983240, 4, 0.55, 2.0, eased +]] +---@field mgv5_np_ground core.NoiseParams.3d? +--[[ +# 3D noise that determines number of dungeons per mapchunk. +[world_creation] +(Dungeon noise) 0.9, 0.5, (500, 500, 500), 0, 2, 0.8, 2.0 +]] +---@field mgv5_np_dungeons core.NoiseParams.3d? + +-- -------------------------- [Mapgen] [*Mapgen V6] ------------------------- -- + +--[[ +WIPDOC +]] +---@class core.LuantiSettings.flags.mgv6_spflags +--[[ +WIPDOC +]] +---@field jungles boolean? +--[[ +WIPDOC +]] +---@field nojungles boolean? +--[[ +WIPDOC +]] +---@field biomeblend boolean? +--[[ +WIPDOC +]] +---@field nobiomeblend boolean? +--[[ +WIPDOC +]] +---@field mudflow boolean? +--[[ +WIPDOC +]] +---@field nomudflow boolean? +--[[ +WIPDOC +]] +---@field snowbiomes boolean? +--[[ +WIPDOC +]] +---@field nosnowbiomes boolean? +--[[ +WIPDOC +]] +---@field flat boolean? +--[[ +WIPDOC +]] +---@field noflat boolean? +--[[ +WIPDOC +]] +---@field trees boolean? +--[[ +WIPDOC +]] +---@field notrees boolean? +--[[ +WIPDOC +]] +---@field temples boolean? +--[[ +WIPDOC +]] +---@field notemples boolean? + +---@class _.LuantiSettings.mapgen.mapgen_v6 +--[[ +# Map generation attributes specific to Mapgen v6. +# The 'snowbiomes' flag enables the new 5 biome system. +# When the 'snowbiomes' flag is enabled jungles are automatically enabled and +# the 'jungles' flag is ignored. +# The 'temples' flag disables generation of desert temples. Normal dungeons will appear instead. +[world_creation] +(Mapgen V6 specific flags) jungles,biomeblend,mudflow,snowbiomes,noflat,trees,temples jungles,biomeblend,mudflow,snowbiomes,flat,trees,temples +]] +---@field mgv6_spflags core.LuantiSettings.flags? +--[[ +# Deserts occur when np_biome exceeds this value. +# When the 'snowbiomes' flag is enabled, this is ignored. +[world_creation] +(Desert noise threshold) 0.45 +]] +---@field mgv6_freq_desert number? +--[[ +# Sandy beaches occur when np_beach exceeds this value. +[world_creation] +(Beach noise threshold) 0.15 +]] +---@field mgv6_freq_beach number? +--[[ +# Lower Y limit of dungeons. +[world_creation] +(Dungeon minimum Y) -31000 -31000 31000 +]] +---@field mgv6_dungeon_ymin integer? +--[[ +# Upper Y limit of dungeons. +[world_creation] +(Dungeon maximum Y) 31000 -31000 31000 +]] +---@field mgv6_dungeon_ymax integer? + +-- -------------------- [Mapgen] [*Mapgen V6] [**Noises] -------------------- -- + +---@class _.LuantiSettings.mapgen.mapgen_v6.noises +--[[ +# Y-level of lower terrain and seabed. +[world_creation] +(Terrain base noise) -4, 20, (250, 250, 250), 82341, 5, 0.6, 2.0, eased +]] +---@field mgv6_np_terrain_base core.NoiseParams.2d? +--[[ +# Y-level of higher terrain that creates cliffs. +[world_creation] +(Terrain higher noise) 20, 16, (500, 500, 500), 85039, 5, 0.6, 2.0, eased +]] +---@field mgv6_np_terrain_higher core.NoiseParams.2d? +--[[ +# Varies steepness of cliffs. +[world_creation] +(Steepness noise) 0.85, 0.5, (125, 125, 125), -932, 5, 0.7, 2.0, eased +]] +---@field mgv6_np_steepness core.NoiseParams.2d? +--[[ +# Defines distribution of higher terrain. +[world_creation] +(Height select noise) 0.5, 1, (250, 250, 250), 4213, 5, 0.69, 2.0, eased +]] +---@field mgv6_np_height_select core.NoiseParams.2d? +--[[ +# Varies depth of biome surface nodes. +[world_creation] +(Mud noise) 4, 2, (200, 200, 200), 91013, 3, 0.55, 2.0, eased +]] +---@field mgv6_np_mud core.NoiseParams.2d? +--[[ +# Defines areas with sandy beaches. +[world_creation] +(Beach noise) 0, 1, (250, 250, 250), 59420, 3, 0.50, 2.0, eased +]] +---@field mgv6_np_beach core.NoiseParams.2d? +--[[ +# Temperature variation for biomes. +[world_creation] +(Biome noise) 0, 1, (500, 500, 500), 9130, 3, 0.50, 2.0, eased +]] +---@field mgv6_np_biome core.NoiseParams.2d? +--[[ +# Variation of number of caves. +[world_creation] +(Cave noise) 6, 6, (250, 250, 250), 34329, 3, 0.50, 2.0, eased +]] +---@field mgv6_np_cave core.NoiseParams.2d? +--[[ +# Humidity variation for biomes. +[world_creation] +(Humidity noise) 0.5, 0.5, (500, 500, 500), 72384, 3, 0.50, 2.0, eased +]] +---@field mgv6_np_humidity core.NoiseParams.2d? +--[[ +# Defines tree areas and tree density. +[world_creation] +(Trees noise) 0, 1, (125, 125, 125), 2, 4, 0.66, 2.0, eased +]] +---@field mgv6_np_trees core.NoiseParams.2d? +--[[ +# Defines areas where trees have apples. +[world_creation] +(Apple trees noise) 0, 1, (100, 100, 100), 342902, 3, 0.45, 2.0, eased +]] +---@field mgv6_np_apple_trees core.NoiseParams.2d? + +-- -------------------------- [Mapgen] [*Mapgen V7] ------------------------- -- + +--[[ +WIPDOC +]] +---@class core.LuantiSettings.flags.mgv7_spflags +--[[ +WIPDOC +]] +---@field mountains boolean? +--[[ +WIPDOC +]] +---@field nomountains boolean? +--[[ +WIPDOC +]] +---@field ridges boolean? +--[[ +WIPDOC +]] +---@field noridges boolean? +--[[ +WIPDOC +]] +---@field floatlands boolean? +--[[ +WIPDOC +]] +---@field nofloatlands boolean? +--[[ +WIPDOC +]] +---@field caverns boolean? +--[[ +WIPDOC +]] +---@field nocaverns boolean? + +---@class _.LuantiSettings.mapgen.mapgen_v7 +--[[ +# Map generation attributes specific to Mapgen v7. +# 'ridges': Rivers. +# 'floatlands': Floating land masses in the atmosphere. +# 'caverns': Giant caves deep underground. +[world_creation] +(Mapgen V7 specific flags) mountains,ridges,nofloatlands,caverns mountains,ridges,floatlands,caverns +]] +---@field mgv7_spflags core.LuantiSettings.flags? +--[[ +# Y of mountain density gradient zero level. Used to shift mountains vertically. +[world_creation] +(Mountain zero level) 0 -31000 31000 +]] +---@field mgv7_mount_zero_level integer? +--[[ +# Lower Y limit of floatlands. +[world_creation] +(Floatland minimum Y) 1024 -31000 31000 +]] +---@field mgv7_floatland_ymin integer? +--[[ +# Upper Y limit of floatlands. +[world_creation] +(Floatland maximum Y) 4096 -31000 31000 +]] +---@field mgv7_floatland_ymax integer? +--[[ +# Y-distance over which floatlands taper from full density to nothing. +# Tapering starts at this distance from the Y limit. +# For a solid floatland layer, this controls the height of hills/mountains. +# Must be less than or equal to half the distance between the Y limits. +[world_creation] +(Floatland tapering distance) 256 0 32767 +]] +---@field mgv7_floatland_taper integer? +--[[ +# Exponent of the floatland tapering. Alters the tapering behavior. +# Value = 1.0 creates a uniform, linear tapering. +# Values > 1.0 create a smooth tapering suitable for the default separated +# floatlands. +# Values < 1.0 (for example 0.25) create a more defined surface level with +# flatter lowlands, suitable for a solid floatland layer. +[world_creation] +(Floatland taper exponent) 2.0 +]] +---@field mgv7_float_taper_exp number? +--[[ +# Adjusts the density of the floatland layer. +# Increase value to increase density. Can be positive or negative. +# Value = 0.0: 50% of volume is floatland. +# Value = 2.0 (can be higher depending on 'mgv7_np_floatland', always test +# to be sure) creates a solid floatland layer. +[world_creation] +(Floatland density) -0.6 +]] +---@field mgv7_floatland_density number? +--[[ +# Surface level of optional water placed on a solid floatland layer. +# Water is disabled by default and will only be placed if this value is set +# to above 'mgv7_floatland_ymax' - 'mgv7_floatland_taper' (the start of the +# upper tapering). +# ***WARNING, POTENTIAL DANGER TO WORLDS AND SERVER PERFORMANCE***: +# When enabling water placement, floatlands must be configured and tested +# to be a solid layer by setting 'mgv7_floatland_density' to 2.0 (or other +# required value depending on 'mgv7_np_floatland'), to avoid +# server-intensive extreme water flow and to avoid vast flooding of the +# world surface below. +[world_creation] +(Floatland water level) -31000 -31000 31000 +]] +---@field mgv7_floatland_ywater integer? +--[[ +# Controls width of tunnels, a smaller value creates wider tunnels. +# Value >= 10.0 completely disables generation of tunnels and avoids the +# intensive noise calculations. +[world_creation] +(Cave width) 0.09 +]] +---@field mgv7_cave_width number? +--[[ +# Y of upper limit of large caves. +[world_creation] +(Large cave depth) -33 -31000 31000 +]] +---@field mgv7_large_cave_depth integer? +--[[ +# Minimum limit of random number of small caves per mapchunk. +[world_creation] +(Small cave minimum number) 0 0 256 +]] +---@field mgv7_small_cave_num_min integer? +--[[ +# Maximum limit of random number of small caves per mapchunk. +[world_creation] +(Small cave maximum number) 0 0 256 +]] +---@field mgv7_small_cave_num_max integer? +--[[ +# Minimum limit of random number of large caves per mapchunk. +[world_creation] +(Large cave minimum number) 0 0 64 +]] +---@field mgv7_large_cave_num_min integer? +--[[ +# Maximum limit of random number of large caves per mapchunk. +[world_creation] +(Large cave maximum number) 2 0 64 +]] +---@field mgv7_large_cave_num_max integer? +--[[ +# Proportion of large caves that contain liquid. +[world_creation] +(Large cave proportion flooded) 0.5 0.0 1.0 +]] +---@field mgv7_large_cave_flooded number? +--[[ +# Y-level of cavern upper limit. +[world_creation] +(Cavern limit) -256 -31000 31000 +]] +---@field mgv7_cavern_limit integer? +--[[ +# Y-distance over which caverns expand to full size. +[world_creation] +(Cavern taper) 256 0 32767 +]] +---@field mgv7_cavern_taper integer? +--[[ +# Defines full size of caverns, smaller values create larger caverns. +[world_creation] +(Cavern threshold) 0.7 +]] +---@field mgv7_cavern_threshold number? +--[[ +# Lower Y limit of dungeons. +[world_creation] +(Dungeon minimum Y) -31000 -31000 31000 +]] +---@field mgv7_dungeon_ymin integer? +--[[ +# Upper Y limit of dungeons. +[world_creation] +(Dungeon maximum Y) 31000 -31000 31000 +]] +---@field mgv7_dungeon_ymax integer? + +-- -------------------- [Mapgen] [*Mapgen V7] [**Noises] -------------------- -- + +---@class _.LuantiSettings.mapgen.mapgen_v7.noises +--[[ +# Y-level of higher terrain that creates cliffs. +[world_creation] +(Terrain base noise) 4, 70, (600, 600, 600), 82341, 5, 0.6, 2.0, eased +]] +---@field mgv7_np_terrain_base core.NoiseParams.2d? +--[[ +# Y-level of lower terrain and seabed. +[world_creation] +(Terrain alternative noise) 4, 25, (600, 600, 600), 5934, 5, 0.6, 2.0, eased +]] +---@field mgv7_np_terrain_alt core.NoiseParams.2d? +--[[ +# Varies roughness of terrain. +# Defines the 'persistence' value for terrain_base and terrain_alt noises. +[world_creation] +(Terrain persistence noise) 0.6, 0.1, (2000, 2000, 2000), 539, 3, 0.6, 2.0, eased +]] +---@field mgv7_np_terrain_persist core.NoiseParams.2d? +--[[ +# Defines distribution of higher terrain and steepness of cliffs. +[world_creation] +(Height select noise) -8, 16, (500, 500, 500), 4213, 6, 0.7, 2.0, eased +]] +---@field mgv7_np_height_select core.NoiseParams.2d? +--[[ +# Variation of biome filler depth. +[world_creation] +(Filler depth noise) 0, 1.2, (150, 150, 150), 261, 3, 0.7, 2.0, eased +]] +---@field mgv7_np_filler_depth core.NoiseParams.2d? +--[[ +# Variation of maximum mountain height (in nodes). +[world_creation] +(Mountain height noise) 256, 112, (1000, 1000, 1000), 72449, 3, 0.6, 2.0, eased +]] +---@field mgv7_np_mount_height core.NoiseParams.2d? +--[[ +# Defines large-scale river channel structure. +[world_creation] +(Ridge underwater noise) 0, 1, (1000, 1000, 1000), 85039, 5, 0.6, 2.0, eased +]] +---@field mgv7_np_ridge_uwater core.NoiseParams.2d? +--[[ +# 3D noise defining mountain structure and height. +# Also defines structure of floatland mountain terrain. +[world_creation] +(Mountain noise) -0.6, 1, (250, 350, 250), 5333, 5, 0.63, 2.0 +]] +---@field mgv7_np_mountain core.NoiseParams.3d? +--[[ +# 3D noise defining structure of river canyon walls. +[world_creation] +(Ridge noise) 0, 1, (100, 100, 100), 6467, 4, 0.75, 2.0 +]] +---@field mgv7_np_ridge core.NoiseParams.3d? +--[[ +# 3D noise defining structure of floatlands. +# If altered from the default, the noise 'scale' (0.7 by default) may need +# to be adjusted, as floatland tapering functions best when this noise has +# a value range of approximately -2.0 to 2.0. +[world_creation] +(Floatland noise) 0, 0.7, (384, 96, 384), 1009, 4, 0.75, 1.618 +]] +---@field mgv7_np_floatland core.NoiseParams.3d? +--[[ +# 3D noise defining giant caverns. +[world_creation] +(Cavern noise) 0, 1, (384, 128, 384), 723, 5, 0.63, 2.0 +]] +---@field mgv7_np_cavern core.NoiseParams.3d? +--[[ +# First of two 3D noises that together define tunnels. +[world_creation] +(Cave1 noise) 0, 12, (61, 61, 61), 52534, 3, 0.5, 2.0 +]] +---@field mgv7_np_cave1 core.NoiseParams.3d? +--[[ +# Second of two 3D noises that together define tunnels. +[world_creation] +(Cave2 noise) 0, 12, (67, 67, 67), 10325, 3, 0.5, 2.0 +]] +---@field mgv7_np_cave2 core.NoiseParams.3d? +--[[ +# 3D noise that determines number of dungeons per mapchunk. +[world_creation] +(Dungeon noise) 0.9, 0.5, (500, 500, 500), 0, 2, 0.8, 2.0 +]] +---@field mgv7_np_dungeons core.NoiseParams.3d? + +-- ---------------------- [Mapgen] [*Mapgen Carpathian] --------------------- -- + +--[[ +WIPDOC +]] +---@class core.LuantiSettings.flags.mgcarpathian_spflags +--[[ +WIPDOC +]] +---@field caverns boolean? +--[[ +WIPDOC +]] +---@field nocaverns boolean? +--[[ +WIPDOC +]] +---@field rivers boolean? +--[[ +WIPDOC +]] +---@field norivers boolean? + +---@class _.LuantiSettings.mapgen.mapgen_carpathian +--[[ +# Map generation attributes specific to Mapgen Carpathian. +[world_creation] +(Mapgen Carpathian specific flags) caverns,norivers caverns,rivers +]] +---@field mgcarpathian_spflags core.LuantiSettings.flags? +--[[ +# Defines the base ground level. +[world_creation] +(Base ground level) 12.0 +]] +---@field mgcarpathian_base_level number? +--[[ +# Defines the width of the river channel. +[world_creation] +(River channel width) 0.05 +]] +---@field mgcarpathian_river_width number? +--[[ +# Defines the depth of the river channel. +[world_creation] +(River channel depth) 24.0 +]] +---@field mgcarpathian_river_depth number? +--[[ +# Defines the width of the river valley. +[world_creation] +(River valley width) 0.25 +]] +---@field mgcarpathian_valley_width number? +--[[ +# Controls width of tunnels, a smaller value creates wider tunnels. +# Value >= 10.0 completely disables generation of tunnels and avoids the +# intensive noise calculations. +[world_creation] +(Cave width) 0.09 +]] +---@field mgcarpathian_cave_width number? +--[[ +# Y of upper limit of large caves. +[world_creation] +(Large cave depth) -33 -31000 31000 +]] +---@field mgcarpathian_large_cave_depth integer? +--[[ +# Minimum limit of random number of small caves per mapchunk. +[world_creation] +(Small cave minimum number) 0 0 256 +]] +---@field mgcarpathian_small_cave_num_min integer? +--[[ +# Maximum limit of random number of small caves per mapchunk. +[world_creation] +(Small cave maximum number) 0 0 256 +]] +---@field mgcarpathian_small_cave_num_max integer? +--[[ +# Minimum limit of random number of large caves per mapchunk. +[world_creation] +(Large cave minimum number) 0 0 64 +]] +---@field mgcarpathian_large_cave_num_min integer? +--[[ +# Maximum limit of random number of large caves per mapchunk. +[world_creation] +(Large cave maximum number) 2 0 64 +]] +---@field mgcarpathian_large_cave_num_max integer? +--[[ +# Proportion of large caves that contain liquid. +[world_creation] +(Large cave proportion flooded) 0.5 0.0 1.0 +]] +---@field mgcarpathian_large_cave_flooded number? +--[[ +# Y-level of cavern upper limit. +[world_creation] +(Cavern limit) -256 -31000 31000 +]] +---@field mgcarpathian_cavern_limit integer? +--[[ +# Y-distance over which caverns expand to full size. +[world_creation] +(Cavern taper) 256 0 32767 +]] +---@field mgcarpathian_cavern_taper integer? +--[[ +# Defines full size of caverns, smaller values create larger caverns. +[world_creation] +(Cavern threshold) 0.7 +]] +---@field mgcarpathian_cavern_threshold number? +--[[ +# Lower Y limit of dungeons. +[world_creation] +(Dungeon minimum Y) -31000 -31000 31000 +]] +---@field mgcarpathian_dungeon_ymin integer? +--[[ +# Upper Y limit of dungeons. +[world_creation] +(Dungeon maximum Y) 31000 -31000 31000 +]] +---@field mgcarpathian_dungeon_ymax integer? + +-- ---------------- [Mapgen] [*Mapgen Carpathian] [**Noises] ---------------- -- + +---@class _.LuantiSettings.mapgen.mapgen_carpathian.noises +--[[ +# Variation of biome filler depth. +[world_creation] +(Filler depth noise) 0, 1, (128, 128, 128), 261, 3, 0.7, 2.0, eased +]] +---@field mgcarpathian_np_filler_depth core.NoiseParams.2d? +--[[ +# First of 4 2D noises that together define hill/mountain range height. +[world_creation] +(Hilliness1 noise) 0, 5, (251, 251, 251), 9613, 5, 0.5, 2.0, eased +]] +---@field mgcarpathian_np_height1 core.NoiseParams.2d? +--[[ +# Second of 4 2D noises that together define hill/mountain range height. +[world_creation] +(Hilliness2 noise) 0, 5, (383, 383, 383), 1949, 5, 0.5, 2.0, eased +]] +---@field mgcarpathian_np_height2 core.NoiseParams.2d? +--[[ +# Third of 4 2D noises that together define hill/mountain range height. +[world_creation] +(Hilliness3 noise) 0, 5, (509, 509, 509), 3211, 5, 0.5, 2.0, eased +]] +---@field mgcarpathian_np_height3 core.NoiseParams.2d? +--[[ +# Fourth of 4 2D noises that together define hill/mountain range height. +[world_creation] +(Hilliness4 noise) 0, 5, (631, 631, 631), 1583, 5, 0.5, 2.0, eased +]] +---@field mgcarpathian_np_height4 core.NoiseParams.2d? +--[[ +# 2D noise that controls the size/occurrence of rolling hills. +[world_creation] +(Rolling hills spread noise) 1, 1, (1301, 1301, 1301), 1692, 3, 0.5, 2.0, eased +]] +---@field mgcarpathian_np_hills_terrain core.NoiseParams.2d? +--[[ +# 2D noise that controls the size/occurrence of ridged mountain ranges. +[world_creation] +(Ridge mountain spread noise) 1, 1, (1889, 1889, 1889), 3568, 3, 0.5, 2.0, eased +]] +---@field mgcarpathian_np_ridge_terrain core.NoiseParams.2d? +--[[ +# 2D noise that controls the size/occurrence of step mountain ranges. +[world_creation] +(Step mountain spread noise) 1, 1, (1889, 1889, 1889), 4157, 3, 0.5, 2.0, eased +]] +---@field mgcarpathian_np_step_terrain core.NoiseParams.2d? +--[[ +# 2D noise that controls the shape/size of rolling hills. +[world_creation] +(Rolling hill size noise) 0, 3, (257, 257, 257), 6604, 6, 0.5, 2.0, eased +]] +---@field mgcarpathian_np_hills core.NoiseParams.2d? +--[[ +# 2D noise that controls the shape/size of ridged mountains. +[world_creation] +(Ridged mountain size noise) 0, 12, (743, 743, 743), 5520, 6, 0.7, 2.0, eased +]] +---@field mgcarpathian_np_ridge_mnt core.NoiseParams.2d? +--[[ +# 2D noise that controls the shape/size of step mountains. +[world_creation] +(Step mountain size noise) 0, 8, (509, 509, 509), 2590, 6, 0.6, 2.0, eased +]] +---@field mgcarpathian_np_step_mnt core.NoiseParams.2d? +--[[ +# 2D noise that locates the river valleys and channels. +[world_creation] +(River noise) 0, 1, (1000, 1000, 1000), 85039, 5, 0.6, 2.0, eased +]] +---@field mgcarpathian_np_rivers core.NoiseParams.2d? +--[[ +# 3D noise for mountain overhangs, cliffs, etc. Usually small variations. +[world_creation] +(Mountain variation noise) 0, 1, (499, 499, 499), 2490, 5, 0.55, 2.0 +]] +---@field mgcarpathian_np_mnt_var core.NoiseParams.3d? +--[[ +# First of two 3D noises that together define tunnels. +[world_creation] +(Cave1 noise) 0, 12, (61, 61, 61), 52534, 3, 0.5, 2.0 +]] +---@field mgcarpathian_np_cave1 core.NoiseParams.3d? +--[[ +# Second of two 3D noises that together define tunnels. +[world_creation] +(Cave2 noise) 0, 12, (67, 67, 67), 10325, 3, 0.5, 2.0 +]] +---@field mgcarpathian_np_cave2 core.NoiseParams.3d? +--[[ +# 3D noise defining giant caverns. +[world_creation] +(Cavern noise) 0, 1, (384, 128, 384), 723, 5, 0.63, 2.0 +]] +---@field mgcarpathian_np_cavern core.NoiseParams.3d? +--[[ +# 3D noise that determines number of dungeons per mapchunk. +[world_creation] +(Dungeon noise) 0.9, 0.5, (500, 500, 500), 0, 2, 0.8, 2.0 +]] +---@field mgcarpathian_np_dungeons core.NoiseParams.3d? + +-- ------------------------- [Mapgen] [*Mapgen Flat] ------------------------ -- + +--[[ +WIPDOC +]] +---@class core.LuantiSettings.flags.mgflat_spflags +--[[ +WIPDOC +]] +---@field lakes boolean? +--[[ +WIPDOC +]] +---@field nolakes boolean? +--[[ +WIPDOC +]] +---@field hills boolean? +--[[ +WIPDOC +]] +---@field nohills boolean? +--[[ +WIPDOC +]] +---@field caverns boolean? +--[[ +WIPDOC +]] +---@field nocaverns boolean? + +---@class _.LuantiSettings.mapgen.mapgen_flat +--[[ +# Map generation attributes specific to Mapgen Flat. +# Occasional lakes and hills can be added to the flat world. +[world_creation] +(Mapgen Flat specific flags) nolakes,nohills,nocaverns lakes,hills,caverns +]] +---@field mgflat_spflags core.LuantiSettings.flags? +--[[ +# Y of flat ground. +[world_creation] +(Ground level) 8 -31000 31000 +]] +---@field mgflat_ground_level integer? +--[[ +# Y of upper limit of large caves. +[world_creation] +(Large cave depth) -33 -31000 31000 +]] +---@field mgflat_large_cave_depth integer? +--[[ +# Minimum limit of random number of small caves per mapchunk. +[world_creation] +(Small cave minimum number) 0 0 256 +]] +---@field mgflat_small_cave_num_min integer? +--[[ +# Maximum limit of random number of small caves per mapchunk. +[world_creation] +(Small cave maximum number) 0 0 256 +]] +---@field mgflat_small_cave_num_max integer? +--[[ +# Minimum limit of random number of large caves per mapchunk. +[world_creation] +(Large cave minimum number) 0 0 64 +]] +---@field mgflat_large_cave_num_min integer? +--[[ +# Maximum limit of random number of large caves per mapchunk. +[world_creation] +(Large cave maximum number) 2 0 64 +]] +---@field mgflat_large_cave_num_max integer? +--[[ +# Proportion of large caves that contain liquid. +[world_creation] +(Large cave proportion flooded) 0.5 0.0 1.0 +]] +---@field mgflat_large_cave_flooded number? +--[[ +# Controls width of tunnels, a smaller value creates wider tunnels. +# Value >= 10.0 completely disables generation of tunnels and avoids the +# intensive noise calculations. +[world_creation] +(Cave width) 0.09 +]] +---@field mgflat_cave_width number? +--[[ +# Terrain noise threshold for lakes. +# Controls proportion of world area covered by lakes. +# Adjust towards 0.0 for a larger proportion. +[world_creation] +(Lake threshold) -0.45 +]] +---@field mgflat_lake_threshold number? +--[[ +# Controls steepness/depth of lake depressions. +[world_creation] +(Lake steepness) 48.0 +]] +---@field mgflat_lake_steepness number? +--[[ +# Terrain noise threshold for hills. +# Controls proportion of world area covered by hills. +# Adjust towards 0.0 for a larger proportion. +[world_creation] +(Hill threshold) 0.45 +]] +---@field mgflat_hill_threshold number? +--[[ +# Controls steepness/height of hills. +[world_creation] +(Hill steepness) 64.0 +]] +---@field mgflat_hill_steepness number? +--[[ +# Y-level of cavern upper limit. +[world_creation] +(Cavern limit) -256 -31000 31000 +]] +---@field mgflat_cavern_limit integer? +--[[ +# Y-distance over which caverns expand to full size. +[world_creation] +(Cavern taper) 256 0 32767 +]] +---@field mgflat_cavern_taper integer? +--[[ +# Defines full size of caverns, smaller values create larger caverns. +[world_creation] +(Cavern threshold) 0.7 +]] +---@field mgflat_cavern_threshold number? +--[[ +# Lower Y limit of dungeons. +[world_creation] +(Dungeon minimum Y) -31000 -31000 31000 +]] +---@field mgflat_dungeon_ymin integer? +--[[ +# Upper Y limit of dungeons. +[world_creation] +(Dungeon maximum Y) 31000 -31000 31000 +]] +---@field mgflat_dungeon_ymax integer? + +-- ------------------- [Mapgen] [*Mapgen Flat] [**Noises] ------------------- -- + +---@class _.LuantiSettings.mapgen.mapgen_flat.noises +--[[ +# Defines location and terrain of optional hills and lakes. +[world_creation] +(Terrain noise) 0, 1, (600, 600, 600), 7244, 5, 0.6, 2.0, eased +]] +---@field mgflat_np_terrain core.NoiseParams.2d? +--[[ +# Variation of biome filler depth. +[world_creation] +(Filler depth noise) 0, 1.2, (150, 150, 150), 261, 3, 0.7, 2.0, eased +]] +---@field mgflat_np_filler_depth core.NoiseParams.2d? +--[[ +# First of two 3D noises that together define tunnels. +[world_creation] +(Cave1 noise) 0, 12, (61, 61, 61), 52534, 3, 0.5, 2.0 +]] +---@field mgflat_np_cave1 core.NoiseParams.3d? +--[[ +# Second of two 3D noises that together define tunnels. +[world_creation] +(Cave2 noise) 0, 12, (67, 67, 67), 10325, 3, 0.5, 2.0 +]] +---@field mgflat_np_cave2 core.NoiseParams.3d? +--[[ +# 3D noise defining giant caverns. +[world_creation] +(Cavern noise) 0, 1, (384, 128, 384), 723, 5, 0.63, 2.0 +]] +---@field mgflat_np_cavern core.NoiseParams.3d? +--[[ +# 3D noise that determines number of dungeons per mapchunk. +[world_creation] +(Dungeon noise) 0.9, 0.5, (500, 500, 500), 0, 2, 0.8, 2.0 +]] +---@field mgflat_np_dungeons core.NoiseParams.3d? + +-- ----------------------- [Mapgen] [*Mapgen Fractal] ----------------------- -- + +--[[ +WIPDOC +]] +---@class core.LuantiSettings.flags.mgfractal_spflags +--[[ +WIPDOC +]] +---@field terrain boolean? +--[[ +WIPDOC +]] +---@field noterrain boolean? + +---@class _.LuantiSettings.mapgen.mapgen_fractal +--[[ +# Map generation attributes specific to Mapgen Fractal. +# 'terrain' enables the generation of non-fractal terrain: +# ocean, islands and underground. +[world_creation] +(Mapgen Fractal specific flags) terrain terrain +]] +---@field mgfractal_spflags core.LuantiSettings.flags? +--[[ +# Controls width of tunnels, a smaller value creates wider tunnels. +# Value >= 10.0 completely disables generation of tunnels and avoids the +# intensive noise calculations. +[world_creation] +(Cave width) 0.09 +]] +---@field mgfractal_cave_width number? +--[[ +# Y of upper limit of large caves. +[world_creation] +(Large cave depth) -33 -31000 31000 +]] +---@field mgfractal_large_cave_depth integer? +--[[ +# Minimum limit of random number of small caves per mapchunk. +[world_creation] +(Small cave minimum number) 0 0 256 +]] +---@field mgfractal_small_cave_num_min integer? +--[[ +# Maximum limit of random number of small caves per mapchunk. +[world_creation] +(Small cave maximum number) 0 0 256 +]] +---@field mgfractal_small_cave_num_max integer? +--[[ +# Minimum limit of random number of large caves per mapchunk. +[world_creation] +(Large cave minimum number) 0 0 64 +]] +---@field mgfractal_large_cave_num_min integer? +--[[ +# Maximum limit of random number of large caves per mapchunk. +[world_creation] +(Large cave maximum number) 2 0 64 +]] +---@field mgfractal_large_cave_num_max integer? +--[[ +# Proportion of large caves that contain liquid. +[world_creation] +(Large cave proportion flooded) 0.5 0.0 1.0 +]] +---@field mgfractal_large_cave_flooded number? +--[[ +# Lower Y limit of dungeons. +[world_creation] +(Dungeon minimum Y) -31000 -31000 31000 +]] +---@field mgfractal_dungeon_ymin integer? +--[[ +# Upper Y limit of dungeons. +[world_creation] +(Dungeon maximum Y) 31000 -31000 31000 +]] +---@field mgfractal_dungeon_ymax integer? +--[[ +# Selects one of 18 fractal types. +# 1 = 4D "Roundy" Mandelbrot set. +# 2 = 4D "Roundy" Julia set. +# 3 = 4D "Squarry" Mandelbrot set. +# 4 = 4D "Squarry" Julia set. +# 5 = 4D "Mandy Cousin" Mandelbrot set. +# 6 = 4D "Mandy Cousin" Julia set. +# 7 = 4D "Variation" Mandelbrot set. +# 8 = 4D "Variation" Julia set. +# 9 = 3D "Mandelbrot/Mandelbar" Mandelbrot set. +# 10 = 3D "Mandelbrot/Mandelbar" Julia set. +# 11 = 3D "Christmas Tree" Mandelbrot set. +# 12 = 3D "Christmas Tree" Julia set. +# 13 = 3D "Mandelbulb" Mandelbrot set. +# 14 = 3D "Mandelbulb" Julia set. +# 15 = 3D "Cosine Mandelbulb" Mandelbrot set. +# 16 = 3D "Cosine Mandelbulb" Julia set. +# 17 = 4D "Mandelbulb" Mandelbrot set. +# 18 = 4D "Mandelbulb" Julia set. +[world_creation] +(Fractal type) 1 1 18 +]] +---@field mgfractal_fractal integer? +--[[ +# Iterations of the recursive function. +# Increasing this increases the amount of fine detail, but also +# increases processing load. +# At iterations = 20 this mapgen has a similar load to mapgen V7. +[world_creation] +(Iterations) 11 1 65535 +]] +---@field mgfractal_iterations integer? +--[[ +# (X,Y,Z) scale of fractal in nodes. +# Actual fractal size will be 2 to 3 times larger. +# These numbers can be made very large, the fractal does +# not have to fit inside the world. +# Increase these to 'zoom' into the detail of the fractal. +# Default is for a vertically-squashed shape suitable for +# an island, set all 3 numbers equal for the raw shape. +[world_creation] +(Scale) (4096.0, 1024.0, 4096.0) +]] +---@field mgfractal_scale vec? +--[[ +# (X,Y,Z) offset of fractal from world center in units of 'scale'. +# Can be used to move a desired point to (0, 0) to create a +# suitable spawn point, or to allow 'zooming in' on a desired +# point by increasing 'scale'. +# The default is tuned for a suitable spawn point for Mandelbrot +# sets with default parameters, it may need altering in other +# situations. +# Range roughly -2 to 2. Multiply by 'scale' for offset in nodes. +[world_creation] +(Offset) (1.79, 0.0, 0.0) +]] +---@field mgfractal_offset vec? +--[[ +# W coordinate of the generated 3D slice of a 4D fractal. +# Determines which 3D slice of the 4D shape is generated. +# Alters the shape of the fractal. +# Has no effect on 3D fractals. +# Range roughly -2 to 2. +[world_creation] +(Slice w) 0.0 +]] +---@field mgfractal_slice_w number? +--[[ +# Julia set only. +# X component of hypercomplex constant. +# Alters the shape of the fractal. +# Range roughly -2 to 2. +[world_creation] +(Julia x) 0.33 +]] +---@field mgfractal_julia_x number? +--[[ +# Julia set only. +# Y component of hypercomplex constant. +# Alters the shape of the fractal. +# Range roughly -2 to 2. +[world_creation] +(Julia y) 0.33 +]] +---@field mgfractal_julia_y number? +--[[ +# Julia set only. +# Z component of hypercomplex constant. +# Alters the shape of the fractal. +# Range roughly -2 to 2. +[world_creation] +(Julia z) 0.33 +]] +---@field mgfractal_julia_z number? +--[[ +# Julia set only. +# W component of hypercomplex constant. +# Alters the shape of the fractal. +# Has no effect on 3D fractals. +# Range roughly -2 to 2. +[world_creation] +(Julia w) 0.33 +]] +---@field mgfractal_julia_w number? + +-- ------------------ [Mapgen] [*Mapgen Fractal] [**Noises] ----------------- -- + +---@class _.LuantiSettings.mapgen.mapgen_fractal.noises +--[[ +# Y-level of seabed. +[world_creation] +(Seabed noise) -14, 9, (600, 600, 600), 41900, 5, 0.6, 2.0, eased +]] +---@field mgfractal_np_seabed core.NoiseParams.2d? +--[[ +# Variation of biome filler depth. +[world_creation] +(Filler depth noise) 0, 1.2, (150, 150, 150), 261, 3, 0.7, 2.0, eased +]] +---@field mgfractal_np_filler_depth core.NoiseParams.2d? +--[[ +# First of two 3D noises that together define tunnels. +[world_creation] +(Cave1 noise) 0, 12, (61, 61, 61), 52534, 3, 0.5, 2.0 +]] +---@field mgfractal_np_cave1 core.NoiseParams.3d? +--[[ +# Second of two 3D noises that together define tunnels. +[world_creation] +(Cave2 noise) 0, 12, (67, 67, 67), 10325, 3, 0.5, 2.0 +]] +---@field mgfractal_np_cave2 core.NoiseParams.3d? +--[[ +# 3D noise that determines number of dungeons per mapchunk. +[world_creation] +(Dungeon noise) 0.9, 0.5, (500, 500, 500), 0, 2, 0.8, 2.0 +]] +---@field mgfractal_np_dungeons core.NoiseParams.3d? + +-- ----------------------- [Mapgen] [*Mapgen Valleys] ----------------------- -- + +--[[ +WIPDOC +]] +---@class core.LuantiSettings.flags.mgvalleys_spflags +--[[ +WIPDOC +]] +---@field altitude_chill boolean? +--[[ +WIPDOC +]] +---@field noaltitude_chill boolean? +--[[ +WIPDOC +]] +---@field humid_rivers boolean? +--[[ +WIPDOC +]] +---@field nohumid_rivers boolean? +--[[ +WIPDOC +]] +---@field vary_river_depth boolean? +--[[ +WIPDOC +]] +---@field novary_river_depth boolean? +--[[ +WIPDOC +]] +---@field altitude_dry boolean? +--[[ +WIPDOC +]] +---@field noaltitude_dry boolean? + +---@class _.LuantiSettings.mapgen.mapgen_valleys +--[[ +# Map generation attributes specific to Mapgen Valleys. +# 'altitude_chill': Reduces heat with altitude. +# 'humid_rivers': Increases humidity around rivers. +# 'vary_river_depth': If enabled, low humidity and high heat causes rivers +# to become shallower and occasionally dry. +# 'altitude_dry': Reduces humidity with altitude. +[world_creation] +(Mapgen Valleys specific flags) altitude_chill,humid_rivers,vary_river_depth,altitude_dry altitude_chill,humid_rivers,vary_river_depth,altitude_dry +]] +---@field mgvalleys_spflags core.LuantiSettings.flags? +--[[ +# The vertical distance over which heat drops by 20 if 'altitude_chill' is +# enabled. Also, the vertical distance over which humidity drops by 10 if +# 'altitude_dry' is enabled. +[world_creation] +(Altitude chill) 90 0 65535 +]] +---@field mgvalleys_altitude_chill integer? +--[[ +# Depth below which you'll find large caves. +[world_creation] +(Large cave depth) -33 -31000 31000 +]] +---@field mgvalleys_large_cave_depth integer? +--[[ +# Minimum limit of random number of small caves per mapchunk. +[world_creation] +(Small cave minimum number) 0 0 256 +]] +---@field mgvalleys_small_cave_num_min integer? +--[[ +# Maximum limit of random number of small caves per mapchunk. +[world_creation] +(Small cave maximum number) 0 0 256 +]] +---@field mgvalleys_small_cave_num_max integer? +--[[ +# Minimum limit of random number of large caves per mapchunk. +[world_creation] +(Large cave minimum number) 0 0 64 +]] +---@field mgvalleys_large_cave_num_min integer? +--[[ +# Maximum limit of random number of large caves per mapchunk. +[world_creation] +(Large cave maximum number) 2 0 64 +]] +---@field mgvalleys_large_cave_num_max integer? +--[[ +# Proportion of large caves that contain liquid. +[world_creation] +(Large cave proportion flooded) 0.5 0.0 1.0 +]] +---@field mgvalleys_large_cave_flooded number? +--[[ +# Depth below which you'll find giant caverns. +[world_creation] +(Cavern upper limit) -256 -31000 31000 +]] +---@field mgvalleys_cavern_limit integer? +--[[ +# Y-distance over which caverns expand to full size. +[world_creation] +(Cavern taper) 192 0 32767 +]] +---@field mgvalleys_cavern_taper integer? +--[[ +# Defines full size of caverns, smaller values create larger caverns. +[world_creation] +(Cavern threshold) 0.6 +]] +---@field mgvalleys_cavern_threshold number? +--[[ +# How deep to make rivers. +[world_creation] +(River depth) 4 0 65535 +]] +---@field mgvalleys_river_depth integer? +--[[ +# How wide to make rivers. +[world_creation] +(River size) 5 0 65535 +]] +---@field mgvalleys_river_size integer? +--[[ +# Controls width of tunnels, a smaller value creates wider tunnels. +# Value >= 10.0 completely disables generation of tunnels and avoids the +# intensive noise calculations. +[world_creation] +(Cave width) 0.09 +]] +---@field mgvalleys_cave_width number? +--[[ +# Lower Y limit of dungeons. +[world_creation] +(Dungeon minimum Y) -31000 -31000 31000 +]] +---@field mgvalleys_dungeon_ymin integer? +--[[ +# Upper Y limit of dungeons. +[world_creation] +(Dungeon maximum Y) 63 -31000 31000 +]] +---@field mgvalleys_dungeon_ymax integer? + +-- ------------------ [Mapgen] [*Mapgen Valleys] [**Noises] ----------------- -- + +---@class _.LuantiSettings.mapgen.mapgen_valleys.noises +--[[ +# First of two 3D noises that together define tunnels. +[world_creation] +(Cave noise #1) 0, 12, (61, 61, 61), 52534, 3, 0.5, 2.0 +]] +---@field mgvalleys_np_cave1 core.NoiseParams.3d? +--[[ +# Second of two 3D noises that together define tunnels. +[world_creation] +(Cave noise #2) 0, 12, (67, 67, 67), 10325, 3, 0.5, 2.0 +]] +---@field mgvalleys_np_cave2 core.NoiseParams.3d? +--[[ +# Variation of biome filler depth. +[world_creation] +(Filler depth) 0, 1.2, (256, 256, 256), 1605, 3, 0.5, 2.0, eased +]] +---@field mgvalleys_np_filler_depth core.NoiseParams.2d? +--[[ +# 3D noise defining giant caverns. +[world_creation] +(Cavern noise) 0, 1, (768, 256, 768), 59033, 6, 0.63, 2.0 +]] +---@field mgvalleys_np_cavern core.NoiseParams.3d? +--[[ +# Defines large-scale river channel structure. +[world_creation] +(River noise) 0, 1, (256, 256, 256), -6050, 5, 0.6, 2.0, eased +]] +---@field mgvalleys_np_rivers core.NoiseParams.2d? +--[[ +# Base terrain height. +[world_creation] +(Terrain height) -10, 50, (1024, 1024, 1024), 5202, 6, 0.4, 2.0, eased +]] +---@field mgvalleys_np_terrain_height core.NoiseParams.2d? +--[[ +# Raises terrain to make valleys around the rivers. +[world_creation] +(Valley depth) 5, 4, (512, 512, 512), -1914, 1, 1.0, 2.0, eased +]] +---@field mgvalleys_np_valley_depth core.NoiseParams.2d? +--[[ +# Slope and fill work together to modify the heights. +[world_creation] +(Valley fill) 0, 1, (256, 512, 256), 1993, 6, 0.8, 2.0 +]] +---@field mgvalleys_np_inter_valley_fill core.NoiseParams.3d? +--[[ +# Amplifies the valleys. +[world_creation] +(Valley profile) 0.6, 0.5, (512, 512, 512), 777, 1, 1.0, 2.0, eased +]] +---@field mgvalleys_np_valley_profile core.NoiseParams.2d? +--[[ +# Slope and fill work together to modify the heights. +[world_creation] +(Valley slope) 0.5, 0.5, (128, 128, 128), 746, 1, 1.0, 2.0, eased +]] +---@field mgvalleys_np_inter_valley_slope core.NoiseParams.2d? +--[[ +# 3D noise that determines number of dungeons per mapchunk. +[world_creation] +(Dungeon noise) 0.9, 0.5, (500, 500, 500), 0, 2, 0.8, 2.0 +]] +---@field mgvalleys_np_dungeons core.NoiseParams.3d? \ No newline at end of file diff --git a/types/luanti_lsp_definitions/library/classes/Settings/LuantiSettings/settings_enums.lua b/types/luanti_lsp_definitions/library/classes/Settings/LuantiSettings/settings_enums.lua new file mode 100644 index 00000000..78218edc --- /dev/null +++ b/types/luanti_lsp_definitions/library/classes/Settings/LuantiSettings/settings_enums.lua @@ -0,0 +1,60 @@ +---@meta _ +-- DRAFT 1 DONE +-- luanti/doc/lua_api.md: Class reference > `Settings` +-- builtin/settingtypes.txt +-- minetest.conf.example + +---@class core.LuantiSettings +local LuantiSettings = {} + +-- -------------------------------- Advanced -------------------------------- -- + +---@nodiscard +---@param key "debug_log_level" +---@return core.LuantiSettings.enums.debug_log_level? value +function LuantiSettings:get(key) end + +---@param key "debug_log_level" +---@param value core.LuantiSettings.enums.debug_log_level? +function LuantiSettings:set(key, value) end + +---@nodiscard +---@param key "deprecated_lua_api_handling" +---@return core.LuantiSettings.enums.deprecated_lua_api_handling? value +function LuantiSettings:get(key) end + +---@param key "deprecated_lua_api_handling" +---@param value core.LuantiSettings.enums.deprecated_lua_api_handling? +function LuantiSettings:set(key, value) end + +---@nodiscard +---@param key "profiler.default_report_format" +---@return core.LuantiSettings.enums.profiler.default_report_format? value +function LuantiSettings:get(key) end + +---@nodiscard +---@param key "profiler.default_report_format" +---@param value core.LuantiSettings.enums.profiler.default_report_format? +function LuantiSettings:set(key, value) end + +---@nodiscard +---@param key "sqlite_synchronous" +---@return core.LuantiSettings.enums.sqlite_synchronous? value +function LuantiSettings:get(key) end + +---@nodiscard +---@param key "sqlite_synchronous" +---@param value core.LuantiSettings.enums.sqlite_synchronous? +function LuantiSettings:set(key, value) end + +-- --------------------------------- Mapgen --------------------------------- -- + +---@nodiscard +---@param key "mg_name" +---@return core.LuantiSettings.enums.mg_name? value +function LuantiSettings:get(key) end + +---@nodiscard +---@param key "mg_name" +---@param value core.LuantiSettings.enums.mg_name? +function LuantiSettings:set(key, value) end \ No newline at end of file diff --git a/types/luanti_lsp_definitions/library/classes/Settings/LuantiSettings/settings_flags.lua b/types/luanti_lsp_definitions/library/classes/Settings/LuantiSettings/settings_flags.lua new file mode 100644 index 00000000..332d6469 --- /dev/null +++ b/types/luanti_lsp_definitions/library/classes/Settings/LuantiSettings/settings_flags.lua @@ -0,0 +1,48 @@ +---@meta _ +-- DRAFT 1 DONE +-- luanti/doc/lua_api.md: Class reference > `Settings` +-- builtin/settingtypes.txt +-- minetest.conf.example + +---@class core.LuantiSettings +local LuantiSettings = {} + +---@nodiscard +---@param key "mg_flags" +---@return core.LuantiSettings.flags.mg_flags? value +function LuantiSettings:get_flags(key) end + +---@nodiscard +---@param key "mgv5_spflags" +---@return core.LuantiSettings.flags.mgv5_spflags? value +function LuantiSettings:get_flags(key) end + +---@nodiscard +---@param key "mgv6_spflags" +---@return core.LuantiSettings.flags.mgv6_spflags? value +function LuantiSettings:get_flags(key) end + +---@nodiscard +---@param key "mgv7_spflags" +---@return core.LuantiSettings.flags.mgv7_spflags? value +function LuantiSettings:get_flags(key) end + +---@nodiscard +---@param key "mgcarpathian_spflags" +---@return core.LuantiSettings.flags.mgcarpathian_spflags? value +function LuantiSettings:get_flags(key) end + +---@nodiscard +---@param key "mgflat_spflags" +---@return core.LuantiSettings.flags.mgflat_spflags? value +function LuantiSettings:get_flags(key) end + +---@nodiscard +---@param key "mgfractal_spflags" +---@return core.LuantiSettings.flags.mgfractal_spflags? value +function LuantiSettings:get_flags(key) end + +---@nodiscard +---@param key "mgvalleys_spflags" +---@return core.LuantiSettings.flags.mgvalleys_spflags? value +function LuantiSettings:get_flags(key) end \ No newline at end of file diff --git a/types/luanti_lsp_definitions/library/classes/Settings/Settings.lua b/types/luanti_lsp_definitions/library/classes/Settings/Settings.lua new file mode 100644 index 00000000..ca3c831a --- /dev/null +++ b/types/luanti_lsp_definitions/library/classes/Settings/Settings.lua @@ -0,0 +1,188 @@ +---@meta _ +-- DRAFT 1 DONE +-- luanti/doc/lua_api.md: Class reference > `Settings` +-- builtin/settingtype.txt + +--[[ +NOTE: types in a .conf settings file +- int -> integer +- string -> string +- bool -> boolean +- float -> number +- enum -> string +- path -> string +- filepath -> string +- key -> string +- flags -> flag table +- noise_params_2d -> noiseparams +- noise_params_3d -> noiseparams +- v3f -> vec +]] + +-- ------------------------------- constructor ------------------------------ -- + +--[[ +WIPDOC +]] +---@nodiscard +---@param filename core.Path +---@return core.Settings +function Settings(filename) end + +-- -------------------------------- Settings -------------------------------- -- + +--[[ +### Format + +The settings have the format `key = value`. Example: + + foo = example text + bar = """ + Multiline + value + """ +]] +---@class core.Settings +Settings = {} + +--[[ +* `get(key)`: returns a value + * Returns `nil` if `key` is not found. +]] +---@nodiscard +---@param key string +---@return string? value +function Settings:get(key) end + +--[[ +* `get_bool(key, [default])`: returns a boolean + * `default` is the value returned if `key` is not found. + * Returns `nil` if `key` is not found and `default` not specified. +]] +---@nodiscard +---@param key string +---@return boolean? value +function Settings:get_bool(key) end + +--[[ +* `get_bool(key, [default])`: returns a boolean + * `default` is the value returned if `key` is not found. + * Returns `nil` if `key` is not found and `default` not specified. +]] +---@nodiscard +---@generic T +---@param key string +---@param default T +---@return boolean|T value +function Settings:get_bool(key, default) end + +--[[ +* `get_np_group(key)`: returns a NoiseParams table + * Returns `nil` if `key` is not found. +]] +---@nodiscard +---@param key string +---@return core.NoiseParams? value +function Settings:get_np_group(key) end + +--[[ +* `get_flags(key)`: + * Returns `{flag = true/false, ...}` according to the set flags. + * Is currently limited to mapgen flags `mg_flags` and mapgen-specific + flags like `mgv5_spflags`. + * Returns `nil` if `key` is not found. +]] +---@nodiscard +---@param key string +---@return table? value +function Settings:get_flags(key) end + +--[[ +* `get_pos(key)`: + * Returns a `vector` + * Returns `nil` if no value is found or parsing failed. +]] +---@nodiscard +---@param key string +---@return vec? value +function Settings:get_pos(key) end + +--[[ +* `set(key, value)` + * Setting names can't contain whitespace or any of `="{}#`. + * Setting values can't contain the sequence `\n"""`. + * Setting names starting with "secure." can't be set on the main settings + object (`core.settings`). +]] +---@param key string +---@param value string +function Settings:set(key, value) end + +--[[ +* `set_bool(key, value)` + * See documentation for `set()` above. +]] +---@param key string +---@param value boolean +function Settings:set_bool(key, value) end + +--[[ +* `set_np_group(key, value)` + * `value` is a NoiseParams table. + * Also, see documentation for `set()` above. +]] +---@param key string +---@param value core.NoiseParams +function Settings:set_np_group(key, value) end + +--[[ +* `set_pos(key, value)` + * `value` is a `vector`. + * Also, see documentation for `set()` above. +]] +---@param key string +---@param value vector +function Settings:set_pos(key, value) end + +--[[ +* `remove(key)`: returns a boolean (`true` for success +]] +---@nodiscard +---@param key boolean +---@return boolean +function Settings:remove(key) end + +--[[ +* `get_names()`: returns `{key1,...}` +]] +---@nodiscard +---@return string[] keys +function Settings:get_names() end + +--[[ +* `has(key)`: + * Returns a boolean indicating whether `key` exists. + * In contrast to the various getter functions, `has()` doesn't consider + any default values. + * This means that on the main settings object (`core.settings`), + `get(key)` might return a value even if `has(key)` returns `false`. +]] +---@nodiscard +---@param key string +---@return boolean +function Settings:has(key) end + +--[[ +* `write()`: returns a boolean (`true` for success + * Writes changes to file. +]] +---@nodiscard +---@return boolean +function Settings:write() end + +--[[ +* `to_table()`: returns `{[key1]=value1,...}` +]] +---@nodiscard +---@return table +function Settings:to_table() end diff --git a/types/luanti_lsp_definitions/library/classes/StorageRef.lua b/types/luanti_lsp_definitions/library/classes/StorageRef.lua new file mode 100644 index 00000000..f78787a4 --- /dev/null +++ b/types/luanti_lsp_definitions/library/classes/StorageRef.lua @@ -0,0 +1,126 @@ +---@meta _ +-- DRAFT 1 DONE +-- luanti/doc/lua_api.md: 'core' namespace reference > Storage API +-- luanti/doc/lua_api.md: Class reference > `StorageRef` + +-- NOTE: changes are linked to MetaDataRef, ItemStackMetaRef, NodeMetaRef, +-- PlayerMetaRef and StorageRef + +-- ------------------------------- constructor ------------------------------ -- + +--[[ +* `core.get_mod_storage()`: + * returns reference to mod private `StorageRef` + * must be called during mod load time +]] +---@nodiscard +---@return core.StorageRef +function core.get_mod_storage() end + +-- ------------------------------- StorageRef ------------------------------- -- + +--[[ +`StorageRef` +------------ + +Mod metadata: per mod and world metadata, saved automatically. +Can be obtained via `core.get_mod_storage()` during load time. + +WARNING: This storage backend is incapable of saving raw binary data due +to restrictions of JSON. + +### Methods + +* All methods in MetaDataRef + +]] +---@class core.StorageRef : core.MetaDataRef +local StorageRef = {} + +--[[ +* `contains(key)`: Returns true if key present, otherwise false. + * Returns `nil` when the MetaData is inexistent. +]] +---@nodiscard +---@param key core.MetadataTable.fields.storage.keys +---@return boolean? +function StorageRef:contains(key) end + +--[[ +* `get(key)`: Returns `nil` if key not present, else the stored string. +]] +---@nodiscard +---@param key core.MetadataTable.fields.storage.keys +---@return string? value +function StorageRef:get(key) end + +--[[ +* `set_string(key, value)`: Value of `""` will delete the key. +]] +---@nodiscard +---@param key core.MetadataTable.fields.storage.keys +---@param value string +function StorageRef:set_string(key, value) end + +--[[ +* `get_string(key)`: Returns `""` if key not present. +]] +---@nodiscard +---@param key core.MetadataTable.fields.storage.keys +---@return string value +function StorageRef:get_string(key) end + +--[[ +* `set_int(key, value)` + * The range for the value is system-dependent (usually 32 bits). + The value will be converted into a string when stored. +]] +---@param key core.MetadataTable.fields.storage.keys.integer +---@param value integer +function StorageRef:set_int(key, value) end + +--[[ +* `get_int(key)`: Returns `0` if key not present. +]] +---@nodiscard +---@param key core.MetadataTable.fields.storage.keys.integer +---@return integer value +function StorageRef:get_int(key) end + +--[[ +* `set_float(key, value)` + * Store a number (a 64-bit float) exactly. + * The value will be converted into a string when stored. +]] +---@param key core.MetadataTable.fields.storage.keys.number +---@param value number +function StorageRef:set_float(key, value) end + +--[[ +WIPDOC +]] +---@nodiscard +---@param key core.MetadataTable.fields.storage.keys.number +---@return number value +function StorageRef:get_float(key) end + +--[[ +WIPDOC +]] +---@return core.MetadataTable.fields.storage.keys[] keys +function StorageRef:get_keys() end + +--[[ +WIPDOC +]] +---@nodiscard +---@param data core.MetadataTable.storage +---@return boolean? +function StorageRef:from_table(data) end + +--[[ +WIPDOC +]] +---@nodiscard +---@return core.MetadataTable.storage +function StorageRef:to_table() end diff --git a/types/luanti_lsp_definitions/library/classes/ValueNoise.lua b/types/luanti_lsp_definitions/library/classes/ValueNoise.lua new file mode 100644 index 00000000..25c505e7 --- /dev/null +++ b/types/luanti_lsp_definitions/library/classes/ValueNoise.lua @@ -0,0 +1,171 @@ +---@meta _ +-- DRAFT 1 DONE +-- luanti/doc/lua_api.md: Fractal Value Noise +-- luanti/doc/lua_api.md: 'core' namespace reference > Environment access +-- luanti/doc/lua_api.md: Class Reference > `ValueNoise` + +-- ------------------------------ constructors ------------------------------ -- + +--[[ +`ValueNoise` +------------- + +A value noise generator. +It can be created via `ValueNoise()` or `core.get_value_noise()`. +For `core.get_value_noise()`, the actual seed used is the noiseparams seed +plus the world seed, to create world-specific noise. + +**Important**: These require the mapgen environment to be initalized, do not use at load time. + +* `ValueNoise(noiseparams)` +* `ValueNoise(seed, octaves, persistence, spread)` (deprecated) +* `core.get_value_noise(noiseparams)` +* `core.get_value_noise(seeddiff, octaves, persistence, spread)` (deprecated) + +These were previously called `PerlinNoise()` and `core.get_perlin()`, but the +implemented noise was not Perlin noise. They were renamed in 5.12.0. The old +names still exist as aliases. +]] +---@nodiscard +---@param noiseparams core.NoiseParams +---@return core.ValueNoise +function ValueNoise(noiseparams) end + +--[[ +WIPDOC +]] +---@nodiscard +---@param noiseparams core.NoiseParams +---@return core.ValueNoise +function PerlinNoise(noiseparams) end + +--[[ +* `core.get_value_noise(noiseparams)` + * Return world-specific value noise. + * The actual seed used is the noiseparams seed plus the world seed. + * **Important**: Requires the mapgen environment to be initalized, do not use at load time. +]] +---@nodiscard +---@param noiseparams core.NoiseParams +---@return core.ValueNoise +function core.get_value_noise(noiseparams) end + +--[[ +* `core.get_perlin(noiseparams)` + * Deprecated: renamed to `core.get_value_noise` in version 5.12.0. +]] +---@deprecated +---@nodiscard +---@param noiseparams core.NoiseParams +---@return core.ValueNoise +function core.get_perlin(noiseparams) end + +-- ---------------------------- old constructors ---------------------------- -- + +--[[ +`ValueNoise` +------------- + +A value noise generator. +It can be created via `ValueNoise()` or `core.get_value_noise()`. +For `core.get_value_noise()`, the actual seed used is the noiseparams seed +plus the world seed, to create world-specific noise. + +**Important**: These require the mapgen environment to be initalized, do not use at load time. + +* `ValueNoise(noiseparams)` +* `ValueNoise(seed, octaves, persistence, spread)` (deprecated) +* `core.get_value_noise(noiseparams)` +* `core.get_value_noise(seeddiff, octaves, persistence, spread)` (deprecated) + +These were previously called `PerlinNoise()` and `core.get_perlin()`, but the +implemented noise was not Perlin noise. They were renamed in 5.12.0. The old +names still exist as aliases. +]] +---@deprecated +---@nodiscard +---@param seeddiff integer +---@param octaves integer +---@param persistence number +---@param spread vector|vec2.xy +---@return core.ValueNoise +function ValueNoise(seeddiff, octaves, persistence, spread) end + +--[[ +WIPDOC +]] +---@deprecated +---@nodiscard +---@param seeddiff integer +---@param octaves integer +---@param persistence number +---@param spread vector|vec2.xy +---@return core.ValueNoise +function PerlinNoise(seeddiff, octaves, persistence, spread) end + +--[[ +* `core.get_value_noise(seeddiff, octaves, persistence, spread)` + * Deprecated: use `core.get_value_noise(noiseparams)` instead. +]] +---@deprecated +---@nodiscard +---@param seeddiff integer +---@param octaves integer +---@param persistence number +---@param spread vector|vec2.xy +---@return core.ValueNoise +function core.get_value_noise(seeddiff, octaves, persistence, spread) end + +--[[ +* `core.get_perlin(seeddiff, octaves, persistence, spread)` + * Deprecated: renamed to `core.get_value_noise` in version 5.12.0. +]] +---@deprecated +---@nodiscard +---@param seeddiff integer +---@param octaves integer +---@param persistence number +---@param spread vector|vec2.xy +---@return core.ValueNoise +function core.get_perlin(seeddiff, octaves, persistence, spread) end + +-- ------------------------------- ValueNoise ------------------------------- -- + +--[[ +`ValueNoise` +------------- + +A value noise generator. +It can be created via `ValueNoise()` or `core.get_value_noise()`. +For `core.get_value_noise()`, the actual seed used is the noiseparams seed +plus the world seed, to create world-specific noise. + +**Important**: These require the mapgen environment to be initalized, do not use at load time. + +* `ValueNoise(noiseparams)` +* `ValueNoise(seed, octaves, persistence, spread)` (deprecated) +* `core.get_value_noise(noiseparams)` +* `core.get_value_noise(seeddiff, octaves, persistence, spread)` (deprecated) + +These were previously called `PerlinNoise()` and `core.get_perlin()`, but the +implemented noise was not Perlin noise. They were renamed in 5.12.0. The old +names still exist as aliases. +]] +---@class core.ValueNoise +local ValueNoise = {} + +--[[ +* `get_2d(pos)`: returns 2D noise value at `pos={x=,y=}` +]] +---@nodiscard +---@param pos vec2.xy +---@return vec2.xy +function ValueNoise:get_2d(pos) end + +--[[ +* `get_3d(pos)`: returns 3D noise value at `pos={x=,y=,z=}` +]] +---@nodiscard +---@param pos vector +---@return vec +function ValueNoise:get_3d(pos) end \ No newline at end of file diff --git a/types/luanti_lsp_definitions/library/classes/ValueNoiseMap.lua b/types/luanti_lsp_definitions/library/classes/ValueNoiseMap.lua new file mode 100644 index 00000000..73448d32 --- /dev/null +++ b/types/luanti_lsp_definitions/library/classes/ValueNoiseMap.lua @@ -0,0 +1,169 @@ +---@meta _ +-- DRAFT 1 DONE +-- luanti/doc/lua_api.md: Fractal Value Noise +-- luanti/doc/lua_api.md: Class Reference > `ValueNoiseMap` + +-- ------------------------------ constructors ------------------------------ -- + +--[[ +WIPDOC +]] +---@nodiscard +---@param noiseparams core.NoiseParams +---@param size ivector|vec2i.xy +---@return core.ValueNoiseMap +function ValueNoiseMap(noiseparams, size) end + +--[[ +WIPDOC +]] +---@nodiscard +---@param noiseparams core.NoiseParams +---@param size ivector|vec2i.xy +---@return core.ValueNoiseMap +function core.get_value_noise_map(noiseparams, size) end + +--[[ +WIPDOC +]] +---@nodiscard +---@param noiseparams core.NoiseParams +---@param size ivector|vec2i.xy +---@return core.ValueNoiseMap +function PerlinNoiseMap(noiseparams, size) end + +--[[ +WIPDOC +]] +---@nodiscard +---@param noiseparams core.NoiseParams +---@param size ivector|vec2i.xy +---@return core.ValueNoiseMap +function core.get_perlin_noise_map(noiseparams, size) end + +-- ------------------------------ ValueNoiseMap ----------------------------- -- + +--[[ +WIPDOC +]] +---@class core.ValueNoiseMap +local ValueNoiseMap = {} + +--[[ +* `get_2d_map(pos)`: returns a `` times `` 2D array of 2D noise + with values starting at `pos={x=,y=}` +]] +---@nodiscard +---@param pos vec2.xy +---@return number[][] +function ValueNoiseMap:get_2d_map(pos) end + +--[[ +* `get_3d_map(pos)`: returns a `` times `` times `` + 3D array of 3D noise with values starting at `pos={x=,y=,z=}`. +]] +---@nodiscard +---@param pos vector +---@return number[][][] +function ValueNoiseMap:get_3d_map(pos) end + +--[[ +* `get_2d_map_flat(pos, buffer)`: returns a flat `` element + array of 2D noise with values starting at `pos={x=,y=}` +]] +---@nodiscard +---@param pos vec2.xy +---@return number[] +function ValueNoiseMap:get_2d_map_flat(pos) end + +--[[ +* `get_2d_map_flat(pos, buffer)`: returns a flat `` element + array of 2D noise with values starting at `pos={x=,y=}` +]] +---@nodiscard +---@param pos vec2.xy +---@param buffer number[] +---@return nil +function ValueNoiseMap:get_2d_map_flat(pos, buffer) end + +--[[ +* `get_3d_map_flat(pos, buffer)`: Same as `get2dMap_flat`, but 3D noise +]] +---@nodiscard +---@param pos vector +---@return number[] +function ValueNoiseMap:get_3d_map_flat(pos) end + +--[[ +* `get_3d_map_flat(pos, buffer)`: Same as `get2dMap_flat`, but 3D noise +]] +---@nodiscard +---@param pos vector +---@param buffer number[] +---@return nil +function ValueNoiseMap:get_3d_map_flat(pos, buffer) end + +--[[ +* `calc_2d_map(pos)`: Calculates the 2d noise map starting at `pos`. The result + is stored internally. +]] +---@param pos vec2.xy +function ValueNoiseMap:calc_2d_map(pos) end + +--[[ +* `calc_3d_map(pos)`: Calculates the 3d noise map starting at `pos`. The result + is stored internally. +]] +---@param pos vector +function ValueNoiseMap:calc_3d_map(pos) end + +--[[ +* `get_map_slice(slice_offset, slice_size, buffer)`: In the form of an array, + returns a slice of the most recently computed noise results. The result slice + begins at coordinates `slice_offset` and takes a chunk of `slice_size`. + E.g., to grab a 2-slice high horizontal 2d plane of noise starting at buffer + offset `y = 20`: + ```lua + noisevals = noise:get_map_slice({y=20}, {y=2}) + ``` + It is important to note that `slice_offset` offset coordinates begin at 1, + and are relative to the starting position of the most recently calculated + noise. + To grab a single vertical column of noise starting at map coordinates + `x = 1023, y=1000, z = 1000`: + ```lua + noise:calc_3d_map({x=1000, y=1000, z=1000}) + noisevals = noise:get_map_slice({x=24, z=1}, {x=1, z=1}) + ``` +]] +---@nodiscard +---@param slice_offset vector +---@param slice_size vector +---@return number[] +function ValueNoiseMap:get_map_slice(slice_offset, slice_size, buffer) end + +--[[ +* `get_map_slice(slice_offset, slice_size, buffer)`: In the form of an array, + returns a slice of the most recently computed noise results. The result slice + begins at coordinates `slice_offset` and takes a chunk of `slice_size`. + E.g., to grab a 2-slice high horizontal 2d plane of noise starting at buffer + offset `y = 20`: + ```lua + noisevals = noise:get_map_slice({y=20}, {y=2}) + ``` + It is important to note that `slice_offset` offset coordinates begin at 1, + and are relative to the starting position of the most recently calculated + noise. + To grab a single vertical column of noise starting at map coordinates + `x = 1023, y=1000, z = 1000`: + ```lua + noise:calc_3d_map({x=1000, y=1000, z=1000}) + noisevals = noise:get_map_slice({x=24, z=1}, {x=1, z=1}) + ``` +]] +---@nodiscard +---@param slice_offset vector +---@param slice_size vector +---@param buffer number[] +---@return nil +function ValueNoiseMap:get_map_slice(slice_offset, slice_size, buffer) end \ No newline at end of file diff --git a/types/luanti_lsp_definitions/library/classes/VoxelArea.lua b/types/luanti_lsp_definitions/library/classes/VoxelArea.lua new file mode 100644 index 00000000..d479473f --- /dev/null +++ b/types/luanti_lsp_definitions/library/classes/VoxelArea.lua @@ -0,0 +1,129 @@ +---@meta _ +-- DRAFT 1 DONE +-- luanti/doc/lua_api.md: Map terminology and coordinates +-- luanti/doc/lua_api.md: Lua Voxel Manipulator +-- luanti/doc/lua_api.md: Class reference > `VoxelArea` + +-- ------------------------------- constructor ------------------------------ -- + +--[[ +WIPDOC +]] +---@nodiscard +---@param pmin ivector +---@param pmax ivector +---@return VoxelArea +function VoxelArea(pmin, pmax) end + +--[[ +WIPDOC +]] +---@nodiscard +---@param arg {MinEdge:ivector, MaxEdge:ivector} +---@return VoxelArea +function VoxelArea:new(arg) end + +-- -------------------------------- VoxelArea ------------------------------- -- + +--[[ +WIPDOC +]] +---@class VoxelArea +VoxelArea = {} + +--[[ +WIPDOC +]] +---@nodiscard +---@return ivec +function VoxelArea:getExtent() end + +--[[ +WIPDOC +]] +---@nodiscard +---@return integer +function VoxelArea:getVolume() end + +--[[ +* `index(x, y, z)`: returns the index of an absolute position in a flat array + starting at `1`. + * `x`, `y` and `z` must be integers to avoid an incorrect index result. + * The position (x, y, z) is not checked for being inside the area volume, + being outside can cause an incorrect index result. + * Useful for things like `VoxelManip`, raw Schematic specifiers, + `ValueNoiseMap:get2d`/`3dMap`, and so on. +]] +---@nodiscard +---@param x integer +---@param y integer +---@param z integer +---@return integer i +function VoxelArea:index(x, y, z) end + +--[[ +* `indexp(p)`: same functionality as `index(x, y, z)` but takes a vector. + * As with `index(x, y, z)`, the components of `p` must be integers, and `p` + is not checked for being inside the area volume. +]] +---@nodiscard +---@param p ivector +---@return integer i +function VoxelArea:indexp(p) end + +--[[ +* `position(i)`: returns the absolute position vector corresponding to index + `i`. +]] +---@nodiscard +---@param i integer +---@return ivec p +function VoxelArea:position(i) end + +--[[ +WIPDOC +]] +---@nodiscard +---@param x number +---@param y number +---@param z number +---@return boolean +function VoxelArea:contains(x, y, z) end + +--[[ +WIPDOC +]] +---@nodiscard +---@param p vector +---@return boolean +function VoxelArea:containsp(p) end + +--[[ +WIPDOC +]] +---@nodiscard +---@param i integer +---@return boolean +function VoxelArea:containsi(i) end + +--[[ +WIPDOC +]] +---@nodiscard +---@param minx integer +---@param miny integer +---@param minz integer +---@param maxx integer +---@param maxy integer +---@param maxz integer +---@return fun():integer? +function VoxelArea:iter(minx, miny, minz, maxx, maxy, maxz) end + +--[[ +WIPDOC +]] +---@nodiscard +---@param minp ivector +---@param maxp ivector +---@return fun():integer? +function VoxelArea:iterp(minp, maxp) end diff --git a/types/luanti_lsp_definitions/library/classes/VoxelManip.lua b/types/luanti_lsp_definitions/library/classes/VoxelManip.lua new file mode 100644 index 00000000..46d1361b --- /dev/null +++ b/types/luanti_lsp_definitions/library/classes/VoxelManip.lua @@ -0,0 +1,325 @@ +---@meta _ +-- DRAFT 1 DONE +-- luanti/doc/lua_api.md: Map terminology and coordinates +-- luanti/doc/lua_api.md: Lua Voxel Manipulator +-- luanti/doc/lua_api.md: 'core' namespace reference > Environment access +-- luanti/doc/lua_api.md: Class reference > `VoxelManip` + +--[[ +WIPDOC +]] +core.MAP_BLOCKSIZE = 16 + +--[[ +WIPDOC +]] +---@class core.ContentID: integer + +--[[ +WIPDOC +]] +---@type core.ContentID +core.CONTENT_UNKNOWN = 125 + +--[[ +WIPDOC +]] +---@type core.ContentID +core.CONTENT_AIR = 126 + +--[[ +WIPDOC +]] +---@type core.ContentID +core.CONTENT_IGNORE = 127 + +-- ---------------------------- VoxelManip.light ---------------------------- -- + +--[[ +WIPDOC +]] +---@class core.VoxelManip.light +local VoxelManipLight = {} + +--[[ +WIPDOC +]] +---@type core.Light.part +VoxelManipLight.day = nil + +--[[ +WIPDOC +]] +---@type core.Light.part +VoxelManipLight.night = nil + +-- ------------------------------- constructor ------------------------------ -- + +--[[ +WIPDOC +]] +---@nodiscard +---@param p1 ivector? +---@param p2 ivector? +---@return core.VoxelManip +function VoxelManip(p1, p2) end + +--[[ +WIPDOC +]] +---@nodiscard +---@param p1 ivector? +---@param p2 ivector? +---@return core.VoxelManip +function core.get_voxel_manip(p1, p2) end + +-- ------------------------------- VoxelManip ------------------------------- -- + +--[[ +Unofficial note: Building the next worldedit eh? + +About VoxelManip +---------------- + +VoxelManip is a scripting interface to the internal 'Map Voxel Manipulator' +facility. The purpose of this object is for fast, low-level, bulk access to +reading and writing Map content. As such, setting map nodes through VoxelManip +will lack many of the higher level features and concepts you may be used to +with other methods of setting nodes. For example, nodes will not have their +construction and destruction callbacks run, and no rollback information is +logged. + +It is important to note that VoxelManip is designed for speed, and *not* ease +of use or flexibility. If your mod requires a map manipulation facility that +will handle 100% of all edge cases, or the use of high level node placement +features, perhaps `core.set_node()` is better suited for the job. + +In addition, VoxelManip might not be faster, or could even be slower, for your +specific use case. VoxelManip is most effective when setting large areas of map +at once - for example, if only setting a 3x3x3 node area, a +`core.set_node()` loop may be more optimal. Always profile code using both +methods of map manipulation to determine which is most appropriate for your +usage. + +A recent simple test of setting cubic areas showed that `core.set_node()` +is faster than a VoxelManip for a 3x3x3 node cube or smaller. +]] +---@class core.VoxelManip +local VoxelManip = {} + +--[[ +* `read_from_map(p1, p2)`: Loads a part of the map into the VoxelManip object + containing the region formed by `p1` and `p2`. + * returns actual emerged `pmin`, actual emerged `pmax` (MapBlock-aligned) + * Note that calling this multiple times will *add* to the area loaded in the + VoxelManip, and not reset it. +]] +---@nodiscard +---@param p1 ivector +---@param p2 ivector +---@return ivec pmin, ivec pmax +function VoxelManip:read_from_map(p1, p2) end + +--[[ +* `initialize(p1, p2, [node])`: Clears and resizes the VoxelManip object to + comprise the region formed by `p1` and `p2`. + * **No data** is read from the map, so you can use this to treat `VoxelManip` + objects as general containers of node data. + * `node`: if present the data will be filled with this node; if not it will + be uninitialized + * returns actual emerged `pmin`, actual emerged `pmax` (MapBlock-aligned) + * (introduced in 5.13.0) +]] +---@nodiscard +---@param p1 ivector +---@param p2 ivector +---@param node core.Node.set +---@return ivec pmin, ivec pmax +function VoxelManip:initialize(p1, p2, node) end + +--[[ +Unofficial note: If you can, try to not use this function for performance reasons (there is no alternative, but you can avoid using it by checking if vmanip data was modified, if yes then use it) + +* `write_to_map([light])`: Writes the data loaded from the `VoxelManip` back to + the map. + * **important**: you should call `set_data()` before this, or nothing will change. + * if `light` is true, then lighting is automatically recalculated. + The default value is true. + If `light` is false, no light calculations happen, and you should correct + all modified blocks with `core.fix_light()` as soon as possible. + Keep in mind that modifying the map where light is incorrect can cause + more lighting bugs. +]] +---@param light boolean? +function VoxelManip:write_to_map(light) end + +--[[ +Unofficial note: i don't think you should be using this for performance reasons, this is a function i would personally NEVER use +]] +---@nodiscard +---@param pos ivector +---@return core.Node.get +function VoxelManip:get_node_at(pos) end + +--[[ +Unofficial note: i don't think you should be using this for performance reasons, this is a function i would personally NEVER use +]] +---@param pos ivector +---@param node core.Node.set +function VoxelManip:set_node_at(pos, node) end + +--[[ +Retrieves the node content data loaded into the `VoxelManip` object, the `data` table will be used to store the result +]] +---@param data core.ContentID[] +---@return nil +function VoxelManip:get_data(data) end + +--[[ +Retrieves the node content data loaded into the `VoxelManip` object and returns it +Unofficial note: I would recommend doing VoxelManip.get_data(data) instead, as this form will make the garbage collector scream, in a way that you can't profile very well +]] +---@nodiscard +---@return core.ContentID[] data +function VoxelManip:get_data() end + +--[[ +WIPDOC +]] +---@param data core.ContentID[] +---@return nil +function VoxelManip:set_data(data) end + +--[[ +Unofficial note: In need of a noop? Instead of depending on modlib to do it, how +about using this pre-made function baked into the luanti api, written most +likely in C for super fast noop +Does nothing, kept for compatibility. +]] +---@deprecated +function VoxelManip:update_map() end + +--[[ +* `set_lighting(light, [p1, p2])`: Set the lighting within the `VoxelManip` to + a uniform value. + * `light` is a table, `{day=<0...15>, night=<0...15>}` + * To be used only by a `VoxelManip` object from + `core.get_mapgen_object`. + * (`p1`, `p2`) is the area in which lighting is set, defaults to the whole + area if left out. +]] +---@param light core.VoxelManip.light +---@param p1 ivector? +---@param p2 ivector? +function VoxelManip:set_lighting(light, p1, p2) end + +--[[ +* `get_light_data([buffer])`: Gets the light data read into the + `VoxelManip` object + * Returns an array (indices 1 to volume) of integers ranging from `0` to + `255`. + * Each value is the bitwise combination of day and night light values + (`0` to `15` each). + * `light = day + (night * 16)` + * If the param `buffer` is present, this table will be used to store the + result instead. +]] +---@param buffer core.Light[] +---@return nil +function VoxelManip:get_light_data(buffer) end + +--[[ +* `get_light_data([buffer])`: Gets the light data read into the + `VoxelManip` object + * Returns an array (indices 1 to volume) of integers ranging from `0` to + `255`. + * Each value is the bitwise combination of day and night light values + (`0` to `15` each). + * `light = day + (night * 16)` + * If the param `buffer` is present, this table will be used to store the + result instead. +]] +---@nodiscard +---@return core.Light[] light_data +function VoxelManip:get_light_data() end + +--[[ +* `set_light_data(light_data)`: Sets the `param1` (light) contents of each node + in the `VoxelManip`. + * expects lighting data in the same format that `get_light_data()` returns +]] +---@param light_data core.Light[] +function VoxelManip:set_light_data(light_data) end + +--[[ +WIPDOC +]] +---@nodiscard +---@return core.Param2[] param2_data +function VoxelManip:get_param2_data() end + +--[[ +WIPDOC +]] +---@param buffer core.Param2[]? +---@return nil +function VoxelManip:get_param2_data(buffer) end + +--[[ +WIPDOC +]] +---@param param2_data core.Param2[] +function VoxelManip:set_param2_data(param2_data) end + +--[[ +* `calc_lighting([p1, p2], [propagate_shadow])`: Calculate lighting within the + `VoxelManip`. + * To be used only with a `VoxelManip` object from `core.get_mapgen_object`. + * (`p1`, `p2`) is the area in which lighting is set, defaults to the whole + area if left out or nil. For almost all uses these should be left out + or nil to use the default. + * `propagate_shadow` is an optional boolean deciding whether shadows in a + generated mapchunk above are propagated down into the mapchunk, defaults + to `true` if left out. +]] +---@param p1 vector? +---@param p2 vector? +---@param propagate_shadow boolean? +function VoxelManip:calc_lighting(p1, p2, propagate_shadow) end + +--[[ +WIPDOC +]] +function VoxelManip:update_liquids() end + +--[[ +* `was_modified()`: Returns `true` if the data in the VoxelManip has been modified + since it was last read from the map. This means you have to call `get_data()` again. + This only applies to a `VoxelManip` object from `core.get_mapgen_object`, + where the engine will keep the map and the VM in sync automatically. + * Note: this doesn't do what you think it does and is subject to removal. Don't use it! +]] +---@deprecated +---@nodiscard +---@return boolean +function VoxelManip:was_modified() end + +--[[ +* `get_emerged_area()`: Returns actual emerged minimum and maximum positions. +* "Emerged" does not imply that this region was actually loaded from the map, + if `initialize()` has been used. +]] +---@nodiscard +---@return ivec emin, ivec emax +function VoxelManip:get_emerged_area() end + +--[[ +* `close()`: Frees the data buffers associated with the VoxelManip object. + It will become empty. + * Since Lua's garbage collector is not aware of the potentially significant + memory behind a VoxelManip, frequent VoxelManip usage can cause the server to + run out of RAM. Therefore it's recommend to call this method once you're done + with the VoxelManip. + * (introduced in 5.13.0) +]] +function VoxelManip:close() end diff --git a/types/luanti_lsp_definitions/library/core/async_environment.lua b/types/luanti_lsp_definitions/library/core/async_environment.lua new file mode 100644 index 00000000..0ce4e761 --- /dev/null +++ b/types/luanti_lsp_definitions/library/core/async_environment.lua @@ -0,0 +1,38 @@ +---@meta _ +-- DRAFT 1 DONE +-- luanti/doc/lua_api.md: 'core' namespace reference > Async environment + +--[[ +WIPDOC +]] +---@nodiscard +---@param f function +---@param callback function +---@param ... any +---@return core.AsyncJob +function core.handle_async(f, callback, ...) end + +--[[ +* `core.register_async_dofile(path)`: + * Register a path to a Lua file to be imported when an async environment + is initialized. You can use this to preload code which you can then call + later using `core.handle_async()`. +]] +---@param path core.Path +function core.register_async_dofile(path) end + +--[[ +WIPDOC +]] +---@class corelib.async +local async = { + settings = core.settings, + +-- TODO async registered_* has functions and userdata set to true instead + registered_items = core.registered_items, + registered_nodes = core.registered_nodes, + registered_tools = core.registered_tools, + registered_craftitems = core.registered_craftitems, + registered_aliases = core.registered_aliases, +-- TODO ... and more. WHY THE FUCK DON'T THEY JUST LIST THE GODDAMN FUNCTIONS +} \ No newline at end of file diff --git a/types/luanti_lsp_definitions/library/core/authentication.lua b/types/luanti_lsp_definitions/library/core/authentication.lua new file mode 100644 index 00000000..bf9b9064 --- /dev/null +++ b/types/luanti_lsp_definitions/library/core/authentication.lua @@ -0,0 +1,185 @@ +---@meta _ +-- DRAFT 1 DONE +-- luanti/doc/lua_api.md: 'core' namespace reference > Authentication + +--[[ +* `core.string_to_privs(str[, delim])`: + * Converts string representation of privs into table form + * `delim`: String separating the privs. Defaults to `","`. + * Returns `{ priv1 = true, ... }` +]] +---@nodiscard +---@param str string +---@param delim string? +---@return core.PrivilegeSet +function core.string_to_privs(str, delim) end + +--[[ +* `core.privs_to_string(privs[, delim])`: + * Returns the string representation of `privs` + * `delim`: String to delimit privs. Defaults to `","`. +]] +---@nodiscard +---@param privs core.PrivilegeSet +---@param delim string? +---@return string +function core.privs_to_string(privs, delim) end + +--[[ +* `core.get_player_privs(name) -> {priv1=true,...}` + +`core.set_player_password`, `core.set_player_privs`, +`core.get_player_privs` and `core.auth_reload` call the authentication +handler. +]] +---@nodiscard +---@param name string +---@return core.PrivilegeSet +function core.get_player_privs(name) end + +--[[ +* `core.check_player_privs(player_or_name, ...)`: + returns `bool, missing_privs` + * A quickhand for checking privileges. + * `player_or_name`: Either a Player object or the name of a player. + * `...` is either a list of strings, e.g. `"priva", "privb"` or + a table, e.g. `{ priva = true, privb = true }`. +]] +---@nodiscard +---@param player_or_name core.PlayerRef|string +---@param privs core.PrivilegeSet +---@return boolean, core.PrivilegeSet missing_privs +function core.check_player_privs(player_or_name, privs) end + +--[[ +* `core.check_player_privs(player_or_name, ...)`: + returns `bool, missing_privs` + * A quickhand for checking privileges. + * `player_or_name`: Either a Player object or the name of a player. + * `...` is either a list of strings, e.g. `"priva", "privb"` or + a table, e.g. `{ priva = true, privb = true }`. +]] +---@nodiscard +---@param player_or_name core.PlayerRef|string +---@param ... core.PrivilegeSet.keys +---@return boolean, core.PrivilegeSet missing_privs +function core.check_player_privs(player_or_name, ...) end + +--[[ +* `core.check_password_entry(name, entry, password)` + * Returns true if the "password entry" for a player with name matches given + password, false otherwise. + * The "password entry" is the password representation generated by the + engine as returned as part of a `get_auth()` call on the auth handler. + * Only use this function for making it possible to log in via password from + external protocols such as IRC, other uses are frowned upon. +]] +---@param name string +---@param entry string +---@param password string +---@return boolean +function core.check_password_entry(name, entry, password) end + +--[[ +* `core.get_password_hash(name, raw_password)` + * Convert a name-password pair to a password hash that Luanti can use. + * The returned value alone is not a good basis for password checks based + on comparing the password hash in the database with the password hash + from the function, with an externally provided password, as the hash + in the db might use the new SRP verifier format. + * For this purpose, use `core.check_password_entry` instead. +]] +---@nodiscard +---@param name string +---@param raw_password string +---@return string +function core.get_password_hash(name, raw_password) end + +--[[ +* `core.get_player_ip(name)`: returns an IP address string for the player + `name`. + * The player needs to be online for this to be successful. +]] +---@nodiscard +---@param name string +---@return string? +function core.get_player_ip(name) end + +--[[ +* `core.get_auth_handler()`: Return the currently active auth handler + * Must be called *after* load time, to ensure that any custom auth handler was + already registered. + * See the [Authentication handler definition](#authentication-handler-definition) + * Use this to e.g. get the authentication data for a player: + `local auth_data = core.get_auth_handler().get_auth(playername)` +]] +---@nodiscard +---@return core.AuthenticationHandlerDef +function core.get_auth_handler() end + +--[[ +* `core.notify_authentication_modified(name)` + * Must be called by the authentication handler for privilege changes. + * `name`: string; if omitted, all auth data should be considered modified +]] +---@param name string? +function core.notify_authentication_modified(name) end + +--[[ +* `core.set_player_password(name, password_hash)`: Set password hash of + player `name`. + +`core.set_player_password`, `core.set_player_privs`, +`core.get_player_privs` and `core.auth_reload` call the authentication +handler. +]] +---@param name string +---@param password_hash string +function core.set_player_password(name, password_hash) end + +--[[ +* `core.set_player_privs(name, privs)`: Set privileges of player `name`. + * `privs` is a **set** of privileges: + A table where the keys are names of privileges and the values are `true`. + * Example: `core.set_player_privs("singleplayer", {interact = true, fly = true})`. + This **sets** the player privileges to `interact` and `fly`; + `singleplayer` will only have these two privileges afterwards. + +`core.set_player_password`, `core.set_player_privs`, +`core.get_player_privs` and `core.auth_reload` call the authentication +handler. +--]] +---@param name string +---@param privs core.PrivilegeSet +function core.set_player_privs(name, privs) end + +--[[ +* `core.change_player_privs(name, changes)`: Helper to grant or revoke privileges. + * `changes`: Table of changes to make. + A field `[privname] = true` grants a privilege, + whereas `[privname] = false` revokes a privilege. + * Example: `core.change_player_privs("singleplayer", {interact = true, fly = false})` + will grant singleplayer the `interact` privilege + and revoke singleplayer's `fly` privilege. + All other privileges will remain unchanged. + +**UNOFFICIAL** + +For directly replacing all of a player's set of privileges with +another set, see `core.set_player_privs(...)` +]] +---@param name string +---@param changes core.PrivilegeSet +function core.change_player_privs(name, changes) end + +--[[ +* `core.auth_reload()` + * See `reload()` in authentication handler definition + +`core.set_player_password`, `core.set_player_privs`, +`core.get_player_privs` and `core.auth_reload` call the authentication +handler. +]] +---@nodiscard +---@return boolean +function core.auth_reload() end \ No newline at end of file diff --git a/types/luanti_lsp_definitions/library/core/ban.lua b/types/luanti_lsp_definitions/library/core/ban.lua new file mode 100644 index 00000000..a40a753d --- /dev/null +++ b/types/luanti_lsp_definitions/library/core/ban.lua @@ -0,0 +1,61 @@ +---@meta _ +-- DRAFT 1 DONE +-- luanti/doc/lua_api.md: 'core' namespace reference > Bans + +--[[ +* `core.get_ban_list()`: returns a list of all bans formatted as string +]] +---@nodiscard +---@return string +function core.get_ban_list() end + +--[[ +* `core.get_ban_description(ip_or_name)`: returns list of bans matching + IP address or name formatted as string +]] +---@nodiscard +---@param ip_or_name string +---@return string +function core.get_ban_description(ip_or_name) end + +--[[ +* `core.ban_player(name)`: ban the IP of a currently connected player + * Returns boolean indicating success +]] +---@nodiscard +---@param name string +---@return boolean success +function core.ban_player(name) end + +--[[ +* `core.unban_player_or_ip(ip_or_name)`: remove ban record matching + IP address or name +]] +---@param ip_or_name string +function core.unban_player_or_ip(ip_or_name) end + +--[=[ +* `core.kick_player(name[, reason[, reconnect]])`: disconnect a player with an optional + reason. + * Returns boolean indicating success (false if player nonexistent) + * If `reconnect` is true, allow the user to reconnect. +]=] +---@nodiscard +---@param name string +---@param reason string? +---@param reconnect boolean? +---@return boolean success +function core.kick_player(name, reason, reconnect) end + +--[=[ +* `core.disconnect_player(name[, reason[, reconnect]])`: disconnect a player with an + optional reason, this will not prefix with 'Kicked: ' like kick_player. + If no reason is given, it will default to 'Disconnected.' + * Returns boolean indicating success (false if player nonexistent) +]=] +---@nodiscard +---@param name string +---@param reason string? +---@param reconnect boolean? +---@return boolean +function core.disconnect_player(name, reason, reconnect) end \ No newline at end of file diff --git a/types/luanti_lsp_definitions/library/core/chat.lua b/types/luanti_lsp_definitions/library/core/chat.lua new file mode 100644 index 00000000..890ea3d0 --- /dev/null +++ b/types/luanti_lsp_definitions/library/core/chat.lua @@ -0,0 +1,30 @@ +---@meta _ +-- DRAFT 1 DONE +-- luanti/doc/lua_api.md: 'core' namespace reference > Chat + +--[[ +WIPDOC +]] +---@param text string +function core.chat_send_all(text) end + +--[[ +WIPDOC +]] +---@param name string +---@param text string +function core.chat_send_player(name, text) end + +--[[ +* `core.format_chat_message(name, message)` + * Used by the server to format a chat message, based on the setting `chat_message_format`. + Refer to the documentation of the setting for a list of valid placeholders. + * Takes player name and message, and returns the formatted string to be sent to players. + * Can be redefined by mods if required, for things like colored names or messages. + * **Only** the first occurrence of each placeholder will be replaced. +]] +---@nodiscard +---@param name string +---@param message string +---@return string +function core.format_chat_message(name, message) end diff --git a/types/luanti_lsp_definitions/library/core/core.lua b/types/luanti_lsp_definitions/library/core/core.lua new file mode 100644 index 00000000..b9897744 --- /dev/null +++ b/types/luanti_lsp_definitions/library/core/core.lua @@ -0,0 +1,24 @@ +---@meta _ +-- DRAFT 1 DONE +-- luanti/doc/lua_api.md: 'core' namespace reference +-- luanti/doc/lua_api.md: 'core' namespace reference > Global objects + +--[[ +WIPDOC +]] +---@class corelib +core = {} + +--[[ +WIPDOC +]] +---@deprecated +---@type corelib +core.env = core + +--[[ +WIPDOC +]] +---@deprecated +---@class minetest: corelib +minetest = core diff --git a/types/luanti_lsp_definitions/library/core/defaults.lua b/types/luanti_lsp_definitions/library/core/defaults.lua new file mode 100644 index 00000000..b349ae88 --- /dev/null +++ b/types/luanti_lsp_definitions/library/core/defaults.lua @@ -0,0 +1,156 @@ +---@meta _ +-- DRAFT 1 DONE +-- luanti/doc/lua_api.md: 'core' namespace reference > Defaults for the `on_place` and `on_drop` item definition functions +-- luanti/doc/lua_api.md: 'core' namespace reference > Defaults for the `on_punch` and `on_dig` node definition callbacks + +--[[ +* `core.item_place_node(itemstack, placer, pointed_thing[, param2, prevent_after_place])` + * Place item as a node + * `param2` overrides `facedir` and wallmounted `param2` + * `prevent_after_place`: if set to `true`, `after_place_node` is not called + for the newly placed node to prevent a callback and placement loop + * returns `itemstack, position` + * `position`: the location the node was placed to. `nil` if nothing was placed. +]] +---@nodiscard +---@param itemstack core.ItemStack +---@param placer core.ObjectRef +---@param pointed_thing core.PointedThing +---@param param2 core.Param2? +---@param prevent_after_place boolean? +---@return core.ItemStack, ivec? +function core.item_place_node(itemstack, placer, pointed_thing, param2, prevent_after_place) end + +--[[ +* `core.item_place_object(itemstack, placer, pointed_thing)` + * Place item as-is + * returns the leftover itemstack + * **Note**: This function is deprecated and will never be called. +]] +---@deprecated +---@nodiscard +---@param itemstack core.ItemStack +---@param placer core.ObjectRef +---@param pointed_thing core.PointedThing +---@return core.ItemStack +function core.item_place_object(itemstack, placer, pointed_thing) end + +--[[ +* `core.item_place(itemstack, placer, pointed_thing[, param2])` + * Wrapper that calls `core.item_place_node` if appropriate + * Calls `on_rightclick` of `pointed_thing.under` if defined instead + * **Note**: is not called when wielded item overrides `on_place` + * `param2` overrides facedir and wallmounted `param2` + * returns `itemstack, position` + * `position`: the location the node was placed to. `nil` if nothing was placed. +]] +---@nodiscard +---@param itemstack core.ItemStack +---@param placer core.ObjectRef +---@param pointed_thing core.PointedThing +---@param param2 core.Param2? +---@return core.ItemStack, vec? +function core.item_place(itemstack, placer, pointed_thing, param2) end + +--[[ +* `core.item_pickup(itemstack, picker, pointed_thing, time_from_last_punch, ...)` + * Runs callbacks registered by `core.register_on_item_pickup` and adds + the item to the picker's `"main"` inventory list. + * Parameters and return value are the same as `on_pickup`. + * **Note**: is not called when wielded item overrides `on_pickup` +]] +---@nodiscard +---@param itemstack core.ItemStack +---@param picker core.ObjectRef +---@param pointed_thing core.PointedThing +---@param time_from_last_punch number +---@param tool_capabilities core.ToolCapabilities? +---@param dir vector +---@param damage integer? +---@return core.ItemStack +function core.item_pickup(itemstack, picker, pointed_thing, time_from_last_punch, tool_capabilities, dir, damage) end + +--[[ +* `core.item_secondary_use(itemstack, user)` + * Global secondary use callback. Does nothing. + * Parameters and return value are the same as `on_secondary_use`. + * **Note**: is not called when wielded item overrides `on_secondary_use` +]] +---@nodiscard +---@param itemstack core.ItemStack +---@param user core.ObjectRef? +---@return core.ItemStack? +function core.item_secondary_use(itemstack, user) end + +--[[ +* `core.item_drop(itemstack, dropper, pos)` + * Converts `itemstack` to an in-world Lua entity. + * `itemstack` (`ItemStack`) is modified (cleared) on success. + * In versions < 5.12.0, `itemstack` was cleared in all cases. + * `dropper` (`ObjectRef`) is optional. + * Returned values on success: + 1. leftover itemstack + 2. `ObjectRef` of the spawned object (provided since 5.12.0) +]] +---@nodiscard +---@param itemstack core.ItemStack +---@param dropper core.ObjectRef? +---@param pos vector +---@return core.ItemStack, core.ObjectRef +function core.item_drop(itemstack, dropper, pos) end + +--[[ +* `core.item_drop(itemstack, dropper, pos)` + * Converts `itemstack` to an in-world Lua entity. + * `itemstack` (`ItemStack`) is modified (cleared) on success. + * In versions < 5.12.0, `itemstack` was cleared in all cases. + * `dropper` (`ObjectRef`) is optional. + * Returned values on success: + 1. leftover itemstack + 2. `ObjectRef` of the spawned object (provided since 5.12.0) +]] +---@nodiscard +---@param itemstack core.ItemStack +---@param dropper core.ObjectRef? +---@param pos vector +---@return nil +function core.item_drop(itemstack, dropper, pos) end + +--[[ +WIPDOC +]] +---@alias core.fn.item_eat fun(itemstack:core.ItemStack, user:core.ObjectRef, pointed_thing:core.PointedThing):core.ItemStack? + +--[[ +* `core.item_eat(hp_change[, replace_with_item])` + * Returns `function(itemstack, user, pointed_thing)` as a + function wrapper for `core.do_item_eat`. + * `replace_with_item` is the itemstring which is added to the inventory. + If the player is eating a stack and `replace_with_item` doesn't fit onto + the eaten stack, then the remaining go to a different spot, or are dropped. +]] +---@nodiscard +---@param hp_change integer +---@param replace_with_item core.Item.stringfmt? +---@return core.fn.item_eat +function core.item_eat(hp_change, replace_with_item) end + +--[[ +* `core.node_punch(pos, node, puncher, pointed_thing)` + * Calls functions registered by `core.register_on_punchnode()` +]] +---@param pos ivector +---@param node core.Node.set +---@param puncher core.ObjectRef +---@param pointed_thing core.PointedThing +function core.node_punch(pos, node, puncher, pointed_thing) end + +--[[ +* `core.node_dig(pos, node, digger)` + * Checks if node can be dug, puts item into inventory, removes node + * Calls functions registered by `core.register_on_dignodes()` +]] +---@param pos ivector +---@param node core.Node.set +---@param digger core.ObjectRef +function core.node_dig(pos, node, digger) end \ No newline at end of file diff --git a/types/luanti_lsp_definitions/library/core/environment/biome_data.lua b/types/luanti_lsp_definitions/library/core/environment/biome_data.lua new file mode 100644 index 00000000..cf4292a1 --- /dev/null +++ b/types/luanti_lsp_definitions/library/core/environment/biome_data.lua @@ -0,0 +1,33 @@ +---@meta _ +-- DRAFT 1 DONE +-- luanti/doc/lua_api.md: 'core' namespace reference > Environment access + +--[[ +WIPDOC +]] +---@class core.BiomeData +--[[ +WIPDOC +]] +---@field biome core.BiomeID +--[[ +WIPDOC +]] +---@field heat number +--[[ +WIPDOC +]] +---@field humidity number + +--[[ +* `core.get_biome_data(pos)` + * Returns a table containing: + * `biome` the biome id of the biome at that position + * `heat` the heat at the position + * `humidity` the humidity at the position + * Or returns `nil` on failure. +]] +---@nodiscard +---@param pos ivector +---@return core.BiomeData? +function core.get_biome_data(pos) end \ No newline at end of file diff --git a/types/luanti_lsp_definitions/library/core/environment/emerge_area.lua b/types/luanti_lsp_definitions/library/core/environment/emerge_area.lua new file mode 100644 index 00000000..57517914 --- /dev/null +++ b/types/luanti_lsp_definitions/library/core/environment/emerge_area.lua @@ -0,0 +1,75 @@ +---@meta _ +-- DRAFT 1 DONE +-- luanti/doc/lua_api.md: 'core' namespace reference > Environment access + +-- ------------------------------- EMERGE enum ------------------------------ -- + +--[[ +WIPDOC +]] +---@class core.EmergeAction : integer + +--[[ +WIPDOC +]] +---@type core.EmergeAction +core.EMERGE_CANCELLED = nil + +--[[ +WIPDOC +]] +---@type core.EmergeAction +core.EMERGE_ERRORED = nil + +--[[ +WIPDOC +]] +---@type core.EmergeAction +core.EMERGE_FROM_MEMORY = nil + +--[[ +WIPDOC +]] +---@type core.EmergeAction +core.EMERGE_FROM_DISK = nil + +--[[ +WIPDOC +]] +---@type core.EmergeAction +core.EMERGE_GENERATED = nil + +-- ---------------------------- core.* functions ---------------------------- -- + +--[[ +WIPDOC +]] +---@alias core.fn.emerge_area fun(blockpos:ivec, action:core.EmergeAction , calls_remaining:integer, param:any?) + +--[[ +* `core.emerge_area(pos1, pos2, [callback], [param])` + * Queue all blocks in the area from `pos1` to `pos2`, inclusive, to be + asynchronously fetched from memory, loaded from disk, or if inexistent, + generates them. + * If `callback` is a valid Lua function, this will be called for each block + emerged. + * The function signature of callback is: + `function EmergeAreaCallback(blockpos, action, calls_remaining, param)` + * `blockpos` is the *block* coordinates of the block that had been + emerged. + * `action` could be one of the following constant values: + * `core.EMERGE_CANCELLED` + * `core.EMERGE_ERRORED` + * `core.EMERGE_FROM_MEMORY` + * `core.EMERGE_FROM_DISK` + * `core.EMERGE_GENERATED` + * `calls_remaining` is the number of callbacks to be expected after + this one. + * `param` is the user-defined parameter passed to emerge_area (or + nil if the parameter was absent). +]] +---@param pos1 ivector +---@param pos2 ivector +---@param callback core.fn.emerge_area? +---@param param any? +function core.emerge_area(pos1, pos2, callback, param) end \ No newline at end of file diff --git a/types/luanti_lsp_definitions/library/core/environment/environment.lua b/types/luanti_lsp_definitions/library/core/environment/environment.lua new file mode 100644 index 00000000..834f54d7 --- /dev/null +++ b/types/luanti_lsp_definitions/library/core/environment/environment.lua @@ -0,0 +1,946 @@ +---@meta _ +-- DRAFT 1 DONE +-- luanti/doc/lua_api.md: 'core' namespace reference > Environment access + +-- ---------------------------------- node ---------------------------------- -- + +--[[ +* `core.set_node(pos, node)` + * Set node at position `pos`. + * Any existing metadata is deleted. + * `node`: table `{name=string, param1=number, param2=number}` + If param1 or param2 is omitted, it's set to `0`. + * e.g. `core.set_node({x=0, y=10, z=0}, {name="default:wood"})` +]] +---@param pos ivector +---@param node core.Node.set +function core.set_node(pos, node) end + +--[[ +Alias to core.set_node +Unofficial note: I think you should be strict and only use `core.set_node` +]] +core.add_node = core.set_node + +--[[ +WIPDOC +]] +---@param posarr ivector[] +---@param node core.Node.set +function core.bulk_set_node(posarr, node) end + +--[[ +* `core.swap_node(pos, node)` + * Swap node at position with another. + * This keeps the metadata intact and will not run con-/destructor callbacks. +]] +---@param pos ivector +---@param node core.Node.set +function core.swap_node(pos, node) end + +--[[ +* `core.bulk_swap_node({pos1, pos2, pos3, ...}, node)` + * Equivalent to `core.swap_node` but in bulk. +]] +---@param posarr ivector[] +---@param node core.Node.set +function core.bulk_swap_node(posarr, node) end + +--[[ +* `core.remove_node(pos)`: Remove a node + * Equivalent to `core.set_node(pos, {name="air"})`, but a bit faster. +]] +---@param pos ivector +function core.remove_node(pos) end + +--[[ +* `core.get_node(pos)` + * Returns the node at the given position as table in the same format as `set_node`. + * This function never returns `nil` and instead returns + `{name="ignore", param1=0, param2=0}` for unloaded areas. +]] +---@nodiscard +---@param pos ivector +---@return core.Node.set +function core.get_node(pos) end + +--[[ +* `core.get_node_or_nil(pos)` + * Same as `get_node` but returns `nil` for unloaded areas. + * Note that even loaded areas can contain "ignore" nodes. +]] +---@nodiscard +---@param pos ivector +---@return core.Node.get? +function core.get_node_or_nil(pos) end + +--[[ +* `core.get_node_raw(x, y, z)` + * Same as `get_node` but a faster low-level API + * Returns `content_id`, `param1`, `param2`, and `pos_ok` + * The `content_id` can be mapped to a name using `core.get_name_from_content_id()` + * If `pos_ok` is false, the area is unloaded and `content_id == core.CONTENT_IGNORE` +]] +---@nodiscard +---@param x integer +---@param y integer +---@param z integer +---@return core.ContentID content_id, core.Param1 param1, core.Param2 param2, boolean pos_ok +function core.get_node_raw(x, y, z) end + +--[[ +* `core.get_node_light(pos[, timeofday])` + * Gets the light value at the given position. Note that the light value + "inside" the node at the given position is returned, so you usually want + to get the light value of a neighbor. + * `pos`: The position where to measure the light. + * `timeofday`: `nil` for current time, `0` for night, `0.5` for day + * Returns a number between `0` and `15` or `nil` + * `nil` is returned e.g. when the map isn't loaded at `pos` +]] +---@nodiscard +---@param pos ivector +---@param timeofday number? +---@return core.Light.part? +function core.get_node_light(pos, timeofday) end + +--[[ +* `core.get_natural_light(pos[, timeofday])` + * Figures out the sunlight (or moonlight) value at pos at the given time of + day. + * `pos`: The position of the node + * `timeofday`: `nil` for current time, `0` for night, `0.5` for day + * Returns a number between `0` and `15` or `nil` + * This function tests 203 nodes in the worst case, which happens very + unlikely +]] +---@param pos ivector +---@param timeofday number? +---@return core.Light.part? +function core.get_natural_light(pos, timeofday) end + +--[[ +* `core.get_artificial_light(param1)` + * Calculates the artificial light (light from e.g. torches) value from the + `param1` value. + * `param1`: The param1 value of a `paramtype = "light"` node. + * Returns a number between `0` and `15` + * Currently it's the same as `math.floor(param1 / 16)`, except that it + ensures compatibility. +]] +---@nodiscard +---@param param1 core.Param1 +---@return core.Light.part +function core.get_artificial_light(param1) end + +--[[ +* `core.place_node(pos, node[, placer])` + * Place node with the same effects that a player would cause + * `placer`: The ObjectRef that places the node (optional) +]] +---@nodiscard +---@param pos ivector +---@param node core.Node.get +---@param placer core.PlayerRef? +---@return boolean +function core.place_node(pos, node, placer) end + +--[[ +* `core.dig_node(pos[, digger])` + * Dig node with the same effects that a player would cause + * `digger`: The ObjectRef that digs the node (optional) + * Returns `true` if successful, `false` on failure (e.g. protected location) +]] +---@nodiscard +---@param pos ivector +---@param digger core.PlayerRef? +---@return boolean +function core.dig_node(pos, digger) end + +--[[ +* `core.punch_node(pos[, puncher])` + * Punch node with the same effects that a player would cause + * `puncher`: The ObjectRef that punches the node (optional) +]] +---@nodiscard +---@param pos ivector +---@param puncher core.PlayerRef? +---@return boolean +function core.punch_node(pos, puncher) end + +--[[ +* `core.spawn_falling_node(pos)` + * Change node into falling node + * Returns `true` and the ObjectRef of the spawned entity if successful, `false` on failure +]] +---@nodiscard +---@param pos ivector +---@return boolean +function core.spawn_falling_node(pos) end + +--[[ +* `core.find_nodes_with_meta(pos1, pos2)` + * Get a table of positions of nodes that have metadata within a region + {pos1, pos2}. +]] +---@nodiscard +---@param pos1 ivector +---@param pos2 ivector +---@return vec[] +function core.find_nodes_with_meta(pos1, pos2) end + +--[[ +WIPDOC +]] +---@nodiscard +---@param pos ivector +---@return core.NodeMetaRef +function core.get_meta(pos) end + +--[[ +WIPDOC +]] +---@nodiscard +---@param pos ivector +---@return core.NodeTimerRef +function core.get_node_timer(pos) end + +-- --------------------------------- entity --------------------------------- -- + +--[[ +* `core.add_entity(pos, name, [staticdata])`: Spawn Lua-defined entity at + position. + * Returns `ObjectRef`, or `nil` if failed + * Entities with `static_save = true` can be added also + to unloaded and non-generated blocks. +]] +---@nodiscard +---@param pos vector +---@param name string +---@param staticdata string? +---@return core.EntityRef? +function core.add_entity(pos, name, staticdata) end + +--[[ +* `core.add_item(pos, item)`: Spawn item + * Returns `ObjectRef`, or `nil` if failed + * Items can be added also to unloaded and non-generated blocks. +]] +---@nodiscard +---@param pos vector +---@param item core.Item +---@return core.EntityRef? +function core.add_item(pos, item) end + +--[[ +* `core.get_player_by_name(name)`: Get an `ObjectRef` to a player + * Returns nothing in case of error (player offline, doesn't exist, ...). +]] +---@nodiscard +---@param name string +---@return core.PlayerRef? +function core.get_player_by_name(name) end + +--[[ +* `core.get_objects_inside_radius(center, radius)` + * returns a list of ObjectRefs + * `radius`: using a Euclidean metric + * **Warning**: Any kind of interaction with the environment or other APIs + can cause later objects in the list to become invalid while you're iterating it. + (e.g. punching an entity removes its children) + It is recommended to use `core.objects_inside_radius` instead, which + transparently takes care of this possibility. +]] +---@nodiscard +---@param center vector +---@param radius number +---@return core.ObjectRef[] +function core.get_objects_inside_radius(center, radius) end + +--[[ +* `core.objects_inside_radius(center, radius)` + * returns an iterator of valid objects + * example: `for obj in core.objects_inside_radius(center, radius) do obj:punch(...) end` +]] +---@nodiscard +---@param center vector +---@param radius number +---@return fun():core.ObjectRef? +function core.objects_inside_radius(center, radius) end + +--[[ +* `core.get_objects_in_area(min_pos, max_pos)` + * returns a list of ObjectRefs + * `min_pos` and `max_pos` are the min and max positions of the area to search + * **Warning**: The same warning as for `core.get_objects_inside_radius` applies. + Use `core.objects_in_area` instead to iterate only valid objects. +]] +---@nodiscard +---@param minp vector +---@param maxp vector +---@return core.ObjectRef[] +function core.get_objects_in_area(minp, maxp) end + +--[[ +* `core.objects_in_area(min_pos, max_pos)` + * returns an iterator of valid objects +]] +---@nodiscard +---@param minp vector +---@param maxp vector +---@return fun():core.ObjectRef? +function core.objects_in_area(minp, maxp) end + +-- ---------------------------------- time ---------------------------------- -- + +--[[ +WIPDOC +]] +---@param val number +function core.set_timeofday(val) end + +--[[ +* `core.get_timeofday()`: get time of day +]] +---@nodiscard +---@return number +function core.get_timeofday() end + +--[[ +* `core.get_gametime()`: returns the time, in seconds, since the world was + created. The time is not available (`nil`) before the first server step. +]] +---@nodiscard +---@return number? +function core.get_gametime() end + +--[[ +* `core.get_day_count()`: returns number days elapsed since world was + created. + * Time changes are accounted for. +]] +---@nodiscard +---@return integer +function core.get_day_count() end + +-- -------------------------------- find node ------------------------------- -- + +--[[ +Unofficial note: I think this function is a lot laggier than the alternatives +If you are simply trying to check if a node is in a big area, use `core.find_nodes_in_area` +Anyway, someone will need to fact check me on that claim! Anyway: The actual docs: +But you can notice that it doesn't have that pesky volume limit, so it's implemented differently + +* `core.find_node_near(pos, radius, nodenames, [search_center])`: returns + pos or `nil`. + * `radius`: using a maximum metric + * `nodenames`: e.g. `{"ignore", "group:tree"}` or `"default:dirt"` + * `search_center` is an optional boolean (default: `false`) + If true `pos` is also checked for the nodes +]] +---@nodiscard +---@param pos ivector +---@param radius integer +---@param nodenames OneOrMany +---@param search_center boolean? +---@return vec? +function core.find_node_near(pos, radius, nodenames, search_center) end + +--[[ +* `core.find_nodes_in_area(pos1, pos2, nodenames, [grouped])` + * `pos1` and `pos2` are the min and max positions of the area to search. + * `nodenames`: e.g. `{"ignore", "group:tree"}` or `"default:dirt"` + * If `grouped` is true the return value is a table indexed by node name + which contains lists of positions. + * If `grouped` is false or absent the return values are as follows: + first value: Table with all node positions + second value: Table with the count of each node with the node name + as index + * Area volume is limited to 150,000,000 nodes +]] +---@nodiscard +---@param pos1 ivector +---@param pos2 ivector +---@param nodenames OneOrMany +---@param grouped true +---@return table +function core.find_nodes_in_area(pos1, pos2, nodenames, grouped) end + +--[[ +WIPDOC +]] +---@nodiscard +---@param pos1 ivector +---@param pos2 ivector +---@param nodenames OneOrMany +---@param grouped false? +---@return ivec[], table +function core.find_nodes_in_area(pos1, pos2, nodenames, grouped) end + +--[[ +* `core.find_nodes_in_area_under_air(pos1, pos2, nodenames)`: returns a + list of positions. + * `nodenames`: e.g. `{"ignore", "group:tree"}` or `"default:dirt"` + * Return value: Table with all node positions with a node air above + * Area volume is limited to 150,000,000 nodes +]] +---@nodiscard +---@param pos1 ivector +---@param pos2 ivector +---@param nodenames OneOrMany +---@return ivec[] +function core.find_nodes_in_area_under_air(pos1, pos2, nodenames) end + +-- ---------------------- mapblocks and map generation ---------------------- -- + +--[[ core.get_value_noise() .. core.get_perlin() split off into library/classes/ValueNoise.lua ]]-- + +--[[ core.get_voxel_manip() split off into library/classes/VoxelManip.lua ]]-- + +--[[ +* `core.set_gen_notify(flags, [deco_ids], [custom_ids])` + * Set the types of on-generate notifications that should be collected. + * `flags`: flag field, see [`gennotify`] for available generation notification types. + * The following parameters are optional: + * `deco_ids` is a list of IDs of decorations which notification + is requested for. + * `custom_ids` is a list of user-defined IDs (strings) which are + requested. By convention these should be the mod name with an optional + colon and specifier added, e.g. `"default"` or `"default:dungeon_loot"` +]] +---@param flags core.GenNotify.flags +---@param deco_ids core.DecorationID[]? +---@param custom_ids string[]? +function core.set_gen_notify(flags, deco_ids, custom_ids) end + +--[[ +* `core.get_gen_notify()` + * Returns a flagstring, a table with the `deco_id`s and a table with + user-defined IDs. +]] +---@nodiscard +---@return core.GenNotify.flags.stringfmt flags, core.DecorationID[] deco_ids, string[] custom_ids +function core.get_gen_notify() end + +--[[ +WIPDOC +]] +---@nodiscard +---@param decoration_name string +---@return core.DecorationID? +function core.get_decoration_id(decoration_name) end + +--[[ +WIPDOC +]] +---@nodiscard +---@param objectname "voxelmanip" +---@return core.VoxelManip, ivec emin, ivec emax +function core.get_mapgen_object(objectname) end + +--[[ +WIPDOC +]] +---@nodiscard +---@param objectname "heightmap" +---@return integer[] +function core.get_mapgen_object(objectname) end + +--[[ +WIPDOC +]] +---@nodiscard +---@param objectname "biomemap" +---@return core.BiomeID[] +function core.get_mapgen_object(objectname) end + +--[[ +WIPDOC +]] +---@nodiscard +---@param objectname "heatmap" +---@return number[] +function core.get_mapgen_object(objectname) end + +--[[ +WIPDOC +]] +---@nodiscard +---@param objectname "humiditymap" +---@return number[] +function core.get_mapgen_object(objectname) end + +--[[ +WIPDOC +]] +---@nodiscard +---@param objectname "gennotify" +---@return core.GenNotify +function core.get_mapgen_object(objectname) end + +--[[ +Unofficial note: this relates to the biome heat, idk override it and make your own custom mapgen if you dare +* `core.get_heat(pos)` + * Returns the heat at the position, or `nil` on failure. +]] +---@nodiscard +---@param pos ivector +---@return number? +function core.get_heat(pos) end + +--[[ +Unofficial note: this relates to the biome humidity, idk override it and make your own custom mapgen if you dare +* `core.get_humidity(pos)` + * Returns the humidity at the position, or `nil` on failure. +]] +---@nodiscard +---@param pos ivector +---@return number? +function core.get_humidity(pos) end + +--[[ core.get_biome_data() split off into ./biome_data.lua ]]-- + +--[[ +* `core.get_biome_id(biome_name)` + * Returns the biome id, as used in the biomemap Mapgen object and returned + by `core.get_biome_data(pos)`, for a given biome_name string. +]] +---@nodiscard +---@param biome_name string +---@return core.BiomeID +function core.get_biome_id(biome_name) end + +--[[ +* `core.get_biome_name(biome_id)` + * Returns the biome name string for the provided biome id, or `nil` on + failure. + * If no biomes have been registered, such as in mgv6, returns `default`. +]] +---@nodiscard +---@param biome_id core.BiomeID +---@return string? +function core.get_biome_name(biome_id) end + +--[[ core.get_mapgen_params() .. core.set_mapgen_params() split off into ./mapgen_params.lua ]]-- + +--[=[ +* `core.get_mapgen_edges([mapgen_limit[, chunksize]])` + * Returns the minimum and maximum possible generated node positions + in that order. + * `mapgen_limit` is an optional number. If it is absent, its value is that + of the *active* mapgen setting `"mapgen_limit"`. + * `chunksize` is an optional number. If it is absent, its value is that + of the *active* mapgen setting `"chunksize"`. +]=] +---@nodiscard +---@param mapgen_limit integer? +---@param chunksize integer? +---@return ivec min, ivec max +function core.get_mapgen_edges(mapgen_limit, chunksize) end + +--[[ +* `core.get_mapgen_chunksize()` + * Returns the currently active chunksize of the mapgen, as a vector. + The size is specified in blocks. +]] +---@nodiscard +---@return ivec +function core.get_mapgen_chunksize() end + +--[[ +* `core.get_mapgen_setting(name)` + * Gets the *active* mapgen setting (or nil if none exists) in string + format with the following order of precedence: + 1) Settings loaded from map_meta.txt or overrides set during mod + execution. + 2) Settings set by mods without a metafile override + 3) Settings explicitly set in the user config file, minetest.conf + 4) Settings set as the user config default +]] +---@nodiscard +---@param name _.LuantiSettings.mapgen.keys +---@return string? +function core.get_mapgen_setting(name) end + +--[[ +* `core.get_mapgen_setting_noiseparams(name)` + * Same as above, but returns the value as a NoiseParams table if the + setting `name` exists and is a valid NoiseParams. +]] +---@nodiscard +---@param name _.LuantiSettings.mapgen.keys.noise_params.3d +---@return core.NoiseParams.3d? +function core.get_mapgen_setting_noiseparams(name) end + +--[[ +* `core.get_mapgen_setting_noiseparams(name)` + * Same as above, but returns the value as a NoiseParams table if the + setting `name` exists and is a valid NoiseParams. +]] +---@nodiscard +---@param name _.LuantiSettings.mapgen.keys.noise_params.2d +---@return core.NoiseParams.2d? +function core.get_mapgen_setting_noiseparams(name) end + +--[[ +* `core.set_mapgen_setting(name, value, [override_meta])` + * Sets a mapgen param to `value`, and will take effect if the corresponding + mapgen setting is not already present in map_meta.txt. + * `override_meta` is an optional boolean (default: `false`). If this is set + to true, the setting will become the active setting regardless of the map + metafile contents. + * Note: to set the seed, use `"seed"`, not `"fixed_map_seed"`. +]] +---@param name _.LuantiSettings.mapgen.keys +---@param value string +---@param override_meta boolean? +function core.set_mapgen_setting(name, value, override_meta) end + +--[[ +* `core.set_mapgen_setting_noiseparams(name, value, [override_meta])` + * Same as above, except value is a NoiseParams table. +]] +---@param name _.LuantiSettings.mapgen.keys.noise_params.3d +---@param value core.NoiseParams.3d +---@param override_meta boolean? +function core.set_mapgen_setting_noiseparams(name, value, override_meta) end + +--[[ +* `core.set_mapgen_setting_noiseparams(name, value, [override_meta])` + * Same as above, except value is a NoiseParams table. +]] +---@param name _.LuantiSettings.mapgen.keys.noise_params.2d +---@param value core.NoiseParams.2d +---@param override_meta boolean? +function core.set_mapgen_setting_noiseparams(name, value, override_meta) end + +--[[ +* `core.set_noiseparams(name, noiseparams, set_default)` + * Sets the noiseparams setting of `name` to the noiseparams table specified + in `noiseparams`. + * `set_default` is an optional boolean (default: `true`) that specifies + whether the setting should be applied to the default config or current + active config. +]] +---@param name _.LuantiSettings.mapgen.keys.noise_params.3d +---@param noiseparams core.NoiseParams.3d +---@param set_default boolean? +function core.set_noiseparams(name, noiseparams, set_default) end + +--[[ +* `core.set_noiseparams(name, noiseparams, set_default)` + * Sets the noiseparams setting of `name` to the noiseparams table specified + in `noiseparams`. + * `set_default` is an optional boolean (default: `true`) that specifies + whether the setting should be applied to the default config or current + active config. +]] +---@param name _.LuantiSettings.mapgen.keys.noise_params.2d +---@param noiseparams core.NoiseParams.2d +---@param set_default boolean? +function core.set_noiseparams(name, noiseparams, set_default) end + +--[[ +WIPDOC +]] +---@nodiscard +---@param name _.LuantiSettings.mapgen.keys.noise_params.3d +---@return core.NoiseParams.3d +function core.get_noiseparams(name) end + +--[[ +WIPDOC +]] +---@nodiscard +---@param name _.LuantiSettings.mapgen.keys.noise_params.2d +---@return core.NoiseParams.2d +function core.get_noiseparams(name) end + +--[[ +* `core.generate_ores(vm, pos1, pos2)` + * Generate all registered ores within the VoxelManip `vm` and in the area + from `pos1` to `pos2`. + * `pos1` and `pos2` are optional and default to mapchunk minp and maxp. +]] +---@param vm core.VoxelManip +---@param pos1 ivector? +---@param pos2 ivector? +function core.generate_ores(vm, pos1, pos2) end + +--[=[ +* `core.generate_decorations(vm[, pos1, pos2, [use_mapgen_biomes]])` + * Generate all registered decorations within the VoxelManip `vm` and in the + area from `pos1` to `pos2`. + * `pos1` and `pos2` are optional and default to mapchunk minp and maxp. + * `use_mapgen_biomes` (optional boolean). For use in on_generated callbacks only. + If set to true, decorations are placed in respect to the biome map of the current chunk. + `pos1` and `pos2` must match the positions of the current chunk, or an error will be raised. + default: `false` +]=] +---@param vm core.VoxelManip +---@param pos1 ivector? +---@param pos2 ivector? +---@param use_mapgen_biomes boolean? +function core.generate_decorations(vm, pos1, pos2, use_mapgen_biomes) end + +--[[ +WIPDOC +]] +---@class core.ClearObjectsOptions +--[[ +WIPDOC +]] +---@field mode "full"|"quick" + +--[[ +* `core.clear_objects([options])` + * Clear all objects in the environment + * Takes an optional table as an argument with the field `mode`. + * mode = `"full"`: Load and go through every mapblock, clearing + objects (default). + * mode = `"quick"`: Clear objects immediately in loaded mapblocks, + clear objects in unloaded mapblocks only when the + mapblocks are next activated. +]] +---@param options core.ClearObjectsOptions? +function core.clear_objects(options) end + +--[[ +* `core.load_area(pos1[, pos2])` + * Load the mapblocks containing the area from `pos1` to `pos2`. + `pos2` defaults to `pos1` if not specified. + * This function does not trigger map generation. +]] +---@param pos1 ivector +---@param pos2 ivector? +function core.load_area(pos1, pos2) end + +--[[ core.emerge_area() split off into ./emerge_area.lua ]]-- + +--[[ +* `core.delete_area(pos1, pos2)` + * delete all mapblocks in the area from pos1 to pos2, inclusive +]] +---@param pos1 ivector +---@param pos2 ivector +function core.delete_area(pos1, pos2) end + +-- ----------------------- ray casting and pathfinding ---------------------- -- + +--[[ +Unofficial note: The annoying thing about this little function is that it is hardcoded to check specifically for "air", nothing else +Though i am sure you can make it work out + +* `core.line_of_sight(pos1, pos2)`: returns `boolean, pos` + * Checks if there is anything other than air between pos1 and pos2. + * Returns false if something is blocking the sight. + * Returns the position of the blocking node when `false` + * `pos1`: First position + * `pos2`: Second position +]] +---@nodiscard +---@param pos1 ivector +---@param pos2 ivector +---@return true +function core.line_of_sight(pos1, pos2) end + +--[[ +Unofficial note: The annoying thing about this little function is that it is hardcoded to check specifically for "air", nothing else +Though i am sure you can make it work out + +* `core.line_of_sight(pos1, pos2)`: returns `boolean, pos` + * Checks if there is anything other than air between pos1 and pos2. + * Returns false if something is blocking the sight. + * Returns the position of the blocking node when `false` + * `pos1`: First position + * `pos2`: Second position +]] +---@nodiscard +---@param pos1 ivector +---@param pos2 ivector +---@return false, core.Node.get +function core.line_of_sight(pos1, pos2) end + +--[[ core.raycast() split off into classes/Raycast.lua ]]-- + +--[[ +* `core.find_path(pos1, pos2, searchdistance, max_jump, max_drop, algorithm)` + * returns table containing path that can be walked on + * returns a table of 3D points representing a path from `pos1` to `pos2` or + `nil` on failure. + * Reasons for failure: + * No path exists at all + * No path exists within `searchdistance` (see below) + * Start or end pos is buried in land + * `pos1`: start position + * `pos2`: end position + * `searchdistance`: maximum distance from the search positions to search in. + In detail: Path must be completely inside a cuboid. The minimum + `searchdistance` of 1 will confine search between `pos1` and `pos2`. + Larger values will increase the size of this cuboid in all directions + * `max_jump`: maximum height difference to consider walkable + * `max_drop`: maximum height difference to consider droppable + * `algorithm`: One of `"A*_noprefetch"` (default), `"A*"`, `"Dijkstra"`. + Difference between `"A*"` and `"A*_noprefetch"` is that + `"A*"` will pre-calculate the cost-data, the other will calculate it + on-the-fly +]] +---@nodiscard +---@param pos1 ivector +---@param pos2 ivector +---@param searchdistance integer +---@param max_jump integer +---@param max_drop integer +---@param algo "A*_noprefetch"|"A*"|"Dijkstra" +---@return ivec[]? +function core.find_path(pos1, pos2, searchdistance, max_jump, max_drop, algo) end + +-- ------------------------------ L-system tree ----------------------------- -- + +--[[ +WIPDOC +]] +---@param pos ivector +---@param lsystem core.LSystemTreeDef +function core.spawn_tree(pos, lsystem) end + +--[[ +WIPDOC +]] +---@param vmanip core.VoxelManip +---@param pos ivector +---@param treedef core.LSystemTreeDef +function core.spawn_tree_on_vmanip(vmanip, pos, treedef) end + +-- --------------------------------- liquid --------------------------------- -- + +--[[ +* `core.transforming_liquid_add(pos)` + * add node to liquid flow update queue +]] +---@param pos ivector +function core.transforming_liquid_add(pos) end + +-- ------------------------------- node level ------------------------------- -- + +--[[ +* `core.get_node_max_level(pos)` + * get max available level for leveled node +]] +---@nodiscard +---@param pos ivector +---@return core.Param2.leveled +function core.get_node_max_level(pos) end + +--[[ +* `core.get_node_level(pos)` + * get level of leveled node (water, snow) +]] +---@nodiscard +---@param pos ivector +---@return core.Param2.leveled +function core.get_node_level(pos) end + +--[[ +* `core.set_node_level(pos, level)` + * set level of leveled node, default `level` equals `1` + * if `totallevel > maxlevel`, returns rest (`total-max`). +]] +---@nodiscard +---@param pos ivector +---@param level core.Param2.leveled +---@return core.Param2.leveled? +function core.set_node_level(pos, level) end + +--[[ +* `core.add_node_level(pos, level)` + * increase level of leveled node by level, default `level` equals `1` + * if `totallevel > maxlevel`, returns rest (`total-max`) + * `level` must be between -127 and 127 +]] +---@nodiscard +---@param pos ivector +---@param level core.Param2.leveled +---@return core.Param2.leveled? +function core.add_node_level(pos, level) end + +-- ---------------------------------- misc ---------------------------------- -- + +--[[ +* `core.get_node_boxes(box_type, pos, [node])` + * `box_type` must be `"node_box"`, `"collision_box"` or `"selection_box"`. + * `pos` must be a node position. + * `node` can be a table in the form `{name=string, param1=number, param2=number}`. + If `node` is `nil`, the actual node at `pos` is used instead. + * Resolves any facedir-rotated boxes, connected boxes and the like into + actual boxes. + * Returns a list of boxes in the form + `{{x1, y1, z1, x2, y2, z2}, {x1, y1, z1, x2, y2, z2}, ...}`. Coordinates + are relative to `pos`. + * See also: [Node boxes](#node-boxes) +]] +---@param box_type "node_box"|"collision_box"|"selection_box" +---@param pos ivector +---@param node core.Node.get? +---@return core.NodeBox.box[] +function core.get_node_boxes(box_type, pos, node) end + +--[[ +* `core.fix_light(pos1, pos2)`: returns `true`/`false` + * resets the light in a cuboid-shaped part of + the map and removes lighting bugs. + * Loads the area if it is not loaded. + * `pos1` is the corner of the cuboid with the least coordinates + (in node coordinates), inclusive. + * `pos2` is the opposite corner of the cuboid, inclusive. + * The actual updated cuboid might be larger than the specified one, + because only whole map blocks can be updated. + The actual updated area consists of those map blocks that intersect + with the given cuboid. + * However, the neighborhood of the updated area might change + as well, as light can spread out of the cuboid, also light + might be removed. + * returns `false` if the area is not fully generated, + `true` otherwise +]] +---@nodiscard +---@param pos1 ivector +---@param pos2 ivector +---@return boolean +function core.fix_light(pos1, pos2) end + +--[[ +Unofficial note: You can override this one for your own custom cool falling blocks +* `core.check_single_for_falling(pos)` + * causes an unsupported `group:falling_node` node to fall and causes an + unattached `group:attached_node` node to fall. + * does not spread these updates to neighbors. +]] +---@param pos ivector +function core.check_single_for_falling(pos) end + +--[[ +* `core.check_for_falling(pos)` + * causes an unsupported `group:falling_node` node to fall and causes an + unattached `group:attached_node` node to fall. + * spread these updates to neighbors and can cause a cascade + of nodes to fall. +]] +---@param pos ivector +function core.check_for_falling(pos) end + +--[[ +* `core.get_spawn_level(x, z)` + * Returns a player spawn y coordinate for the provided (x, z) + coordinates, or `nil` for an unsuitable spawn point. + * For most mapgens a 'suitable spawn point' is one with y between + `water_level` and `water_level + 16`, and in mgv7 well away from rivers, + so `nil` will be returned for many (x, z) coordinates. + * The spawn level returned is for a player spawn in unmodified terrain. + * The spawn level is intentionally above terrain level to cope with + full-node biome 'dust' nodes. +]] +---@param x integer +---@param z integer +---@return integer? y +function core.get_spawn_level(x, z) end \ No newline at end of file diff --git a/types/luanti_lsp_definitions/library/core/environment/mapgen_params.lua b/types/luanti_lsp_definitions/library/core/environment/mapgen_params.lua new file mode 100644 index 00000000..06f946d2 --- /dev/null +++ b/types/luanti_lsp_definitions/library/core/environment/mapgen_params.lua @@ -0,0 +1,69 @@ +---@meta _ +-- DRAFT 1 DONE +-- luanti/doc/lua_api.md: 'core' namespace reference > Environment access + +-- ------------------------------ MapgenParams ------------------------------ -- + +--[[ +WIPDOC +]] +---@class core.MapgenParams +--[[ +WIPDOC +]] +---@field mgname core.LuantiSettings.enums.mg_name +--[[ +WIPDOC +]] +---@field seed integer +--[[ +WIPDOC +]] +---@field chunksize integer +--[[ +WIPDOC +]] +---@field water_level integer +--[[ +WIPDOC +]] +---@field flags core.LuantiSettings.flags.mg_flags|core.LuantiSettings.flags + +-- ---------------------------- core.* functions ---------------------------- -- + +--[[ +* `core.get_mapgen_params()` + * Deprecated: use `core.get_mapgen_setting(name)` instead. + * Returns a table containing: + * `mgname` + * `seed` + * `chunksize` + * `water_level` + * `flags` +]] +---@deprecated +---@nodiscard +---@return core.MapgenParams +function core.get_mapgen_params() end + +--[[ +* `core.set_mapgen_params(MapgenParams)` + * Deprecated: use `core.set_mapgen_setting(name, value, override)` + instead. + * Set map generation parameters. + * Function cannot be called after the registration period. + * Takes a table as an argument with the fields: + * `mgname` + * `seed` + * `chunksize` + * `water_level` + * `flags` + * Leave field unset to leave that parameter unchanged. + * `flags` contains a comma-delimited string of flags to set, or if the + prefix `"no"` is attached, clears instead. + * `flags` is in the same format and has the same options as `mg_flags` in + `minetest.conf`. +]] +---@deprecated +---@param MapgenParams core.MapgenParams +function core.set_mapgen_params(MapgenParams) end \ No newline at end of file diff --git a/types/luanti_lsp_definitions/library/core/escape_sequences.lua b/types/luanti_lsp_definitions/library/core/escape_sequences.lua new file mode 100644 index 00000000..5a7b3127 --- /dev/null +++ b/types/luanti_lsp_definitions/library/core/escape_sequences.lua @@ -0,0 +1,66 @@ +---@meta _ +-- DRAFT 1 DONE +-- luanti/doc/lua_api.md: Colors +-- luanti/doc/lua_api.md: Escape sequences + +--[[ +The escape sequence sets the text color to color +(Unofficial note: this is mostly for formspec UI elements) +]] +---@nodiscard +---@param color core.ColorString +---@return string +function core.get_color_escape_sequence(color) end + +--[[ +Equivalent to: core.get_color_escape_sequence(color) .. message .. core.get_color_escape_sequence("#ffffff") +(Unofficial note: this is mostly for formspec UI elements) +]] +---@nodiscard +---@param color core.ColorString +---@param message string +---@return string +function core.colorize(color, message) end + +--[[ +The escape sequence sets the background of the whole text element to color. Only defined for item descriptions and tooltips. +]] +---@nodiscard +---@param color core.ColorString +---@return string +function core.get_background_escape_sequence(color) end + +--[[ +Removes foreground colors added by get_color_escape_sequence. +]] +---@nodiscard +---@param str string +---@return string +function core.strip_foreground_colors(str) end + +--[[ +Removes background colors added by get_background_escape_sequence. +]] +---@nodiscard +---@param str string +---@return string +function core.strip_background_colors(str) end + +--[[ +Removes all color escape sequences. +]] +---@nodiscard +---@param str string +---@return string +function core.strip_colors(str) end + +--[[ +* `core.strip_escapes(str)` + * Removes all escape sequences, including client-side translations and + any unknown or future escape sequences that Luanti might define. + * You can use this to clean text before logging or handing to an external system. +]] +---@nodiscard +---@param str string +---@return string +function core.strip_escape(str) end \ No newline at end of file diff --git a/types/luanti_lsp_definitions/library/core/formspec_functions.lua b/types/luanti_lsp_definitions/library/core/formspec_functions.lua new file mode 100644 index 00000000..0b2db293 --- /dev/null +++ b/types/luanti_lsp_definitions/library/core/formspec_functions.lua @@ -0,0 +1,145 @@ +---@meta _ +-- DRAFT 1 DONE +-- luanti/doc/lua_api.md: 'core' namespace reference > Formspec functions + +--[[ +* `core.show_formspec(playername, formname, formspec)` + * `playername`: name of player to show formspec + * `formname`: name passed to `on_player_receive_fields` callbacks. + * It should follow the `"modname:"` naming convention. + * If empty: Shows a custom, temporary inventory formspec. + * An inventory formspec shown this way will also be updated if + `ObjectRef:set_inventory_formspec` is called. + * Use `ObjectRef:set_inventory_formspec` to change the player's + inventory formspec for future opens. + * Supported if server AND client are both of version >= 5.13.0. + * `formspec`: formspec to display + * See also: `core.register_on_player_receive_fields` +]] +---@param playername string +---@param formname string +---@param formspec core.Formspec +function core.show_formspec(playername, formname, formspec) end + +--[[ +* `core.close_formspec(playername, formname)` + * `playername`: name of player to close formspec + * `formname`: has to exactly match the one given in `show_formspec`, or the + formspec will not close. + * calling `show_formspec(playername, formname, "")` is equal to this + expression. + * to close a formspec regardless of the formname, call + `core.close_formspec(playername, "")`. + **USE THIS ONLY WHEN ABSOLUTELY NECESSARY!** +]] +---@param playername string +---@param formname string +function core.close_formspec(playername, formname) end + +--[[ +* `core.hypertext_escape(string)`: returns a string + * escapes the characters "\", "<", and ">" to show text in a hypertext element. + * not safe for use with tag attributes. + * this function does not do formspec escaping, you will likely need to do + `core.formspec_escape(core.hypertext_escape(string))` if the hypertext is + not already being formspec escaped. +]] +---@nodiscard +---@param string string +---@return string +function core.hypertext_escape(string) end + +--[[ +WIPDOC +]] +---@class core.ExplodeEvent.table +--[[ +WIPDOC +]] +---@field type "INV"|"CHG"|"DCL" +--[[ +WIPDOC +]] +---@field row integer +--[[ +WIPDOC +]] +---@field column integer + +--[[ +* `core.explode_table_event(string)`: returns a table + * returns e.g. `{type="CHG", row=1, column=2}` + * `type` is one of: + * `"INV"`: no row selected + * `"CHG"`: selected + * `"DCL"`: double-click +]] +---@nodiscard +---@param string string +---@return core.ExplodeEvent.table +function core.explode_table_event(string) end + +--[[ +WIPDOC +]] +---@class core.ExplodeEvent.textlist +--[[ +WIPDOC +]] +---@field type "INV"|"CHG"|"DCL" +--[[ +WIPDOC +]] +---@field index integer + +--[[ +* `core.explode_textlist_event(string)`: returns a table + * returns e.g. `{type="CHG", index=1}` + * `type` is one of: + * `"INV"`: no row selected + * `"CHG"`: selected + * `"DCL"`: double-click +]] +---@nodiscard +---@param string string +---@return core.ExplodeEvent.textlist +function core.explode_textlist_event(string) end + +--[[ +WIPDOC +]] +---@class core.ExplodeEvent.scrollbar +--[[ +WIPDOC +]] +---@field type "INV"|"CHG"|"VAL" +--[[ +WIPDOC +]] +---@field value integer + +--[[ +* `core.explode_scrollbar_event(string)`: returns a table + * returns e.g. `{type="CHG", value=500}` + * `type` is one of: + * `"INV"`: something failed + * `"CHG"`: has been changed + * `"VAL"`: not changed +]] +---@nodiscard +---@param string string +---@return core.ExplodeEvent.scrollbar +function core.explode_scrollbar_event(string) end + +--[[ +* `core.show_death_screen(player, reason)` + * Called when the death screen should be shown. + * `player` is an ObjectRef, `reason` is a PlayerHPChangeReason table or nil. + * By default, this shows a simple formspec with the option to respawn. + Respawning is done via `ObjectRef:respawn`. + * You can override this to show a custom death screen. + * For general death handling, use `core.register_on_dieplayer` instead. +]] +---@param player core.PlayerRef +---@param reason core.PlayerHPChangeReason? +function core.show_death_screen(player, reason) end \ No newline at end of file diff --git a/types/luanti_lsp_definitions/library/core/global_tables.lua b/types/luanti_lsp_definitions/library/core/global_tables.lua new file mode 100644 index 00000000..3bf1799c --- /dev/null +++ b/types/luanti_lsp_definitions/library/core/global_tables.lua @@ -0,0 +1,332 @@ +---@meta _ +-- DRAFT 1 DONE +-- luanti/doc/lua_api.md: 'core' namespace reference > Global tables +--[=[ +NOTE: manually searched from output log of below in a minimal game: +core.log(dump2(core, 'core')) +]=] + +--[[ +WIPDOC +]] +---@type core.fn.on_mods_loaded[] +core.registered_on_mods_loaded = {} + +--[[ +WIPDOC +]] +---@type core.fn.on_shutdown[] +core.registered_on_shutdown = {} + +--[[ +WIPDOC +]] +---@type core.fn.on_generated[] +core.registered_on_generateds = {} + +--[[ +WIPDOC +]] +---@type core.fn.on_newplayer[] +core.registered_on_newplayers = {} + +--[[ +WIPDOC +]] +---@type core.fn.on_dieplayer[] +core.registered_on_dieplayers = {} + +--[[ +WIPDOC +]] +---@type core.fn.on_respawnplayer[] +core.registered_on_respawnplayers = {} + +--[[ +WIPDOC +]] +---@type core.fn.on_prejoinplayer[] +core.registered_on_prejoinplayers = {} + +--[[ +WIPDOC +]] +---@type core.fn.on_joinplayer[] +core.registered_on_joinplayers = {} + +--[[ +WIPDOC +]] +---@type core.fn.on_leaveplayer[] +core.registered_on_leaveplayers = {} + +--[[ +WIPDOC +]] +---@type core.fn.on_player_receive_fields[] +core.registered_on_player_receive_fields = {} + +--[[ +WIPDOC +]] +---@type core.fn.on_cheat[] +core.registered_on_cheats = {} + +--[[ +WIPDOC +]] +---@type core.fn.on_protection_violation[] +core.registered_on_protection_violation = {} + +--[[ +WIPDOC +]] +---@type core.fn.on_punchplayer[] +core.registered_on_punchplayers = {} + +--[[ +WIPDOC +]] +---@type core.fn.on_priv_grant[] +core.registered_on_priv_grant = {} + +--[[ +WIPDOC +]] +---@type core.fn.on_priv_revoke[] +core.registered_on_priv_revoke = {} + +--[[ +WIPDOC +]] +---@type core.fn.on_authplayer[] +core.registered_on_authplayers = {} + +--[[ +WIPDOC +]] +---@type core.fn.can_bypass_userlimit[] +core.registered_can_bypass_userlimit = {} + +--[[ +WIPDOC +]] +---@type core.fn.on_modchannel_message[] +core.registered_on_modchannel_message = {} + +--[[ +WIPDOC +]] +---@type core.fn.on_player_inventory_action[] +core.registered_on_player_inventory_actions = {} + +--[[ +WIPDOC +]] +---@type core.fn.allow_player_inventory_action[] +core.registered_allow_player_inventory_actions = {} + +--[[ +WIPDOC +]] +---@type core.fn.on_rightclickplayer[] +core.registered_on_rightclickplayers = {} + +--[[ +WIPDOC +]] +---@type core.fn.on_liquid_transform[] +core.registered_on_liquid_transformed = {} + +--[[ +WIPDOC +]] +---@type core.fn.on_mapblocks_changed[] +core.registered_on_mapblocks_changed = {} + +--[[ +WIPDOC +]] +---@type table +core.registered_privileges = {} + +--[[ +WIPDOC +]] +---@type table +core.registered_chatcommands = {} + +--[[ +WIPDOC +]] +---@type table +core.registered_nodes = {} + +--[[ +WIPDOC +]] +---@type core.fn.on_craft[] +core.registered_on_crafts = {} + +--[[ +WIPDOC +]] +---@type core.fn.craft_predict[] +core.registered_craft_predicts = {} + +--[[ +WIPDOC +]] +---@type core.fn.on_item_pickup[] +core.registered_on_item_pickups = {} + +--[[ +WIPDOC +]] +---@type core.fn.on_item_eat[] +core.registered_on_item_eats = {} + +--[[ +WIPDOC +]] +---@type core.fn.on_dignode[] +core.registered_on_dignodes = {} + +--[[ +WIPDOC +]] +---@type core.fn.on_placenode[] +core.registered_on_placenodes = {} + +--[[ +WIPDOC +]] +---@type core.fn.on_punchnode[] +core.registered_on_punchnodes = {} + +--[[ +WIPDOC +]] +---@type table +core.objects_by_guid = {} + +--[[ +WIPDOC +]] +---@deprecated +---@type table +core.object_refs = {} + +--[[ +WIPDOC +]] +---@type table +core.luaentities = {} + +--[[ +WIPDOC +]] +---@type table +core.registered_aliases = {} + +--[[ +WIPDOC +]] +---@type table +core.registered_tools = {} + +--[[ +WIPDOC +]] +---@type table +core.registered_craftitems = {} + +--[[ +WIPDOC +]] +---@type table +core.registered_items = {} + +--[[ +WIPDOC +]] +---@type table +core.registered_entities = {} + +--[[ +WIPDOC +]] +---@type core.LBMDef[] +core.registered_lbms = {} + +--[[ +WIPDOC +]] +---@type core.ABMDef[] +core.registered_abms = {} + +--[[ +WIPDOC +]] +---@class core.reg.on_player_hpchanges +core.registered_on_player_hpchanges = {} + +--[[ +WIPDOC +]] +---@type core.fn.on_player_hpchange.modifier[] +core.registered_on_player_hpchanges.modifiers = {} + +--[[ +WIPDOC +]] +---@type core.fn.on_player_hpchange.logger[] +core.registered_on_player_hpchanges.loggers = {} + +--[[ +WIPDOC +]] +---@type table +core.registered_biomes = {} + +--[[ +WIPDOC +]] +---@type table +core.registered_ores = {} + +--[[ +WIPDOC +]] +---@type table +core.registered_decorations = {} + +--[[ +WIPDOC +]] +---@type core.fn.on_chat_message[] +core.registered_on_chat_messages = {} + +--[[ +WIPDOC +]] +---@type core.fn.on_chatcommand[] +core.registered_on_chatcommands = {} + +--[[ +WIPDOC +]] +---@type core.fn.globalstep[] +core.registered_globalsteps = {} + +--[[ +WIPDOC +]] +---@type core.fn.playerevent[] +core.registered_playerevents = {} + +--[[ +WIPDOC +]] +---@type table +core.detached_inventories = {} \ No newline at end of file diff --git a/types/luanti_lsp_definitions/library/core/http.lua b/types/luanti_lsp_definitions/library/core/http.lua new file mode 100644 index 00000000..2058856c --- /dev/null +++ b/types/luanti_lsp_definitions/library/core/http.lua @@ -0,0 +1,66 @@ +---@meta _ +-- DRAFT 1 DONE +-- luanti/doc/lua_api.md: 'core' namespace reference > HTTP Requests + +-- ------------------------------ HTTPApiTable ------------------------------ -- + +--[[ +WIPDOC +]] +---@alias core.HTTPApiTable.fetch.fn fun(res:core.HTTPRequestDef) + +--[[ +WIPDOC +]] +---@alias core.HTTPApiTable.fetch fun(req:core.HTTPRequestDef, callback:core.HTTPApiTable.fetch.fn) + +--[[ +WIPDOC +]] +---@class core.HTTPFetchAsyncID : integer + +--[[ +WIPDOC +]] +---@alias core.HTTPApiTable.fetch_async fun(req:core.HTTPRequestDef) + +--[[ +WIPDOC +]] +---@alias core.HTTPApiTable.fetch_async_get fun(handle:core.HTTPFetchAsyncID):core.HTTPRequestResultDef + +--[[ +WIPDOC +]] +---@class core.HTTPApiTable +--[[ +WIPDOC +]] +---@field fetch core.HTTPApiTable.fetch +--[[ +WIPDOC +]] +---@field fetch_async core.HTTPApiTable.fetch_async +--[[ +WIPDOC +]] +---@field fetch_async_get core.HTTPApiTable.fetch_async_get + +-- ---------------------------- core.* functions ---------------------------- -- + +--[[ +* `core.request_http_api()`: + * returns `HTTPApiTable` containing http functions if the calling mod has + been granted access by being listed in the `secure.http_mods` or + `secure.trusted_mods` setting, otherwise returns `nil`. + * The returned table contains the functions `fetch`, `fetch_async` and + `fetch_async_get` described below. + * Only works at init time and must be called from the mod's main scope + (not from a function). + * Function only exists if Luanti server was built with cURL support. + * **DO NOT ALLOW ANY OTHER MODS TO ACCESS THE RETURNED TABLE, STORE IT IN + A LOCAL VARIABLE!** +]] +---@nodiscard +---@return core.HTTPApiTable? +function core.request_http_api() end diff --git a/types/luanti_lsp_definitions/library/core/inventory.lua b/types/luanti_lsp_definitions/library/core/inventory.lua new file mode 100644 index 00000000..ecba285f --- /dev/null +++ b/types/luanti_lsp_definitions/library/core/inventory.lua @@ -0,0 +1,93 @@ +---@meta _ +-- DRAFT 1 DONE +-- luanti/doc/lua_api.md: 'core' namespace reference > Inventory + +-- ---------------------------- InventoryLocation --------------------------- -- + +--[[ +WIPDOC +]] +---@class core.InventoryLocation.node +--[[ +WIPDOC +]] +---@field type "node" +--[[ +WIPDOC +]] +---@field pos ivec + +--[[ +WIPDOC +]] +---@class core.InventoryLocation.player +--[[ +WIPDOC +]] +---@field type "player" +--[[ +WIPDOC +]] +---@field name string + +--[[ +WIPDOC +]] +---@class core.InventoryLocation.detached +--[[ +WIPDOC +]] +---@field type "detached" +--[[ +WIPDOC +]] +---@field name string + +--[[ +WIPDOC +]] +---@alias core.InventoryLocation +--- | core.InventoryLocation.node +--- | core.InventoryLocation.player +--- | core.InventoryLocation.detached + +--[[ +WIPDOC +]] +---@class core.InventoryLocation.undefined +--[[ +WIPDOC +]] +---@field type "undefined" + +-- ---------------------------- core.* functions ---------------------------- -- + +--[[ +`core.get_inventory(location)`: returns an `InvRef` + +* `location` = e.g. + * `{type="player", name="celeron55"}` + * `{type="node", pos={x=, y=, z=}}` + * `{type="detached", name="creative"}` +]] +---@param location core.InventoryLocation +---@return core.InvRef +function core.get_inventory(location) end + +--[[ +WIPDOC +]] +---@nodiscard +---@param name string +---@param callbacks core.DetachedInventoryCallbacks +---@param player_name string? +---@return core.InvRef +function core.create_detached_inventory(name, callbacks, player_name) end + +--[[ +WIPDOC +]] +---@nodiscard +---@param name string +---@return boolean +function core.remove_detached_inventory(name) end \ No newline at end of file diff --git a/types/luanti_lsp_definitions/library/core/ipc.lua b/types/luanti_lsp_definitions/library/core/ipc.lua new file mode 100644 index 00000000..e0cc9c93 --- /dev/null +++ b/types/luanti_lsp_definitions/library/core/ipc.lua @@ -0,0 +1,69 @@ +---@meta _ +-- DRAFT 1 DONE +-- luanti/doc/lua_api.md: 'core' namespace reference > IPC + +--[[ +* `core.ipc_get(key)`: + * Read a value from the shared data area. + * `key`: string, should use the `"modname:thing"` convention to avoid conflicts. + * returns an arbitrary Lua value, or `nil` if this key does not exist +]] +---@nodiscard +---@param key string +---@return core.Serializable? +function core.ipc_get(key) end + +--[[ +* `core.ipc_set(key, value)`: + * Write a value to the shared data area. + * `key`: as above + * `value`: an arbitrary Lua value, cannot be or contain userdata. + +Interacting with the shared data will perform an operation comparable to +(de)serialization on each access. +For that reason modifying references will not have any effect, as in this example: +```lua +core.ipc_set("test:foo", {}) +core.ipc_get("test:foo").subkey = "value" -- WRONG! +core.ipc_get("test:foo") -- returns an empty table +``` + +]] +---@param key string +---@param value core.Serializable +function core.ipc_set(key, value) end + +--[[ +* `core.ipc_cas(key, old_value, new_value)`: + * Write a value to the shared data area, but only if the previous value + equals what was given. + This operation is called Compare-and-Swap and can be used to implement + synchronization between threads. + * `key`: as above + * `old_value`: value compared to using `==` (`nil` compares equal for non-existing keys) + * `new_value`: value that will be set + * returns: true on success, false otherwise +]] +---@nodiscard +---@param key string +---@param old_value core.Serializable +---@param new_value core.Serializable +---@return boolean success +function core.ipc_cas(key, old_value, new_value) end + +--[[ +* `core.ipc_poll(key, timeout)`: + * Do a blocking wait until a value (other than `nil`) is present at the key. + * **IMPORTANT**: You usually don't need this function. Use this as a last resort + if nothing else can satisfy your use case! None of the Lua environments the + engine has are safe to block for extended periods, especially on the main + thread any delays directly translate to lag felt by players. + * `key`: as above + * `timeout`: maximum wait time, in milliseconds (positive values only) + * returns: true on success, false on timeout +]] +---@nodiscard +---@param key string +---@param timeout number +---@return boolean success +function core.ipc_poll(key, timeout) end \ No newline at end of file diff --git a/types/luanti_lsp_definitions/library/core/item_handling/craft_result.lua b/types/luanti_lsp_definitions/library/core/item_handling/craft_result.lua new file mode 100644 index 00000000..9c2e6f47 --- /dev/null +++ b/types/luanti_lsp_definitions/library/core/item_handling/craft_result.lua @@ -0,0 +1,285 @@ +---@meta _ +-- DRAFT 1 DONE +-- luanti/doc/lua_api.md: 'core' namespace reference > Item handling + +--[[ +WIPDOC +]] +---@class core.CraftRecipe.unknown +--[[ +WIPDOC +]] +---@field method "unknown" +--[[ +WIPDOC +]] +---@field width 0 +--[[ +WIPDOC +]] +---@field items nil + +--[[ +WIPDOC +]] +---@class core.CraftRecipe.normal.set +--[[ +WIPDOC +]] +---@field method "normal" +--[[ +WIPDOC +]] +---@field width integer? +--[[ +WIPDOC +]] +---@field items core.ItemList + +--[[ +WIPDOC +]] +---@class core.CraftRecipe.normal.get +--[[ +WIPDOC +]] +---@field method "normal" +--[[ +WIPDOC +]] +---@field width integer +--[[ +WIPDOC +]] +---@field items core.ItemList + +--[[ +WIPDOC +]] +---@class core.CraftRecipe.cooking +--[[ +WIPDOC +]] +---@field method "cooking" +--[[ +WIPDOC +]] +---@field items core.ItemList + +--[[ +WIPDOC +]] +---@class core.CraftRecipe.fuel +--[[ +WIPDOC +]] +---@field method "fuel" +--[[ +WIPDOC +]] +---@field items core.ItemList + +--[[ +WIPDOC +]] +---@alias core.CraftRecipe.set +--- | core.CraftRecipe.normal.set +--- | core.CraftRecipe.cooking +--- | core.CraftRecipe.fuel + +--[[ +WIPDOC +]] +---@alias core.CraftRecipe.get +--- | core.CraftRecipe.normal.get +--- | core.CraftRecipe.cooking +--- | core.CraftRecipe.fuel + +-- ----------------------- CraftingRecipe.with_output ----------------------- -- + +---@class _.CraftRecipe.with_output +--[[ +WIPDOC +]] +---@field output core.Item.stringfmt + +--[[ +WIPDOC +]] +---@class core.CraftRecipe.with_output.unknown : core.CraftRecipe.unknown, _.CraftRecipe.with_output + +--[[ +WIPDOC +]] +---@class core.CraftRecipe.with_output.normal : core.CraftRecipe.normal.get, _.CraftRecipe.with_output + +--[[ +WIPDOC +]] +---@class core.CraftRecipe.with_output.cooking : core.CraftRecipe.cooking, _.CraftRecipe.with_output + +--[[ +WIPDOC +]] +---@class core.CraftRecipe.with_output.fuel : core.CraftRecipe.fuel, _.CraftRecipe.with_output + +--[[ +WIPDOC +]] +---@alias core.CraftRecipe.with_output +--- | core.CraftRecipe.with_output.unknown +--- | core.CraftRecipe.with_output.normal +--- | core.CraftRecipe.with_output.cooking +--- | core.CraftRecipe.with_output.fuel + +-- ------------------------------- CraftOutput ------------------------------ -- + +--[[ +WIPDOC +]] +---@class core.CraftOutput.normal +--[[ +WIPDOC +]] +---@field item core.ItemStack +--[[ +WIPDOC +]] +---@field replacements SparseList + +--[[ +WIPDOC +]] +---@class core.CraftOutput.cooking +--[[ +WIPDOC +]] +---@field item core.ItemStack +--[[ +WIPDOC +]] +---@field replacements SparseList +--[[ +WIPDOC +]] +---@field time number + +--[[ +WIPDOC +]] +---@class core.CraftOutput.fuel +--[[ +WIPDOC +]] +---@field replacements SparseList +--[[ +WIPDOC +]] +---@field time number + +--[[ +WIPDOC +]] +---@alias core.CraftOutput +--- | core.CraftOutput.normal +--- | core.CraftOutput.cooking +--- | core.CraftOutput.fuel + +-- ---------------------------- core.* functions ---------------------------- -- + +--[[ +* `core.get_craft_result(input)`: returns `output, decremented_input` + * `input.method` = `"normal"` or `"cooking"` or `"fuel"` + * `input.width` = for example `3` + * `input.items` = for example + `{stack1, stack2, stack3, stack4, stack 5, stack 6, stack 7, stack 8, stack 9}` + * `output.item` = `ItemStack`, if unsuccessful: empty `ItemStack` + * `output.time` = a number, if unsuccessful: `0` + * `output.replacements` = List of replacement `ItemStack`s that couldn't be + placed in `decremented_input.items`. Replacements can be placed in + `decremented_input` if the stack of the replaced item has a count of 1. + * `decremented_input` = like `input` +]] +---@nodiscard +---@param input core.CraftRecipe.normal.set +---@return core.CraftOutput.normal, core.CraftRecipe.normal.get +function core.get_craft_result(input) end + +--[[ +* `core.get_craft_result(input)`: returns `output, decremented_input` + * `input.method` = `"normal"` or `"cooking"` or `"fuel"` + * `input.width` = for example `3` + * `input.items` = for example + `{stack1, stack2, stack3, stack4, stack 5, stack 6, stack 7, stack 8, stack 9}` + * `output.item` = `ItemStack`, if unsuccessful: empty `ItemStack` + * `output.time` = a number, if unsuccessful: `0` + * `output.replacements` = List of replacement `ItemStack`s that couldn't be + placed in `decremented_input.items`. Replacements can be placed in + `decremented_input` if the stack of the replaced item has a count of 1. + * `decremented_input` = like `input` +]] +---@nodiscard +---@param input core.CraftRecipe.cooking +---@return core.CraftOutput.cooking, core.CraftRecipe.cooking +function core.get_craft_result(input) end + +--[[ +* `core.get_craft_result(input)`: returns `output, decremented_input` + * `input.method` = `"normal"` or `"cooking"` or `"fuel"` + * `input.width` = for example `3` + * `input.items` = for example + `{stack1, stack2, stack3, stack4, stack 5, stack 6, stack 7, stack 8, stack 9}` + * `output.item` = `ItemStack`, if unsuccessful: empty `ItemStack` + * `output.time` = a number, if unsuccessful: `0` + * `output.replacements` = List of replacement `ItemStack`s that couldn't be + placed in `decremented_input.items`. Replacements can be placed in + `decremented_input` if the stack of the replaced item has a count of 1. + * `decremented_input` = like `input` +]] +---@nodiscard +---@param input core.CraftRecipe.fuel +---@return core.CraftOutput.fuel, core.CraftRecipe.fuel +function core.get_craft_result(input) end + +--[[ +* `core.get_craft_recipe(output)`: returns input + * returns last registered recipe for output item (node) + * `output` is a node or item type such as `"default:torch"` + * `input.method` = `"normal"` or `"cooking"` or `"fuel"` + * `input.width` = for example `3` + * `input.items` = for example + `{stack1, stack2, stack3, stack4, stack 5, stack 6, stack 7, stack 8, stack 9}` + * `input.items` = `nil` if no recipe found +]] +---@nodiscard +---@param output core.Item.name +---@return core.CraftRecipe.get|core.CraftRecipe.unknown +function core.get_craft_recipe(output) end + +--[[ +* `core.get_all_craft_recipes(query item)`: returns a table or `nil` + * returns indexed table with all registered recipes for query item (node) + or `nil` if no recipe was found. + * recipe entry table: + * `method`: 'normal' or 'cooking' or 'fuel' + * `width`: 0-3, 0 means shapeless recipe + * `items`: indexed [1-9] table with recipe items + * `output`: string with item name and quantity + * Example result for `"default:gold_ingot"` with two recipes: + ```lua + { + { + method = "cooking", width = 3, + output = "default:gold_ingot", items = {"default:gold_lump"} + }, + { + method = "normal", width = 1, + output = "default:gold_ingot 9", items = {"default:goldblock"} + } + } + ``` +]] +---@nodiscard +---@param query_item core.Item.name +---@return core.CraftRecipe.with_output[] +function core.get_all_craft_recipes(query_item) end \ No newline at end of file diff --git a/types/luanti_lsp_definitions/library/core/item_handling/item_handling.lua b/types/luanti_lsp_definitions/library/core/item_handling/item_handling.lua new file mode 100644 index 00000000..4f0ae051 --- /dev/null +++ b/types/luanti_lsp_definitions/library/core/item_handling/item_handling.lua @@ -0,0 +1,167 @@ +---@meta _ +-- DRAFT 1 DONE +-- luanti/doc/lua_api.md: 'core' namespace reference > Item handling + +--[[ +WIPDOC +]] +---@nodiscard +---@param img1 core.Texture +---@param img2 core.Texture +---@param img3 core.Texture +---@return core.Texture +function core.inventorycube(img1, img2, img3) end + +--[[ +* `core.get_pointed_thing_position(pointed_thing, above)` + * Returns the position of a `pointed_thing` or `nil` if the `pointed_thing` + does not refer to a node or entity. + * If the optional `above` parameter is true and the `pointed_thing` refers + to a node, then it will return the `above` position of the `pointed_thing`. +]] +---@nodiscard +---@param pointed_thing core.PointedThing +---@param above boolean? +---@return vec? +function core.get_pointed_thing_position(pointed_thing, above) end + +--[[ +WIPDOC +]] +---@nodiscard +---@param dir vector +---@param is6d boolean? +---@return core.Param2.facedir +function core.dir_to_facedir(dir, is6d) end + +--[[ +WIPDOC +]] +---@nodiscard +---@param facedir core.Param2.facedir +---@return ivec +function core.facedir_to_dir(facedir) end + +--[[ +WIPDOC +]] +---@nodiscard +---@param dir vector +---@return core.Param2.4dir +function core.dir_to_fourdir(dir) end + +--[[ +WIPDOC +]] +---@nodiscard +---@param fourdir core.Param2.4dir +---@return ivec +function core.fourdir_to_dir(fourdir) end + +--[[ +WIPDOC +]] +---@nodiscard +---@param dir vector +---@return core.Param2.wallmounted +function core.dir_to_wallmounted(dir) end + +--[[ +WIPDOC +]] +---@nodiscard +---@param wallmounted core.Param2.wallmounted +---@return ivec +function core.wallmounted_to_dir(wallmounted) end + +--[[ +WIPDOC +]] +---@nodiscard +---@param dir vector +---@return number +function core.dir_to_yaw(dir) end + +--[[ +WIPDOC +]] +---@nodiscard +---@param yaw number +---@return vec +function core.yaw_to_dir(yaw) end + +--[[ +WIPDOC +]] +---@nodiscard +---@param param2 core.Param2 +---@param paramtype2 core.NodeDef.paramtype2.color +---@return core.Param2 +function core.strip_param2_color(param2, paramtype2) end + +--[[ +WIPDOC +]] +---@nodiscard +---@param param2 core.Param2 +---@param paramtype2 string +---@return nil +function core.strip_param2_color(param2, paramtype2) end + +--[[ +WIPDOC +]] +---@nodiscard +---@param node core.Node.name|core.Node.set +---@param toolname core.Tool.name? +---@param tool core.ItemStack? +---@param digger core.ObjectRef? +---@param pos ivector? +---@return core.Item.stringfmt[] +function core.get_node_drops(node, toolname, tool, digger, pos) end + +--[[ core.get_craft_result() .. core.get_all_craft_recipes() split off into ./craft_result.lua ]]-- + +--[[ +* `core.handle_node_drops(pos, drops, digger)` + * `drops`: list of itemstrings + * Handles drops from nodes after digging: Default action is to put them + into digger's inventory. + * Can be overridden to get different functionality (e.g. dropping items on + ground) +]] +---@param pos ivector +---@param drops core.Item.stringfmt[] +---@param digger core.ObjectRef +function core.handle_node_drops(pos, drops, digger) end + +--[[ +* `core.itemstring_with_palette(item, palette_index)`: returns an item + string. + * Creates an item string which contains palette index information + for hardware colorization. You can use the returned string + as an output in a craft recipe. + * `item`: the item stack which becomes colored. Can be in string, + table and native form. + * `palette_index`: this index is added to the item stack +]] +---@nodiscard +---@param item core.Item +---@param palette_index integer +---@return core.Item.stringfmt +function core.itemstring_with_palette(item, palette_index) end + +--[[ +* `core.itemstring_with_color(item, colorstring)`: returns an item string + * Creates an item string which contains static color information + for hardware colorization. Use this method if you wish to colorize + an item that does not own a palette. You can use the returned string + as an output in a craft recipe. + * `item`: the item stack which becomes colored. Can be in string, + table and native form. + * `colorstring`: the new color of the item stack +]] +---@param item core.Item +---@param colorstring core.ColorString +---@return core.Item.stringfmt +function core.itemstring_with_color(item, colorstring) end \ No newline at end of file diff --git a/types/luanti_lsp_definitions/library/core/logging.lua b/types/luanti_lsp_definitions/library/core/logging.lua new file mode 100644 index 00000000..6e70c68b --- /dev/null +++ b/types/luanti_lsp_definitions/library/core/logging.lua @@ -0,0 +1,35 @@ +---@meta _ +-- DRAFT 1 DONE +-- luanti/doc/lua_api.md: 'core' namespace reference > Logging + +--[[ +WIPDOC +]] +---@alias core.LoggingLevel +--- | "none" +--- | "error" +--- | "warning" +--- | "action" +--- | "info" +--- | "verbose" + +--[[ +Unofficial note: I made it deprecated because this should NOT be in any production code, and you should use something better tbh, like dbg.pp (from lars's dbg mod) +* Equivalent to `core.log(table.concat({...}, "\t"))` +]] +---@deprecated +---@param ... any +function core.debug(...) end + +--[[ +WIPDOC +]] +---@param loglevel core.LoggingLevel +---@param text string +function core.log(loglevel, text) end + +--[[ +WIPDOC +]] +---@param text string +function core.log(text) end \ No newline at end of file diff --git a/types/luanti_lsp_definitions/library/core/mapgen_environment.lua b/types/luanti_lsp_definitions/library/core/mapgen_environment.lua new file mode 100644 index 00000000..2cc70480 --- /dev/null +++ b/types/luanti_lsp_definitions/library/core/mapgen_environment.lua @@ -0,0 +1,70 @@ +---@meta _ +-- DRAFT 1 DONE +-- luanti/doc/lua_api.md: 'core' namespace reference > Mapgen environment + +--[[ +WIPDOC +]] +---@param path core.Path +function core.register_mapgen_script(path) end + +--[[ +WIPDOC +]] +---@class corelib.mapgen : corelib.async +local mapgen = { + get_biome_id = core.get_biome_id, + get_biome_name = core.get_biome_name, + get_heat = core.get_heat, + get_humidity = core.get_humidity, + get_biome_data = core.get_biome_data, + get_mapgen_object = core.get_mapgen_object, + ---@diagnostic disable-next-line: deprecated + get_mapgen_params = core.get_mapgen_params, + get_mapgen_edges = core.get_mapgen_edges, + get_mapgen_setting = core.get_mapgen_setting, + get_noiseparams = core.get_noiseparams, + get_decoration_id = core.get_decoration_id, +-- TODO ... and more. WHY THE FUCK DON'T THEY JUST LIST THE GODDAMN FUNCTIONS + + -- TODO each needs a disclaimer that it operates only in the current chunk. separate this later + get_node = core.get_node, + set_node = core.set_node, + find_node_near = core.find_node_near, + find_nodes_in_area = core.find_nodes_in_area, + spawn_tree = core.spawn_tree, +-- TODO ... and more. WHY THE FUCK DON'T THEY JUST LIST THE GODDAMN FUNCTIONS + + settings = core.settings, + +-- TODO async registered_* has functions and userdata set to true instead + registered_items = core.registered_items, + registered_nodes = core.registered_nodes, + registered_tools = core.registered_tools, + registered_craftitems = core.registered_craftitems, + registered_aliases = core.registered_aliases, +-- TODO ... and more. WHY THE FUCK DON'T THEY JUST LIST THE GODDAMN FUNCTIONS + registered_biomes = core.registered_biomes, + registered_ores = core.registered_ores, + registered_decorations = core.registered_decorations, +} + +--[[ +WIPDOC +]] +---@alias mapgen.fn.on_generated fun(vmanip:core.VoxelManip, minp:ivec, maxp:ivec, blockseed:integer) + +--[[ +WIPDOC +]] +---@param f mapgen.fn.on_generated +function mapgen.register_on_generated(f) end + +--[[ +WIPDOC +]] +---@nodiscard +---@param id string +---@param data core.Serializable +---@return true? +function mapgen.register_on_generated(id, data) end diff --git a/types/luanti_lsp_definitions/library/core/misc/get_group.lua b/types/luanti_lsp_definitions/library/core/misc/get_group.lua new file mode 100644 index 00000000..f71dbd21 --- /dev/null +++ b/types/luanti_lsp_definitions/library/core/misc/get_group.lua @@ -0,0 +1,145 @@ +---@meta _ +-- DRAFT 1 DONE +-- luanti/doc/lua_api.md: 'core' namespace reference > Misc. + +--[[ +* `core.get_item_group(name, group)`: returns a rating + * Get rating of a group of an item. (`0` means: not in group) +]] +---@nodiscard +---@param name core.Item.name +---@param group string +---@return integer +function core.get_item_group(name, group) end + +--[[ +* `core.get_item_group(name, group)`: returns a rating + * Get rating of a group of an item. (`0` means: not in group) +]] +---@nodiscard +---@param name core.Item.name +---@param group "not_in_creative_inventory" +---@return integer +function core.get_item_group(name, group) end + +--[[ +* `core.get_item_group(name, group)`: returns a rating + * Get rating of a group of an item. (`0` means: not in group) +]] +---@nodiscard +---@param name core.Item.name +---@param group "attached_node" +---@return core.Groups.special.attached_node +function core.get_item_group(name, group) end + +--[[ +* `core.get_item_group(name, group)`: returns a rating + * Get rating of a group of an item. (`0` means: not in group) +]] +---@nodiscard +---@param name core.Item.name +---@param group "bouncy" +---@return integer +function core.get_item_group(name, group) end + +--[[ +* `core.get_item_group(name, group)`: returns a rating + * Get rating of a group of an item. (`0` means: not in group) +]] +---@nodiscard +---@param name core.Item.name +---@param group "connect_to_raillike" +---@return integer +function core.get_item_group(name, group) end + +--[[ +* `core.get_item_group(name, group)`: returns a rating + * Get rating of a group of an item. (`0` means: not in group) +]] +---@nodiscard +---@param name core.Item.name +---@param group "dig_immediate" +---@return core.Groups.special.dig_immediate +function core.get_item_group(name, group) end + +--[[ +* `core.get_item_group(name, group)`: returns a rating + * Get rating of a group of an item. (`0` means: not in group) +]] +---@nodiscard +---@param name core.Item.name +---@param group "disable_jump" +---@return core.Groups.special.disable_jump +function core.get_item_group(name, group) end + +--[[ +* `core.get_item_group(name, group)`: returns a rating + * Get rating of a group of an item. (`0` means: not in group) +]] +---@nodiscard +---@param name core.Item.name +---@param group "disable_descend" +---@return core.Groups.special.disable_descend +function core.get_item_group(name, group) end + +--[[ +* `core.get_item_group(name, group)`: returns a rating + * Get rating of a group of an item. (`0` means: not in group) +]] +---@nodiscard +---@param name core.Item.name +---@param group "fall_damage_add_percent" +---@return integer +function core.get_item_group(name, group) end + +--[[ +* `core.get_item_group(name, group)`: returns a rating + * Get rating of a group of an item. (`0` means: not in group) +]] +---@nodiscard +---@param name core.Item.name +---@param group "falling_node" +---@return core.Groups.special.falling_node +function core.get_item_group(name, group) end + +--[[ +* `core.get_item_group(name, group)`: returns a rating + * Get rating of a group of an item. (`0` means: not in group) +]] +---@nodiscard +---@param name core.Item.name +---@param group "float" +---@return core.Groups.special.float +function core.get_item_group(name, group) end + +--[[ +* `core.get_item_group(name, group)`: returns a rating + * Get rating of a group of an item. (`0` means: not in group) +]] +---@nodiscard +---@param name core.Item.name +---@param group "slippery" +---@return integer +function core.get_item_group(name, group) end + +--[[ +* `core.get_item_group(name, group)`: returns a rating + * Get rating of a group of an item. (`0` means: not in group) +]] +---@nodiscard +---@param name core.Item.name +---@param group "level" +---@return integer +function core.get_item_group(name, group) end + +-- NOTE: core.get_node_group don't get any completion. this is intentional + +--[[ +* `core.get_node_group(name, group)`: returns a rating + * Deprecated: An alias for the former. +]] +---@deprecated +---@param name core.Item.name +---@param group string +---@return integer +function core.get_node_group(name, group) end \ No newline at end of file diff --git a/types/luanti_lsp_definitions/library/core/misc/insecure_environment.lua b/types/luanti_lsp_definitions/library/core/misc/insecure_environment.lua new file mode 100644 index 00000000..a0a7691c --- /dev/null +++ b/types/luanti_lsp_definitions/library/core/misc/insecure_environment.lua @@ -0,0 +1,26 @@ +---@meta _ +-- DRAFT 1 DONE +-- luanti/doc/lua_api.md: 'core' namespace reference > Misc. + +--[[ +WIPDOC +]] +---@class corelib.insecure +local insecure = {} + +-- TODO inspect what's inside an insecure environment +-- TODO research what's different in an insecure environment + +--[[ +* `core.request_insecure_environment()`: returns an environment containing + insecure functions if the calling mod has been listed as trusted in the + `secure.trusted_mods` setting or security is disabled, otherwise returns + `nil`. + * Only works at init time and must be called from the mod's main scope + (ie: the init.lua of the mod, not from another Lua file or within a function). + * **DO NOT ALLOW ANY OTHER MODS TO ACCESS THE RETURNED ENVIRONMENT, STORE + IT IN A LOCAL VARIABLE!** +]] +---@nodiscard +---@return corelib.insecure? +function core.request_insecure_environment() end \ No newline at end of file diff --git a/types/luanti_lsp_definitions/library/core/misc/misc.lua b/types/luanti_lsp_definitions/library/core/misc/misc.lua new file mode 100644 index 00000000..a6cc63c6 --- /dev/null +++ b/types/luanti_lsp_definitions/library/core/misc/misc.lua @@ -0,0 +1,596 @@ +---@meta _ +-- DRAFT 1 DONE +-- luanti/doc/lua_api.md: 'core' namespace reference > Misc. + +-- --------------------------- Player and Entities -------------------------- -- + +--[[ +* `core.get_connected_players()`: returns list of `ObjectRefs` +]] +---@nodiscard +---@return core.PlayerRef[] +function core.get_connected_players() end + +--[[ +* `core.is_player(obj)`: boolean, whether `obj` is a player +]] +---@nodiscard +---@param obj core.ObjectRef +---@return boolean +function core.is_player(obj) end + +--[[ +* `core.is_player(obj)`: boolean, whether `obj` is a player +]] +---@nodiscard +---@param obj core.PlayerRef +---@return true +function core.is_player(obj) end + +--[[ +* `core.player_exists(name)`: boolean, whether player exists + (regardless of online status) +]] +---@nodiscard +---@param name string +---@return boolean +function core.player_exists(name) end + +--[[ +* `core.is_valid_player_name(name)`: boolean, whether the given name + could be used as a player name (regardless of whether said player exists). +]] +---@nodiscard +---@param name string +---@return boolean +function core.is_valid_player_name(name) end + +--[[ +* `core.hud_replace_builtin(name, hud_definition)` + * Replaces definition of a builtin hud element + * `name`: `"breath"`, `"health"`, `"minimap"` or `"hotbar"` + * `hud_definition`: definition to replace builtin definition +]] +---@param name "breath"|"health"|"minimap"|"hotbar" +---@param hud_definition core.HUDDef +function core.hud_replace_builtin(name, hud_definition) end + +-- -------------------------------------------------------------------------- -- + +--[[ +* `core.parse_relative_number(arg, relative_to)`: returns number or nil + * Helper function for chat commands. + * For parsing an optionally relative number of a chat command + parameter, using the chat command tilde notation. + * `arg`: String snippet containing the number; possible values: + * `""`: return as number + * `"~"`: return `relative_to + ` + * `"~"`: return `relative_to` + * Anything else will return `nil` + * `relative_to`: Number to which the `arg` number might be relative to + * Examples: + * `core.parse_relative_number("5", 10)` returns 5 + * `core.parse_relative_number("~5", 10)` returns 15 + * `core.parse_relative_number("~", 10)` returns 10 +]] +---@nodiscard +---@param arg string +---@param relative_to vector +---@return vec? +function core.parse_relative_number(arg, relative_to) end + +--[[ +* `core.send_join_message(player_name)` + * This function can be overridden by mods to change the join message. +]] +---@param player_name string +function core.send_join_message(player_name) end + +--[[ +* `core.send_leave_message(player_name, timed_out)` + * This function can be overridden by mods to change the leave message. +]] +---@param player_name string +---@param timed_out boolean +function core.send_leave_message(player_name, timed_out) end + +-- ------------------------------ position hash ----------------------------- -- + +--[[ +WIPDOC +]] +---@alias core.PosHash integer + +--[[ +* `core.hash_node_position(pos)`: returns a 48-bit integer + * `pos`: table {x=number, y=number, z=number}, + * Gives a unique numeric encoding for a node position (16+16+16=48bit) + * Despite the name, this is not a hash function (so it doesn't mix or produce collisions). +]] +---@nodiscard +---@param pos ivector +---@return core.PosHash +function core.hash_node_position(pos) end + +--[[ +* `core.get_position_from_hash(hash)`: returns a position + * Inverse transform of `core.hash_node_position` +]] +---@nodiscard +---@param hash core.PosHash +---@return ivec +function core.get_position_from_hash(hash) end + +-- --------------------------------- groups --------------------------------- -- + +--[[ core.get_item_group() .. core.get_node_group() split off into ./get_group.lua ]]-- + +--[[ +* `core.raillike_group(name)`: returns a rating + * Returns rating of the connect_to_raillike group corresponding to name + * If name is not yet the name of a connect_to_raillike group, a new group + id is created, with that name. +]] +---@nodiscard +---@param name core.Node.name +---@return integer +function core.raillike_group(name) end + +-- ------------------------------- content ID ------------------------------- -- + +--[[ +* `core.get_content_id(name)`: returns an integer + * Gets the internal content ID of `name` +]] +---@nodiscard +---@param name core.Node.name +---@return core.ContentID +function core.get_content_id(name) end + +--[[ +* `core.get_name_from_content_id(content_id)`: returns a string + * Gets the name of the content with that content ID +]] +---@nodiscard +---@param content_id core.ContentID +---@return core.Node.name +function core.get_name_from_content_id(content_id) end + +-- ------------------------------ serialization ----------------------------- -- + +--[[ +* `core.parse_json(string[, nullvalue, return_error])`: returns something + * Convert a string containing JSON data into the Lua equivalent + * `nullvalue`: returned in place of the JSON null; defaults to `nil` + * On success returns a table, a string, a number, a boolean or `nullvalue` + * On failure: If `return_error` is not set or is `false`, + outputs an error message and returns `nil`. + Otherwise returns `nil, err` (error message). + * Example: `parse_json("[10, {\"a\":false}]")`, returns `{10, {a = false}}` +]] +---@nodiscard +---@param string string +---@param nullvalue any? +---@param return_error false? +---@return core.Serializable? +function core.parse_json(string, nullvalue, return_error) end + +--[[ +* `core.parse_json(string[, nullvalue, return_error])`: returns something + * Convert a string containing JSON data into the Lua equivalent + * `nullvalue`: returned in place of the JSON null; defaults to `nil` + * On success returns a table, a string, a number, a boolean or `nullvalue` + * On failure: If `return_error` is not set or is `false`, + outputs an error message and returns `nil`. + Otherwise returns `nil, err` (error message). + * Example: `parse_json("[10, {\"a\":false}]")`, returns `{10, {a = false}}` +]] +---@nodiscard +---@param string string +---@param nullvalue any? +---@param return_error true +---@return core.Serializable?, string? +function core.parse_json(string, nullvalue, return_error) end + +--[[ +* `core.write_json(data[, styled])`: returns a string or `nil` and an error + message. + * Convert a Lua table into a JSON string + * styled: Outputs in a human-readable format if this is set, defaults to + false. + * Unserializable things like functions and userdata will cause an error. + * **Warning**: JSON is more strict than the Lua table format. + 1. You can only use strings and positive integers of at least one as + keys. + 2. You cannot mix string and integer keys. + This is due to the fact that JSON has two distinct array and object + values. + * Example: `write_json({10, {a = false}})`, + returns `'[10, {"a": false}]'` +]] +---@nodiscard +---@param data core.Serializable +---@param styled boolean? +---@return string +function core.write_json(data, styled) end + +--[[ +* `core.serialize(table)`: returns a string + * Convert a value into string form readable by `core.deserialize`. + * Supports tables, strings, numbers, booleans and `nil`. + * Support for dumping function bytecode is **deprecated**. + * Note: To obtain a human-readable representation of a value, use `dump` instead. + * Example: `serialize({foo="bar"})`, returns `'return { ["foo"] = "bar" }'` +]] +---@nodiscard +---@param table core.Serializable +---@return string +function core.serialize(table) end + +--[[ +* `core.deserialize(string[, safe])`: returns a table + * Convert a string returned by `core.serialize` into a table + * `string` is loaded in an empty sandbox environment. + * Will load functions if `safe` is `false` or omitted. + Although these functions cannot directly access the global environment, + they could bypass this restriction with maliciously crafted Lua bytecode + if mod security is disabled. + * Will silently strip functions embedded via calls to `loadstring` + (typically bytecode dumped by `core.serialize`) if `safe` is `true`. + You should not rely on this if possible. + * Example: `core.deserialize("return loadstring('')", true)` will be `nil`. + * This function should not be used on untrusted data, regardless of the + value of `safe`. It is fine to serialize then deserialize user-provided + data, but directly providing user input to deserialize is always unsafe. + * Example: `deserialize('return { ["foo"] = "bar" }')`, + returns `{foo="bar"}` + * Example: `deserialize('print("foo")')`, returns `nil` + (function call fails), returns + `error:[string "print("foo")"]:1: attempt to call global 'print' (a nil value)` +]] +---@nodiscard +---@param string string +---@param safe boolean? +---@return core.Serializable +function core.deserialize(string, safe) end + +-- ------------------------------- compression ------------------------------ -- + +--[[ +* `core.compress(data, method, ...)`: returns `compressed_data` + * Compress a string of data. + * `method` is a string identifying the compression method to be used. + * Supported compression methods: + * Deflate (zlib): `"deflate"` + * Zstandard: `"zstd"` + * `...` indicates method-specific arguments. Currently defined arguments + are: + * Deflate: `level` - Compression level, `0`-`9` or `nil`. + * Zstandard: `level` - Compression level. Integer or `nil`. Default `3`. + Note any supported Zstandard compression level could be used here, + but these are subject to change between Zstandard versions. +]] +---@nodiscard +---@param data string +---@param method "deflate" +---@param level 0|1|2|3|4|5|6|7|8|9? +---@return string +function core.compress(data, method, level) end + +--[[ +* `core.compress(data, method, ...)`: returns `compressed_data` + * Compress a string of data. + * `method` is a string identifying the compression method to be used. + * Supported compression methods: + * Deflate (zlib): `"deflate"` + * Zstandard: `"zstd"` + * `...` indicates method-specific arguments. Currently defined arguments + are: + * Deflate: `level` - Compression level, `0`-`9` or `nil`. + * Zstandard: `level` - Compression level. Integer or `nil`. Default `3`. + Note any supported Zstandard compression level could be used here, + but these are subject to change between Zstandard versions. +]] +---@nodiscard +---@param data string +---@param method "zstd" +---@param level integer? +---@return string +function core.compress(data, method, level) end + +--[[ +* `core.decompress(compressed_data, method, ...)`: returns data + * Decompress a string of data using the algorithm specified by `method`. + * See documentation on `core.compress()` for supported compression + methods. + * `...` indicates method-specific arguments. Currently, no methods use this +]] +---@nodiscard +---@param compressed_data string +---@param method "zstd"|"deflate" +---@return string +function core.decompress(compressed_data, method) end + +-- -------------------------------------------------------------------------- -- + +--[[ +* `core.rgba(red, green, blue[, alpha])`: returns a string + * Each argument is an 8 Bit unsigned integer + * Returns the ColorString from rgb or rgba values + * Example: `core.rgba(10, 20, 30, 40)`, returns `"#0A141E28"` +]] +---@nodiscard +---@param red integer +---@param green integer +---@param blue integer +---@param alpha integer? +---@return core.ColorString +function core.rgba(red, green, blue, alpha) end + +-- -------------------------------- encoding -------------------------------- -- + +--[[ +* `core.encode_base64(string)`: returns string encoded in base64 + * Encodes a string in base64. +]] +---@param string string +---@return string +function core.encode_base64(string) end + +--[[ +* `core.decode_base64(string)`: returns string or nil on failure + * Padding characters are only supported starting at version 5.4.0, where + 5.5.0 and newer perform proper checks. + * Decodes a string encoded in base64. +]] +---@param string string +---@return string +function core.decode_base64(string) end + +-- ------------------------------- protection ------------------------------- -- + +--[[ +Unofficial note: Do NOT localize it, i know you want to, just don't +* `core.is_protected(pos, name)`: returns boolean + * Returning `true` restricts the player `name` from modifying (i.e. digging, + placing) the node at position `pos`. + * `name` will be `""` for non-players or unknown players. + * This function should be overridden by protection mods. It is highly + recommended to grant access to players with the `protection_bypass` privilege. + * Cache and call the old version of this function if the position is + not protected by the mod. This will allow using multiple protection mods. + * Example: + ```lua + local old_is_protected = core.is_protected + function core.is_protected(pos, name) + if mymod:position_protected_from(pos, name) then + return true + end + return old_is_protected(pos, name) + end + ``` +]] +---@nodiscard +---@param pos ivector +---@param name string +---@return boolean +function core.is_protected(pos, name) end + +--[[ +* `core.record_protection_violation(pos, name)` + * This function calls functions registered with + `core.register_on_protection_violation`. +]] +---@param pos ivector +---@param name string +function core.record_protection_violation(pos, name) end + +--[[ +* `core.is_creative_enabled(name)`: returns boolean + * Returning `true` means that Creative Mode is enabled for player `name`. + * `name` will be `""` for non-players or if the player is unknown. + * This function should be overridden by Creative Mode-related mods to + implement a per-player Creative Mode. + * By default, this function returns `true` if the setting + `creative_mode` is `true` and `false` otherwise. +]] +---@nodiscard +---@param name string +---@return boolean +function core.is_creative_enabled(name) end + +--[[ +* `core.is_area_protected(pos1, pos2, player_name, interval)` + * Returns the position of the first node that `player_name` may not modify + in the specified cuboid between `pos1` and `pos2`. + * Returns `false` if no protections were found. + * Applies `is_protected()` to a 3D lattice of points in the defined volume. + The points are spaced evenly throughout the volume and have a spacing + similar to, but no larger than, `interval`. + * All corners and edges of the defined volume are checked. + * `interval` defaults to 4. + * `interval` should be carefully chosen and maximized to avoid an excessive + number of points being checked. + * Like `core.is_protected`, this function may be extended or + overwritten by mods to provide a faster implementation to check the + cuboid for intersections. +]] +---@nodiscard +---@param pos1 ivector +---@param pos2 ivector +---@param player_name string +---@param interval integer +---@return boolean +function core.is_area_protected(pos1, pos2, player_name, interval) end + +--[[ +WIPDOC +]] +---@class core.RotateAndPlace.orient_flags +--[[ +WIPDOC +]] +---@field invert_wall boolean? +--[[ +WIPDOC +]] +---@field force_wall boolean? +--[[ +WIPDOC +]] +---@field force_ceiling boolean? +--[[ +WIPDOC +]] +---@field force_floor boolean? +--[[ +WIPDOC +]] +---@field force_facedir boolean? + +--[[ +* `core.rotate_and_place(itemstack, placer, pointed_thing[, infinitestacks, + orient_flags, prevent_after_place])` + * Attempt to predict the desired orientation of the facedir-capable node + defined by `itemstack`, and place it accordingly (on-wall, on the floor, + or hanging from the ceiling). + * `infinitestacks`: if `true`, the itemstack is not changed. Otherwise the + stacks are handled normally. + * `orient_flags`: Optional table containing extra tweaks to the placement code: + * `invert_wall`: if `true`, place wall-orientation on the ground and + ground-orientation on the wall. + * `force_wall`: if `true`, always place the node in wall orientation. + * `force_ceiling`: if `true`, always place on the ceiling. + * `force_floor`: if `true`, always place the node on the floor. + * `force_facedir`: if `true`, forcefully reset the facedir to north + when placing on the floor or ceiling. + * The first four options are mutually-exclusive; the last in the list + takes precedence over the first. + * `prevent_after_place` is directly passed to `core.item_place_node` + * Returns the new itemstack after placement +]] +---@nodiscard +---@param itemstack core.ItemStack +---@param placer core.ObjectRef +---@param pointed_thing core.PointedThing +---@param infinitestacks boolean? +---@param orient_flags core.RotateAndPlace.orient_flags? +---@param prevent_after_place boolean? +---@return core.ItemStack +function core.rotate_and_place(itemstack, placer, pointed_thing, infinitestacks, orient_flags, prevent_after_place) end + + +--[[ +* `core.rotate_node(itemstack, placer, pointed_thing)` + * calls `rotate_and_place()` with `infinitestacks` set according to the state + of the creative mode setting, checks for "sneak" to set the `invert_wall` + parameter and `prevent_after_place` set to `true` +]] +---@param itemstack core.ItemStack +---@param placer core.ObjectRef +---@param pointed_thing core.PointedThing +function core.rotate_node(itemstack, placer, pointed_thing) end + + +--[[ +* `core.calculate_knockback(player, hitter, time_from_last_punch, + tool_capabilities, dir, distance, damage)` + * Returns the amount of knockback applied on the punched player. + * Arguments are equivalent to `register_on_punchplayer`, except the following: + * `distance`: distance between puncher and punched player + * This function can be overridden by mods that wish to modify this behavior. + * You may want to cache and call the old function to allow multiple mods to + change knockback behavior. +]] +---@nodiscard +---@param player core.PlayerRef +---@param hitter core.ObjectRef +---@param time_from_last_punch number +---@param tool_capabilities core.ToolCapabilities +---@param dir vector +---@param distance number +---@param damage integer +---@return number +function core.calculate_knockback(player, hitter, time_from_last_punch, tool_capabilities, dir, distance, damage) end + +-- ----------------------------- mapblock status ---------------------------- -- + +--[=[ +* `core.forceload_block(pos[, transient[, limit]])` + * forceloads the position `pos`. + * this means that the mapblock containing `pos` will always be kept in the + `"active"` state, regardless of nearby players or server settings. + * returns `true` if area could be forceloaded + * If `transient` is `false` or absent, the forceload will be persistent + (saved between server runs). If `true`, the forceload will be transient + (not saved between server runs). + * `limit` is an optional limit on the number of blocks that can be + forceloaded at once. If `limit` is negative, there is no limit. If it is + absent, the limit is the value of the setting `"max_forceloaded_blocks"`. + If the call would put the number of blocks over the limit, the call fails. +]=] +---@nodiscard +---@param pos ivector +---@param transient boolean? +---@param limit number? +---@return boolean +function core.forceload_block(pos, transient, limit) end + +--[[ +* `core.forceload_free_block(pos[, transient])` + * stops forceloading the position `pos` + * If `transient` is `false` or absent, frees a persistent forceload. + If `true`, frees a transient forceload. +]] +---@param pos ivector +---@param transient boolean? +function core.forceload_free_block(pos, transient) end + +--[[ +* `core.compare_block_status(pos, condition)` + * Checks whether the mapblock at position `pos` is in the wanted condition. + * `condition` may be one of the following values: + * `"unknown"`: not in memory + * `"emerging"`: in the queue for loading from disk or generating + * `"loaded"`: in memory but inactive (no ABMs are executed) + * `"active"`: in memory and active + * Other values are reserved for future functionality extensions + * Return value, the comparison status: + * `false`: Mapblock does not fulfill the wanted condition + * `true`: Mapblock meets the requirement + * `nil`: Unsupported `condition` value +]] +---@nodiscard +---@param pos ivector +---@param condition "unknown"|"emerging"|"loaded"|"active" +---@return boolean? +function core.compare_block_status(pos, condition) end + +-- -------------------------------------------------------------------------- -- + +--[[ core.request_insecure_environment() split off into ./insecure_environment.lua ]]-- + +--[[ +* `core.global_exists(name)` + * Checks if a global variable has been set, without triggering a warning. +]] +---@nodiscard +---@param name string +---@return boolean +function core.global_exists(name) end + +--[[ +* `core.register_portable_metatable(name, mt)`: + * Register a metatable that should be preserved when Lua data is transferred + between environments (via IPC or `handle_async`). + * `name` is a string that identifies the metatable. It is recommended to + follow the `modname:name` convention for this identifier. + * `mt` is the metatable to register. + * Note that the same metatable can be registered under multiple names, + but multiple metatables must not be registered under the same name. + * You must register the metatable in both the main environment + and the async environment for this mechanism to work. +]] +---@param name string +---@param mt table +function core.register_portable_metatable(name, mt) end \ No newline at end of file diff --git a/types/luanti_lsp_definitions/library/core/mod_channels.lua b/types/luanti_lsp_definitions/library/core/mod_channels.lua new file mode 100644 index 00000000..d2998b5c --- /dev/null +++ b/types/luanti_lsp_definitions/library/core/mod_channels.lua @@ -0,0 +1,11 @@ +---@meta _ +-- DRAFT 1 DONE +-- luanti/doc/lua_api.md: 'core' namespace reference > Mod channels + +--[[ +WIPDOC +]] +---@nodiscard +---@param channel_name string +---@return core.ModChannel +function core.mod_channel_join(channel_name) end \ No newline at end of file diff --git a/types/luanti_lsp_definitions/library/core/particles.lua b/types/luanti_lsp_definitions/library/core/particles.lua new file mode 100644 index 00000000..49d6fdeb --- /dev/null +++ b/types/luanti_lsp_definitions/library/core/particles.lua @@ -0,0 +1,72 @@ +---@meta _ +-- DRAFT 1 DONE +-- luanti/doc/lua_api.md: 'core' namespace reference > Particles + +--[[ +* `core.add_particle(particle definition)` + * Spawn a single particle + * Deprecated: `core.add_particle(pos, velocity, acceleration, + expirationtime, size, collisiondetection, texture, playername)` +]] +---@deprecated +---@param pos vector +---@param velocity vector +---@param acceleration vector +---@param expirationtime number +---@param size number +---@param collisiondetection boolean +---@param texture core.Texture +---@param playername string +function core.add_particle(pos, velocity, acceleration, + expirationtime, size, collisiondetection, texture, playername) end + +--[[ +Unofficial note: Prefer not doing 100 000 particles in a single globalstep +Because that will make the network scream, with no way to debug it +Instead, invest time into particlespawners, invest time into creating an issue on luanti github, invest time into creating a client side mod +]] +---@param particle_def core.ParticleDef.regular +function core.add_particle(particle_def) end + +--[[ +WIPDOC +]] +---@deprecated +---@nodiscard +---@param amount integer +---@param time number +---@param minpos vector +---@param maxpos vector +---@param minvel vector +---@param maxvel vector +---@param minacc vector +---@param maxacc vector +---@param minexptime number +---@param maxexptime number +---@param minsize number +---@param maxsize number +---@param collisiondetection boolean +---@param texture core.Texture +---@param playername string +---@return core.ParticleSpawnerID +function core.add_particlespawner(amount, time, minpos, maxpos, minvel, maxvel, minacc, maxacc, minexptime, maxexptime, minsize, maxsize, collisiondetection, texture, playername) end +--[[ +* Add a `ParticleSpawner`, an object that spawns an amount of particles + over `time` seconds. +* Returns an `id`, and -1 if adding didn't succeed +]] +---@nodiscard +---@param particlespawner_def core.ParticleSpawnerDef +---@return core.ParticleSpawnerID +function core.add_particlespawner(particlespawner_def) end + +--[[ +* `core.delete_particlespawner(id, player)` + * Delete `ParticleSpawner` with `id` (return value from + `core.add_particlespawner`). + * If playername is specified, only deletes on the player's client, + otherwise on all clients. +]] +---@param id core.ParticleSpawnerID +---@param player string? +function core.delete_particlespawner(id, player) end \ No newline at end of file diff --git a/types/luanti_lsp_definitions/library/core/register/cheat.lua b/types/luanti_lsp_definitions/library/core/register/cheat.lua new file mode 100644 index 00000000..7bb2e03b --- /dev/null +++ b/types/luanti_lsp_definitions/library/core/register/cheat.lua @@ -0,0 +1,48 @@ +---@meta _ +-- DRAFT 1 DONE +-- luanti/doc/lua_api.md: 'core' namespace reference > Global callback registration functions + +-- ---------------------------------- Cheat --------------------------------- -- + +--[[ +WIPDOC +]] +---@alias core.Cheat.type +--- | "moved_too_fast" +--- | "interacted_too_far" +--- | "interacted_with_self" +--- | "interacted_while_dead" +--- | "finished_unknown_dig" +--- | "dug_unbreakable" +--- | "dug_too_fast" + +--[[ +WIPDOC +]] +---@class core.Cheat +--[[ +WIPDOC +]] +---@field type core.Cheat.type + +-- ---------------------------- core.* functions ---------------------------- -- + +--[[ +WIPDOC +]] +---@alias core.fn.on_cheat fun(ObjectRef:core.PlayerRef, cheat:core.Cheat) + +--[[ +* `core.register_on_cheat(function(ObjectRef, cheat))` + * Called when a player cheats + * `cheat`: `{type=}`, where `` is one of: + * `moved_too_fast` + * `interacted_too_far` + * `interacted_with_self` + * `interacted_while_dead` + * `finished_unknown_dig` + * `dug_unbreakable` + * `dug_too_fast` +]] +---@param f core.fn.on_cheat +function core.register_on_cheat(f) end \ No newline at end of file diff --git a/types/luanti_lsp_definitions/library/core/register/environment.lua b/types/luanti_lsp_definitions/library/core/register/environment.lua new file mode 100644 index 00000000..c324ea79 --- /dev/null +++ b/types/luanti_lsp_definitions/library/core/register/environment.lua @@ -0,0 +1,150 @@ +---@meta _ +-- DRAFT 1 DONE +-- luanti/doc/lua_api.md: 'core' namespace reference > Registration functions > Environment + +--[[ +* Note: you must pass a clean table that hasn't already been used for + another registration to this function, as it will be modified. +]] +---@param name string +---@param node_def core.NodeDef +function core.register_node(name, node_def) end + +--[[ +* Note: you must pass a clean table that hasn't already been used for + another registration to this function, as it will be modified. +]] +---@param name string +---@param itemdef core.ItemDef +function core.register_craftitem(name, itemdef) end + +--[[ +* Note: you must pass a clean table that hasn't already been used for + another registration to this function, as it will be modified. +]] +---@param name string +---@param itemdef core.ItemDef +function core.register_tool(name, itemdef) end + +--[[ +* `core.override_item(name, redefinition, del_fields)` + * `redefinition` is a table of fields `[name] = new_value`, + overwriting fields of or adding fields to the existing definition. + * `del_fields` is a list of field names to be set + to `nil` ("deleted from") the original definition. + * Overrides fields of an item registered with register_node/tool/craftitem. + * Note: Item must already be defined. + * Example: `core.override_item("default:mese", + {light_source=core.LIGHT_MAX}, {"sounds"})`: + Overwrites the `light_source` field, + removes the sounds from the definition of the mese block. +]] +---@param name string +---@param redefinition core.ItemDef|core.NodeDef +---@param del_fields core.ItemDef.keys|core.NodeDef.keys +function core.override_item(name, redefinition, del_fields) end + +--[[ +WIPDOC +]] +---@param name string +function core.unregister_item(name) end + +--[[ +WIPDOC +]] +---@param name string +---@param entity_def core.EntityDef +function core.register_entity(name, entity_def) end + +--[[ +WIPDOC +]] +---@param abmdef core.ABMDef +function core.register_abm(abmdef) end + +--[[ +WIPDOC +]] +---@param lbmdef core.LBMDef +function core.register_lbm(lbmdef) end + +--[[ +Also use this to set the 'mapgen aliases' needed in a game for the code mapgens. +]] +---@param alias core.Alias +---@param original_name core.Item.name +function core.register_alias(alias, original_name) end + +--[[ +WIPDOC +]] +---@param alias core.Alias +---@param original_name core.Item.name +function core.register_alias_force(alias, original_name) end + +--[[ +WIPDOC +]] +---@nodiscard +---@param def core.OreDef +---@return core.OreID? +function core.register_ore(def) end + +--[[ +WIPDOC +]] +---@nodiscard +---@param biome_def core.BiomeDef +---@return core.BiomeID? +function core.register_biome(biome_def) end + +--[[ +* Unregisters the biome from the engine, and deletes the entry with key + `name` from `core.registered_biomes`. +* Warning: This alters the biome to biome ID correspondences, so any + decorations or ores using the 'biomes' field must afterwards be cleared + and re-registered. +]] +---@param name string +function core.unregister_biome(name) end + +--[[ +WIPDOC +]] +---@nodiscard +---@param decoration_def core.DecorationDef +---@return core.DecorationID? +function core.register_decoration(decoration_def) end + +--[[ +WIPDOC +]] +---@nodiscard +---@param schem_def core.SchematicDef +---@return core.SchematicID +function core.register_schematic(schem_def) end + +--[[ +* `core.clear_registered_biomes()` + * Clears all biomes currently registered. + * Warning: Clearing and re-registering biomes alters the biome to biome ID + correspondences, so any decorations or ores using the 'biomes' field must + afterwards be cleared and re-registered. +]] +function core.clear_registered_biomes() end + +--[[ +WIPDOC +]] +function core.clear_registered_decorations() end + +--[[ +WIPDOC +]] +function core.clear_registered_ores() end + +--[[ +WIPDOC +]] +function core.clear_registered_schematics() end diff --git a/types/luanti_lsp_definitions/library/core/register/gameplay.lua b/types/luanti_lsp_definitions/library/core/register/gameplay.lua new file mode 100644 index 00000000..10998425 --- /dev/null +++ b/types/luanti_lsp_definitions/library/core/register/gameplay.lua @@ -0,0 +1,49 @@ +---@meta _ +-- DRAFT 1 DONE +-- luanti/doc/lua_api.md: 'core' namespace reference > Registration functions > Gameplay + +--[[ +WIPDOC +]] +---@param craft_recipe core.CraftingRecipeDef +function core.register_craft(craft_recipe) end + +--[[ +WIPDOC +]] +---@param recipe core.CraftingRecipeDef.clear? +function core.clear_craft(recipe) end + +--[[ +WIPDOC +]] +---@param name string +---@param chatcommand_def core.ChatCommandDef +function core.register_chatcommand(name, chatcommand_def) end + +--[[ +WIPDOC +]] +---@param name string +---@param redef core.ChatCommandDef.override +function core.override_chatcommand(name, redef) end + +--[[ +WIPDOC +]] +---@param name string +function core.unregister_chatcommand(name) end + +--[[ +WIPDOC +]] +---@param name string +---@param def core.PrivilegeDef +function core.register_privilege(name, def) end + +--[[ +* Registers an auth handler that overrides the builtin one. +* This function can be called by a single mod once only. +]] +---@param auth_handler_def core.AuthenticationHandlerDef +function core.register_authentication_handler(auth_handler_def) end \ No newline at end of file diff --git a/types/luanti_lsp_definitions/library/core/register/global_callback.lua b/types/luanti_lsp_definitions/library/core/register/global_callback.lua new file mode 100644 index 00000000..1cf57444 --- /dev/null +++ b/types/luanti_lsp_definitions/library/core/register/global_callback.lua @@ -0,0 +1,451 @@ +---@meta _ +-- DRAFT 1 DONE +-- luanti/doc/lua_api.md: 'core' namespace reference > Global callback registration functions + +-- ---------------------- server step, start, shutdown ---------------------- -- + +--[[ +WIPDOC +]] +---@alias core.fn.globalstep fun(dtime:number) + +--[[ +* Called every server step, usually interval of 0.1s. +* `dtime` is the time since last execution in seconds. +]] +---@param f core.fn.globalstep +function core.register_globalstep(f) end + +--[[ +WIPDOC +]] +---@alias core.fn.on_mods_loaded fun() + +--[[ +* Called after all mods have finished loading and before the media is cached + or aliases are handled. +]] +---@param f core.fn.on_mods_loaded +function core.register_on_mods_loaded(f) end + +--[[ +WIPDOC +]] +---@alias core.fn.on_shutdown fun() + +--[[ +* `core.register_on_shutdown(function())` + * Called during server shutdown before players are kicked. + * **Warning**: If the server terminates abnormally (i.e. crashes), the + registered callbacks will likely **not run**. Data should be saved at + semi-frequent intervals as well as on server shutdown. +]] +---@param f core.fn.on_shutdown +function core.register_on_shutdown(f) end + +-- ------------------------------- node events ------------------------------ -- + +--[[ +WIPDOC +]] +---@alias core.fn.on_placenode fun(pos:ivec, newnode:core.Node.get, placer:core.ObjectRef?, oldnode:core.Node.get, itemstack:core.ItemStack, pointed_thing:core.PointedThing):boolean? + +--[[ +* `core.register_on_placenode(function(pos, newnode, placer, oldnode, itemstack, pointed_thing))` + * Called after a node has been placed. + * If `true` is returned no item is taken from `itemstack` + * `placer` may be any valid ObjectRef or nil. + * **Not recommended**; use `on_construct` or `after_place_node` in node + definition whenever possible. +]] +---@param f core.fn.on_placenode +function core.register_on_placenode(f) end + +--[[ +WIPDOC +]] +---@alias core.fn.on_dignode fun(pos:ivec, oldnode:core.Node.get, digger:core.ObjectRef?) + +--[[ +* `core.register_on_dignode(function(pos, oldnode, digger))` + * Called after a node has been dug. + * **Not recommended**; Use `on_destruct` or `after_dig_node` in node + definition whenever possible. +]] +---@param f core.fn.on_dignode +---@return nil +function core.register_on_dignode(f) end + +--[[ +WIPDOC +]] +---@alias core.fn.on_punchnode fun(pos:ivec, node:core.Node.get, puncher:core.ObjectRef?, pointed_thing:core.PointedThing) + +--[[ +* `core.register_on_punchnode(function(pos, node, puncher, pointed_thing))` + * Called after a node is punched +]] +---@param f core.fn.on_punchnode +---@return nil +function core.register_on_punchnode(f) end + +--[[ +WIPDOC +]] +---@alias core.fn.on_generated fun(minp:ivec, maxp:ivec, blockseed:integer) + +--[[ +* `core.register_on_generated(function(minp, maxp, blockseed))` + * Called after a piece of world between `minp` and `maxp` has been + generated and written into the map. + * **Avoid using this** whenever possible. As with other callbacks this blocks + the main thread and is prone to introduce noticeable latency/lag. + Consider [Mapgen environment](#mapgen-environment) as an alternative. +]] +---@deprecated +---@param f core.fn.on_generated +function core.register_on_generated(f) end + +-- ------------------------------ player events ----------------------------- -- + +--[[ +WIPDOC +]] +---@alias core.fn.on_newplayer fun(ObjectRef:core.PlayerRef) + +--[[ +* `core.register_on_newplayer(function(player))` + * Called when a new player enters the world for the first time + * `player`: ObjectRef +]] +---@param f core.fn.on_newplayer +function core.register_on_newplayer(f) end + +--[[ +WIPDOC +]] +---@alias core.fn.on_punchplayer fun(player:core.PlayerRef, hitter:core.PlayerRef?, time_from_last_punch:number?, tool_capabilities:core.ToolCapabilities?, dir:vec, damage: integer):boolean? + +--[[ +* `core.register_on_punchplayer(function(player, hitter, time_from_last_punch, tool_capabilities, dir, damage))` + * Called when a player is punched + * Note: This callback is invoked even if the punched player is dead. + * `player`: ObjectRef - Player that was punched + * `hitter`: ObjectRef - Player that hit. Can be nil. + * `time_from_last_punch`: Meant for disallowing spamming of clicks + (can be nil). + * `tool_capabilities`: Capability table of used item (can be nil) + * `dir`: Unit vector of direction of punch. Always defined. Points from + the puncher to the punched. + * `damage`: Number that represents the damage calculated by the engine + * should return `true` to prevent the default damage mechanism +]] +---@param f core.fn.on_punchplayer +function core.register_on_punchplayer(f) end + +--[[ +WIPDOC +]] +---@alias core.fn.on_rightclickplayer fun(player:core.PlayerRef, clicker:core.PlayerRef) + +--[[ +* `core.register_on_rightclickplayer(function(player, clicker))` + * Called when the 'place/use' key was used while pointing a player + (not necessarily an actual rightclick) + * `player`: ObjectRef - Player that is acted upon + * `clicker`: ObjectRef - Object that acted upon `player`, may or may not be a player +]] +---@param f core.fn.on_rightclickplayer +function core.register_on_rightclickplayer(f) end + +--[[ core.register_on_player_hpchange() .. core.register_on_dieplayer() split off into ./hpchange.lua ]]-- + +--[[ +WIPDOC +]] +---@alias core.fn.on_respawnplayer fun(ObjectRef:core.PlayerRef):boolean? + +--[[ +WIPDOC +]] +---@param f core.fn.on_respawnplayer +function core.register_on_respawnplayer(f) end + +--[[ +WIPDOC +]] +---@alias core.fn.on_prejoinplayer fun(name:string, ip:string):string? + +--[[ +WIPDOC +]] +---@param f core.fn.on_prejoinplayer +function core.register_on_prejoinplayer(f) end + +--[[ +WIPDOC +]] +---@alias core.fn.on_joinplayer fun(ObjectRef:core.PlayerRef, last_login:integer) + +--[[ +WIPDOC +]] +---@param f core.fn.on_joinplayer +function core.register_on_joinplayer(f) end + +--[[ +WIPDOC +]] +---@alias core.fn.on_leaveplayer fun(ObjectRef:core.PlayerRef, timed_out:boolean) + +--[[ +WIPDOC +]] +---@param f core.fn.on_leaveplayer +function core.register_on_leaveplayer(f) end + +--[[ +WIPDOC +]] +---@alias core.fn.on_authplayer fun(name:string, ip:string, is_success:boolean) + +--[[ +* `core.register_on_authplayer(function(name, ip, is_success))` + * Called when a client attempts to log into an account. + * `name`: The name of the account being authenticated. + * `ip`: The IP address of the client + * `is_success`: Whether the client was successfully authenticated + * For newly registered accounts, `is_success` will always be true +]] +---@param f core.fn.on_authplayer +function core.register_on_authplayer(f) end + +--[[ +WIPDOC +]] +---@alias core.fn.on_auth_fail fun(name:string, ip:string) + +--[[ +* Deprecated: use `core.register_on_authplayer(name, ip, is_success)` instead. +]] +---@deprecated +---@param f core.fn.on_auth_fail +function core.register_on_auth_fail(f) end + +--[[ core.register_on_cheat() split into ./cheat.lua ]]-- + +--[[ core.register_playerevent() split into ./playerevent.lua ]]-- + +-- ---------------------------------- chat ---------------------------------- -- + +--[[ +WIPDOC +]] +---@alias core.fn.on_chat_message fun(name:string, message:string):boolean? + +--[[ +* `core.register_on_chat_message(function(name, message))` + * Called always when a player says something + * Return `true` to mark the message as handled, which means that it will + not be sent to other players. +]] +---@param f core.fn.on_chat_message +function core.register_on_chat_message(f) end + +--[[ +WIPDOC +]] +---@alias core.fn.on_chatcommand fun(name:string, command:string, params:string) + +--[[ +* `core.register_on_chatcommand(function(name, command, params))` + * Called always when a chatcommand is triggered, before `core.registered_chatcommands` + is checked to see if the command exists, but after the input is parsed. + * Return `true` to mark the command as handled, which means that the default + handlers will be prevented. +]] +---@param f core.fn.on_chatcommand +function core.register_on_chatcommand(f) end + +-- -------------------------------- formspec -------------------------------- -- + +--[[ core.register_on_player_receive_fields() split off into ./player_receive_fields.lua ]]-- + +--[[ +WIPDOC +]] +---@alias core.fn.on_craft fun(itemstack:core.ItemStack, player:core.PlayerRef, old_crafting_grid:core.Item.name[][], craft_inv:core.InvRef):core.ItemStack? + +--[[ +* `core.register_on_craft(function(itemstack, player, old_craft_grid, craft_inv))` + * Called when `player` crafts something + * `itemstack` is the output + * `old_craft_grid` contains the recipe (Note: the one in the inventory is + cleared). + * `craft_inv` is the inventory with the crafting grid + * Return either an `ItemStack`, to replace the output, or `nil`, to not + modify it. +]] +---@param f core.fn.on_craft +function core.register_on_craft(f) end + +--[[ +WIPDOC +]] +---@alias core.fn.craft_predict fun(itemstack:core.ItemStack, player:core.PlayerRef, old_crafting_grid:core.Item.name[][], craft_inv:core.InvRef):core.ItemStack? + +--[[ +* `core.register_craft_predict(function(itemstack, player, old_craft_grid, craft_inv))` + * The same as before, except that it is called before the player crafts, to + make craft prediction, and it should not change anything. +]] +---@param f core.fn.craft_predict +function core.register_craft_predict(f) end + +--[[ core.register_allow_player_inventory_action() .. core.register_on_player_inventory_action() split off into ./inventory_action.lua ]]-- + +-- ------------------------------- protection ------------------------------- -- + +--[[ +WIPDOC +]] +---@alias core.fn.on_protection_violation fun(pos:ivec, name:string) + +--[[ +* `core.register_on_protection_violation(function(pos, name))` + * Called by `builtin` and mods when a player violates protection at a + position (eg, digs a node or punches a protected entity). + * The registered functions can be called using + `core.record_protection_violation`. + * The provided function should check that the position is protected by the + mod calling this function before it prints a message, if it does, to + allow for multiple protection mods. +]] +---@param f core.fn.on_protection_violation +function core.register_on_protection_violation(f) end + +-- ------------------------------- item events ------------------------------ -- + +--[[ +WIPDOC +]] +---@alias core.fn.on_item_eat fun(hp_change:integer, replace_with_item:core.ItemStack?, itemstack:core.ItemStack, user:core.PlayerRef, pointed_thing:core.PointedThing):core.ItemStack? + +--[[ +* `core.register_on_item_eat(function(hp_change, replace_with_item, itemstack, user, pointed_thing))` + * Called when an item is eaten, by `core.item_eat` + * Return `itemstack` to cancel the default item eat response (i.e.: hp increase). +]] +---@param f core.fn.on_item_eat +function core.register_on_item_eat(f) end + +--[[ +WIPDOC +]] +---@alias core.fn.on_item_pickup fun(itemstack:core.ItemStack, picker:core.PlayerRef?, pointed_thing:core.PointedThing?, time_from_last_punch:number?, direction:vec?, damage:integer?):core.ItemStack? + +--[[ +* `core.register_on_item_pickup(function(itemstack, picker, pointed_thing, time_from_last_punch, ...))` + * Called by `core.item_pickup` before an item is picked up. + * Function is added to `core.registered_on_item_pickups`. + * Oldest functions are called first. + * Parameters are the same as in the `on_pickup` callback. + * Return an itemstack to cancel the default item pick-up response (i.e.: adding + the item into inventory). +]] +---@param f core.ItemDef.on_pickup +function core.register_on_item_pickup(f) end + +-- ------------------------------- privileges ------------------------------- -- + +--[[ +WIPDOC +]] +---@alias core.fn.on_priv_grant fun(name:string, granter:core.PlayerRef?, priv:core.PrivilegeSet.keys) + +--[[ +* `core.register_on_priv_grant(function(name, granter, priv))` + * Called when `granter` grants the priv `priv` to `name`. + * Note that the callback will be called twice if it's done by a player, + once with granter being the player name, and again with granter being nil. +]] +---@param f core.fn.on_priv_grant +function core.register_on_priv_grant(f) end + +--[[ +WIPDOC +]] +---@alias core.fn.on_priv_revoke fun(name:string, revoker:core.PlayerRef?, priv:core.PrivilegeSet.keys) + +--[[ +* `core.register_on_priv_revoke(function(name, revoker, priv))` + * Called when `revoker` revokes the priv `priv` from `name`. + * Note that the callback will be called twice if it's done by a player, + once with revoker being the player name, and again with revoker being nil. +]] +---@param f core.fn.on_priv_revoke +function core.register_on_priv_revoke(f) end + +-- -------------------------------------------------------------------------- -- + +--[[ +WIPDOC +]] +---@alias core.fn.can_bypass_userlimit fun(name:string, ip:string):boolean? + +--[[ +* `core.register_can_bypass_userlimit(function(name, ip))` + * Called when `name` user connects with `ip`. + * Return `true` to by pass the player limit +]] +---@param f core.fn.can_bypass_userlimit +function core.register_can_bypass_userlimit(f) end + +--[[ +WIPDOC +]] +---@alias core.fn.on_modchannel_message fun(channel_name:string, sender:string, message:string) + +--[[ +WIPDOC +]] +---@param f core.fn.on_modchannel_message +function core.register_on_modchannel_message(f) end + +-- ------------------------------- map events ------------------------------- -- + +--[[ +WIPDOC +]] +---@alias core.fn.on_liquid_transform fun(pos_list: ivec[], node_list: core.Node.get[]) + +--[[ +* `core.register_on_liquid_transformed(function(pos_list, node_list))` + * Called after liquid nodes (`liquidtype ~= "none"`) are modified by the + engine's liquid transformation process. + * `pos_list` is an array of all modified positions. + * `node_list` is an array of the old node that was previously at the position + with the corresponding index in pos_list. +]] +---@param f core.fn.on_liquid_transform +function core.register_on_liquid_transformed(f) end + +--[[ +WIPDOC +]] +---@alias core.fn.on_mapblocks_changed fun(modified_blocks:table, modified_block_count:integer) + +--[[ +* `core.register_on_mapblocks_changed(function(modified_blocks, modified_block_count))` + * Called soon after any nodes or node metadata have been modified. No + modifications will be missed, but there may be false positives. + * Will never be called more than once per server step. + * `modified_blocks` is the set of modified mapblock position hashes. These + are in the same format as those produced by `core.hash_node_position`, + and can be converted to positions with `core.get_position_from_hash`. + The set is a table where the keys are hashes and the values are `true`. + * `modified_block_count` is the number of entries in the set. + * Note: callbacks must be registered at mod load time. +]] +---@param f core.fn.on_mapblocks_changed +function core.register_on_mapblocks_changed(f) end diff --git a/types/luanti_lsp_definitions/library/core/register/hpchange.lua b/types/luanti_lsp_definitions/library/core/register/hpchange.lua new file mode 100644 index 00000000..40f24781 --- /dev/null +++ b/types/luanti_lsp_definitions/library/core/register/hpchange.lua @@ -0,0 +1,155 @@ +---@meta _ +-- DRAFT 1 DONE +-- luanti/doc/lua_api.md: 'core' namespace reference > Global callback registration functions + +-- -------------------------- PlayerHPChangeReason -------------------------- -- + +--[[ +WIPDOC +]] +---@alias core.PlayerHPChangeReason.regular.type +--- | "set_hp" +--- | "fall" +--- | "drown" +--- | "respawn" +--- | string + +--[[ +WIPDOC +]] +---@class core.PlayerHPChangeReason.regular : {[string]:any} +--[[ +WIPDOC +]] +---@field type core.PlayerHPChangeReason.regular.type +--[[ +WIPDOC +]] +---@field from "mod"|"engine" + +--[[ +WIPDOC +]] +---@class core.PlayerHPChangeReason.punch : core.PlayerHPChangeReason.regular +--[[ +WIPDOC +]] +---@field type "punch" +--[[ +WIPDOC +]] +---@field object core.ObjectRef? + +--[[ +WIPDOC +]] +---@class core.PlayerHPChangeReason.node_damage : core.PlayerHPChangeReason.regular +--[[ +WIPDOC +]] +---@field type "node_damage" +--[[ +WIPDOC +]] +---@field node core.Node.name? +--[[ +WIPDOC +]] +---@field node_pos vec? + +--[[ +WIPDOC +]] +---@alias core.PlayerHPChangeReason +--- | core.PlayerHPChangeReason.regular +--- | core.PlayerHPChangeReason.punch +--- | core.PlayerHPChangeReason.node_damage + +-- ---------------------------- core.* functions ---------------------------- -- + +--[[ +WIPDOC +]] +---@alias core.fn.on_player_hpchange.logger fun(player:core.PlayerRef, hp_change:integer, reason:core.PlayerHPChangeReason) + +--[[ +* `core.register_on_player_hpchange(function(player, hp_change, reason), modifier)` + * Called when the player gets damaged or healed + * When `hp == 0`, damage doesn't trigger this callback. + * When `hp == hp_max`, healing does still trigger this callback. + * `player`: ObjectRef of the player + * `hp_change`: the amount of change. Negative when it is damage. + * Historically, the new HP value was clamped to [0, 65535] before + calculating the HP change. This clamping has been removed as of + version 5.10.0 + * `reason`: a PlayerHPChangeReason table. + * The `type` field will have one of the following values: + * `set_hp`: A mod or the engine called `set_hp` without + giving a type - use this for custom damage types. + * `punch`: Was punched. `reason.object` will hold the puncher, or nil if none. + * `fall` + * `node_damage`: `damage_per_second` from a neighboring node. + `reason.node` will hold the node name or nil. + `reason.node_pos` will hold the position of the node + * `drown` + * `respawn` + * Any of the above types may have additional fields from mods. + * `reason.from` will be `mod` or `engine`. + * `modifier`: when true, the function should return the actual `hp_change`. + Note: modifiers only get a temporary `hp_change` that can be modified by later modifiers. + Modifiers can return true as a second argument to stop the execution of further functions. + Non-modifiers receive the final HP change calculated by the modifiers. +]] +---@param f core.fn.on_player_hpchange.logger +function core.register_on_player_hpchange(f) end + +--[[ +WIPDOC +]] +---@alias core.fn.on_player_hpchange.modifier fun(player:core.PlayerRef, hp_change:integer, reason:core.PlayerHPChangeReason):integer, boolean? + +--[[ +* `core.register_on_player_hpchange(function(player, hp_change, reason), modifier)` + * Called when the player gets damaged or healed + * When `hp == 0`, damage doesn't trigger this callback. + * When `hp == hp_max`, healing does still trigger this callback. + * `player`: ObjectRef of the player + * `hp_change`: the amount of change. Negative when it is damage. + * Historically, the new HP value was clamped to [0, 65535] before + calculating the HP change. This clamping has been removed as of + version 5.10.0 + * `reason`: a PlayerHPChangeReason table. + * The `type` field will have one of the following values: + * `set_hp`: A mod or the engine called `set_hp` without + giving a type - use this for custom damage types. + * `punch`: Was punched. `reason.object` will hold the puncher, or nil if none. + * `fall` + * `node_damage`: `damage_per_second` from a neighboring node. + `reason.node` will hold the node name or nil. + `reason.node_pos` will hold the position of the node + * `drown` + * `respawn` + * Any of the above types may have additional fields from mods. + * `reason.from` will be `mod` or `engine`. + * `modifier`: when true, the function should return the actual `hp_change`. + Note: modifiers only get a temporary `hp_change` that can be modified by later modifiers. + Modifiers can return true as a second argument to stop the execution of further functions. + Non-modifiers receive the final HP change calculated by the modifiers. +]] +---@param f core.fn.on_player_hpchange.modifier +---@param modifier true +function core.register_on_player_hpchange(f, modifier) end + +--[[ +WIPDOC +]] +---@alias core.fn.on_dieplayer fun(ObjectRef:core.PlayerRef, reason: core.PlayerHPChangeReason) + +--[[ +* `core.register_on_dieplayer(function(ObjectRef, reason))` + * Called when a player dies + * `reason`: a PlayerHPChangeReason table, see register_on_player_hpchange + * For customizing the death screen, see `core.show_death_screen`. +]] +---@param f core.fn.on_dieplayer +function core.register_on_dieplayer(f) end \ No newline at end of file diff --git a/types/luanti_lsp_definitions/library/core/register/inventory_action.lua b/types/luanti_lsp_definitions/library/core/register/inventory_action.lua new file mode 100644 index 00000000..e6ad2434 --- /dev/null +++ b/types/luanti_lsp_definitions/library/core/register/inventory_action.lua @@ -0,0 +1,114 @@ +---@meta _ +-- DRAFT 1 DONE +-- luanti/doc/lua_api.md: 'core' namespace reference > Global callback registration functions + +-- ------------------------------ InventoryInfo ----------------------------- -- + +--[[ +WIPDOC +]] +---@class core.InventoryInfo.move +--[[ +WIPDOC +]] +---@field from_list core.InventoryList +--[[ +WIPDOC +]] +---@field to_list core.InventoryList +--[[ +WIPDOC +]] +---@field from_index integer +--[[ +WIPDOC +]] +---@field to_index integer +--[[ +WIPDOC +]] +---@field count integer + + +--[[ +WIPDOC +]] +---@class core.InventoryInfo.put_or_take +--[[ +WIPDOC +]] +---@field listname core.InventoryList +--[[ +WIPDOC +]] +---@field index integer +--[[ +WIPDOC +]] +---@field stack core.ItemStack + +-- ---------------------------- core.* functions ---------------------------- -- + +--[[ +WIPDOC +]] +---@alias core.fn.allow_player_inventory_action.move fun(player:core.PlayerRef, action:"move", inventory:core.InvRef, inventory_info:core.InventoryInfo.move):integer + +--[[ +WIPDOC +]] +---@alias core.fn.allow_player_inventory_action.put fun(player:core.PlayerRef, action:"put", inventory:core.InvRef, inventory_info:core.InventoryInfo.put_or_take):integer + +--[[ +WIPDOC +]] +---@alias core.fn.allow_player_inventory_action.take fun(player:core.PlayerRef, action:"take", inventory:core.InvRef, inventory_info:core.InventoryInfo.put_or_take):integer + +--[[ +WIPDOC +]] +---@alias core.fn.allow_player_inventory_action +--- | core.fn.allow_player_inventory_action.move +--- | core.fn.allow_player_inventory_action.put +--- | core.fn.allow_player_inventory_action.take + +--[[ +* `core.register_allow_player_inventory_action(function(player, action, inventory, inventory_info))` + * Determines how much of a stack may be taken, put or moved to a + player inventory. + * Function arguments: see `core.register_on_player_inventory_action` + * Return a numeric value to limit the amount of items to be taken, put or + moved. A value of `-1` for `take` will make the source stack infinite. +]] +---@param f core.fn.allow_player_inventory_action +function core.register_allow_player_inventory_action(f) end + +--[[ +WIPDOC +]] +---@alias core.fn.on_player_inventory_action.move fun(player:core.PlayerRef, action:"move", inventory:core.InvRef, inventory_info:core.InventoryInfo.move) + +--[[ +WIPDOC +]] +---@alias core.fn.on_player_inventory_action.put fun(player:core.PlayerRef, action:"put", inventory:core.InvRef, inventory_info:core.InventoryInfo.put_or_take) + +--[[ +WIPDOC +]] +---@alias core.fn.on_player_inventory_action.take fun(player:core.PlayerRef, action:"take", inventory:core.InvRef, inventory_info:core.InventoryInfo.put_or_take) + +--[[ +WIPDOC +]] +---@alias core.fn.on_player_inventory_action +--- | core.fn.on_player_inventory_action.move +--- | core.fn.on_player_inventory_action.put +--- | core.fn.on_player_inventory_action.take + + +--[[ +WIPDOC +]] +---@param f core.fn.on_player_inventory_action +function core.register_on_player_inventory_action(f) end \ No newline at end of file diff --git a/types/luanti_lsp_definitions/library/core/register/player_receive_fields.lua b/types/luanti_lsp_definitions/library/core/register/player_receive_fields.lua new file mode 100644 index 00000000..69e62e96 --- /dev/null +++ b/types/luanti_lsp_definitions/library/core/register/player_receive_fields.lua @@ -0,0 +1,73 @@ +---@meta _ +-- DRAFT 1 DONE +-- luanti/doc/lua_api.md: 'core' namespace reference > Global callback registration functions + +--[[ +WIPDOC +]] +---@class core.FormspecFields : {[string]:string} +--[[ +WIPDOC +]] +---@field quit "true"? +--[[ +WIPDOC +]] +---@field try_quit "true"? +--[[ +WIPDOC +]] +---@field key_enter "true"? + +--[[ +WIPDOC +]] +---@alias core.fn.on_player_receive_fields fun(player:core.PlayerRef, formname:string, fields:core.FormspecFields):boolean? + +--[[ +* `core.register_on_player_receive_fields(function(player, formname, fields))` +* Called when the server received input from `player`. + Specifically, this is called on any of the + following events: + * a button was pressed, + * Enter was pressed while the focus was on a text field + * a checkbox was toggled, + * something was selected in a dropdown list, + * a different tab was selected, + * selection was changed in a textlist or table, + * an entry was double-clicked in a textlist or table, + * a scrollbar was moved, or + * the form was actively closed by the player. +* `formname` is the name passed to `core.show_formspec`. + Special case: The empty string refers to the player inventory + (the formspec set by the `set_inventory_formspec` player method). +* Fields are sent for formspec elements which define a field. `fields` + is a table containing each formspecs element value (as string), with + the `name` parameter as index for each. The value depends on the + formspec element type: + * `animated_image`: Returns the index of the current frame. + * `button` and variants: If pressed, contains the user-facing button + text as value. If not pressed, is `nil` + * `field`, `textarea` and variants: Text in the field + * `dropdown`: Either the index or value, depending on the `index event` + dropdown argument. + * `tabheader`: Tab index, starting with `"1"` (only if tab changed) + * `checkbox`: `"true"` if checked, `"false"` if unchecked + * `textlist`: See `core.explode_textlist_event` + * `table`: See `core.explode_table_event` + * `scrollbar`: See `core.explode_scrollbar_event` + * Special case: `["quit"]="true"` is sent when the user actively + closed the form by mouse click, keypress or through a `button_exit[]` + element. + * Special case: `["try_quit"]="true"` is sent when the user tries to + close the formspec, but the formspec used `allow_close[false]`. + * Special case: `["key_enter"]="true"` is sent when the user pressed + the Enter key and the focus was either nowhere (causing the formspec + to be closed) or on a button. If the focus was on a text field, + additionally, the index `key_enter_field` contains the name of the + text field. See also: `field_close_on_enter`. +* Newest functions are called first +* If function returns `true`, remaining functions are not called +]] +---@param f core.fn.on_player_receive_fields +function core.register_on_player_receive_fields(f) end \ No newline at end of file diff --git a/types/luanti_lsp_definitions/library/core/register/playerevent.lua b/types/luanti_lsp_definitions/library/core/register/playerevent.lua new file mode 100644 index 00000000..dedca24d --- /dev/null +++ b/types/luanti_lsp_definitions/library/core/register/playerevent.lua @@ -0,0 +1,28 @@ +---@meta _ +-- DRAFT 1 DONE +-- builtin/game/register.lua +-- src/script/cpp_api/s_env.cpp + +-- ------------------------------- PlayerEvent ------------------------------ -- + +--[[ +WIPDOC +]] +---@alias core.PlayerEvent +--- | "hud_changed" +--- | "properties_changed" +--- | "health_changed" +--- | "breath_changed" + +-- ---------------------------- core.* functions ---------------------------- -- + +--[[ +WIPDOC +]] +---@alias core.fn.playerevent fun(player:core.PlayerRef, event:core.PlayerEvent) + +--[[ +WIPDOC +]] +---@param f core.fn.playerevent +function core.register_playerevent(f) end \ No newline at end of file diff --git a/types/luanti_lsp_definitions/library/core/rollback.lua b/types/luanti_lsp_definitions/library/core/rollback.lua new file mode 100644 index 00000000..eb170c92 --- /dev/null +++ b/types/luanti_lsp_definitions/library/core/rollback.lua @@ -0,0 +1,54 @@ +---@meta _ +-- DRAFT 1 DONE +-- luanti/doc/lua_api.md: 'core' namespace reference > Rollback + +--[[ +WIPDOC +]] +---@class core.RollbackNodeAction +--[[ +WIPDOC +]] +---@field [1] string +--[[ +WIPDOC +]] +---@field [2] ivec +--[[ +WIPDOC +]] +---@field [3] number +--[[ +WIPDOC +]] +---@field [4] core.Node.get +--[[ +WIPDOC +]] +---@field [5] core.Node.get + +--[[ +* `core.rollback_get_node_actions(pos, range, seconds, limit)`: + returns `{{actor, pos, time, oldnode, newnode}, ...}` + * Find who has done something to a node, or near a node + * `actor`: `"player:"`, also `"liquid"`. +]] +---@nodiscard +---@param pos ivector +---@param range integer +---@param seconds number +---@param limit number +---@return core.RollbackNodeAction[] +function core.rollback_get_node_actions(pos, range, seconds, limit) end + +--[[ +* `core.rollback_revert_actions_by(actor, seconds)`: returns + `boolean, log_messages`. + * Revert latest actions of someone + * `actor`: `"player:"`, also `"liquid"`. +]] +---@nodiscard +---@param actor string|"liquid" +---@param seconds number +---@return boolean success, string[] log_messages +function core.rollback_revert_actions_by(actor, seconds) end \ No newline at end of file diff --git a/types/luanti_lsp_definitions/library/core/schematics.lua b/types/luanti_lsp_definitions/library/core/schematics.lua new file mode 100644 index 00000000..dbdd178d --- /dev/null +++ b/types/luanti_lsp_definitions/library/core/schematics.lua @@ -0,0 +1,168 @@ +---@meta _ +-- DRAFT 1 DONE +-- luanti/doc/lua_api.md: 'core' namespace reference > Schematics + +--[[ +WIPDOC +]] +---@class core.Schematic.probability_list +--[[ +WIPDOC +]] +---@field pos integer +--[[ +* A probability value of `0` or `1` means that node will never appear + (0% chance). +* A probability value of `254` or `255` means the node will always appear + (100% chance). +* If the probability value `p` is greater than `1`, then there is a + `(p / 256 * 100)` percent chance that node will appear when the schematic is + placed on the map. +]] +---@field prob integer + +--[[ +WIPDOC +]] +---@param p1 ivector +---@param p2 ivector +---@param probability_list core.Schematic.probability_list? +---@param filename core.Path +---@param slice_prob_list core.SchematicDef.yslice_prob? +function core.create_schematic(p1, p2, probability_list, filename, slice_prob_list) end + +--[[ +WIPDOC +]] +---@alias core.Schematic.rotation +--- | "0" +--- | "90" +--- | "180" +--- | "270" +--- | "random" + +--[[ +WIPDOC +]] +---@alias core.Schematic.replacements table + +--[[ +* `core.place_schematic(pos, schematic, rotation, replacements, force_placement, flags)` + * Place the schematic specified by schematic (see [Schematic specifier]) at + `pos`. + * `rotation` can equal `"0"`, `"90"`, `"180"`, `"270"`, or `"random"`. + * If the `rotation` parameter is omitted, the schematic is not rotated. + * `replacements` = `{["old_name"] = "convert_to", ...}` + * `force_placement` is a boolean indicating whether nodes other than `air` + and `ignore` are replaced by the schematic. + * Returns nil if the schematic could not be loaded. + * **Warning**: Once you have loaded a schematic from a file, it will be + cached. Future calls will always use the cached version and the + replacement list defined for it, regardless of whether the file or the + replacement list parameter have changed. The only way to load the file + anew is to restart the server. + * `flags` is a flag field with the available flags: + * place_center_x + * place_center_y + * place_center_z +]] +---@nodiscard +---@param pos ivector +---@param schematic core.Schematic +---@param rotation core.Schematic.rotation? +---@param replacements core.Schematic.replacements? +---@param force_placement boolean? +---@param flags core.Schematic.flags? +---@return boolean? +function core.place_schematic(pos, schematic, rotation, replacements, force_placement, flags) end + +--[[ +* `core.place_schematic_on_vmanip(vmanip, pos, schematic, rotation, replacement, force_placement, flags)`: + * This function is analogous to core.place_schematic, but places a + schematic onto the specified VoxelManip object `vmanip` instead of the + map. + * Returns false if any part of the schematic was cut-off due to the + VoxelManip not containing the full area required, and true if the whole + schematic was able to fit. + * Returns nil if the schematic could not be loaded. + * After execution, any external copies of the VoxelManip contents are + invalidated. + * `flags` is a flag field with the available flags: + * place_center_x + * place_center_y + * place_center_z +]] +---@nodiscard +---@param vmanip core.VoxelManip +---@param schematic core.Schematic +---@param rotation core.Schematic.rotation? +---@param replacements core.Schematic.replacements? +---@param force_placement boolean? +---@param flags core.Schematic.flags? +---@return boolean? +function core.place_schematic_on_vmanip(vmanip, pos, schematic, rotation, replacements, force_placement, flags) end + +--[[ +WIPDOC +]] +---@class core.SerializeSchematicOptions +--[[ +WIPDOC +]] +---@field lua_use_comments boolean? +--[[ +WIPDOC +]] +---@field lua_num_indent_spaces integer? + +--[[ +* `core.serialize_schematic(schematic, format, options)` + * Return the serialized schematic specified by schematic + (see [Schematic specifier]) + * in the `format` of either "mts" or "lua". + * "mts" - a string containing the binary MTS data used in the MTS file + format. + * "lua" - a string containing Lua code representing the schematic in table + format. + * `options` is a table containing the following optional parameters: + * If `lua_use_comments` is true and `format` is "lua", the Lua code + generated will have (X, Z) position comments for every X row + generated in the schematic data for easier reading. + * If `lua_num_indent_spaces` is a nonzero number and `format` is "lua", + the Lua code generated will use that number of spaces as indentation + instead of a tab character. +]] +---@nodiscard +---@param schematic core.Schematic +---@param format "mts"|"lua" +---@param options core.SerializeSchematicOptions? +---@return string +function core.serialize_schematic(schematic, format, options) end + +--[[ +WIPDOC +]] +---@class core.ReadSchematicOptions +--[[ +WIPDOC +]] +---@field write_yslice_prob "none"|"low"|"all"? + +--[[ +* `core.read_schematic(schematic, options)` + * Returns a Lua table representing the schematic (see: [Schematic specifier]) + * `schematic` is the schematic to read (see: [Schematic specifier]) + * `options` is a table containing the following optional parameters: + * `write_yslice_prob`: string value: + * `none`: no `write_yslice_prob` table is inserted, + * `low`: only probabilities that are not 254 or 255 are written in + the `write_yslice_prob` table, + * `all`: write all probabilities to the `write_yslice_prob` table. + * The default for this option is `all`. + * Any invalid value will be interpreted as `all`. +]] +---@nodiscard +---@param schematic core.Schematic +---@param options core.ReadSchematicOptions +---@return core.SchematicDef? +function core.read_schematic(schematic, options) end \ No newline at end of file diff --git a/types/luanti_lsp_definitions/library/core/server/dynamic_media.lua b/types/luanti_lsp_definitions/library/core/server/dynamic_media.lua new file mode 100644 index 00000000..3185d784 --- /dev/null +++ b/types/luanti_lsp_definitions/library/core/server/dynamic_media.lua @@ -0,0 +1,69 @@ +---@meta _ +-- DRAFT 1 DONE +-- luanti/doc/lua_api.md: 'core' namespace reference > Server + +-- --------------------------- DynamicMediaOptions -------------------------- -- + +--[[ +WIPDOC +]] +---@class _.DynamicMediaOptions.__base +--[[ +WIPDOC +]] +---@field to_player string? +--[[ +WIPDOC +]] +---@field ephemeral boolean? +--[[ +WIPDOC +]] +---@field client_cache boolean? + +--[[ +WIPDOC +]] +---@class core.DynamicMediaOptions.filepath : _.DynamicMediaOptions.__base +--[[ +WIPDOC +]] +---@field filename string? +--[[ +WIPDOC +]] +---@field filepath core.Path + +--[[ +WIPDOC +]] +---@class core.DynamicMediaOptions.filedata : _.DynamicMediaOptions.__base +--[[ +WIPDOC +]] +---@field filename string +--[[ +WIPDOC +]] +---@field filedata string + +--[[ +WIPDOC +]] +---@alias core.DynamicMediaOptions +--- | core.DynamicMediaOptions.filepath +--- | core.DynamicMediaOptions.filedata + +-- ---------------------------- core.* functions ---------------------------- -- + +--[[ +WIPDOC +]] +---@alias core.fn.dynamic_add_media fun(name:string):boolean + +--[[ +WIPDOC +]] +---@param options core.DynamicMediaOptions +---@param callback core.fn.dynamic_add_media +function core.dynamic_add_media(options, callback) end \ No newline at end of file diff --git a/types/luanti_lsp_definitions/library/core/server/server.lua b/types/luanti_lsp_definitions/library/core/server/server.lua new file mode 100644 index 00000000..7431343a --- /dev/null +++ b/types/luanti_lsp_definitions/library/core/server/server.lua @@ -0,0 +1,76 @@ +---@meta _ +-- DRAFT 1 DONE +-- luanti/doc/lua_api.md: 'core' namespace reference > Server + +--[[ +* `core.request_shutdown([message],[reconnect],[delay])`: request for + server shutdown. Will display `message` to clients. + * `reconnect` == true displays a reconnect button + * `delay` adds an optional delay (in seconds) before shutdown. + Negative delay cancels the current active shutdown. + Zero delay triggers an immediate shutdown. +]] +---@param message string? +---@param reconnect boolean? +---@param delay number? +function core.request_shutdown(message, reconnect, delay) end + +--[[ +* `core.cancel_shutdown_requests()`: cancel current delayed shutdown +]] +function core.cancel_shutdown_requests() end + +--[[ +Unofficial note: This is really cool i didn't know this +* `core.get_server_status(name, joined)` + * Returns the server status string when a player joins or when the command + `/status` is called. Returns `nil` or an empty string when the message is + disabled. + * `joined`: Boolean value, indicates whether the function was called when + a player joined. + * This function may be overwritten by mods to customize the status message. +]] +---@nodiscard +---@param name string +---@param joined boolean +---@return string? +function core.get_server_status(name, joined) end + +--[[ +* `core.get_server_uptime()`: returns the server uptime in seconds +]] +---@nodiscard +---@return number +function core.get_server_uptime() end + +--[[ +* `core.get_server_max_lag()`: returns the current maximum lag + of the server in seconds or nil if server is not fully loaded yet +]] +---@nodiscard +---@return number? +function core.get_server_max_lag() end + +--[[ +* `core.remove_player(name)`: remove player from database (if they are not + connected). + * As auth data is not removed, `core.player_exists` will continue to + return true. Call the below method as well if you want to remove auth + data too. + * Returns a code (0: successful, 1: no such player, 2: player is connected) +]] +---@nodiscard +---@param name string +---@return 0|1|2 +function core.remove_player(name) end + +--[[ +* `core.remove_player_auth(name)`: remove player authentication data + * Returns boolean indicating success (false if player nonexistent) +]] +---@nodiscard +---@param name string +---@return boolean success +function core.remove_player_auth(name) end + +--[[ core.dynamic_add_media() split off into dynamic_media.lua ]]-- \ No newline at end of file diff --git a/types/luanti_lsp_definitions/library/core/settings.lua b/types/luanti_lsp_definitions/library/core/settings.lua new file mode 100644 index 00000000..eeeadd5d --- /dev/null +++ b/types/luanti_lsp_definitions/library/core/settings.lua @@ -0,0 +1,14 @@ +---@meta _ +-- DRAFT 1 DONE +-- luanti/doc/lua_api.md: 'core' namespace reference > Setting-related + +--[[ core.settings split off into library/classes/Settings/LuantiSettings.lua ]]-- + +--[[ +WIPDOC +]] +---@nodiscard +---@deprecated +---@param name core.LuantiSettings.keys.vector +---@return vec? +function core.setting_get_pos(name) end \ No newline at end of file diff --git a/types/luanti_lsp_definitions/library/core/sounds.lua b/types/luanti_lsp_definitions/library/core/sounds.lua new file mode 100644 index 00000000..ef6f67f1 --- /dev/null +++ b/types/luanti_lsp_definitions/library/core/sounds.lua @@ -0,0 +1,48 @@ +---@meta _ +-- DRAFT 1 DONE +-- luanti/doc/lua_api.md: 'core' namespace reference > Sounds + +--[[ +WIPDOC +]] +---@class core.SoundID : integer + +--[[ +Unofficial note: i made ephemeral NOT be optional because it's a good idea to explicitly set it (most of the time you don't use that, so set it to true) +* `core.sound_play(spec, parameters, [ephemeral])`: returns a handle + * `spec` is a `SimpleSoundSpec` + * `parameters` is a sound parameter table + * `ephemeral` is a boolean (default: false) + Ephemeral sounds will not return a handle and can't be stopped or faded. + It is recommend to use this for short sounds that happen in response to + player actions (e.g. door closing). +]] +---@nodiscard +---@param spec core.SimpleSoundSpec +---@param parameters core.SoundParamter +---@param ephemeral boolean? +---@return core.SoundID? +function core.sound_play(spec, parameters, ephemeral) end + +--[[ +* `core.sound_stop(handle)` + * `handle` is a handle returned by `core.sound_play` +]] +---@param handle core.SoundID +function core.sound_stop(handle) end + +--[[ +* `core.sound_fade(handle, step, gain)` + * `handle` is a handle returned by `core.sound_play` + * `step` determines how fast a sound will fade. + The gain will change by this much per second, + until it reaches the target gain. + Note: Older versions used a signed step. This is deprecated, but old + code will still work. (the client uses abs(step) to correct it) + * `gain` the target gain for the fade. + Fading to zero will delete the sound. +]] +---@param handle core.SoundID +---@param step number +---@param gain number +function core.sound_fade(handle, step, gain) end \ No newline at end of file diff --git a/types/luanti_lsp_definitions/library/core/timing.lua b/types/luanti_lsp_definitions/library/core/timing.lua new file mode 100644 index 00000000..bf585a5f --- /dev/null +++ b/types/luanti_lsp_definitions/library/core/timing.lua @@ -0,0 +1,32 @@ +---@meta _ +-- DRAFT 1 DONE +-- luanti/doc/lua_api.md: 'core' namespace reference > Timing + +--[[ +WIPDOC +]] +---@class core.Job +--[[ +* `job:cancel()` + * Cancels the job function from being called +]] +---@field cancel fun() + +--[[ +* `core.after(time, func, ...)`: returns job table to use as below. + * Call the function `func` after `time` seconds, may be fractional + * Optional: Variable number of arguments that are passed to `func` + * Jobs set for earlier times are executed earlier. If multiple jobs expire + at exactly the same time, then they are executed in registration order. + * `time` is a lower bound. The job is executed in the first server-step that + started at least `time` seconds after the last time a server-step started, + measured with globalstep dtime. + * If `time` is `0`, the job is executed in the next step. +]] +---@nodiscard +---@param time number +---@param f function +---@param ... any +---@return core.Job +function core.after(time, f, ...) end + diff --git a/types/luanti_lsp_definitions/library/core/translations.lua b/types/luanti_lsp_definitions/library/core/translations.lua new file mode 100644 index 00000000..132fa488 --- /dev/null +++ b/types/luanti_lsp_definitions/library/core/translations.lua @@ -0,0 +1,87 @@ +---@meta _ +-- DRAFT 1 DONE +-- luanti/doc/lua_api.md: Translations + +--[[ +WIPDOC +]] +---@alias core.fn.translate_singular fun(str:string, ...:string):string + +--[[ +WIPDOC +]] +---@alias core.fn.translate_plural fun(str:string, str_plural:string, n:integer, ...:string):string + +--[[ +`core.get_translator(textdomain)` is a simple wrapper around +`core.translate` and `core.translate_n`. +After `local S, PS = core.get_translator(textdomain)`, we have +`S(str, ...)` equivalent to `core.translate(textdomain, str, ...)`, and +`PS(str, str_plural, n, ...)` to `core.translate_n(textdomain, str, str_plural, n, ...)`. +It is intended to be used in the following way, so that it avoids verbose +repetitions of `core.translate`: + +```lua +local S, PS = core.get_translator(textdomain) +S(str, ...) +``` + +As an extra commodity, if `textdomain` is nil, it is assumed to be "" instead. +]] +---@nodiscard +---@param textdomain string? +---@return core.fn.translate_singular S, core.fn.translate_plural PS +function core.get_translator(textdomain) end + +--[[ +* `core.translate(textdomain, str, ...)` translates the string `str` with + the given `textdomain` for disambiguation. The textdomain must match the + textdomain specified in the translation file in order to get the string + translated. This can be used so that a string is translated differently in + different contexts. + It is advised to use the name of the mod as textdomain whenever possible, to + avoid clashes with other mods. + This function must be given a number of arguments equal to the number of + arguments the translated string expects. + Arguments are literal strings -- they will not be translated. +]] +---@nodiscard +---@param textdomain string +---@param str string +---@param ... string +---@return string +function core.translate(textdomain, str, ...) end + +--[[ +WIPDOC +]] +---@nodiscard +---@param textdomain string +---@param str string +---@param str_plural string +---@param n integer +---@param ... string +---@return string +function core.translate_n(textdomain, str, str_plural, n, ...) end + +--[[ +On some specific cases, server translation could be useful. For example, filter +a list on labels and send results to client. A method is supplied to achieve +that: + +`core.get_translated_string(lang_code, string)`: resolves translations in +the given string just like the client would, using the translation files for +`lang_code`. For this to have any effect, the string needs to contain translation +markup, e.g. `core.get_translated_string("fr", S("Hello"))`. + +The `lang_code` to use for a given player can be retrieved from +the table returned by `core.get_player_information(name)`. + +IMPORTANT: This functionality should only be used for sorting, filtering or similar purposes. +You do not need to use this to get translated strings to show up on the client. +]] +---@nodiscard +---@param lang_code core.LuantiSettings.enums.language +---@param str string +---@return string +function core.get_translated_string(lang_code, str) end \ No newline at end of file diff --git a/types/luanti_lsp_definitions/library/core/utilities/dig_params.lua b/types/luanti_lsp_definitions/library/core/utilities/dig_params.lua new file mode 100644 index 00000000..c0e9b6f0 --- /dev/null +++ b/types/luanti_lsp_definitions/library/core/utilities/dig_params.lua @@ -0,0 +1,54 @@ +---@meta _ +-- DRAFT 1 DONE +-- luanti/doc/lua_api.md: Helper functions + +--[[ +WIPDOC +]] +---@class core.DigParams.not_diggable +--[[ +WIPDOC +]] +---@field diggable false + +--[[ +WIPDOC +]] +---@class core.DigParams.item.diggable +--[[ +WIPDOC +]] +---@field diggable true +--[[ +WIPDOC +]] +---@field time number + +--[[ +WIPDOC +]] +---@class core.DigParams.tool.diggable : core.DigParams.item.diggable +--[[ +WIPDOC +]] +---@field wear core.Tool.wear + +--[[ +WIPDOC +]] +---@alias core.DigParams +--- | core.DigParams.not_diggable +--- | core.DigParams.item.diggable +--- | core.DigParams.tool.diggable + +-- ---------------------------- core.* functions ---------------------------- -- + +--[[ +WIPDOC +]] +---@nodiscard +---@param groups core.Groups.node +---@param tool_capabilities core.ToolCapabilities +---@param wear core.Tool.wear? +---@return core.DigParams +function core.get_dig_params(groups, tool_capabilities, wear) end \ No newline at end of file diff --git a/types/luanti_lsp_definitions/library/core/utilities/engine_version.lua b/types/luanti_lsp_definitions/library/core/utilities/engine_version.lua new file mode 100644 index 00000000..c3cef625 --- /dev/null +++ b/types/luanti_lsp_definitions/library/core/utilities/engine_version.lua @@ -0,0 +1,48 @@ +---@meta _ +-- DRAFT 1 DONE +-- luanti/doc/lua_api.md: 'core' namespace reference > Utilities + +-- ------------------------------ EngineVersion ----------------------------- -- + +--[[ +Use this for informational purposes only. The information in the returned + table does not represent the capabilities of the engine, nor is it + reliable or verifiable. Compatible forks will have a different name and + version entirely. To check for the presence of engine features, test + whether the functions exported by the wanted features exist. For example: + `if core.check_for_falling then ... end`. +]] +---@class core.EngineVersion +--[[ +Name of the project, eg, "Luanti" +]] +---@field project "Luanti"|string +--[[ +Simple version, eg, "1.2.3-dev" +]] +---@field string string +--[[ +The minimum supported protocol version +]] +---@field proto_min core.Protocol +--[[ +The maximum supported protocol version +]] +---@field proto_max core.Protocol +--[[ +Full git version (only set if available), eg, "1.2.3-dev-01234567-dirty". +]] +---@field hash string +--[[ +Boolean value indicating whether it's a development build +]] +---@field is_dev boolean + +-- ---------------------------- core.* functions ---------------------------- -- + +--[[ +WIPDOC +]] +---@nodiscard +---@return core.EngineVersion +function core.get_version() end \ No newline at end of file diff --git a/types/luanti_lsp_definitions/library/core/utilities/features.lua b/types/luanti_lsp_definitions/library/core/utilities/features.lua new file mode 100644 index 00000000..3b998aae --- /dev/null +++ b/types/luanti_lsp_definitions/library/core/utilities/features.lua @@ -0,0 +1,314 @@ +---@meta _ +-- DRAFT 1 DONE +-- luanti/doc/lua_api.md: 'core' namespace reference > Utilities + +-- ---------------------------- core.FeatureFlags --------------------------- -- + +--[[ +WIPDOC +]] +---@alias core.FeatureFlags.keys +--- | "glasslike_framed" +--- | "nodebox_as_selectionbox" +--- | "get_all_craft_recipes_works" +--- | "use_texture_alpha" +--- | "no_legacy_abms" +--- | "texture_names_parens" +--- | "area_store_custom_ids" +--- | "add_entity_with_staticdata" +--- | "no_chat_message_prediction" +--- | "object_use_texture_alpha" +--- | "object_independent_selectionbox" +--- | "httpfetch_binary_data" +--- | "formspec_version_element" +--- | "area_store_persistent_ids" +--- | "pathfinder_works" +--- | "object_step_has_moveresult" +--- | "direct_velocity_on_players" +--- | "use_texture_alpha_string_modes" +--- | "degrotate_240_steps" +--- | "abm_min_max_y" +--- | "dynamic_add_media_table" +--- | "particlespawner_tweenable" +--- | "get_sky_as_table" +--- | "get_light_data_buffer" +--- | "mod_storage_on_disk" +--- | "compress_zstd" +--- | "sound_params_start_time" +--- | "physics_overrides_v2" +--- | "hud_def_type_field" +--- | "random_state_restore" +--- | "after_order_expiry_registration" +--- | "wallmounted_rotate" +--- | "item_specific_pointabilities" +--- | "blocking_pointability_type" +--- | "dynamic_add_media_startup" +--- | "dynamic_add_media_filepath" +--- | "lsystem_decoration_type" +--- | "item_meta_range" +--- | "node_interaction_actor" +--- | "moveresult_new_pos" +--- | "override_item_remove_fields" +--- | "hotbar_hud_element" +--- | "bulk_lbms" +--- | "abm_without_neighbors" +--- | "biome_weights" +--- | "particle_blend_clip" +--- | "remove_item_match_meta" +--- | "httpfetch_additional_methods" +--- | "object_guids" +--- | "on_timer_four_args" +--- | "particlespawner_exclude_player" +--- | "generate_decorations_biomes" + +--[[ +WIPDOC +]] +---@class core.FeatureFlags +core.features = {} + +---@class core.FeatureFlags +--[[ +0.4.7 +]] +---@field glasslike_framed boolean? +--[[ +0.4.7 +]] +---@field nodebox_as_selectionbox boolean? +--[[ +0.4.7 +]] +---@field get_all_craft_recipes_works boolean? +--[[ +The transparency channel of textures can optionally be used on +nodes (0.4.7) +]] +---@field use_texture_alpha boolean? +--[[ +Tree and grass ABMs are no longer done from C++ (0.4.8) +]] +---@field no_legacy_abms boolean? +--[[ +Texture grouping is possible using parentheses (0.4.11) +]] +---@field texture_names_parens boolean? +--[[ +Unique Area ID for AreaStoreinsert_area (0.4.14) +]] +---@field area_store_custom_ids boolean? +--[[ +add_entity supports passing initial staticdata to on_activate +-- (0.4.16) +]] +---@field add_entity_with_staticdata boolean? +--[[ +Chat messages are no longer predicted (0.4.16) +]] +---@field no_chat_message_prediction boolean? +--[[ +The transparency channel of textures can optionally be used on +objects (ie players and lua entities) (5.0.0) +]] +---@field object_use_texture_alpha boolean? +--[[ +Object selectionbox is settable independently from collisionbox +(5.0.0) +]] +---@field object_independent_selectionbox boolean? +--[[ +SpeeldQcifies whether binary data can be uploaded or downloaded using +the HTTP API (5.1.0) +]] +---@field httpfetch_binary_data boolean? +--[[ +Whether formspec_version[] may be used (5.1.0) +]] +---@field formspec_version_element boolean? +--[[ +Whether AreaStore's IDs are kept on save/load (5.1.0) +]] +---@field area_store_persistent_ids boolean? +--[[ +Whether core.find_path is functional (5.2.0) +]] +---@field pathfinder_works boolean? +--[[ +Whether Collision info is available to an objects' on_step (5.3.0) +]] +---@field object_step_has_moveresult boolean? +--[[ +Whether get_velocity() and add_velocity() can be used on players (5.4.0) +]] +---@field direct_velocity_on_players boolean? +--[[ +nodedef's use_texture_alpha accepts new string modes (5.4.0) +]] +---@field use_texture_alpha_string_modes boolean? +--[[ +degrotate param2 rotates in units of 1.5° instead of 2° +thus changing the range of values from 0-179 to 0-240 (5.5.0) +]] +---@field degrotate_240_steps boolean? +--[[ +ABM supports min_y and max_y fields in definition (5.5.0) +]] +---@field abm_min_max_y boolean? +--[[ +dynamic_add_media supports passing a table with options (5.5.0) +]] +---@field dynamic_add_media_table boolean? +--[[ +particlespawners support texpools and animation of properties, +particle textures support smooth fade and scale animations, and +sprite-sheet particle animations can by synced to the lifetime +of individual particles (5.6.0) +]] +---@field particlespawner_tweenable boolean? +--[[ +allows get_sky to return a table instead of separate values (5.6.0) +]] +---@field get_sky_as_table boolean? +--[[ +VoxelManipget_light_data accepts an optional buffer argument (5.7.0) +]] +---@field get_light_data_buffer boolean? +--[[ +When using a mod storage backend that is not "files" or "dummy", +the amount of data in mod storage is not constrained by +the amount of RAM available. (5.7.0) +]] +---@field mod_storage_on_disk boolean? +--[[ +"zstd" method for compress/decompress (5.7.0) +]] +---@field compress_zstd boolean? +--[[ +Sound parameter tables support start_time (5.8.0) +]] +---@field sound_params_start_time boolean? +--[[ +New fields for set_physics_override speed_climb, speed_crouch, +liquid_fluidity, liquid_fluidity_smooth, liquid_sink, +acceleration_default, acceleration_air (5.8.0) +]] +---@field physics_overrides_v2 boolean? +--[[ +In HUD definitions the field `type` is used and `hud_elem_type` is deprecated (5.9.0) +]] +---@field hud_def_type_field boolean? +--[[ +PseudoRandom and PcgRandom state is restorable +PseudoRandom has get_state method +PcgRandom has get_state and set_state methods (5.9.0) +]] +---@field random_state_restore boolean? +--[[ +core.after guarantees that coexisting jobs are executed primarily +in order of expiry and secondarily in order of registration (5.9.0) +]] +---@field after_order_expiry_registration boolean? +--[[ +wallmounted nodes mounted at floor or ceiling may additionally +be rotated by 90° with special param2 values (5.9.0) +]] +---@field wallmounted_rotate boolean? +--[[ +Availability of the `pointabilities` property in the item definition (5.9.0) +]] +---@field item_specific_pointabilities boolean? +--[[ +Nodes `pointable` property can be `"blocking"` (5.9.0) +]] +---@field blocking_pointability_type boolean? +--[[ +dynamic_add_media can be called at startup when leaving callback as `nil` (5.9.0) +]] +---@field dynamic_add_media_startup boolean? +--[[ +dynamic_add_media supports `filename` and `filedata` parameters (5.9.0) +]] +---@field dynamic_add_media_filepath boolean? +--[[ +L-system decoration type (5.9.0) +]] +---@field lsystem_decoration_type boolean? +--[[ +Overridable pointing range using the itemstack meta key `"range"` (5.9.0) +]] +---@field item_meta_range boolean? +--[[ +Allow passing an optional "actor" ObjectRef to the following functions +core.place_node, core.dig_node, core.punch_node (5.9.0) +]] +---@field node_interaction_actor boolean? +--[[ +"new_pos" field in entity moveresult (5.9.0) +]] +---@field moveresult_new_pos boolean? +--[[ +Allow removing definition fields in `core.override_item` (5.9.0) +]] +---@field override_item_remove_fields boolean? +--[[ +The predefined hotbar is a Lua HUD element of type `hotbar` (5.10.0) +]] +---@field hotbar_hud_element boolean? +--[[ +Bulk LBM support (5.10.0) +]] +---@field bulk_lbms boolean? +--[[ +ABM supports field without_neighbors (5.10.0) +]] +---@field abm_without_neighbors boolean? +--[[ +biomes have a weight parameter (5.11.0) +]] +---@field biome_weights boolean? +--[[ +Particles can specify a "clip" blend mode (5.11.0) +]] +---@field particle_blend_clip boolean? +--[[ +The `match_meta` optional parameter is available for `InvRefremove_item()` (5.12.0) +]] +---@field remove_item_match_meta boolean? +--[[ +The HTTP API supports the HEAD and PATCH methods (5.12.0) +]] +---@field httpfetch_additional_methods boolean? +--[[ +WIPDOC +]] +---@field object_guids boolean? +--[[ +The NodeTimer `on_timer` callback is passed additional `node` and `timeout` args (5.14.0) +]] +---@field on_timer_four_args boolean? +--[[ +`ParticleSpawner` definition supports `exclude_player` field (5.14.0) +]] +---@field particlespawner_exclude_player boolean? +--[[ +core.generate_decorations() supports `use_mapgen_biomes` parameter (5.14.0) +]] +---@field generate_decorations_biomes boolean? + +-- ---------------------------- core.* functions ---------------------------- -- + +--[[ +WIPDOC +]] +---@nodiscard +---@param arg core.FeatureFlags +---@return boolean, {}? missing_features +function core.has_feature(arg) end + +--[[ +WIPDOC +]] +---@nodiscard +---@param arg core.FeatureFlags[] +---@return boolean, core.FeatureFlags missing_features +function core.has_feature(arg) end \ No newline at end of file diff --git a/types/luanti_lsp_definitions/library/core/utilities/game_info.lua b/types/luanti_lsp_definitions/library/core/utilities/game_info.lua new file mode 100644 index 00000000..0989e73b --- /dev/null +++ b/types/luanti_lsp_definitions/library/core/utilities/game_info.lua @@ -0,0 +1,35 @@ +---@meta _ +-- DRAFT 1 DONE +-- luanti/doc/lua_api.md: 'core' namespace reference > Utilities + +-- -------------------------------- GameInfo -------------------------------- -- + +--[[ +WIPDOC +]] +---@class core.GameInfo +--[[ +WIPDOC +]] +---@field id string +--[[ +WIPDOC +]] +---@field title string +--[[ +WIPDOC +]] +---@field author string +--[[ +WIPDOC +]] +---@field path core.Path + +-- ---------------------------- core.* functions ---------------------------- -- + +--[[ +Unofficial: Path is the root directory of the game, useful if you are looking for it +]] +---@nodiscard +---@return core.GameInfo +function core.get_game_info() end \ No newline at end of file diff --git a/types/luanti_lsp_definitions/library/core/utilities/helpers.lua b/types/luanti_lsp_definitions/library/core/utilities/helpers.lua new file mode 100644 index 00000000..63bbeac9 --- /dev/null +++ b/types/luanti_lsp_definitions/library/core/utilities/helpers.lua @@ -0,0 +1,102 @@ +---@meta _ +-- DRAFT 1 DONE +-- luanti/doc/lua_api.md: Helper functions + +-- NOTE: helpers not under core.* are in library/helpers.lua + +--[[ +WIPDOC +]] +---@nodiscard +---@param str string +---@param limit integer +---@param as_table boolean? +---@return string +function core.wrap_text(str, limit, as_table) end + +--[[ +WIPDOC +]] +---@nodiscard +---@param pos vector +---@param decimal_places integer? +---@return string +function core.pos_to_string(pos, decimal_places) end + +--[[ +WIPDOC +]] +---@nodiscard +---@param string string +---@return vec +function core.string_to_pos(string) end + +--[[ +returns two positions +Converts a string representing an area box into two positions +X1, Y1, ... Z2 are coordinates +relative_to: Optional. If set to a position, each coordinate can use the tilde notation for relative positions +"~": Relative coordinate +"~": Relative coordinate plus +Example: core.string_to_area("(1,2,3) (~5,~-5,~)", {x=10,y=10,z=10}) returns {x=1,y=2,z=3}, {x=15,y=5,z=10} +]] +---@nodiscard +---@param str string (X1, Y1, Z1) (X2, Y2, Z2) +---@param relative_to vector? +---@return vec?, vec? +function core.string_to_area(str, relative_to) end + +--[[ +escapes the characters "[", "]", "", "," and ";", which cannot be used in formspecs. +]] +---@nodiscard +---@param string string +---@return string +function core.formspec_escape(string) end + +--[[ +WIPDOC +]] +---@nodiscard +---@param arg string|number|boolean +---@return boolean +function core.is_yes(arg) end + +--[[ +WIPDOC +]] +---@nodiscard +---@param arg number +---@return boolean +function core.is_nan(arg) end + +--[[ +returns time with microsecond precision. May not return wall time. +Unofficial note: I think you should use os.clock() for benchmarking instead +]] +---@nodiscard +---@return integer +function core.get_us_time() end + +--[[ after table.* intermission ]]-- + +--[[ +WIPDOC +]] +---@nodiscard +---@param placer core.ObjectRef +---@param pointed_thing core.PointedThing +---@return vec +function core.pointed_thing_to_face_pos(placer, pointed_thing) end + +--[[ +WIPDOC +]] +---@param uses integer +---@param initial_wear core.Tool.wear? +---@return core.Tool.wear +function core.get_tool_wear_after_use(uses, initial_wear) end + +--[[ core.get_dig_params() split off into ./dig_params.lua ]]-- + +--[[ core.get_hit_params() split off into ./hit_params.lua ]]-- \ No newline at end of file diff --git a/types/luanti_lsp_definitions/library/core/utilities/hit_params.lua b/types/luanti_lsp_definitions/library/core/utilities/hit_params.lua new file mode 100644 index 00000000..f1a6fbec --- /dev/null +++ b/types/luanti_lsp_definitions/library/core/utilities/hit_params.lua @@ -0,0 +1,41 @@ +---@meta _ +-- DRAFT 1 DONE +-- luanti/doc/lua_api.md: Helper functions + +--[[ +WIPDOC +]] +---@class core.HitParams.item +--[[ +WIPDOC +]] +---@field hp integer + +--[[ +WIPDOC +]] +---@class core.HitParams.tool : core.HitParams.item +--[[ +WIPDOC +]] +---@field wear core.Tool.wear + +--[[ +WIPDOC +]] +---@alias core.HitParams +--- | core.HitParams.item +--- | core.HitParams.tool + +-- ---------------------------- core.* functions ---------------------------- -- + +--[[ +WIPDOC +]] +---@nodiscard +---@param groups core.Groups.armor +---@param tool_capabilities core.ToolCapabilities +---@param time_from_last_punch number? +---@param wear core.Tool.wear? +---@return core.HitParams +function core.get_hit_params(groups, tool_capabilities, time_from_last_punch, wear) end \ No newline at end of file diff --git a/types/luanti_lsp_definitions/library/core/utilities/player_information.lua b/types/luanti_lsp_definitions/library/core/utilities/player_information.lua new file mode 100644 index 00000000..8850fbf8 --- /dev/null +++ b/types/luanti_lsp_definitions/library/core/utilities/player_information.lua @@ -0,0 +1,131 @@ +---@meta _ +-- DRAFT 1 DONE +-- luanti/doc/lua_api.md: 'core' namespace reference > Utilities + +-- ----------------------------- core.PlayerInfo ---------------------------- -- + +--[[ +WIPDOC +]] +---@class core.PlayerInfo +--[[ +IP address of client +]] +---@field address string +--[[ +IPv4 / IPv6 +]] +---@field ip_version 4|6 +--[[ +seconds since client connected +]] +---@field connection_uptime number +--[[ +protocol version used by client +]] +---@field protocol_version core.Protocol +--[[ +supported formspec version +]] +---@field formspec_version integer +--[[ +Language code used for translation +]] +---@field lang_code core.LuantiSettings.enums.language +--[[ +minimum round trip time +]] +---@field min_rtt number? +--[[ +maximum round trip time +]] +---@field max_rtt number? +--[[ +average round trip time +]] +---@field avg_rtt number? +--[[ +minimum packet time jitter +]] +---@field min_jitter number? +--[[ +maximum packet time jitter +]] +---@field max_jitter number? +--[[ +average packet time jitter +]] +---@field avg_jitter number? +--[[ +The version information is provided by the client and may be spoofed +or inconsistent in engine forks. You must not use this for checking +feature availability of clients. Instead, do use the fields +`protocol_version` and `formspec_version` where it matters. +Use `core.protocol_versions` to map Luanti versions to protocol versions. +This version string is only suitable for analysis purposes. +full version string +]] +---@field version_string string + +-- ---------------------------- PlayerWindowInfo ---------------------------- -- + +--[[ +Unofficial note: You can compute the pixel size from this, if you are crazy you can make a library based on this or something +Will only be present if the client sent this information (requires v5.7+) + +Note that none of these things are constant, they are likely to change during a client +connection as the player resizes the window and moves it between monitors + +real_gui_scaling and real_hud_scaling can be used instead of DPI. +OSes don't necessarily give the physical DPI, as they may allow user configuration. +real_*_scaling is just OS DPI / 96 but with another level of user configuration. +]] +---@class core.PlayerWindowInfo +--[[ +Current size of the in-game render target (pixels). + +This is usually the window size, but may be smaller in certain situations, +such as side-by-side mode. +]] +---@field size vec2i.xy +--[[ +Estimated maximum formspec size before Luanti will start shrinking the +formspec to fit. For a fullscreen formspec, use the size returned by +this table and `padding[0,0]`. `bgcolor[;true]` is also recommended. +]] +---@field max_formspec_size vec2i.xy +--[[ +GUI Scaling multiplier +Equal to the setting `gui_scaling` multiplied by `dpi / 96` +]] +---@field real_gui_scaling number +--[[ +HUD Scaling multiplier +Equal to the setting `hud_scaling` multiplied by `dpi / 96` +]] +---@field real_hud_scaling number +--[[ +Whether the touchscreen controls are enabled. +Usually (but not always) `true` on Android. +Requires at least version 5.9.0 on the client. For older clients, it +is always set to `false`. +]] +---@field touch_controls boolean + +-- ---------------------------- core.* functions ---------------------------- -- + +--[[ +WIPDOC +]] +---@nodiscard +---@param player_name string +---@return core.PlayerInfo +function core.get_player_information(player_name) end + +--[[ +WIPDOC +]] +---@nodiscard +---@param player_name string +---@return core.PlayerWindowInfo? # Client must have version 5.7+ +function core.get_player_window_information(player_name) end \ No newline at end of file diff --git a/types/luanti_lsp_definitions/library/core/utilities/protocol_versions.lua b/types/luanti_lsp_definitions/library/core/utilities/protocol_versions.lua new file mode 100644 index 00000000..1685372b --- /dev/null +++ b/types/luanti_lsp_definitions/library/core/utilities/protocol_versions.lua @@ -0,0 +1,89 @@ +---@meta _ +-- DRAFT 1 DONE +-- luanti/doc/lua_api.md: 'core' namespace reference > Utilities + +--[[ +WIPDOC +]] +---@alias core.Protocol +--- | 37 +--- | 38 +--- | 39 +--- | 40 +--- | 41 +--- | 42 +--- | 43 +--- | 44 +--- | 45 +--- | 46 +--- | 47 +--- | 48 +--- | 49 + +--[[ +WIPDOC +]] +---@class core.ProtocolVersions +core.protocol_versions = {} + +---@class core.ProtocolVersions : {[string]:core.Protocol} +--[[ +WIPDOC +]] +---@field ["5.0.0"] 37 +--[[ +WIPDOC +]] +---@field ["5.1.0"] 38 +--[[ +WIPDOC +]] +---@field ["5.2.0"] 39 +--[[ +WIPDOC +]] +---@field ["5.3.0"] 39 +--[[ +WIPDOC +]] +---@field ["5.4.0"] 39 +--[[ +WIPDOC +]] +---@field ["5.5.0"] 40 +--[[ +WIPDOC +]] +---@field ["5.6.0"] 41 +--[[ +WIPDOC +]] +---@field ["5.7.0"] 42 +--[[ +WIPDOC +]] +---@field ["5.8.0"] 43 +--[[ +WIPDOC +]] +---@field ["5.9.0"] 44 +--[[ +WIPDOC +]] +---@field ["5.9.1"] 45 +--[[ +WIPDOC +]] +---@field ["5.10.0"] 46 +--[[ +WIPDOC +]] +---@field ["5.11.0"] 47 +--[[ +WIPDOC +]] +---@field ["5.12.0"] 48 +--[[ +WIPDOC +]] +---@field ["5.13.0"] 49 \ No newline at end of file diff --git a/types/luanti_lsp_definitions/library/core/utilities/utilities.lua b/types/luanti_lsp_definitions/library/core/utilities/utilities.lua new file mode 100644 index 00000000..b2d90562 --- /dev/null +++ b/types/luanti_lsp_definitions/library/core/utilities/utilities.lua @@ -0,0 +1,208 @@ +---@meta _ +-- DRAFT 1 DONE +-- luanti/doc/lua_api.md: 'core' namespace reference > Utilities + +-- ------------------------- engine and client info ------------------------- -- + +--[[ +Returns currently loading mod's name WHEN LOADING A MOD +]] +---@nodiscard +---@return string +function core.get_current_modname() end + +--[[ +WIPDOC +]] +---@nodiscard +---@param modname string +---@return core.Path +function core.get_modpath(modname) end + +--[[ +WIPDOC +]] +---@return string[] +---@nodiscard +function core.get_modnames() end + +--[[ core.get_game_info() split off into ./game_info.lua ]]-- + +--[[ +WIPDOC +]] +---@nodiscard +---@return core.Path +function core.get_worldpath() end + +--[[ +WIPDOC +]] +---@nodiscard +---@return boolean +function core.is_singleplayer() end + +--[[ core.features .. core.has_features() split off into ./features.lua ]]-- + +--[[ core.get_player_information() split off into ./player_information.lua ]]-- + +--[[ core.protocol_versions.lua() split off into ./protocol_versions.lua ]]-- + +--[[ core.get_player_window_information() split off into ./player_information.lua ]]-- + +-- ------------------------------- filesystem ------------------------------- -- + +--[[ +WIPDOC +]] +---@nodiscard +---@param path core.Path +---@return boolean success +function core.mkdir(path) end + +--[[ +WIPDOC +]] +---@nodiscard +---@param path core.Path +---@param recursive boolean? +---@return boolean success +function core.rmdir(path, recursive) end + +--[[ +WIPDOC +]] +---@nodiscard +---@param source core.Path +---@param destination core.Path +---@return boolean success +function core.cpdir(source, destination) end + +--[[ +WIPDOC +]] +---@nodiscard +---@param source core.Path +---@param destination core.Path +---@return boolean success +function core.mvdir(source, destination) end + +--[[ +* `core.get_dir_list(path, [is_dir])`: returns list of entry names + * is_dir is one of: + * nil: return all entries, + * true: return only subdirectory names, or + * false: return only file names. +]] +---@nodiscard +---@param path string +---@param is_dir nil|true|false +---@return core.Path[] +function core.get_dir_list(path, is_dir) end + +--[[ +* `core.safe_file_write(path, content)`: returns boolean indicating success + * Replaces contents of file at path with new contents in a safe (atomic) + way. Use this instead of below code when writing e.g. database files: + `local f = io.open(path, "wb"); f:write(content); f:close()` +]] +---@nodiscard +---@param path core.Path +---@param content string +---@return boolean success +function core.safe_file_write(path, content) end + +-- ----------------------------- engine version ----------------------------- -- + +--[[ core.get_version() split off into ./engine_version.lua ]]-- + +-- --------------------------------- hashing -------------------------------- -- + +--[[ +WIPDOC +]] +---@nodiscard +---@param data string +---@param raw boolean? raw bytes instead of hex digits, default: false +---@return string +function core.sha1(data, raw) end + +--[[ +WIPDOC +]] +---@nodiscard +---@param data string +---@param raw boolean? raw bytes instead of hex digits, default: false +---@return string +function core.sha256(data, raw) end + +-- --------------------------------- colors --------------------------------- -- + +--[[ +Colorspec to hex basically +]] +---@nodiscard +---@param colorspec core.ColorSpec +---@return core.ColorString +function core.colorspec_to_colorstring(colorspec) end + +--[[ +Layout: RGBA +]] +---@nodiscard +---@return core.ColorSpec +---@param colorspec core.ColorSpec.numberfmt +function core.colorspec_to_bytes(colorspec) end + +--[[ +WIPDOC +]] +---@nodiscard +---@param colorspec core.ColorSpec +---@return core.ColorSpec.tablefmt +function core.colorspec_to_table(colorspec) end + +-- ---------------------------------- misc ---------------------------------- -- + +--[[ +WIPDOC +]] +---@param time_of_day string +---@return number +function core.time_to_day_night_ratio(time_of_day) end + +--[[ +Unofficial note: shhh.... but you can do this in `core.handle_async` instead, get like a really good Promise library +Unofficial note: shh... but you can also use it real-time and it's real cool +Unofficial note: you can do "[png:"..core.encode_base64(core.encode_png(...)) to have a png +* `core.encode_png(width, height, data, [compression])`: Encode a PNG + image and return it in string form. + * `width`: Width of the image + * `height`: Height of the image + * `data`: Image data, one of: + * array table of ColorSpec, length must be width*height + * string with raw RGBA pixels, length must be width*height*4 + * `compression`: Optional zlib compression level, number in range 0 to 9. + The data is one-dimensional, starting in the upper left corner of the image + and laid out in scanlines going from left to right, then top to bottom. + You can use `colorspec_to_bytes` to generate raw RGBA values. + Palettes are not supported at the moment. + You may use this to procedurally generate textures during server init. +]] +---@nodiscard +---@param width integer +---@param height integer +---@param data string|core.ColorSpec[] +---@param compression integer? +---@return string +function core.encode_png(width, height, data, compression) end + +--[[ +* `core.urlencode(str)`: Encodes reserved URI characters by a + percent sign followed by two hex digits. See + [RFC 3986, section 2.3](https://datatracker.ietf.org/doc/html/rfc3986#section-2.3). +]] +---@nodiscard +---@param str string +---@return string +function core.urlencode(str) end \ No newline at end of file diff --git a/types/luanti_lsp_definitions/library/defs/HTTPRequest.lua b/types/luanti_lsp_definitions/library/defs/HTTPRequest.lua new file mode 100644 index 00000000..329281de --- /dev/null +++ b/types/luanti_lsp_definitions/library/defs/HTTPRequest.lua @@ -0,0 +1,60 @@ +---@meta _ +-- DRAFT 1 DONE +-- luanti/doc/lua_api.md: Definition tables > `HTTPRequest` definition + +--[[ +WIPDOC +]] +---@alias core.HTTPRequestDef.method +--- | "GET" +--- | "HEAD" +--- | "POST" +--- | "PUT" +--- | "PATCH" +--- | "DELETE" + +--[[ +WIPDOC +]] +---@class core.HTTPRequestDef +--[[ +WIPDOC +]] +---@field url string? +--[[ +Timeout for request to be completed in seconds. Default depends on engine settings. +]] +---@field timeout number? +--[[ +The http method to use. Defaults to "GET". +]] +---@field method core.HTTPRequestDef.method? +--[[ +Data for the POST, PUT, PATCH or DELETE request. +Accepts both a string and a table. If a table is specified, encodes +table as x-www-form-urlencoded key-value pairs. +]] +---@field data string|table? +--[[ +Optional, if specified replaces the default Luanti user agent with +given string. +]] +---@field user_agent string? +--[[ +Optional, if specified adds additional headers to the HTTP request. +You must make sure that the header strings follow HTTP specification +("Key: Value"). +]] +---@field extra_headers string[]? +--[[ +Optional, if true performs a multipart HTTP request. +Default is false. +Not allowed for GET or HEAD method and `data` must be a table. +]] +---@field multipart boolean? +--[[ +Deprecated, use `data` instead. Forces `method = "POST"`. + +* @deprecated +]] +---@field post_data string|table? diff --git a/types/luanti_lsp_definitions/library/defs/HTTPRequestResult.lua b/types/luanti_lsp_definitions/library/defs/HTTPRequestResult.lua new file mode 100644 index 00000000..baed5b34 --- /dev/null +++ b/types/luanti_lsp_definitions/library/defs/HTTPRequestResult.lua @@ -0,0 +1,29 @@ +---@meta _ +-- DRAFT 1 DONE +-- luanti/doc/lua_api.md: Definition tables > `HTTPRequestResult` definition + +--[[ +WIPDOC +]] +---@class core.HTTPRequestResultDef +--[[ +If true, the request has finished (either succeeded, failed or timed +out) +]] +---@field completed boolean? +--[[ +If true, the request was successful +]] +---@field succeeded boolean? +--[[ +If true, the request timed out +]] +---@field timeout boolean? +--[[ +HTTP status code +]] +---@field code integer? +--[[ +Response body +]] +---@field data string? diff --git a/types/luanti_lsp_definitions/library/defs/abm.lua b/types/luanti_lsp_definitions/library/defs/abm.lua new file mode 100644 index 00000000..a2890757 --- /dev/null +++ b/types/luanti_lsp_definitions/library/defs/abm.lua @@ -0,0 +1,76 @@ +---@meta _ +-- DRAFT 1 DONE +-- luanti/doc/lua_api.md: Definition tables > ABM (ActiveBlockModifier) definition + +--[[ +WIPDOC +]] +---@alias core.ABMDef.action fun(pos:ivec, node:core.Node.get, active_object_count:integer, active_object_count_wider:integer) + +--[[ +ABM (ActiveBlockModifier) definition +------------------------------------ + +Used by `core.register_abm`. + +An active block modifier (ABM) is used to define a function that is continuously +and randomly called for specific nodes (defined by `nodenames` and other conditions) +in active mapblocks. +]] +---@class core.ABMDef +--[[ +Descriptive label for profiling purposes (optional). +Definitions with identical labels will be listed as one. +]] +---@field label string +--[[ +Apply `action` function to these nodes. +`group:groupname` can also be used here. +]] +---@field nodenames OneOrMany +--[[ +Only apply `action` to nodes that have one of, or any +combination of, these neighbors. +If left out or empty, any neighbor will do. +`group:groupname` can also be used here. +]] +---@field neighbors OneOrMany? +--[[ +Only apply `action` to nodes that have no one of these neighbors. +If left out or empty, it has no effect. +`group:groupname` can also be used here. +]] +---@field without_neighbors OneOrMany? +--[[ +Operation interval in seconds +]] +---@field interval number? +--[[ +Probability of triggering `action` per-node per-interval is 1.0 / chance (integers only) +]] +---@field chance integer? +--[[ +WIPDOC +]] +---@field min_y integer? +--[[ +WIPDOC +]] +---@field max_y integer? +--[[ +If true, catch-up behavior is enabled: The `chance` value is +temporarily reduced when returning to an area to simulate time lost +by the area being unattended. Note that the `chance` value can often +be reduced to 1. +]] +---@field catch_up boolean? +--[[ +Function triggered for each qualifying node. +`active_object_count` is number of active objects in the node's +mapblock. +`active_object_count_wider` is number of active objects in the node's +mapblock plus all 26 neighboring mapblocks. If any neighboring +mapblocks are unloaded an estimate is calculated for them based on +loaded mapblocks. +]] +---@field action core.ABMDef.action diff --git a/types/luanti_lsp_definitions/library/defs/aliases.lua b/types/luanti_lsp_definitions/library/defs/aliases.lua new file mode 100644 index 00000000..eeb429bb --- /dev/null +++ b/types/luanti_lsp_definitions/library/defs/aliases.lua @@ -0,0 +1,71 @@ +---@meta _ +-- DRAFT 1 DONE +-- luanti/doc/lua_api.md: Aliases > Mapgen aliases + +-- ------------------------------- MapgenAlias ------------------------------ -- + +--[[ +WIPDOC +]] +---@alias core.MapgenAlias.essential +--- | "mapgen_stone" +--- | "mapgen_water_source" +--- | "mapgen_river_water_source" + +--[[ +WIPDOC +]] +---@alias core.MapgenAlias.optional +--- | "mapgen_lava_source" +--- | "mapgen_cobble" + +--[[ +WIPDOC +]] +---@alias core.MapgenAlias.v6.essential +--- | "mapgen_stone" +--- | "mapgen_water_source" +--- | "mapgen_lava_source" +--- | "mapgen_dirt" +--- | "mapgen_dirt_with_grass" +--- | "mapgen_sand" +--- | "mapgen_tree" +--- | "mapgen_leaves" +--- | "mapgen_apple" +--- | "mapgen_cobble" + +--[[ +WIPDOC +]] +---@alias core.MapgenAlias.v6.optional +--- | "mapgen_gravel" +--- | "mapgen_desert_stone" +--- | "mapgen_desert_sand" +--- | "mapgen_dirt_with_snow" +--- | "mapgen_snowblock" +--- | "mapgen_snow" +--- | "mapgen_ice" +--- | "mapgen_jungletree" +--- | "mapgen_jungleleaves" +--- | "mapgen_junglegrass" +--- | "mapgen_pine_tree" +--- | "mapgen_pine_needles" +--- | "mapgen_stair_cobble" +--- | "mapgen_mossycobble" +--- | "mapgen_stair_desert_stone" + +--[[ +WIPDOC +]] +---@alias core.MapgenAlias +--- | core.MapgenAlias.essential +--- | core.MapgenAlias.optional +--- | core.MapgenAlias.v6.essential +--- | core.MapgenAlias.v6.optional + +--[[ +WIPDOC +]] +---@alias core.Alias +--- | core.MapgenAlias +--- | string \ No newline at end of file diff --git a/types/luanti_lsp_definitions/library/defs/authentication_handler.lua b/types/luanti_lsp_definitions/library/defs/authentication_handler.lua new file mode 100644 index 00000000..75cd1441 --- /dev/null +++ b/types/luanti_lsp_definitions/library/defs/authentication_handler.lua @@ -0,0 +1,106 @@ +---@meta _ +-- DRAFT 1 DONE +-- luanti/doc/lua_api.md: Definition tables > Authentication handler definition + +-- --------------------------- AuthenticationData --------------------------- -- + +--[[ +WIPDOC +]] +---@class core.AuthenticationData +--[[ +WIPDOC +]] +---@field password string +--[[ +WIPDOC +]] +---@field privileges core.PrivilegeSet +--[[ +WIPDOC +]] +---@field last_login number? + +-- ------------------------ AuthenticationHandlerDef ------------------------ -- + +--[[ +WIPDOC +]] +---@alias core.AuthenticationHandlerDef.get_auth fun(name:string?): core.AuthenticationData + +--[[ +WIPDOC +]] +---@alias core.AuthenticationHandlerDef.create_auth fun(name:string, password:string) + +--[[ +WIPDOC +]] +---@alias core.AuthenticationHandlerDef.delete_auth fun(name:string): boolean + +--[[ +WIPDOC +]] +---@alias core.AuthenticationHandlerDef.set_password fun(name:string, password:string) + +--[[ +WIPDOC +]] +---@alias core.AuthenticationHandlerDef.set_privileges fun(name:string?, privileges:core.PrivilegeSet?) + +--[[ +WIPDOC +]] +---@alias core.AuthenticationHandlerDef.reload fun(): boolean + +--[[ +WIPDOC +]] +---@alias core.AuthenticationHandlerDef.record_login fun(name:string) + +--[[ +WIPDOC +]] +---@alias _.AuthenticationHandlerDef.iterate fun():string? + +--[[ +WIPDOC +]] +---@alias core.AuthenticationHandlerDef.iterate fun():_.AuthenticationHandlerDef.iterate + +--[[ +WIPDOC +]] +---@class core.AuthenticationHandlerDef +--[[ +WIPDOC +]] +---@field get_auth core.AuthenticationHandlerDef.get_auth +--[[ +WIPDOC +]] +---@field create_auth core.AuthenticationHandlerDef.create_auth +--[[ +WIPDOC +]] +---@field delete_auth core.AuthenticationHandlerDef.delete_auth +--[[ +WIPDOC +]] +---@field set_password core.AuthenticationHandlerDef.set_password +--[[ +WIPDOC +]] +---@field set_privileges core.AuthenticationHandlerDef.set_privileges +--[[ +WIPDOC +]] +---@field reload core.AuthenticationHandlerDef.reload +--[[ +WIPDOC +]] +---@field record_login core.AuthenticationHandlerDef.record_login +--[[ +WIPDOC +]] +---@field iterate core.AuthenticationHandlerDef.iterate \ No newline at end of file diff --git a/types/luanti_lsp_definitions/library/defs/biome.lua b/types/luanti_lsp_definitions/library/defs/biome.lua new file mode 100644 index 00000000..979fc7dd --- /dev/null +++ b/types/luanti_lsp_definitions/library/defs/biome.lua @@ -0,0 +1,143 @@ +---@meta _ +-- DRAFT 1 DONE +-- luanti/doc/lua_api.md: Definition table > Biome definition + +--[[ +WIPDOC +]] +---@class core.BiomeID : integer + +--[[ +WIPDOC +]] +---@class core.BiomeDef +--[[ +Biome name +]] +---@field name string +--[[ +Node dropped onto upper surface after all else is generated +]] +---@field node_dust core.Node.name? +--[[ +Node forming surface layer of biome +]] +---@field node_top core.Node.name? +--[[ +Node forming surface layer of biome and thickness of this layer +]] +---@field depth_top integer? +--[[ +Node forming lower layer of biome +]] +---@field node_filler core.Node.name? +--[[ +Node forming lower layer of biome and thickness of this layer +]] +---@field depth_filler integer? +--[[ +Node that replaces all stone nodes between roughly y_min and y_max. +]] +---@field node_stone core.Node.name? +--[[ +Node forming a surface layer in seawater with the defined thickness +]] +---@field node_water_top core.Node.name? +--[[ +Node forming a surface layer in seawater with the defined thickness +]] +---@field depth_water_top integer? +--[[ +Node that replaces all seawater nodes not in the surface layer +]] +---@field node_water core.Node.name? +--[[ +Node that replaces river water in mapgens that use default:river_water +]] +---@field node_river_water core.Node.name? +--[[ +Node placed under river water and thickness of this layer +]] +---@field node_riverbed core.Node.name? +--[[ +Node placed under river water and thickness of this layer +]] +---@field depth_riverbed integer? +--[[ +Nodes placed inside 50% of the medium size caves. +Multiple nodes can be specified, each cave will use a randomly +chosen node from the list. +If this field is left out or 'nil', cave liquids fall back to +classic behavior of lava and water distributed using 3D noise. +For no cave liquid, specify "air". +]] +---@field node_cave_liquid core.Node.name|core.Node.name[]? +--[[ +Node used for primary dungeon structure. +If absent, dungeon nodes fall back to the 'mapgen_cobble' mapgen +alias, if that is also absent, dungeon nodes fall back to the biome +'node_stone'. +If present, the following two nodes are also used. +]] +---@field node_dungeon core.Node.name? +--[[ +Node used for randomly-distributed alternative structure nodes. +If alternative structure nodes are not wanted leave this absent. +]] +---@field node_dungeon_alt core.Node.name? +--[[ +Node used for dungeon stairs. +If absent, stairs fall back to 'node_dungeon'. +]] +---@field node_dungeon_stair core.Node.name? +--[[ +WIPDOC +]] +---@field y_max integer? +--[[ +WIPDOC +]] +---@field y_min integer? +--[[ +xyz limits for biome, an alternative to using 'y_min' and 'y_max'. +Biome is limited to a cuboid defined by these positions. +Any x, y or z field left undefined defaults to -31000 in 'min_pos' or +31000 in 'max_pos'. +]] +---@field max_pos ivector? +--[[ +xyz limits for biome, an alternative to using 'y_min' and 'y_max'. +Biome is limited to a cuboid defined by these positions. +Any x, y or z field left undefined defaults to -31000 in 'min_pos' or +31000 in 'max_pos'. +]] +---@field min_pos ivector? +--[[ +Vertical distance in nodes above 'y_max' over which the biome will +blend with the biome above. +Set to 0 for no vertical blend. Defaults to 0. +]] +---@field vertical_blend integer? +--[[ +Characteristic temperature and humidity for the biome. +These values create 'biome points' on a voronoi diagram with heat and +humidity as axes. The resulting voronoi cells determine the +distribution of the biomes. +Heat and humidity have average values of 50, vary mostly between +0 and 100 but can exceed these values. +]] +---@field heat_point integer +--[[ +Characteristic temperature and humidity for the biome. +These values create 'biome points' on a voronoi diagram with heat and +humidity as axes. The resulting voronoi cells determine the +distribution of the biomes. +Heat and humidity have average values of 50, vary mostly between +0 and 100 but can exceed these values. +]] +---@field humidity_point integer +--[[ +Relative weight of the biome in the Voronoi diagram. +A value of 0 (or less) is ignored and equivalent to 1.0. +]] +---@field weight number? \ No newline at end of file diff --git a/types/luanti_lsp_definitions/library/defs/chat_command.lua b/types/luanti_lsp_definitions/library/defs/chat_command.lua new file mode 100644 index 00000000..250c8895 --- /dev/null +++ b/types/luanti_lsp_definitions/library/defs/chat_command.lua @@ -0,0 +1,92 @@ +---@meta _ +-- DRAFT 1 DONE +-- luanti/doc/lua_api.md: Definition tables > Chat command definition + +--[[ +WIPDOC +]] +---@alias core.ChatCommandDef.keys +--- | "pulverize" +--- | "fixlight" +--- | "dump" +--- | "grantme" +--- | "rollback_check" +--- | "mods" +--- | "days" +--- | "last-login" +--- | "help" +--- | "privs" +--- | "clearinv" +--- | "status" +--- | "msg" +--- | "shutdown" +--- | "revokeme" +--- | "grant" +--- | "revoke" +--- | "admin" +--- | "ban" +--- | "kick" +--- | "giveme" +--- | "remove_player" +--- | "unban" +--- | "haspriv" +--- | "kill" +--- | "set" +--- | "rollback" +--- | "auth_reload" +--- | "clearobjects" +--- | "setpassword" +--- | "me" +--- | "emergeblocks" +--- | "teleport" +--- | "give" +--- | "time" +--- | "spawnentity" +--- | "clearpassword" +--- | "deleteblocks" +--- | string + +--[[ +WIPDOC +]] +---@alias core.ChatCommandDef.func fun(name:string, param:string): boolean?, string? + +--[[ +WIPDOC +]] +---@class core.ChatCommandDef +--[[ +Note that in params, the conventional use of symbols is as follows: + +* `<>` signifies a placeholder to be replaced when the command is used. For + example, when a player name is needed: `` +* `[]` signifies param is optional and not required when the command is used. + For example, if you require param1 but param2 is optional: + ` []` +* `|` signifies exclusive or. The command requires one param from the options + provided. For example: ` | ` +* `()` signifies grouping. For example, when param1 and param2 are both + required, or only param3 is required: `( ) | ` +]] +---@field params string? +--[[ +WIPDOC +]] +---@field description string? +--[[ +WIPDOC +]] +---@field privs core.PrivilegeSet? +--[[ +WIPDOC +]] +---@field func core.ChatCommandDef.func + +--[[ +WIPDOC +]] +---@class core.ChatCommandDef.override +--[[ +WIPDOC +]] +---@field func core.ChatCommandDef.func? \ No newline at end of file diff --git a/types/luanti_lsp_definitions/library/defs/colors.lua b/types/luanti_lsp_definitions/library/defs/colors.lua new file mode 100644 index 00000000..3c170b80 --- /dev/null +++ b/types/luanti_lsp_definitions/library/defs/colors.lua @@ -0,0 +1,208 @@ +---@meta +-- DRAFT 1 DONE +-- luanti/doc/lua_api.md: Colors + +--[[ +WIPDOC +]] +---@class core.ColorSpec.tablefmt +--[[ +WIPDOC +]] +---@field a integer? +--[[ +WIPDOC +]] +---@field r integer? +--[[ +WIPDOC +]] +---@field g integer? +--[[ +WIPDOC +]] +---@field b integer? + +--[[ +WIPDOC +]] +---@alias core.ColorString.CSSColors +--- | "aliceblue" +--- | "antiquewhite" +--- | "aqua" +--- | "aquamarine" +--- | "azure" +--- | "beige" +--- | "bisque" +--- | "black" +--- | "blanchedalmond" +--- | "blue" +--- | "blueviolet" +--- | "brown" +--- | "burlywood" +--- | "cadetblue" +--- | "chartreuse" +--- | "chocolate" +--- | "coral" +--- | "cornflowerblue" +--- | "cornsilk" +--- | "crimson" +--- | "cyan" +--- | "darkblue" +--- | "darkcyan" +--- | "darkgoldenrod" +--- | "darkgray" +--- | "darkgreen" +--- | "darkgrey" +--- | "darkkhaki" +--- | "darkmagenta" +--- | "darkolivegreen" +--- | "darkorange" +--- | "darkorchid" +--- | "darkred" +--- | "darksalmon" +--- | "darkseagreen" +--- | "darkslateblue" +--- | "darkslategray" +--- | "darkslategrey" +--- | "darkturquoise" +--- | "darkviolet" +--- | "deeppink" +--- | "deepskyblue" +--- | "dimgray" +--- | "dimgrey" +--- | "dodgerblue" +--- | "firebrick" +--- | "floralwhite" +--- | "forestgreen" +--- | "fuchsia" +--- | "gainsboro" +--- | "ghostwhite" +--- | "gold" +--- | "goldenrod" +--- | "gray" +--- | "green" +--- | "greenyellow" +--- | "grey" +--- | "honeydew" +--- | "hotpink" +--- | "indianred" +--- | "indigo" +--- | "ivory" +--- | "khaki" +--- | "lavender" +--- | "lavenderblush" +--- | "lawngreen" +--- | "lemonchiffon" +--- | "lightblue" +--- | "lightcoral" +--- | "lightcyan" +--- | "lightgoldenrodyellow" +--- | "lightgray" +--- | "lightgreen" +--- | "lightgrey" +--- | "lightpink" +--- | "lightsalmon" +--- | "lightseagreen" +--- | "lightskyblue" +--- | "lightslategray" +--- | "lightslategrey" +--- | "lightsteelblue" +--- | "lightyellow" +--- | "lime" +--- | "limegreen" +--- | "linen" +--- | "magenta" +--- | "maroon" +--- | "mediumaquamarine" +--- | "mediumblue" +--- | "mediumorchid" +--- | "mediumpurple" +--- | "mediumseagreen" +--- | "mediumslateblue" +--- | "mediumspringgreen" +--- | "mediumturquoise" +--- | "mediumvioletred" +--- | "midnightblue" +--- | "mintcream" +--- | "mistyrose" +--- | "moccasin" +--- | "navajowhite" +--- | "navy" +--- | "oldlace" +--- | "olive" +--- | "olivedrab" +--- | "orange" +--- | "orangered" +--- | "orchid" +--- | "palegoldenrod" +--- | "palegreen" +--- | "paleturquoise" +--- | "palevioletred" +--- | "papayawhip" +--- | "peachpuff" +--- | "peru" +--- | "pink" +--- | "plum" +--- | "powderblue" +--- | "purple" +--- | "rebeccapurple" +--- | "red" +--- | "rosybrown" +--- | "royalblue" +--- | "saddlebrown" +--- | "salmon" +--- | "sandybrown" +--- | "seagreen" +--- | "seashell" +--- | "sienna" +--- | "silver" +--- | "skyblue" +--- | "slateblue" +--- | "slategray" +--- | "slategrey" +--- | "snow" +--- | "springgreen" +--- | "steelblue" +--- | "tan" +--- | "teal" +--- | "thistle" +--- | "tomato" +--- | "turquoise" +--- | "violet" +--- | "wheat" +--- | "white" +--- | "whitesmoke" +--- | "yellow" +--- | "yellowgreen" + +--[[ +`#RGB` defines a color in hexadecimal format. + +`#RGBA` defines a color in hexadecimal format and alpha channel. + +`#RRGGBB` defines a color in hexadecimal format. + +`#RRGGBBAA` defines a color in hexadecimal format and alpha channel. + +Named colors are also supported and are equivalent to +[CSS Color Module Level 4](https://www.w3.org/TR/css-color-4/#named-color). +To specify the value of the alpha channel, append `#A` or `#AA` to the end of +the color name (e.g. `colorname#08`). +]] +---@alias core.ColorString +--- | string +--- | core.ColorString.CSSColors + +--[[ +WIPDOC +]] +---@alias core.ColorSpec.numberfmt integer + +--[[ +WIPDOC +]] +---@alias core.ColorSpec +--- | core.ColorSpec.tablefmt +--- | core.ColorString +--- | core.ColorSpec.numberfmt \ No newline at end of file diff --git a/types/luanti_lsp_definitions/library/defs/crafting/cooking.lua b/types/luanti_lsp_definitions/library/defs/crafting/cooking.lua new file mode 100644 index 00000000..e53bda0f --- /dev/null +++ b/types/luanti_lsp_definitions/library/defs/crafting/cooking.lua @@ -0,0 +1,60 @@ +---@meta _ +-- DRAFT 1 DONE +-- luanti/doc/lua_api.md: Groups > Groups in crafting recipes +-- luanti/doc/lua_api.md: Definition tables > Crafting recipes + +--[[ +WIPDOC +]] +---@class core.CraftingRecipeDef.cooking.input +--[[ +* `type = "cooking"`: Mandatory +]] +---@field type "cooking" +--[[ +* `recipe`: An itemname of the single input item +]] +---@field recipe core.Item.namelike +--[[ +* `cooktime`: (optional) Time it takes to cook this item, in seconds. + A floating-point number. (default: 3.0) +Note: Games and mods are free to re-interpret the cooktime in special + +]] +---@field cooktime number +--[[ +* `replacements`: (optional) Allows you to replace input items with some other items + when something is crafted + * Provided as a list of item pairs of the form `{ old_item, new_item }` where + `old_item` is the input item to replace (same syntax as for a regular input + slot; groups are allowed) and `new_item` is an itemstring for the item stack + it will become + * When the output is crafted, Luanti iterates through the list + of input items if the crafting grid. For each input item stack, it checks if + it matches with an `old_item` in the item pair list. + * If it matches, the item will be replaced. Also, this item pair + will *not* be applied again for the remaining items + * If it does not match, the item is consumed (reduced by 1) normally + * The `new_item` will appear in one of 3 places: + * Crafting grid, if the input stack size was exactly 1 + * Player inventory, if input stack size was larger + * Drops as item entity, if it fits neither in craft grid or inventory + +Mods that utilize cooking recipes (e.g. for adding a furnace node) need to implement +replacements on their own +]] +---@field replacements [core.Item.namelike, core.Item.name][]? + +--[[ +### Cooking + +A cooking recipe has a single input item, a single output item stack +and a cooking time. It represents cooking/baking/smelting/etc. items in +an oven, furnace, or something similar; the exact meaning is up for games +to decide, if they choose to use cooking at all. + +The engine does not implement anything specific to cooking recipes, but +the recipes can be retrieved later using `core.get_craft_result` to +have a consistent interface across different games/mods. +]] +---@class core.CraftingRecipeDef.cooking : core.CraftingRecipeDef.cooking.input, core.CraftingRecipeDef.output \ No newline at end of file diff --git a/types/luanti_lsp_definitions/library/defs/crafting/crafting.lua b/types/luanti_lsp_definitions/library/defs/crafting/crafting.lua new file mode 100644 index 00000000..1f9a902f --- /dev/null +++ b/types/luanti_lsp_definitions/library/defs/crafting/crafting.lua @@ -0,0 +1,58 @@ +---@meta _ +-- DRAFT 1 DONE +-- luanti/doc/lua_api.md: Groups > Groups in crafting recipes +-- luanti/doc/lua_api.md: 'core' namespace reference > Registration functions > Gameplay +-- luanti/doc/lua_api.md: Definition tables > Crafting recipes + +--[[ +WIPDOC +]] +---@class core.CraftingRecipeDef.output +--[[ +* `output`: Itemstring of output itemstack (item counts >= 1 are allowed) +]] +---@field output core.Item.stringfmt + +--[[ +WIPDOC +]] +---@alias core.CraftingRecipeDef.clear +--- | core.CraftingRecipeDef.shaped.input +--- | core.CraftingRecipeDef.shapeless.input +--- | core.CraftingRecipeDef.toolrepair +--- | core.CraftingRecipeDef.cooking.input +--- | core.CraftingRecipeDef.fuel +--- | core.CraftingRecipeDef.output + +-- ---------------------------- CraftingRecipeDef --------------------------- -- + +--[[ +Crafting recipes +---------------- + +Crafting converts one or more inputs to one output itemstack of arbitrary +count (except for fuels, which don't have an output). The conversion reduces +each input ItemStack by 1. + +Craft recipes are registered by `core.register_craft` and use a +table format. The accepted parameters are listed below. + +Recipe input items can either be specified by item name (item count = 1) +or by group (see "Groups in crafting recipes" for details). +Only the item name (and groups) matter for matching a recipe, i.e. meta and count +are ignored. + +If multiple recipes match the input of a craft grid, one of them is chosen by the +following priority rules: + +* Shaped recipes are preferred over shapeless recipes, which in turn are preferred + over tool repair. +* Otherwise, recipes without groups are preferred over recipes with groups. +* Otherwise, earlier registered recipes are preferred. +]] +---@alias core.CraftingRecipeDef +--- | core.CraftingRecipeDef.shaped +--- | core.CraftingRecipeDef.shapeless +--- | core.CraftingRecipeDef.toolrepair +--- | core.CraftingRecipeDef.cooking +--- | core.CraftingRecipeDef.fuel diff --git a/types/luanti_lsp_definitions/library/defs/crafting/fuel.lua b/types/luanti_lsp_definitions/library/defs/crafting/fuel.lua new file mode 100644 index 00000000..4ef44ba4 --- /dev/null +++ b/types/luanti_lsp_definitions/library/defs/crafting/fuel.lua @@ -0,0 +1,54 @@ +---@meta _ +-- DRAFT 1 DONE +-- luanti/doc/lua_api.md: Groups > Groups in crafting recipes +-- luanti/doc/lua_api.md: Definition tables > Crafting recipes + +--[[ +### Fuel + +A fuel recipe is an item associated with a "burning time" and an optional +item replacement. There is no output. This is usually used as fuel for +furnaces, ovens, stoves, etc. + +Like with cooking recipes, the engine does not do anything specific with +fuel recipes and it's up to games and mods to use them by retrieving +them via `core.get_craft_result`. +]] +---@class core.CraftingRecipeDef.fuel +--[[ +* `type = "fuel"`: Mandatory +]] +---@field type "fuel" +--[[ +* `recipe`: Itemname of the item to be used as fuel +]] +---@field recipe core.Item.namelike +--[[ +* `burntime`: (optional) Burning time this item provides, in seconds. + A floating-point number. (default: 1.0) +Note: Games and mods are free to re-interpret the burntime in special +cases, e.g. for an efficient furnace in which fuels burn twice as +long. +]] +---@field burntime number +--[[ +* `replacements`: (optional) Allows you to replace input items with some other items + when something is crafted + * Provided as a list of item pairs of the form `{ old_item, new_item }` where + `old_item` is the input item to replace (same syntax as for a regular input + slot; groups are allowed) and `new_item` is an itemstring for the item stack + it will become + * When the output is crafted, Luanti iterates through the list + of input items if the crafting grid. For each input item stack, it checks if + it matches with an `old_item` in the item pair list. + * If it matches, the item will be replaced. Also, this item pair + will *not* be applied again for the remaining items + * If it does not match, the item is consumed (reduced by 1) normally + * The `new_item` will appear in one of 3 places: + * Crafting grid, if the input stack size was exactly 1 + * Player inventory, if input stack size was larger + * Drops as item entity, if it fits neither in craft grid or inventory + +Mods that utilize fuels need to implement replacements on their own +]] +---@field replacements [core.Item.namelike, core.Item.name][]? \ No newline at end of file diff --git a/types/luanti_lsp_definitions/library/defs/crafting/shaped.lua b/types/luanti_lsp_definitions/library/defs/crafting/shaped.lua new file mode 100644 index 00000000..a701c85f --- /dev/null +++ b/types/luanti_lsp_definitions/library/defs/crafting/shaped.lua @@ -0,0 +1,65 @@ +---@meta _ +-- DRAFT 1 DONE +-- luanti/doc/lua_api.md: Groups > Groups in crafting recipes +-- luanti/doc/lua_api.md: Definition tables > Crafting recipes + +--[[ +WIPDOC +]] +---@class core.CraftingRecipeDef.shaped.input +--[[ +* `type = "shaped"`: (optional) specifies recipe type as shaped +]] +---@field type "shaped"? +--[[ +* `recipe`: A 2-dimensional matrix of items, with a width *w* and height *h*. + * *w* and *h* are chosen by you, they don't have to be equal but must be at least 1 + + * The inner tables are the rows. There must be *h* tables, specified from the top to the bottom row + * Values inside of the inner table are the columns. + Each inner table must contain a list of *w* items, specified from left to right + * Empty slots *must* be filled with the empty string +]] +---@field recipe core.Item.namelike[][] +--[[ +* `replacements`: (optional) Allows you to replace input items with some other items + when something is crafted + * Provided as a list of item pairs of the form `{ old_item, new_item }` where + `old_item` is the input item to replace (same syntax as for a regular input + slot; groups are allowed) and `new_item` is an itemstring for the item stack + it will become + * When the output is crafted, Luanti iterates through the list + of input items if the crafting grid. For each input item stack, it checks if + it matches with an `old_item` in the item pair list. + * If it matches, the item will be replaced. Also, this item pair + will *not* be applied again for the remaining items + * If it does not match, the item is consumed (reduced by 1) normally + * The `new_item` will appear in one of 3 places: + * Crafting grid, if the input stack size was exactly 1 + * Player inventory, if input stack size was larger + * Drops as item entity, if it fits neither in craft grid or inventory +]] +---@field replacements [core.Item.namelike, core.Item.name][]? + +--[[ +### Shaped + +This is the default recipe type (when no `type` is specified). + +A shaped recipe takes one or multiple items as input and has +a single item stack as output. The input items must be specified +in a 2-dimensional matrix (see parameters below) to specify the +exact arrangement (the "shape") in which the player must place them +in the crafting grid. + +For example, for a 3x3 recipe, the `recipes` table must have +3 rows and 3 columns. + +In order to craft the recipe, the players' crafting grid must +have equal or larger dimensions (both width and height). + +Empty slots outside of the recipe's extents are ignored, e.g. a 3x3 +recipe where only the bottom right 2x2 slots are filled is the same +as the corresponding 2x2 recipe without the empty slots.\ +]] +---@class core.CraftingRecipeDef.shaped : core.CraftingRecipeDef.shaped.input, core.CraftingRecipeDef.output \ No newline at end of file diff --git a/types/luanti_lsp_definitions/library/defs/crafting/shapeless.lua b/types/luanti_lsp_definitions/library/defs/crafting/shapeless.lua new file mode 100644 index 00000000..2c2f6019 --- /dev/null +++ b/types/luanti_lsp_definitions/library/defs/crafting/shapeless.lua @@ -0,0 +1,47 @@ +---@meta _ +-- DRAFT 1 DONE +-- luanti/doc/lua_api.md: Groups > Groups in crafting recipes +-- luanti/doc/lua_api.md: Definition tables > Crafting recipes + +--[[ +WIPDOC +]] +---@class core.CraftingRecipeDef.shapeless.input +--[[ +* `type = "shapeless"`: Mandatory +]] +---@field type "shapeless" +--[[ +* `recipe`: List of item names +]] +---@field recipe core.Item.namelike[] +--[[ +* `replacements`: (optional) Allows you to replace input items with some other items + when something is crafted + * Provided as a list of item pairs of the form `{ old_item, new_item }` where + `old_item` is the input item to replace (same syntax as for a regular input + slot; groups are allowed) and `new_item` is an itemstring for the item stack + it will become + * When the output is crafted, Luanti iterates through the list + of input items if the crafting grid. For each input item stack, it checks if + it matches with an `old_item` in the item pair list. + * If it matches, the item will be replaced. Also, this item pair + will *not* be applied again for the remaining items + * If it does not match, the item is consumed (reduced by 1) normally + * The `new_item` will appear in one of 3 places: + * Crafting grid, if the input stack size was exactly 1 + * Player inventory, if input stack size was larger + * Drops as item entity, if it fits neither in craft grid or inventory +]] +---@field replacements [core.Item.namelike, core.Item.name][]? + +--[[ +### Shapeless + +Takes a list of input items (at least 1). The order or arrangement +of input items does not matter. + +In order to craft the recipe, the players' crafting grid must have matching or +larger *count* of slots. The grid dimensions do not matter. +]] +---@class core.CraftingRecipeDef.shapeless : core.CraftingRecipeDef.shapeless.input, core.CraftingRecipeDef.output \ No newline at end of file diff --git a/types/luanti_lsp_definitions/library/defs/crafting/toolrepair.lua b/types/luanti_lsp_definitions/library/defs/crafting/toolrepair.lua new file mode 100644 index 00000000..1afbb8a8 --- /dev/null +++ b/types/luanti_lsp_definitions/library/defs/crafting/toolrepair.lua @@ -0,0 +1,52 @@ +---@meta _ +-- DRAFT 1 DONE +-- luanti/doc/lua_api.md: Groups > Groups in crafting recipes +-- luanti/doc/lua_api.md: Definition tables > Crafting recipes + +--[[ +### Tool repair + +Syntax: + + { + type = "toolrepair", + additional_wear = -0.02, -- multiplier of 65536 + } + +Adds a shapeless recipe for *every* tool that doesn't have the `disable_repair=1` +group. If this recipe is used, repairing is possible with any crafting grid +with at least 2 slots. +The player can put 2 equal tools in the craft grid to get one "repaired" tool +back. +The wear of the output is determined by the wear of both tools, plus a +'repair bonus' given by `additional_wear`. To reduce the wear (i.e. 'repair'), +you want `additional_wear` to be negative. + +The formula used to calculate the resulting wear is: + + 65536 * (1 - ( (1 - tool_1_wear) + (1 - tool_2_wear) + additional_wear)) + +The result is rounded and can't be lower than 0. If the result is 65536 or higher, +no crafting is possible. +]] +---@class core.CraftingRecipeDef.toolrepair +--[[ +* `type = "toolrepair"`: Mandatory +]] +---@field type "toolrepair" +--[[ +**AMENDMENT** +* `additional_wear`: multiplier of 65536. When repairing by getting a + repaired tool from 2 same tools in the craft grid, the resulting wear is a + combination of the 2 tools and a repair bonus from `additional_wear`. More + precisely, the pseudocode determining the result is: + +```lua +result = 65536 * (1 - ( (1 - tool_1_wear) + (1 - tool_2_wear) + additional_wear ) ) +result = max(0, round(result)) -- rounded and can't be lower than 0 +if result >= 65536 then + -- craft made not possible +end +``` +]] +---@field additional_wear core.Tool.wear \ No newline at end of file diff --git a/types/luanti_lsp_definitions/library/defs/decoration/decoration.lua b/types/luanti_lsp_definitions/library/defs/decoration/decoration.lua new file mode 100644 index 00000000..1409fd4f --- /dev/null +++ b/types/luanti_lsp_definitions/library/defs/decoration/decoration.lua @@ -0,0 +1,259 @@ +---@meta _ +-- DRAFT 1 DONE +-- luanti/doc/lua_api.md: Flag Specifier Format +-- luanti/doc/lua_api.md: Decoration types +-- luanti/doc/lua_api.md: Mapgen objects +-- luanti/doc/lua_api.md: Definition tables > Decoration definition + +--[[ +WIPDOC +]] +---@class core.DecorationID : integer + +-- ------------------------- DecorationDef partials ------------------------- -- + +---@class _.DecorationDef.fill_ratio.__partial +--[[ +The value determines 'decorations per surface node'. +Used only if noise_params is not specified. +If >= 10.0 complete coverage is enabled and decoration placement uses +a different and much faster method. +]] +---@field fill_ratio number? + +---@class _.DecorationDef.noise_params.__partial +--[[ +NoiseParams structure describing the noise used for decoration +distribution. +A noise value is calculated for each square division and determines +'decorations per surface node' within each division. +If the noise value >= 10.0 complete coverage is enabled and +decoration placement uses a different and much faster method. +]] +---@field noise_params core.NoiseParams.3d? + +-- -------------------------- DecorationDef.__base -------------------------- -- + +--[[ +WIPDOC +]] +---@alias core.DecorationDef.check_offset +--- | -1 +--- | 0 +--- | 1 + +--[[ +WIPDOC +]] +---@alias core.DecorationDef.biome +--- | string +--- | core.BiomeID +--- | core.BiomeDef + +---@class _.DecorationDef.__base +--[[ +Node (or list of nodes) that the decoration can be placed on +]] +---@field place_on OneOrMany +--[[ +Size of the square (X / Z) divisions of the mapchunk being generated. +Determines the resolution of noise variation if used. +If the chunk size is not evenly divisible by sidelen, sidelen is made +equal to the chunk size. +]] +---@field sidelen integer +--[[ +List of biomes in which this decoration occurs. Occurs in all biomes +if this is omitted, and ignored if the Mapgen being used does not +support biomes. +Can be a list of (or a single) biome names, IDs, or definitions. +]] +---@field biomes OneOrMany? +--[[ +*@default* `-31000` + +Lower limit for decoration (inclusive). +Refer to the Y coordinate of the 'place_on' node. +]] +---@field y_min integer? +--[[ +*@default* `31000` + +Upper limit for decoration (inclusive). +Refer to the Y coordinate of the 'place_on' node. +]] +---@field y_max integer? +--[[ +Node (or list of nodes) that the decoration only spawns next to. +Checks the 8 neighboring nodes on the same height, +and also the ones at the height plus the check_offset, excluding both center nodes. +]] +---@field spawn_by OneOrMany? +--[[ +*@default* `0` + +Specifies the offset that spawn_by should also check +The default value of -1 is useful to e.g check for water next to the base node. +0 disables additional checks, valid values: {-1, 0, 1} +]] +---@field check_offset core.DecorationDef.check_offset? +--[[ +Number of spawn_by nodes that must be surrounding the decoration +position to occur. +If absent or -1, decorations occur next to any nodes. +]] +---@field num_spawn_by integer? +--[[ +Flags for all decoration types. +- "liquid_surface": Find the highest liquid (not solid) surface under + open air. Search stops and fails on the first solid node. + Cannot be used with "all_floors" or "all_ceilings" below. +- "force_placement": Nodes other than "air" and "ignore" are replaced + by the decoration. +- "all_floors", "all_ceilings": Instead of placement on the highest + surface in a mapchunk the decoration is placed on all floor and/or + ceiling surfaces, for example in caves and dungeons. + Ceiling decorations act as an inversion of floor decorations so the + effect of 'place_offset_y' is inverted. + Y-slice probabilities do not function correctly for ceiling + schematic decorations as the behavior is unchanged. + If a single decoration registration has both flags the floor and + ceiling decorations will be aligned vertically. +]] +---@field flags core.DecorationDef.flags? + +-- -------------------------- DecorationDef.simple -------------------------- -- + +---@class _.DecorationDef.simple.fill_ratio : _.DecorationDef.__base, _.DecorationDef.fill_ratio.__partial, _.DecorationDef.simple.__partial +---@class _.DecorationDef.simple.noise_params : _.DecorationDef.__base, _.DecorationDef.noise_params.__partial, _.DecorationDef.simple.__partial + +--[[ +WIPDOC +]] +---@alias core.DecorationDef.simple +--- | _.DecorationDef.simple.fill_ratio +--- | _.DecorationDef.simple.noise_params + +---@class _.DecorationDef.simple.__partial +--[[ +Type. "simple", "schematic" or "lsystem" supported +]] +---@field deco_type "simple" +--[[ +The node name used as the decoration. +If instead a list of strings, a randomly selected node from the list +is placed as the decoration. +]] +---@field decoration OneOrMany +--[[ +*@default* `1` + +Decoration height in nodes. +If height_max is not 0, this is the lower limit of a randomly +selected height. +]] +---@field height integer? +--[[ +Upper limit of the randomly selected height. +If absent, the parameter 'height' is used as a constant. +]] +---@field height_max integer? +--[[ +*@default* `0` + +Param2 value of decoration nodes. +If param2_max is not 0, this is the lower limit of a randomly +selected param2. +]] +---@field param2 core.Param2? +--[[ +*@default* `0` + +Upper limit of the randomly selected param2. +If absent, the parameter 'param2' is used as a constant. +]] +---@field param2_max core.Param2? +--[[ +Y offset of the decoration base node relative to the standard base +node position. +Can be positive or negative. Default is 0. +Effect is inverted for "all_ceilings" decorations. +Ignored by 'y_min', 'y_max' and 'spawn_by' checks, which always refer +to the 'place_on' node. +]] +---@field place_offset_y integer? + +-- ------------------------- DecorationDef.schematic ------------------------ -- + +---@class _.DecorationDef.schematic.fill_ratio : _.DecorationDef.__base, _.DecorationDef.fill_ratio.__partial, _.DecorationDef.schematic.__partial +---@class _.DecorationDef.schematic.noise_params : _.DecorationDef.__base, _.DecorationDef.noise_params.__partial, _.DecorationDef.schematic.__partial + +--[[ +WIPDOC +]] +---@alias core.DecorationDef.schematic +--- | _.DecorationDef.schematic.fill_ratio +--- | _.DecorationDef.schematic.noise_params + +---@class _.DecorationDef.schematic.__partial +--[[ +Type. "simple", "schematic" or "lsystem" supported +]] +---@field deco_type "schematic" +--[[ +If schematic is a string, it is the filepath relative to the current +working directory of the specified Luanti schematic file. +Could also be the ID of a previously registered schematic. +]] +---@field schematic core.Schematic +--[[ +Map of node names to replace in the schematic after reading it. +]] +---@field replacements table? +--[[ +Rotation can be "0", "90", "180", "270", or "random" +]] +---@field rotation core.Schematic.rotation? +--[[ +Y offset of the decoration base node relative to the standard base +node position. +Can be positive or negative. Default is 0. +Effect is inverted for "all_ceilings" decorations. +Ignored by 'y_min', 'y_max' and 'spawn_by' checks, which always refer +to the 'place_on' node. +]] +---@field place_offset_y integer? +--[[ +WIPDOC +]] +---@field flags core.DecorationDef.schematic.flags + +-- -------------------------- DecorationDef.lsystem ------------------------- -- + +---@class _.DecorationDef.lsystem.fill_ratio : _.DecorationDef.__base, _.DecorationDef.fill_ratio.__partial, _.DecorationDef.lsystem.__partial +---@class _.DecorationDef.lsystem.noise_params : _.DecorationDef.__base, _.DecorationDef.noise_params.__partial, _.DecorationDef.lsystem.__partial + +--[[ +WIPDOC +]] +---@alias core.DecorationDef.lsystem +--- | _.DecorationDef.lsystem.fill_ratio +--- | _.DecorationDef.lsystem.noise_params + +---@class _.DecorationDef.lsystem.__partial +--[[ +Type. "simple", "schematic" or "lsystem" supported +]] +---@field deco_type "lsystem" +--[[ +Same as for `core.spawn_tree`. +See section [L-system trees] for more details. +]] +---@field treedef core.LSystemTreeDef + +-- ------------------------------ DecorationDef ----------------------------- -- + +---@alias core.DecorationDef +--- | core.DecorationDef.simple +--- | core.DecorationDef.schematic +--- | core.DecorationDef.lsystem \ No newline at end of file diff --git a/types/luanti_lsp_definitions/library/defs/decoration/flags.lua b/types/luanti_lsp_definitions/library/defs/decoration/flags.lua new file mode 100644 index 00000000..3423fed6 --- /dev/null +++ b/types/luanti_lsp_definitions/library/defs/decoration/flags.lua @@ -0,0 +1,96 @@ +---@meta _ +-- DRAFT 1 DONE +-- luanti/doc/lua_api.md: Flag Specifier Format +-- luanti/doc/lua_api.md: Decoration types +-- luanti/doc/lua_api.md: Mapgen objects +-- luanti/doc/lua_api.md: Definition tables > Decoration definition + +-- --------------------------- DecorationDef.flags -------------------------- -- + +---@class _.DecorationDef.flags.tablefmt.__base +--[[ +WIPDOC +]] +---@field force_placement boolean? +--[[ +WIPDOC +]] +---@field noforce_placement boolean? + +---@class _.DecorationDef.flags.tablefmt.liquid_surface : _.DecorationDef.flags.tablefmt.__base +--[[ +WIPDOC +]] +---@field liquid_surface boolean? +--[[ +WIPDOC +]] +---@field noliquid_surface boolean? + +---@class _.DecorationDef.flags.tablefmt.all : _.DecorationDef.flags.tablefmt.__base +--[[ +WIPDOC +]] +---@field all_floors boolean? +--[[ +WIPDOC +]] +---@field noall_floors boolean? +--[[ +WIPDOC +]] +---@field all_ceilings boolean? +--[[ +WIPDOC +]] +---@field noall_ceilings boolean? + +--[[ +WIPDOC +]] +---@alias core.DecorationDef.flags.tablefmt +--- | _.DecorationDef.flags.tablefmt.liquid_surface +--- | _.DecorationDef.flags.tablefmt.all + +--[[ +WIPDOC +]] +---@alias core.DecorationDef.flags.stringfmt string + +--[[ +WIPDOC +]] +---@alias core.DecorationDef.flags +--- | core.DecorationDef.flags.tablefmt +--- | core.DecorationDef.flags.stringfmt + +-- ------------------- core.DecorationDef.schematic.flags ------------------- -- + +--[[ +WIPDOC +]] +---@class core.DecorationDef.schematic.flags.tablefmt.liquid_surface : _.DecorationDef.flags.tablefmt.liquid_surface, core.Schematic.flags.tablefmt + +--[[ +WIPDOC +]] +---@class core.DecorationDef.schematic.flags.tablefmt.all : _.DecorationDef.flags.tablefmt.all, core.Schematic.flags.tablefmt + +--[[ +WIPDOC +]] +---@alias core.DecorationDef.schematic.flags.tablefmt +--- | core.DecorationDef.schematic.flags.tablefmt.liquid_surface +--- | core.DecorationDef.schematic.flags.tablefmt.all + +--[[ +WIPDOC +]] +---@alias core.DecorationDef.schematic.flags.stringfmt string + +--[[ +WIPDOC +]] +---@alias core.DecorationDef.schematic.flags +--- | core.DecorationDef.schematic.flags.tablefmt +--- | core.DecorationDef.schematic.flags.stringfmt \ No newline at end of file diff --git a/types/luanti_lsp_definitions/library/defs/detached_inventory.lua b/types/luanti_lsp_definitions/library/defs/detached_inventory.lua new file mode 100644 index 00000000..9f5b190e --- /dev/null +++ b/types/luanti_lsp_definitions/library/defs/detached_inventory.lua @@ -0,0 +1,62 @@ +---@meta _ +-- DRAFT 1 DONE +-- luanti/doc/lua_api.md: Definition tables > Detached inventory callbacks + +--[[ +WIPDOC +]] +---@alias core.DetachedInventoryCallbacks.allow_move fun(inv:core.InvRef, from_list:core.InventoryList, from_index:integer, to_list:core.InventoryList, to_index:integer, count:integer, player:core.PlayerRef):integer? + +--[[ +WIPDOC +]] +---@alias core.DetachedInventoryCallbacks.allow_put fun(inv:core.InvRef, listname:core.InventoryList, index:integer, stack:core.ItemStack, player:core.PlayerRef):integer? + +--[[ +WIPDOC +]] +---@alias core.DetachedInventoryCallbacks.allow_take fun(inv:core.InvRef, listname:core.InventoryList, index:integer, stack:core.ItemStack, player:core.PlayerRef):integer? + +--[[ +WIPDOC +]] +---@alias core.DetachedInventoryCallbacks.on_move fun(inv:core.InvRef, from_list:core.InventoryList, from_index:integer, to_list:core.InventoryList, to_index:integer, count:integer, player:core.PlayerRef) + +--[[ +WIPDOC +]] +---@alias core.DetachedInventoryCallbacks.on_put fun(inv:core.InvRef, listname:core.InventoryList, index:integer, stack:core.ItemStack, player:core.PlayerRef) + +--[[ +WIPDOC +]] +---@alias core.DetachedInventoryCallbacks.on_take fun(inv:core.InvRef, listname:core.InventoryList, index:integer, stack:core.ItemStack, player:core.PlayerRef) + +--[[ +WIPDOC +]] +---@class core.DetachedInventoryCallbacks +--[[ +WIPDOC +]] +---@field allow_move core.DetachedInventoryCallbacks.allow_move? +--[[ +WIPDOC +]] +---@field allow_put core.DetachedInventoryCallbacks.allow_put? +--[[ +WIPDOC +]] +---@field allow_take core.DetachedInventoryCallbacks.allow_take? +--[[ +WIPDOC +]] +---@field on_move core.DetachedInventoryCallbacks.on_move? +--[[ +WIPDOC +]] +---@field on_put core.DetachedInventoryCallbacks.on_put? +--[[ +WIPDOC +]] +---@field on_take core.DetachedInventoryCallbacks.on_take? diff --git a/types/luanti_lsp_definitions/library/defs/entity/collision.lua b/types/luanti_lsp_definitions/library/defs/entity/collision.lua new file mode 100644 index 00000000..86b55423 --- /dev/null +++ b/types/luanti_lsp_definitions/library/defs/entity/collision.lua @@ -0,0 +1,62 @@ +---@meta _ +-- DRAFT 1 DONE +-- luanti/doc/lua_api.md: Registered entities + +-- ------------------------- Entity.collision.__base ------------------------ -- + +---@class _.Entity.collision.__base +--[[ +WIPDOC +]] +---@field axis "x"|"y"|"z" +--[[ +WIPDOC +]] +---@field new_pos vector +--[[ +WIPDOC +]] +---@field old_velocity vector +--[[ +WIPDOC +]] +---@field new_velocity vector + +-- -------------------------- Entity.collision.node ------------------------- -- + +--[[ +WIPDOC +]] +---@class core.Entity.collision.node : _.Entity.collision.__base +--[[ +WIPDOC +]] +---@field type "node" +--[[ +WIPDOC +]] +---@field node_pos vector + +-- ------------------------- Entity.collision.object ------------------------ -- + +--[[ +WIPDOC +]] +---@class core.Entity.collision.object : _.Entity.collision.__base +--[[ +WIPDOC +]] +---@field type "object" +--[[ +WIPDOC +]] +---@field object core.ObjectRef + +-- ---------------------------- Entity.collision ---------------------------- -- + +--[[ +WIPDOC +]] +---@alias core.Entity.collision +--- | core.Entity.collision.node +--- | core.Entity.collision.object \ No newline at end of file diff --git a/types/luanti_lsp_definitions/library/defs/entity/entity.lua b/types/luanti_lsp_definitions/library/defs/entity/entity.lua new file mode 100644 index 00000000..ea16f9e2 --- /dev/null +++ b/types/luanti_lsp_definitions/library/defs/entity/entity.lua @@ -0,0 +1,140 @@ +---@meta _ +-- DRAFT 1 DONE +-- luanti/doc/lua_api.md: Registered entities +-- luanti/doc/lua_api.md: Definition tables > Entity definition + +--[[ +WIPDOC +]] +---@alias core.Entity.name string + +--[[ +WIPDOC +]] +---@alias core.Entity.namelike +--- | core.Groups.armor +--- | core.Entity.name + +-- -------------------------------- EntityDef ------------------------------- -- + +--[[ +WIPDOC +]] +---@alias core.EntityDef.on_activate fun(self:core.Entity, staticdata:string, dtime_s:number) + +--[[ +WIPDOC +]] +---@alias core.EntityDef.on_deactivate fun(self:core.Entity, removal:boolean) + +--[[ +WIPDOC +]] +---@alias core.EntityDef.on_step fun(self:core.Entity, dtime:number, moveresult:core.Entity.moveresult?) + +--[[ +WIPDOC +]] +---@alias core.EntityDef.on_punch fun(self:core.Entity, puncher:core.EntityRef?, ime_from_last_punch:number?, tool_capabilities:core.ToolCapabilities?, dir:vector, damage:integer):boolean + +--[[ +WIPDOC +]] +---@alias core.EntityDef.on_death fun(self:core.Entity, killer:core.EntityRef?) + +--[[ +WIPDOC +]] +---@alias core.EntityDef.on_rightclick fun(self:core.Entity, clicker:core.EntityRef) + +--[[ +WIPDOC +]] +---@alias core.EntityDef.on_attach_child fun(self:core.Entity, child:core.EntityRef) + +--[[ +WIPDOC +]] +---@alias core.EntityDef.on_detach_child fun(self:core.Entity, child:core.EntityRef) + +--[[ +WIPDOC +]] +---@alias core.EntityDef.on_detach fun(self:core.Entity, parent:core.EntityRef) + +--[[ +WIPDOC +]] +---@alias core.EntityDef.get_staticdata fun(self:core.Entity):string + +--[[ +WIPDOC +]] +---@class core.EntityDef +--[[ +WIPDOC +]] +---@field initial_properties core.ObjectProperties.set +--[[ +WIPDOC +]] +---@field on_activate core.EntityDef.on_activate? +--[[ +WIPDOC +]] +---@field on_deactivate core.EntityDef.on_deactivate? +--[[ +WIPDOC +]] +---@field on_step core.EntityDef.on_step? +--[[ +WIPDOC +]] +---@field on_punch core.EntityDef.on_punch? +--[[ +WIPDOC +]] +---@field on_death core.EntityDef.on_death? +--[[ +WIPDOC +]] +---@field on_rightclick core.EntityDef.on_rightclick? +--[[ +WIPDOC +]] +---@field on_attach_child core.EntityDef.on_attach_child? +--[[ +WIPDOC +]] +---@field on_detach_child core.EntityDef.on_detach_child? +--[[ +WIPDOC +]] +---@field on_detach core.EntityDef.on_detach? +--[[ +WIPDOC +]] +---@field get_staticdata core.EntityDef.get_staticdata? + +-- --------------------------------- Entity --------------------------------- -- + +--[[ +Functions receive a "luaentity" table as `self`: + +* It has the member `name`, which is the registered name `("mod:thing")` +* It has the member `object`, which is an `core.EntityRef` pointing to the object +* The original prototype is visible directly via a metatable +]] +---@class core.Entity : core.EntityDef +--[[ +WIPDOC +]] +---@field initial_properties core.ObjectProperties.set +--[[ +WIPDOC +]] +---@field name core.Entity.name +--[[ +WIPDOC +]] +---@field object core.EntityRef diff --git a/types/luanti_lsp_definitions/library/defs/entity/moveresult.lua b/types/luanti_lsp_definitions/library/defs/entity/moveresult.lua new file mode 100644 index 00000000..665f8350 --- /dev/null +++ b/types/luanti_lsp_definitions/library/defs/entity/moveresult.lua @@ -0,0 +1,26 @@ +---@meta _ +-- DRAFT 1 DONE +-- luanti/doc/lua_api.md: Registered entities + +-- ---------------------------- Entity.moveresult --------------------------- -- + +--[[ +WIPDOC +]] +---@class core.Entity.moveresult +--[[ +WIPDOC +]] +---@field touching_ground boolean +--[[ +WIPDOC +]] +---@field collides boolean +--[[ +WIPDOC +]] +---@field standing_on_object boolean +--[[ +WIPDOC +]] +---@field collisions core.Entity.collision[] diff --git a/types/luanti_lsp_definitions/library/defs/formspec.lua b/types/luanti_lsp_definitions/library/defs/formspec.lua new file mode 100644 index 00000000..a81b5212 --- /dev/null +++ b/types/luanti_lsp_definitions/library/defs/formspec.lua @@ -0,0 +1,8 @@ +---@meta _ +-- DRAFT 1 DONE +-- luanti/doc/lua_api.md: Formspec + +--[[ +WIPDOC +]] +---@alias core.Formspec string \ No newline at end of file diff --git a/types/luanti_lsp_definitions/library/defs/group.lua b/types/luanti_lsp_definitions/library/defs/group.lua new file mode 100644 index 00000000..a10f1d7a --- /dev/null +++ b/types/luanti_lsp_definitions/library/defs/group.lua @@ -0,0 +1,172 @@ +---@meta _ +-- DRAFT 1 DONE +-- luanti/doc/lua_api.md: Groups + +-- ------------------------------- Groups.item ------------------------------ -- + +--[[ +WIPDOC +]] +---@class core.Groups.item : {[string]:integer} +--[[ +WIPDOC +]] +---@field not_in_creative_inventory integer? + +-- ------------------------------- Groups.node ------------------------------ -- + +--[[ +WIPDOC +]] +---@alias core.Groups.special.attached_node +--- | 0 +--- | 1 +--- | 2 +--- | 3 +--- | 4 +--- | integer + +--[[ +WIPDOC +]] +---@alias core.Groups.special.dig_immediate +--- | 0 +--- | 1 +--- | 2 +--- | 3 +--- | integer + +--[[ +WIPDOC +]] +---@alias core.Groups.special.disable_jump +--- | 0 +--- | 1 +--- | integer + +--[[ +WIPDOC +]] +---@alias core.Groups.special.disable_descend +--- | 0 +--- | 1 +--- | integer + +--[[ +WIPDOC +]] +---@alias core.Groups.special.falling_node +--- | 0 +--- | 1 +--- | integer + +--[[ +WIPDOC +]] +---@alias core.Groups.special.float +--- | 0 +--- | 1 +--- | integer + +--[[ +WIPDOC +]] +---@class core.Groups.node : core.Groups.item +--[[ +WIPDOC +]] +---@field attached_node core.Groups.special.attached_node? +--[[ +WIPDOC +]] +---@field bouncy integer? +--[[ +WIPDOC +]] +---@field connect_to_raillike integer? +--[[ +WIPDOC +]] +---@field dig_immediate core.Groups.special.dig_immediate? +--[[ +WIPDOC +]] +---@field disable_jump core.Groups.special.disable_jump? +--[[ +WIPDOC +]] +---@field disable_descend core.Groups.special.disable_descend? +--[[ +WIPDOC +]] +---@field fall_damage_add_percent integer? +--[[ +WIPDOC +]] +---@field falling_node core.Groups.special.falling_node? +--[[ +WIPDOC +]] +---@field float core.Groups.special.float? +--[[ +WIPDOC +]] +---@field level integer? +--[[ +WIPDOC +]] +---@field slippery integer? + +-- ------------------------------- Groups.tool ------------------------------ -- + +--[[ +WIPDOC +]] +---@alias core.Groups.special.disable_repair +--- | 0 +--- | 1 +--- | integer + +--[[ +WIPDOC +]] +---@class core.Groups.tool : core.Groups.item +--[[ +WIPDOC +]] +---@field disable_repair core.Groups.special.disable_repair? + +-- ------------------------------ Groups.armor ------------------------------ -- + +--[[ +WIPDOC +]] +---@alias core.Groups.special.immortal +--- | 0 +--- | 1 +--- | integer + +--[[ +WIPDOC +]] +---@alias core.Groups.special.punch_operable +--- | 0 +--- | 1 +--- | integer + +--[[ +WIPDOC +]] +---@class core.Groups.armor : {[string]:integer} +--[[ +WIPDOC +]] +---@field immortal core.Groups.special.immortal? +--[[ +WIPDOC +]] +---@field fall_damage_add_percent integer? +--[[ +WIPDOC +]] +---@field punch_operable core.Groups.special.punch_operable? \ No newline at end of file diff --git a/types/luanti_lsp_definitions/library/defs/hud/compass.lua b/types/luanti_lsp_definitions/library/defs/hud/compass.lua new file mode 100644 index 00000000..c71c96ed --- /dev/null +++ b/types/luanti_lsp_definitions/library/defs/hud/compass.lua @@ -0,0 +1,65 @@ +---@meta _ +-- DRAFT 1 DONE +-- luanti/doc/lua_api.md: HUD +-- luanti/doc/lua_api.md: Definition tables > HUD Definition + +--[[ +WIPDOC +]] +---@alias core.HUDDef.compass.regular.direction +--- | 0 +--- | 1 + +--[[ +WIPDOC +]] +---@alias core.HUDDef.compass.scalable.direction +--- | 2 +--- | 3 + +--[[ +WIPDOC +]] +---@class core.HUDDef.compass.regular : _.HUDDef.__base, _.HUDDef.position, _.HUDDef.alignment +--[[ +WIPDOC +]] +---@field type "compass" +--[[ +* `direction`: How the image is rotated/translated: + * 0 - Rotate as heading direction + * 1 - Rotate in reverse direction + * 2 - Translate as landscape direction + * 3 - Translate in reverse direction + +If translation is chosen, texture is repeated horizontally to fill the whole element. +]] +---@field direction core.HUDDef.compass.regular.direction? +--[[ +WIPDOC +]] +---@field text string +--[[ +WIPDOC +]] +---@field size vec2.xy + +--[[ +WIPDOC +]] +---@class core.HUDDef.compass.scalable +--[[ +WIPDOC +]] +---@field scale vec2.xy? +--[[ +WIPDOC +]] +---@field direction core.HUDDef.compass.scalable.direction + +--[[ +WIPDOC +]] +---@alias core.HUDDef.compass +--- | core.HUDDef.compass.regular +--- | core.HUDDef.compass.scalable \ No newline at end of file diff --git a/types/luanti_lsp_definitions/library/defs/hud/hotbar.lua b/types/luanti_lsp_definitions/library/defs/hud/hotbar.lua new file mode 100644 index 00000000..818ee4c5 --- /dev/null +++ b/types/luanti_lsp_definitions/library/defs/hud/hotbar.lua @@ -0,0 +1,13 @@ +---@meta _ +-- DRAFT 1 DONE +-- luanti/doc/lua_api.md: HUD +-- luanti/doc/lua_api.md: Definition tables > HUD Definition + +--[[ +WIPDOC +]] +---@class core.HUDDef.hotbar : _.HUDDef.__base, _.HUDDef.position, _.HUDDef.direction, _.HUDDef.alignment +--[[ +WIPDOC +]] +---@field type "hotbar" diff --git a/types/luanti_lsp_definitions/library/defs/hud/hud.lua b/types/luanti_lsp_definitions/library/defs/hud/hud.lua new file mode 100644 index 00000000..cb3b2152 --- /dev/null +++ b/types/luanti_lsp_definitions/library/defs/hud/hud.lua @@ -0,0 +1,100 @@ +---@meta _ +-- DRAFT 1 DONE +-- luanti/doc/lua_api.md: HUD +-- luanti/doc/lua_api.md: Definition tables > HUD Definition + +--[[ +WIPDOC +]] +---@class core.HUDID : integer + +--[[ +WIPDOC +]] +---@alias core.HUDDef.keys +--- | "position" +--- | "name" +--- | "scale" +--- | "text" +--- | "text2" +--- | "number" +--- | "item" +--- | "direction" +--- | "alignment" +--- | "offset" +--- | "world_pos" +--- | "size" +--- | "z_index" +--- | "style" +--- | "precision" + +-- ------------------------------ HUDDef.__base ----------------------------- -- + +---@class _.HUDDef.__base +--[[ +WIPDOC +]] +---@field type "image" +--[[ +WIPDOC +]] +---@field name string +--[[ +WIPDOC +]] +---@field offset vec2.xy? +--[[ +WIPDOC +]] +---@field z_index integer + +-- ----------------------------- HUDDef partials ---------------------------- -- + +---@class _.HUDDef.position +--[[ +Top left corner position of element +]] +---@field position vec2.xy + +--[[ +WIPDOC +]] +---@alias core.HUDDef.direction +--- | 0 +--- | 1 +--- | 2 +--- | 3 + +---@class _.HUDDef.direction +--[[ +WIPDOC +]] +---@field direction core.HUDDef.direction? + +---@class _.HUDDef.alignment +--[[ +WIPDOC +]] +---@field alignment vec2.xy? + +---@class _.HUDDef.world_pos +--[[ +WIPDOC +]] +---@field world_pos vec? + +-- --------------------------------- HUDDef --------------------------------- -- + +--[[ +WIPDOC +]] +---@alias core.HUDDef +--- | core.HUDDef.image +--- | core.HUDDef.text +--- | core.HUDDef.statbar +--- | core.HUDDef.inventory +--- | core.HUDDef.hotbar +--- | core.HUDDef.waypoint +--- | core.HUDDef.image_waypoint +--- | core.HUDDef.compass +--- | core.HUDDef.minimap \ No newline at end of file diff --git a/types/luanti_lsp_definitions/library/defs/hud/image.lua b/types/luanti_lsp_definitions/library/defs/hud/image.lua new file mode 100644 index 00000000..80c4756f --- /dev/null +++ b/types/luanti_lsp_definitions/library/defs/hud/image.lua @@ -0,0 +1,21 @@ +---@meta _ +-- DRAFT 1 DONE +-- luanti/doc/lua_api.md: HUD +-- luanti/doc/lua_api.md: Definition tables > HUD Definition + +--[[ +WIPDOC +]] +---@class core.HUDDef.image : _.HUDDef.__base, _.HUDDef.position, _.HUDDef.alignment +--[[ +WIPDOC +]] +---@field type "image" +--[[ +WIPDOC +]] +---@field scale vec2.xy? +--[[ +WIPDOC +]] +---@field text string diff --git a/types/luanti_lsp_definitions/library/defs/hud/image_waypoint.lua b/types/luanti_lsp_definitions/library/defs/hud/image_waypoint.lua new file mode 100644 index 00000000..ce170979 --- /dev/null +++ b/types/luanti_lsp_definitions/library/defs/hud/image_waypoint.lua @@ -0,0 +1,24 @@ +---@meta _ +-- DRAFT 1 DONE +-- luanti/doc/lua_api.md: HUD +-- luanti/doc/lua_api.md: Definition tables > HUD Definition + +-- NOTE: while it *might* look like image_waypoint should derive from waypoint, +-- that is false. It's instead derived from image + +--[[ +WIPDOC +]] +---@class core.HUDDef.image_waypoint : _.HUDDef.__base, _.HUDDef.alignment, _.HUDDef.world_pos +--[[ +WIPDOC +]] +---@field type "image_waypoint" +--[[ +WIPDOC +]] +---@field scale vec2.xy? +--[[ +WIPDOC +]] +---@field text string diff --git a/types/luanti_lsp_definitions/library/defs/hud/inventory.lua b/types/luanti_lsp_definitions/library/defs/hud/inventory.lua new file mode 100644 index 00000000..1d4aec1a --- /dev/null +++ b/types/luanti_lsp_definitions/library/defs/hud/inventory.lua @@ -0,0 +1,25 @@ +---@meta _ +-- DRAFT 1 DONE +-- luanti/doc/lua_api.md: HUD +-- luanti/doc/lua_api.md: Definition tables > HUD Definition + +--[[ +WIPDOC +]] +---@class core.HUDDef.inventory : _.HUDDef.__base, _.HUDDef.position, _.HUDDef.direction, _.HUDDef.alignment +--[[ +WIPDOC +]] +---@field type "inventory" +--[[ +WIPDOC +]] +---@field text string +--[[ +WIPDOC +]] +---@field number integer? +--[[ +WIPDOC +]] +---@field item integer? diff --git a/types/luanti_lsp_definitions/library/defs/hud/minimap.lua b/types/luanti_lsp_definitions/library/defs/hud/minimap.lua new file mode 100644 index 00000000..562693b3 --- /dev/null +++ b/types/luanti_lsp_definitions/library/defs/hud/minimap.lua @@ -0,0 +1,17 @@ +---@meta _ +-- DRAFT 1 DONE +-- luanti/doc/lua_api.md: HUD +-- luanti/doc/lua_api.md: Definition tables > HUD Definition + +--[[ +WIPDOC +]] +---@class core.HUDDef.minimap : _.HUDDef.__base, _.HUDDef.position, _.HUDDef.alignment +--[[ +WIPDOC +]] +---@field type "minimap" +--[[ +WIPDOC +]] +---@field size vec2.xy? diff --git a/types/luanti_lsp_definitions/library/defs/hud/statbar.lua b/types/luanti_lsp_definitions/library/defs/hud/statbar.lua new file mode 100644 index 00000000..7a03834d --- /dev/null +++ b/types/luanti_lsp_definitions/library/defs/hud/statbar.lua @@ -0,0 +1,33 @@ +---@meta _ +-- DRAFT 1 DONE +-- luanti/doc/lua_api.md: HUD +-- luanti/doc/lua_api.md: Definition tables > HUD Definition + +--[[ +WIPDOC +]] +---@class core.HUDDef.statbar : _.HUDDef.__base, _.HUDDef.position, _.HUDDef.direction +--[[ +WIPDOC +]] +---@field type "statbar" +--[[ +WIPDOC +]] +---@field text string +--[[ +WIPDOC +]] +---@field text2 string? +--[[ +WIPDOC +]] +---@field number integer +--[[ +WIPDOC +]] +---@field item integer +--[[ +WIPDOC +]] +---@field size vec2.xy? diff --git a/types/luanti_lsp_definitions/library/defs/hud/text.lua b/types/luanti_lsp_definitions/library/defs/hud/text.lua new file mode 100644 index 00000000..60239905 --- /dev/null +++ b/types/luanti_lsp_definitions/library/defs/hud/text.lua @@ -0,0 +1,46 @@ +---@meta _ +-- DRAFT 1 DONE +-- luanti/doc/lua_api.md: HUD +-- luanti/doc/lua_api.md: Definition tables > HUD Definition + +--[[ +WIPDOC +]] +---@alias core.HUDDef.text.style +--- | 0 +--- | 1 +--- | 2 +--- | 3 +--- | 4 +--- | 5 +--- | 6 +--- | 7 + +--[[ +WIPDOC +]] +---@class core.HUDDef.text : _.HUDDef.__base, _.HUDDef.position, _.HUDDef.alignment +--[[ +WIPDOC +]] +---@field type "text" +--[[ +WIPDOC +]] +---@field scale vec2.xy +--[[ +WIPDOC +]] +---@field text string +--[[ +WIPDOC +]] +---@field number integer? +--[[ +WIPDOC +]] +---@field size vec2.xy? +--[[ +WIPDOC +]] +---@field style core.HUDDef.text.style? diff --git a/types/luanti_lsp_definitions/library/defs/hud/waypoint.lua b/types/luanti_lsp_definitions/library/defs/hud/waypoint.lua new file mode 100644 index 00000000..aa18999e --- /dev/null +++ b/types/luanti_lsp_definitions/library/defs/hud/waypoint.lua @@ -0,0 +1,25 @@ +---@meta _ +-- DRAFT 1 DONE +-- luanti/doc/lua_api.md: HUD +-- luanti/doc/lua_api.md: Definition tables > HUD Definition + +--[[ +WIPDOC +]] +---@class core.HUDDef.waypoint : _.HUDDef.__base, _.HUDDef.position, _.HUDDef.alignment, _.HUDDef.world_pos +--[[ +WIPDOC +]] +---@field type "waypoint" +--[[ +WIPDOC +]] +---@field text string? +--[[ +WIPDOC +]] +---@field precision integer? +--[[ +WIPDOC +]] +---@field number integer? diff --git a/types/luanti_lsp_definitions/library/defs/inventory.lua b/types/luanti_lsp_definitions/library/defs/inventory.lua new file mode 100644 index 00000000..4304d3fa --- /dev/null +++ b/types/luanti_lsp_definitions/library/defs/inventory.lua @@ -0,0 +1,83 @@ +---@meta _ +-- DRAFT 1 DONE +-- luanti/doc/lua_api.md: Inventory +-- luanti/doc/lua_api.md: Class reference > `InvRef` +-- luanti/doc/lua_api.md: Class reference > `MetaDataRef` + +-- ------------------------------ InventoryList ----------------------------- -- + +--[[ +WIPDOC +]] +---@alias core.InventoryList +--- | "main" +--- | "craft" +--- | "craftpreview" +--- | "craftresult" +--- | "hand" +--- | string + +-- -------------------------------- InventoryTable -------------------------------- -- + +--[[ +WIPDOC +]] +---@alias core.ItemList.stringfmt SparseList + +--[[ +WIPDOC +]] +---@class core.InventoryTable.stringfmt : {[core.InventoryList]:core.ItemList.stringfmt?} +--[[ +WIPDOC +]] +---@field main core.ItemList.stringfmt? +--[[ +WIPDOC +]] +---@field craft core.ItemList.stringfmt? +--[[ +WIPDOC +]] +---@field craftpreview core.ItemList.stringfmt? +--[[ +WIPDOC +]] +---@field craftresult core.ItemList.stringfmt? +--[[ +WIPDOC +]] +---@field hand core.ItemList.stringfmt? + +--[[ +WIPDOC +]] +---@alias core.ItemList SparseList + +--[[ +* inventory table keys are inventory list names +* inventory table values are item tables +* item table keys are slot IDs (starting with 1) +* item table values are ItemStacks +]] +---@class core.InventoryTable : {[core.InventoryList]:core.ItemList} +--[[ +WIPDOC +]] +---@field main core.ItemList? +--[[ +WIPDOC +]] +---@field craft core.ItemList? +--[[ +WIPDOC +]] +---@field craftpreview core.ItemList? +--[[ +WIPDOC +]] +---@field craftresult core.ItemList? +--[[ +WIPDOC +]] +---@field hand core.ItemList? \ No newline at end of file diff --git a/types/luanti_lsp_definitions/library/defs/item/item.lua b/types/luanti_lsp_definitions/library/defs/item/item.lua new file mode 100644 index 00000000..09c4db21 --- /dev/null +++ b/types/luanti_lsp_definitions/library/defs/item/item.lua @@ -0,0 +1,70 @@ +---@meta _ +-- DRAFT 1 DONE +-- luanti/doc/lua_api.md: Items + +--[[ +WIPDOC +]] +---@alias core.Tool.name +--- | string + +--[[ +WIPDOC +]] +---@alias core.Item.name +--- | "" +--- | core.Tool.name +--- | core.Node.name + +--[[ +WIPDOC +]] +---@alias core.Item.namelike +--- | core.Groups.item +--- | core.Groups.tool +--- | core.Item.name + +--[[ +WIPDOC +]] +---@alias core.Tool.wear integer + +--[[ +WIPDOC +]] +---@class core.Item.tablefmt +--[[ +WIPDOC +]] +---@field name core.Item.name +--[[ +WIPDOC +]] +---@field count integer? +--[[ +WIPDOC +]] +---@field wear core.Tool.wear? +--[[ +WIPDOC +]] +---@field metadata string? + +--[[ +WIPDOC +]] +---@alias core.Item.stringfmt string + +--[[ +WIPDOC +]] +---@alias core.Item.simple +--- | core.Item.tablefmt +--- | core.Item.stringfmt + +--[[ +WIPDOC +]] +---@alias core.Item +--- | core.Item.simple +--- | core.ItemStack \ No newline at end of file diff --git a/types/luanti_lsp_definitions/library/defs/item/itemdef.lua b/types/luanti_lsp_definitions/library/defs/item/itemdef.lua new file mode 100644 index 00000000..d01e9717 --- /dev/null +++ b/types/luanti_lsp_definitions/library/defs/item/itemdef.lua @@ -0,0 +1,282 @@ +---@meta _ +-- DRAFT 1 DONE +-- luanti/doc/lua_api.md: Items +-- luanti/doc/lua_api.md: Definition tables > Item definition + +--[[ +WIPDOC +]] +---@alias core.ItemDef.keys +--- | "description" +--- | "short_description" +--- | "groups" +--- | "inventory_image" +--- | "inventory_overlay" +--- | "wield_image" +--- | "wield_overlay" +--- | "wield_scale" +--- | "palette" +--- | "color" +--- | "stack_max" +--- | "range" +--- | "liquids_pointable" +--- | "pointabilities" +--- | "light_source" +--- | "tool_capabilities" +--- | "wear_color" +--- | "node_placement_prediction" +--- | "node_dig_prediction" +--- | "touch_interaction" +--- | "sounds" +--- | "on_place" +--- | "on_secondary_use" +--- | "on_drop" +--- | "on_pickup" +--- | "on_use" +--- | "after_use" + +-- --------------------------------- ToolDef -------------------------------- -- +--[[ +WIPDOC +]] +---@class core.ToolDef : core.ItemDef +--[[ +WIPDOC +]] +---@field tool_capabilities core.ToolCapabilities + +-- ------------------------------- description ------------------------------ -- + +--[[ +WIPDOC +]] +---@class core.ItemDef +--[[ +Can contain new lines. "\n" has to be used as new line character. +See also: `get_description` in [`ItemStack`] +]] +---@field description string? +--[[ +Must not contain new lines. +Defaults to nil. +Use an [`ItemStack`] to get the short description, e.g.: + ItemStack(itemname):get_short_description() +]] +---@field short_description string? + +-- -------------------------------------------------------------------------- -- + +---@class core.ItemDef +--[[ +key = name, value = rating; rating = . +If rating not applicable, use 1. +e.g. {wool = 1, fluffy = 3} + {soil = 2, outerspace = 1, crumbly = 1} + {bendy = 2, snappy = 1}, + {hard = 1, metal = 1, spikes = 1} +]] +---@field groups core.Groups.item? + + +-- ------------------------ inventory and wield image ----------------------- -- + +---@class core.ItemDef +--[[ +Texture shown in the inventory GUI +Defaults to a 3D rendering of the node if left empty. +]] +---@field inventory_image core.Texture? +--[[ +An overlay texture which is not affected by colorization +]] +---@field inventory_overlay core.Texture? +--[[ +Texture shown when item is held in hand +Defaults to a 3D rendering of the node if left empty. +]] +---@field wield_image core.Texture? +--[[ +Like inventory_overlay but only used in the same situation as wield_image +]] +---@field wield_overlay core.Texture? +--[[ +Scale for the item when held in hand +]] +---@field wield_scale vector? +--[[ +An image file containing the palette of a node. +You can set the currently used color as the "palette_index" field of +the item stack metadata. +The palette is always stretched to fit indices between 0 and 255, to +ensure compatibility with "colorfacedir" (and similar) nodes. +]] +---@field palette core.Texture? +--[[ +Color the item is colorized with. The palette overrides this. +]] +---@field color core.ColorSpec? + +-- -------------------------------------------------------------------------- -- + +---@class core.ItemDef +--[[ +Maximum amount of items that can be in a single stack. +The default can be changed by the setting `default_stack_max` +]] +---@field stack_max integer? + +-- ----------------------------- pointabilities ----------------------------- -- + +---@class core.ItemDef +--[[ +Range of node and object pointing that is possible with this item held +Can be overridden with itemstack meta. +]] +---@field range number? +--[[ +If true, item can point to all liquid nodes (`liquidtype ~= "none"`), +even those for which `pointable = false` +]] +---@field liquids_pointable boolean? + +--[[ ItemDef.pointabilities split off into ./pointabilities.lua ]]-- + +-- -------------------------------------------------------------------------- -- + +--[[ +WIPDOC +]] +core.LIGHT_MAX = 14 + +---@class core.ItemDef +--[[ +When used for nodes: Defines amount of light emitted by node. +Otherwise: Defines texture glow when viewed as a dropped item +To set the maximum (14), use the value 'core.LIGHT_MAX'. +A value outside the range 0 to core.LIGHT_MAX causes undefined +behavior. +]] +---@field light_source core.Light.source? +--[[ +See "Tool Capabilities" section for an example including explanation +]] +---@field tool_capabilities core.ToolCapabilities? +--[[ +Set wear bar color of the tool by setting color stops and blend mode +See "Wear Bar Color" section for further explanation including an example +]] +---@field wear_color core.WearBarColor? +--[[ +If nil and item is node, prediction is made automatically. +If nil and item is not a node, no prediction is made. +If "" and item is anything, no prediction is made. +Otherwise should be name of node which the client immediately places +on ground when the player places the item. Server will always update +with actual result shortly. +]] +---@field node_placement_prediction core.Node.name? +--[[ +if "", no prediction is made. +if "air", node is removed. +Otherwise should be name of node which the client immediately places +upon digging. Server will always update with actual result shortly. +]] +---@field node_dig_prediction core.Node.name? + +--[[ ItemDef.touch_interaction split off into ./touch_interaction.lua ]]-- + +--[[ ItemDef.sound split off into ./sound.lua ]]-- + +-- -------------------------------- callbacks ------------------------------- -- + +--[[ +When the 'place' key was pressed with the item in hand +and a node was pointed at. +Shall place item and return the leftover itemstack +or nil to not modify the inventory. +The placer may be any ObjectRef or nil. +default: core.item_place +]] +---@alias core.ItemDef.on_place fun(itemstack:core.ItemStack, placer:core.ObjectRef?, pointed_thing:core.PointedThing): core.ItemStack? + +--[[ +Same as on_place but called when not pointing at a node. +Function must return either nil if inventory shall not be modified, +or an itemstack to replace the original itemstack. +The user may be any ObjectRef or nil. +default: nil +]] +---@alias core.ItemDef.on_secondary_use fun(itemstack:core.ItemStack, user:core.ObjectRef?, pointed_thing:core.PointedThing): core.ItemStack? + +--[[ +Shall drop item and return the leftover itemstack. +The dropper may be any ObjectRef or nil. +default: core.item_drop +]] +---@alias core.ItemDef.on_drop fun(itemstack:core.ItemStack, dropper:core.ObjectRef?, pos:vec): core.ItemStack? + +--[[ +Called when a dropped item is punched by a player. +Shall pick-up the item and return the leftover itemstack or nil to not +modify the dropped item. +Parameters: +* `itemstack`: The `ItemStack` to be picked up. +* `picker`: Any `ObjectRef` or `nil`. +* `pointed_thing` (optional): The dropped item (a `"__builtin:item"` + luaentity) as `type="object"` `pointed_thing`. +* `time_from_last_punch, ...` (optional): Other parameters from + `luaentity:on_punch`. +default: `core.item_pickup` +]] +---@alias core.ItemDef.on_pickup fun(itemstack: core.ItemStack, picker:core.ObjectRef?, pointed_thing:core.PointedThing?, time_from_last_punch:number?, tool_capabilities:core.ToolCapabilities?, dir:vec?, damage:integer?): core.ItemStack? + +--[[ +default: nil +When user pressed the 'punch/mine' key with the item in hand. +Function must return either nil if inventory shall not be modified, +or an itemstack to replace the original itemstack. +e.g. itemstack:take_item(); return itemstack +Otherwise, the function is free to do what it wants. +The user may be any ObjectRef or nil. +The default functions handle regular use cases. +]] +---@alias core.ItemDef.on_use fun(itemstack:core.ItemStack, user:core.ObjectRef?, pointed_thing:core.PointedThing): core.ItemStack? + +--[[ +default: nil +If defined, should return an itemstack and will be called instead of +wearing out the item (if tool). If returns nil, does nothing. +If after_use doesn't exist, it is the same as: + function(itemstack, user, node, digparams) + itemstack:add_wear(digparams.wear) + return itemstack + end +The user may be any ObjectRef or nil. +]] +---@alias core.ItemDef.after_use fun(itemstack:core.ItemStack, user:core.ObjectRef?, node:core.Node.get, digparams:core.DigParams): core.ItemStack? + +---@class core.ItemDef +--[[ +WIPDOC +]] +---@field on_place core.ItemDef.on_place? +--[[ +WIPDOC +]] +---@field on_secondary_use core.ItemDef.on_secondary_use? +--[[ +WIPDOC +]] +---@field on_drop core.ItemDef.on_drop? +--[[ +WIPDOC +]] +---@field on_pickup core.ItemDef.on_pickup? +--[[ +WIPDOC +]] +---@field on_use core.ItemDef.on_use? +--[[ +WIPDOC +]] +---@field after_use core.ItemDef.after_use? \ No newline at end of file diff --git a/types/luanti_lsp_definitions/library/defs/item/pointabilities.lua b/types/luanti_lsp_definitions/library/defs/item/pointabilities.lua new file mode 100644 index 00000000..67326ac9 --- /dev/null +++ b/types/luanti_lsp_definitions/library/defs/item/pointabilities.lua @@ -0,0 +1,43 @@ +---@meta _ +-- DRAFT 1 DONE +-- luanti/doc/lua_api.md: Definition tables > Item definition + +-- ------------------------- ItemDef.pointabilities ------------------------- -- + +--[[ +WIPDOC +]] +---@alias core.ItemDef.pointabilities.value +--- | boolean +--- | "blocking" + +--[[ +WIPDOC +]] +---@class core.ItemDef.pointabilities +--[[ +WIPDOC +]] +---@field nodes table +--[[ +WIPDOC +]] +---@field objects table> + + +-- ----------------------------- ItemDef fields ----------------------------- -- + +---@class core.ItemDef +--[[ +Contains lists to override the `pointable` property of nodes and objects. +The index can be a node/entity name or a group with the prefix `"group:"`. +(For objects `armor_groups` are used and for players the entity name is irrelevant.) +If multiple fields fit, the following priority order is applied: +1. value of matching node/entity name +2. `true` for any group +3. `false` for any group +4. `"blocking"` for any group +5. `liquids_pointable` if it is a liquid node +6. `pointable` property of the node or object +]] +---@field pointabilities core.ItemDef.pointabilities? diff --git a/types/luanti_lsp_definitions/library/defs/item/sound.lua b/types/luanti_lsp_definitions/library/defs/item/sound.lua new file mode 100644 index 00000000..4ae7e52f --- /dev/null +++ b/types/luanti_lsp_definitions/library/defs/item/sound.lua @@ -0,0 +1,34 @@ +---@meta _ +-- DRAFT 1 DONE +-- luanti/doc/lua_api.md: Definition tables > Item definition + +-- ------------------------------ ItemDef.sound ----------------------------- -- + +--[[ +WIPDOC +]] +---@class core.ItemDef.sound +--[[ +WIPDOC +]] +---@field breaks core.SimpleSoundSpec? +--[[ +WIPDOC +]] +---@field eat core.SimpleSoundSpec? +--[[ +WIPDOC +]] +---@field punch_use core.SimpleSoundSpec? +--[[ +WIPDOC +]] +---@field punch_use_air core.SimpleSoundSpec? + +-- ----------------------------- ItemDef fields ----------------------------- -- + +---@class core.ItemDef +--[[ +WIPDOC +]] +---@field sound core.ItemDef.sound? diff --git a/types/luanti_lsp_definitions/library/defs/item/touch_interaction.lua b/types/luanti_lsp_definitions/library/defs/item/touch_interaction.lua new file mode 100644 index 00000000..1998a121 --- /dev/null +++ b/types/luanti_lsp_definitions/library/defs/item/touch_interaction.lua @@ -0,0 +1,55 @@ +---@meta _ +-- DRAFT 1 DONE +-- luanti/doc/lua_api.md: Definition tables > Item definition + +-- ------------------------ ItemDef.touch_interaction ----------------------- -- + +---@alias core.ItemDef.touch_interaction.mode +--- | "long_dig_short_place" +--- | "short_dig_long_place" +--- | "user" + +---@class core.ItemDef.touch_interaction.pointed_thing +--[[ +WIPDOC +]] +---@field pointed_nothing core.ItemDef.touch_interaction.mode? +--[[ +WIPDOC +]] +---@field pointed_node core.ItemDef.touch_interaction.mode? +--[[ +WIPDOC +]] +---@field pointed_object core.ItemDef.touch_interaction.mode? + +--[[ +WIPDOC +]] +---@alias core.ItemDef.touch_interaction +--- | core.ItemDef.touch_interaction.mode +--- | core.ItemDef.touch_interaction.pointed_thing + +-- ----------------------------- ItemDef fields ----------------------------- -- + +---@class core.ItemDef +--[[ +Only affects touchscreen clients. +Defines the meaning of short and long taps with the item in hand. +If specified as a table, the field to be used is selected according to +the current `pointed_thing`. +There are three possible TouchInteractionMode values: +* "long_dig_short_place" (long tap = dig, short tap = place) +* "short_dig_long_place" (short tap = dig, long tap = place) +* "user": + * For `pointed_object`: Equivalent to "short_dig_long_place" if the + client-side setting "touch_punch_gesture" is "short_tap" (the + default value) and the item is able to punch (i.e. has no on_use + callback defined). + Equivalent to "long_dig_short_place" otherwise. + * For `pointed_node` and `pointed_nothing`: + Equivalent to "long_dig_short_place". + * The behavior of "user" may change in the future. +The default value is "user". +]] +---@field touch_interaction core.ItemDef.touch_interaction? diff --git a/types/luanti_lsp_definitions/library/defs/lbm.lua b/types/luanti_lsp_definitions/library/defs/lbm.lua new file mode 100644 index 00000000..5714a51a --- /dev/null +++ b/types/luanti_lsp_definitions/library/defs/lbm.lua @@ -0,0 +1,96 @@ +---@meta _ +-- DRAFT 1 DONE +-- luanti/doc/lua_api.md: Definition tables > LBM (LoadingBlockModifier) definition + +-- ------------------------------ LBMDef.__base ----------------------------- -- + +--[[ +LBM (LoadingBlockModifier) definition +------------------------------------- + +Used by `core.register_lbm`. + +A loading block modifier (LBM) is used to define a function that is called for +specific nodes (defined by `nodenames`) when a mapblock which contains such nodes +gets **activated** (**not loaded!**). + +*Note*: LBMs operate on a "snapshot" of node positions taken once before they are triggered. +That means if an LBM callback adds a node, it won't be taken into account. +However the engine guarantees that at the point in time when the callback is called +that all given positions contain a matching node. + +For `run_at_every_load = false` to work, both mapblocks and LBMs have timestamps +associated with them: + +* Each mapblock has a "last active" timestamp. It is also updated when the + mapblock is generated. +* For each LBM, an introduction timestamp is stored in the world data, identified + by the LBM's `name` field. If an LBM disappears, the corresponding timestamp + is cleared. + +When a mapblock is activated, only LBMs whose introduction timestamp is newer +than the mapblock's timestamp are run. + +*Note*: For maps generated in 5.11.0 or older, many newly generated mapblocks +did not get a timestamp set. This means LBMs introduced between generation time +and time of first activation will never run. +Currently the only workaround is to use `run_at_every_load = true`. +]] +---@class _.LBMDef.__base +--[[ +Descriptive label for profiling purposes (optional). +Definitions with identical labels will be listed as one. +]] +---@field label string? +--[[ +Identifier of the LBM, should follow the modname: convention +]] +---@field name string? +--[[ +List of node names to trigger the LBM on. +]] +---@field nodenames core.Node.namelike[]? +--[[ +If `false`: The LBM only runs on mapblocks the first time they are +activated after the LBM was introduced. +It never runs on mapblocks generated after the LBM's introduction. +See above for details. + +If `true`: The LBM runs every time a mapblock is activated. +]] +---@field run_at_every_load boolean? + +-- --------------------------------- LBMDef --------------------------------- -- + +--[[ +WIPDOC +]] +---@alias core.LBMDef.action.fn fun(pos:ivec, node:core.Node.get, dtime_s:number) + +---@class core.LBMDef.action : _.LBMDef.__base +--[[ +Function triggered for each qualifying node. + +`dtime_s` is the in-game time (in seconds) elapsed since the mapblock +was last active (available since 5.7.0). +]] +---@field action core.LBMDef.action.fn + +--[[ +WIPDOC +]] +---@alias core.LBMDef.bulk_action.fn fun(pos_list:ivec[], dtime_s:number) + +---@class core.LBMDef.bulk_action : _.LBMDef.__base +--[[ +Function triggered with a list of all applicable node positions at once. + +This can be provided as an alternative to `action` (not both). +Available since `core.features.bulk_lbms` (5.10.0) +`dtime_s`: as above +]] +---@field bulk_action core.LBMDef.bulk_action.fn + +---@alias core.LBMDef +--- | core.LBMDef.action +--- | core.LBMDef.bulk_action \ No newline at end of file diff --git a/types/luanti_lsp_definitions/library/defs/lsystem.lua b/types/luanti_lsp_definitions/library/defs/lsystem.lua new file mode 100644 index 00000000..b9415cfe --- /dev/null +++ b/types/luanti_lsp_definitions/library/defs/lsystem.lua @@ -0,0 +1,126 @@ +---@meta _ +-- DRAFT 1 DONE +-- luanti/doc/lua_api.md: L-system trees + +--[[ +## Key for special L-System symbols + +* `G`: move forward one unit with the pen up +* `F`: move forward one unit with the pen down drawing trunks and branches +* `f`: move forward one unit with the pen down drawing leaves (100% chance) +* `T`: move forward one unit with the pen down drawing trunks only +* `R`: move forward one unit with the pen down placing fruit +* `A`: replace with rules set A +* `B`: replace with rules set B +* `C`: replace with rules set C +* `D`: replace with rules set D +* `a`: replace with rules set A, chance 90% +* `b`: replace with rules set B, chance 80% +* `c`: replace with rules set C, chance 70% +* `d`: replace with rules set D, chance 60% +* `+`: yaw the turtle right by `angle` parameter +* `-`: yaw the turtle left by `angle` parameter +* `&`: pitch the turtle down by `angle` parameter +* `^`: pitch the turtle up by `angle` parameter +* `/`: roll the turtle to the right by `angle` parameter +* `*`: roll the turtle to the left by `angle` parameter +* `[`: save in stack current state info +* `]`: recover from stack state info + +[L-System Trees on docs.luanti.org](https://docs.luanti.org/for-creators/l-system-trees/) +]] +---@alias core.LsystemTreeDef.rules string + +--[[ +WIPDOC +]] +---@alias core.LSystemTreeDef.trunk_type +--- | "single" +--- | "double" +--- | "crossed" + +--[[ +**LIBDEF REVISION** + +L-system trees in Luanti are procedurally generated trees defined by a set of +rules rather than fixed shapes. They use an axiom (starting string) and +recursive replacement rules based on L-systems. One way to interpret is to +compare it to turtle graphics. This allows complex, natural-looking trees with +branching, leaves, and fruit to be created from relatively small definitions. + +[L-System Trees on docs.luanti.org](https://docs.luanti.org/for-creators/l-system-trees/) +]] +---@class core.LSystemTreeDef +--[[ +Initial tree axiom +]] +---@field axiom core.LsystemTreeDef.rules +--[[ +Rules set A +]] +---@field rules_a core.LsystemTreeDef.rules? +--[[ +Rules set B +]] +---@field rules_b core.LsystemTreeDef.rules? +--[[ +Rules set C +]] +---@field rules_c core.LsystemTreeDef.rules? +--[[ +Rules set D +]] +---@field rules_d core.LsystemTreeDef.rules? +--[[ +Trunk node name (default: `"ignore"`) +]] +---@field trunk core.Node.name? +--[[ +Leaves node name (default: `"ignore"`) +]] +---@field leaves core.Node.name? +--[[ +Secondary leaves node name (default: `"ignore"`) +]] +---@field leaves2 core.Node.name? +--[[ +Chance (0-100) to replace leaves with leaves2 (default: 0) +]] +---@field leaves2_chance integer? +--[[ +Angle in deg (default: 0) +]] +---@field angle integer? +--[[ +Max # of iterations, usually 2 -5 (default 0) +]] +---@field iterations integer? +--[[ +Factor to lower number of iterations, usually 0 - 3 (default: 0) +]] +---@field random_level integer? +--[[ +**LIBDEF REVISION** + +Type of trunk: +- `"single"` (default): 1 node +- `"double"`: 2x2 nodes +- `"crossed"`: 3x3 in cross shape +]] +---@field trunk_type core.LSystemTreeDef.trunk_type? +--[[ +Whether to use thin (1 node) branches (default: `false`) +]] +---@field thin_branches boolean? +--[[ +Fruit node name. (default: `"air"`) +]] +---@field fruit core.Node.name? +--[[ +Chance (0-100) to replace leaves with fruit node (default: 0) +]] +---@field fruit_chance integer? +--[[ +Random seed, if no seed is provided, the engine will create one. +]] +---@field seed integer \ No newline at end of file diff --git a/types/luanti_lsp_definitions/library/defs/mapgen_objects.lua b/types/luanti_lsp_definitions/library/defs/mapgen_objects.lua new file mode 100644 index 00000000..ee7c203d --- /dev/null +++ b/types/luanti_lsp_definitions/library/defs/mapgen_objects.lua @@ -0,0 +1,158 @@ +---@meta _ +-- DRAFT 1 DONE +-- luanti/doc/lua_api.md: Mapgen objects + +-- ----------------------------- GenNotify.flags ---------------------------- -- + +--[[ +WIPDOC +]] +---@class core.GenNotify.flags.tablefmt : {[string]:boolean?} +--[[ +WIPDOC +]] +---@field dungeon boolean? +--[[ +WIPDOC +]] +---@field nodungeon boolean? +--[[ +WIPDOC +]] +---@field temple boolean? +--[[ +WIPDOC +]] +---@field notemple boolean? +--[[ +WIPDOC +]] +---@field cave_begin boolean? +--[[ +WIPDOC +]] +---@field nocave_begin boolean? +--[[ +WIPDOC +]] +---@field cave_end boolean? +--[[ +WIPDOC +]] +---@field nocave_end boolean? +--[[ +WIPDOC +]] +---@field large_cave_begin boolean? +--[[ +WIPDOC +]] +---@field nolarge_cave_begin boolean? +--[[ +WIPDOC +]] +---@field large_cave_end boolean? +--[[ +WIPDOC +]] +---@field nolarge_cave_end boolean? +--[[ +WIPDOC +]] +---@field custom boolean? +--[[ +WIPDOC +]] +---@field nocustom boolean? +--[[ +WIPDOC +]] +---@field decoration boolean? +--[[ +WIPDOC +]] +---@field nodecoration boolean? + +--[[ +WIPDOC +]] +---@alias core.GenNotify.flags.stringfmt string + +--[[ +WIPDOC +]] +---@alias core.GenNotify.flags +--- | core.GenNotify.flags.tablefmt +--- | core.GenNotify.flags.stringfmt + +-- -------------------------------- GenNotify ------------------------------- -- + +--[[ +WIPDOC +]] +---@alias core.GenNotify.key.decoration string + +--[[ +Returns a table. You need to announce your interest in a specific +field by calling `core.set_gen_notify()` *before* map generation happens. + +* key = string: generation notification type +* value = list of positions (usually) + * Exceptions are denoted in the listing below. + +Available generation notification types: + +* `dungeon`: bottom center position of dungeon rooms +* `temple`: as above but for desert temples (mgv6 only) +* `cave_begin` +* `cave_end` +* `large_cave_begin` +* `large_cave_end` +* `custom`: data originating from [Mapgen environment](#mapgen-environment) (Lua API) + * This is a table. + * key = user-defined ID (string) + * value = arbitrary Lua value +* `decoration#id`: decorations + * (see below) + +Decorations have a key in the format of `"decoration#id"`, where `id` is the +numeric unique decoration ID as returned by `core.get_decoration_id()`. +For example, `decoration#123`. + +The returned positions are the ground surface 'place_on' nodes, +not the decorations themselves. A 'simple' type decoration is often 1 +node above the returned position and possibly displaced by 'place_offset_y'. +]] +---@class core.GenNotify +--[[ +WIPDOC +]] +---@field dungeon ivec? +--[[ +WIPDOC +]] +---@field temple ivec? +--[[ +WIPDOC +]] +---@field cave_begin ivec? +--[[ +WIPDOC +]] +---@field cave_end ivec? +--[[ +WIPDOC +]] +---@field large_cave_begin ivec? +--[[ +WIPDOC +]] +---@field large_cave_end ivec? +--[[ +WIPDOC +]] +---@field custom table +--[[ +WIPDOC +]] +---@field [core.GenNotify.key.decoration] ivec? \ No newline at end of file diff --git a/types/luanti_lsp_definitions/library/defs/metadata/item.lua b/types/luanti_lsp_definitions/library/defs/metadata/item.lua new file mode 100644 index 00000000..99693335 --- /dev/null +++ b/types/luanti_lsp_definitions/library/defs/metadata/item.lua @@ -0,0 +1,120 @@ +---@meta _ +-- DRAFT 1 DONE +-- luanti/doc/lua_api.md: Metadata +-- luanti/doc/lua_api.md: Class reference > `MetaDataRef` + +-- ------------------- MetadataTable.*.item special fields ------------------ -- +--[[ +WIPDOC +]] +---@alias core.MetadataTable.fields.item.keys.special +--- | "description" +--- | "short_description" +--- | "inventory_image" +--- | "inventory_overlay" +--- | "wield_image" +--- | "wield_overlay" +--- | "wield_scale" +--- | "color" +--- | "palette_index" +--- | "count_meta" +--- | "count_alignment" +--- | "range" + +--[[ +WIPDOC +]] +---@alias core.MetadataTable.fields.item.keys +--- | core.MetadataTable.fields.item.keys.special +--- | string + +--[[ +WIPDOC +]] +---@alias core.MetadataTable.fields.item.keys.integer.special +--- | "palette_index" +--- | "count_alignment" + +--[[ +WIPDOC +]] +---@alias core.MetadataTable.fields.item.keys.integer +--- | core.MetadataTable.fields.item.keys.integer.special +--- | string + +--[[ +WIPDOC +]] +---@alias core.MetadataTable.fields.item.keys.number.special +--- | "range" + +--[[ +WIPDOC +]] +---@alias core.MetadataTable.fields.item.keys.number +--- | core.MetadataTable.fields.item.keys.number.special +--- | string + +-- --------------------------- MetadataTable.item --------------------------- -- + +--[[ +WIPDOC +]] +---@class core.MetadataTable.fields.item : {[string]:string?} +--[[ +WIPDOC +]] +---@field description string? +--[[ +WIPDOC +]] +---@field short_description string? +--[[ +WIPDOC +]] +---@field inventory_image core.Texture? +--[[ +WIPDOC +]] +---@field inventory_overlay core.Texture? +--[[ +WIPDOC +]] +---@field wield_image core.Texture? +--[[ +WIPDOC +]] +---@field wield_overlay core.Texture? +--[[ +WIPDOC +]] +---@field wield_scale core.MetadataTable.vector? +--[[ +WIPDOC +]] +---@field color core.ColorString? +--[[ +WIPDOC +]] +---@field palette_index integer? +--[[ +WIPDOC +]] +---@field count_meta string? +--[[ +WIPDOC +]] +---@field count_alignment integer? +--[[ +WIPDOC +]] +---@field range number? + +--[[ +WIPDOC +]] +---@class core.MetadataTable.item +--[[ +WIPDOC +]] +---@field fields core.MetadataTable.fields.item? \ No newline at end of file diff --git a/types/luanti_lsp_definitions/library/defs/metadata/metadata.lua b/types/luanti_lsp_definitions/library/defs/metadata/metadata.lua new file mode 100644 index 00000000..6ff20bfd --- /dev/null +++ b/types/luanti_lsp_definitions/library/defs/metadata/metadata.lua @@ -0,0 +1,50 @@ +---@meta _ +-- DRAFT 1 DONE +-- luanti/doc/lua_api.md: Metadata +-- luanti/doc/lua_api.md: Class reference > `MetaDataRef` + +--[[ +WIPDOC +]] +---@alias core.MetadataTable.vector string + +--[[ +WIPDOC +]] +---@alias core.MetadataTable.fields.keys +--- | core.MetadataTable.fields.item.keys +--- | core.MetadataTable.fields.node.keys +--- | core.MetadataTable.fields.player.keys +--- | core.MetadataTable.fields.storage.keys + +--[[ +WIPDOC +]] +---@alias core.MetadataTable.fields.keys.integer +--- | core.MetadataTable.fields.item.keys.integer +--- | core.MetadataTable.fields.node.keys.integer +--- | core.MetadataTable.fields.player.keys.integer +--- | core.MetadataTable.fields.storage.keys.integer + +--[[ +WIPDOC +]] +---@alias core.MetadataTable.fields.keys.number +--- | core.MetadataTable.fields.item.keys.number +--- | core.MetadataTable.fields.node.keys.number +--- | core.MetadataTable.fields.player.keys.number +--- | core.MetadataTable.fields.storage.keys.number + +--[[ +WIPDOC +]] +---@alias core.MetadataTable.set +--- | core.MetadataTable.node.set +--- | core.MetadataTable.item + +--[[ +WIPDOC +]] +---@alias core.MetadataTable.get +--- | core.MetadataTable.node.get +--- | core.MetadataTable.item \ No newline at end of file diff --git a/types/luanti_lsp_definitions/library/defs/metadata/node.lua b/types/luanti_lsp_definitions/library/defs/metadata/node.lua new file mode 100644 index 00000000..2a1d44f5 --- /dev/null +++ b/types/luanti_lsp_definitions/library/defs/metadata/node.lua @@ -0,0 +1,87 @@ +---@meta _ +-- DRAFT 1 DONE +-- luanti/doc/lua_api.md: Metadata +-- luanti/doc/lua_api.md: Class reference > `MetaDataRef` + +-- ------------------- MetadataTable.*.node special fields ------------------ -- + +--[[ +WIPDOC +]] +---@alias core.MetadataTable.fields.node.keys.special +--- | "formpsec" +--- | "infotext" + +--[[ +WIPDOC +]] +---@alias core.MetadataTable.fields.node.keys +--- | core.MetadataTable.fields.node.keys.special +--- | string + +--[[ +WIPDOC +]] +---@alias core.MetadataTable.fields.node.keys.integer.special +--- | string + +--[[ +WIPDOC +]] +---@alias core.MetadataTable.fields.node.keys.integer +--- | core.MetadataTable.fields.node.keys.integer.special +--- | string + +--[[ +WIPDOC +]] +---@alias core.MetadataTable.fields.node.keys.number.special +--- | string + +--[[ +WIPDOC +]] +---@alias core.MetadataTable.fields.node.keys.number +--- | core.MetadataTable.fields.node.keys.number.special +--- | string + +-- --------------------------- MetadataTable.node --------------------------- -- + +--[[ +WIPDOC +]] +---@class core.MetadataTable.fields.node : {[string]:string?} +--[[ +WIPDOC +]] +---@field formspec core.Formspec? +--[[ +WIPDOC +]] +---@field infotext string? + +--[[ +WIPDOC +]] +---@class core.MetadataTable.node.set +--[[ +WIPDOC +]] +---@field fields core.MetadataTable.fields.node? +--[[ +WIPDOC +]] +---@field inventory core.InventoryTable? + +--[[ +WIPDOC +]] +---@class core.MetadataTable.node.get +--[[ +WIPDOC +]] +---@field fields core.MetadataTable.fields.node? +--[[ +WIPDOC +]] +---@field inventory core.InventoryTable.stringfmt? \ No newline at end of file diff --git a/types/luanti_lsp_definitions/library/defs/metadata/player.lua b/types/luanti_lsp_definitions/library/defs/metadata/player.lua new file mode 100644 index 00000000..77e7dafc --- /dev/null +++ b/types/luanti_lsp_definitions/library/defs/metadata/player.lua @@ -0,0 +1,61 @@ +---@meta _ +-- DRAFT 1 DONE +-- luanti/doc/lua_api.md: Metadata +-- luanti/doc/lua_api.md: Class reference > `MetaDataRef` + +-- ------------------ MetadataTable.*.player special fields ----------------- -- + +--[[ +WIPDOC +]] +---@alias core.MetadataTable.fields.player.keys.special +--- | string + +--[[ +WIPDOC +]] +---@alias core.MetadataTable.fields.player.keys +--- | core.MetadataTable.fields.player.keys.special +--- | string + +--[[ +WIPDOC +]] +---@alias core.MetadataTable.fields.player.keys.integer.special +--- | string + +--[[ +WIPDOC +]] +---@alias core.MetadataTable.fields.player.keys.integer +--- | core.MetadataTable.fields.player.keys.integer.special +--- | string + +--[[ +WIPDOC +]] +---@alias core.MetadataTable.fields.player.keys.number.special +--- | string + +--[[ +WIPDOC +]] +---@alias core.MetadataTable.fields.player.keys.number +--- | core.MetadataTable.fields.player.keys.number.special +--- | string + +-- -------------------------- MetadataTable.player -------------------------- -- + +--[[ +WIPDOC +]] +---@class core.MetadataTable.fields.player : {[string]:string?} + +--[[ +WIPDOC +]] +---@class core.MetadataTable.player +--[[ +WIPDOC +]] +---@field fields core.MetadataTable.fields.player? \ No newline at end of file diff --git a/types/luanti_lsp_definitions/library/defs/metadata/storage.lua b/types/luanti_lsp_definitions/library/defs/metadata/storage.lua new file mode 100644 index 00000000..5c29d7f2 --- /dev/null +++ b/types/luanti_lsp_definitions/library/defs/metadata/storage.lua @@ -0,0 +1,61 @@ +---@meta _ +-- DRAFT 1 DONE +-- luanti/doc/lua_api.md: Metadata +-- luanti/doc/lua_api.md: Class reference > `MetaDataRef` + +-- ----------------- MetadataTable.*.storage special fields ----------------- -- + +--[[ +WIPDOC +]] +---@alias core.MetadataTable.fields.storage.keys.special +--- | string + +--[[ +WIPDOC +]] +---@alias core.MetadataTable.fields.storage.keys +--- | core.MetadataTable.fields.storage.keys.special +--- | string + +--[[ +WIPDOC +]] +---@alias core.MetadataTable.fields.storage.keys.integer.special +--- | string + +--[[ +WIPDOC +]] +---@alias core.MetadataTable.fields.storage.keys.integer +--- | core.MetadataTable.fields.storage.keys.integer.special +--- | string + +--[[ +WIPDOC +]] +---@alias core.MetadataTable.fields.storage.keys.number.special +--- | string + +--[[ +WIPDOC +]] +---@alias core.MetadataTable.fields.storage.keys.number +--- | core.MetadataTable.fields.storage.keys.number.special +--- | string + +-- -------------------------- MetadataTable.storage ------------------------- -- + +--[[ +WIPDOC +]] +---@class core.MetadataTable.fields.storage : {[string]:string?} + +--[[ +WIPDOC +]] +---@class core.MetadataTable.storage +--[[ +WIPDOC +]] +---@field fields core.MetadataTable.fields.storage? \ No newline at end of file diff --git a/types/luanti_lsp_definitions/library/defs/node/drawtype.lua b/types/luanti_lsp_definitions/library/defs/node/drawtype.lua new file mode 100644 index 00000000..b64e8cec --- /dev/null +++ b/types/luanti_lsp_definitions/library/defs/node/drawtype.lua @@ -0,0 +1,37 @@ +---@meta _ +-- DRAFT 1 DONE +-- luanti/doc/lua_api.md: Nodes > Node drawtypes +-- luanti/doc/lua_api.md: Definition tables > Node definition + +-- ---------------------------- NodeDef.drawtype ---------------------------- -- + +--[[ +WIPDOC +]] +---@alias core.NodeDef.drawtype +--- | "normal" +--- | "airlike" +--- | "liquid" +--- | "flowingliquid" +--- | "glasslike" +--- | "glasslike_framed" +--- | "glasslike_framed_optional" +--- | "allfaces" +--- | "allfaces_optional" +--- | "torchlike" +--- | "signlike" +--- | "plantlike" +--- | "firelike" +--- | "fencelike" +--- | "raillike" +--- | "nodebox" +--- | "mesh" +--- | "plantlike_rooted" + +-- ----------------------------- NodeDef fields ----------------------------- -- + +---@class core.NodeDef +--[[ +WIPDOC +]] +---@field drawtype core.NodeDef.drawtype? diff --git a/types/luanti_lsp_definitions/library/defs/node/drop.lua b/types/luanti_lsp_definitions/library/defs/node/drop.lua new file mode 100644 index 00000000..eb06728e --- /dev/null +++ b/types/luanti_lsp_definitions/library/defs/node/drop.lua @@ -0,0 +1,61 @@ +---@meta _ +-- DRAFT 1 DONE +-- luanti/doc/lua_api.md: Definition tables > Node definition + +-- --------------------------- NodeDef.drop.items --------------------------- -- + +--[[ +WIPDOC +]] +---@class core.NodeDef.drop.item +--[[ +WIPDOC +]] +---@field rarity integer? +--[[ +WIPDOC +]] +---@field items core.Item.name[]? +--[[ +WIPDOC +* @deprecated 5.X Use `tool_groups` instead +]] +---@field tools core.Tool.name[]? +--[[ +WIPDOC +]] +---@field tool_groups OneOrMany[]? +--[[ +WIPDOC +]] +---@field inherit_color boolean? + +-- ------------------------------ NodeDef.drop ------------------------------ -- + +--[[ +WIPDOC +]] +---@class core.NodeDef.drop.tablefmt +--[[ +WIPDOC +]] +---@field max_items integer? +--[[ +WIPDOC +]] +---@field items core.NodeDef.drop.item? + +--[[ +WIPDOC +]] +---@alias core.NodeDef.drop +--- | core.NodeDef.drop.tablefmt +--- | core.Item.stringfmt + +-- ----------------------------- NodeDef fields ----------------------------- -- + +---@class core.NodeDef +--[[ +WIPDOC +]] +---@field drop core.NodeDef.drop diff --git a/types/luanti_lsp_definitions/library/defs/node/node.lua b/types/luanti_lsp_definitions/library/defs/node/node.lua new file mode 100644 index 00000000..14d1ad28 --- /dev/null +++ b/types/luanti_lsp_definitions/library/defs/node/node.lua @@ -0,0 +1,155 @@ +---@meta _ +-- DRAFT 1 DONE +-- luanti/doc/lua_api.md: Nodes +-- luanti/doc/lua_api.md: Nodes > Node paramtypes + +--[[ +WIPDOC +]] +---@alias core.Node.name +--- | "unknown" +--- | "air" +--- | "ignore" +--- | string + +--[[ +WIPDOC +]] +---@alias core.Node.namelike +--- | core.Groups.node +--- | core.Node.name + +-- ------------------------------- Node.param1 ------------------------------ -- + +--[[ +WIPDOC +]] +---@alias core.Light integer + +--[[ +WIPDOC +]] +---@alias core.Light.part integer + +--[[ +WIPDOC +]] +---@alias core.Light.source integer + +--[[ +WIPDOC +]] +---@alias core.Param1 integer + +-- ------------------------------- Node.param2 ------------------------------ -- + +--[[ +WIPDOC +]] +---@alias core.Param2.wallmounted integer + +--[[ +WIPDOC +]] +---@alias core.Param2.facedir integer + +--[[ +WIPDOC +]] +---@alias core.Param2.4dir integer + +--[[ +WIPDOC +]] +---@alias core.Param2.leveled integer + +--[[ +WIPDOC +]] +---@alias core.Param2.leveled.rooted_plantlike integer + +--[[ +WIPDOC +]] +---@alias core.Param2.degrotate integer + +--[[ +WIPDOC +]] +---@alias core.Param2.meshoptions.plantlike integer + +--[[ +WIPDOC +]] +---@alias core.Param2.facedir.color integer + +--[[ +WIPDOC +]] +---@alias core.Param2.4dir.color integer + +--[[ +WIPDOC +]] +---@alias core.Param2.wallmounted.color integer + +--[[ +WIPDOC +]] +---@alias core.Param2.glasslikeliquidlevel.liquid integer + +--[[ +WIPDOC +]] +---@alias core.Param2.glasslikeliquidlevel.frame integer + +--[[ +WIPDOC +]] +---@alias core.Param2.glasslikeliquidlevel integer + +--[[ +WIPDOC +]] +---@alias core.Param2.degrotate.color integer + +--[[ +WIPDOC +]] +---@alias core.Param2 integer + +-- ---------------------------------- Node ---------------------------------- -- + +--[[ +WIPDOC +]] +---@class core.Node.get +--[[ +WIPDOC +]] +---@field name string +--[[ +WIPDOC +]] +---@field param1 core.Param1 +--[[ +WIPDOC +]] +---@field param2 core.Param2 + +--[[ +WIPDOC +]] +---@class core.Node.set +--[[ +WIPDOC +]] +---@field name string +--[[ +WIPDOC +]] +---@field param1 core.Param1? +--[[ +WIPDOC +]] +---@field param2 core.Param2? diff --git a/types/luanti_lsp_definitions/library/defs/node/nodebox.lua b/types/luanti_lsp_definitions/library/defs/node/nodebox.lua new file mode 100644 index 00000000..65e8bd3b --- /dev/null +++ b/types/luanti_lsp_definitions/library/defs/node/nodebox.lua @@ -0,0 +1,182 @@ +---@meta _ +-- DRAFT 1 DONE +-- luanti/doc/lua_api.md: Nodes > Node boxes + +-- ------------------------------- NodeBox.box ------------------------------ -- + +--[[ +WIPDOC +]] +---@class core.NodeBox.box.strict +--[[ +WIPDOC +]] +---@field [1] number +--[[ +WIPDOC +]] +---@field [2] number +--[[ +WIPDOC +]] +---@field [3] number +--[[ +WIPDOC +]] +---@field [4] number +--[[ +WIPDOC +]] +---@field [5] number +--[[ +WIPDOC +]] +---@field [6] number + +--[[ +WIPDOC +]] +---@alias core.NodeBox.box +--- | number[] +--- | core.NodeBox.box.strict + +--[[ +WIPDOC +]] +---@alias core.NodeBox.boxes +--- | core.NodeBox.box +--- | core.NodeBox.box[] + +-- ----------------------------- NodeBox.regular ---------------------------- -- + +--[[ +WIPDOC +]] +---@class core.NodeBox.regular +--[[ +WIPDOC +]] +---@field type "regular"? + + +-- ------------------------------ NodeBox.fixed ----------------------------- -- + +--[[ +WIPDOC +]] +---@class core.NodeBox.fixed +--[[ +WIPDOC +]] +---@field type "fixed"|"leveled" +--[[ +WIPDOC +]] +---@field fixed core.NodeBox.boxes + +-- --------------------------- NodeBox.wallmounted -------------------------- -- + +--[[ +WIPDOC +]] +---@class core.NodeBox.wallmounted +--[[ +WIPDOC +]] +---@field type "wallmounted" +--[[ +WIPDOC +]] +---@field wall_top core.NodeBox.box +--[[ +WIPDOC +]] +---@field wall_bottom core.NodeBox.box +--[[ +WIPDOC +]] +---@field wall_side core.NodeBox.box + + +-- ---------------------------- NodeBox.connected --------------------------- -- + +--[[ +WIPDOC +]] +---@class core.NodeBox.connected +--[[ +WIPDOC +]] +---@field type "connected" +--[[ +WIPDOC +]] +---@field fixed core.NodeBox.boxes +--[[ +WIPDOC +]] +---@field connect_top core.NodeBox.boxes? +--[[ +WIPDOC +]] +---@field connect_bottom core.NodeBox.boxes? +--[[ +WIPDOC +]] +---@field connect_front core.NodeBox.boxes? +--[[ +WIPDOC +]] +---@field connect_left core.NodeBox.boxes? +--[[ +WIPDOC +]] +---@field connect_back core.NodeBox.boxes? +--[[ +WIPDOC +]] +---@field connect_right core.NodeBox.boxes? +--[[ +WIPDOC +]] +---@field disconnected_top core.NodeBox.boxes? +--[[ +WIPDOC +]] +---@field disconnected_bottom core.NodeBox.boxes? +--[[ +WIPDOC +]] +---@field disconnected_front core.NodeBox.boxes? +--[[ +WIPDOC +]] +---@field disconnected_left core.NodeBox.boxes? +--[[ +WIPDOC +]] +---@field disconnected_back core.NodeBox.boxes? +--[[ +WIPDOC +]] +---@field disconnected_right core.NodeBox.boxes? +--[[ +WIPDOC +]] +---@field disconnected core.NodeBox.boxes? +--[[ +WIPDOC +]] +---@field disconnected_sides core.NodeBox.boxes? + + +-- --------------------------------- NodeBox -------------------------------- -- + +--[[ +WIPDOC +]] +---@alias core.NodeBox +--- | core.NodeBox.regular +--- | core.NodeBox.fixed +--- | core.NodeBox.wallmounted +--- | core.NodeBox.connected \ No newline at end of file diff --git a/types/luanti_lsp_definitions/library/defs/node/nodedef.lua b/types/luanti_lsp_definitions/library/defs/node/nodedef.lua new file mode 100644 index 00000000..62be0fc0 --- /dev/null +++ b/types/luanti_lsp_definitions/library/defs/node/nodedef.lua @@ -0,0 +1,821 @@ +---@meta _ +-- DRAFT 1 DONE +-- luanti/doc/lua_api.md: Nodes +-- luanti/doc/lua_api.md: Definition tables > Node definition + +-- NOTE: not practical to separate out every mutually exclusive fields as there +-- are too many states resulting in too many permutations. + +--[[ +WIPDOC +]] +---@alias core.NodeDef.keys +--- | core.ItemDef.keys +--- | "light_source" +--- | "drawtype" +--- | "visual_scale" +--- | "tiles" +--- | "overlay_tiles" +--- | "special_tiles" +--- | "color" +--- | "use_texture_alpha" +--- | "palette" +--- | "post_effect_color" +--- | "post_effect_color_shaded" +--- | "paramtype" +--- | "paramtype2" +--- | "place_param2" +--- | "wallmounted_rotate_vertical" +--- | "is_ground_content" +--- | "sunlight_propagates" +--- | "walkable" +--- | "pointable" +--- | "diggable" +--- | "climbable" +--- | "move_resistance" +--- | "buildable_to" +--- | "floodable" +--- | "liquidtype" +--- | "liquid_alternative_flowing" +--- | "liquid_alternative_source" +--- | "liquid_viscosity" +--- | "liquid_renewable" +--- | "liquid_move_physics" +--- | "air_equivalent" +--- | "leveled" +--- | "leveled_max" +--- | "liquid_range" +--- | "drowning" +--- | "damage_per_second" +--- | "node_box" +--- | "connects_to" +--- | "connect_sides" +--- | "mesh" +--- | "selection_box" +--- | "collision_box" +--- | "legacy_wallmounted" +--- | "legacy_facedir_simple" +--- | "waving" +--- | "mod_origin" +--- | "sounds" +--- | "drop" +--- | "on_construct" +--- | "on_destruct" +--- | "after_destruct" +--- | "on_flood" +--- | "preserve_metadata" +--- | "after_place_node" +--- | "after_dig_node" +--- | "can_dig" +--- | "on_punch" +--- | "on_rightclick" +--- | "on_dig" +--- | "on_timer" +--- | "on_receive_fields" +--- | "allow_metadata_inventory_move" +--- | "allow_metadata_inventory_put" +--- | "allow_metadata_inventory_take" +--- | "on_metadata_inventory_move" +--- | "on_metadata_inventory_put" +--- | "on_metadata_inventory_take" +--- | "on_blast" + +-- -------------------------------------------------------------------------- -- + +--[[ NodeDef.drawtype split off into ./drawtype.lua ]]-- + +--[[ +WIPDOC +]] +---@class core.NodeDef: core.ItemDef +--[[ +When used for nodes: Defines amount of light emitted by node. +Otherwise: Defines texture glow when viewed as a dropped item +To set the maximum (14), use the value 'core.LIGHT_MAX'. +A value outside the range 0 to core.LIGHT_MAX causes undefined +behavior. +]] +---@field light_source core.Light.source? +--[[ +visual_scale = 1.0, +Supported for drawtypes "plantlike", "signlike", "torchlike", +"firelike", "mesh", "nodebox", "allfaces". +For plantlike and firelike, the image will start at the bottom of the +node. For torchlike, the image will start at the surface to which the +node "attaches". For the other drawtypes the image will be centered +on the node. +]] +---@field visual_scale number? + +--[[ NodeDef.tiles .. NodeDef.special_tiles split off into ./tiles.lua ]]-- + +-- ------------------------- color and transparency ------------------------- -- + +--[[ +WIPDOC +]] +---@alias core.NodeDef.use_texture_alpha +--- | "opaque" +--- | "clip" +--- | "blend" + +---@class core.NodeDef +--[[ +color = ColorSpec, +The node's original color will be multiplied with this color. +If the node has a palette, then this setting only has an effect in +the inventory and on the wield item. +]] +---@field color core.ColorSpec? +--[[ +use_texture_alpha = ..., +Specifies how the texture's alpha channel will be used for rendering. +Possible values: +* "opaque": + Node is rendered opaque regardless of alpha channel. +* "clip": + A given pixel is either fully see-through or opaque + depending on the alpha channel being below/above 50% in value. + Use this for nodes with fully transparent and fully opaque areas. +* "blend": + The alpha channel specifies how transparent a given pixel + of the rendered node is. This comes at a performance cost. + Only use this when correct rendering + among semitransparent nodes is necessary. +The default is "opaque" for drawtypes normal, liquid and flowingliquid, +mesh and nodebox or "clip" otherwise. +If set to a boolean value (deprecated): true either sets it to blend +or clip, false sets it to clip or opaque mode depending on the drawtype. + +* @deprecated 5.X `true` may blend or clip, `false` had special handling depending on drawtype +]] +---@field use_texture_alpha core.NodeDef.use_texture_alpha? +--[[ +palette = "", +The node's `param2` is used to select a pixel from the image. +Pixels are arranged from left to right and from top to bottom. +The node's color will be multiplied with the selected pixel's color. +Tiles can override this behavior. +Only when `paramtype2` supports palettes. +]] +---@field palette core.Texture? +--[[ +post_effect_color = "#00000000", +Screen tint if a player is inside this node, see `ColorSpec`. +Color is alpha-blended over the screen. +]] +---@field post_effect_color core.ColorSpec? +--[[ +post_effect_color_shaded = false, +Determines whether `post_effect_color` is affected by lighting. +]] +---@field post_effect_color_shaded boolean? + +-- ---------------------------------- param --------------------------------- -- + +--[[ NodeDef.paramtype .. NodeDef.paramtype2 split off into ./paramtype2.lua ]]-- + +---@class core.NodeDef +--[[ +place_param2 = 0, +Value for param2 that is set when player places node +]] +---@field place_param2 core.Param2? +--[[ +wallmounted_rotate_vertical = false, +If true, place_param2 is nil, and this is a wallmounted node, +this node might use the special 90° rotation when placed +on the floor or ceiling, depending on the direction. +See the explanation about wallmounted for details. +Otherwise, the rotation is always the same on vertical placement. +]] +---@field wallmounted_rotate_vertical boolean? + + +-- -------------------------------------------------------------------------- -- + +--[[ +WIPDOC +]] +---@alias core.NodeDef.move_resistance +--- | 0 +--- | 1 +--- | 2 +--- | 3 +--- | 4 +--- | 5 +--- | 6 +--- | 7 +--- | integer + +---@class core.NodeDef +--[[ +is_ground_content = true, +If false, the cave generator and dungeon generator will not carve +through this node. +Specifically, this stops mod-added nodes being removed by caves and +dungeons when those generate in a neighbor mapchunk and extend out +beyond the edge of that mapchunk. +]] +---@field is_ground_content boolean? +--[[ +sunlight_propagates = false, +If true, sunlight will go infinitely through this node +]] +---@field sunlight_propagates boolean? +--[[ +walkable = true, -- If true, objects collide with node +]] +---@field walkable boolean? +--[[ +pointable = true, +Can be `true` if it is pointable, `false` if it can be pointed through, +or `"blocking"` if it is pointable but not selectable. +Clients older than 5.9.0 interpret `pointable = "blocking"` as `pointable = true`. +Can be overridden by the `pointabilities` of the held item. +A client may be able to point non-pointable nodes, since it isn't checked server-side. +]] +---@field pointable boolean? +--[[ +diggable = true, -- If false, can never be dug +]] +---@field diggable boolean? +--[[ +climbable = false, -- If true, can be climbed on like a ladder +]] +---@field climbable boolean? +--[[ +move_resistance = 0, +Slows down movement of players through this node (max. 7). +If this is nil, it will be equal to liquid_viscosity. +Note: If liquid movement physics apply to the node +(see `liquid_move_physics`), the movement speed will also be +affected by the `movement_liquid_*` settings. +]] +---@field move_resistance core.NodeDef.move_resistance? +--[[ +buildable_to = false, -- If true, placed nodes can replace this node +]] +---@field buildable_to boolean? +--[[ +floodable = false, +If true, liquids flow into and replace this node. +Warning: making a liquid node 'floodable' will cause problems. +]] +---@field floodable boolean? + + +-- ---------------------------- liquid properties --------------------------- -- + +--[[ +WIPDOC +]] +---@alias core.NodeDef.liquidtype +--- | "none" +--- | "source" +--- | "flowing" + +--[[ +WIPDOC +]] +---@alias core.NodeDef.liquid_viscosity +--- | 0 +--- | 1 +--- | 2 +--- | 3 +--- | 4 +--- | 5 +--- | 6 +--- | 7 +--- | integer + +---@class core.NodeDef +--[[ +liquidtype = "none", -- specifies liquid flowing physics +* "none": no liquid flowing physics +* "source": spawns flowing liquid nodes at all 4 sides and below; + recommended drawtype: "liquid". +* "flowing": spawned from source, spawns more flowing liquid nodes + around it until `liquid_range` is reached; + will drain out without a source; + recommended drawtype: "flowingliquid". +If it's "source" or "flowing", then the +`liquid_alternative_*` fields _must_ be specified +]] +---@field liquidtype core.NodeDef.liquidtype? +--[[ +`liquid_alternative_flowing` may contain the node name that represents +the flowing version of a liquid. + +This field is required if `liquidtype ~= "none"` or +`drawtype == "flowingliquid"`. + +Liquids consist of up to two nodes: source and flowing. + +There are two ways to define a liquid: +1) Source node and flowing node. This requires both fields to be + specified for both nodes. +2) Standalone source node (cannot flow). `liquid_alternative_source` + must be specified and `liquid_range` must be set to 0. + +Example: + liquid_alternative_flowing = "example:water_flowing", +]] +---@field liquid_alternative_flowing string? +--[[ +`liquid_alternative_source` may contain the node name that represents +the source version of a liquid. + +This field is required if `liquidtype ~= "none"` or +`drawtype == "flowingliquid"`. + +Liquids consist of up to two nodes: source and flowing. + +There are two ways to define a liquid: +1) Source node and flowing node. This requires both fields to be + specified for both nodes. +2) Standalone source node (cannot flow). `liquid_alternative_source` + must be specified and `liquid_range` must be set to 0. + +Example: + liquid_alternative_source = "example:water_source", +]] +---@field liquid_alternative_source string? +--[[ +liquid_viscosity = 0, +Controls speed at which the liquid spreads/flows (max. 7). +0 is fastest, 7 is slowest. +By default, this also slows down movement of players inside the node +(can be overridden using `move_resistance`) +]] +---@field liquid_viscosity core.NodeDef.liquid_viscosity? +--[[ +liquid_renewable = true, +If true, a new liquid source can be created by placing two or more +sources nearby +]] +---@field liquid_renewable boolean? +--[[ +liquid_move_physics = nil, -- specifies movement physics if inside node +* false: No liquid movement physics apply. +* true: Enables liquid movement physics. Enables things like + ability to "swim" up/down, sinking slowly if not moving, + smoother speed change when falling into, etc. The `movement_liquid_*` + settings apply. +* nil: Will be treated as true if `liquidtype ~= "none"` + and as false otherwise. +]] +---@field liquid_move_physics boolean? +--[[ +air_equivalent = nil, +unclear meaning, the engine sets this to true for 'air' and 'ignore' +deprecated. +Unofficial note: But what else are you supposed to do? i guess make an is_air function lmao + +* @deprecated 5.X +]] +---@field air_equivalent boolean? + +-- --------------------------------- leveled -------------------------------- -- + +---@class core.NodeDef +--[[ +leveled = 0, +Only valid for "nodebox" drawtype with 'type = "leveled"'. +Allows defining the nodebox height without using param2. +The nodebox height is 'leveled' / 64 nodes. +The maximum value of 'leveled' is `leveled_max`. +]] +---@field leveled core.Param2.leveled? +--[[ +leveled_max = 127, +Maximum value for `leveled` (0-127), enforced in +`core.set_node_level` and `core.add_node_level`. +Values above 124 might causes collision detection issues. +]] +---@field leveled_max core.Param2.leveled? + +-- -------------------------------------------------------------------------- -- + +--[[ +WIPDOC +]] +---@alias core.NodeDef.liquid_range +--- | 0 +--- | 1 +--- | 2 +--- | 3 +--- | 4 +--- | 5 +--- | 6 +--- | 7 +--- | 8 + +---@class core.NodeDef +--[[ +liquid_range = 8, +Maximum distance that flowing liquid nodes can spread around +source on flat land; +maximum = 8; set to 0 to disable liquid flow +]] +---@field liquid_range core.NodeDef.liquid_range? +--[[ +drowning = 0, +Player will take this amount of damage if no bubbles are left +]] +---@field drowning integer? +--[[ +damage_per_second = 0, +If player is inside node, this damage is caused +]] +---@field damage_per_second integer? + +-- -------------------------- node shape properties ------------------------- -- + +--[[ +WIPDOC +]] +---@alias core.NodeDef.connect_side +--- | "top" +--- | "bottom" +--- | "front" +--- | "left" +--- | "back" +--- | "right" + +---@class core.NodeDef +--[[ +node_box = {type = "regular"}, -- See "Node boxes" +]] +---@field node_box core.NodeBox? +--[[ +connects_to = {}, +Used for nodebox nodes with the type == "connected". +Specifies to what neighboring nodes connections will be drawn. +e.g. `{"group:fence", "default:wood"}` or `"default:stone"` +]] +---@field connects_to OneOrMany? +--[[ +connect_sides = {}, +Tells connected nodebox nodes to connect only to these sides of this +node. possible: "top", "bottom", "front", "left", "back", "right" +]] +---@field connect_sides core.NodeDef.connect_side[]? +--[[ +mesh = "", +File name of mesh when using "mesh" drawtype +The center of the node is the model origin. +For legacy reasons, this uses a different scale depending on the mesh: +1. For glTF models: 10 units = 1 node (consistent with the scale for entities). +2. For obj models: 1 unit = 1 node. +3. For b3d and x models: 1 unit = 1 node if static, otherwise 10 units = 1 node. +Using static glTF or obj models is recommended. +You can use the `visual_scale` multiplier to achieve the expected scale. +]] +---@field mesh core.Path? +--[[ +selection_box = { +see [Node boxes] for possibilities +}, +Custom selection box definition. Multiple boxes can be defined. +If "nodebox" drawtype is used and selection_box is nil, then node_box +definition is used for the selection box. +]] +---@field selection_box core.NodeBox? +--[[ +collision_box = { +see [Node boxes] for possibilities +}, +Custom collision box definition. Multiple boxes can be defined. +If "nodebox" drawtype is used and collision_box is nil, then node_box +definition is used for the collision box. +]] +---@field collision_box core.NodeBox? + +-- -------------------------------------------------------------------------- -- + +--[[ +WIPDOC +]] +---@alias core.NodeDef.waving +--- | 0 +--- | 1 +--- | 2 +--- | 3 + +---@class core.NodeDef +--[[ +Support maps made in and before January 2012 +]] +---@field legacy_wallmounted boolean? +--[[ +Support maps made in and before January 2012 +]] +---@field legacy_facedir_simple boolean? +--[[ +waving = 0, +Valid for drawtypes: +mesh, nodebox, plantlike, allfaces_optional, liquid, flowingliquid. +1 - wave node like plants (node top moves side-to-side, bottom is fixed) +2 - wave node like leaves (whole node moves side-to-side) +3 - wave node like liquids (whole node moves up and down) +Not all models will properly wave. +plantlike drawtype can only wave like plants. +allfaces_optional drawtype can only wave like leaves. +liquid, flowingliquid drawtypes can only wave like liquids. +]] +---@field waving core.NodeDef.waving? + +--[[ NodeDefBase.sounds split off into ./sounds.lua ]]-- + +--[[ NodeDef.drop split off into ./drop.lua ]]-- + +---@class core.NodeDef +--[[ +mod_origin = "modname", +stores which mod actually registered a node +If the source could not be determined it contains "??" +Useful for getting which mod truly registered something +example: if a node is registered as ":othermodname:nodename", +nodename will show "othermodname", but mod_origin will say "modname" +]] +---@field mod_origin string? + +-- -------------------------------- callbacks ------------------------------- -- + +--[[ +WIPDOC +]] +---@alias core.NodeDef.on_construct fun(pos:ivec) + +--[[ +WIPDOC +]] +---@alias core.NodeDef.on_destruct fun(pos:ivec?) + +--[[ +WIPDOC +]] +---@alias core.NodeDef.after_destruct fun(pos:ivec, oldnode:core.Node.get) + +--[[ +WIPDOC +]] +---@alias core.NodeDef.on_flood fun(pos:ivec, oldnode:core.Node.get, newnode:core.Node.get):boolean? + +--[[ +WIPDOC +]] +---@alias core.NodeDef.preserve_metadata fun(pos:ivec, oldnode:core.Node.get, oldmeta:core.MetadataTable.node.get) + +--[[ +WIPDOC +]] +---@alias core.NodeDef.after_place_node fun(pos:ivec, placer:core.ObjectRef?, itemstack:core.ItemStack, pointed_thing:core.PointedThing) + +--[[ +WIPDOC +]] +---@alias core.NodeDef.after_dig_node fun(pos:ivec, oldnode:core.Node.get, oldmetadata:core.MetadataTable.node.get, digger:core.ObjectRef?) + +--[[ +WIPDOC +]] +---@alias core.NodeDef.can_dig fun(pos:ivec, player:core.ObjectRef?):boolean + +--[[ +WIPDOC +]] +---@alias core.NodeDef.on_punch fun(pos:ivec, node:core.Node.get, puncher:core.ObjectRef?, pointed_thing:core.PointedThing) + +--[[ +WIPDOC +]] +---@alias core.NodeDef.on_rightclick fun(pos:ivec, node:core.Node.get, clicker:core.ObjectRef?, itemstack:core.ItemStack, pointed_thing:core.PointedThing?):core.ItemStack? + +--[[ +WIPDOC + +* @deprecated 5.X returning `nil` is the same are `true` +]] +---@alias core.NodeDef.on_dig fun(pos:ivec, node:core.Node.get, digger:core.ObjectRef?):boolean + +--[[ +WIPDOC +]] +---@alias core.NodeDef.on_timer fun(pos:ivec, elapsed:number, node:core.Node.get, timeout:number):boolean? + +--[[ +WIPDOC +]] +---@alias core.NodeDef.on_receive_fields fun(pos:ivec, formname:"", fields: core.FormspecFields, sender:core.ObjectRef) + +--[[ +WIPDOC +]] +---@alias core.NodeDef.allow_metadata_inventory_move fun(pos:ivec, from_list:core.InventoryList, from_index:integer, to_list:core.InventoryList, to_index:integer, count:integer, player:core.ObjectRef):integer + +--[[ +WIPDOC +]] +---@alias core.NodeDef.allow_metadata_inventory_put fun(pos:ivec, listname:core.InventoryList, index:integer, stack:core.ItemStack, player:core.ObjectRef):integer + +--[[ +WIPDOC +]] +---@alias core.NodeDef.allow_metadata_inventory_take fun(pos:ivec, listname:core.InventoryList, index:integer, stack:core.ItemStack, player:core.ObjectRef):integer + +--[[ +WIPDOC +]] +---@alias core.NodeDef.on_metadata_inventory_move fun(pos:ivec, from_list:core.InventoryList, from_index:integer, to_list:core.InventoryList, to_index:integer, count:integer, player:core.ObjectRef):nil + +--[[ +WIPDOC +]] +---@alias core.NodeDef.on_metadata_inventory_put fun(pos:ivec, listname:core.InventoryList, index:integer, stack:core.ItemStack, player:core.ObjectRef):nil + +--[[ +WIPDOC +]] +---@alias core.NodeDef.on_metadata_inventory_take fun(pos:ivec, listname:core.InventoryList, index:integer, stack:core.ItemStack, player:core.ObjectRef):nil + +--[[ +WIPDOC +]] +---@alias core.NodeDef.on_blast fun(pos:ivec, intensity:number?) + +---@class core.NodeDef +--[[ +on_construct = function(pos), +Node constructor; called after adding node. +Can set up metadata and stuff like that. +Not called for bulk node placement (i.e. schematics and VoxelManip). +Note: Within an on_construct callback, core.set_node can cause an +infinite loop if it invokes the same callback. + Consider using core.swap_node instead. +default: nil +]] +---@field on_construct core.NodeDef.on_construct? +--[[ +on_destruct = function(pos), +Node destructor; called before removing node. +Not called for bulk node placement. +default: nil +]] +---@field on_destruct core.NodeDef.on_destruct? +--[[ +after_destruct = function(pos, oldnode), +Node destructor; called after removing node. +Not called for bulk node placement. +default: nil +]] +---@field after_destruct core.NodeDef.after_destruct? +--[[ +on_flood = function(pos, oldnode, newnode), +Called when a liquid (newnode) is about to flood oldnode, if it has +`floodable = true` in the nodedef. Not called for bulk node placement +(i.e. schematics and VoxelManip) or air nodes. If return true the +node is not flooded, but on_flood callback will most likely be called +over and over again every liquid update interval. +Default: nil +Warning: making a liquid node 'floodable' will cause problems. +]] +---@field on_flood core.NodeDef.on_flood? +--[[ +preserve_metadata = function(pos, oldnode, oldmeta, drops), +Called when `oldnode` is about be converted to an item, but before the +node is deleted from the world or the drops are added. This is +generally the result of either the node being dug or an attached node +becoming detached. +* `pos`: node position +* `oldnode`: node table of node before it was deleted +* `oldmeta`: metadata of node before it was deleted, as a metadata table +* `drops`: a table of `ItemStack`s, so any metadata to be preserved can + be added directly to one or more of the dropped items. See + "ItemStackMetaRef". +default: `nil` +]] +---@field preserve_metadata core.NodeDef.preserve_metadata? +--[[ +after_place_node = function(pos, placer, itemstack, pointed_thing), +Called after constructing node when node was placed using +core.item_place_node / core.place_node. +If return true no item is taken from itemstack. +`placer` may be any valid ObjectRef or nil. +default: nil +]] +---@field after_place_node core.NodeDef.after_place_node? +--[[ +after_dig_node = function(pos, oldnode, oldmetadata, digger), +Called after destructing the node when node was dug using +`core.node_dig` / `core.dig_node`. +* `pos`: node position +* `oldnode`: node table of node before it was dug +* `oldmetadata`: metadata of node before it was dug, + as a metadata table +* `digger`: ObjectRef of digger +default: nil +]] +---@field after_dig_node core.NodeDef.after_dig_node? +--[[ +can_dig = function(pos, [player]), +Returns true if node can be dug, or false if not. +default: nil +]] +---@field can_dig core.NodeDef.can_dig? +--[[ +on_punch = function(pos, node, puncher, pointed_thing), +default: core.node_punch +Called when puncher (an ObjectRef) punches the node at pos. +By default calls core.register_on_punchnode callbacks. +]] +---@field on_punch core.NodeDef.on_punch? +--[[ +on_rightclick = function(pos, node, clicker, itemstack, pointed_thing), +default: nil +Called when clicker (an ObjectRef) used the 'place/build' key +(not necessarily an actual rightclick) +while pointing at the node at pos with 'node' being the node table. +itemstack will hold clicker's wielded item. +Shall return the leftover itemstack. +Note: pointed_thing can be nil, if a mod calls this function. +This function does not get triggered by clients <=0.4.16 if the +"formspec" node metadata field is set. +]] +---@field on_rightclick core.NodeDef.on_rightclick? +--[[ +on_dig = function(pos, node, digger), +default: core.node_dig +By default checks privileges, wears out item (if tool) and removes node. +return true if the node was dug successfully, false otherwise. +Deprecated: returning nil is the same as returning true. +]] +---@field on_dig core.NodeDef.on_dig? +--[[ +on_timer = function(pos, elapsed), +default: nil +called by NodeTimers, see core.get_node_timer and NodeTimerRef. +elapsed is the total time passed since the timer was started. +return true to run the timer for another cycle with the same timeout +value. +]] +---@field on_timer core.NodeDef.on_timer? +--[[ +on_receive_fields = function(pos, formname, fields, sender), +fields = {name1 = value1, name2 = value2, ...} +formname should be the empty string; you **must not** use formname. +Called when an UI form (e.g. sign text input) returns data. +See core.register_on_player_receive_fields for more info. +default: nil +]] +---@field on_receive_fields core.NodeDef.on_receive_fields? +--[[ +allow_metadata_inventory_move = function(pos, from_list, from_index, to_list, to_index, count, player), +Called when a player wants to move items inside the inventory. +Return value: number of items allowed to move. +]] +---@field allow_metadata_inventory_move core.NodeDef.allow_metadata_inventory_move? +--[[ +allow_metadata_inventory_put = function(pos, listname, index, stack, player), +Called when a player wants to put something into the inventory. +Return value: number of items allowed to put. +Return value -1: Allow and don't modify item count in inventory. +]] +---@field allow_metadata_inventory_put core.NodeDef.allow_metadata_inventory_put? +--[[ +allow_metadata_inventory_take = function(pos, listname, index, stack, player), +Called when a player wants to take something out of the inventory. +Return value: number of items allowed to take. +Return value -1: Allow and don't modify item count in inventory. +]] +---@field allow_metadata_inventory_take core.NodeDef.allow_metadata_inventory_take? +--[[ +on_metadata_inventory_move = function(pos, from_list, from_index, to_list, to_index, count, player), +Called after the actual action has happened, according to what was +allowed. +No return value. +]] +---@field on_metadata_inventory_move core.NodeDef.on_metadata_inventory_move? +--[[ +on_metadata_inventory_put = function(pos, listname, index, stack, player), +Called after the actual action has happened, according to what was +allowed. +No return value. +]] +---@field on_metadata_inventory_put core.NodeDef.on_metadata_inventory_put? +--[[ +on_metadata_inventory_take = function(pos, listname, index, stack, player), +Called after the actual action has happened, according to what was +allowed. +No return value. +]] +---@field on_metadata_inventory_take core.NodeDef.on_metadata_inventory_take? +--[[ +on_blast = function(pos, intensity), +intensity: 1.0 = mid range of regular TNT. +If defined, called when an explosion touches the node, instead of +removing the node. +Unofficial note: this is a custom field, just documented in lua_api.md i assume because TNT mods usually don't handle indestructible nodes/whatever very well +]] +---@field on_blast core.NodeDef.on_blast? \ No newline at end of file diff --git a/types/luanti_lsp_definitions/library/defs/node/paramtype.lua b/types/luanti_lsp_definitions/library/defs/node/paramtype.lua new file mode 100644 index 00000000..ae5811a6 --- /dev/null +++ b/types/luanti_lsp_definitions/library/defs/node/paramtype.lua @@ -0,0 +1,72 @@ +---@meta _ +-- DRAFT 1 DONE +-- luanti/doc/lua_api.md: Nodes > Node paramtypes +-- luanti/doc/lua_api.md: Definition tables > Node definition + +-- --------------------------- NodeDef.paramtype2 --------------------------- -- + +--[[ +WIPDOC +]] +---@alias core.NodeDef.paramtype +--- | "light" +--- | "none" + +--[[ +WIPDOC +]] +---@alias core.NodeDef.paramtype2.color +--- | "color" +--- | "colorfacedir" +--- | "color4dir" +--- | "colorwallmounted" +--- | "colordegrotate" + +--[[ +WIPDOC +]] +---@alias core.NodeDef.paramtype2 +--- | "flowingliquid" +--- | "wallmounted" +--- | "facedir" +--- | "4dir" +--- | "leveled" +--- | "degrotate" +--- | "meshoptions" +--- | "color" +--- | "colorfacedir" +--- | "color4dir" +--- | "colorwallmounted" +--- | "glasslikeliquidlevel" +--- | "colordegrotate" +--- | "none" + +-- ----------------------------- NodeDef fields ----------------------------- -- + +---@class core.NodeDef +--[[ +paramtype = "none", -- See "Nodes" +* `paramtype = "light"` + * The value stores light with and without sun in its lower and upper 4 bits + respectively. + * Required by a light source node to enable spreading its light. + * Required by the following drawtypes as they determine their visual + brightness from their internal light value: + * torchlike + * signlike + * firelike + * fencelike + * raillike + * nodebox + * mesh + * plantlike + * plantlike_rooted +* `paramtype = "none"` + * `param1` will not be used by the engine and can be used to store + an arbitrary value +]] +---@field paramtype core.NodeDef.paramtype? +--[[ +WIPDOC +]] +---@field paramtype2 core.NodeDef.paramtype2? diff --git a/types/luanti_lsp_definitions/library/defs/node/sounds.lua b/types/luanti_lsp_definitions/library/defs/node/sounds.lua new file mode 100644 index 00000000..ec9e855e --- /dev/null +++ b/types/luanti_lsp_definitions/library/defs/node/sounds.lua @@ -0,0 +1,42 @@ +---@meta _ +-- DRAFT 1 DONE +-- luanti/doc/lua_api.md: Definition tables > Node definition + +-- ----------------------------- NodeDef.sounds ----------------------------- -- + +--[[ +WIPDOC +]] +---@class core.NodeDef.sounds +--[[ +WIPDOC +]] +---@field footstep core.SimpleSoundSpec? +--[[ +WIPDOC +]] +---@field dig core.SimpleSoundSpec|"__group"? +--[[ +WIPDOC +]] +---@field dug core.SimpleSoundSpec? +--[[ +WIPDOC +]] +---@field place core.SimpleSoundSpec? +--[[ +WIPDOC +]] +---@field place_failed core.SimpleSoundSpec? +--[[ +WIPDOC +]] +---@field fall core.SimpleSoundSpec? + +-- ----------------------------- NodeDef fields ----------------------------- -- + +---@class core.NodeDef +--[[ +WIPDOC +]] +---@field sounds core.NodeDef.sounds diff --git a/types/luanti_lsp_definitions/library/defs/node/tiles.lua b/types/luanti_lsp_definitions/library/defs/node/tiles.lua new file mode 100644 index 00000000..5a76da56 --- /dev/null +++ b/types/luanti_lsp_definitions/library/defs/node/tiles.lua @@ -0,0 +1,85 @@ +---@meta _ +-- DRAFT 1 DONE +-- luanti/doc/lua_api.md: Definition tables > Node definition + +-- ------------------------------ NodeDef.tiles ----------------------------- -- + +--[[ +WIPDOC +]] +---@class core.NodeDef.tiles.strict +--[[ +WIPDOC +]] +---@field [1] core.TileDef? +--[[ +WIPDOC +]] +---@field [2] core.TileDef? +--[[ +WIPDOC +]] +---@field [3] core.TileDef? +--[[ +WIPDOC +]] +---@field [4] core.TileDef? +--[[ +WIPDOC +]] +---@field [5] core.TileDef? +--[[ +WIPDOC +]] +---@field [6] core.TileDef? + +--[[ +WIPDOC +]] +---@alias core.NodeDef.tiles +--- | core.NodeDef.tiles.strict +--- | core.TileDef[] + +-- -------------------------- NodeDef.special_tiles ------------------------- -- + +---@class core.NodeDef.special_tiles.strict +--[[ +WIPDOC +]] +---@field [1] core.TileDef? +--[[ +WIPDOC +]] +---@field [2] core.TileDef? + +--[[ +WIPDOC +]] +---@alias core.NodeDef.special_tiles +--- | core.NodeDef.special_tiles.strict +--- | core.TileDef[] + +-- ----------------------------- NodeDef fields ----------------------------- -- + +---@class core.NodeDef +--[[ +tiles = {tile definition 1, def2, def3, def4, def5, def6}, +Textures of node; +Y, -Y, +X, -X, +Z, -Z +List can be shortened to needed length. +]] +---@field tiles core.NodeDef.tiles? +--[[ +overlay_tiles = {tile definition 1, def2, def3, def4, def5, def6}, +Same as `tiles`, but these textures are drawn on top of the base +tiles. You can use this to colorize only specific parts of your +texture. If the texture name is an empty string, that overlay is not +drawn. Since such tiles are drawn twice, it is not recommended to use +overlays on very common nodes. +]] +---@field overlay_tiles core.NodeDef.tiles? +--[[ +special_tiles = {tile definition 1, Tile definition 2}, +Special textures of node; used rarely. +List can be shortened to needed length. +]] +---@field special_tiles core.NodeDef.special_tiles? \ No newline at end of file diff --git a/types/luanti_lsp_definitions/library/defs/noiseparams.lua b/types/luanti_lsp_definitions/library/defs/noiseparams.lua new file mode 100644 index 00000000..c313643f --- /dev/null +++ b/types/luanti_lsp_definitions/library/defs/noiseparams.lua @@ -0,0 +1,209 @@ +---@meta _ +-- DRAFT 1 DONE +-- luanti/doc/lua_api.md: Fractal Value Noise +-- luanti/doc/lua_api.md: Flag Specifier Format + +-- ---------------------------- NoiseParams.flags --------------------------- -- + +--[[ +WIPDOC +]] +---@class core.NoiseParams.flags.tablefmt +--[[ +WIPDOC +]] +---@field defaults boolean +--[[ +WIPDOC +]] +---@field nodefaults boolean +--[[ +WIPDOC +]] +---@field eased boolean +--[[ +WIPDOC +]] +---@field noeased boolean +--[[ +WIPDOC +]] +---@field absvalue boolean +--[[ +WIPDOC +]] +---@field noabsvalue boolean + +--[[ +WIPDOC +]] +---@alias core.NoiseParams.flags.stringfmt string + +--[[ +WIPDOC +]] +---@alias core.NoiseParams.flags +--- | core.NoiseParams.flags.tablefmt +--- | core.NoiseParams.flags.stringfmt + +-- --------------------------- NoiseParams.__base --------------------------- -- + +---@class _.NoiseParams.__base +--[[ +After the multiplication by `scale` this is added to the result and is the final +step in creating the noise value. +Can be positive or negative. +]] +---@field offset number +--[[ +Once all octaves have been combined, the result is multiplied by this. +Can be positive or negative. +]] +---@field scale number +--[[ +This is a whole number that determines the entire pattern of the noise +variation. Altering it enables different noise patterns to be created. +With other parameters equal, different seeds produce different noise patterns +and identical seeds produce identical noise patterns. + +For this parameter you can randomly choose any whole number. Usually it is +preferable for this to be different from other seeds, but sometimes it is useful +to be able to create identical noise patterns. + +In some noise APIs the world seed is added to the seed specified in noise +parameters. This is done to make the resulting noise pattern vary in different +worlds, and be 'world-specific'. +]] +---@field seed integer +--[[ +The number of simple noise generators that are combined. +A whole number, 1 or more. +Each additional octave adds finer detail to the noise but also increases the +noise calculation load. +3 is a typical minimum for a high quality, complex and natural-looking noise +variation. 1 octave has a slight 'gridlike' appearance. + +Choose the number of octaves according to the `spread` and `lacunarity`, and the +size of the finest detail you require. For example: +if `spread` is 512 nodes, `lacunarity` is 2.0 and finest detail required is 16 +nodes, octaves will be 6 because the 'wavelengths' of the octaves will be +512, 256, 128, 64, 32, 16 nodes. +Warning: If the 'wavelength' of any octave falls below 1 an error will occur. +]] +---@field octaves integer +--[[ +Each additional octave has an amplitude that is the amplitude of the previous +octave multiplied by `persistence`, to reduce the amplitude of finer details, +as is often helpful and natural to do so. +Since this controls the balance of fine detail to large-scale detail +`persistence` can be thought of as the 'roughness' of the noise. + +A positive or negative non-zero number, often between 0.3 and 1.0. +A common medium value is 0.5, such that each octave has half the amplitude of +the previous octave. +This may need to be tuned when altering `lacunarity`; when doing so consider +that a common medium value is 1 / lacunarity. + +Instead of `persistence`, the key `persist` may be used to the same effect. +]] +---@field persistence number? +--[[ +WIPDOC +]] +---@field persist number? +--[[ +Each additional octave has a 'wavelength' that is the 'wavelength' of the +previous octave multiplied by 1 / lacunarity, to create finer detail. +'lacunarity' is often 2.0 so 'wavelength' often halves per octave. + +A positive number no smaller than 1.0. +Values below 2.0 create higher quality noise at the expense of requiring more +octaves to cover a particular range of 'wavelengths'. +]] +---@field lacunarity number? +--[[ +Leave this field unset for no special handling. +Currently supported are `defaults`, `eased` and `absvalue`: +]] +---@field flags core.NoiseParams.flags? + +-- ------------------------------- NoiseParams ------------------------------ -- + +--[[ +### Format example + +For 2D or 3D value noise or value noise maps: + +```lua +np_terrain = { + offset = 0, + scale = 1, + spread = {x = 500, y = 500, z = 500}, + seed = 571347, + octaves = 5, + persistence = 0.63, + lacunarity = 2.0, + flags = "defaults, absvalue", +} +``` + +For 2D noise the Z component of `spread` is still defined but is ignored. +A single noise parameter table can be used for 2D or 3D noise. +]] +---@class core.NoiseParams.2d : _.NoiseParams.__base +--[[ +For octave1, this is roughly the change of input value needed for a very large +variation in the noise value generated by octave1. It is almost like a +'wavelength' for the wavy noise variation. +Each additional octave has a 'wavelength' that is smaller than the previous +octave, to create finer detail. `spread` will therefore roughly be the typical +size of the largest structures in the final noise variation. + +`spread` is a vector with values for x, y, z to allow the noise variation to be +stretched or compressed in the desired axes. +Values are positive numbers. +]] +---@field spread vec2.xy + +--[[ +### Format example + +For 2D or 3D value noise or value noise maps: + +```lua +np_terrain = { + offset = 0, + scale = 1, + spread = {x = 500, y = 500, z = 500}, + seed = 571347, + octaves = 5, + persistence = 0.63, + lacunarity = 2.0, + flags = "defaults, absvalue", +} +``` + +For 2D noise the Z component of `spread` is still defined but is ignored. +A single noise parameter table can be used for 2D or 3D noise. +]] +---@class core.NoiseParams.3d : _.NoiseParams.__base +--[[ +For octave1, this is roughly the change of input value needed for a very large +variation in the noise value generated by octave1. It is almost like a +'wavelength' for the wavy noise variation. +Each additional octave has a 'wavelength' that is smaller than the previous +octave, to create finer detail. `spread` will therefore roughly be the typical +size of the largest structures in the final noise variation. + +`spread` is a vector with values for x, y, z to allow the noise variation to be +stretched or compressed in the desired axes. +Values are positive numbers. +]] +---@field spread vector + +--[[ +WIPDOC +]] +---@alias core.NoiseParams +--- | core.NoiseParams.2d +--- | core.NoiseParams.3d \ No newline at end of file diff --git a/types/luanti_lsp_definitions/library/defs/object_properties/box.lua b/types/luanti_lsp_definitions/library/defs/object_properties/box.lua new file mode 100644 index 00000000..65d1bfdf --- /dev/null +++ b/types/luanti_lsp_definitions/library/defs/object_properties/box.lua @@ -0,0 +1,109 @@ +---@meta _ +-- DRAFT 1 DONE +-- luanti/doc/lua_api.md: Definition tables > Object properties + +-- ------------------ ObjectProperties.collisionbox.strict ------------------ -- + +--[[ +WIPDOC +]] +---@class core.ObjectProperties.collisionbox.strict +--[[ +WIPDOC +]] +---@field [1] number +--[[ +WIPDOC +]] +---@field [2] number +--[[ +WIPDOC +]] +---@field [3] number +--[[ +WIPDOC +]] +---@field [4] number +--[[ +WIPDOC +]] +---@field [5] number +--[[ +WIPDOC +]] +---@field [6] number + +--[[ +WIPDOC +]] +---@alias core.ObjectProperties.collisionbox +--- | core.ObjectProperties.collisionbox.strict +--- | number[] + +-- ------------------ ObjectProperties.selectionbox.strict ------------------ -- + +--[[ +WIPDOC +--]] +---@class core.ObjectProperties.selectionbox.strict.set : core.ObjectProperties.collisionbox.strict +--[[ +WIPDOC +]] +---@field rotate boolean? + +--[[ +WIPDOC +--]] +---@class core.ObjectProperties.selectionbox.strict.get : core.ObjectProperties.collisionbox.strict +--[[ +WIPDOC +]] +---@field rotate boolean + +--[[ +WIPDOC +]] +---@alias core.ObjectProperties.selectionbox.set +--- | core.ObjectProperties.selectionbox.strict.set +--- | number[] + +--[[ +WIPDOC +]] +---@alias core.ObjectProperties.selectionbox.get +--- | core.ObjectProperties.selectionbox.strict.get +--- | number[] + +-- ----------------------- ObjectPropertiesBase fields ---------------------- -- + +---@class _.ObjectProperties.__base.set +--[[ +{ xmin, ymin, zmin, xmax, ymax, zmax } in nodes from object position. +Collision boxes cannot rotate, setting `rotate = true` on it has no effect. +If not set, the selection box copies the collision box, and will also not rotate. +]] +---@field collisionbox core.ObjectProperties.collisionbox? +--[[ +If `rotate = false`, the selection box will not rotate with the object itself, remaining fixed to the axes. +If `rotate = true`, it will match the object's rotation and any attachment rotations. +Raycasts use the selection box and object's rotation, but do *not* obey attachment rotations. +For server-side raycasts to work correctly, +the selection box should extend at most 5 units in each direction. +]] +---@field selectionbox core.ObjectProperties.selectionbox.set? + +---@class _.ObjectProperties.__base.get +--[[ +{ xmin, ymin, zmin, xmax, ymax, zmax } in nodes from object position. +Collision boxes cannot rotate, setting `rotate = true` on it has no effect. +If not set, the selection box copies the collision box, and will also not rotate. +]] +---@field collisionbox core.ObjectProperties.collisionbox +--[[ +If `rotate = false`, the selection box will not rotate with the object itself, remaining fixed to the axes. +If `rotate = true`, it will match the object's rotation and any attachment rotations. +Raycasts use the selection box and object's rotation, but do *not* obey attachment rotations. +For server-side raycasts to work correctly, +the selection box should extend at most 5 units in each direction. +]] +---@field selectionbox core.ObjectProperties.selectionbox.get diff --git a/types/luanti_lsp_definitions/library/defs/object_properties/object_properties.lua b/types/luanti_lsp_definitions/library/defs/object_properties/object_properties.lua new file mode 100644 index 00000000..d90eb566 --- /dev/null +++ b/types/luanti_lsp_definitions/library/defs/object_properties/object_properties.lua @@ -0,0 +1,300 @@ +---@meta _ +-- DRAFT 1 DONE +-- luanti/doc/lua_api.md: Entity damage mechanism +-- luanti/doc/lua_api.md: Definition tables > Object properties + +-- Default values are injected, so nil value does not persist -> .set and .get + +-- INTERPRETATION: follow the same interpretation in ObjectRef. ObjectProperties +-- assumes it's an entity, and its fields overridden by PlayerProperties. If +-- there were any entity exclusive fields, EntityProperties would exist + +--[[ +WIPDOC +]] +core.PLAYER_MAX_HP_DEFAULT = 20 + +--[[ +WIPDOC +]] +core.PLAYER_MAX_BREATH_DEFAULT = 10 + +-- ------------------------- ObjectProperties.__base ------------------------ -- + +---@class _.ObjectProperties.__base.set +--[[ +Defines the maximum and default HP of the object. +For Lua entities, the maximum is not enforced. +For players, this defaults to `core.PLAYER_MAX_HP_DEFAULT` (20). +For Lua entities, the default is 10. +]] +---@field hp_max integer? + +---@class _.ObjectProperties.__base.get +--[[ +Defines the maximum and default HP of the object. +For Lua entities, the maximum is not enforced. +For players, this defaults to `core.PLAYER_MAX_HP_DEFAULT` (20). +For Lua entities, the default is 10. +]] +---@field hp_max integer + +-- -------------------------------- collision ------------------------------- -- + +---@class _.ObjectProperties.__base.set +--[[ +Collide with `walkable` nodes. +]] +---@field physical boolean? +--[[ +Collide with other objects if physical = true +]] +---@field collide_with_objects boolean? + + +---@class _.ObjectProperties.__base.get +--[[ +Collide with `walkable` nodes. +]] +---@field physical boolean +--[[ +Collide with other objects if physical = true +]] +---@field collide_with_objects boolean + +--[[ ObjectPropertiesBaseSet.collisionbox .. ObjectPropertiesBaseGet.selectionbox split off into box.lua ]]-- + +-- -------------------------------------------------------------------------- -- + +---@class _.ObjectProperties.__base.set +--[[ +Can be `true` if it is pointable, `false` if it can be pointed through, +or `"blocking"` if it is pointable but not selectable. +Clients older than 5.9.0 interpret `pointable = "blocking"` as `pointable = true`. +Can be overridden by the `pointabilities` of the held item. +]] +---@field pointable "blocking"|boolean? +--[[ +Multipliers for the visual size. If `z` is not specified, `x` will be used +to scale the entity along both horizontal axes. +]] +---@field visual_size vector? +--[[ +Currently unused. +]] +---@field colors {}? +--[[ +If false, object is invisible and can't be pointed. +]] +---@field is_visible boolean? +--[[ +If true, object is able to make footstep sounds of nodes +(see node sound definition for details). +]] +---@field makes_footstep_sound boolean? +--[[ +Set constant rotation in radians per second, positive or negative. +Object rotates along the local Y-axis, and works with set_rotation. +Set to 0 to disable constant rotation. +]] +---@field automatic_rotate number? +--[[ +If positive number, object will climb upwards when it moves +horizontally against a `walkable` node, if the height difference +is within `stepheight` and if the object current max Y in the world +is greater or equal than the node min Y. +]] +---@field stepheight number? +--[[ +Automatically set yaw to movement direction, offset in degrees. +'false' to disable. +]] +---@field automatic_face_movement_dir number|false? +--[[ +Limit automatic rotation to this value in degrees per second. +No limit if value <= 0. +]] +---@field automatic_face_movement_max_rotation_per_sec number? +--[[ +Add this much extra lighting when calculating texture color. +Value < 0 disables light's effect on texture color. +For faking self-lighting, UI style entities, or programmatic coloring +in mods. +]] +---@field glow core.Light.source? + +---@class _.ObjectProperties.__base.get +--[[ +Can be `true` if it is pointable, `false` if it can be pointed through, +or `"blocking"` if it is pointable but not selectable. +Clients older than 5.9.0 interpret `pointable = "blocking"` as `pointable = true`. +Can be overridden by the `pointabilities` of the held item. +]] +---@field pointable "blocking"|boolean +--[[ +Multipliers for the visual size. If `z` is not specified, `x` will be used +to scale the entity along both horizontal axes. +]] +---@field visual_size vector +--[[ +Currently unused. +]] +---@field colors {} +--[[ +If false, object is invisible and can't be pointed. +]] +---@field is_visible boolean +--[[ +If true, object is able to make footstep sounds of nodes +(see node sound definition for details). +]] +---@field makes_footstep_sound boolean +--[[ +Set constant rotation in radians per second, positive or negative. +Object rotates along the local Y-axis, and works with set_rotation. +Set to 0 to disable constant rotation. +]] +---@field automatic_rotate number +--[[ +If positive number, object will climb upwards when it moves +horizontally against a `walkable` node, if the height difference +is within `stepheight` and if the object current max Y in the world +is greater or equal than the node min Y. +]] +---@field stepheight number +--[[ +Automatically set yaw to movement direction, offset in degrees. +'false' to disable. +]] +---@field automatic_face_movement_dir number|false +--[[ +Limit automatic rotation to this value in degrees per second. +No limit if value <= 0. +]] +---@field automatic_face_movement_max_rotation_per_sec number +--[[ +Add this much extra lighting when calculating texture color. +Value < 0 disables light's effect on texture color. +For faking self-lighting, UI style entities, or programmatic coloring +in mods. +]] +---@field glow core.Light.source + +-- --------------------------------- nametag -------------------------------- -- + +---@class _.ObjectProperties.__base.set +--[[ +The name to display on the head of the object. By default empty. +If the object is a player, a nil or empty nametag is replaced by the player's name. +For all other objects, a nil or empty string removes the nametag. +To hide a nametag, set its color alpha to zero. That will disable it entirely. +]] +---@field nametag string? +--[[ +Sets text color of nametag +]] +---@field nametag_color core.ColorSpec? +--[[ +Sets background color of nametag +`false` will cause the background to be set automatically based on user settings. +Default: false +]] +---@field nametag_bgcolor core.ColorSpec? +--[[ +Sets the font size of the nametag in pixels. +`false` will cause the size to be set automatically based on user settings. +Default: false +]] +---@field nametag_fontsize integer|false? +--[[ +Sets the font size of the nametag in pixels. +`false` will cause the size to be set automatically based on user settings. +Default: false +]] +---@field nametag_scale_z boolean? + +---@class _.ObjectProperties.__base.get +--[[ +The name to display on the head of the object. By default empty. +If the object is a player, a nil or empty nametag is replaced by the player's name. +For all other objects, a nil or empty string removes the nametag. +To hide a nametag, set its color alpha to zero. That will disable it entirely. +]] +---@field nametag string +--[[ +Sets text color of nametag +]] +---@field nametag_color core.ColorSpec +--[[ +Sets background color of nametag +`false` will cause the background to be set automatically based on user settings. +Default: false +]] +---@field nametag_bgcolor core.ColorSpec + + +-- -------------------------------------------------------------------------- -- + +---@class _.ObjectProperties.__base.set +--[[ +Same as infotext for nodes. Empty by default +]] +---@field infotext string? +--[[ +If false, never save this object statically. It will simply be +deleted when the block gets unloaded. +The get_staticdata() callback is never called then. +Defaults to 'true'. +]] +---@field static_save boolean? +--[[ +Texture modifier to be applied for a short duration when object is hit +]] +---@field damage_texture_modifier core.Texture? +--[[ +Defaults to true for players, false for other entities. +If set to true the entity will show as a marker on the minimap. +]] +---@field show_on_minimap boolean? + +---@class _.ObjectProperties.__base.get +--[[ +Same as infotext for nodes. Empty by default +]] +---@field infotext string +--[[ +If false, never save this object statically. It will simply be +deleted when the block gets unloaded. +The get_staticdata() callback is never called then. +Defaults to 'true'. +]] +---@field static_save boolean +--[[ +Texture modifier to be applied for a short duration when object is hit +]] +---@field damage_texture_modifier core.Texture +--[[ +Defaults to true for players, false for other entities. +If set to true the entity will show as a marker on the minimap. +]] +---@field show_on_minimap boolean + +-- ---------------------------- ObjectProperties ---------------------------- -- + +---@alias core.ObjectProperties.set +--- | core.ObjectProperties.cube.set +--- | core.ObjectProperties.sprite.set +--- | core.ObjectProperties.upright_sprite.set +--- | core.ObjectProperties.mesh.set +--- | core.ObjectProperties.wielditem.set +--- | core.ObjectProperties.item.set +--- | core.ObjectProperties.node.set + +---@alias core.ObjectProperties.get +--- | core.ObjectProperties.cube.get +--- | core.ObjectProperties.sprite.get +--- | core.ObjectProperties.upright_sprite.get +--- | core.ObjectProperties.mesh.get +--- | core.ObjectProperties.wielditem.get +--- | core.ObjectProperties.item.get +--- | core.ObjectProperties.node.get \ No newline at end of file diff --git a/types/luanti_lsp_definitions/library/defs/object_properties/partial/backface_clling.lua b/types/luanti_lsp_definitions/library/defs/object_properties/partial/backface_clling.lua new file mode 100644 index 00000000..e9877322 --- /dev/null +++ b/types/luanti_lsp_definitions/library/defs/object_properties/partial/backface_clling.lua @@ -0,0 +1,17 @@ +---@meta _ +-- DRAFT 1 DONE +-- luanti/doc/lua_api.md: Definition tables > Object properties + +---@class _.ObjectProperties.backface_culling.set.__partial +--[[ +Set to false to disable backface_culling for model +Note: only used by "mesh" and "cube" visual +]] +---@field backface_culling boolean? + +---@class _.ObjectProperties.backface_culling.get.__partial +--[[ +Set to false to disable backface_culling for model +Note: only used by "mesh" and "cube" visual +]] +---@field backface_culling boolean \ No newline at end of file diff --git a/types/luanti_lsp_definitions/library/defs/object_properties/partial/shaded.lua b/types/luanti_lsp_definitions/library/defs/object_properties/partial/shaded.lua new file mode 100644 index 00000000..f1a803eb --- /dev/null +++ b/types/luanti_lsp_definitions/library/defs/object_properties/partial/shaded.lua @@ -0,0 +1,19 @@ +---@meta _ +-- DRAFT 1 DONE +-- luanti/doc/lua_api.md: Definition tables > Object properties + +---@class _.ObjectProperties.shaded.set.__partial +--[[ +Setting this to 'false' disables diffuse lighting of entity +Note: ignored for "item", "wielditem" and "node" visual +]] +---@field shaded boolean? + +---@class _.ObjectProperties.shaded.get.__partial +--[[ +Setting this to 'false' disables diffuse lighting of entity +Note: ignored for "item", "wielditem" and "node" visual +]] +---@field shaded boolean + + diff --git a/types/luanti_lsp_definitions/library/defs/object_properties/partial/spritesheet.lua b/types/luanti_lsp_definitions/library/defs/object_properties/partial/spritesheet.lua new file mode 100644 index 00000000..a0054f15 --- /dev/null +++ b/types/luanti_lsp_definitions/library/defs/object_properties/partial/spritesheet.lua @@ -0,0 +1,33 @@ +---@meta _ +-- DRAFT 1 DONE +-- luanti/doc/lua_api.md: Definition tables > Object properties + +---@class _.ObjectProperties.spritesheet.set.__partial +--[[ +Used with spritesheet textures for animation and/or frame selection +according to position relative to player. +Defines the number of columns and rows in the spritesheet: +{columns, rows}. +]] +---@field spritediv vec2i.xy? +--[[ +Used with spritesheet textures. +Defines the {column, row} position of the initially used frame in the +spritesheet. +]] +---@field initial_sprite_basepos vec2i.xy? + +---@class _.ObjectProperties.spritesheet.get.__partial +--[[ +Used with spritesheet textures for animation and/or frame selection +according to position relative to player. +Defines the number of columns and rows in the spritesheet: +{columns, rows}. +]] +---@field spritediv vec2i.xy +--[[ +Used with spritesheet textures. +Defines the {column, row} position of the initially used frame in the +spritesheet. +]] +---@field initial_sprite_basepos vec2i.xy diff --git a/types/luanti_lsp_definitions/library/defs/object_properties/player_properties.lua b/types/luanti_lsp_definitions/library/defs/object_properties/player_properties.lua new file mode 100644 index 00000000..3b32273d --- /dev/null +++ b/types/luanti_lsp_definitions/library/defs/object_properties/player_properties.lua @@ -0,0 +1,111 @@ +---@meta _ +-- DRAFT 1 DONE +-- luanti/doc/lua_api.md: Definition tables > Object properties + +-- ------------------------- PlayerProperties.__base ------------------------ -- + +--[[ +WIPDOC +]] +---@class _.PlayerProperties.__base.set : _.ObjectProperties.__base.set +--[[ +For players only. Defines the maximum amount of "breath" for the player. +Defaults to `core.PLAYER_MAX_BREATH_DEFAULT` (10). +]] +---@field breath_max integer? +--[[ +For players only. Zoom FOV in degrees. +Note that zoom loads and/or generates world beyond the server's +maximum send and generate distances, so acts like a telescope. +Smaller zoom_fov values increase the distance loaded/generated. +Defaults to 15 in creative mode, 0 in survival mode. +zoom_fov = 0 disables zooming for the player. +]] +---@field zoom_fov number? +--[[ +For players only. Camera height above feet position in nodes. +]] +---@field eye_height number? +--[[ +The name to display on the head of the object. By default empty. +If the object is a player, a nil or empty nametag is replaced by the player's name. +For all other objects, a nil or empty string removes the nametag. +To hide a nametag, set its color alpha to zero. That will disable it entirely. +]] +---@field nametag string? +--[[ +Defaults to true for players, false for other entities. +If set to true the entity will show as a marker on the minimap. +]] +---@field show_on_minimap boolean? + +--[[ +WIPDOC +]] +---@class _.PlayerProperties.__base.get : _.ObjectProperties.__base.get +--[[ +For players only. Defines the maximum amount of "breath" for the player. +Defaults to `core.PLAYER_MAX_BREATH_DEFAULT` (10). +]] +---@field breath_max integer +--[[ +For players only. Zoom FOV in degrees. +Note that zoom loads and/or generates world beyond the server's +maximum send and generate distances, so acts like a telescope. +Smaller zoom_fov values increase the distance loaded/generated. +Defaults to 15 in creative mode, 0 in survival mode. +zoom_fov = 0 disables zooming for the player. +]] +---@field zoom_fov number +--[[ +For players only. Camera height above feet position in nodes. +]] +---@field eye_height number +--[[ +The name to display on the head of the object. By default empty. +If the object is a player, a nil or empty nametag is replaced by the player's name. +For all other objects, a nil or empty string removes the nametag. +To hide a nametag, get its color alpha to zero. That will disable it entirely. +]] +---@field nametag string +--[[ +Defaults to true for players, false for other entities. +If get to true the entity will show as a marker on the minimap. +]] +---@field show_on_minimap boolean + +-- ---------------------------- PlayerProperties ---------------------------- -- + +---@class core.PlayerProperties.cube.set : _.PlayerProperties.__base.set, _.ObjectProperties.cube.set.__partial +---@class core.PlayerProperties.sprite.set : _.PlayerProperties.__base.set, _.ObjectProperties.sprite.set.__partial +---@class core.PlayerProperties.upright_sprite.set : _.PlayerProperties.__base.set, _.ObjectProperties.upright_sprite.set.__partial +---@class core.PlayerProperties.mesh.set : _.PlayerProperties.__base.set, _.ObjectProperties.mesh.set.__partial +---@class core.PlayerProperties.wielditem.set : _.PlayerProperties.__base.set, _.ObjectProperties.wielditem.set.__partial +---@class core.PlayerProperties.item.set : _.PlayerProperties.__base.set, _.ObjectProperties.item.__partial +---@class core.PlayerProperties.node.set : _.PlayerProperties.__base.set, _.ObjectProperties.node.set.__partial + +---@alias core.PlayerProperties.set +--- | core.PlayerProperties.cube.set +--- | core.PlayerProperties.sprite.set +--- | core.PlayerProperties.upright_sprite.set +--- | core.PlayerProperties.mesh.set +--- | core.PlayerProperties.wielditem.set +--- | core.PlayerProperties.item.set +--- | core.PlayerProperties.node.set + +---@class core.PlayerProperties.cube.get : _.PlayerProperties.__base.get, _.ObjectProperties.cube.get.__partial +---@class core.PlayerProperties.sprite.get : _.PlayerProperties.__base.get, _.ObjectProperties.sprite.get.__partial +---@class core.PlayerProperties.upright_sprite.get : _.PlayerProperties.__base.get, _.ObjectProperties.upright_sprite.get.__partial +---@class core.PlayerProperties.mesh.get : _.PlayerProperties.__base.get, _.ObjectProperties.mesh.get.__partial +---@class core.PlayerProperties.wielditem.get : _.PlayerProperties.__base.get, _.ObjectProperties.wielditem.get.__partial +---@class core.PlayerProperties.item.get : _.PlayerProperties.__base.get, _.ObjectProperties.item.__partial +---@class core.PlayerProperties.node.get : _.PlayerProperties.__base.get, _.ObjectProperties.node.get.__partial + +---@alias core.PlayerProperties.get +--- | core.PlayerProperties.cube.get +--- | core.PlayerProperties.sprite.get +--- | core.PlayerProperties.upright_sprite.get +--- | core.PlayerProperties.mesh.get +--- | core.PlayerProperties.wielditem.get +--- | core.PlayerProperties.item.get +--- | core.PlayerProperties.node.get \ No newline at end of file diff --git a/types/luanti_lsp_definitions/library/defs/object_properties/types/cube.lua b/types/luanti_lsp_definitions/library/defs/object_properties/types/cube.lua new file mode 100644 index 00000000..7a4ab614 --- /dev/null +++ b/types/luanti_lsp_definitions/library/defs/object_properties/types/cube.lua @@ -0,0 +1,85 @@ +---@meta _ +-- DRAFT 1 DONE +-- luanti/doc/lua_api.md: Definition tables > Object properties + +-- ------------------ ObjectProperties.cube.textures.strict ----------------- -- + +--[[ +WIPDOC +]] +---@class core.ObjectProperties.cube.textures.strict +--[[ +WIPDOC +]] +---@field [1] core.Texture +--[[ +WIPDOC +]] +---@field [2] core.Texture +--[[ +WIPDOC +]] +---@field [3] core.Texture +--[[ +WIPDOC +]] +---@field [4] core.Texture +--[[ +WIPDOC +]] +---@field [5] core.Texture +--[[ +WIPDOC +]] +---@field [6] core.Texture + +--[[ +WIPDOC +]] +---@alias core.ObjectProperties.cube.textures +--- | core.ObjectProperties.cube.textures.strict +--- | string[] + +-- -------------------------- ObjectProperties.cube ------------------------- -- + +--[[ +WIPDOC +]] +---@class core.ObjectProperties.cube.set : _.ObjectProperties.__base.set, _.ObjectProperties.cube.set.__partial + +--[[ +WIPDOC +]] +---@class core.ObjectProperties.cube.get : _.ObjectProperties.__base.get, _.ObjectProperties.cube.get.__partial + +---@class _.ObjectProperties.cube.set.__partial : _.ObjectProperties.backface_culling.set.__partial, _.ObjectProperties.shaded.set.__partial +--[[ +WIPDOC +]] +---@field visual "cube" +--[[ +Number of required textures depends on visual: +"cube" uses 6 textures just like a node, but all 6 must be defined. +"sprite" uses 1 texture. +"upright_sprite" uses 2 textures: {front, back}. +"mesh" requires one texture for each mesh buffer/material (in order) +Deprecated usage of "wielditem" expects 'textures = {itemname}' (see 'visual' above). +Unofficial note: I *guessed* that it's string[] but i am not sure +]] +---@field textures core.ObjectProperties.cube.textures? + +---@class _.ObjectProperties.cube.get.__partial : _.ObjectProperties.backface_culling.get.__partial, _.ObjectProperties.shaded.get.__partial +--[[ +WIPDOC +]] +---@field visual "cube" +--[[ +Number of required textures depends on visual: +"cube" uses 6 textures just like a node, but all 6 must be defined. +"sprite" uses 1 texture. +"upright_sprite" uses 2 textures: {front, back}. +"mesh" requires one texture for each mesh buffer/material (in order) +Deprecated usage of "wielditem" expects 'textures = {itemname}' (see 'visual' above). +Unofficial note: I *guessed* that it's string[] but i am not sure +]] +---@field textures core.ObjectProperties.cube.textures diff --git a/types/luanti_lsp_definitions/library/defs/object_properties/types/item.lua b/types/luanti_lsp_definitions/library/defs/object_properties/types/item.lua new file mode 100644 index 00000000..54dd93a1 --- /dev/null +++ b/types/luanti_lsp_definitions/library/defs/object_properties/types/item.lua @@ -0,0 +1,19 @@ +---@meta _ +-- DRAFT 1 DONE +-- luanti/doc/lua_api.md: Definition tables > Object properties + +--[[ +WIPDOC +]] +---@class core.ObjectProperties.item.set : _.ObjectProperties.__base.set, _.ObjectProperties.item.__partial + +--[[ +WIPDOC +]] +---@class core.ObjectProperties.item.get : _.ObjectProperties.__base.get, _.ObjectProperties.item.__partial + +---@class _.ObjectProperties.item.__partial +--[[ +WIPDOC +]] +---@field visual "item" diff --git a/types/luanti_lsp_definitions/library/defs/object_properties/types/mesh.lua b/types/luanti_lsp_definitions/library/defs/object_properties/types/mesh.lua new file mode 100644 index 00000000..130a6495 --- /dev/null +++ b/types/luanti_lsp_definitions/library/defs/object_properties/types/mesh.lua @@ -0,0 +1,55 @@ +---@meta _ +-- DRAFT 1 DONE +-- luanti/doc/lua_api.md: Definition tables > Object properties + +--[[ +WIPDOC +]] +---@class core.ObjectProperties.mesh.set : _.ObjectProperties.__base.set, _.ObjectProperties.mesh.set.__partial + +--[[ +WIPDOC +]] +---@class core.ObjectProperties.mesh.get : _.ObjectProperties.__base.get, _.ObjectProperties.mesh.get.__partial + +---@class _.ObjectProperties.mesh.set.__partial : _.ObjectProperties.backface_culling.set.__partial, _.ObjectProperties.shaded.set.__partial +--[[ +WIPDOC +]] +---@field visual "mesh" +--[[ +File name of mesh when using "mesh" visual. +For legacy reasons, this uses a 10x scale for meshes: 10 units = 1 node. +]] +---@field mesh core.Path? +--[[ +Number of required textures depends on visual: +"cube" uses 6 textures just like a node, but all 6 must be defined. +"sprite" uses 1 texture. +"upright_sprite" uses 2 textures: {front, back}. +"mesh" requires one texture for each mesh buffer/material (in order) +Deprecated usage of "wielditem" expects 'textures = {itemname}' (see 'visual' above). +Unofficial note: I *guessed* that it's string[] but i am not sure +]] +---@field textures core.Texture[]? + +---@class _.ObjectProperties.mesh.get.__partial : _.ObjectProperties.backface_culling.get.__partial, _.ObjectProperties.shaded.get.__partial +--[[ +WIPDOC +]] +---@field visual "mesh" +--[[ +File name of mesh when using "mesh" visual. +For legacy reasons, this uses a 10x scale for meshes: 10 units = 1 node. +]] +---@field mesh core.Path +--[[ +Number of required textures depends on visual: +"cube" uses 6 textures just like a node, but all 6 must be defined. +"sprite" uses 1 texture. +"upright_sprite" uses 2 textures: {front, back}. +"mesh" requires one texture for each mesh buffer/material (in order) +Deprecated usage of "wielditem" expects 'textures = {itemname}' (see 'visual' above). +Unofficial note: I *guessed* that it's string[] but i am not sure +]] +---@field textures core.Texture[] diff --git a/types/luanti_lsp_definitions/library/defs/object_properties/types/node.lua b/types/luanti_lsp_definitions/library/defs/object_properties/types/node.lua new file mode 100644 index 00000000..79a3de1f --- /dev/null +++ b/types/luanti_lsp_definitions/library/defs/object_properties/types/node.lua @@ -0,0 +1,33 @@ +---@meta _ +-- DRAFT 1 DONE +-- luanti/doc/lua_api.md: Definition tables > Object properties + +--[[ +WIPDOC +]] +---@class core.ObjectProperties.node.set : _.ObjectProperties.__base.set, _.ObjectProperties.node.set.__partial + +--[[ +WIPDOC +]] +---@class core.ObjectProperties.node.get : _.ObjectProperties.__base.get, _.ObjectProperties.node.get.__partial + +---@class _.ObjectProperties.node.set.__partial +--[[ +WIPDOC +]] +---@field visual "node" +--[[ +Node to show when using the "node" visual +]] +---@field node core.Node.set? + +---@class _.ObjectProperties.node.get.__partial +--[[ +WIPDOC +]] +---@field visual "node" +--[[ +Node to show when using the "node" visual +]] +---@field node core.Node.get diff --git a/types/luanti_lsp_definitions/library/defs/object_properties/types/sprite.lua b/types/luanti_lsp_definitions/library/defs/object_properties/types/sprite.lua new file mode 100644 index 00000000..6ecf7d33 --- /dev/null +++ b/types/luanti_lsp_definitions/library/defs/object_properties/types/sprite.lua @@ -0,0 +1,64 @@ +---@meta _ +-- DRAFT 1 DONE +-- luanti/doc/lua_api.md: Definition tables > Object properties + +-- ----------------- ObjectProperties.sprite.textures.strict ---------------- -- + +--[[ +WIPDOC +]] +---@class core.ObjectProperties.sprite.textures.strict +--[[ +WIPDOC +]] +---@field [1] number + +--[[ +WIPDOC +]] +---@alias core.ObjectProperties.sprite.textures +--- | core.ObjectProperties.sprite.textures.strict +--- | string[] + +-- ------------------------- ObjectProperties.sprite ------------------------ -- +--[[ +WIPDOC +]] +---@class core.ObjectProperties.sprite.set : _.ObjectProperties.__base.set, _.ObjectProperties.sprite.set.__partial + +--[[ +WIPDOC +]] +---@class core.ObjectProperties.sprite.get : _.ObjectProperties.__base.get, _.ObjectProperties.sprite.get.__partial + +---@class _.ObjectProperties.sprite.set.__partial : _.ObjectProperties.spritesheet.set.__partial, _.ObjectProperties.spritesheet.set.__partial +--[[ +WIPDOC +]] +---@field visual "sprite" +--[[ +Number of required textures depends on visual: +"cube" uses 6 textures just like a node, but all 6 must be defined. +"sprite" uses 1 texture. +"upright_sprite" uses 2 textures: {front, back}. +"mesh" requires one texture for each mesh buffer/material (in order) +Deprecated usage of "wielditem" expects 'textures = {itemname}' (see 'visual' above). +Unofficial note: I *guessed* that it's string[] but i am not sure +]] +---@field textures core.ObjectProperties.sprite.textures? + +---@class _.ObjectProperties.sprite.get.__partial : _.ObjectProperties.spritesheet.get.__partial, _.ObjectProperties.spritesheet.get.__partial +--[[ +WIPDOC +]] +---@field visual "sprite" +--[[ +Number of required textures depends on visual: +"cube" uses 6 textures just like a node, but all 6 must be defined. +"sprite" uses 1 texture. +"upright_sprite" uses 2 textures: {front, back}. +"mesh" requires one texture for each mesh buffer/material (in order) +Deprecated usage of "wielditem" expects 'textures = {itemname}' (see 'visual' above). +Unofficial note: I *guessed* that it's string[] but i am not sure +]] +---@field textures core.ObjectProperties.sprite.textures diff --git a/types/luanti_lsp_definitions/library/defs/object_properties/types/upright_sprite.lua b/types/luanti_lsp_definitions/library/defs/object_properties/types/upright_sprite.lua new file mode 100644 index 00000000..dc28b81e --- /dev/null +++ b/types/luanti_lsp_definitions/library/defs/object_properties/types/upright_sprite.lua @@ -0,0 +1,69 @@ +---@meta _ +-- DRAFT 1 DONE +-- luanti/doc/lua_api.md: Definition tables > Object properties + +-- ------------- ObjectProperties.upright_sprite.textures.strict ------------ -- + +--[[ +WIPDOC +]] +---@class core.ObjectProperties.upright_sprite.textures.strict +--[[ +WIPDOC +]] +---@field [1] number +--[[ +WIPDOC +]] +---@field [2] number + +--[[ +WIPDOC +]] +---@alias core.ObjectProperties.upright_sprite.textures +--- | core.ObjectProperties.upright_sprite.textures.strict +--- | string[] + +-- ------------------- ObjectProperties.upright_sprite.set ------------------ -- + +--[[ +WIPDOC +]] +---@class core.ObjectProperties.upright_sprite.set : _.ObjectProperties.__base.set, _.ObjectProperties.upright_sprite.set.__partial + +--[[ +WIPDOC +]] +---@class core.ObjectProperties.upright_sprite.get : _.ObjectProperties.__base.get, _.ObjectProperties.upright_sprite.get.__partial + +---@class _.ObjectProperties.upright_sprite.set.__partial : _.ObjectProperties.spritesheet.set.__partial, _.ObjectProperties.shaded.set.__partial +--[[ +WIPDOC +]] +---@field visual "upright_sprite" +--[[ +Number of required textures depends on visual: +"cube" uses 6 textures just like a node, but all 6 must be defined. +"sprite" uses 1 texture. +"upright_sprite" uses 2 textures: {front, back}. +"mesh" requires one texture for each mesh buffer/material (in order) +Deprecated usage of "wielditem" expects 'textures = {itemname}' (see 'visual' above). +Unofficial note: I *guessed* that it's string[] but i am not sure +]] +---@field textures core.ObjectProperties.upright_sprite.textures? + +---@class _.ObjectProperties.upright_sprite.get.__partial : _.ObjectProperties.spritesheet.get.__partial, _.ObjectProperties.shaded.get.__partial +--[[ +WIPDOC +]] +---@field visual "upright_sprite" +--[[ +Number of required textures depends on visual: +"cube" uses 6 textures just like a node, but all 6 must be defined. +"sprite" uses 1 texture. +"upright_sprite" uses 2 textures: {front, back}. +"mesh" requires one texture for each mesh buffer/material (in order) +Deprecated usage of "wielditem" expects 'textures = {itemname}' (see 'visual' above). +Unofficial note: I *guessed* that it's string[] but i am not sure +]] +---@field textures core.ObjectProperties.upright_sprite.textures diff --git a/types/luanti_lsp_definitions/library/defs/object_properties/types/wielditem.lua b/types/luanti_lsp_definitions/library/defs/object_properties/types/wielditem.lua new file mode 100644 index 00000000..178e642a --- /dev/null +++ b/types/luanti_lsp_definitions/library/defs/object_properties/types/wielditem.lua @@ -0,0 +1,66 @@ +---@meta _ +-- DRAFT 1 DONE +-- luanti/doc/lua_api.md: Definition tables > Object properties + +-- --------------- ObjectProperties.wielditem.textures.strict --------------- -- + +--[[ +WIPDOC +]] +---@class core.ObjectProperties.wielditem.textures.strict +--[[ +WIPDOC +]] +---@field [1] number + +--[[ +WIPDOC +]] +---@alias core.ObjectProperties.wielditem.textures +--- | core.ObjectProperties.wielditem.textures.strict +--- | string[] + +-- ----------------------- ObjectProperties.wielditem ----------------------- -- + +--[[ +WIPDOC +]] +---@class core.ObjectProperties.wielditem.set : _.ObjectProperties.__base.set, _.ObjectProperties.wielditem.set.__partial + +--[[ +WIPDOC +]] +---@class core.ObjectProperties.wielditem.get : _.ObjectProperties.__base.get, _.ObjectProperties.wielditem.get.__partial + +---@class _.ObjectProperties.wielditem.set.__partial +--[[ +WIPDOC +]] +---@field visual "wielditem" +--[[ +WIPDOC +]] +---@field wield_item core.Item.name +--[[ +WIPDOC + +* @deprecated +]] +---@field textures core.ObjectProperties.wielditem.textures? + +---@class _.ObjectProperties.wielditem.get.__partial +--[[ +WIPDOC +]] +---@field visual "wielditem" +--[[ +WIPDOC +]] +---@field wield_item core.Item.name +--[[ +WIPDOC + +* @deprecated 5.X +]] +---@field textures core.ObjectProperties.wielditem.textures + diff --git a/types/luanti_lsp_definitions/library/defs/ore/blob.lua b/types/luanti_lsp_definitions/library/defs/ore/blob.lua new file mode 100644 index 00000000..ebd22a28 --- /dev/null +++ b/types/luanti_lsp_definitions/library/defs/ore/blob.lua @@ -0,0 +1,43 @@ +---@meta _ +-- DRAFT 1 DONE +-- luanti/doc/lua_api.md: Ores +-- luanti/doc/lua_api.md: Definition tables > Ore Definition + +--[[ +WIPDOC +]] +---@class core.OreDef.blob : _.OreDef.__base +--[[ +WIPDOC +]] +---@field ore_type "blob" +--[[ +Ore has a 1 out of clust_scarcity chance of spawning in a node. +If the desired average distance between ores is 'd', set this to +d * d * d. +]] +---@field clust_scarcity integer? +--[[ +Number of ores in a clust +]] +---@field clust_num_ores integer? +--[[ +Size of the bounding box of the cluster. +In this example, there is a 3 * 3 * 3 cluster where 8 out of the 27 +nodes are coal ore. +]] +---@field clust_size integer? +--[[ +If noise is above this threshold, ore is placed. Not needed for a +uniform distribution. +]] +---@field noise_threshold number? +--[[ +NoiseParams structure describing one of the noises used for +ore distribution. +Needed by "sheet", "puff", "blob" and "vein" ores. +Omit from "scatter" ore for a uniform ore distribution. +Omit from "stratum" ore for a simple horizontal strata from y_min to +y_max. +]] +---@field noise_params core.NoiseParams.3d diff --git a/types/luanti_lsp_definitions/library/defs/ore/ore.lua b/types/luanti_lsp_definitions/library/defs/ore/ore.lua new file mode 100644 index 00000000..eb062f15 --- /dev/null +++ b/types/luanti_lsp_definitions/library/defs/ore/ore.lua @@ -0,0 +1,58 @@ +---@meta _ +-- DRAFT 1 DONE +-- luanti/doc/lua_api.md: Ores +-- luanti/doc/lua_api.md: Definition tables > Ore Definition + +--[[ +WIPDOC +]] +---@class core.OreID : integer + +-- ------------------------------ OreDef.__base ----------------------------- -- + +---@class _.OreDef.__base +--[[ +WIPDOC +]] +---@field name string? +--[[ +Ore node to place +]] +---@field ore core.Node.name +--[[ +Param2 to set for ore (e.g. facedir rotation) +]] +---@field ore_param2 core.Param2? +--[[ +Node to place ore in. Multiple are possible by passing a list. +]] +---@field wherein OneOrMany +--[[ +WIPDOC +]] +---@field y_min integer? +--[[ +WIPDOC +]] +---@field y_max integer? +--[[ +List of biomes in which this ore occurs. +Occurs in all biomes if this is omitted, and ignored if the Mapgen +being used does not support biomes. +Can be a list of (or a single) biome names, IDs, or definitions. +]] +---@field biomes OneOrMany? + +-- --------------------------------- OreDef --------------------------------- -- + +--[[ +WIPDOC +]] +---@alias core.OreDef +--- | core.OreDef.scatter.uniform +--- | core.OreDef.scatter.nonuniform +--- | core.OreDef.sheet +--- | core.OreDef.puff +--- | core.OreDef.blob +--- | core.OreDef.vein +--- | core.OreDef.stratum \ No newline at end of file diff --git a/types/luanti_lsp_definitions/library/defs/ore/puff.lua b/types/luanti_lsp_definitions/library/defs/ore/puff.lua new file mode 100644 index 00000000..70d67b54 --- /dev/null +++ b/types/luanti_lsp_definitions/library/defs/ore/puff.lua @@ -0,0 +1,92 @@ +---@meta _ +-- DRAFT 1 DONE +-- luanti/doc/lua_api.md: Flag Specifier Format +-- luanti/doc/lua_api.md: Ores +-- luanti/doc/lua_api.md: Definition tables > Ore Definition + +-- ---------------------------- OreDef.puff.flags --------------------------- -- + +--[[ +WIPDOC +]] +---@class core.OreDef.puff.flags.tablefmt +--[[ +WIPDOC +]] +---@field puff_cliffs boolean? +--[[ +WIPDOC +]] +---@field nopuff_cliffs boolean? +--[[ +WIPDOC +]] +---@field puff_additive_composition boolean? +--[[ +WIPDOC +]] +---@field nopuff_additive_composition boolean? +--[[ +WIPDOC +]] +---@alias core.OreDef.puff.flags.stringfmt string + +--[[ +WIPDOC +]] +---@alias core.OreDef.puff.flags +--- | core.OreDef.puff.flags.tablefmt +--- | core.OreDef.puff.flags.stringfmt + +-- ------------------------------- OreDef.puff ------------------------------ -- + +--[[ +WIPDOC +]] +---@class core.OreDef.puff : _.OreDef.__base +--[[ +WIPDOC +]] +---@field ore_type "puff" +--[[ +WIPDOC +]] +---@field flags core.OreDef.puff.flags? +--[[ +Ore has a 1 out of clust_scarcity chance of spawning in a node. +If the desired average distance between ores is 'd', set this to +d * d * d. +]] +---@field clust_scarcity integer? +--[[ +Number of ores in a cluster +]] +---@field clust_num_ores integer? +--[[ +Size of the bounding box of the cluster. +In this example, there is a 3 * 3 * 3 cluster where 8 out of the 27 +nodes are coal ore. +]] +---@field clust_size integer? +--[[ +If noise is above this threshold, ore is placed. Not needed for a +uniform distribution. +]] +---@field noise_threshold number? +--[[ +NoiseParams structure describing one of the noises used for +ore distribution. +Needed by "sheet", "puff", "blob" and "vein" ores. +Omit from "scatter" ore for a uniform ore distribution. +Omit from "stratum" ore for a simple horizontal strata from y_min to +y_max. +]] +---@field noise_params core.NoiseParams.3d +--[[ +"puff" type +]] +---@field np_puff_top core.NoiseParams.3d? +--[[ +WIPDOC +]] +---@field np_puff_bottom core.NoiseParams.3d? \ No newline at end of file diff --git a/types/luanti_lsp_definitions/library/defs/ore/scatter.lua b/types/luanti_lsp_definitions/library/defs/ore/scatter.lua new file mode 100644 index 00000000..a9ba2870 --- /dev/null +++ b/types/luanti_lsp_definitions/library/defs/ore/scatter.lua @@ -0,0 +1,55 @@ +---@meta _ +-- DRAFT 1 DONE +-- luanti/doc/lua_api.md: Ores + + +-- ------------------------ OreDef.scatter.__partial ------------------------ -- + +---@class _.OreDef.scatter.__partial +--[[ +WIPDOC +]] +---@field ore_type "scatter" +--[[ +Ore has a 1 out of clust_scarcity chance of spawning in a node. +If the desired average distance between ores is 'd', set this to +d * d * d. +]] +---@field clust_scarcity integer? +--[[ +Number of ores in a cluster +]] +---@field clust_num_ores integer? +--[[ +Size of the bounding box of the cluster. +In this example, there is a 3 * 3 * 3 cluster where 8 out of the 27 +nodes are coal ore. +]] +---@field clust_size integer? + +-- ----------------------------- OreDef.scatter ----------------------------- -- + + +--[[ +WIPDOC +]] +---@class core.OreDef.scatter.uniform : _.OreDef.__base, _.OreDef.scatter.__partial + +--[[ +WIPDOC +]] +---@class core.OreDef.scatter.nonuniform : _.OreDef.__base, _.OreDef.scatter.__partial +--[[ +If noise is above this threshold, ore is placed. Not needed for a +uniform distribution. +]] +---@field noise_threshold number? +--[[ +NoiseParams structure describing one of the noises used for +ore distribution. +Needed by "sheet", "puff", "blob" and "vein" ores. +Omit from "scatter" ore for a uniform ore distribution. +Omit from "stratum" ore for a simple horizontal strata from y_min to +y_max. +]] +---@field noise_params core.NoiseParams.3d diff --git a/types/luanti_lsp_definitions/library/defs/ore/sheet.lua b/types/luanti_lsp_definitions/library/defs/ore/sheet.lua new file mode 100644 index 00000000..12c21544 --- /dev/null +++ b/types/luanti_lsp_definitions/library/defs/ore/sheet.lua @@ -0,0 +1,45 @@ +---@meta _ +-- DRAFT 1 DONE +-- luanti/doc/lua_api.md: Ores +-- luanti/doc/lua_api.md: Definition tables > Ore Definition + +--[[ +WIPDOC +]] +---@class core.OreDef.sheet : _.OreDef.__base +--[[ +WIPDOC +]] +---@field ore_type "sheet" +--[[ +Size of the bounding box of the cluster. +In this example, there is a 3 * 3 * 3 cluster where 8 out of the 27 +nodes are coal ore. +]] +---@field clust_size integer? +--[[ +If noise is above this threshold, ore is placed. Not needed for a +uniform distribution. +]] +---@field noise_threshold number? +--[[ +NoiseParams structure describing one of the noises used for +ore distribution. +Needed by "sheet", "puff", "blob" and "vein" ores. +Omit from "scatter" ore for a uniform ore distribution. +Omit from "stratum" ore for a simple horizontal strata from y_min to +y_max. +]] +---@field noise_params core.NoiseParams.3d +--[[ +"sheet" type +]] +---@field column_height_min integer? +--[[ +"sheet" type +]] +---@field column_height_max integer? +--[[ +"sheet" type +]] +---@field column_midpoint_factor number? \ No newline at end of file diff --git a/types/luanti_lsp_definitions/library/defs/ore/stratum.lua b/types/luanti_lsp_definitions/library/defs/ore/stratum.lua new file mode 100644 index 00000000..afa4edb0 --- /dev/null +++ b/types/luanti_lsp_definitions/library/defs/ore/stratum.lua @@ -0,0 +1,35 @@ +---@meta _ +-- DRAFT 1 DONE +-- luanti/doc/lua_api.md: Ores +-- luanti/doc/lua_api.md: Definition tables > Ore Definition + +--[[ +WIPDOC +]] +---@class core.OreDef.stratum : _.OreDef.__base +--[[ +WIPDOC +]] +---@field ore_type "stratum" +--[[ +If noise is above this threshold, ore is placed. Not needed for a +uniform distribution. +]] +---@field noise_threshold number? +--[[ +NoiseParams structure describing one of the noises used for +ore distribution. +Needed by "sheet", "puff", "blob" and "vein" ores. +Omit from "scatter" ore for a uniform ore distribution. +Omit from "stratum" ore for a simple horizontal strata from y_min to +y_max. +]] +---@field noise_params core.NoiseParams.3d? +--[[ +WIPDOC +]] +---@field np_stratum_thickness core.NoiseParams.3d? +--[[ +WIPDOC +]] +---@field stratum_thickness integer? \ No newline at end of file diff --git a/types/luanti_lsp_definitions/library/defs/ore/vein.lua b/types/luanti_lsp_definitions/library/defs/ore/vein.lua new file mode 100644 index 00000000..8f39303b --- /dev/null +++ b/types/luanti_lsp_definitions/library/defs/ore/vein.lua @@ -0,0 +1,31 @@ +---@meta _ +-- DRAFT 1 DONE +-- luanti/doc/lua_api.md: Ores +-- luanti/doc/lua_api.md: Definition tables > Ore Definition + +--[[ +WIPDOC +]] +---@class core.OreDef.vein : _.OreDef.__base +--[[ +WIPDOC +]] +---@field ore_type "vein" +--[[ +If noise is above this threshold, ore is placed. Not needed for a +uniform distribution. +]] +---@field noise_threshold number? +--[[ +NoiseParams structure describing one of the noises used for +ore distribution. +Needed by "sheet", "puff", "blob" and "vein" ores. +Omit from "scatter" ore for a uniform ore distribution. +Omit from "stratum" ore for a simple horizontal strata from y_min to +y_max. +]] +---@field noise_params core.NoiseParams.3d? +--[[ +"vein" type +]] +---@field random_factor number? diff --git a/types/luanti_lsp_definitions/library/defs/particle/ParticleSpawner.lua b/types/luanti_lsp_definitions/library/defs/particle/ParticleSpawner.lua new file mode 100644 index 00000000..9b6439db --- /dev/null +++ b/types/luanti_lsp_definitions/library/defs/particle/ParticleSpawner.lua @@ -0,0 +1,197 @@ +---@meta _ +-- DRAFT 1 DONE +-- luanti/doc/lua_api.md: Definition tables > `ParticleSpawner` definition + +-- NOTE: only the modern ParticleSpawner definition is annotated. However, +-- interested contributors seeking to additionally annotate the legacy +-- ParticleSpawner definition is welcome to submit a complete PR/patch + +--[[ +WIPDOC +]] +---@class core.ParticleSpawnerID : integer + +-- ----------------------- ParticleSpawnerDef.regular ----------------------- -- + +--[[ +WIPDOC +]] +---@class core.ParticleSpawnerDef.regular +--[[ +Number of particles spawned over the time period `time`. +]] +---@field amount integer +--[[ +Lifespan of spawner in seconds. +If time is 0 spawner has infinite lifespan and spawns the `amount` on +a per-second basis. +]] +---@field time number +--[[ +If true collide with `walkable` nodes and, depending on the +`object_collision` field, objects too. +]] +---@field collisiondetection boolean? +--[[ +If true particles are removed when they collide. +Requires collisiondetection = true to have any effect. +]] +---@field collision_removal boolean? +--[[ +If true particles collide with objects that are defined as +`physical = true,` and `collide_with_objects = true,`. +Requires collisiondetection = true to have any effect. +]] +---@field object_collision boolean? +--[[ +If defined, particle positions, velocities and accelerations are +relative to this object's position and yaw +]] +---@field attached core.ObjectRef? +--[[ +If true face player using y axis only +]] +---@field vertical boolean? +--[[ +The texture of the particle +v5.6.0 and later: also supports the table format described in the +following section. +]] +---@field texture core.ParticleTexture? +--[[ +TODO separate both fields +Optional, if specified spawns particles only for this player +Can't be used together with `exclude_player`. +]] +---@field playername string? +--[[ +TODO separate both fields +Optional, if specified spawns particles not for this player +Added in v5.14.0. Can't be used together with `playername`. +]] +---@field exclude_player string? +--[[ +Optional, specifies how to animate the particles' texture +v5.6.0 and later: set length to -1 to synchronize the length +of the animation with the expiration time of individual particles. +(-2 causes the animation to be played twice, and so on) +]] +---@field animation core.TileAnimationDef? +--[[ +Optional, specify particle self-luminescence in darkness. +Values 0-14. +]] +---@field glow core.Light.source? + +-- -------------------- modern ParticleSpawner properties ------------------- -- + +---@class core.ParticleSpawnerDef.regular +--[[ +WIPDOC +]] +---@field pos core.ParticleSpawner.vec3_range? +--[[ +WIPDOC +]] +---@field pos_tween core.ParticleSpawner.tween.vec3_range? +--[[ +WIPDOC +]] +---@field vel core.ParticleSpawner.vec3_range? +--[[ +WIPDOC +]] +---@field vel_tween core.ParticleSpawner.tween.vec3_range? +--[[ +WIPDOC +]] +---@field acc core.ParticleSpawner.vec3_range? +--[[ +WIPDOC +]] +---@field acc_tween core.ParticleSpawner.vec3_range? +--[[ +WIPDOC +]] +---@field size core.ParticleSpawner.float_range? +--[[ +WIPDOC +]] +---@field size_tween core.ParticleSpawner.tween.float_range? +--[[ +WIPDOC +]] +---@field jitter core.ParticleSpawner.vec3_range? +--[[ +WIPDOC +]] +---@field jitter_tween core.ParticleSpawner.tween.vec3_range? +--[[ +WIPDOC +]] +---@field drag core.ParticleSpawner.vec3_range? +--[[ +WIPDOC +]] +---@field drag_tween core.ParticleSpawner.tween.vec3_range? +--[[ +WIPDOC +]] +---@field bounce core.ParticleSpawner.float_range? +--[[ +WIPDOC +]] +---@field bounce_tween core.ParticleSpawner.tween.float_range? +--[[ +WIPDOC +]] +---@field exptime core.ParticleSpawner.float_range? +--[[ +WIPDOC +]] +---@field exptime_tween core.ParticleSpawner.tween.float_range? +--[[ +WIPDOC +]] +---@field attract core.ParticleSpawner.attract? +--[[ +WIPDOC +]] +---@field radius core.ParticleSpawner.vec3_range? +--[[ +WIPDOC +]] +---@field radius_tween core.ParticleSpawner.tween.vec3_range? +--[[ +WIPDOC +]] +---@field texpool core.ParticleTexture? + +-- ------------------------- ParticleSpawnerDef.node ------------------------ -- + +--[[ +WIPDOC +]] +---@class core.ParticleSpawnerDef.node +--[[ +Optional, if specified the particles will have the same appearance as +node dig particles for the given node. +`texture` and `animation` will be ignored if this is set. +]] +---@field node core.Node.set? +--[[ +Optional, only valid in combination with `node` +If set to a valid number 1-6, specifies the tile from which the +particle texture is picked. +Otherwise, the default behavior is used. (currently: any random tile) +]] +---@field node_tile integer? + +-- ----------------------------- ParticleSpawner ---------------------------- -- + +--[[ +WIPDOC +]] +---@alias core.ParticleSpawnerDef +--- | core.ParticleSpawnerDef.regular +--- | core.ParticleSpawnerDef.node \ No newline at end of file diff --git a/types/luanti_lsp_definitions/library/defs/particle/attract.lua b/types/luanti_lsp_definitions/library/defs/particle/attract.lua new file mode 100644 index 00000000..84010c97 --- /dev/null +++ b/types/luanti_lsp_definitions/library/defs/particle/attract.lua @@ -0,0 +1,57 @@ +---@meta _ +-- DRAFT 1 DONE +-- luanti/doc/lua_api.md: Definition tables > `ParticleSpawner` definition + +--[[ +WIPDOC +]] +---@alias core.ParticleSpawner.kind +--- | "none" +--- | "point" +--- | "line" +--- | "plane" + +--[[ +WIPDOC +]] +---@class core.ParticleSpawner.attract +--[[ +WIPDOC +]] +---@field kind core.ParticleSpawner.kind +--[[ +WIPDOC +]] +---@field strength core.ParticleSpawner.float_range +--[[ +WIPDOC +]] +---@field strength_tween core.ParticleSpawner.tween.float_range? +--[[ +WIPDOC +]] +---@field origin core.ParticleSpawner.vec3? +--[[ +WIPDOC +]] +---@field origin_tween core.ParticleSpawner.tween.vec3? +--[[ +WIPDOC +]] +---@field direction core.ParticleSpawner.vec3? +--[[ +WIPDOC +]] +---@field direction_tween core.ParticleSpawner.tween.vec3? +--[[ +WIPDOC +]] +---@field origin_attached core.ObjectRef? +--[[ +WIPDOC +]] +---@field direction_attached core.ObjectRef? +--[[ +WIPDOC +]] +---@field die_on_contact boolean? \ No newline at end of file diff --git a/types/luanti_lsp_definitions/library/defs/particle/particle.lua b/types/luanti_lsp_definitions/library/defs/particle/particle.lua new file mode 100644 index 00000000..504c6faf --- /dev/null +++ b/types/luanti_lsp_definitions/library/defs/particle/particle.lua @@ -0,0 +1,115 @@ +---@meta _ +-- DRAFT 1 DONE +-- luanti/doc/lua_api.md: Definition tables > Particle definition +-- luanti/doc/lua_api.md: Definition tables > `ParticleSpawner` definition + +-- --------------------------- ParticleDef.regular -------------------------- -- + +---@class core.ParticleDef.regular +--[[ +WIPDOC +]] +---@field pos vector +--[[ +WIPDOC +]] +---@field velocity vector? +--[[ +WIPDOC +]] +---@field acceleration vector? +--[[ +WIPDOC +]] +---@field expirationtime number +--[[ +Scales the visual size of the particle texture. +If `node` is set, size can be set to 0 to spawn a randomly-sized +particle (just like actual node dig particles). +]] +---@field size number? +--[[ +If true collides with `walkable` nodes and, depending on the +`object_collision` field, objects too. +]] +---@field collisiondetection boolean? +--[[ +If true particle is removed when it collides. +Requires collisiondetection = true to have any effect. +]] +---@field collision_removal boolean? +--[[ +If true particle collides with objects that are defined as +`physical = true,` and `collide_with_objects = true,`. +Requires collisiondetection = true to have any effect. +]] +---@field object_collision boolean? +--[[ +If true faces player using y axis only +]] +---@field vertical boolean? +--[[ +The texture of the particle +v5.6.0 and later: also supports the table format described in the +following section, but due to a bug this did not take effect +(beyond the texture name). +v5.9.0 and later: fixes the bug. +Note: "texture.animation" is ignored here. Use "animation" below instead. +]] +---@field texture core.ParticleTexture? +--[[ +Optional, if specified spawns particle only on the player's client +]] +---@field playername string? +--[[ +Optional, specifies how to animate the particle texture +]] +---@field animation core.TileAnimationDef? +--[[ +Optional, specify particle self-luminescence in darkness. +Values 0-14. +]] +---@field glow number? +--[[ +v5.6.0 and later: Optional drag value, consult the following section +Note: Only a vector is supported here. Alternative forms like a single +number are not supported. +]] +---@field drag vector? +--[[ +v5.6.0 and later: Optional jitter range, consult the following section +]] +---@field jitter core.ParticleSpawner.vec3_range? +--[[ +v5.6.0 and later: Optional bounce range, consult the following section +]] +---@field bounce core.ParticleSpawner.vec3_range? + +-- ---------------------------- ParticleDef.node ---------------------------- -- + +--[[ +WIPDOC +]] +---@class core.ParticleDef.node : core.ParticleDef.regular +--[[ +Optional, if specified the particle will have the same appearance as +node dig particles for the given node. +`texture` and `animation` will be ignored if this is set. +]] +---@field node core.Node.set? +--[[ +Optional, only valid in combination with `node` +If set to a valid number 1-6, specifies the tile from which the +particle texture is picked. +Otherwise, the default behavior is used. (currently: any random tile) +]] +---@field node_tile number? + +-- ------------------------------- ParticleDef ------------------------------ -- + +--[[ +WIPDOC +]] +---@alias core.ParticleDef +--- | core.ParticleDef.regular +--- | core.ParticleDef.node \ No newline at end of file diff --git a/types/luanti_lsp_definitions/library/defs/particle/texture.lua b/types/luanti_lsp_definitions/library/defs/particle/texture.lua new file mode 100644 index 00000000..0d34f89d --- /dev/null +++ b/types/luanti_lsp_definitions/library/defs/particle/texture.lua @@ -0,0 +1,58 @@ +---@meta _ +-- DRAFT 1 DONE +-- luanti/doc/lua_api.md: Definition tables > `ParticleSpawner` definition + +--[[ +WIPDOC +]] +---@alias core.ParticleTexture.blend +--- | "alpha" +--- | "clip" +--- | "add" +--- | "screen" +--- | "sub" + +--[[ +WIPDOC +]] +---@class core.ParticleTexture.tablefmt +--[[ +WIPDOC +]] +---@field name core.Texture +--[[ +WIPDOC +]] +---@field alpha number? +--[[ +WIPDOC +]] +---@field alpha_tween core.ParticleSpawner.tween.float? +--[[ +WIPDOC +]] +---@field scale core.ParticleSpawner.vec2? +--[[ +WIPDOC +]] +---@field scale_tween core.ParticleSpawner.tween.vec2? +--[[ +WIPDOC +]] +---@field blend core.ParticleTexture.blend? +--[[ +WIPDOC +]] +---@field animation core.TileAnimationDef? + +--[[ +WIPDOC +]] +---@class core.ParticleTexture.stringfmt + +--[[ +WIPDOC +]] +---@alias core.ParticleTexture +--- | core.ParticleTexture.tablefmt +--- | core.ParticleTexture.stringfmt \ No newline at end of file diff --git a/types/luanti_lsp_definitions/library/defs/particle/type.lua b/types/luanti_lsp_definitions/library/defs/particle/type.lua new file mode 100644 index 00000000..bd9f67dd --- /dev/null +++ b/types/luanti_lsp_definitions/library/defs/particle/type.lua @@ -0,0 +1,133 @@ +---@meta _ +-- DRAFT 1 DONE +-- luanti/doc/lua_api.md: Definition tables > `ParticleSpawner` definition + +-- -------------------------- ParticleSpawner.vec2 -------------------------- -- + +--[[ +WIPDOC +]] +---@alias core.ParticleSpawner.vec2 +--- | vec2.xy +--- | number + +-- -------------------------- ParticleSpawner.vec3 -------------------------- -- + +---@alias core.ParticleSpawner.vec3 +--- | vector +--- | number + +-- ----------------------- ParticleSpawner.float_range ---------------------- -- + +---@class _.ParticleSpawner.float_range +--[[ +WIPDOC +]] +---@field min number +--[[ +WIPDOC +]] +---@field max number + +--[[ +WIPDOC +]] +---@alias core.ParticleSpawner.float_range +--- | _.ParticleSpawner.float_range +--- | number + +-- ----------------------- ParticleSpawner.vec2_range ----------------------- -- + +---@class _.ParticleSpawner.vec2_range +--[[ +WIPDOC +]] +---@field min vec2.xy +--[[ +WIPDOC +]] +---@field max vec2.xy +--[[ +WIPDOC +]] +---@field bias number? + +--[[ +WIPDOC +]] +---@alias core.ParticleSpawner.vec2_range +--- | _.ParticleSpawner.vec2_range +--- | core.ParticleSpawner.vec2 + +-- ----------------------- ParticleSpawner.vec3_range ----------------------- -- + +---@class _.ParticleSpawner.vec3_range +--[[ +WIPDOC +]] +---@field min vector +--[[ +WIPDOC +]] +---@field max vector +--[[ +WIPDOC +]] +---@field bias number? + +--[[ +WIPDOC +]] +---@alias core.ParticleSpawner.vec3_range +--- | _.ParticleSpawner.vec3_range +--- | core.ParticleSpawner.vec3 + +-- -------------------------- ParticleSpawner.tween ------------------------- -- + +--[[ +WIPDOC +]] +---@alias core.ParticleSpawner.tween.style +--- | "fwd" +--- | "rev" +--- | "pulse" +--- | "flicker" + +---@class _.ParticleSpawner.tween.__base +--[[ +WIPDOC +]] +---@field style core.ParticleSpawner.tween.style? +--[[ +WIPDOC +]] +---@field reps number? +--[[ +WIPDOC +]] +---@field start number? + +--[[ +WIPDOC +]] +---@class core.ParticleSpawner.tween.float : {[integer]:number}, _.ParticleSpawner.tween.__base + +--[[ +WIPDOC +]] +---@class core.ParticleSpawner.tween.vec2 : {[integer]:core.ParticleSpawner.vec2}, _.ParticleSpawner.tween.__base + +--[[ +WIPDOC +]] +---@class core.ParticleSpawner.tween.vec3 : {[integer]:core.ParticleSpawner.vec3}, _.ParticleSpawner.tween.__base + +--[[ +WIPDOC +]] +---@class core.ParticleSpawner.tween.float_range : {[integer]:core.ParticleSpawner.float_range}, _.ParticleSpawner.tween.__base + +--[[ +WIPDOC +]] +---@class core.ParticleSpawner.tween.vec3_range : {[integer]:core.ParticleSpawner.vec3_range}, _.ParticleSpawner.tween.__base \ No newline at end of file diff --git a/types/luanti_lsp_definitions/library/defs/pointed_thing.lua b/types/luanti_lsp_definitions/library/defs/pointed_thing.lua new file mode 100644 index 00000000..cb8f26b2 --- /dev/null +++ b/types/luanti_lsp_definitions/library/defs/pointed_thing.lua @@ -0,0 +1,99 @@ +---@meta _ +-- DRAFT 1 DONE +-- luanti/doc/lua_api.md: Representations of simple things + +-- -------------------------- PointedThing.nothing -------------------------- -- + +--[[ +WIPDOC +]] +---@class core.PointedThing.nothing +--[[ +WIPDOC +]] +---@field type "nothing" + +-- ---------------------------- PointedThing.node --------------------------- -- + +--[[ +WIPDOC +]] +---@class core.PointedThing.node +--[[ +WIPDOC +]] +---@field type "node" +--[[ +WIPDOC +]] +---@field under ivector +--[[ +WIPDOC +]] +---@field above ivector + +-- --------------------------- PointedThing.object -------------------------- -- + +--[[ +WIPDOC +]] +---@class core.PointedThing.object +--[[ +WIPDOC +]] +---@field type "object" +--[[ +WIPDOC +]] +---@field ref core.ObjectRef + +--[[ +WIPDOC +]] +---@alias core.PointedThing +--- | core.PointedThing.nothing +--- | core.PointedThing.node +--- | core.PointedThing.object + +-- -------------------------- PointedThing.raycast -------------------------- -- + +---@class _.PointedThing.raycast.__partial +--[[ +Only raycast supports this +* `pointed_thing.intersection_point`: The absolute world coordinates of the + point on the selection box which is pointed at. May be in the selection box + if the pointer is in the box too. +]] +---@field intersection_point vector +--[[ +Only raycast supports this +* `pointed_thing.box_id`: The ID of the pointed selection box (counting starts + from 1). +]] +---@field box_id integer +--[[ +Only raycast supports this +* `pointed_thing.intersection_normal`: Unit vector, points outwards of the + selected selection box. This specifies which face is pointed at. + Is a null vector `vector.zero()` when the pointer is inside the selection box. + For entities with rotated selection boxes, this will be rotated properly + by the entity's rotation - it will always be in absolute world space. +]] +---@field intersection_normal vector + +--[[ +WIPDOC +]] +---@class core.PointedThing.raycast.node : core.PointedThing.node, _.PointedThing.raycast.__partial + +--[[ +WIPDOC +]] +---@class core.PointedThing.raycast.object : core.PointedThing.object, _.PointedThing.raycast.__partial + +--[[ +WIPDOC +]] +---@alias core.PointedThing.raycast.all +--- | core.PointedThing.raycast.node +--- | core.PointedThing.raycast.object \ No newline at end of file diff --git a/types/luanti_lsp_definitions/library/defs/privilege.lua b/types/luanti_lsp_definitions/library/defs/privilege.lua new file mode 100644 index 00000000..0f60df25 --- /dev/null +++ b/types/luanti_lsp_definitions/library/defs/privilege.lua @@ -0,0 +1,152 @@ +---@meta _ +-- DRAFT 1 DONE +-- luanti/doc/lua_api.md: Definition tables > Privilege definition + +-- ------------------------------ PrivilegeSet ------------------------------ -- + +--[[ +WIPDOC +]] +---@alias core.PrivilegeSet.keys +--- | "shout" +--- | "interact" +--- | "fast" +--- | "fly" +--- | "noclip" +--- | "teleport" +--- | "bring" +--- | "give" +--- | "settime" +--- | "debug" +--- | "privs" +--- | "basic_privs" +--- | "kick" +--- | "ban" +--- | "password" +--- | "protection_bypass" +--- | "server" +--- | "rollback" +--- | string + +--[[ +WIPDOC +]] +---@class core.PrivilegeSet : {[string]:boolean?} +--[[ +WIPDOC +]] +---@field shout boolean? +--[[ +WIPDOC +]] +---@field interact boolean? +--[[ +WIPDOC +]] +---@field fast boolean? +--[[ +WIPDOC +]] +---@field fly boolean? +--[[ +WIPDOC +]] +---@field noclip boolean? +--[[ +WIPDOC +]] +---@field teleport boolean? +--[[ +WIPDOC +]] +---@field bring boolean? +--[[ +WIPDOC +]] +---@field give boolean? +--[[ +WIPDOC +]] +---@field settime boolean? +--[[ +WIPDOC +]] +---@field debug boolean? +--[[ +WIPDOC +]] +---@field privs boolean? +--[[ +WIPDOC +]] +---@field basic_privs boolean? +--[[ +WIPDOC +]] +---@field kick boolean? +--[[ +WIPDOC +]] +---@field ban boolean? +--[[ +WIPDOC +]] +---@field password boolean? +--[[ +WIPDOC +]] +---@field protection_bypass boolean? +--[[ +WIPDOC +]] +---@field server boolean? +--[[ +WIPDOC +]] +---@field rollback boolean? + +-- ------------------------------ PrivilegeDef ------------------------------ -- + +--[[ +WIPDOC +]] +---@alias core.PrivilegeDef.on_grant fun(name:string, granter_name:string): boolean? + +--[[ +WIPDOC +]] +---@alias core.PrivilegeDef.on_revoke fun(name:string, revoker_name:string): boolean? + +--[[ +WIPDOC +]] +---@class core.PrivilegeDef +--[[ +WIPDOC +]] +---@field description string? +--[[ +WIPDOC +]] +---@field give_to_singleplayer boolean? +--[[ +Whether to grant the privilege to the server admin. +Uses value of 'give_to_singleplayer' by default. +]] +---@field give_to_admin boolean? +--[[ +Note that the above two callbacks will be called twice if a player is +responsible, once with the player name, and then with a nil player +name. +Return true in the above callbacks to stop register_on_priv_grant or +revoke being called. +]] +---@field on_grant core.PrivilegeDef.on_grant? +--[[ +Note that the above two callbacks will be called twice if a player is +responsible, once with the player name, and then with a nil player +name. +Return true in the above callbacks to stop register_on_priv_grant or +revoke being called. +]] +---@field on_revoke core.PrivilegeDef.on_revoke? diff --git a/types/luanti_lsp_definitions/library/defs/schematics.lua b/types/luanti_lsp_definitions/library/defs/schematics.lua new file mode 100644 index 00000000..3fc78f29 --- /dev/null +++ b/types/luanti_lsp_definitions/library/defs/schematics.lua @@ -0,0 +1,155 @@ +---@meta _ +-- DRAFT 1 DONE +-- luanti/doc/lua_api.md: Schematics + +-- ----------------------------- Schematic.flag ----------------------------- -- + +--[[ +WIPDOC +]] +---@class core.Schematic.flags.tablefmt +--[[ +WIPDOC +]] +---@field place_center_x boolean? +--[[ +WIPDOC +]] +---@field noplace_center_x boolean? +--[[ +WIPDOC +]] +---@field place_center_y boolean? +--[[ +WIPDOC +]] +---@field noplace_center_y boolean? +--[[ +WIPDOC +]] +---@field place_center_z boolean? +--[[ +WIPDOC +]] +---@field noplace_center_z boolean? + +--[[ +WIPDOC +]] +---@alias core.Schematic.flags.stringfmt string + +--[[ +WIPDOC +]] +---@alias core.Schematic.flags +--- | core.Schematic.flags.tablefmt +--- | core.Schematic.flags.stringfmt + +-- ------------------------ SchematicDef.yslice_prob ------------------------ -- + +--[[ +WIPDOC +]] +---@class core.SchematicDef.yslice_prob +--[[ +WIPDOC +]] +---@field ypos integer +--[[ +* A probability value of `0` or `1` means that node will never appear + (0% chance). +* A probability value of `254` or `255` means the node will always appear + (100% chance). +* If the probability value `p` is greater than `1`, then there is a + `(p / 256 * 100)` percent chance that node will appear when the schematic is + placed on the map. +]] +---@field prob integer + +-- ---------------------------- SchematicDef.node --------------------------- -- + +--[[ +WIPDOC +]] +---@class core.SchematicDef.Node +--[[ + * `name`: the name of the map node to place (required) +]] +---@field name string +--[[ + * `param2`: the raw param2 value of the node being placed onto the map + (default: 0) +]] +---@field param2 core.Param2? +--[[ + * `force_place`: boolean representing if the node should forcibly overwrite + any previous contents (default: false) +]] +---@field force_place boolean? +--[[ + * `prob` (alias `param1`): the probability of this node being placed + (default: 255) +]] +---@field prob integer? +--[[ + * `prob` (alias `param1`): the probability of this node being placed + (default: 255) + +* @deprecated +]] +---@field param1 integer? + +-- -------------------------------- Schematic ------------------------------- -- + +--[[ +WIPDOC +]] +---@class core.SchematicID + +--[[ +A schematic specifier identifies a schematic by either a filename to a +Luanti Schematic file (`.mts`) or through raw data supplied through Lua, +in the form of a table. +]] +---@class core.SchematicDef +--[[ +* The `size` field is a 3D vector containing the dimensions of the provided + schematic. (required field) +]] +---@field size ivector +--[[ +* The `yslice_prob` field is a table of {ypos, prob} slice tables. A slice table + sets the probability of a particular horizontal slice of the schematic being + placed. (optional field) + `ypos` = 0 for the lowest horizontal slice of a schematic. + The default of `prob` is 255. + * A probability value of `0` or `1` means that node will never appear + (0% chance). + * A probability value of `254` or `255` means the node will always appear + (100% chance). + * If the probability value `p` is greater than `1`, then there is a + `(p / 256 * 100)` percent chance that node will appear when the schematic is + placed on the map. +]] +---@field yslice_prob core.SchematicDef.yslice_prob +--[=[ +* The `data` field is a flat table of Node tables making up the schematic, + in the order of `[z [y [x]]]`. (required field) + Each Node table contains: + * `name`: the name of the map node to place (required) + * `prob` (alias `param1`): the probability of this node being placed + (default: 255) + * `param2`: the raw param2 value of the node being placed onto the map + (default: 0) + * `force_place`: boolean representing if the node should forcibly overwrite + any previous contents (default: false) +]=] +---@field data core.SchematicDef.Node[] + +--[[ +WIPDOC +]] +---@alias core.Schematic +--- | core.SchematicID +--- | core.Path +--- | core.SchematicDef \ No newline at end of file diff --git a/types/luanti_lsp_definitions/library/defs/sound.lua b/types/luanti_lsp_definitions/library/defs/sound.lua new file mode 100644 index 00000000..1507af5a --- /dev/null +++ b/types/luanti_lsp_definitions/library/defs/sound.lua @@ -0,0 +1,81 @@ +---@meta _ +-- DRAFT 1 DONE +-- luanti/doc/lua_api.md: Sounds + +--[[ +WIPDOC +]] +---@class core.SimpleSoundSpec.tablefmt +--[[ +WIPDOC +]] +---@field name string +--[[ +WIPDOC +]] +---@field gain number? +--[[ +WIPDOC +]] +---@field pitch number? +--[[ +WIPDOC +]] +---@field fade number? + +--[[ +WIPDOC +]] +---@alias core.SimpleSoundSpec.stringfmt string + +--[[ +WIPDOC +]] +---@alias core.SimpleSoundSpec +--- | core.SimpleSoundSpec.tablefmt +--- | core.SimpleSoundSpec.stringfmt + +--[[ +WIPDOC +]] +---@class core.SoundParamter +--[[ +WIPDOC +]] +---@field gain number? +--[[ +WIPDOC +]] +---@field pitch number? +--[[ +WIPDOC +]] +---@field fade number? +--[[ +WIPDOC +]] +---@field start_time number? +--[[ +WIPDOC +]] +---@field loop boolean? +--[[ +WIPDOC +]] +---@field pos vector? +--[[ +WIPDOC +]] +---@field object core.ObjectRef? +--[[ +WIPDOC +]] +---@field to_player string? +--[[ +WIPDOC +]] +---@field exclude_player string? +--[[ +WIPDOC +]] +---@field max_hear_distance number? \ No newline at end of file diff --git a/types/luanti_lsp_definitions/library/defs/textures.lua b/types/luanti_lsp_definitions/library/defs/textures.lua new file mode 100644 index 00000000..0911ef4a --- /dev/null +++ b/types/luanti_lsp_definitions/library/defs/textures.lua @@ -0,0 +1,8 @@ +---@meta _ +-- DRAFT 1 DONE +-- luanti/doc/lua_api.md: Textures + +--[[ +WIPDOC +]] +---@alias core.Texture string \ No newline at end of file diff --git a/types/luanti_lsp_definitions/library/defs/tile.lua b/types/luanti_lsp_definitions/library/defs/tile.lua new file mode 100644 index 00000000..bed85327 --- /dev/null +++ b/types/luanti_lsp_definitions/library/defs/tile.lua @@ -0,0 +1,134 @@ +---@meta _ +-- DRAFT 1 DONE +-- luanti/doc/lua_api.md: Definition tables > Tile definition +-- luanti/doc/lua_api.md: Definition tables > Tile animation definition + +-- -------------------- TileAnimationDef.vertical_frames -------------------- -- + +--[[ +WIPDOC +]] +---@class core.TileAnimationDef.vertical_frames +--[[ +WIPDOC +]] +---@field type "vertical_frames" +--[[ +WIPDOC +]] +---@field aspect_w integer +--[[ +WIPDOC +]] +---@field aspect_h integer +--[[ +WIPDOC +]] +---@field length number + +-- ------------------------ TileAnimationDef.sheet_2d ----------------------- -- + +--[[ +WIPDOC +]] +---@class core.TileAnimationDef.sheet_2d +--[[ +WIPDOC +]] +---@field type "sheet_2d" +--[[ +WIPDOC +]] +---@field frames_w integer +--[[ +WIPDOC +]] +---@field frames_h integer +--[[ +WIPDOC +]] +---@field frame_length number + +-- ---------------------------- TileAnimationDef ---------------------------- -- + +--[[ +WIPDOC +]] +---@alias core.TileAnimationDef +--- | core.TileAnimationDef.vertical_frames +--- | core.TileAnimationDef.sheet_2d + +-- ----------------------------- TileDef.__base ----------------------------- -- + +---@class _.TileDef.__base +--[[ +WIPDOC +]] +---@field name core.Texture +--[[ +WIPDOC + +* @deprecated 5.X +]] +---@field image string? + +-- ---------------------------- TileDef.animation --------------------------- -- + +--[[ +WIPDOC +]] +---@class core.TileDef.animation : _.TileDef.__base +--[[ +WIPDOC +]] +---@field animation core.TileAnimationDef + + +-- ----------------------------- TileDef.regular ---------------------------- -- + +--[[ +WIPDOC +]] +---@alias core.TileDef.align_style +--- | "node" +--- | "world" +--- | "user" + +--[[ +WIPDOC +]] +---@class core.TileDef.regular : _.TileDef.__base +--[[ +WIPDOC +]] +---@field backface_culling boolean? +--[[ +WIPDOC +]] +---@field align_style core.TileDef.align_style? +--[[ +WIPDOC +]] +---@field scale integer? + +-- ------------------------------ TileDef.color ----------------------------- -- + +--[[ +WIPDOC +]] +---@class core.TileDef.color : _.TileDef.__base +--[[ +WIPDOC +]] +---@field color core.ColorSpec + +-- --------------------------------- TileDef -------------------------------- -- + +--[[ +WIPDOC +]] +---@alias core.TileDef +--- | core.Texture +--- | core.TileDef.animation +--- | core.TileDef.regular +--- | core.TileDef.color \ No newline at end of file diff --git a/types/luanti_lsp_definitions/library/defs/tool_capabilities.lua b/types/luanti_lsp_definitions/library/defs/tool_capabilities.lua new file mode 100644 index 00000000..f8635953 --- /dev/null +++ b/types/luanti_lsp_definitions/library/defs/tool_capabilities.lua @@ -0,0 +1,96 @@ +---@meta _ +-- DRAFT 1 DONE +-- luanti/doc/lua_api.md: Tool Capabilities + +-- ---------------------- ToolCapabilities.*.groupcaps ---------------------- -- + +--[[ +WIPDOC +]] +---@class core.ToolCapabilities.item.groupcap +--[[ +WIPDOC +]] +---@field times number[]? +--[[ +WIPDOC +]] +---@field maxlevel integer? + +--[[ +WIPDOC +]] +---@alias core.ToolCapabilities.item.groupcaps table + +--[[ +WIPDOC +]] +---@class core.ToolCapabilities.tool.groupcap : core.ToolCapabilities.item.groupcap +--[[ +WIPDOC +]] +---@field uses integer? + +--[[ +WIPDOC +]] +---@alias core.ToolCapabilities.tool.groupcaps table + +-- --------------------- ToolCapabilities.damage_groups --------------------- -- + +--[[ +WIPDOC +]] +---@alias core.ToolCapabilities.damage_groups table + +-- -------------------------- ToolCapabilities.item ------------------------- -- + +--[[ +WIPDOC +]] +---@class core.ToolCapabilities.item +--[[ +WIPDOC +]] +---@field full_punch_interval number? +--[[ +WIPDOC +]] +---@field max_drop_level integer? +--[[ +WIPDOC +]] +---@field groupcaps core.ToolCapabilities.item.groupcaps? +--[[ +WIPDOC +]] +---@field damage_groups core.ToolCapabilities.damage_groups? + +-- -------------------------- ToolCapabilities.tool ------------------------- -- + +--[[ +WIPDOC +]] +---@class core.ToolCapabilities.tool : core.ToolCapabilities.item +--[[ +WIPDOC +]] +---@field groupcaps core.ToolCapabilities.item.groupcaps? +--[[ +Amount of uses this tool has for attacking players and entities +by punching them (0 = infinite uses). +For compatibility, this is automatically set from the first +suitable groupcap using the formula "uses * 3^(maxlevel - 1)". +It is recommend to set this explicitly instead of relying on the +fallback behavior. +]] +---@field punch_attack_uses integer? + +-- ---------------------------- ToolCapabilities ---------------------------- -- + +--[[ +WIPDOC +]] +---@alias core.ToolCapabilities +--- | core.ToolCapabilities.item +--- | core.ToolCapabilities.tool \ No newline at end of file diff --git a/types/luanti_lsp_definitions/library/defs/wear_bar_color.lua b/types/luanti_lsp_definitions/library/defs/wear_bar_color.lua new file mode 100644 index 00000000..c8120991 --- /dev/null +++ b/types/luanti_lsp_definitions/library/defs/wear_bar_color.lua @@ -0,0 +1,23 @@ +---@meta _ +-- DRAFT 1 DONE +-- luanti/doc/lua_api.md: Definition tables > Wear Bar Color + +--[[ +WIPDOC +]] +---@class core.WearBarColor.tablefmt +--[[ +WIPDOC +]] +---@field blend "linear"|"constant" +--[[ +WIPDOC +]] +---@field color_stops table + +--[[ +WIPDOC +]] +---@alias core.WearBarColor +--- | core.ColorSpec +--- | core.WearBarColor.tablefmt \ No newline at end of file diff --git a/types/luanti_lsp_definitions/library/helpers.lua b/types/luanti_lsp_definitions/library/helpers.lua new file mode 100644 index 00000000..ab0f6e33 --- /dev/null +++ b/types/luanti_lsp_definitions/library/helpers.lua @@ -0,0 +1,203 @@ +---@meta _ +-- Helper functions in the global namespace or extends Lua's stdlib +-- luanti/doc/lua_api.md: Helper functions + +-- NOTE: core.* helpers are in library/core/utilities/helpers.lua + +--[[ +Returns `obj` as a human-readable string assigned to `name`. Handles reference +loops. Table format resembles flattened JSON representation. + +* @see luanti/builtin/common/misc_helpers.lua +]] +---@param obj any +---@param name string? #@default(`"_"`) +---@param dumped table? #@default(`{}`) +---@return string +function dump2(obj, name, dumped) end + +--[[ +Returns `value` as a human-readable string. Handles reference loops. Table +format resembles JSON. + +* @see luanti/builtin/common/misc_helpers.lua +]] +---@param value any +---@param indent string? +---@return string +function dump(value, indent) end + +-- ---------------------------------- math ---------------------------------- -- + +--[[ +Returns hypotenuse of a triangle with legs x and y. Useful to obtain distance. + +* @see luanti/builtin/common/math.lua +]] +---@nodiscard +---@param x number +---@param y number +---@return number +function math.hypot(x, y) end + +--[[ +Returns the sign of a number. + +* @see luanti/builtin/common/math.lua +]] +---@nodiscard +---@param x number +---@param tolerance number? #@default(`0`) anchor where the zero would be +---@return -1|0|1 #@hint(`[-1, 1]`) +function math.sign(x, tolerance) end + +--[[ +Returns factorial of `x` + +* @see luanti/builtin/common/math.lua +]] +---@nodiscard +---@param x integer #@hint(`[0,171]`) +---@return integer +function math.factorial(x) end + +--[[ +Returns `x` rounded to the nearest integer + +* @see luanti/builtin/common/math.lua +]] +---@nodiscard +---@param x number +---@return integer +function math.round(x) end + +-- --------------------------------- string --------------------------------- -- + +--[[ +Splits given string into a list. + +* @see luanti/builtin/common/misc_helpers.lua +]] +---@nodiscard +---@param str string +---@param separator string? #@default(`","`) @hint(`not empty`) +---@param include_empty boolean? #@default(`false`) +---@param max_splits integer? #@default(`-1`) Unlimited if negative +---@param sep_is_pattern boolean? #@default(`false`) `separator` is lua pattern or plain string +---@return string[] +function string.split(str, separator, include_empty, max_splits, sep_is_pattern) end + +--[[ +Trim whitespace out of given string at beginning and end. Uses the `%s` lua +pattern item. + +* @see luanti/builtin/common/misc_helpers.lua +]] +---@nodiscard +---@param str string +---@return string +function string.trim(str) end + +-- ---------------------------------- table --------------------------------- -- + +-- NOTE: SparseList doesn't work here because these list operations work on +-- #list or ipairs(list) + +--[[ +Returns a deep copy of given table. Metatables are ignored. + +* @see luanti/builtin/common/misc_helpers.lua +]] +---@nodiscard +---@generic T : table +---@param table `T` +---@return T +function table.copy(table) end + +--[[ +Returns a deep copy of given table. Metatables are included. + +* @added 5.12 +* @see luanti/builtin/common/misc_helpers.lua +]] +---@nodiscard +---@generic T : table +---@param table `T` +---@return T +function table.copy_with_metatables(table) end + +--[[ +Returns first smallest index of `val` in given list. Ignores non-array part of +list. List must not have negative indices. + +If not found, returns -1 instead. + +* @see luanti/builtin/common/misc_helpers.lua +]] +---@nodiscard +---@generic T +---@param val T +---@param list T[] +---@return integer +function table.indexof(list, val) end + +--[[ +Returns a key of `val` in given table. Not specified which key is returned if +many has `val` + +If not found, returns `nil` instead + +* @see luanti/builtin/common/misc_helpers.lua +]] +---@nodiscard +---@generic T +---@param table table +---@param val any +---@return T? +function table.keyof(table, val) end + +--[[ +Inserts all values from `other_list` into `list`. Returns `list`. + +* @see luanti/builtin/common/misc_helpers.lua +]] +---@nodiscard +---@generic T +---@param list T[] +---@param other_list T[] +---@return T[] +function table.insert_all(list, other_list) end + +--[[ +Returns a table with keys and values of given table swapped. Not specified +value would map to which keys if many keys has the same value. + +* @see luanti/builtin/common/misc_helpers.lua +]] +---@nodiscard +---@param t table +---@return table +function table.key_value_swap(t) end + +--[[ +Function accepts two positive integers and must return a value inclusively +between the integers. + +* @hint int1 `0` +* @hint int2 `>=1` +* @hint return `[int1,int2]` +* @see luanti/builtin/common/misc_helpers.lua +]] +---@alias table.random_func fun(int1:integer, int2:integer): integer + +--[[ +Shuffles elements in given list from `from` to `to` in place. + +* @see luanti/builtin/common/misc_helpers.lua +]] +---@generic T +---@param list T[] +---@param from integer? #@default(`1`) +---@param to integer? #@default(`#list`) +---@param random_func table.random_func? #@default(`math.random`) +function table.shuffle(list, from, to, random_func) end \ No newline at end of file diff --git a/types/luanti_lsp_definitions/library/misc.lua b/types/luanti_lsp_definitions/library/misc.lua new file mode 100644 index 00000000..e8928734 --- /dev/null +++ b/types/luanti_lsp_definitions/library/misc.lua @@ -0,0 +1,66 @@ +---@meta _ +-- Miscellaneous. No cohesive grouping +-- luanti/doc/lua_api.md: Definition tables > Bit Library + +--[[ +Called on uncaught errors to transform error objects into string to display. + +By default this is a backtrace from `debug.traceback`. Error object is first +converted with `tostring` if it's not a string. This means that you can use +tables as error objects so long as you give them `__tostring` metamethods. + +* @overrideable +* @see luanti/builtin/init.lua +]] +---@nodiscard +---@param err any +---@param level integer #@hint(`>=0`) +---@return string +function core.error_handler(err, level) end + +--[[ +Path separator + +* @deprecated 5.X Recommended to use the forward slash `/` instead +* @see +]] +---@deprecated +---@type "/"|"\\" +DIR_DELIM = nil + +--[[ +Luanti provids the bitop library. Avoid using this unless you really need bit +manipulation as it's not faster than JIT traced arithmetic operations. + +* @see for more information about the specifics in LuaJIT +* @see luanti/lib/bitop/ for its implementation +]] +---@type bitlib +bit = bit + +--[[ +Full absolute path to a file or directory. +]] +---@alias core.Path string + +--[[ +Partial path or filename corresponding to a file within the current mod. +]] +---@alias core.ModAsset string + +--[[ +Serializable types +]] +---@alias core.Serializable nil|boolean|number|string|table + +--[[ +Helper type: `T` or a list of `T` +]] +---@generic T +---@alias OneOrMany T|T[] + +--[[ +Helper type: accepts a sparse list of `T` with holes +]] +---@generic T +---@alias SparseList {[integer]:T}|T[] \ No newline at end of file diff --git a/types/luanti_lsp_definitions/library/vector/vec.lua b/types/luanti_lsp_definitions/library/vector/vec.lua new file mode 100644 index 00000000..b599f2ac --- /dev/null +++ b/types/luanti_lsp_definitions/library/vector/vec.lua @@ -0,0 +1,95 @@ +---@meta _ +-- DRAFT 1 DONE +-- luanti/doc/lua_api.md: Spatial Vectors + +-- ---------------------------------- vec2 ---------------------------------- -- + +--[[ +WIPDOC +]] +---@class vec2i.xy +---@field x integer +---@field y integer + +--[[ +WIPDOC +]] +---@class vec2i.12 +---@field [1] number +---@field [2] number + +--[[ +WIPDOC +]] +---@alias vec2i +--- | vec2i.xy +--- | vec2i.12 + +--[[ +WIPDOC +]] +---@class vec2.xy +---@field x number +---@field y number + +--[[ +WIPDOC +]] +---@class vec2.12 +---@field [1] number +---@field [2] number + +--[[ +WIPDOC +]] +---@alias vec2 +--- | vec2.xy +--- | vec2.12 + +-- ---------------------------------- vec3 ---------------------------------- -- + +--[[ +WIPDOC +]] +---@class vec3i.xyz +---@field x integer +---@field y integer +---@field z integer + +--[[ +WIPDOC +]] +---@class vec3i.123 +---@field [1] integer +---@field [2] integer +---@field [3] integer + +--[[ +WIPDOC +]] +---@alias vec3i +--- | vec3i.xyz +--- | vec3i.123 + +--[[ +WIPDOC +]] +---@class vec3.xyz +---@field x number +---@field y number +---@field z number + +--[[ +WIPDOC +]] +---@class vec3.123 +---@field [1] number +---@field [2] number +---@field [3] number + +--[[ +WIPDOC +]] +---@alias vec3 +--- | vec3.xyz +--- | vec3.123 \ No newline at end of file diff --git a/types/luanti_lsp_definitions/library/vector/vector.lua b/types/luanti_lsp_definitions/library/vector/vector.lua new file mode 100644 index 00000000..0144ca7a --- /dev/null +++ b/types/luanti_lsp_definitions/library/vector/vector.lua @@ -0,0 +1,35 @@ +---@meta _ +-- DRAFT 1 DONE +-- luanti/doc/lua_api.md: Spatial Vectors + +---@class _.vec.__base : core.VectorLib +---@field metatable core.VectorLib +---@operator unm(vector):vector +---@operator add(vector):vector +---@operator sub(vector):vector +---@operator div(vector):vector +---@operator mul(vector):vector + +--[[ +WIPDOC +]] +---@class ivec: vec3i.xyz, _.vec.__base + +--[[ +WIPDOC +]] +---@class vec: vec3.xyz, _.vec.__base + +--[[ +WIPDOC +]] +---@alias ivector +--- | vec3i.xyz +--- | ivec + +--[[ +WIPDOC +]] +---@alias vector +--- | vec3.xyz +--- | vec \ No newline at end of file diff --git a/types/luanti_lsp_definitions/library/vector/vectorlib.lua b/types/luanti_lsp_definitions/library/vector/vectorlib.lua new file mode 100644 index 00000000..d70afa9e --- /dev/null +++ b/types/luanti_lsp_definitions/library/vector/vectorlib.lua @@ -0,0 +1,377 @@ +---@meta _ +-- DRAFT 1 DONE +-- luanti/doc/lua_api.md: Spatial Vectors + +--[[ +WIPDOC +]] +---@class core.VectorLib +vector = {} + +-- ------------------------------ constructors ------------------------------ -- + +--[[ +Returns a new vector `(a, b, c)` +]] +---@nodiscard +---@param a number +---@param b number +---@param c number +---@return vec +function vector.new(a, b, c) end + +--[[ +Returns a new vector `(a, a, a)` +]] +---@nodiscard +---@param a number +---@return vec +function vector.new(a) end + +--[[ +`vector.new(v)` does the same as `vector.copy(v)` +]] +---@deprecated +---@nodiscard +---@param a vector +---@return vec +function vector.new(a) end + +--[[ +`vector.new()` does the same as `vector.zero()` +]] +---@deprecated +---@nodiscard +---@return vec +function vector.new() end + +--[[ +Returns a new vector `(0, 0, 0)` +]] +---@nodiscard +---@return vec +function vector.zero() end + +--[[ +Returns a new vector of length 1, pointing into a direction chosen uniformly at random. +]] +---@nodiscard +---@return vec +function vector.random_direction() end + +--[[ +Returns a copy of the vector `v`. +]] +---@nodiscard +---@param v vector +---@return vec +function vector.copy(v) end + +-- ---------------------------- string conversion --------------------------- -- + +--[[ +Returns v, np, where v is a vector read from the given string s and np is the +next position in the string after the vector. +Returns nil on failure. +]] +---@nodiscard +---@param s string Has to begin with a substring of the form `"(x, y, z)"`. Additional spaces, leaving away commas, and adding an additional comma to the end is allowed. +---@param init number? Starts looking for the vector at this string index +---@return vec? v, integer? np +function vector.from_string(s, init) end + +--[[ +Returns a string of the form `"(x, y, z)"` +`tostring(v)` does the same +]] +---@nodiscard +---@param v vector +---@return vec +function vector.to_string(v) end + +-- -------------------------------------------------------------------------- -- + +--[[ +Returns a vector of length 1 with direction p1 to p2. +If p1 and p2 are identical, returns (0, 0, 0). +]] +---@nodiscard +---@param p1 vector +---@param p2 vector +---@return vec +function vector.direction(p1, p2) end + +--[[ +Returns zero or a positive number, the distance between p1 and p2. +]] +---@nodiscard +---@param p1 vector +---@param p2 vector +---@return number +function vector.distance(p1, p2) end + +--[[ +Returns zero or a positive number, the length of vector v. +]] +---@nodiscard +---@param v vector +---@return number +function vector.length(v) end + +--[[ +Returns a vector of length 1 with direction of vector v. +If v has zero length, returns (0, 0, 0). +]] +---@nodiscard +---@param v vector +---@return vec +function vector.normalize(v) end + +-- -------------------------- rounding and signness ------------------------- -- + +--[[ +Returns a vector, each dimension rounded down. +]] +---@nodiscard +---@param v vector +---@return ivec +function vector.floor(v) end + +--[[ +Returns a vector, each dimension rounded up. +]] +---@nodiscard +---@param v vector +---@return ivec +function vector.ceil(v) end + +--[[ +Returns a vector, each dimension rounded to the nearest integer. +At a multiple of 0.5, rounds away from zero. +]] +---@nodiscard +---@param v vector +---@return ivec +function vector.round(v) end + +--[[ +Returns a vector where `math.sign` was called for each component +]] +---@nodiscard +---@param v vector +---@param tolerance number? +---@return ivec +function vector.sign(v, tolerance) end + +--[[ +Returns a vector with absolute values for each component +]] +---@nodiscard +---@param v vector +---@return vec +function vector.abs(v) end + +-- -------------------------------------------------------------------------- -- + +--[[ +Applies `func` to each component +]] +---@nodiscard +---@param v vector +---@param func fun(n: number): number +---@param ... any Optional arguments passed to `func` +---@return vec +function vector.apply(v, func, ...) end + +--[[ +Returns a vector where the function `func` has combined both components of `v` +and `w` for each component +]] +---@nodiscard +---@param v vector +---@param w vector +---@param func fun(x:number, y:number):number +---@return vec +function vector.combine(v, w, func) end + +--[[ +Returns true if the vectors are identical, false if not +]] +---@nodiscard +---@param v1 vector +---@param v2 vector +---@return vec +function vector.equals(v1, v2) end + +--[[ +Returns in order minp, maxp vectors of the cuboid defined by v1, v2. +(Unofficial note: In other words, each component of the minp is smaller than component in maxp) +]] +---@nodiscard +---@param v1 vector +---@param v2 vector +---@return vec, vec +function vector.sort(v1, v2) end + +-- -------------------------------------------------------------------------- -- + +--[[ +Returns the angle between v1 and v2 in radians +]] +---@nodiscard +---@param v1 vector +---@param v2 vector +---@return number +function vector.angle(v1, v2) end + +--[[ +Returns the dot product +]] +---@nodiscard +---@param v1 vector +---@param v2 vector +---@return number +function vector.dot(v1, v2) end + +--[[ +Returns the cross product +]] +---@nodiscard +---@param v1 vector +---@param v2 vector +---@return vec +function vector.cross(v1, v2) end + +--[[ +Returns the sum of vectors `v` and `(x,y,z)` +]] +---@nodiscard +---@param v vector +---@param x number +---@param y number +---@param z number +---@return vec +function vector.offset(v, x, y, z) end + +--[[ +Checks if `v` is a vector, returns false even for tables like {x=,y=,z=}, has to be created with a vector function +]] +---@nodiscard +---@param v vector +---@return boolean +function vector.check(v) end + +--[[ +Checks if `pos` is inside an area formed by `min` and `max` +`min` and `max` are inclusive +If min is bigger than max on some axis, function always returns false. +You can use vector.sort if you have two vectors and don't know which are the minimum and the maximum. +]] +---@nodiscard +---@param pos vector +---@param min vector +---@param max vector +---@return boolean +function vector.in_area(pos, min, max) end + +--[[ +Returns a random integer position in area formed by min and max +min and max are inclusive. +You can use vector.sort if you have two vectors and don't know which are the minimum and the maximum. +]] +---@nodiscard +---@param min vector +---@param max vector +---@return vec +function vector.random_in_area(min, max) end + +-- ------------------------- arithmetic and products ------------------------ -- + +--[[ +WIPDOC +]] +---@nodiscard +---@param v vector +---@param x vector|number +---@return vec +function vector.add(v, x) end + +--[[ +WIPDOC +]] +---@nodiscard +---@param v vector +---@param x vector|number +---@return vec +function vector.subtract(v, x) end + +--[[ +WIPDOC +]] +---@nodiscard +---@param v vector +---@param x number +---@return vec +function vector.multiply(v, x) end + +--[[ +WIPDOC +]] +---@nodiscard +---@param v vector +---@param x number +---@return vec +function vector.divide(v, x) end + +--[[ +WIPDOC +]] +---@deprecated +---@nodiscard +---@param v vector +---@param x vector +---@return vec +function vector.multiply(v, x) end + +--[[ +WIPDOC +]] +---@deprecated +---@nodiscard +---@param v vector +---@param x vector +---@return vec +function vector.divide(v, x) end + +-- ----------------------- rotation-related functions ----------------------- -- + +--[[ +Applies the rotation r to v and returns the result. +vector.rotate(vector.new(0, 0, 1), r) and vector.rotate(vector.new(0, 1, 0), r) return vectors pointing forward and up relative to an entity's rotation r. +]] +---@nodiscard +---@param v vector +---@param r vector Rotation vector {x=, y=, z=} +---@return vec +function vector.rotate(v, r) end + +--[[ +Returns v1 rotated around axis v2 by a radians according to the right hand rule. +]] +---@nodiscard +---@param v1 vector +---@param v2 vector +---@param a number radians +---@return vec +function vector.rotate_around_axis(v1, v2, a) end + +--[[ +Returns a rotation vector for direction pointing forward using up as the up vector. +If up is omitted, the roll of the returned vector defaults to zero. +Otherwise direction and up need to be vectors in a 90 degree angle to each other. +]] +---@nodiscard +---@param up vector? +---@param direction vector +---@return vec +function vector.dir_to_rotation(direction, up) end \ No newline at end of file diff --git a/types/luanti_lsp_definitions/utils/.cspell-luanti.txt b/types/luanti_lsp_definitions/utils/.cspell-luanti.txt new file mode 100644 index 00000000..28396964 --- /dev/null +++ b/types/luanti_lsp_definitions/utils/.cspell-luanti.txt @@ -0,0 +1,40 @@ +bgcolor +dtime +emax +emin +hpchange +hypot +indexof +irrlicht +lbm +lbmdef +lbms +lsystem +luals +luanti +luma +manip +maxp +maxx +maxy +maxz +minp +minx +miny +minz +mymod +nodiscard +noiseparam +noiseparams +pmax +pmin +priv +privs +prng +schem +unregister +unregisters +vmanip +xslice +yslice +zslice diff --git a/types/luanti_lsp_definitions/utils/.cspell-misc.txt b/types/luanti_lsp_definitions/utils/.cspell-misc.txt new file mode 100644 index 00000000..6d658b38 --- /dev/null +++ b/types/luanti_lsp_definitions/utils/.cspell-misc.txt @@ -0,0 +1,7 @@ +emmylua +fgaz +luarc +nvim +burnti +FFFFFAFFBF +voronoi \ No newline at end of file diff --git a/types/luanti_lsp_definitions/utils/LGPLv2.1..txt b/types/luanti_lsp_definitions/utils/LGPLv2.1..txt new file mode 100644 index 00000000..f6683e74 --- /dev/null +++ b/types/luanti_lsp_definitions/utils/LGPLv2.1..txt @@ -0,0 +1,501 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 + + Copyright (C) 1991, 1999 Free Software Foundation, Inc. + + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the Lesser GPL. It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Lesser General Public License, applies to some +specially designated software packages--typically libraries--of the +Free Software Foundation and other authors who decide to use it. You +can use it too, but we suggest you first think carefully about whether +this license or the ordinary General Public License is the better +strategy to use in any particular case, based on the explanations below. + + When we speak of free software, we are referring to freedom of use, +not price. Our General Public Licenses are designed to make sure that +you have the freedom to distribute copies of free software (and charge +for this service if you wish); that you receive source code or can get +it if you want it; that you can change the software and use pieces of +it in new free programs; and that you are informed that you can do +these things. + + To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +rights. These restrictions translate to certain responsibilities for +you if you distribute copies of the library or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link other code with the library, you must provide +complete object files to the recipients, so that they can relink them +with the library after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + + To protect each distributor, we want to make it very clear that +there is no warranty for the free library. Also, if the library is +modified by someone else and passed on, the recipients should know +that what they have is not the original version, so that the original +author's reputation will not be affected by problems that might be +introduced by others. + + Finally, software patents pose a constant threat to the existence of +any free program. We wish to make sure that a company cannot +effectively restrict the users of a free program by obtaining a +restrictive license from a patent holder. Therefore, we insist that +any patent license obtained for a version of the library must be +consistent with the full freedom of use specified in this license. + + Most GNU software, including some libraries, is covered by the +ordinary GNU General Public License. This license, the GNU Lesser +General Public License, applies to certain designated libraries, and +is quite different from the ordinary General Public License. We use +this license for certain libraries in order to permit linking those +libraries into non-free programs. + + When a program is linked with a library, whether statically or using +a shared library, the combination of the two is legally speaking a +combined work, a derivative of the original library. The ordinary +General Public License therefore permits such linking only if the +entire combination fits its criteria of freedom. The Lesser General +Public License permits more lax criteria for linking other code with +the library. + + We call this license the "Lesser" General Public License because it +does Less to protect the user's freedom than the ordinary General +Public License. It also provides other free software developers Less +of an advantage over competing non-free programs. These disadvantages +are the reason we use the ordinary General Public License for many +libraries. However, the Lesser license provides advantages in certain +special circumstances. + + For example, on rare occasions, there may be a special need to +encourage the widest possible use of a certain library, so that it becomes +a de-facto standard. To achieve this, non-free programs must be +allowed to use the library. A more frequent case is that a free +library does the same job as widely used non-free libraries. In this +case, there is little to gain by limiting the free library to free +software only, so we use the Lesser General Public License. + + In other cases, permission to use a particular library in non-free +programs enables a greater number of people to use a large body of +free software. For example, permission to use the GNU C Library in +non-free programs enables many more people to use the whole GNU +operating system, as well as its variant, the GNU/Linux operating +system. + + Although the Lesser General Public License is Less protective of the +users' freedom, it does ensure that the user of a program that is +linked with the Library has the freedom and the wherewithal to run +that program using a modified version of the Library. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, whereas the latter must +be combined with the library in order to run. + + GNU LESSER GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library or other +program which contains a notice placed by the copyright holder or +other authorized party saying it may be distributed under the terms of +this Lesser General Public License (also called "this License"). +Each licensee is addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also combine or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a + copy of the library already present on the user's computer system, + rather than copying library functions into the executable, and (2) + will operate properly with a modified version of the library, if + the user installs one, as long as the modified version is + interface-compatible with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + d) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + e) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the materials to be distributed need not include anything that is +normally distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties with +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Lesser General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + + To apply these terms, attach the following notices to the library. It is +safest to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least the +"copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, see . + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James Random Hacker. + + , 1 April 1990 + Moe Ghoul, President of Vice + +That's all there is to it! From 1818c88e79035325e152337354db84bb0793aae4 Mon Sep 17 00:00:00 2001 From: TheEt1234 Date: Fri, 3 Oct 2025 19:51:40 +0200 Subject: [PATCH 09/28] Submodules experiment #02 --- .gitmodules | 3 + luanti_lsp_definitions | 1 + types/luanti_lsp_definitions/.cspell.json | 22 - types/luanti_lsp_definitions/.gitignore | 37 - types/luanti_lsp_definitions/.luarc.json | 4 - types/luanti_lsp_definitions/CHANGELOG.md | 0 types/luanti_lsp_definitions/LICENSE | 38 - types/luanti_lsp_definitions/MAINTENANCE.md | 141 -- types/luanti_lsp_definitions/README.md | 135 -- types/luanti_lsp_definitions/config.json | 21 - .../library/classes/AreaStore.lua | 301 --- .../library/classes/AsyncJob.lua | 16 - .../library/classes/InvRef.lua | 156 -- .../library/classes/ItemStack.lua | 268 --- .../library/classes/ItemStackMetaRef.lua | 113 - .../library/classes/MetaDataRef.lua | 100 - .../library/classes/ModChannel.lua | 35 - .../library/classes/NodeMetaRef.lua | 118 -- .../library/classes/NodeTimer.lua | 53 - .../library/classes/ObjectRef/EntityRef.lua | 176 -- .../library/classes/ObjectRef/ObjectRef.lua | 373 ---- .../library/classes/ObjectRef/PlayerRef.lua | 549 ----- .../library/classes/ObjectRef/bones.lua | 150 -- .../library/classes/ObjectRef/nametag.lua | 80 - .../classes/ObjectRef/player_clouds.lua | 107 - .../classes/ObjectRef/player_control.lua | 110 - .../classes/ObjectRef/player_flags.lua | 63 - .../classes/ObjectRef/player_hud_flags.lua | 112 - .../classes/ObjectRef/player_lighting.lua | 219 -- .../classes/ObjectRef/player_minimap.lua | 71 - .../library/classes/ObjectRef/player_moon.lua | 66 - .../ObjectRef/player_physics_override.lua | 162 -- .../classes/ObjectRef/player_skybox.lua | 368 ---- .../library/classes/ObjectRef/player_star.lua | 89 - .../library/classes/ObjectRef/player_sun.lua | 82 - .../library/classes/PcgRandom.lua | 66 - .../library/classes/PlayerMetaRef.lua | 100 - .../library/classes/PseudoRandom.lua | 59 - .../library/classes/Raycast.lua | 177 -- .../library/classes/SecureRandom.lua | 40 - .../LuantiSettings/LuantiSettings.lua | 266 --- .../Settings/LuantiSettings/advanced.lua | 1398 ------------ .../LuantiSettings/client_and_server.lua | 490 ----- .../Settings/LuantiSettings/controls.lua | 700 ------ .../LuantiSettings/graphics_and_audio.lua | 1032 --------- .../Settings/LuantiSettings/mapgen.lua | 1888 ----------------- .../LuantiSettings/settings_enums.lua | 60 - .../LuantiSettings/settings_flags.lua | 48 - .../library/classes/Settings/Settings.lua | 188 -- .../library/classes/StorageRef.lua | 126 -- .../library/classes/ValueNoise.lua | 171 -- .../library/classes/ValueNoiseMap.lua | 169 -- .../library/classes/VoxelArea.lua | 129 -- .../library/classes/VoxelManip.lua | 325 --- .../library/core/async_environment.lua | 38 - .../library/core/authentication.lua | 185 -- .../library/core/ban.lua | 61 - .../library/core/chat.lua | 30 - .../library/core/core.lua | 24 - .../library/core/defaults.lua | 156 -- .../library/core/environment/biome_data.lua | 33 - .../library/core/environment/emerge_area.lua | 75 - .../library/core/environment/environment.lua | 946 --------- .../core/environment/mapgen_params.lua | 69 - .../library/core/escape_sequences.lua | 66 - .../library/core/formspec_functions.lua | 145 -- .../library/core/global_tables.lua | 332 --- .../library/core/http.lua | 66 - .../library/core/inventory.lua | 93 - .../library/core/ipc.lua | 69 - .../core/item_handling/craft_result.lua | 285 --- .../core/item_handling/item_handling.lua | 167 -- .../library/core/logging.lua | 35 - .../library/core/mapgen_environment.lua | 70 - .../library/core/misc/get_group.lua | 145 -- .../core/misc/insecure_environment.lua | 26 - .../library/core/misc/misc.lua | 596 ------ .../library/core/mod_channels.lua | 11 - .../library/core/particles.lua | 72 - .../library/core/register/cheat.lua | 48 - .../library/core/register/environment.lua | 150 -- .../library/core/register/gameplay.lua | 49 - .../library/core/register/global_callback.lua | 451 ---- .../library/core/register/hpchange.lua | 155 -- .../core/register/inventory_action.lua | 114 - .../core/register/player_receive_fields.lua | 73 - .../library/core/register/playerevent.lua | 28 - .../library/core/rollback.lua | 54 - .../library/core/schematics.lua | 168 -- .../library/core/server/dynamic_media.lua | 69 - .../library/core/server/server.lua | 76 - .../library/core/settings.lua | 14 - .../library/core/sounds.lua | 48 - .../library/core/timing.lua | 32 - .../library/core/translations.lua | 87 - .../library/core/utilities/dig_params.lua | 54 - .../library/core/utilities/engine_version.lua | 48 - .../library/core/utilities/features.lua | 314 --- .../library/core/utilities/game_info.lua | 35 - .../library/core/utilities/helpers.lua | 102 - .../library/core/utilities/hit_params.lua | 41 - .../core/utilities/player_information.lua | 131 -- .../core/utilities/protocol_versions.lua | 89 - .../library/core/utilities/utilities.lua | 208 -- .../library/defs/HTTPRequest.lua | 60 - .../library/defs/HTTPRequestResult.lua | 29 - .../library/defs/abm.lua | 76 - .../library/defs/aliases.lua | 71 - .../library/defs/authentication_handler.lua | 106 - .../library/defs/biome.lua | 143 -- .../library/defs/chat_command.lua | 92 - .../library/defs/colors.lua | 208 -- .../library/defs/crafting/cooking.lua | 60 - .../library/defs/crafting/crafting.lua | 58 - .../library/defs/crafting/fuel.lua | 54 - .../library/defs/crafting/shaped.lua | 65 - .../library/defs/crafting/shapeless.lua | 47 - .../library/defs/crafting/toolrepair.lua | 52 - .../library/defs/decoration/decoration.lua | 259 --- .../library/defs/decoration/flags.lua | 96 - .../library/defs/detached_inventory.lua | 62 - .../library/defs/entity/collision.lua | 62 - .../library/defs/entity/entity.lua | 140 -- .../library/defs/entity/moveresult.lua | 26 - .../library/defs/formspec.lua | 8 - .../library/defs/group.lua | 172 -- .../library/defs/hud/compass.lua | 65 - .../library/defs/hud/hotbar.lua | 13 - .../library/defs/hud/hud.lua | 100 - .../library/defs/hud/image.lua | 21 - .../library/defs/hud/image_waypoint.lua | 24 - .../library/defs/hud/inventory.lua | 25 - .../library/defs/hud/minimap.lua | 17 - .../library/defs/hud/statbar.lua | 33 - .../library/defs/hud/text.lua | 46 - .../library/defs/hud/waypoint.lua | 25 - .../library/defs/inventory.lua | 83 - .../library/defs/item/item.lua | 70 - .../library/defs/item/itemdef.lua | 282 --- .../library/defs/item/pointabilities.lua | 43 - .../library/defs/item/sound.lua | 34 - .../library/defs/item/touch_interaction.lua | 55 - .../library/defs/lbm.lua | 96 - .../library/defs/lsystem.lua | 126 -- .../library/defs/mapgen_objects.lua | 158 -- .../library/defs/metadata/item.lua | 120 -- .../library/defs/metadata/metadata.lua | 50 - .../library/defs/metadata/node.lua | 87 - .../library/defs/metadata/player.lua | 61 - .../library/defs/metadata/storage.lua | 61 - .../library/defs/node/drawtype.lua | 37 - .../library/defs/node/drop.lua | 61 - .../library/defs/node/node.lua | 155 -- .../library/defs/node/nodebox.lua | 182 -- .../library/defs/node/nodedef.lua | 821 ------- .../library/defs/node/paramtype.lua | 72 - .../library/defs/node/sounds.lua | 42 - .../library/defs/node/tiles.lua | 85 - .../library/defs/noiseparams.lua | 209 -- .../library/defs/object_properties/box.lua | 109 - .../object_properties/object_properties.lua | 300 --- .../partial/backface_clling.lua | 17 - .../defs/object_properties/partial/shaded.lua | 19 - .../object_properties/partial/spritesheet.lua | 33 - .../object_properties/player_properties.lua | 111 - .../defs/object_properties/types/cube.lua | 85 - .../defs/object_properties/types/item.lua | 19 - .../defs/object_properties/types/mesh.lua | 55 - .../defs/object_properties/types/node.lua | 33 - .../defs/object_properties/types/sprite.lua | 64 - .../types/upright_sprite.lua | 69 - .../object_properties/types/wielditem.lua | 66 - .../library/defs/ore/blob.lua | 43 - .../library/defs/ore/ore.lua | 58 - .../library/defs/ore/puff.lua | 92 - .../library/defs/ore/scatter.lua | 55 - .../library/defs/ore/sheet.lua | 45 - .../library/defs/ore/stratum.lua | 35 - .../library/defs/ore/vein.lua | 31 - .../library/defs/particle/ParticleSpawner.lua | 197 -- .../library/defs/particle/attract.lua | 57 - .../library/defs/particle/particle.lua | 115 - .../library/defs/particle/texture.lua | 58 - .../library/defs/particle/type.lua | 133 -- .../library/defs/pointed_thing.lua | 99 - .../library/defs/privilege.lua | 152 -- .../library/defs/schematics.lua | 155 -- .../library/defs/sound.lua | 81 - .../library/defs/textures.lua | 8 - .../library/defs/tile.lua | 134 -- .../library/defs/tool_capabilities.lua | 96 - .../library/defs/wear_bar_color.lua | 23 - .../library/helpers.lua | 203 -- types/luanti_lsp_definitions/library/misc.lua | 66 - .../library/vector/vec.lua | 95 - .../library/vector/vector.lua | 35 - .../library/vector/vectorlib.lua | 377 ---- .../utils/.cspell-luanti.txt | 40 - .../utils/.cspell-misc.txt | 7 - .../utils/LGPLv2.1..txt | 501 ----- 200 files changed, 4 insertions(+), 27476 deletions(-) create mode 160000 luanti_lsp_definitions delete mode 100644 types/luanti_lsp_definitions/.cspell.json delete mode 100644 types/luanti_lsp_definitions/.gitignore delete mode 100644 types/luanti_lsp_definitions/.luarc.json delete mode 100644 types/luanti_lsp_definitions/CHANGELOG.md delete mode 100644 types/luanti_lsp_definitions/LICENSE delete mode 100644 types/luanti_lsp_definitions/MAINTENANCE.md delete mode 100644 types/luanti_lsp_definitions/README.md delete mode 100644 types/luanti_lsp_definitions/config.json delete mode 100644 types/luanti_lsp_definitions/library/classes/AreaStore.lua delete mode 100644 types/luanti_lsp_definitions/library/classes/AsyncJob.lua delete mode 100644 types/luanti_lsp_definitions/library/classes/InvRef.lua delete mode 100644 types/luanti_lsp_definitions/library/classes/ItemStack.lua delete mode 100644 types/luanti_lsp_definitions/library/classes/ItemStackMetaRef.lua delete mode 100644 types/luanti_lsp_definitions/library/classes/MetaDataRef.lua delete mode 100644 types/luanti_lsp_definitions/library/classes/ModChannel.lua delete mode 100644 types/luanti_lsp_definitions/library/classes/NodeMetaRef.lua delete mode 100644 types/luanti_lsp_definitions/library/classes/NodeTimer.lua delete mode 100644 types/luanti_lsp_definitions/library/classes/ObjectRef/EntityRef.lua delete mode 100644 types/luanti_lsp_definitions/library/classes/ObjectRef/ObjectRef.lua delete mode 100644 types/luanti_lsp_definitions/library/classes/ObjectRef/PlayerRef.lua delete mode 100644 types/luanti_lsp_definitions/library/classes/ObjectRef/bones.lua delete mode 100644 types/luanti_lsp_definitions/library/classes/ObjectRef/nametag.lua delete mode 100644 types/luanti_lsp_definitions/library/classes/ObjectRef/player_clouds.lua delete mode 100644 types/luanti_lsp_definitions/library/classes/ObjectRef/player_control.lua delete mode 100644 types/luanti_lsp_definitions/library/classes/ObjectRef/player_flags.lua delete mode 100644 types/luanti_lsp_definitions/library/classes/ObjectRef/player_hud_flags.lua delete mode 100644 types/luanti_lsp_definitions/library/classes/ObjectRef/player_lighting.lua delete mode 100644 types/luanti_lsp_definitions/library/classes/ObjectRef/player_minimap.lua delete mode 100644 types/luanti_lsp_definitions/library/classes/ObjectRef/player_moon.lua delete mode 100644 types/luanti_lsp_definitions/library/classes/ObjectRef/player_physics_override.lua delete mode 100644 types/luanti_lsp_definitions/library/classes/ObjectRef/player_skybox.lua delete mode 100644 types/luanti_lsp_definitions/library/classes/ObjectRef/player_star.lua delete mode 100644 types/luanti_lsp_definitions/library/classes/ObjectRef/player_sun.lua delete mode 100644 types/luanti_lsp_definitions/library/classes/PcgRandom.lua delete mode 100644 types/luanti_lsp_definitions/library/classes/PlayerMetaRef.lua delete mode 100644 types/luanti_lsp_definitions/library/classes/PseudoRandom.lua delete mode 100644 types/luanti_lsp_definitions/library/classes/Raycast.lua delete mode 100644 types/luanti_lsp_definitions/library/classes/SecureRandom.lua delete mode 100644 types/luanti_lsp_definitions/library/classes/Settings/LuantiSettings/LuantiSettings.lua delete mode 100644 types/luanti_lsp_definitions/library/classes/Settings/LuantiSettings/advanced.lua delete mode 100644 types/luanti_lsp_definitions/library/classes/Settings/LuantiSettings/client_and_server.lua delete mode 100644 types/luanti_lsp_definitions/library/classes/Settings/LuantiSettings/controls.lua delete mode 100644 types/luanti_lsp_definitions/library/classes/Settings/LuantiSettings/graphics_and_audio.lua delete mode 100644 types/luanti_lsp_definitions/library/classes/Settings/LuantiSettings/mapgen.lua delete mode 100644 types/luanti_lsp_definitions/library/classes/Settings/LuantiSettings/settings_enums.lua delete mode 100644 types/luanti_lsp_definitions/library/classes/Settings/LuantiSettings/settings_flags.lua delete mode 100644 types/luanti_lsp_definitions/library/classes/Settings/Settings.lua delete mode 100644 types/luanti_lsp_definitions/library/classes/StorageRef.lua delete mode 100644 types/luanti_lsp_definitions/library/classes/ValueNoise.lua delete mode 100644 types/luanti_lsp_definitions/library/classes/ValueNoiseMap.lua delete mode 100644 types/luanti_lsp_definitions/library/classes/VoxelArea.lua delete mode 100644 types/luanti_lsp_definitions/library/classes/VoxelManip.lua delete mode 100644 types/luanti_lsp_definitions/library/core/async_environment.lua delete mode 100644 types/luanti_lsp_definitions/library/core/authentication.lua delete mode 100644 types/luanti_lsp_definitions/library/core/ban.lua delete mode 100644 types/luanti_lsp_definitions/library/core/chat.lua delete mode 100644 types/luanti_lsp_definitions/library/core/core.lua delete mode 100644 types/luanti_lsp_definitions/library/core/defaults.lua delete mode 100644 types/luanti_lsp_definitions/library/core/environment/biome_data.lua delete mode 100644 types/luanti_lsp_definitions/library/core/environment/emerge_area.lua delete mode 100644 types/luanti_lsp_definitions/library/core/environment/environment.lua delete mode 100644 types/luanti_lsp_definitions/library/core/environment/mapgen_params.lua delete mode 100644 types/luanti_lsp_definitions/library/core/escape_sequences.lua delete mode 100644 types/luanti_lsp_definitions/library/core/formspec_functions.lua delete mode 100644 types/luanti_lsp_definitions/library/core/global_tables.lua delete mode 100644 types/luanti_lsp_definitions/library/core/http.lua delete mode 100644 types/luanti_lsp_definitions/library/core/inventory.lua delete mode 100644 types/luanti_lsp_definitions/library/core/ipc.lua delete mode 100644 types/luanti_lsp_definitions/library/core/item_handling/craft_result.lua delete mode 100644 types/luanti_lsp_definitions/library/core/item_handling/item_handling.lua delete mode 100644 types/luanti_lsp_definitions/library/core/logging.lua delete mode 100644 types/luanti_lsp_definitions/library/core/mapgen_environment.lua delete mode 100644 types/luanti_lsp_definitions/library/core/misc/get_group.lua delete mode 100644 types/luanti_lsp_definitions/library/core/misc/insecure_environment.lua delete mode 100644 types/luanti_lsp_definitions/library/core/misc/misc.lua delete mode 100644 types/luanti_lsp_definitions/library/core/mod_channels.lua delete mode 100644 types/luanti_lsp_definitions/library/core/particles.lua delete mode 100644 types/luanti_lsp_definitions/library/core/register/cheat.lua delete mode 100644 types/luanti_lsp_definitions/library/core/register/environment.lua delete mode 100644 types/luanti_lsp_definitions/library/core/register/gameplay.lua delete mode 100644 types/luanti_lsp_definitions/library/core/register/global_callback.lua delete mode 100644 types/luanti_lsp_definitions/library/core/register/hpchange.lua delete mode 100644 types/luanti_lsp_definitions/library/core/register/inventory_action.lua delete mode 100644 types/luanti_lsp_definitions/library/core/register/player_receive_fields.lua delete mode 100644 types/luanti_lsp_definitions/library/core/register/playerevent.lua delete mode 100644 types/luanti_lsp_definitions/library/core/rollback.lua delete mode 100644 types/luanti_lsp_definitions/library/core/schematics.lua delete mode 100644 types/luanti_lsp_definitions/library/core/server/dynamic_media.lua delete mode 100644 types/luanti_lsp_definitions/library/core/server/server.lua delete mode 100644 types/luanti_lsp_definitions/library/core/settings.lua delete mode 100644 types/luanti_lsp_definitions/library/core/sounds.lua delete mode 100644 types/luanti_lsp_definitions/library/core/timing.lua delete mode 100644 types/luanti_lsp_definitions/library/core/translations.lua delete mode 100644 types/luanti_lsp_definitions/library/core/utilities/dig_params.lua delete mode 100644 types/luanti_lsp_definitions/library/core/utilities/engine_version.lua delete mode 100644 types/luanti_lsp_definitions/library/core/utilities/features.lua delete mode 100644 types/luanti_lsp_definitions/library/core/utilities/game_info.lua delete mode 100644 types/luanti_lsp_definitions/library/core/utilities/helpers.lua delete mode 100644 types/luanti_lsp_definitions/library/core/utilities/hit_params.lua delete mode 100644 types/luanti_lsp_definitions/library/core/utilities/player_information.lua delete mode 100644 types/luanti_lsp_definitions/library/core/utilities/protocol_versions.lua delete mode 100644 types/luanti_lsp_definitions/library/core/utilities/utilities.lua delete mode 100644 types/luanti_lsp_definitions/library/defs/HTTPRequest.lua delete mode 100644 types/luanti_lsp_definitions/library/defs/HTTPRequestResult.lua delete mode 100644 types/luanti_lsp_definitions/library/defs/abm.lua delete mode 100644 types/luanti_lsp_definitions/library/defs/aliases.lua delete mode 100644 types/luanti_lsp_definitions/library/defs/authentication_handler.lua delete mode 100644 types/luanti_lsp_definitions/library/defs/biome.lua delete mode 100644 types/luanti_lsp_definitions/library/defs/chat_command.lua delete mode 100644 types/luanti_lsp_definitions/library/defs/colors.lua delete mode 100644 types/luanti_lsp_definitions/library/defs/crafting/cooking.lua delete mode 100644 types/luanti_lsp_definitions/library/defs/crafting/crafting.lua delete mode 100644 types/luanti_lsp_definitions/library/defs/crafting/fuel.lua delete mode 100644 types/luanti_lsp_definitions/library/defs/crafting/shaped.lua delete mode 100644 types/luanti_lsp_definitions/library/defs/crafting/shapeless.lua delete mode 100644 types/luanti_lsp_definitions/library/defs/crafting/toolrepair.lua delete mode 100644 types/luanti_lsp_definitions/library/defs/decoration/decoration.lua delete mode 100644 types/luanti_lsp_definitions/library/defs/decoration/flags.lua delete mode 100644 types/luanti_lsp_definitions/library/defs/detached_inventory.lua delete mode 100644 types/luanti_lsp_definitions/library/defs/entity/collision.lua delete mode 100644 types/luanti_lsp_definitions/library/defs/entity/entity.lua delete mode 100644 types/luanti_lsp_definitions/library/defs/entity/moveresult.lua delete mode 100644 types/luanti_lsp_definitions/library/defs/formspec.lua delete mode 100644 types/luanti_lsp_definitions/library/defs/group.lua delete mode 100644 types/luanti_lsp_definitions/library/defs/hud/compass.lua delete mode 100644 types/luanti_lsp_definitions/library/defs/hud/hotbar.lua delete mode 100644 types/luanti_lsp_definitions/library/defs/hud/hud.lua delete mode 100644 types/luanti_lsp_definitions/library/defs/hud/image.lua delete mode 100644 types/luanti_lsp_definitions/library/defs/hud/image_waypoint.lua delete mode 100644 types/luanti_lsp_definitions/library/defs/hud/inventory.lua delete mode 100644 types/luanti_lsp_definitions/library/defs/hud/minimap.lua delete mode 100644 types/luanti_lsp_definitions/library/defs/hud/statbar.lua delete mode 100644 types/luanti_lsp_definitions/library/defs/hud/text.lua delete mode 100644 types/luanti_lsp_definitions/library/defs/hud/waypoint.lua delete mode 100644 types/luanti_lsp_definitions/library/defs/inventory.lua delete mode 100644 types/luanti_lsp_definitions/library/defs/item/item.lua delete mode 100644 types/luanti_lsp_definitions/library/defs/item/itemdef.lua delete mode 100644 types/luanti_lsp_definitions/library/defs/item/pointabilities.lua delete mode 100644 types/luanti_lsp_definitions/library/defs/item/sound.lua delete mode 100644 types/luanti_lsp_definitions/library/defs/item/touch_interaction.lua delete mode 100644 types/luanti_lsp_definitions/library/defs/lbm.lua delete mode 100644 types/luanti_lsp_definitions/library/defs/lsystem.lua delete mode 100644 types/luanti_lsp_definitions/library/defs/mapgen_objects.lua delete mode 100644 types/luanti_lsp_definitions/library/defs/metadata/item.lua delete mode 100644 types/luanti_lsp_definitions/library/defs/metadata/metadata.lua delete mode 100644 types/luanti_lsp_definitions/library/defs/metadata/node.lua delete mode 100644 types/luanti_lsp_definitions/library/defs/metadata/player.lua delete mode 100644 types/luanti_lsp_definitions/library/defs/metadata/storage.lua delete mode 100644 types/luanti_lsp_definitions/library/defs/node/drawtype.lua delete mode 100644 types/luanti_lsp_definitions/library/defs/node/drop.lua delete mode 100644 types/luanti_lsp_definitions/library/defs/node/node.lua delete mode 100644 types/luanti_lsp_definitions/library/defs/node/nodebox.lua delete mode 100644 types/luanti_lsp_definitions/library/defs/node/nodedef.lua delete mode 100644 types/luanti_lsp_definitions/library/defs/node/paramtype.lua delete mode 100644 types/luanti_lsp_definitions/library/defs/node/sounds.lua delete mode 100644 types/luanti_lsp_definitions/library/defs/node/tiles.lua delete mode 100644 types/luanti_lsp_definitions/library/defs/noiseparams.lua delete mode 100644 types/luanti_lsp_definitions/library/defs/object_properties/box.lua delete mode 100644 types/luanti_lsp_definitions/library/defs/object_properties/object_properties.lua delete mode 100644 types/luanti_lsp_definitions/library/defs/object_properties/partial/backface_clling.lua delete mode 100644 types/luanti_lsp_definitions/library/defs/object_properties/partial/shaded.lua delete mode 100644 types/luanti_lsp_definitions/library/defs/object_properties/partial/spritesheet.lua delete mode 100644 types/luanti_lsp_definitions/library/defs/object_properties/player_properties.lua delete mode 100644 types/luanti_lsp_definitions/library/defs/object_properties/types/cube.lua delete mode 100644 types/luanti_lsp_definitions/library/defs/object_properties/types/item.lua delete mode 100644 types/luanti_lsp_definitions/library/defs/object_properties/types/mesh.lua delete mode 100644 types/luanti_lsp_definitions/library/defs/object_properties/types/node.lua delete mode 100644 types/luanti_lsp_definitions/library/defs/object_properties/types/sprite.lua delete mode 100644 types/luanti_lsp_definitions/library/defs/object_properties/types/upright_sprite.lua delete mode 100644 types/luanti_lsp_definitions/library/defs/object_properties/types/wielditem.lua delete mode 100644 types/luanti_lsp_definitions/library/defs/ore/blob.lua delete mode 100644 types/luanti_lsp_definitions/library/defs/ore/ore.lua delete mode 100644 types/luanti_lsp_definitions/library/defs/ore/puff.lua delete mode 100644 types/luanti_lsp_definitions/library/defs/ore/scatter.lua delete mode 100644 types/luanti_lsp_definitions/library/defs/ore/sheet.lua delete mode 100644 types/luanti_lsp_definitions/library/defs/ore/stratum.lua delete mode 100644 types/luanti_lsp_definitions/library/defs/ore/vein.lua delete mode 100644 types/luanti_lsp_definitions/library/defs/particle/ParticleSpawner.lua delete mode 100644 types/luanti_lsp_definitions/library/defs/particle/attract.lua delete mode 100644 types/luanti_lsp_definitions/library/defs/particle/particle.lua delete mode 100644 types/luanti_lsp_definitions/library/defs/particle/texture.lua delete mode 100644 types/luanti_lsp_definitions/library/defs/particle/type.lua delete mode 100644 types/luanti_lsp_definitions/library/defs/pointed_thing.lua delete mode 100644 types/luanti_lsp_definitions/library/defs/privilege.lua delete mode 100644 types/luanti_lsp_definitions/library/defs/schematics.lua delete mode 100644 types/luanti_lsp_definitions/library/defs/sound.lua delete mode 100644 types/luanti_lsp_definitions/library/defs/textures.lua delete mode 100644 types/luanti_lsp_definitions/library/defs/tile.lua delete mode 100644 types/luanti_lsp_definitions/library/defs/tool_capabilities.lua delete mode 100644 types/luanti_lsp_definitions/library/defs/wear_bar_color.lua delete mode 100644 types/luanti_lsp_definitions/library/helpers.lua delete mode 100644 types/luanti_lsp_definitions/library/misc.lua delete mode 100644 types/luanti_lsp_definitions/library/vector/vec.lua delete mode 100644 types/luanti_lsp_definitions/library/vector/vector.lua delete mode 100644 types/luanti_lsp_definitions/library/vector/vectorlib.lua delete mode 100644 types/luanti_lsp_definitions/utils/.cspell-luanti.txt delete mode 100644 types/luanti_lsp_definitions/utils/.cspell-misc.txt delete mode 100644 types/luanti_lsp_definitions/utils/LGPLv2.1..txt diff --git a/.gitmodules b/.gitmodules index e58e8e7b..fdcc0588 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,6 @@ [submodule "mods/hotbar_switching"] path = mods/hotbar_switching url = https://github.com/TheEt1234/hotbar_switching +[submodule "luanti_lsp_definitions"] + path = luanti_lsp_definitions + url = https://github.com/corpserot/luanti_lsp_definitions/ diff --git a/luanti_lsp_definitions b/luanti_lsp_definitions new file mode 160000 index 00000000..bdbb099e --- /dev/null +++ b/luanti_lsp_definitions @@ -0,0 +1 @@ +Subproject commit bdbb099e4fc5f2c7a75abfc91ac820dd093b3249 diff --git a/types/luanti_lsp_definitions/.cspell.json b/types/luanti_lsp_definitions/.cspell.json deleted file mode 100644 index 7a31c11f..00000000 --- a/types/luanti_lsp_definitions/.cspell.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "$schema": "https://raw.githubusercontent.com/streetsidesoftware/cspell/main/cspell.schema.json", - "allowCompoundWords": true, - "dictionaryDefinitions": [ - { - "name": "luanti", - "path": "utils/.cspell-luanti.txt", - "addWords": true - }, - { - "name": "misc", - "path": "utils/.cspell-misc.txt", - "addWords": true - } - ], - "dictionaries": ["lua", "luanti", "misc", "public-licenses"], - "ignorePaths": [ - "utils/.cspell-luanti.txt", - "utils/.cspell-misc.txt", - "LICENSE" - ], -} diff --git a/types/luanti_lsp_definitions/.gitignore b/types/luanti_lsp_definitions/.gitignore deleted file mode 100644 index 2f151ff8..00000000 --- a/types/luanti_lsp_definitions/.gitignore +++ /dev/null @@ -1,37 +0,0 @@ -*~ - -# vscode(ium) -.vscode/* -.vscode/settings.json -!.vscode/tasks.json -!.vscode/launch.json -!.vscode/extensions.json -!.vscode/*.code-snippets -!*.code-workspace - -# (neo)vim -[._]*.s[a-v][a-z] -!*.svg -[._]*.sw[a-p] -[._]s[a-rt-v][a-z] -[._]ss[a-gi-z] -[._]sw[a-p] -Session.vim -Sessionx.vim -.netrwhist -tags - -# emacs -*~ -\#*\# -/.emacs.desktop -/.emacs.desktop.lock -*.elc -auto-save-list -tramp -.\#* -.org-id-locations -*_archive -*_flymake.* -.projectile -.dir-locals.el \ No newline at end of file diff --git a/types/luanti_lsp_definitions/.luarc.json b/types/luanti_lsp_definitions/.luarc.json deleted file mode 100644 index 7c60475b..00000000 --- a/types/luanti_lsp_definitions/.luarc.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "$schema": "https://raw.githubusercontent.com/LuaLS/vscode-lua/master/setting/schema.json", - "runtime.version": "LuaJIT" -} diff --git a/types/luanti_lsp_definitions/CHANGELOG.md b/types/luanti_lsp_definitions/CHANGELOG.md deleted file mode 100644 index e69de29b..00000000 diff --git a/types/luanti_lsp_definitions/LICENSE b/types/luanti_lsp_definitions/LICENSE deleted file mode 100644 index 13749ff4..00000000 --- a/types/luanti_lsp_definitions/LICENSE +++ /dev/null @@ -1,38 +0,0 @@ -For parts original in Luanti_lsp_definitions: ---------------------------------------------- - -Copyright (C) 2025 - corpserot a.k.a Acorp <@corpserot on github> - TheEt1234 a.k.a frog <@TheEt1234 on github> -and contributors (see version control log for their names and contact details) - -Licensed under the GNU Lesser General Public License, version 2.1 (or later). ---- - -For parts from Luanti: ----------------------- - -Copyright (C) 2010-2025 - celeron55, Perttu Ahola -and contributors (see respective project source file comments and the version control log) - -Licensed under the GNU Lesser General Public License, version 2.1 (or later). ---- - -LGPLv2.1 license notice: ------------------------- - -This program is free software; you can redistribute it and/or modify -it under the terms of the GNU Lesser General Public License as published by -the Free Software Foundation; either version 2.1 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public License along -with this program; if not, write to the Free Software Foundation, Inc., -51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. ---- diff --git a/types/luanti_lsp_definitions/MAINTENANCE.md b/types/luanti_lsp_definitions/MAINTENANCE.md deleted file mode 100644 index 82e497c5..00000000 --- a/types/luanti_lsp_definitions/MAINTENANCE.md +++ /dev/null @@ -1,141 +0,0 @@ -# Guidelines -You should try to get new information merged into the following places first. These are considered *primary sources*. e.g. You want to clarify that object rotations are actually right-handed. You should make a PR to these repos first. -- , usually something within `doc` directory. -- - -This project represents yet another place to document Luanti API . This time, through annotation. It is expected that this project will have some extra information not suitable for inclusion in the primary sources. - -Contributors should get familiar with [LuaCATS, the annotation & type system](https://luals.github.io/wiki/annotations) used in this project. Please read this document in full \:D - -## Annotation conventions -### Annotation flavours -These are the main annotation flavours used by other Lua library definition projects: -1. LuaCATS: currently the most popular annotation flavour. Product of the [LuaLS project](https://luals.github.io/) -2. EmmyLua: renewed annotation flavour now fully supporting LuaCATS. Product of the [EmmyLua project](https://github.com/EmmyLuaLs/emmylua-analyzer-rust) - -For compatibility with both great projects, the subset of both is used which currently means that annotations are written in LuaCATS. In the future, this may change as EmmyLua development outpaces LuaLS. - -### `@class` and inheritance -LuaCATS' `@class` allows us to create plain table types, or perhaps better known in Luanti as *definition tables*. - -Next, inheritance refers to how these `@class` types can mix together into one. This is useful to split up fields and methods to reduce duplication. The following describes the conventions used in this library definition: - -- `*.__base`: Designates the main base type, usually acting as the sub-`@class` to a multitude of variant types. - -- `*.__partial`: Designates a sub-`@class` with extra fields and functions unique to a subset of variant types - -- `*.fmt`: Designates a sub-type in the format of that `` - - `tablefmt` is the most common sub-type format, followed by `stringfmt` - -### Field limitations -Many annotation keywords just don't work with fields, so it's placed inside the documentation text. - -```lua ---[[ -This is my field - -* @default `false` for players, `true` for entities -* @deprecated 5.12 Consider doing Y instead -* @see [lua_api.md > 'core' namespace reference > section](https://api.luanti.org/core-namespace-reference/#section) > `core.function` -]] ----@field my_field boolean? -``` - -Not supported: -- `@default` -- `@deprecated` -- `@see` - -### Aliases -LuaCATS' `@alias`se are used in many ways in this library definition. Any special values will be suggested by the language server, so it's useful from that perspective too. Common techniques are listed below: - -- Used to annotate [nominal types](#nominal-types). - -- Used to create non-table enums also known as special values. This is *very* common in Luanti API. Table enums annotated with `@enum` are very rare in comparison. Sometimes, it's actually a primitive type with handling for a few special values.\ - Sometimes indicated by `*.special` - -- Used to create table key enums. In absence of `keyof` like in typescript, this is implemented by the error-prone approach of just writing it like a non-table enum.\ - Sometimes indicated by `*.keys` - -### Nominal types -Some types derived from primitive types have no differences whatsoever in the annotation type system. In some cases however, it is useful to give these types names even if it's not possible to express its true restrictions and rules. We call these types *nominal types*\ - -To qualify as a *Nominal types*, it must have special restrictions, rules or contents that is not expressible through the annotation type system. This rule is to prevent flooding the library definition with too many useless verbose types. The following lists specifics about this rule: -- Built-in special values satisfies this rule. A different interpretation is that a nominal type is needed to suggest special values such as table keys or enums. - - e.g. Item names violates some subrules below. However, it has special values `"air"`, `"ignore"` and others. So, it is granted a `string` nominal type `core.Item.name`. -- Name syntax/specification does not satisfy this rule. - - e.g. LBM names (should) have a special syntax `:`. But, it isn't granted a `string` nominal type `core.LBMDef.name` -- General integer/number range limitations does not satisfy this rule. - - e.g. world units in nodes are limited to within [-31000,31000]. But, it isn't granted a `number` or `integer` nominal type `core.WorldUnit` - - e.g. Node params has special meanings and conversion rules, not just a [0,255] range. So, it is granted an `integer` nominal type `core.Param2` -- General units does not satisfy this rule. - - e.g. `ObjectRef` health does not use a unit, or could be interpreted as a very general unit used everywhere. So, it isn't granted an `integer` nominal type `core.ObjectRef.hp` - - e.g. Tool wear uses a unit unique to Luanti with some special rules in how to interpret it. So, it is granted an `integer` nominal type `core.Tool.wear` - -### Other conventions - -- Use `--[[ ... ]]` comment blocks to indicate the documentation text. - - Requirements below are loose, but consider using `@see` to defer information to the primary sources. - - It may be up to 32 lines long and at most 80 characters long, not including the brackets. - - Do not include examples in annotations if it is too long (>8 lines). Use `@see`\ - e.g. `core.LSystemTreeDef` has a 15 line example, thusly it is excluded. - -- Mark deprecated or discouraged practices with `@deprecated`.\ - e.g. using `minetest` namespace. - -- Implementation details can be intentionally opaque or hidden where useful.\ - e.g. the `number` handle returned by `core.sound_play(...)` is instead annotated as `core.SoundHandle`. - -- While it is *preferred* to maintain the primary sources text verbatim, it's usually too lengthy to be included as-is or would create a confusing amalgamation. This library definition *derives* from the primary sources, not simply copy it. - -- Naming conventions: - - All type names must be under the `core.*` namespace. The immediate name must be in `PascalCase` while the rest are in `snake_case`\ - e.g. `core.ParticleSpawner.tween.float_range` - - `vector` types are considered to be a "primitive" and are exempt. - - General purpose helper types are exempt. - - If a name is not explicitly provided in the primary sources, please derive a sensible name - -- Do not annotate implicit typecasting as valid practice.\ - e.g. (*Rejected*) `number` to `string` automatic casting for `MetaDataRef:set_string(...)` because it uses `luaL_checklstring(...)` - -- Do not discard useful return values by annotating `@nodiscard` - -- Do not annotate undocumented `builtin/*.lua` APIs. These APIs shouldn't be exposed in this project as it is out of scope. - - There's exceptions for common builtins spotted in (usually older) mods and games. It's expected that this would shrink as more internal symbols get documented in `lua_api.md` - -# Maintenance -## Update checklist -Every time the definition files are updated please check through this list: -1. [Check and test](#checking-and-testing) your modifications. -2. Run through the [`cspell` checker](#spell-checking). -3. Update the commit hash at the top of the `README.md`. -4. Is there a Luanti stable release update? grep for the last release version and update wherever necessary. - -## Checking and testing -After updating or adding more complicated symbols, you should test if your annotation appears correctly. Make a temporary Lua project outside of the library definition and play around with related symbols, you don't need to run it in Luanti. You may need to restart LuaLS as you modify annotations. - -Another way of checking whether your annotation is correct is to try it out with existing mods and games. This is a bit advanced since you're expected to know how to create your own `.luarc.json` file for that project if it doesn't have one (very common). Perhaps even make a custom definition file for that project due to meddling with engine APIs. - -## Looking up the implementation and use of a symbol -Sometimes, the primary sources does not really document the API very well leading to confusion, or that you felt that the primary sources missed something. You will need to search through Luanti's source code for mentions of that symbol. You may use `find`, `grep`, `fzf`, your built-in editor project-wide search, LSP symbols search, etc to ease the work. You'll become more familiar with the codebase as you do this more often, so don't get discouraged! - -**EXAMPLE** Let's say you vaguely remember seeing shaped craft recipes passed to `core.register_craft(recipe)` accepting `core.ItemStack`s. Here are some searches you could try to check its implementation: -- `^//.*register_craft` regex in C++ source code files -- `"registered_craft"` regex in C++ source code files -- `function.*register_craft` regex in Lua files under `builtin/*` -- `registered_craft` regex in Lua files under `builtin/*` -- Or any other more specific searches. Reading the code surrounding the results will lead you to a better understanding of the codebase. - -## Tracking new Luanti changes -For lazier maintenance, you can check Luanti's `doc` directory git history when tracking down new changes. You should also use the commit from that directory's git history when accounting for *last Luanti commit* instead of the repository as a whole. - -Sometimes, there could be API and implementation details outside of `doc` important to annotate. Feel free to defer that work to whoever spots that mistake. - -It's recommended that you get familiar with Git, or have tools to help you. - -## Spell Checking -For spell checking, [`cspell`](https://cspell.org/) is used. You are encouraged to set it up for your editor or use it as-is. - -- With npm, you can run it simply like so `npx cspell path/to/repo` -- For VSCode users, you can use [Code Spell Checker](https://marketplace.visualstudio.com/items?itemName=streetsidesoftware.code-spell-checker) -- For Neovim users, you can use [cspell.nvim](https://github.com/davidmh/cspell.nvim). It depend on null-ls/none-ls however. \ No newline at end of file diff --git a/types/luanti_lsp_definitions/README.md b/types/luanti_lsp_definitions/README.md deleted file mode 100644 index 0237a425..00000000 --- a/types/luanti_lsp_definitions/README.md +++ /dev/null @@ -1,135 +0,0 @@ -# Luanti LuaLS Definitions -- **Status:** DRAFT 2 WIP (see [this issue tracker](https://github.com/corpserot/luanti_lsp_definitions/issues/6)) -- **Luanti commit coverage:** `421835a3` (`5.14.X`) -- **Target projects when testing:** - - [Minetest Game (MTG)](https://github.com/luanti-org/minetest_game) commit `0ebe46e4`\ - With a custom LuaLS config (To be published). -- **Scheduled breaking changes**: Anytime, still in development. - - -# Why to use -This enables a lua language server to operate with Luanti APIs and types. This in turn allows for IDE-like capabilities including but not limited to: -- Typed annotation system called LuaCATS a la JSDoc annotations. Has definition files like Typescript `.d.ts` files. -- Diagnostics through semantic analysis, replacing [luacheck](https://github.com/mpeterv/luacheck) completely -- Autocompletion and hover information for API symbols, types, fields and more. - -# How to use -- Install [Lua Language Server, LuaLS](https://luals.github.io/) or [EmmyLua](https://github.com/EmmyLuaLs/emmylua-analyzer-rust) for your favourite text editor. Make sure it works first! ^v^ - - For VSCode users, you get first-class support with extra features enabled. So, please visit relevant first-party guides. - - For Neovim users, you have many ways to configure your language server. As of 2025-08-25 there isn't any (easy and simple) setup that interactively asks you whether to enable an addon for a workspace/project. -- Manual setup for single library definitions (Recommended for one-off uses): - - Git clone this repository. - - In your personal project config, add entries below. Optionally, manually inject whatever is inside `config.json` > `"settings"` into your LuaLS config. That entry contains recommended settings for Luanti game and mod development. - ```json - { - "workspace.library": ["/path/to/luanti-lsp-definitions/library"], - // e.g. selecting this specifically from "settings.Lua" entry in config.json: - "diagnostics.disable": [ - "lowercase-global" - ], - } - ``` -- Manual setup for collection of library definitions (Recommended for multiple library definition uses): - - Git clone this repository into this file structure: `luals_addons/luanti-lsp-definitions`. This allows you to add more addons under the same directory, e.g. `luals_addons/busted` for the testing suite. - - in your config, add entries below. The `Apply` value allows the LSP to read library definitions without asking, provided you matched the criteria to enable it. - ```json - { - "workspace.checkThirdParty": "Apply", - "workspace.userThirdParty": ["/path/to/luals_addons"] - } - ``` -- Automatic setup: WIP as this project is still in development. - -## Using this as a Luanti game/mod developer -After following the above instructions, in the context of annotations, you are left with two types of dependencies for your game/mod: Annotated dependencies and Un-annotated dependencies - -- *Annotated dependencies* and *Un-annotated dependencies* as-is: - - Game developers simply just include them in their project without any further additions. - - - Mod developers should put them inside a `.gitignore`d directory where you can safely fetch/clone your dependencies without distributing them. `.git/info/exclude` is an alternative choice. - - - You may notice errors due to how language server configurations are applied project-wide instead of scoped to the dependencies. Unfortunately, this approach means that you need to apply the same project-wide diagnostics configuration. - - Please do not rely on setting project-wide diagnostics in your game/mod. Instead use file-scoped or line diagnostics directives.\ - e.g `---@diagnostic disable-next-line: lowercase-global` - -- *Un-annotated dependencies* and you wish to annotate it: - - There's two ways of approaching this: - 1. (*Simple, recommended*) Annotate the dependency's code. - 2. (*Complicated, niche needs*) Annotate a separate library definition. This is the approach used by this Luanti library definition. - - There are benefits to either or both approaches, however the usual approach is to annotate the dependency's code. - - -### Namespace reservation -If you use this library definition, you acknowledge that it reserves the following type namespaces -- `_.*` -- `core.*` -- `corelib.*` -- vector "primitive" types. - -Helper types are listed below. More may be added. -- `OneOrMany` -- `SparseList` - -It's recommended that you own annotations sit inside a namespace i.e. `.MyType` - -# File Structure -- `.luarc.json` is the default LuaLS project configuration. You're expected to override it with your editor's personal project configuration. -- (NYI) `.emmyrc.json` is the default EmmyLua project configuration. You're expected to override it with your editor's personal project configuration. -- `config.json` is this library definition's configuration file. The `"settings"` portion should be minimal to encourage the developer to decide their own language server configurations. -- `MAINTAINENCE.md` is the guide for maintaining this project. Please read it if you would like to contribute. -- `library/` has definition files related to engine API. There is a short description at the top of each file. The contents are arranged following `lua_api.md` - - `library/classes/` has definition files related to classes. - - `library/core/` has definition files related to the `core` namespace. - - `library/vector` has definition files related to vectors - - `library/defs/` has definition files catching the rest of the `lua_api.md` contents. - -# Questions and Answers -## If i use this, do i have to use a LGPL-compliant license for my game/mod? -***Disclaimer: I am not a lawyer, and nothing in this material should be taken as legal advice. It may even be inaccurate. No attorney–client relationship is created by your use of this information provided for informative purposes. You should not act or rely on any information provided here without seeking the advice of a qualified attorney licensed in your jurisdiction. I disclaim all liability for actions you take or fail to take based on any content provided.*** - -You may skip this if you're well-informed about copyleft software licenses. - -The answer is probably not... well, it depends. You can embed or use this library definition alongside your game/mod. However, please don't copy-paste contents of this library definition straight into your code. Particularly, the documentation text itself has to be treated a bit more carefully. - -**Example:** Person A wrote a mod with a permissive license like MIT or 0BSD. If person A carelessly include content of this library definition into the mod's `init.lua`, then a portion of that file is at risk of being subjected to LGPL terms due to documentation text. - -If you would like to modify or derive contents of this library definition, it's recommended to treat your derived work like a separate module from your game/mod. It could be simply a separate directory or file. - -**Example:** Person A, being careful this time, copy-pastes parts of this library definition into a separate definition file `.defs.lua`. This would help isolate where LGPL terms apply. - -## How do i extend types? -You can extend existing classes like so: -```lua ----@class core.ItemDef ----@field _mymod_rarity integer - ---- Sometimes, you'll have to work with internal classes ----@class _.ObjectProperties.__base ----@field _mymod_power integer -``` - -However, it's expected that you need delve into this project's definitions as you're likely to extend the wrong type or an alias (cannot be extended using this technique). - -Be on the lookout for scheduled breaking changes. - -## I think this primitive type should get a name, like how `core.Formspec` is just a `string`! -Please open an issue for discusssion. In particular, you're encouraged to read about [*Nominal types*](https://github.com/corpserot/luanti_lsp_definitions/blob/master/MAINTENANCE.md#nominal-types) to help you justify why it should get a name. You should also search in this repo's issues if it's already discussed or not. - -## Why not contribute to [`luanti-lls-definitions by @fgaz`](https://codeberg.org/fgaz/luanti-lls-definitions)? -For context, that is the existing solution before this library definition was conceived. - -(by @frog) So i tried to use luanti-lls-definitions but those were really incomplete, and i didn't feel like contributing back to them\ -And i felt like it would be easier to start from scratch than to attempt to complete them. - -(by @corpserot) Well, there's a couple of reasons: -1. first and foremost that project uses an unreliable method to extract information from `lua_api.md` using TCL (seriously??) -2. @fgaz is very inactive in updating the definition files (check commits since project inception). It's very incomplete. -3. It uses EUPL license, which overcomplicates matters as it resembles closer to AGPLv3.0 than LGPLv2.1. Yet, it won't deter people that are already set on violating FOSS licenses. We don't use any definitions from that project, obviously. -4. I don't think @fgaz actually uses the definitions themself (dogfooding). - -## Why not contribute to [luanti-api by @archie](https://git.minetest.land/archie/luanti-api/)? -See this issue: [luanti-api#21](https://git.minetest.land/archie/luanti-api/issues/21) \ No newline at end of file diff --git a/types/luanti_lsp_definitions/config.json b/types/luanti_lsp_definitions/config.json deleted file mode 100644 index 56b58a91..00000000 --- a/types/luanti_lsp_definitions/config.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "$schema": "https://raw.githubusercontent.com/LuaLS/LLS-Addons/main/schemas/addon_config.schema.json", - "words": [ - "luanti", - "minetest", - "formspec", - "luaentity", - "core%.get_current_modname", - "core%.get_modpath" - ], - "settings": { - "Lua" : { - "diagnostics.disable": [ - "lowercase-global" - ], - "diagnostics.severity": { - "duplicate-set-field": "Information!" - } - } - } -} \ No newline at end of file diff --git a/types/luanti_lsp_definitions/library/classes/AreaStore.lua b/types/luanti_lsp_definitions/library/classes/AreaStore.lua deleted file mode 100644 index f0b78549..00000000 --- a/types/luanti_lsp_definitions/library/classes/AreaStore.lua +++ /dev/null @@ -1,301 +0,0 @@ ----@meta _ --- DRAFT 1 DONE --- luanti/doc/lua_api.md: Class reference > `AreaStore` - ---[[ -WIPDOC -]] ----@class core.AreaStoreID : integer - --- ----------------------------- AreaStore.area ----------------------------- -- - ---[[ -WIPDOC -]] ----@class core.AreaStore.area.include_corners ---[[ -WIPDOC -]] ----@field min ivec ---[[ -WIPDOC -]] ----@field max ivec - - ---[[ -WIPDOC -]] ----@class core.AreaStore.area.include_data ---[[ -WIPDOC -]] ----@field data string - ---[[ -WIPDOC -]] ----@class core.AreaStore.area.include_all : core.AreaStore.area.include_corners, core.AreaStore.area.include_data - --- ------------------------- AreaStore.cache_params ------------------------- -- - ---[[ -WIPDOC -]] ----@class core.AreaStore.cache_params ---[[ -WIPDOC -]] ----@field enabled boolean? ---[[ -WIPDOC -]] ----@field block_radius integer? ---[[ -WIPDOC -]] ----@field limit integer? - --- ------------------------------- constructor ------------------------------ -- - ---[[ -Unofficial note: I am aware that "Luanti" isn't a valid AreaStore type, but that makes it default to Luanti functions so, is it not accurate? -* `AreaStore(type_name)` - * Returns a new AreaStore instance - * `type_name`: optional, forces the internally used API. - * Possible values: `"LibSpatial"` (default). - * When other values are specified, or SpatialIndex is not available, - the custom Luanti functions are used. -]] ----@nodiscard ----@param type "LibSpatial"|string? ----@return core.AreaStore -function AreaStore(type) end - --- -------------------------------- AreaStore ------------------------------- -- - ---[[ -`AreaStore` ------------ - -AreaStore is a data structure to calculate intersections of 3D cuboid volumes -and points. The `data` field (string) may be used to store and retrieve any -mod-relevant information to the specified area. - -Despite its name, mods must take care of persisting AreaStore data. They may -use the provided load and write functions for this. - -]] ----@class core.AreaStore -AreaStore = {} - ---[[ -WIPDOC -]] ----@nodiscard ----@param id core.AreaStoreID ----@param include_corners false? ----@param include_data false? ----@return true? -function AreaStore:get_area(id, include_corners, include_data) end - ---[[ -WIPDOC -]] ----@nodiscard ----@param id core.AreaStoreID ----@param include_corners true ----@param include_data false? ----@return core.AreaStore.area.include_corners? -function AreaStore:get_area(id, include_corners, include_data) end - ---[[ -WIPDOC -]] ----@nodiscard ----@param id core.AreaStoreID ----@param include_corners false? ----@param include_data true ----@return core.AreaStore.area.include_data? -function AreaStore:get_area(id, include_corners, include_data) end - ---[[ -WIPDOC -]] ----@nodiscard ----@param id core.AreaStoreID ----@param include_corners true ----@param include_data true ----@return core.AreaStore.area.include_all? -function AreaStore:get_area(id, include_corners, include_data) end - ---[[ -WIPDOC -]] ----@nodiscard ----@param id core.AreaStoreID ----@param include_corners false? ----@param include_data false? ----@return table -function AreaStore:get_areas_for_pos(id, include_corners, include_data) end - ---[[ -WIPDOC -]] ----@nodiscard ----@param id core.AreaStoreID ----@param include_corners true ----@param include_data false? ----@return table -function AreaStore:get_areas_for_pos(id, include_corners, include_data) end - ---[[ -WIPDOC -]] ----@nodiscard ----@param id core.AreaStoreID ----@param include_corners false? ----@param include_data true ----@return table -function AreaStore:get_areas_for_pos(id, include_corners, include_data) end - ---[[ -WIPDOC -]] ----@nodiscard ----@param id core.AreaStoreID ----@param include_corners true ----@param include_data true ----@return table -function AreaStore:get_areas_for_pos(id, include_corners, include_data) end - ---[[ -WIPDOC -]] ----@nodiscard ----@param pos1 ivector ----@param pos2 ivector ----@param accept_overlap boolean ----@param include_corners false? ----@param include_data false? ----@return table -function AreaStore:get_areas_in_area(pos1, pos2, accept_overlap, include_corners, include_data) end - ---[[ -WIPDOC -]] ----@nodiscard ----@param pos1 ivector ----@param pos2 ivector ----@param accept_overlap boolean ----@param include_corners true ----@param include_data false? ----@return table -function AreaStore:get_areas_in_area(pos1, pos2, accept_overlap, include_corners, include_data) end - ---[[ -WIPDOC -]] ----@nodiscard ----@param pos1 ivector ----@param pos2 ivector ----@param accept_overlap boolean ----@param include_corners false? ----@param include_data true ----@return table -function AreaStore:get_areas_in_area(pos1, pos2, accept_overlap, include_corners, include_data) end - ---[[ -WIPDOC -]] ----@nodiscard ----@param pos1 ivector ----@param pos2 ivector ----@param accept_overlap boolean ----@param include_corners true ----@param include_data true ----@return table -function AreaStore:get_areas_in_area(pos1, pos2, accept_overlap, include_corners, include_data) end - ---[[ -* `insert_area(corner1, corner2, data, [id])`: inserts an area into the store. - * Returns the new area's ID, or nil if the insertion failed. - * The (inclusive) positions `corner1` and `corner2` describe the area. - * `data` is a string stored with the area. - * `id` (optional): will be used as the internal area ID if it is a unique - number between 0 and 2^32-2. -]] ----@nodiscard ----@param corner1 ivector ----@param corner2 ivector ----@param data string ----@param id core.AreaStoreID? ----@return core.AreaStoreID? -function AreaStore:insert_area(corner1, corner2, data, id) end - ---[[ -* `reserve(count)` - * Requires SpatialIndex, no-op function otherwise. - * Reserves resources for `count` many contained areas to improve - efficiency when working with many area entries. Additional areas can still - be inserted afterwards at the usual complexity. -]] ----@param count integer -function AreaStore:reserve(count) end - ---[[ -* `remove_area(id)`: removes the area with the given id from the store, returns - success. -]] ----@nodiscard ----@param id core.AreaStoreID ----@return boolean -function AreaStore:remove_area(id) end - ---[[ -* `set_cache_params(params)`: sets params for the included prefiltering cache. - Calling invalidates the cache, so that its elements have to be newly - generated. - * `params` is a table with the following fields: - ```lua - { - enabled = boolean, -- Whether to enable, default true - block_radius = int, -- The radius (in nodes) of the areas the cache - -- generates prefiltered lists for, minimum 16, - -- default 64 - limit = int, -- The cache size, minimum 20, default 1000 - } - ``` -]] ----@param params core.AreaStore.cache_params -function AreaStore:set_cache_params(params) end - ---[[ -* `to_string()`: Experimental. Returns area store serialized as a (binary) - string. -]] ----@nodiscard ----@return string -function AreaStore:to_string() end - ---[[ -* `to_file(filename)`: Experimental. Like `to_string()`, but writes the data to - a file. -]] ----@param filename core.Path -function AreaStore:to_file(filename) end - ---[[ -* `from_string(str)`: Experimental. Deserializes string and loads it into the - AreaStore. - Returns success and, optionally, an error message. -]] ----@param str string -function AreaStore:from_string(str) end - ---[[ -* `from_file(filename)`: Experimental. Like `from_string()`, but reads the data - from a file. -]] ----@param filename core.Path -function AreaStore:from_file(filename) end \ No newline at end of file diff --git a/types/luanti_lsp_definitions/library/classes/AsyncJob.lua b/types/luanti_lsp_definitions/library/classes/AsyncJob.lua deleted file mode 100644 index bb0f919b..00000000 --- a/types/luanti_lsp_definitions/library/classes/AsyncJob.lua +++ /dev/null @@ -1,16 +0,0 @@ ----@meta _ --- DRAFT 1 DONE --- luanti/doc/lua_api.md: Class reference > `AsyncJob` - ---[[ -WIPDOC -]] ----@class core.AsyncJob -local AsyncJob = {} - ---[[ -WIPDOC -]] ----@nodiscard ----@return boolean -function AsyncJob:cancel() end \ No newline at end of file diff --git a/types/luanti_lsp_definitions/library/classes/InvRef.lua b/types/luanti_lsp_definitions/library/classes/InvRef.lua deleted file mode 100644 index 6998692f..00000000 --- a/types/luanti_lsp_definitions/library/classes/InvRef.lua +++ /dev/null @@ -1,156 +0,0 @@ ----@meta _ --- DRAFT 1 DONE --- luanti/doc/lua_api.md: Class reference > `InvRef` - ---[[ -WIPDOC -]] ----@class core.InvRef -local InvRef = {} - ---[[ -* `is_empty(listname)`: return `true` if list is empty -]] ----@nodiscard ----@param listname core.InventoryList ----@return boolean -function InvRef:is_empty(listname) end - ---[[ -* `get_size(listname)`: get size of a list -]] ----@nodiscard ----@param listname core.InventoryList ----@return integer size -function InvRef:get_size(listname) end - ---[[ -* `set_size(listname, size)`: set size of a list - * If `listname` is not known, a new list will be created - * Setting `size` to 0 deletes a list - * returns `false` on error (e.g. invalid `listname` or `size` -]] ----@nodiscard ----@param listname core.InventoryList ----@param size integer ----@return boolean -function InvRef:set_size(listname, size) end - ---[[ -* `get_width(listname)`: get width of a list -]] ----@nodiscard ----@param listname core.InventoryList ----@return integer width -function InvRef:get_width(listname) end - ---[[ -* `set_width(listname, width)`: set width of list; currently used for crafting - * returns `false` on error (e.g. invalid `listname` or `width` -]] ----@nodiscard ----@param listname core.InventoryList ----@param width integer -function InvRef:set_width(listname, width) end - ---[[ -* `get_stack(listname, i)`: get a copy of stack index `i` in list -]] ----@nodiscard ----@param listname core.InventoryList ----@param i integer ----@return core.ItemStack stack -function InvRef:get_stack(listname, i) end - ---[[ -* `set_stack(listname, i, stack)`: copy `stack` to index `i` in list -]] ----@param listname core.InventoryList ----@param i integer ----@param stack core.ItemStack -function InvRef:set_stack(listname, i, stack) end - ---[[ -* `get_list(listname)`: returns full list (list of `ItemStack`s - or `nil` if list doesn't exist (size 0 -]] ----@nodiscard ----@param listname core.InventoryList ----@return core.ItemList list -function InvRef:get_list(listname) end - ---[[ -* `set_list(listname, list)`: set full list (size will not change -]] ----@param listname core.InventoryList ----@param list core.ItemList -function InvRef:set_list(listname, list) end - ---[[ -* `get_lists()`: returns table that maps listnames to inventory lists -]] ----@nodiscard ----@return core.InventoryTable lists -function InvRef:get_lists() end - ---[[ -* `set_lists(lists)`: sets inventory lists (size will not change -]] ----@param lists core.InventoryTable -function InvRef:set_lists(lists) end - ---[[ -* `add_item(listname, stack)`: add item somewhere in list, returns leftover - `ItemStack`. -]] ----@param listname core.InventoryList ----@param stack core.Item -function InvRef:add_item(listname, stack) end - ---[[ -* `room_for_item(listname, stack):` returns `true` if the stack of items - can be fully added to the list -]] ----@nodiscard ----@param listname core.InventoryList ----@param stack core.Item ----@return boolean -function InvRef:room_for_item(listname, stack) end - ---[[ -* `contains_item(listname, stack, [match_meta])`: returns `true` if - the stack of items can be fully taken from the list. - * If `match_meta` is `true`, item metadata is also considered when comparing - items. Otherwise, only the items names are compared. Default: `false` - * The method ignores wear. -]] ----@nodiscard ----@param listname core.InventoryList ----@param stack core.Item ----@param match_meta boolean? ----@return boolean -function InvRef:contains_item(listname, stack, match_meta) end - ---[[ -* `remove_item(listname, stack, [match_meta])`: take as many items as specified from the - list, returns the items that were actually removed (as an `ItemStack`). - * If `match_meta` is `true` (available since feature `remove_item_match_meta`), - item metadata is also considered when comparing items. Otherwise, only the - items names are compared. Default: `false` - * The method ignores wear. -]] ----@nodiscard ----@param listname core.InventoryList ----@param stack core.Item ----@param match_meta boolean? ----@return core.ItemStack -function InvRef:remove_item(listname, stack, match_meta) end - ---[[ -* `get_location()`: returns a location compatible to - `core.get_inventory(location)`. - * returns `{type="undefined"}` in case location is not known -]] ----@nodiscard ----@return core.InventoryLocation|core.InventoryLocation.undefined -function InvRef:get_location() end diff --git a/types/luanti_lsp_definitions/library/classes/ItemStack.lua b/types/luanti_lsp_definitions/library/classes/ItemStack.lua deleted file mode 100644 index 84718229..00000000 --- a/types/luanti_lsp_definitions/library/classes/ItemStack.lua +++ /dev/null @@ -1,268 +0,0 @@ ----@meta _ --- DRAFT 1 DONE --- luanti/doc/lua_api.md: Class reference > `ItemStack` - --- ------------------------------- constructor ------------------------------ -- - ---[[ -WIPDOC -]] ----@nodiscard ----@param any core.Item? ----@return core.ItemStack -function ItemStack(any) end - --- -------------------------------- ItemStack ------------------------------- -- - ---[[ -WIPDOC -]] ----@class core.ItemStack -local ItemStack = {} - ---[[ -* `is_empty()`: returns `true` if stack is empty. -]] ----@nodiscard ----@return boolean -function ItemStack:is_empty() end - ---[[ -* `get_name()`: returns item name (e.g. `"default:stone"`). -]] ----@nodiscard ----@return core.Item.name item_name -function ItemStack:get_name() end - ---[[ -* `set_name(item_name)`: returns a boolean indicating whether the item was - cleared. -]] ----@nodiscard ----@param item_name core.Item.name ----@return boolean -function ItemStack:set_name(item_name) end - ---[[ -* `get_count()`: Returns number of items on the stack. -]] ----@nodiscard ----@return integer count -function ItemStack:get_count() end - ---[[ -* `set_count(count)`: returns a boolean indicating whether the item was cleared - * `count`: number, unsigned 16 bit integer -]] ----@nodiscard ----@param count integer ----@return boolean -function ItemStack:set_count(count) end - ---[[ -* `get_wear()`: returns tool wear (`0`-`65535`), `0` for non-tools. -]] ----@nodiscard ----@return core.Tool.wear wear -function ItemStack:get_wear() end - ---[[ -* `set_wear(wear)`: returns boolean indicating whether item was cleared - * `wear`: number, unsigned 16 bit integer -]] ----@nodiscard ----@param wear core.Tool.wear ----@return boolean -function ItemStack:set_wear(wear) end - ---[[ -`get_meta()`: returns ItemStackMetaRef. See section for more details -]] ----@nodiscard ----@return core.ItemStackMetaRef -function ItemStack:get_meta() end - ---[[ -* `get_metadata()`: **Deprecated.** Returns metadata (a string attached to an item stack). - * If you need to access this to maintain backwards compatibility, - use `stack:get_meta():get_string("")` instead. -]] ----@deprecated ----@nodiscard ----@return string metadata -function ItemStack:get_metadata() end - ---[[ -* `set_metadata(metadata)`: **Deprecated.** Returns true. - * If you need to set this to maintain backwards compatibility, - use `stack:get_meta():set_string("", metadata)` instead. -]] ----@deprecated ----@param metadata string ----@return true -function ItemStack:set_metadata(metadata) end - ---[[ -* `get_description()`: returns the description shown in inventory list tooltips. - * The engine uses this when showing item descriptions in tooltips. - * Fields for finding the description, in order: - * `description` in item metadata (See [Item Metadata]. - * `description` in item definition - * item name -]] ----@nodiscard ----@return string -function ItemStack:get_description() end - ---[[ -* `get_short_description()`: returns the short description or nil. - * Unlike the description, this does not include new lines. - * Fields for finding the short description, in order: - * `short_description` in item metadata (See [Item Metadata]. - * `short_description` in item definition - * first line of the description (From item meta or def, see `get_description()`. - * Returns nil if none of the above are set -]] ----@nodiscard ----@return string? -function ItemStack:get_short_description() end - ---[[ -* `clear()`: removes all items from the stack, making it empty. -]] -function ItemStack:clear() end - ---[[ -* `replace(item)`: replace the contents of this stack. - * `item` can also be an itemstring or table. -]] ----@param item core.Item -function ItemStack:replace(item) end - ---[[ -* `to_string()`: returns the stack in itemstring form. -]] ----@nodiscard ----@return core.Item.stringfmt -function ItemStack:to_string() end - ---[[ -* `to_table()`: returns the stack in Lua table form. -]] ----@nodiscard ----@return core.Item.tablefmt -function ItemStack:to_table() end - ---[[ -* `get_stack_max()`: returns the maximum size of the stack (depends on the - item). -]] ----@nodiscard ----@return integer -function ItemStack:get_stack_max() end - ---[[ -* `get_free_space()`: returns `get_stack_max() - get_count()`. -]] ----@nodiscard ----@return integer -function ItemStack:get_free_space() end - ---[[ -* `is_known()`: returns `true` if the item name refers to a defined item type. -]] ----@nodiscard ----@return boolean -function ItemStack:is_known() end - ---[[ -* `get_definition()`: returns the item definition table. -]] ----@nodiscard ----@return core.ItemDef -function ItemStack:get_definition() end - ---[[ -* `get_tool_capabilities()`: returns the digging properties of the item, - or those of the hand if none are defined for this item type -]] ----@nodiscard ----@return core.ToolCapabilities -function ItemStack:get_tool_capabilities() end - ---[[ -* `add_wear(amount)` - * Increases wear by `amount` if the item is a tool, otherwise does nothing - * Valid `amount` range is [0,65536] - * `amount`: number, integer -]] ----@param amount core.Tool.wear -function ItemStack:add_wear(amount) end - ---[[ -* `add_wear_by_uses(max_uses)` - * Increases wear in such a way that, if only this function itself called, - the item breaks after `max_uses` times - * Valid `max_uses` range is [0,65536] - * Does nothing if item is not a tool or if `max_uses` is 0 -]] ----@param max_uses core.Tool.wear -function ItemStack:add_wear_by_uses(max_uses) end - ---[[ -* `get_wear_bar_params()`: returns the wear bar parameters of the item, - or nil if none are defined for this item type or in the stack's meta -]] ----@nodiscard ----@return core.WearBarColor? -function ItemStack:get_wear_bar_params() end - ---[[ -* `add_item(item)`: returns leftover `ItemStack` - * Put some item or stack onto this stack -]] ----@param item core.Item -function ItemStack:add_item(item) end - ---[[ -* `item_fits(item)`: returns `true` if item or stack can be fully added to - this one. -]] ----@nodiscard ----@param item core.Item ----@return boolean -function ItemStack:item_fits(item) end - ---[[ -* `take_item(n)`: returns taken `ItemStack` - * Take (and remove) up to `n` items from this stack - * `n`: number, default: `1` -]] ----@nodiscard ----@param n integer? ----@return core.ItemStack -function ItemStack:take_item(n) end - ---[[ -* `peek_item(n)`: returns taken `ItemStack` - * Copy (don't remove) up to `n` items from this stack - * `n`: number, default: `1` -]] ----@nodiscard ----@param n integer? ----@return core.ItemStack -function ItemStack:peek_item(n) end - ---[[ -* `equals(other)`: - * returns `true` if this stack is identical to `other`. - * Note: `stack1:to_string() == stack2:to_string()` is not reliable, - as stack metadata can be serialized in arbitrary order. - * Note: if `other` is an itemstring or table representation of an - ItemStack, this will always return false, even if it is - "equivalent". -]] ----@nodiscard ----@param other core.ItemStack ----@return boolean -function ItemStack:equals(other) end diff --git a/types/luanti_lsp_definitions/library/classes/ItemStackMetaRef.lua b/types/luanti_lsp_definitions/library/classes/ItemStackMetaRef.lua deleted file mode 100644 index eb3faf3d..00000000 --- a/types/luanti_lsp_definitions/library/classes/ItemStackMetaRef.lua +++ /dev/null @@ -1,113 +0,0 @@ ----@meta _ --- DRAFT 1 DONE --- luanti/doc/lua_api.md: Class reference > `ItemStackMetaRef` - --- NOTE: changes are linked to MetaDataRef, ItemStackMetaRef, NodeMetaRef, --- PlayerMetaRef and StorageRef - ---[[ -WIPDOC -]] ----@class core.ItemStackMetaRef: core.MetaDataRef -local ItemStackMetaRef = {} - ---[[ -* `contains(key)`: Returns true if key present, otherwise false. - * Returns `nil` when the MetaData is inexistent. -]] ----@nodiscard ----@param key core.MetadataTable.fields.item.keys ----@return boolean? -function ItemStackMetaRef:contains(key) end - ---[[ -* `get(key)`: Returns `nil` if key not present, else the stored string. -]] ----@nodiscard ----@param key core.MetadataTable.fields.item.keys ----@return string? value -function ItemStackMetaRef:get(key) end - ---[[ -* `set_string(key, value)`: Value of `""` will delete the key. -]] ----@param key core.MetadataTable.fields.item.keys ----@param value string -function ItemStackMetaRef:set_string(key, value) end - ---[[ -* `get_string(key)`: Returns `""` if key not present. -]] ----@nodiscard ----@param key core.MetadataTable.fields.item.keys ----@return string value -function ItemStackMetaRef:get_string(key) end - ---[[ -* `set_int(key, value)` - * The range for the value is system-dependent (usually 32 bits). - The value will be converted into a string when stored. -]] ----@param key core.MetadataTable.fields.item.keys.integer ----@param value integer -function ItemStackMetaRef:set_int(key, value) end - ---[[ -* `get_int(key)`: Returns `0` if key not present. -]] ----@nodiscard ----@param key core.MetadataTable.fields.item.keys.integer ----@return integer value -function ItemStackMetaRef:get_int(key) end - ---[[ -* `set_float(key, value)` - * Store a number (a 64-bit float) exactly. - * The value will be converted into a string when stored. -]] ----@param key core.MetadataTable.fields.item.keys.number ----@param value number -function ItemStackMetaRef:set_float(key, value) end - ---[[ -WIPDOC -]] ----@nodiscard ----@param key core.MetadataTable.fields.item.keys.number ----@return number value -function ItemStackMetaRef:get_float(key) end - ---[[ -WIPDOC -]] ----@nodiscard ----@return core.MetadataTable.fields.item.keys[] keys -function ItemStackMetaRef:get_keys() end - ---[[ -WIPDOC -]] ----@nodiscard ----@param data core.MetadataTable.item ----@return boolean? -function ItemStackMetaRef:from_table(data) end - ---[[ -WIPDOC -]] ----@nodiscard ----@return core.MetadataTable.item -function ItemStackMetaRef:to_table() end - - ---[[ -WIPDOC -]] ----@param tool_capabilities core.ToolCapabilities? -function ItemStackMetaRef:set_tool_capabilities(tool_capabilities) end - ---[[ -WIPDOC -]] ----@param wear_bar_params core.WearBarColor? -function ItemStackMetaRef:set_wear_bar_params(wear_bar_params) end diff --git a/types/luanti_lsp_definitions/library/classes/MetaDataRef.lua b/types/luanti_lsp_definitions/library/classes/MetaDataRef.lua deleted file mode 100644 index 46e4f2e8..00000000 --- a/types/luanti_lsp_definitions/library/classes/MetaDataRef.lua +++ /dev/null @@ -1,100 +0,0 @@ ----@meta _ --- DRAFT 1 DONE --- luanti/doc/lua_api.md: Class reference > `MetaDataRef` - --- NOTE: changes are linked to MetaDataRef, ItemStackMetaRef, NodeMetaRef, --- PlayerMetaRef and StorageRef - ---[[ -will return the value associated with key `k`. There is a low recursion limit. -]] ----@class core.MetaDataRef -local MetaDataRef = {} - ---[[ -* `contains(key)`: Returns true if key present, otherwise false. - * Returns `nil` when the MetaData is inexistent. -]] ----@nodiscard ----@param key core.MetadataTable.fields.keys ----@return boolean? -function MetaDataRef:contains(key) end - ---[[ -* `get(key)`: Returns `nil` if key not present, else the stored string. -]] ----@nodiscard ----@param key core.MetadataTable.fields.keys ----@return string? value -function MetaDataRef:get(key) end - ---[[ -* `set_string(key, value)`: Value of `""` will delete the key. -]] ----@param key core.MetadataTable.fields.keys ----@param value string -function MetaDataRef:set_string(key, value) end - ---[[ -* `get_string(key)`: Returns `""` if key not present. -]] ----@nodiscard ----@param key core.MetadataTable.fields.keys ----@return string value -function MetaDataRef:get_string(key) end - ---[[ -* `set_int(key, value)` - * The range for the value is system-dependent (usually 32 bits). - The value will be converted into a string when stored. -]] ----@param key core.MetadataTable.fields.keys.integer ----@param value integer -function MetaDataRef:set_int(key, value) end - ---[[ -* `get_int(key)`: Returns `0` if key not present. -]] ----@nodiscard ----@param key core.MetadataTable.fields.keys.integer ----@return integer value -function MetaDataRef:get_int(key) end - ---[[ -* `set_float(key, value)` - * Store a number (a 64-bit float) exactly. - * The value will be converted into a string when stored. -]] ----@param key core.MetadataTable.fields.keys.number ----@param value number -function MetaDataRef:set_float(key, value) end - ---[[ -WIPDOC -]] ----@nodiscard ----@param key core.MetadataTable.fields.keys.number ----@return number value -function MetaDataRef:get_float(key) end - ---[[ -WIPDOC -]] ----@nodiscard ----@return core.MetadataTable.fields.keys[] keys -function MetaDataRef:get_keys() end - ---[[ -WIPDOC -]] ----@nodiscard ----@param data core.MetadataTable.set ----@return boolean? -function MetaDataRef:from_table(data) end - ---[[ -WIPDOC -]] ----@nodiscard ----@return core.MetadataTable.get -function MetaDataRef:to_table() end diff --git a/types/luanti_lsp_definitions/library/classes/ModChannel.lua b/types/luanti_lsp_definitions/library/classes/ModChannel.lua deleted file mode 100644 index a3835769..00000000 --- a/types/luanti_lsp_definitions/library/classes/ModChannel.lua +++ /dev/null @@ -1,35 +0,0 @@ ----@meta _ --- DRAFT 1 DONE --- luanti/doc/lua_api.md: Class reference > `ModChannel` - ---[[ -WIPDOC -]] ----@class core.ModChannel -local ModChannel = {} - ---[[ -* `leave()`: leave the mod channel. - * Server leaves channel `channel_name`. - * No more incoming or outgoing messages can be sent to this channel from - server mods. - * This invalidate all future object usage. - * Ensure you set ModChannel to nil after that to free Lua resources. -]] -function ModChannel:leave() end - ---[[ -* `is_writeable()`: returns true if channel is writeable and mod can send over - it. -]] ----@nodiscard ----@return boolean -function ModChannel:is_writeable() end - ---[[ -* `send_all(message)`: Send `message` though the mod channel. - * If mod channel is not writeable or invalid, message will be dropped. - * Message size is limited to 65535 characters by protocol. -]] ----@param message string -function ModChannel:send_all(message) end diff --git a/types/luanti_lsp_definitions/library/classes/NodeMetaRef.lua b/types/luanti_lsp_definitions/library/classes/NodeMetaRef.lua deleted file mode 100644 index 234751db..00000000 --- a/types/luanti_lsp_definitions/library/classes/NodeMetaRef.lua +++ /dev/null @@ -1,118 +0,0 @@ ----@meta _ --- DRAFT 1 DONE --- luanti/doc/lua_api.md: Class reference > `NodeMetaRef` - --- NOTE: changes are linked to MetaDataRef, ItemStackMetaRef, NodeMetaRef, --- PlayerMetaRef and StorageRef - ---[[ -WIPDOC -]] ----@class core.NodeMetaRef : core.MetaDataRef -local NodeMetaRef = {} - ---[[ -* `contains(key)`: Returns true if key present, otherwise false. - * Returns `nil` when the MetaData is inexistent. -]] ----@nodiscard ----@param key core.MetadataTable.fields.node.keys ----@return boolean? -function NodeMetaRef:contains(key) end - ---[[ -* `get(key)`: Returns `nil` if key not present, else the stored string. -]] ----@nodiscard ----@param key core.MetadataTable.fields.node.keys ----@return string? value -function NodeMetaRef:get(key) end - ---[[ -* `set_string(key, value)`: Value of `""` will delete the key. -]] ----@param key core.MetadataTable.fields.node.keys ----@param value string -function NodeMetaRef:set_string(key, value) end - ---[[ -* `get_string(key)`: Returns `""` if key not present. -]] ----@nodiscard ----@param key core.MetadataTable.fields.node.keys ----@return string value -function NodeMetaRef:get_string(key) end - ---[[ -* `set_int(key, value)` - * The range for the value is system-dependent (usually 32 bits). - The value will be converted into a string when stored. -]] ----@param key core.MetadataTable.fields.node.keys.integer ----@param value integer -function NodeMetaRef:set_int(key, value) end - ---[[ -* `get_int(key)`: Returns `0` if key not present. -]] ----@nodiscard ----@param key core.MetadataTable.fields.node.keys.integer ----@return integer value -function NodeMetaRef:get_int(key) end - ---[[ -* `set_float(key, value)` - * Store a number (a 64-bit float) exactly. - * The value will be converted into a string when stored. -]] ----@param key core.MetadataTable.fields.node.keys.number ----@param value number -function NodeMetaRef:set_float(key, value) end - ---[[ -WIPDOC -]] ----@nodiscard ----@param key core.MetadataTable.fields.node.keys.number ----@return number value -function NodeMetaRef:get_float(key) end - ---[[ -WIPDOC -]] ----@nodiscard ----@return core.MetadataTable.fields.node.keys[] keys -function NodeMetaRef:get_keys() end - ---[[ -WIPDOC -]] ----@nodiscard ----@param data core.MetadataTable.node.set ----@return boolean? -function NodeMetaRef:from_table(data) end - ---[[ -WIPDOC -]] ----@nodiscard ----@return core.MetadataTable.node.get -function NodeMetaRef:to_table() end - - ---[[ -WIPDOC -]] ----@nodiscard ----@return core.InvRef -function NodeMetaRef:get_inventory() end - ---[[ -* `mark_as_private(name or {name1, name2, ...})`: Mark specific vars as private - This will prevent them from being sent to the client. Note that the "private" - status will only be remembered if an associated key-value pair exists, - meaning it's best to call this when initializing all other meta (e.g. - `on_construct`). -]] ----@param fields OneOrMany -function NodeMetaRef:mark_as_private(fields) end diff --git a/types/luanti_lsp_definitions/library/classes/NodeTimer.lua b/types/luanti_lsp_definitions/library/classes/NodeTimer.lua deleted file mode 100644 index 82d41410..00000000 --- a/types/luanti_lsp_definitions/library/classes/NodeTimer.lua +++ /dev/null @@ -1,53 +0,0 @@ ----@meta _ --- DRAFT 1 DONE --- luanti/doc/lua_api.md: Class reference > `NodeTimerRef` - ---[[ -WIPDOC -]] ----@class core.NodeTimerRef -local NodeTimerRef = {} - ---[[ -* `set(timeout,elapsed)` - * set a timer's state - * `timeout` is in seconds, and supports fractional values (0.1 etc) - * `elapsed` is in seconds, and supports fractional values (0.1 etc) - * will trigger the node's `on_timer` function after `(timeout - elapsed)` - seconds. -]] ----@param timeout number ----@param elapsed number -function NodeTimerRef:set(timeout, elapsed) end - ---[[ -WIPDOC -]] ----@param timeout number -function NodeTimerRef:start(timeout) end - ---[[ -WIPDOC -]] -function NodeTimerRef:stop() end - ---[[ -WIPDOC -]] ----@nodiscard ----@return number -function NodeTimerRef:get_timeout() end - ---[[ -WIPDOC -]] ----@nodiscard ----@return number -function NodeTimerRef:get_elapsed() end - ---[[ -WIPDOC -]] ----@nodiscard ----@return boolean -function NodeTimerRef:is_started() end \ No newline at end of file diff --git a/types/luanti_lsp_definitions/library/classes/ObjectRef/EntityRef.lua b/types/luanti_lsp_definitions/library/classes/ObjectRef/EntityRef.lua deleted file mode 100644 index 40944d93..00000000 --- a/types/luanti_lsp_definitions/library/classes/ObjectRef/EntityRef.lua +++ /dev/null @@ -1,176 +0,0 @@ ----@meta _ --- DRAFT 1 DONE --- luanti/doc/lua_api.md: Class reference > `ObjectRef` - ---[[ -WIPDOC -]] ----@class core.EntityRef : _.ObjectRef.__base -local EntityRef = {} - --- ----------------------------- entity lifetime ---------------------------- -- - ---[[ -* `remove()`: remove object - * The object is removed after returning from Lua. However the `ObjectRef` - itself instantly becomes unusable with all further method calls having - no effect and returning `nil`. -]] -function EntityRef:remove() end - --- ---------------------- entity position and movement ---------------------- -- - ---[[ -* `set_velocity(vel)` - * Sets the velocity - * `vel` is a vector, e.g. `{x=0.0, y=2.3, z=1.0}` -]] ----@param vel vector -function EntityRef:set_velocity(vel) end - ---[[ -* `set_acceleration(acc)` - * Sets the acceleration - * `acc` is a vector -]] ----@param acc vector -function EntityRef:set_acceleration(acc) end - ---[[ -* `get_acceleration()`: returns the acceleration, a vector -]] ----@nodiscard ----@return vec? acc -function EntityRef:get_acceleration() end - --- --------------------- entity rotation and orientation -------------------- -- - ---[[ -* `set_rotation(rot)` - * Sets the rotation - * `rot` is a vector (radians). X is pitch (elevation), Y is yaw (heading - and Z is roll (bank). - * Does not reset rotation incurred through `automatic_rotate`. - Remove & re-add your objects to force a certain rotation. -]] ----@param rot vector -function EntityRef:set_rotation(rot) end - ---[[ -* `get_rotation()`: returns the rotation, a vector (radians) -]] ----@nodiscard ----@return vec? rot -function EntityRef:get_rotation() end - ---[[ -* `set_yaw(yaw)`: sets the yaw in radians (heading). -]] ----@param yaw number -function EntityRef:set_yaw(yaw) end - ---[[ -* `get_yaw()`: returns number in radians -]] ----@nodiscard ----@return number yaw -function EntityRef:get_yaw() end - --- ----------------------------- entity texture ----------------------------- -- - ---[[ -* `set_texture_mod(mod)` - * Set a texture modifier to the base texture, for sprites and meshes. - * When calling `set_texture_mod` again, the previous one is discarded. - * `mod` the texture modifier. See [Texture modifiers]. -]] ----@param mod core.Texture -function EntityRef:set_texture_mod(mod) end - ---[[ -* `get_texture_mod()` returns current texture modifier -]] ----@nodiscard ----@return core.Texture? mod -function EntityRef:get_texture_mod() end - ---[[ -WIPDOC -]] ----@class core.EntityRef.select_x_by_camera.strict ---[[ -WIPDOC -]] ----@field [1] integer ---[[ -WIPDOC -]] ----@field [2] integer ---[[ -WIPDOC -]] ----@field [3] integer ---[[ -WIPDOC -]] ----@field [4] integer ---[[ -WIPDOC -]] ----@field [5] integer ---[[ -WIPDOC -]] ----@field [6] integer - ---[[ -WIPDOC -]] ----@alias core.EntityRef.select_x_by_camera ---- | core.EntityRef.select_x_by_camera.strict ---- | string[] - ---[[ -* `set_sprite(start_frame, num_frames, framelength, select_x_by_camera)` - * Specifies and starts a sprite animation - * Only used by `sprite` and `upright_sprite` visuals - * Animations iterate along the frame `y` position. - * `start_frame`: {x=column number, y=row number}, the coordinate of the - first frame, default: `{x=0, y=0}` - * `num_frames`: Total frames in the texture, default: `1` - * `framelength`: Time per animated frame in seconds, default: `0.2` - * `select_x_by_camera`: Only for visual = `sprite`. Changes the frame `x` - position according to the view direction. default: `false`. - * First column: subject facing the camera - * Second column: subject looking to the left - * Third column: subject backing the camera - * Fourth column: subject looking to the right - * Fifth column: subject viewed from above - * Sixth column: subject viewed from below -]] ----@param start_frame vec2.xy? ----@param num_frames integer? ----@param framelength number? ----@param select_x_by_camera core.EntityRef.select_x_by_camera|boolean? -function EntityRef:set_sprite(start_frame, num_frames, framelength, select_x_by_camera) end - --- ------------------------------- entity misc ------------------------------ -- - ---[[ -* `get_luaentity()`: - * Returns the object's associated luaentity table, if there is one - * Otherwise returns `nil` (e.g. for players -]] ----@nodiscard ----@return core.Entity -function EntityRef:get_luaentity() end - ---[[ -* `get_entity_name()`: - * **Deprecated**: Will be removed in a future version, - use `:get_luaentity().name` instead. -]] ----@nodiscard ----@deprecated ----@return core.Entity.name -function EntityRef:get_entity_name() end diff --git a/types/luanti_lsp_definitions/library/classes/ObjectRef/ObjectRef.lua b/types/luanti_lsp_definitions/library/classes/ObjectRef/ObjectRef.lua deleted file mode 100644 index c773841d..00000000 --- a/types/luanti_lsp_definitions/library/classes/ObjectRef/ObjectRef.lua +++ /dev/null @@ -1,373 +0,0 @@ ----@meta _ --- DRAFT 1 DONE --- luanti/doc/lua_api.md: Class reference > `ObjectRef` - --- INTERPRETATION: EntityRef does not override ObjectRef, merely supplies --- ObjectRef with exclusive entity methods. This is because of the relationship --- where PlayerRef overrides ObjectRef's methods. This is seen in how some --- ObjectRef methods assumes it's an entity and not a player. - ---[[ -WIPDOC -]] ----@class _.ObjectRef.__base -local ObjectRefBase = {} - ---[[ -WIPDOC -]] ----@alias core.ObjectRef ---- | core.PlayerRef ---- | core.EntityRef - --- -------------------------------- is valid -------------------------------- -- - ---[[ -* `is_valid()`: returns whether the object is valid. -]] ----@nodiscard ----@return boolean -function ObjectRefBase:is_valid() end - --- -------------------------- position and movement ------------------------- -- - ---[[ -* `get_pos()`: returns position as vector `{x=num, y=num, z=num}` -]] ----@nodiscard ----@return vec pos -function ObjectRefBase:get_pos() end - ---[[ -* `set_pos(pos)`: - * Sets the position of the object. - * No-op if object is attached. - * `pos` is a vector `{x=num, y=num, z=num}` -]] ----@param pos vector -function ObjectRefBase:set_pos(pos) end - ---[[ -* `add_pos(pos)`: - * Changes position by adding to the current position. - * No-op if object is attached. - * `pos` is a vector `{x=num, y=num, z=num}`. - * In comparison to using `set_pos`, `add_pos` will avoid synchronization problems. -]] ----@param pos vector -function ObjectRefBase:add_pos(pos) end - ---[[ -* `get_velocity()`: returns the velocity, a vector. -]] ----@nodiscard ----@return vec vel -function ObjectRefBase:get_velocity() end - ---[[ -* `add_velocity(vel)` - * Changes velocity by adding to the current velocity. - * `vel` is a vector, e.g. `{x=0.0, y=2.3, z=1.0}` - * In comparison to using `get_velocity`, adding the velocity and then using - `set_velocity`, `add_velocity` is supposed to avoid synchronization problems. - Additionally, players also do not support `set_velocity`. - * If object is a player: - * Does not apply during `free_move`. - * Note that since the player speed is normalized at each move step, - increasing e.g. Y velocity beyond what would usually be achieved - (see: physics overrides) will cause existing X/Z velocity to be reduced. - * Example: `add_velocity({x=0, y=6.5, z=0})` is equivalent to - pressing the jump key (assuming default settings) -]] ----@param vel vector -function ObjectRefBase:add_velocity(vel) end - ---[[ -* `move_to(pos, continuous=false)` - * Does an interpolated move for Lua entities for visually smooth transitions. - * If `continuous` is true, the Lua entity will not be moved to the current - position before starting the interpolated move. - * For players this does the same as `set_pos`,`continuous` is ignored. - * no-op if object is attached -]] ----@param pos vector ----@param continuous boolean? -function ObjectRefBase:move_to(pos, continuous) end - --- --------------------------------- actions -------------------------------- -- - ---[[ -* `punch(puncher, time_from_last_punch, tool_capabilities, dir)` - * punches the object, triggering all consequences a normal punch would have - * Other arguments: See `on_punch` for entities - * Arguments `time_from_last_punch`, `tool_capabilities`, and `dir` - will be replaced with a default value when the caller sets them to `nil`. -]] ----@param puncher core.ObjectRef ----@param time_from_last_punch number ----@param tool_capabilities core.ToolCapabilities ----@param dir vector ----@return core.Tool.wear wear -function ObjectRefBase:punch(puncher, time_from_last_punch, tool_capabilities, dir) end - ---[[ -* `right_click(clicker)`: - * simulates using the 'place/use' key on the object - * triggers all consequences as if a real player had done this - * `clicker` is another `ObjectRef` which has clicked - * note: this is called `right_click` for historical reasons only -]] ----@param clicker core.ObjectRef -function ObjectRefBase:right_click(clicker) end - --- --------------------------------- health --------------------------------- -- - ---[[ -* `get_hp()`: returns number of health points -]] ----@nodiscard ----@return integer hp -function ObjectRefBase:get_hp() end - ---[[ -* `set_hp(hp, reason)`: set number of health points - * See reason in register_on_player_hpchange - * Is limited to the range of 0 ... 65535 (2^16 - 1) - * For players: HP are also limited by `hp_max` specified in object properties -]] ----@param hp integer ----@param reason core.PlayerHPChangeReason? -function ObjectRefBase:set_hp(hp, reason) end - --- ------------------------- inventory and wielding ------------------------- -- - ---[[ -* `get_inventory()`: returns an `InvRef` for players, otherwise returns `nil` -]] ----@nodiscard ----@return nil -function ObjectRefBase:get_inventory() end - ---[[ -* `get_wield_list()`: returns the name of the inventory list the wielded item - is in. -]] ----@nodiscard ----@return core.InventoryList -function ObjectRefBase:get_wield_list() end - ---[[ -* `get_wield_index()`: returns the wield list index of the wielded item (starting with 1) -]] ----@nodiscard ----@return integer -function ObjectRefBase:get_wield_index() end - ---[[ -* `get_wielded_item()`: returns a copy of the wielded item as an `ItemStack` -]] ----@nodiscard ----@return core.ItemStack item -function ObjectRefBase:get_wielded_item() end - ---[[ -* `set_wielded_item(item)`: replaces the wielded item, returns `true` if - successful. -]] ----@param item core.Item -function ObjectRefBase:set_wielded_item(item) end - --- ---------------------------------- armor --------------------------------- -- - ---[[ -* `get_armor_groups()`: - * returns a table with all of the object's armor group ratings - * syntax: the table keys are the armor group names, - the table values are the corresponding group ratings - * see section '`ObjectRef` armor groups' for details -]] ----@nodiscard ----@return core.Groups.armor groups -function ObjectRefBase:get_armor_groups() end - ---[[ -* `set_armor_groups({group1=rating, group2=rating, ...})` - * sets the object's full list of armor groups - * same table syntax as for `get_armor_groups` - * note: all armor groups not in the table will be removed -]] ----@param groups core.Groups.armor -function ObjectRefBase:set_armor_groups(groups) end - --- -------------------------------- animation ------------------------------- -- - ---[[ -* `set_animation(frame_range, frame_speed, frame_blend, frame_loop)` - * Sets the object animation parameters and (re)starts the animation - * Animations only work with a `"mesh"` visual - * `frame_range`: Beginning and end frame (as specified in the mesh file). - * Syntax: `{x=start_frame, y=end_frame}` - * Animation interpolates towards the end frame but stops when it is reached - * If looped, there is no interpolation back to the start frame - * If looped, the model should look identical at start and end - * default: `{x=1.0, y=1.0}` - * `frame_speed`: How fast the animation plays, in frames per second (number) - * default: `15.0` - * `frame_blend`: number, default: `0.0` - * `frame_loop`: If `true`, animation will loop. If false, it will play once - * default: `true` -]] ----@param frame_range vec2.xy? ----@param frame_speed number? ----@param frame_blend number? ----@param frame_loop boolean? -function ObjectRefBase:set_animation(frame_range, frame_speed, frame_blend, frame_loop) end - ---[[ -* `get_animation()`: returns current animation parameters set by `set_animation`: - * `frame_range`, `frame_speed`, `frame_blend`, `frame_loop`. -]] ----@nodiscard ----@return vec2.xy frame_range, number frame_speed, number frame_blend, boolean frame_loop -function ObjectRefBase:get_animation() end - ---[[ -* `set_animation_frame_speed(frame_speed)` - * Sets the frame speed of the object's animation - * Unlike `set_animation`, this will not restart the animation - * `frame_speed`: See `set_animation` -]] ----@param frame_speed number -function ObjectRefBase:set_animation_frame_speed(frame_speed) end - --- ------------------------------- attachment ------------------------------- -- - ---[[ -* `set_attach(parent[, bone, position, rotation, forced_visible])` - * Attaches object to `parent` - * See 'Attachments' section for details - * `parent`: `ObjectRef` to attach to - * `bone`: Bone to attach to. Default is `""` (the root bone) - * `position`: relative position, default `{x=0, y=0, z=0}` - * `rotation`: relative rotation in degrees, default `{x=0, y=0, z=0}` - * `forced_visible`: Boolean to control whether the attached entity - should appear in first person, default `false`. - * This command may fail silently (do nothing) when it would result - in circular attachments. -]] ----@param parent core.ObjectRef ----@param bone string? ----@param position vector? ----@param rotation vector? ----@param forced_visible boolean? -function ObjectRefBase:set_attach(parent, bone, position, rotation, forced_visible) end - ---[[ -* `get_attach()`: - * returns current attachment parameters or nil if it isn't attached - * If attached, returns `parent`, `bone`, `position`, `rotation`, `forced_visible` -]] ----@nodiscard ----@return core.ObjectRef? parent, string? bones, vector? positions, vector? rotation, boolean? forced_visible -function ObjectRefBase:get_attach() end - ---[[ -* `get_children()`: returns a list of ObjectRefs that are attached to the - object. -]] ----@nodiscard ----@return core.ObjectRef[] -function ObjectRefBase:get_children() end - ---[[ -* `set_detach()`: Detaches object. No-op if object was not attached.]] -function ObjectRefBase:set_detach() end - --- ---------------------------------- bones --------------------------------- -- - ---[[ ObjectRef:set_bone_position() .. ObjectRef:get_bone_overrides() split off into ./bones.lua ]]-- - --- ----------------------------- object property ---------------------------- -- - ---[[ -* `set_properties(object property table)` -]] ----@param objprops core.ObjectProperties.set -function ObjectRefBase:set_properties(objprops) end - ---[[ -* `get_properties()`: returns a table of all object properties -]] ----@nodiscard ----@return core.ObjectProperties.get -function ObjectRefBase:get_properties() end - --- -------------------------------- observer -------------------------------- -- - ---[[ -* `set_observers(observers)`: sets observers (players this object is sent to) - * If `observers` is `nil`, the object's observers are "unmanaged": - The object is sent to all players as governed by server settings. This is the default. - * `observers` is a "set" of player names: `{name1 = true, name2 = true, ...}` - * A set is a table where the keys are the elements of the set - (in this case, *valid* player names) and the values are all `true`. - * Attachments: The *effective observers* of an object are made up of - all players who can observe the object *and* are also effective observers - of its parent object (if there is one). - * Players are automatically added to their own observer sets. - Players **must** effectively observe themselves. - * Object activation and deactivation are unaffected by observability. - * Attached sounds do not work correctly and thus should not be used - on objects with managed observers yet. -]] ----@param observers table? -function ObjectRefBase:set_observers(observers) end - ---[[ -* `get_observers()`: - * throws an error if the object is invalid - * returns `nil` if the observers are unmanaged - * returns a table with all observer names as keys and `true` values (a "set") otherwise -]] ----@nodiscard ----@return table? observers -function ObjectRefBase:get_observers() end - ---[[ -* `get_effective_observers()`: - * Like `get_observers()`, but returns the "effective" observers, taking into account attachments - * Time complexity: O(nm) - * n: number of observers of the involved entities - * m: number of ancestors along the attachment chain -]] ----@nodiscard ----@return table -function ObjectRefBase:get_effective_observers() end - --- -------------------------------- is player ------------------------------- -- - ---[[ -* `is_player()`: returns true for players, false otherwise -]] ----@nodiscard ----@return false -function ObjectRefBase:is_player() end - --- --------------------------------- nametag -------------------------------- -- - ---[[ ObjectRef:get_nametag_attributes() .. ObjectRef:set_nametag_attributes() split off into ./nametag.lua ]]-- - --- ---------------------------------- GUID ---------------------------------- -- - ---[[ -* `get_guid()`: returns a global unique identifier (a string) - * For players, this is a player name. - * For Lua entities, this is a uniquely generated string, guaranteed not to collide with player names. - * example: `@bGh3p2AbRE29Mb4biqX6OA` - * GUIDs only use printable ASCII characters. - * GUIDs persist between object reloads, and their format is guaranteed not to change. - Thus you can use the GUID to identify an object in a particular world online and offline. -]] ----@nodiscard ----@return string -function ObjectRefBase:get_guid() end \ No newline at end of file diff --git a/types/luanti_lsp_definitions/library/classes/ObjectRef/PlayerRef.lua b/types/luanti_lsp_definitions/library/classes/ObjectRef/PlayerRef.lua deleted file mode 100644 index fb03baf7..00000000 --- a/types/luanti_lsp_definitions/library/classes/ObjectRef/PlayerRef.lua +++ /dev/null @@ -1,549 +0,0 @@ ----@meta _ --- DRAFT 1 DONE --- luanti/doc/lua_api.md: Class reference > `ObjectRef` - ---[[ -WIPDOC -]] ----@class core.PlayerRef : _.ObjectRef.__base -local PlayerRef = {} - --- --------------------------- ObjectRef overrides -------------------------- -- - ---[[ -* `add_velocity(vel)` - * Changes velocity by adding to the current velocity. - * `vel` is a vector, e.g. `{x=0.0, y=2.3, z=1.0}` - * In comparison to using `get_velocity`, adding the velocity and then using - `set_velocity`, `add_velocity` is supposed to avoid synchronization problems. - Additionally, players also do not support `set_velocity`. - * If object is a player: - * Does not apply during `free_move`. - * Note that since the player speed is normalized at each move step, - increasing e.g. Y velocity beyond what would usually be achieved - (see: physics overrides) will cause existing X/Z velocity to be reduced. - * Example: `add_velocity({x=0, y=6.5, z=0})` is equivalent to - pressing the jump key (assuming default settings) -]] ----@param vel vector -function PlayerRef:add_velocity(vel) end - ---[[ -* `move_to(pos, continuous=false)` - * Does an interpolated move for Lua entities for visually smooth transitions. - * If `continuous` is true, the Lua entity will not be moved to the current - position before starting the interpolated move. - * For players this does the same as `set_pos`,`continuous` is ignored. - * no-op if object is attached -]] ----@param pos vector ----@param continuous boolean? -function PlayerRef:move_to(pos, continuous) end - ---[[ -* `set_hp(hp, reason)`: set number of health points - * See reason in register_on_player_hpchange - * Is limited to the range of 0 ... 65535 (2^16 - 1) - * For players: HP are also limited by `hp_max` specified in object properties -]] ----@param hp integer ----@param reason core.PlayerHPChangeReason? -function PlayerRef:set_hp(hp, reason) end - ---[[ -* `get_inventory()`: returns an `InvRef` for players, otherwise returns `nil` -]] ----@nodiscard ----@return core.InvRef -function PlayerRef:get_inventory() end - ---[[ -* `set_properties(object property table)` -]] ----@param objprops core.PlayerProperties.set -function PlayerRef:set_properties(objprops) end - ---[[ -* `get_properties()`: returns a table of all object properties -]] ----@nodiscard ----@return core.PlayerProperties.get objprops -function PlayerRef:get_properties() end - ---[[ -* `is_player()`: returns true for players, false otherwise -]] ----@nodiscard ----@return true -function PlayerRef:is_player() end - ---[[ -* `get_guid()`: returns a global unique identifier (a string) - * For players, this is a player name. - * For Lua entities, this is a uniquely generated string, guaranteed not to collide with player names. - * example: `@bGh3p2AbRE29Mb4biqX6OA` - * GUIDs only use printable ASCII characters. - * GUIDs persist between object reloads, and their format is guaranteed not to change. - Thus you can use the GUID to identify an object in a particular world online and offline. -]] ----@nodiscard ----@return string -function PlayerRef:get_guid() end - --- ------------------------------- player name ------------------------------ -- - ---[[ -* `get_player_name()`: Returns player name or `""` if is not a player -]] ----@nodiscard ----@return string -function PlayerRef:get_player_name() end - --- ---------------------- player position and movement ---------------------- -- - ---[[ -* `get_player_velocity()`: **DEPRECATED**, use get_velocity() instead. - table {x, y, z} representing the player's instantaneous velocity in nodes/s -]] ----@deprecated ----@nodiscard ----@return vec vel -function PlayerRef:get_player_velocity() end - ---[[ -* `add_player_velocity(vel)`: **DEPRECATED**, use add_velocity(vel) instead. -]] ----@deprecated ----@param vel vector -function PlayerRef:add_player_velocity(vel) end - --- ------------------------------ player camera ----------------------------- -- - ---[[ -* `get_look_dir()`: get camera direction as a unit vector -]] ----@nodiscard ----@return vector radians -function PlayerRef:get_look_dir() end - ---[[ -* `get_look_vertical()`: pitch in radians - * Angle ranges between -pi/2 and pi/2, which are straight up and down - respectively. -]] ----@nodiscard ----@return number radians -function PlayerRef:get_look_vertical() end - ---[[ -* `get_look_horizontal()`: yaw in radians - * Angle is counter-clockwise from the +z direction. -]] ----@nodiscard ----@return number radians -function PlayerRef:get_look_horizontal() end - ---[[ -* `set_look_vertical(radians)`: sets look pitch - * radians: Angle from looking forward, where positive is downwards. -]] ----@param radians number -function PlayerRef:set_look_vertical(radians) end - ---[[ -* `get_look_horizontal()`: yaw in radians - * Angle is counter-clockwise from the +z direction. -]] ----@param radians number -function PlayerRef:set_look_horizontal(radians) end - ---[[ -* `get_look_pitch()`: pitch in radians - Deprecated as broken. Use - `get_look_vertical`. -]] ----@deprecated ----@nodiscard ----@return number radians -function PlayerRef:get_look_pitch() end - ---[[ -* `get_look_yaw()`: yaw in radians - Deprecated as broken. Use - `get_look_horizontal`. -]] ----@deprecated ----@nodiscard ----@return number radians -function PlayerRef:get_look_yaw() end - ---[[ -* `set_look_pitch(radians)`: sets look pitch - Deprecated. Use - `set_look_vertical`. -]] ----@deprecated ----@param radians number -function PlayerRef:set_look_pitch(radians) end - ---[[ -* `set_look_yaw(radians)`: sets look yaw - Deprecated. Use - `set_look_horizontal`. -]] ----@deprecated ----@param radians number -function PlayerRef:set_look_yaw(radians) end - --- ------------------------------ player breath ----------------------------- -- - ---[[ -* `get_breath()`: returns player's breath -]] ----@nodiscard ----@return integer value -function PlayerRef:get_breath() end - ---[[ -* `set_breath(value)`: sets player's breath - * values: - * `0`: player is drowning - * Is limited to range 0 ... 65535 (2^16 - 1) -]] ----@nodiscard ----@param value integer -function PlayerRef:set_breath(value) end - --- ------------------------------- player fov ------------------------------- -- - ---[[ -* `set_fov(fov, is_multiplier, transition_time)`: Sets player's FOV - * `fov`: Field of View (FOV) value. - * `is_multiplier`: Set to `true` if the FOV value is a multiplier. - Defaults to `false`. - * `transition_time`: If defined, enables smooth FOV transition. - Interpreted as the time (in seconds) to reach target FOV. - If set to 0, FOV change is instantaneous. Defaults to 0. - * Set `fov` to 0 to clear FOV override. -]] ----@param fov number ----@param is_multiplier boolean? ----@param transition_time number? -function PlayerRef:set_fov(fov, is_multiplier, transition_time) end - ---[[ -* `get_fov()`: Returns the following: - * Server-sent FOV value. Returns 0 if an FOV override doesn't exist. - * Boolean indicating whether the FOV value is a multiplier. - * Time (in seconds) taken for the FOV transition. Set by `set_fov`. -]] ----@nodiscard ----@return number fov, boolean is_multiplier, number transition_time -function PlayerRef:get_fov() end - --- ----------------------------- player metadata ---------------------------- -- - ---[[ -* `set_attribute(attribute, value)`: DEPRECATED, use get_meta() instead - * Sets an extra attribute with value on player. - * `value` must be a string, or a number which will be converted to a - string. - * If `value` is `nil`, remove attribute from player. -]] ----@deprecated ----@param attribute string ----@param value string|number? -function PlayerRef:set_attribute(attribute, value) end - ---[[ -* `get_attribute(attribute)`: DEPRECATED, use get_meta() instead - * Returns value (a string) for extra attribute. - * Returns `nil` if no attribute found. -]] ----@deprecated ----@nodiscard ----@param attribute string ----@return string? -function PlayerRef:get_attribute(attribute) end - ---[[ -* `get_meta()`: Returns metadata associated with the player (a PlayerMetaRef). -]] ----@nodiscard ----@return core.PlayerMetaRef -function PlayerRef:get_meta() end - --- ----------------------------- player formspec ---------------------------- -- - ---[[ -* `set_inventory_formspec(formspec)` - * Redefines the player's inventory formspec. - * Should usually be called at least once in the `on_joinplayer` callback. - * If `formspec` is `""`, the player's inventory is disabled. - * If the inventory formspec is currently open on the client, it is - updated immediately. - * See also: `core.register_on_player_receive_fields` -]] ----@param formspec core.Formspec -function PlayerRef:set_inventory_formspec(formspec) end - ---[[ -* `get_inventory_formspec()`: returns a formspec string -]] ----@nodiscard ----@return core.Formspec? formspec -function PlayerRef:get_inventory_formspec() end - ---[[ -* `set_formspec_prepend(formspec)`: - * the formspec string will be added to every formspec shown to the user, - except for those with a no_prepend[] tag. - * This should be used to set style elements such as background[] and - bgcolor[], any non-style elements (eg: label) may result in weird behavior. - * Only affects formspecs shown after this is called. -]] ----@param formspec core.Formspec -function PlayerRef:set_formspec_prepend(formspec) end - ---[[ -* `get_formspec_prepend()`: returns a formspec string. -]] ----@nodiscard ----@return core.Formspec? formspec -function PlayerRef:get_formspec_prepend() end - --- ----------------------------- player control ----------------------------- -- - ---[[ PlayerRef:get_player_control() .. PlayerRef:get_player_control_bits() split off into ./player_control.lua ]]-- - --- ------------------------- player physics override ------------------------ -- - ---[[ PlayerRef:set_physics_override() .. PlayerRef:get_physics_override() splits off into ./player_physics_override.lua ]]-- - --- ------------------------------- player hud ------------------------------- -- - ---[[ -* `hud_add(hud definition)`: add a HUD element described by HUD def, returns ID - number on success -]] ----@nodiscard ----@param hud_definition core.HUDDef ----@return core.HUDID? id -function PlayerRef:hud_add(hud_definition) end - ---[[ -* `hud_remove(id)`: remove the HUD element of the specified id -]] ----@param id core.HUDID -function PlayerRef:hud_remove(id) end - ---[[ -* `hud_change(id, stat, value)`: change a value of a previously added HUD - element. - * `stat` supports the same keys as in the hud definition table except for - `"type"` (or the deprecated `"hud_elem_type"`). -]] ----@param id core.HUDID ----@param stat core.HUDDef.keys ----@param value number|string|core.Texture|vec2.xy|vec? -function PlayerRef:hud_change(id, stat, value) end - ---[[ -* `hud_get(id)`: gets the HUD element definition structure of the specified ID -]] ----@nodiscard ----@param id core.HUDID ----@return core.HUDDef? hud_definition -function PlayerRef:hud_get(id) end - ---[[ -* `hud_get_all()`: - * Returns a table in the form `{ [id] = HUD definition, [id] = ... }`. - * A mod should keep track of its introduced IDs and only use this to access foreign elements. - * It is discouraged to change foreign HUD elements. -]] ----@nodiscard ----@return table -function PlayerRef:hud_get_all() end - ---[[ PlayerRef:hud_set_flags() .. PlayerRef:hud_get_flags() split off into ./player_hud_flags.lua ]]-- - ---[[ -* `hud_set_hotbar_itemcount(count)`: sets number of items in builtin hotbar - * `count`: number of items, must be between `1` and `32` - * If `count` exceeds the `"main"` list size, the list size will be used instead. -]] ----@param count integer -function PlayerRef:hud_set_hotbar_itemcount(count) end - ---[[ -* `hud_get_hotbar_itemcount()`: returns number of visible items - * This value is also clamped by the `"main"` list size. -]] ----@nodiscard ----@return integer count -function PlayerRef:hud_get_hotbar_itemcount() end - ---[[ -* `hud_set_hotbar_image(texturename)` - * sets background image for hotbar -]] ----@param texturename core.Texture -function PlayerRef:hud_set_hotbar_image(texturename) end - ---[[ -* `hud_get_hotbar_image()`: returns texturename -]] ----@nodiscard ----@return core.Texture texturename -function PlayerRef:hud_get_hotbar_image() end - ---[[ -* `hud_set_hotbar_selected_image(texturename)` - * sets image for selected item of hotbar -]] ----@param texturename core.Texture -function PlayerRef:hud_set_hotbar_selected_image(texturename) end - ---[[ -* `hud_get_hotbar_selected_image()`: returns texturename -]] ----@nodiscard ----@return core.Texture texturename -function PlayerRef:hud_get_hotbar_selected_image() end - --- ----------------------------- player minimap ----------------------------- -- - ---[[ PlayerRef:set_minimap_modes() split off into ./player_minimap.lua ]]-- - --- ------------------------------- player sky ------------------------------- -- - ---[[ PlayerRef:set_sky() .. PlayerRef:get_sky_color() split off into ./player_skybox.lua ]]-- ---[[ PlayerRef:set_sun() .. PlayerRef:get_sun() split off into ./player_sun.lua ]]-- ---[[ PlayerRef:set_moon() .. PlayerRef:get_moon() split off into ./player_moon.lua ]]-- ---[[ PlayerRef:set_stars() .. PlayerRef:get_stars() split off into ./player_stars.lua ]]-- ---[[ PlayerRef:set_clouds() .. PlayerRef:get_clouds() split off into ./player_clouds.lua ]]-- - ---[[ -* `override_day_night_ratio(ratio or nil)` - * `0`...`1`: Overrides day-night ratio, controlling sunlight to a specific - amount. - * Passing no arguments disables override, defaulting to sunlight based on day-night cycle - * See also `core.time_to_day_night_ratio`, -]] ----@param ratio number? -function PlayerRef:override_day_night_ratio(ratio) end - ---[[ -* `get_day_night_ratio()`: returns the ratio or nil if it isn't overridden -]] ----@nodiscard ----@return number? ratio -function PlayerRef:get_day_night_ratio() end - --- ---------------------------- player animation ---------------------------- -- - ---[[ -* `set_local_animation(idle, walk, dig, walk_while_dig, frame_speed)`: - set animation for player model in third person view. - * Every animation equals to a `{x=starting frame, y=ending frame}` table. - * `frame_speed` sets the animations frame speed. Default is 30. -]] ----@param idle vec2.xy ----@param walk vec2.xy ----@param dig vec2.xy ----@param walk_while_dig vec2.xy ----@param frame_speed number -function PlayerRef:set_local_animation(idle, walk, dig, walk_while_dig, frame_speed) end - ---[[ -* `get_local_animation()`: returns idle, walk, dig, walk_while_dig tables and - `frame_speed`. -]] ----@nodiscard ----@return vec2.xy idle, vec2.xy walk, vec2.xy dig -function PlayerRef:get_local_animation() end - --- ------------------------------ player camera ----------------------------- -- - ---[[ -* `set_eye_offset([firstperson, thirdperson_back, thirdperson_front])`: Sets camera offset vectors. - * `firstperson`: Offset in first person view. - Defaults to `vector.zero()` if unspecified. - * `thirdperson_back`: Offset in third person back view. - Clamped between `vector.new(-10, -10, -5)` and `vector.new(10, 15, 5)`. - Defaults to `vector.zero()` if unspecified. - * `thirdperson_front`: Offset in third person front view. - Same limits as for `thirdperson_back` apply. - Defaults to `thirdperson_back` if unspecified. -]] ----@param firstperson vector? ----@param thirdperson_back vector? ----@param thirdperson_front vector? -function PlayerRef:set_eye_offset(firstperson, thirdperson_back, thirdperson_front) end - ---[[ -* `get_eye_offset()`: Returns camera offset vectors as set via `set_eye_offset`. -]] ----@nodiscard ----@return vec firstperson, vec thirdperson_back, vec thirdperson_front -function PlayerRef:get_eye_offset() end - ---[[ -WIPDOC -]] ----@alias core.PlayerCameraParams.mode ---- | "any" ---- | "first" ---- | "third" ---- | "third_front" - ---[[ -WIPDOC -]] ----@class core.PlayerCameraParams ---[[ -WIPDOC -]] ----@field mode core.PlayerCameraParams.mode - ---[[ -* `set_camera(params)`: Sets camera parameters. - * `mode`: Defines the camera mode used - - `any`: free choice between all modes (default) - - `first`: first-person camera - - `third`: third-person camera - - `third_front`: third-person camera, looking opposite of movement direction - * Supported by client since 5.12.0. -]] ----@param params core.PlayerCameraParams -function PlayerRef:set_camera(params) end - ---[[ -* `get_camera()`: Returns the camera parameters as a table as above. -]] ----@nodiscard ----@return core.PlayerCameraParams params -function PlayerRef:get_camera() end - --- ---------------------- player mapblock and lighting ---------------------- -- - ---[[ -* `send_mapblock(blockpos)`: - * Sends an already loaded mapblock to the player. - * Returns `false` if nothing was sent (note that this can also mean that - the client already has the block) - * Resource intensive - use sparsely -]] ----@nodiscard ----@param blockpos vector ----@return boolean? -function PlayerRef:send_mapblock(blockpos) end - ---[[ PlayerRef:set_lighting() .. PlayerRef:get_lighting() split off into ./player_lighting.lua ]]-- - --- ------------------------------- player misc ------------------------------ -- - ---[[ -* `respawn()`: Respawns the player using the same mechanism as the death screen, - including calling `on_respawnplayer` callbacks. -]] -function PlayerRef:respawn() end - ---[[ PlayerRef:get_flags() .. PlayerRef:set_flags() split off into ./player_flags.lua ]]-- \ No newline at end of file diff --git a/types/luanti_lsp_definitions/library/classes/ObjectRef/bones.lua b/types/luanti_lsp_definitions/library/classes/ObjectRef/bones.lua deleted file mode 100644 index 37d8fb2e..00000000 --- a/types/luanti_lsp_definitions/library/classes/ObjectRef/bones.lua +++ /dev/null @@ -1,150 +0,0 @@ ----@meta _ --- DRAFT 1 DONE --- luanti/doc/lua_api.md: Class reference > `ObjectRef` - --- -------------------------- BoneOverride.property ------------------------- -- - ---[[ -WIPDOC -]] ----@class core.BoneOverride.property.set ---[[ -WIPDOC -]] ----@field vec vector? ---[[ -WIPDOC -]] ----@field interpolation number? ---[[ -WIPDOC -]] ----@field absolute boolean? - ---[[ -WIPDOC -]] ----@class core.BoneOverride.property.get ---[[ -WIPDOC -]] ----@field vec vector ---[[ -WIPDOC -]] ----@field interpolation number ---[[ -WIPDOC -]] ----@field absolute boolean - - --- ------------------------------ BoneOverride ------------------------------ -- - ---[[ -WIPDOC -]] ----@class core.BoneOverride.set ---[[ -WIPDOC -]] ----@field position core.BoneOverride.property.set? ---[[ -WIPDOC -]] ----@field rotation core.BoneOverride.property.set? ---[[ -WIPDOC -]] ----@field scale core.BoneOverride.property.set? - ---[[ -WIPDOC -]] ----@class core.BoneOverride.get ---[[ -WIPDOC -]] ----@field position core.BoneOverride.property.get ---[[ -WIPDOC -]] ----@field rotation core.BoneOverride.property.get ---[[ -WIPDOC -]] ----@field scale core.BoneOverride.property.get - - --- ---------------------------- ObjectRef methods --------------------------- -- - ----@class _.ObjectRef.__base -local ObjectRefBase - ---[[ -* `set_bone_position([bone, position, rotation])` - * Sets absolute bone overrides, e.g. it is equivalent to - ```lua - obj:set_bone_override(bone, { - position = {vec = position, absolute = true}, - ``` - * **Note:** Rotation is in degrees, not radians. - * **Deprecated:** Use `set_bone_override` instead. -]] ----@deprecated ----@param bone string ----@param position vector ----@param rotation vector -function ObjectRefBase:set_bone_position(bone, position, rotation) end - ---[[ -* `get_bone_position(bone)`: returns the previously set position and rotation of the bone - * Shorthand for `get_bone_override(bone).position.vec, get_bone_override(bone).rotation.vec:apply(math.deg)`. - * **Note:** Returned rotation is in degrees, not radians. - * **Deprecated:** Use `get_bone_override` instead. -]] ----@nodiscard ----@deprecated ----@param bone string ----@return vec position, vec rotation -function ObjectRefBase:get_bone_position(bone) end - ---[[ -* `set_bone_override(bone, override)` - * `bone`: string - * `override`: `{ position = property, rotation = property, scale = property }` or `nil` - * `override = nil` (including omission) is shorthand for `override = {}` which clears the override - * Each `property` is a table of the form - `{ vec = vector, interpolation = 0, absolute = false }` or `nil` - * `vec` is in the same coordinate system as the model, and in radians for rotation. - It defaults to `vector.zero()` for translation and rotation and `vector.new(1, 1, 1)` for scale. - * `interpolation`: The old and new overrides are interpolated over this timeframe (in seconds). - * `absolute`: If set to `false` (which is the default), - the override will be relative to the animated property: - * Translation in the case of `position`; - * Composition in the case of `rotation`; - * Per-axis multiplication in the case of `scale` - * `property = nil` is equivalent to no override on that property - * **Note:** Unlike `set_bone_position`, the rotation is in radians, not degrees. - * Compatibility note: Clients prior to 5.9.0 only support absolute position and rotation. - All values are treated as absolute and are set immediately (no interpolation). -]] ----@param bone string ----@param override core.BoneOverride.set? -function ObjectRefBase:set_bone_override(bone, override) end - ---[[ -* `get_bone_override(bone)`: returns `override` in the above format - * **Note:** Unlike `get_bone_position`, the returned rotation is in radians, not degrees. -]] ----@nodiscard ----@param bone string ----@return core.BoneOverride.get -function ObjectRefBase:get_bone_override(bone) end - ---[[ -* `get_bone_overrides()`: returns all bone overrides as table `{[bonename] = override, ...}` -]] ----@nodiscard ----@return table -function ObjectRefBase:get_bone_overrides() end \ No newline at end of file diff --git a/types/luanti_lsp_definitions/library/classes/ObjectRef/nametag.lua b/types/luanti_lsp_definitions/library/classes/ObjectRef/nametag.lua deleted file mode 100644 index 2359dfb5..00000000 --- a/types/luanti_lsp_definitions/library/classes/ObjectRef/nametag.lua +++ /dev/null @@ -1,80 +0,0 @@ ----@meta _ --- DRAFT 1 DONE --- luanti/doc/lua_api.md: Class reference > `ObjectRef` - --- ---------------------------- NametagAttributes --------------------------- -- - ---[[ -WIPDOC -]] ----@class core.NametagAttributes.get ---[[ -WIPDOC -]] ----@field text string ---[[ -WIPDOC -]] ----@field color core.ColorSpec.tablefmt ---[[ -WIPDOC -]] ----@field bgcolor core.ColorSpec.tablefmt - ---[[ -WIPDOC -]] ----@class core.NametagAttributes.set ---[[ -WIPDOC -]] ----@field text string ---[[ -WIPDOC -]] ----@field color core.ColorSpec ---[[ -WIPDOC -]] ----@field bgcolor core.ColorSpec | false | nil - - --- ---------------------------- ObjectRef methods --------------------------- -- - ----@class _.ObjectRef.__base -local ObjectRefBase - ---[[ -* `get_nametag_attributes()` - * returns a table with the attributes of the nametag of an object - * a nametag is a HUD text rendered above the object - * ```lua - { - text = "", - color = {a=0..255, r=0..255, g=0..255, b=0..255}, - bgcolor = {a=0..255, r=0..255, g=0..255, b=0..255}, - } - ``` -]] ----@nodiscard ----@return core.NametagAttributes.get attributes -function ObjectRefBase:get_nametag_attributes() end - ---[[ -* `set_nametag_attributes(attributes)` - * sets the attributes of the nametag of an object - * `attributes`: - ```lua - { - text = "My Nametag", - color = ColorSpec, - -- ^ Text color - bgcolor = ColorSpec or false, - -- ^ Sets background color of nametag - -- `false` will cause the background to be set automatically based on user settings - -- Default: false - } - ``` -]] ----@param attributes core.NametagAttributes.set -function ObjectRefBase:set_nametag_attributes(attributes) end \ No newline at end of file diff --git a/types/luanti_lsp_definitions/library/classes/ObjectRef/player_clouds.lua b/types/luanti_lsp_definitions/library/classes/ObjectRef/player_clouds.lua deleted file mode 100644 index 38b1bce1..00000000 --- a/types/luanti_lsp_definitions/library/classes/ObjectRef/player_clouds.lua +++ /dev/null @@ -1,107 +0,0 @@ ----@meta _ --- DRAFT 1 DONE --- luanti/doc/lua_api.md: Class reference > `ObjectRef` - - --- -------------------------- PlayerCloudParameters ------------------------- -- - ---[[ -WIPDOC -]] ----@class core.PlayerCloudParameters.set ---[[ -WIPDOC -]] ----@field density number? ---[[ -WIPDOC -]] ----@field color core.ColorSpec? ---[[ -WIPDOC -]] ----@field ambient core.ColorSpec? ---[[ -WIPDOC -]] ----@field height integer? ---[[ -WIPDOC -]] ----@field thickness integer? ---[[ -WIPDOC -]] ----@field speed vec2.xy? ---[[ -WIPDOC -]] ----@field shadow core.ColorSpec? - ---[[ -WIPDOC -]] ----@class core.PlayerCloudParameters.get ---[[ -WIPDOC -]] ----@field density number ---[[ -WIPDOC -]] ----@field color core.ColorSpec ---[[ -WIPDOC -]] ----@field ambient core.ColorSpec ---[[ -WIPDOC -]] ----@field height integer ---[[ -WIPDOC -]] ----@field thickness integer ---[[ -WIPDOC -]] ----@field speed vec2.xy ---[[ -WIPDOC -]] ----@field shadow core.ColorSpec - --- ---------------------------- PlayerRef methods --------------------------- -- - ----@class core.PlayerRef -local PlayerRef - - ---[[ -* `set_clouds(cloud_parameters)`: set cloud parameters - * Passing no arguments resets clouds to their default values. - * `cloud_parameters` is a table with the following optional fields: - * `density`: from `0` (no clouds) to `1` (full clouds) (default `0.4`) - * `color`: basic cloud color with alpha channel, ColorSpec - (default `#fff0f0e5`). - * `ambient`: cloud color lower bound, use for a "glow at night" effect. - ColorSpec (alpha ignored, default `#000000`) - * `height`: cloud height, i.e. y of cloud base (default per conf, - usually `120`) - * `thickness`: cloud thickness in nodes (default `16`). - if set to zero the clouds are rendered flat. - * `speed`: 2D cloud speed + direction in nodes per second - (default `{x=0, z=-2}`). - * `shadow`: shadow color, applied to the base of the cloud - (default `#cccccc`). -]] ----@param cloud_parameters core.PlayerCloudParameters.set -function PlayerRef:set_clouds(cloud_parameters) end - ---[[ -* `get_clouds()`: returns a table with the current cloud parameters as in - `set_clouds`. -]] ----@nodiscard ----@return core.PlayerCloudParameters.get cloud_parameters -function PlayerRef:get_clouds() end \ No newline at end of file diff --git a/types/luanti_lsp_definitions/library/classes/ObjectRef/player_control.lua b/types/luanti_lsp_definitions/library/classes/ObjectRef/player_control.lua deleted file mode 100644 index f40b027f..00000000 --- a/types/luanti_lsp_definitions/library/classes/ObjectRef/player_control.lua +++ /dev/null @@ -1,110 +0,0 @@ ----@meta _ --- DRAFT 1 DONE --- luanti/doc/lua_api.md: Class reference > `ObjectRef` - --- ------------------------------ PlayerControl ----------------------------- -- - ---[[ -WIPDOC -]] ----@class core.PlayerControl ---[[ -WIPDOC -]] ----@field up boolean ---[[ -WIPDOC -]] ----@field down boolean ---[[ -WIPDOC -]] ----@field left boolean ---[[ -WIPDOC -]] ----@field right boolean ---[[ -WIPDOC -]] ----@field jump boolean ---[[ -WIPDOC -]] ----@field aux1 boolean ---[[ -WIPDOC -]] ----@field sneak boolean ---[[ -WIPDOC -]] ----@field dig boolean ---[[ -WIPDOC -]] ----@field place boolean ---[[ -WIPDOC -]] ----@field LMB boolean ---[[ -WIPDOC -]] ----@field RMB boolean ---[[ -WIPDOC -]] ----@field zoom boolean ---[[ -WIPDOC -]] ----@field movement_x number ---[[ -WIPDOC -]] ----@field movement_y number - --- ---------------------------- PlayerRef methods --------------------------- -- - ----@class core.PlayerRef -local PlayerRef - ---[[ -* `get_player_control()`: returns table with player input - * The table contains the following boolean fields representing the pressed - keys: `up`, `down`, `left`, `right`, `jump`, `aux1`, `sneak`, `dig`, - `place`, `LMB`, `RMB` and `zoom`. - * The fields `LMB` and `RMB` are equal to `dig` and `place` respectively, - and exist only to preserve backwards compatibility. - * The table also contains the fields `movement_x` and `movement_y`. - * They represent the movement of the player. Values are numbers in the - range [-1.0,+1.0]. - * They take both keyboard and joystick input into account. - * You should prefer them over `up`, `down`, `left` and `right` to - support different input methods correctly. - * Returns an empty table `{}` if the object is not a player. -]] ----@nodiscard ----@return core.PlayerControl -function PlayerRef:get_player_control() end - ---[[ -* `get_player_control_bits()`: returns integer with bit packed player pressed - keys. - * Bits: - * 0 - up - * 1 - down - * 2 - left - * 3 - right - * 4 - jump - * 5 - aux1 - * 6 - sneak - * 7 - dig - * 8 - place - * 9 - zoom - * Returns `0` (no bits set) if the object is not a player. -]] ----@nodiscard ----@return integer -function PlayerRef:get_player_control_bits() end \ No newline at end of file diff --git a/types/luanti_lsp_definitions/library/classes/ObjectRef/player_flags.lua b/types/luanti_lsp_definitions/library/classes/ObjectRef/player_flags.lua deleted file mode 100644 index f74b9843..00000000 --- a/types/luanti_lsp_definitions/library/classes/ObjectRef/player_flags.lua +++ /dev/null @@ -1,63 +0,0 @@ ----@meta _ --- DRAFT 1 DONE --- luanti/doc/lua_api.md: Class reference > `ObjectRef` - --- ------------------------------- PlayerFlags ------------------------------ -- - ---[[ -WIPDOC -]] ----@class core.PlayerFlags.get ---[[ -WIPDOC -]] ----@field breathing boolean ---[[ -WIPDOC -]] ----@field drowning boolean ---[[ -WIPDOC -]] ----@field node_damage boolean - ---[[ -WIPDOC -]] ----@class core.PlayerFlags.set ---[[ -WIPDOC -]] ----@field breathing boolean? ---[[ -WIPDOC -]] ----@field drowning boolean? ---[[ -WIPDOC -]] ----@field node_damage boolean? - - --- ---------------------------- PlayerRef methods --------------------------- -- - ----@class core.PlayerRef -local PlayerRef - ---[[ -* `get_flags()`: returns a table of player flags (the following boolean fields): - * `breathing`: Whether breathing (regaining air) is enabled, default `true`. - * `drowning`: Whether drowning (losing air) is enabled, default `true`. - * `node_damage`: Whether the player takes damage from nodes, default `true`. -]] ----@nodiscard ----@return core.PlayerFlags.get flags -function PlayerRef:get_flags() end - ---[[ -* `set_flags(flags)`: sets flags - * takes a table in the same format as returned by `get_flags` - * absent fields are left unchanged -]] ----@param flags core.PlayerFlags.set -function PlayerRef:set_flags(flags) end \ No newline at end of file diff --git a/types/luanti_lsp_definitions/library/classes/ObjectRef/player_hud_flags.lua b/types/luanti_lsp_definitions/library/classes/ObjectRef/player_hud_flags.lua deleted file mode 100644 index e13f351f..00000000 --- a/types/luanti_lsp_definitions/library/classes/ObjectRef/player_hud_flags.lua +++ /dev/null @@ -1,112 +0,0 @@ ----@meta _ --- DRAFT 1 DONE --- luanti/doc/lua_api.md: Class reference > `ObjectRef` - --- ----------------------------- PlayerHudFlags ----------------------------- -- - ---[[ -WIPDOC -]] ----@class core.PlayerHudFlags.set ---[[ -WIPDOC -]] ----@field hotbar boolean? ---[[ -WIPDOC -]] ----@field healthbar boolean? ---[[ -WIPDOC -]] ----@field crosshair boolean? ---[[ -WIPDOC -]] ----@field wielditem boolean? ---[[ -WIPDOC -]] ----@field breathbar boolean? ---[[ -WIPDOC -]] ----@field minimap boolean? ---[[ -WIPDOC -]] ----@field minimap_radar boolean? ---[[ -WIPDOC -]] ----@field basic_debug boolean? - ---[[ -WIPDOC -]] ----@class core.PlayerHudFlags.get ---[[ -WIPDOC -]] ----@field hotbar boolean ---[[ -WIPDOC -]] ----@field healthbar boolean ---[[ -WIPDOC -]] ----@field crosshair boolean ---[[ -WIPDOC -]] ----@field wielditem boolean ---[[ -WIPDOC -]] ----@field breathbar boolean ---[[ -WIPDOC -]] ----@field minimap boolean ---[[ -WIPDOC -]] ----@field minimap_radar boolean ---[[ -WIPDOC -]] ----@field basic_debug boolean - - --- ---------------------------- PlayerRef methods --------------------------- -- - ----@class core.PlayerRef -local PlayerRef - ---[[ -* `hud_set_flags(flags)`: sets specified HUD flags of player. - * `flags`: A table with the following fields set to boolean values - * `hotbar` - * `healthbar` - * `crosshair` - * `wielditem` - * `breathbar` - * `minimap`: Modifies the client's permission to view the minimap. - The client may locally elect to not view the minimap. - * `minimap_radar`: is only usable when `minimap` is true - * `basic_debug`: Allow showing basic debug info that might give a gameplay advantage. - This includes map seed, player position, look direction, the pointed node and block bounds. - Does not affect players with the `debug` privilege. - * If a flag equals `nil`, the flag is not modified -]] ----@param flags core.PlayerHudFlags.set -function PlayerRef:hud_set_flags(flags) end - ---[[ -* `hud_get_flags()`: returns a table of player HUD flags with boolean values. - * See `hud_set_flags` for a list of flags that can be toggled. -]] ----@nodiscard ----@return core.PlayerHudFlags.get flags -function PlayerRef:hud_get_flags() end \ No newline at end of file diff --git a/types/luanti_lsp_definitions/library/classes/ObjectRef/player_lighting.lua b/types/luanti_lsp_definitions/library/classes/ObjectRef/player_lighting.lua deleted file mode 100644 index 546ecee9..00000000 --- a/types/luanti_lsp_definitions/library/classes/ObjectRef/player_lighting.lua +++ /dev/null @@ -1,219 +0,0 @@ ----@meta _ --- DRAFT 1 DONE --- luanti/doc/lua_api.md: Class reference > `ObjectRef` - --- -------------------------- PlayerLightDef.shadow ------------------------- -- - ---[[ -WIPDOC -]] ----@class core.PlayerLightDef.shadow.set ---[[ -WIPDOC -]] ----@field intensity number? ---[[ -WIPDOC -]] ----@field tint core.ColorSpec? - ---[[ -WIPDOC -]] ----@class core.PlayerLightDef.shadow.get ---[[ -WIPDOC -]] ----@field intensity number? ---[[ -WIPDOC -]] ----@field tint core.ColorSpec? - --- ------------------------- PlayerLightDef.exposure ------------------------ -- - ---[[ -WIPDOC -]] ----@class core.PlayerLightDef.exposure.set ---[[ -WIPDOC -]] ----@field luminescence_min number? ---[[ -WIPDOC -]] ----@field luminescence_max number? ---[[ -WIPDOC -]] ----@field exposure_correction number? ---[[ -WIPDOC -]] ----@field speed_dark_bright number? ---[[ -WIPDOC -]] ----@field speed_bright_dark number? ---[[ -WIPDOC -]] ----@field center_weight_power number? - ---[[ -WIPDOC -]] ----@class core.PlayerLightDef.exposure.get ---[[ -WIPDOC -]] ----@field luminescence_min number ---[[ -WIPDOC -]] ----@field luminescence_max number ---[[ -WIPDOC -]] ----@field exposure_correction number ---[[ -WIPDOC -]] ----@field speed_dark_bright number ---[[ -WIPDOC -]] ----@field speed_bright_dark number ---[[ -WIPDOC -]] ----@field center_weight_power number - --- -------------------------- PlayerLightDef.bloom -------------------------- -- - ---[[ -WIPDOC -]] ----@class core.PlayerLightDef.bloom.set ---[[ -WIPDOC -]] ----@field intensity number? ---[[ -WIPDOC -]] ----@field strength_factor number? ---[[ -WIPDOC -]] ----@field radius number? - ---[[ -WIPDOC -]] ----@class core.PlayerLightDef.bloom.get ---[[ -WIPDOC -]] ----@field intensity number ---[[ -WIPDOC -]] ----@field strength_factor number ---[[ -WIPDOC -]] ----@field radius number - --- --------------------- PlayerLightDef.volumetric_light -------------------- -- - ---[[ -WIPDOC -]] ----@class core.PlayerLightDef.volumetric_light.set ---[[ -WIPDOC -]] ----@field strength number? - ---[[ -WIPDOC -]] ----@class core.PlayerLightDef.volumetric_light.get ---[[ -WIPDOC -]] ----@field strength number - - --- ----------------------------- PlayerLightDef ----------------------------- -- - ---[[ -WIPDOC -]] ----@class core.PlayerLightDef.set ---[[ -WIPDOC -]] ----@field saturation number? ---[[ -WIPDOC -]] ----@field shadows core.PlayerLightDef.shadow.set? ---[[ -WIPDOC -]] ----@field exposure core.PlayerLightDef.exposure.set? ---[[ -WIPDOC -]] ----@field bloom core.PlayerLightDef.bloom.set? ---[[ -WIPDOC -]] ----@field volumetric_light core.PlayerLightDef.volumetric_light.set? - ---[[ -WIPDOC -]] ----@class core.PlayerLightDef.get ---[[ -WIPDOC -]] ----@field saturation number ---[[ -WIPDOC -]] ----@field shadows core.PlayerLightDef.shadow.get ---[[ -WIPDOC -]] ----@field exposure core.PlayerLightDef.exposure.get ---[[ -WIPDOC -]] ----@field bloom core.PlayerLightDef.bloom.get ---[[ -WIPDOC -]] ----@field volumetric_light core.PlayerLightDef.volumetric_light.get - --- ---------------------------- PlayerRef methods --------------------------- -- - ----@class core.PlayerRef -local PlayerRef - ---[[ -WIPDOC -]] ----@param light_definition core.PlayerLightDef.set -function PlayerRef:set_lighting(light_definition) end - ---[[ -* `get_lighting()`: returns the current state of lighting for the player. - * Result is a table with the same fields as `light_definition` in `set_lighting`. -]] ----@nodiscard ----@return core.PlayerLightDef.get light_definition -function PlayerRef:get_lighting() end \ No newline at end of file diff --git a/types/luanti_lsp_definitions/library/classes/ObjectRef/player_minimap.lua b/types/luanti_lsp_definitions/library/classes/ObjectRef/player_minimap.lua deleted file mode 100644 index c2ad92d2..00000000 --- a/types/luanti_lsp_definitions/library/classes/ObjectRef/player_minimap.lua +++ /dev/null @@ -1,71 +0,0 @@ ----@meta _ --- DRAFT 1 DONE --- luanti/doc/lua_api.md: Class reference > `ObjectRef` - --- ---------------------------- PlayreMinimapMode --------------------------- -- - ---[[ -WIPDOC -]] ----@alias core.PlayerMinimapMode.type ---- | "off" ---- | "surface" ---- | "radar" ---- | "texture" - ---[[ -WIPDOC -]] ----@class core.PlayerMinimapMode ---[[ -WIPDOC -]] ----@field type core.PlayerMinimapMode.type ---[[ -WIPDOC -]] ----@field label string? ---[[ -WIPDOC -]] ----@field size integer ---[[ -WIPDOC -]] ----@field texture core.Texture? ---[[ -WIPDOC -]] ----@field scale integer? - --- ---------------------------- PlayerRef methods --------------------------- -- - ----@class core.PlayerRef -local PlayerRef - ---[[ -* `set_minimap_modes({mode, mode, ...}, selected_mode)` - * Overrides the available minimap modes (and toggle order), and changes the - selected mode. - * `mode` is a table consisting of up to four fields: - * `type`: Available type: - * `off`: Minimap off - * `surface`: Minimap in surface mode - * `radar`: Minimap in radar mode - * `texture`: Texture to be displayed instead of terrain map - (texture is centered around 0,0 and can be scaled). - Texture size is limited to 512 x 512 pixel. - * `label`: Optional label to display on minimap mode toggle - The translation must be handled within the mod. - * `size`: Sidelength or diameter, in number of nodes, of the terrain - displayed in minimap - * `texture`: Only for texture type, name of the texture to display - * `scale`: Only for texture type, scale of the texture map in nodes per - pixel (for example a `scale` of 2 means each pixel represents a 2x2 - nodes square) - * `selected_mode` is the mode index to be selected after modes have been changed - (0 is the first mode). -]] ----@param modes core.PlayerMinimapMode[] ----@param selected_mode integer -function PlayerRef:set_minimap_modes(modes, selected_mode) end \ No newline at end of file diff --git a/types/luanti_lsp_definitions/library/classes/ObjectRef/player_moon.lua b/types/luanti_lsp_definitions/library/classes/ObjectRef/player_moon.lua deleted file mode 100644 index b788055f..00000000 --- a/types/luanti_lsp_definitions/library/classes/ObjectRef/player_moon.lua +++ /dev/null @@ -1,66 +0,0 @@ ----@meta _ --- DRAFT 1 DONE --- luanti/doc/lua_api.md: Class reference > `ObjectRef` - --- -------------------------- PlayerMoonParameters -------------------------- -- - ---[[ -WIPDOC -]] ----@class core.PlayerMoonParameters.set ---[[ -WIPDOC -]] ----@field visible boolean? ---[[ -WIPDOC -]] ----@field texture core.Texture? ---[[ -WIPDOC -]] ----@field tonemap core.Texture? ---[[ -WIPDOC -]] ----@field scale number? - ---[[ -WIPDOC -]] ----@class core.PlayerMoonParameters.get ---[[ -WIPDOC -]] ----@field visible boolean ---[[ -WIPDOC -]] ----@field texture core.Texture ---[[ -WIPDOC -]] ----@field tonemap core.Texture ---[[ -WIPDOC -]] ----@field scale number - --- ---------------------------- PlayerRef methods --------------------------- -- - ----@class core.PlayerRef -local PlayerRef - ---[[ -WIPDOC -]] ----@param moon_parameters core.PlayerMoonParameters.set -function PlayerRef:set_moon(moon_parameters) end - ---[[ -* `get_moon()`: returns a table with the current moon parameters as in - `set_moon`. -]] ----@nodiscard ----@return core.PlayerMoonParameters.get moon_parameters -function PlayerRef:get_moon() end \ No newline at end of file diff --git a/types/luanti_lsp_definitions/library/classes/ObjectRef/player_physics_override.lua b/types/luanti_lsp_definitions/library/classes/ObjectRef/player_physics_override.lua deleted file mode 100644 index b8d168e8..00000000 --- a/types/luanti_lsp_definitions/library/classes/ObjectRef/player_physics_override.lua +++ /dev/null @@ -1,162 +0,0 @@ ----@meta _ --- DRAFT 1 DONE --- luanti/doc/lua_api.md: Class reference > `ObjectRef` - --- -------------------------- PlayerPhysicsOverride ------------------------- -- - ---[[ -WIPDOC -]] ----@class core.PlayerPhysicsOverride.set ---[[ -WIPDOC -]] ----@field speed number? ---[[ -WIPDOC -]] ----@field speed_walk number? ---[[ -WIPDOC -]] ----@field speed_climb number? ---[[ -WIPDOC -]] ----@field speed_crouch number? ---[[ -WIPDOC -]] ----@field speed_fast number? ---[[ -WIPDOC -]] ----@field jump number? ---[[ -WIPDOC -]] ----@field gravity number? ---[[ -WIPDOC -]] ----@field liquid_fluidity number? ---[[ -WIPDOC -]] ----@field liquid_fluidity_smooth number? ---[[ -WIPDOC -]] ----@field liquid_sink number? ---[[ -WIPDOC -]] ----@field acceleration_default number? ---[[ -WIPDOC -]] ----@field acceleration_air number? ---[[ -WIPDOC -]] ----@field acceleration_fast number? ---[[ -WIPDOC -]] ----@field sneak number? ---[[ -WIPDOC -]] ----@field sneak_glitch number? ---[[ -WIPDOC -]] ----@field new_move number? - ---[[ -WIPDOC -]] ----@class core.PlayerPhysicsOverride.get ---[[ -WIPDOC -]] ----@field speed number ---[[ -WIPDOC -]] ----@field speed_walk number ---[[ -WIPDOC -]] ----@field speed_climb number ---[[ -WIPDOC -]] ----@field speed_crouch number ---[[ -WIPDOC -]] ----@field speed_fast number ---[[ -WIPDOC -]] ----@field jump number ---[[ -WIPDOC -]] ----@field gravity number ---[[ -WIPDOC -]] ----@field liquid_fluidity number ---[[ -WIPDOC -]] ----@field liquid_fluidity_smooth number ---[[ -WIPDOC -]] ----@field liquid_sink number ---[[ -WIPDOC -]] ----@field acceleration_default number ---[[ -WIPDOC -]] ----@field acceleration_air number ---[[ -WIPDOC -]] ----@field acceleration_fast number ---[[ -WIPDOC -]] ----@field sneak number ---[[ -WIPDOC -]] ----@field sneak_glitch number ---[[ -WIPDOC -]] ----@field new_move number - - --- ---------------------------- PlayerRef methods --------------------------- -- - ----@class core.PlayerRef -local PlayerRef - ---[[ -WIPDOC -]] ----@param override_table core.PlayerPhysicsOverride.set -function PlayerRef:set_physics_override(override_table) end - ---[[ -* `get_physics_override()`: returns the table given to `set_physics_override` -]] ----@nodiscard ----@return core.PlayerPhysicsOverride.get override_table -function PlayerRef:get_physics_override() end \ No newline at end of file diff --git a/types/luanti_lsp_definitions/library/classes/ObjectRef/player_skybox.lua b/types/luanti_lsp_definitions/library/classes/ObjectRef/player_skybox.lua deleted file mode 100644 index 778b6e02..00000000 --- a/types/luanti_lsp_definitions/library/classes/ObjectRef/player_skybox.lua +++ /dev/null @@ -1,368 +0,0 @@ ----@meta _ --- DRAFT 1 DONE --- luanti/doc/lua_api.md: Class reference > `ObjectRef` - --- -------------------- PlayerSkyParameters.regular.color ------------------- -- - ---[[ -WIPDOC -]] ----@class core.PlayerSkyParameters.regular.color.set ---[[ -WIPDOC -]] ----@field day_sky core.ColorSpec? ---[[ -WIPDOC -]] ----@field day_horizon core.ColorSpec? ---[[ -WIPDOC -]] ----@field dawn_sky core.ColorSpec? ---[[ -WIPDOC -]] ----@field dawn_horizon core.ColorSpec? ---[[ -WIPDOC -]] ----@field night_sky core.ColorSpec? ---[[ -WIPDOC -]] ----@field night_horizon core.ColorSpec? ---[[ -WIPDOC -]] ----@field indoors core.ColorSpec? ---[[ -WIPDOC -]] ----@field fog_sun_tint core.ColorSpec? ---[[ -WIPDOC -]] ----@field fog_moon_tint core.ColorSpec? ---[[ -WIPDOC -]] ----@field fog_tint_type "custom"|"default"? - ---[[ -WIPDOC -]] ----@class core.PlayerSkyParameters.regular.color.get ---[[ -WIPDOC -]] ----@field day_sky core.ColorSpec ---[[ -WIPDOC -]] ----@field day_horizon core.ColorSpec ---[[ -WIPDOC -]] ----@field dawn_sky core.ColorSpec ---[[ -WIPDOC -]] ----@field dawn_horizon core.ColorSpec ---[[ -WIPDOC -]] ----@field night_sky core.ColorSpec ---[[ -WIPDOC -]] ----@field night_horizon core.ColorSpec ---[[ -WIPDOC -]] ----@field indoors core.ColorSpec ---[[ -WIPDOC -]] ----@field fog_sun_tint core.ColorSpec ---[[ -WIPDOC -]] ----@field fog_moon_tint core.ColorSpec ---[[ -WIPDOC -]] ----@field fog_tint_type "custom"|"default" - - --- ------------------------- PlayerSkyParameters.fog ------------------------ -- - ---[[ -WIPDOC -]] ----@class core.PlayerSkyParameters.fog.set ---[[ -WIPDOC -]] ----@field fog_distance integer? ---[[ -WIPDOC -]] ----@field fog_start number? ---[[ -WIPDOC -]] ----@field fog_color core.ColorSpec? - ---[[ -WIPDOC -]] ----@class core.PlayerSkyParameters.fog.get ---[[ -WIPDOC -]] ----@field fog_distance integer ---[[ -WIPDOC -]] ----@field fog_start number ---[[ -WIPDOC -]] ----@field fog_color core.ColorSpec - - - --- ----------------------- PlayerSkyParameters.__base ----------------------- -- - ---[[ -WIPDOC -]] ----@class _.PlayerSkyParameters.__base.set ---[[ -WIPDOC -]] ----@field base_color core.ColorSpec? ---[[ -WIPDOC -]] ----@field body_orbit_tilt number? ---[[ -WIPDOC -]] ----@field textures {}? ---[[ -WIPDOC -]] ----@field clouds boolean? ---[[ -WIPDOC -]] ----@field fog core.PlayerSkyParameters.fog.set? - ---[[ -WIPDOC -]] ----@class _.PlayerSkyParameters.__base.get ---[[ -WIPDOC -]] ----@field base_color core.ColorSpec ---[[ -WIPDOC -]] ----@field body_orbit_tilt number ---[[ -WIPDOC -]] ----@field textures {} ---[[ -WIPDOC -]] ----@field clouds boolean ---[[ -WIPDOC -]] ----@field fog core.PlayerSkyParameters.fog.get - --- ----------------------- PlayerSkyParameters.regular ---------------------- -- - ---[[ -WIPDOC -]] ----@class core.PlayerSkyParameters.regular.set : _.PlayerSkyParameters.__base.set ---[[ -WIPDOC -]] ----@field type "regular" ---[[ -WIPDOC -]] ----@field sky_color core.PlayerSkyParameters.regular.color.set? - ---[[ -WIPDOC -]] ----@class core.PlayerSkyParameters.regular.get : _.PlayerSkyParameters.__base.get ---[[ -WIPDOC -]] ----@field type "regular" ---[[ -WIPDOC -]] ----@field sky_color core.PlayerSkyParameters.regular.color.get - --- ----------------------- PlayerSkyParameters.skybox ----------------------- -- - ---[[ -WIPDOC -]] ----@class core.PlayerSkyParameters.skybox.textures.strict ---[[ -WIPDOC -]] ----@field [1] core.Texture ---[[ -WIPDOC -]] ----@field [2] core.Texture ---[[ -WIPDOC -]] ----@field [3] core.Texture ---[[ -WIPDOC -]] ----@field [4] core.Texture ---[[ -WIPDOC -]] ----@field [5] core.Texture ---[[ -WIPDOC -]] ----@field [6] core.Texture - ---[[ -WIPDOC -]] ----@alias core.PlayerSkyParameters.skybox.textures ---- | core.PlayerSkyParameters.skybox.textures.strict ---- | core.Texture[] - ---[[ -WIPDOC -]] ----@class core.PlayerSkyParameters.skybox.set : _.PlayerSkyParameters.__base.set ---[[ -WIPDOC -]] ----@field type "skybox" ---[[ -WIPDOC -]] ----@field textures core.PlayerSkyParameters.skybox.textures? - ---[[ -WIPDOC -]] ----@class core.PlayerSkyParameters.skybox.get : _.PlayerSkyParameters.__base.get ---[[ -WIPDOC -]] ----@field type "skybox" ---[[ -WIPDOC -]] ----@field textures core.PlayerSkyParameters.skybox.textures - --- ------------------------ PlayerSkyParameters.plain ----------------------- -- - ---[[ -WIPDOC -]] ----@class core.PlayerSkyParameters.plain.set : _.PlayerSkyParameters.__base.set ---[[ -WIPDOC -]] ----@field type "plain" - ---[[ -WIPDOC -]] ----@class core.PlayerSkyParameters.plain.get : _.PlayerSkyParameters.__base.get ---[[ -WIPDOC -]] ----@field type "plain" - - --- --------------------------- PlayerSkyParameters -------------------------- -- - ----@alias core.PlayerSkyParameters.set ---- | core.PlayerSkyParameters.regular.set ---- | core.PlayerSkyParameters.skybox.set ---- | core.PlayerSkyParameters.plain.set - ----@alias core.PlayerSkyParameters.get ---- | core.PlayerSkyParameters.regular.get ---- | core.PlayerSkyParameters.skybox.get ---- | core.PlayerSkyParameters.plain.get - --- ---------------------------- PlayerRef methods --------------------------- -- - ----@class core.PlayerRef -local PlayerRef - ---[[ -WIPDOC -]] ----@param sky_parameters core.PlayerSkyParameters.set -function PlayerRef:set_sky(sky_parameters) end - ---[[ -* `get_sky(as_table)`: - * `as_table`: boolean that determines whether the deprecated version of this - function is being used. - * `true` returns a table containing sky parameters as defined in `set_sky(sky_parameters)`. - * Deprecated: `false` or `nil` returns base_color, type, table of textures, - clouds. -]] ----@nodiscard ----@param as_table true ----@return core.PlayerSkyParameters.get sky_parameters -function PlayerRef:get_sky(as_table) end - ---[[ -WIPDOC -]] ----@deprecated ----@param base_color core.ColorSpec ----@param type "regular"|"skybox"|"plain" ----@param textures core.Texture[] ----@param clouds boolean? -function PlayerRef:set_sky(base_color, type, textures, clouds) end - ---[[ -* `get_sky(as_table)`: - * `as_table`: boolean that determines whether the deprecated version of this - function is being used. - * `true` returns a table containing sky parameters as defined in `set_sky(sky_parameters)`. - * Deprecated: `false` or `nil` returns base_color, type, table of textures, - clouds. -]] ----@deprecated ----@nodiscard ----@return core.ColorSpec base_color, "regular"|"skybox"|"plain" type, core.Texture[] textures, boolean? clouds -function PlayerRef:get_sky(as_table) end - ---[[ -* `get_sky_color()`: - * Deprecated: Use `get_sky(as_table)` instead. - * returns a table with the `sky_color` parameters as in `set_sky`. -]] ----@deprecated ----@nodiscard ----@return core.PlayerSkyParameters.regular.color.get sky_color -function PlayerRef:get_sky_color() end \ No newline at end of file diff --git a/types/luanti_lsp_definitions/library/classes/ObjectRef/player_star.lua b/types/luanti_lsp_definitions/library/classes/ObjectRef/player_star.lua deleted file mode 100644 index 46174326..00000000 --- a/types/luanti_lsp_definitions/library/classes/ObjectRef/player_star.lua +++ /dev/null @@ -1,89 +0,0 @@ ----@meta _ --- DRAFT 1 DONE --- luanti/doc/lua_api.md: Class reference > `ObjectRef` - --- -------------------------- PlayerStarParameters -------------------------- -- - ---[[ -WIPDOC -]] ----@class core.PlayerStarParameters.set ---[[ -WIPDOC -]] ----@field visible boolean? ---[[ -WIPDOC -]] ----@field day_opacity number? ---[[ -WIPDOC -]] ----@field count integer? ---[[ -WIPDOC -]] ----@field star_color core.ColorSpec? ---[[ -WIPDOC -]] ----@field scale number? - ---[[ -WIPDOC -]] ----@class core.PlayerStarParameters.get ---[[ -WIPDOC -]] ----@field visible boolean ---[[ -WIPDOC -]] ----@field day_opacity number ---[[ -WIPDOC -]] ----@field count integer ---[[ -WIPDOC -]] ----@field star_color core.ColorSpec ---[[ -WIPDOC -]] ----@field scale number - --- ---------------------------- PlayerRef methods --------------------------- -- - ----@class core.PlayerRef -local PlayerRef - - ---[[ -* `set_stars(star_parameters)`: - * Passing no arguments resets stars to their default values. - * `star_parameters` is a table with the following optional fields: - * `visible`: Boolean for whether the stars are visible. - (default: `true`) - * `day_opacity`: Float for maximum opacity of stars at day. - No effect if `visible` is false. - (default: 0.0; maximum: 1.0; minimum: 0.0) - * `count`: Integer number to set the number of stars in - the skybox. Only applies to `"skybox"` and `"regular"` sky types. - (default: `1000`) - * `star_color`: ColorSpec, sets the colors of the stars, - alpha channel is used to set overall star brightness. - (default: `#ebebff69`) - * `scale`: Float controlling the overall size of the stars (default: `1`) -]] ----@param star_parameters core.PlayerStarParameters.set -function PlayerRef:set_stars(star_parameters) end - ---[[ -* `get_stars()`: returns a table with the current stars parameters as in - `set_stars`. -]] ----@nodiscard ----@return core.PlayerStarParameters.get star_parameters -function PlayerRef:get_stars() end \ No newline at end of file diff --git a/types/luanti_lsp_definitions/library/classes/ObjectRef/player_sun.lua b/types/luanti_lsp_definitions/library/classes/ObjectRef/player_sun.lua deleted file mode 100644 index 71d1acb5..00000000 --- a/types/luanti_lsp_definitions/library/classes/ObjectRef/player_sun.lua +++ /dev/null @@ -1,82 +0,0 @@ ----@meta _ --- DRAFT 1 DONE --- luanti/doc/lua_api.md: Class reference > `ObjectRef` - --- --------------------------- PlayerSunParameters -------------------------- -- - ---[[ -WIPDOC -]] ----@class core.PlayerSunParameters.set ---[[ -WIPDOC -]] ----@field visible boolean? ---[[ -WIPDOC -]] ----@field texture core.Texture? ---[[ -WIPDOC -]] ----@field tonemap core.Texture? ---[[ -WIPDOC -]] ----@field sunrise core.Texture? ---[[ -WIPDOC -]] ----@field sunrise_visible boolean? ---[[ -WIPDOC -]] ----@field scale number? - ---[[ -WIPDOC -]] ----@class core.PlayerSunParameters.get ---[[ -WIPDOC -]] ----@field visible boolean ---[[ -WIPDOC -]] ----@field texture core.Texture ---[[ -WIPDOC -]] ----@field tonemap core.Texture ---[[ -WIPDOC -]] ----@field sunrise core.Texture ---[[ -WIPDOC -]] ----@field sunrise_visible boolean ---[[ -WIPDOC -]] ----@field scale number - --- ---------------------------- PlayerRef methods --------------------------- -- - ----@class core.PlayerRef -local PlayerRef - ---[[ -WIPDOC -]] ----@param sun_parameters core.PlayerSunParameters.set -function PlayerRef:set_sun(sun_parameters) end - ---[[ -* `get_sun()`: returns a table with the current sun parameters as in - `set_sun`. -]] ----@nodiscard ----@return core.PlayerSunParameters.get sun_parameters -function PlayerRef:get_sun() end \ No newline at end of file diff --git a/types/luanti_lsp_definitions/library/classes/PcgRandom.lua b/types/luanti_lsp_definitions/library/classes/PcgRandom.lua deleted file mode 100644 index 85f694b6..00000000 --- a/types/luanti_lsp_definitions/library/classes/PcgRandom.lua +++ /dev/null @@ -1,66 +0,0 @@ ----@meta _ --- DRAFT 1 DONE --- luanti/doc/lua_api.md: Class reference > `PcgRandom` - --- ------------------------------- constructor ------------------------------ -- - ---[[ -WIPDOC -]] ----@nodiscard ----@param seed integer ----@param seq integer[]? ----@return core.PcgRandom -function PcgRandom(seed, seq) end - --- -------------------------------- PcgRandom ------------------------------- -- - ---[[ -WIPDOC -]] ----@class core.PcgRandom -PcgRandom = {} - ---[[ -* `next()`: return next integer random number [`-2147483648`...`2147483647`] -]] ----@nodiscard ----@return integer -function PcgRandom:next() end - ---[[ -* `next(min, max)`: return next integer random number [`min`...`max`] -]] ----@nodiscard ----@param min integer ----@param max integer ----@return integer -function PcgRandom:next(min, max) end - ---[[ -* `rand_normal_dist(min, max, num_trials=6)`: return normally distributed - random number [`min`...`max`]. - * This is only a rough approximation of a normal distribution with: - * `mean = (max - min) / 2`, and - * `variance = (((max - min + 1) ^ 2) - 1) / (12 * num_trials)` - * Increasing `num_trials` improves accuracy of the approximation -]] ----@nodiscard ----@param min integer ----@param max integer ----@param num_trials integer? ----@return integer -function PcgRandom:rand_normal_dist(min, max, num_trials) end - ---[[ -* `get_state()`: return generator state encoded in string -]] ----@nodiscard ----@return string state -function PcgRandom:get_state() end - ---[[ -* `set_state(state_string)`: restore generator state from encoded string -]] ----@param state string -function PcgRandom:set_state(state) end diff --git a/types/luanti_lsp_definitions/library/classes/PlayerMetaRef.lua b/types/luanti_lsp_definitions/library/classes/PlayerMetaRef.lua deleted file mode 100644 index a22807ac..00000000 --- a/types/luanti_lsp_definitions/library/classes/PlayerMetaRef.lua +++ /dev/null @@ -1,100 +0,0 @@ ----@meta _ --- DRAFT 1 DONE --- luanti/doc/lua_api.md: Class reference > `PlayerMetaRef` - --- NOTE: changes are linked to MetaDataRef, ItemStackMetaRef, NodeMetaRef, --- PlayerMetaRef and StorageRef - ---[[ -WIPDOC -]] ----@class core.PlayerMetaRef: core.MetaDataRef -local PlayerMetaRef = {} - ---[[ -* `contains(key)`: Returns true if key present, otherwise false. - * Returns `nil` when the MetaData is inexistent. -]] ----@nodiscard ----@param key core.MetadataTable.fields.player.keys ----@return boolean? -function PlayerMetaRef:contains(key) end - ---[[ -* `get(key)`: Returns `nil` if key not present, else the stored string. -]] ----@nodiscard ----@param key core.MetadataTable.fields.player.keys ----@return string? value -function PlayerMetaRef:get(key) end - ---[[ -* `set_string(key, value)`: Value of `""` will delete the key. -]] ----@param key core.MetadataTable.fields.player.keys ----@param value string -function PlayerMetaRef:set_string(key, value) end - ---[[ -* `get_string(key)`: Returns `""` if key not present. -]] ----@nodiscard ----@param key core.MetadataTable.fields.player.keys ----@return string value -function PlayerMetaRef:get_string(key) end - ---[[ -* `set_int(key, value)` - * The range for the value is system-dependent (usually 32 bits). - The value will be converted into a string when stored. -]] ----@param key core.MetadataTable.fields.player.keys.integer ----@param value integer -function PlayerMetaRef:set_int(key, value) end - ---[[ -* `get_int(key)`: Returns `0` if key not present. -]] ----@nodiscard ----@param key core.MetadataTable.fields.player.keys.integer ----@return integer value -function PlayerMetaRef:get_int(key) end - ---[[ -* `set_float(key, value)` - * Store a number (a 64-bit float) exactly. - * The value will be converted into a string when stored. -]] ----@param key core.MetadataTable.fields.player.keys.number ----@param value number -function PlayerMetaRef:set_float(key, value) end - ---[[ -WIPDOC -]] ----@nodiscard ----@param key core.MetadataTable.fields.player.keys.number ----@return number value -function PlayerMetaRef:get_float(key) end - ---[[ -WIPDOC -]] ----@nodiscard ----@return core.MetadataTable.fields.player.keys[] keys -function PlayerMetaRef:get_keys() end - ---[[ -WIPDOC -]] ----@nodiscard ----@param data core.MetadataTable.player ----@return boolean? -function PlayerMetaRef:from_table(data) end - ---[[ -WIPDOC -]] ----@nodiscard ----@return core.MetadataTable.player -function PlayerMetaRef:to_table() end diff --git a/types/luanti_lsp_definitions/library/classes/PseudoRandom.lua b/types/luanti_lsp_definitions/library/classes/PseudoRandom.lua deleted file mode 100644 index c5cbbe1b..00000000 --- a/types/luanti_lsp_definitions/library/classes/PseudoRandom.lua +++ /dev/null @@ -1,59 +0,0 @@ ----@meta _ --- DRAFT 1 DONE --- luanti/doc/lua_api.md: Class reference > `PseudoRandom` - --- ------------------------------- constructor ------------------------------ -- - ---[[ -WIPDOC -]] ----@nodiscard ----@param seed integer ----@return core.PseudoRandom -function PseudoRandom(seed) end - --- ------------------------------ PseudoRandom ------------------------------ -- - ---[[ -`PseudoRandom` --------------- - -A 16-bit pseudorandom number generator. -Uses a well-known LCG algorithm introduced by K&R. - -**Note**: -`PseudoRandom` is slower and has worse random distribution than `PcgRandom`. -Use `PseudoRandom` only if you need output to match the well-known LCG algorithm introduced by K&R. -Otherwise, use `PcgRandom`. - -* constructor `PseudoRandom(seed)` - * `seed`: 32-bit signed number -]] ----@class core.PseudoRandom -local PseudoRandom = {} - ---[[ -* `next()`: return next integer random number [`0`...`32767`] -]] ----@nodiscard ----@return integer -function PseudoRandom:next() end - ---[[ -* `next(min, max)`: return next integer random number [`min`...`max`] - * Either `max - min == 32767` or `max - min <= 6553` must be true - due to the simple implementation making a bad distribution otherwise. -]] ----@nodiscard ----@param min integer ----@param max integer ----@return integer -function PseudoRandom:next(min, max) end - ---[[ -* `get_state()`: return state of pseudorandom generator as number - * use returned number as seed in PseudoRandom constructor to restore -]] ----@nodiscard ----@return integer -function PseudoRandom:get_state() end \ No newline at end of file diff --git a/types/luanti_lsp_definitions/library/classes/Raycast.lua b/types/luanti_lsp_definitions/library/classes/Raycast.lua deleted file mode 100644 index a23af7b0..00000000 --- a/types/luanti_lsp_definitions/library/classes/Raycast.lua +++ /dev/null @@ -1,177 +0,0 @@ ----@meta _ --- DRAFT 1 DONE --- luanti/doc/lua_api.md: Representations of simple things --- luanti/doc/lua_api.md: 'core' namespace reference > Environment access --- luanti/doc/lua_api.md: Class reference > `Raycast` - --- ------------------------------- constructor ------------------------------ -- - ---[[ -* `core.raycast(pos1, pos2, objects, liquids, pointabilities)`: returns `Raycast` - * Creates a `Raycast` object. - * `pos1`: start of the ray - * `pos2`: end of the ray - * `objects`: if false, only nodes will be returned. Default is `true`. - * `liquids`: if false, liquid nodes (`liquidtype ~= "none"`) won't be - returned. Default is `false`. - * `pointabilities`: Allows overriding the `pointable` property of - nodes and objects. Uses the same format as the `pointabilities` property - of item definitions. Default is `nil`. -]] ----@nodiscard ----@param pos1 vector ----@param pos2 vector ----@param objects false ----@param liquids boolean? ----@param pointabilities core.ItemDef.pointabilities? ----@return core.Raycast.nodes -function Raycast(pos1, pos2, objects, liquids, pointabilities) end - ---[[ -* `core.raycast(pos1, pos2, objects, liquids, pointabilities)`: returns `Raycast` - * Creates a `Raycast` object. - * `pos1`: start of the ray - * `pos2`: end of the ray - * `objects`: if false, only nodes will be returned. Default is `true`. - * `liquids`: if false, liquid nodes (`liquidtype ~= "none"`) won't be - returned. Default is `false`. - * `pointabilities`: Allows overriding the `pointable` property of - nodes and objects. Uses the same format as the `pointabilities` property - of item definitions. Default is `nil`. -]] ----@nodiscard ----@param pos1 vector ----@param pos2 vector ----@param objects true? ----@param liquids false? ----@param pointabilities core.ItemDef.pointabilities? ----@return core.Raycast.objects -function Raycast(pos1, pos2, objects, liquids, pointabilities) end - ---[[ -* `core.raycast(pos1, pos2, objects, liquids, pointabilities)`: returns `Raycast` - * Creates a `Raycast` object. - * `pos1`: start of the ray - * `pos2`: end of the ray - * `objects`: if false, only nodes will be returned. Default is `true`. - * `liquids`: if false, liquid nodes (`liquidtype ~= "none"`) won't be - returned. Default is `false`. - * `pointabilities`: Allows overriding the `pointable` property of - nodes and objects. Uses the same format as the `pointabilities` property - of item definitions. Default is `nil`. -]] ----@nodiscard ----@param pos1 vector ----@param pos2 vector ----@param objects true? ----@param liquids true ----@param pointabilities core.ItemDef.pointabilities? ----@return core.Raycast.all -function Raycast(pos1, pos2, objects, liquids, pointabilities) end - ---[[ -* `core.raycast(pos1, pos2, objects, liquids, pointabilities)`: returns `Raycast` - * Creates a `Raycast` object. - * `pos1`: start of the ray - * `pos2`: end of the ray - * `objects`: if false, only nodes will be returned. Default is `true`. - * `liquids`: if false, liquid nodes (`liquidtype ~= "none"`) won't be - returned. Default is `false`. - * `pointabilities`: Allows overriding the `pointable` property of - nodes and objects. Uses the same format as the `pointabilities` property - of item definitions. Default is `nil`. -]] ----@nodiscard ----@param pos1 vector ----@param pos2 vector ----@param objects false ----@param liquids boolean? ----@param pointabilities core.ItemDef.pointabilities? ----@return core.Raycast.nodes -function core.raycast(pos1, pos2, objects, liquids, pointabilities) end - ---[[ -* `core.raycast(pos1, pos2, objects, liquids, pointabilities)`: returns `Raycast` - * Creates a `Raycast` object. - * `pos1`: start of the ray - * `pos2`: end of the ray - * `objects`: if false, only nodes will be returned. Default is `true`. - * `liquids`: if false, liquid nodes (`liquidtype ~= "none"`) won't be - returned. Default is `false`. - * `pointabilities`: Allows overriding the `pointable` property of - nodes and objects. Uses the same format as the `pointabilities` property - of item definitions. Default is `nil`. -]] ----@nodiscard ----@param pos1 vector ----@param pos2 vector ----@param objects true? ----@param liquids false? ----@param pointabilities core.ItemDef.pointabilities? ----@return core.Raycast.objects -function core.raycast(pos1, pos2, objects, liquids, pointabilities) end - ---[[ -* `core.raycast(pos1, pos2, objects, liquids, pointabilities)`: returns `Raycast` - * Creates a `Raycast` object. - * `pos1`: start of the ray - * `pos2`: end of the ray - * `objects`: if false, only nodes will be returned. Default is `true`. - * `liquids`: if false, liquid nodes (`liquidtype ~= "none"`) won't be - returned. Default is `false`. - * `pointabilities`: Allows overriding the `pointable` property of - nodes and objects. Uses the same format as the `pointabilities` property - of item definitions. Default is `nil`. -]] ----@nodiscard ----@param pos1 vector ----@param pos2 vector ----@param objects true? ----@param liquids true ----@param pointabilities core.ItemDef.pointabilities? ----@return core.Raycast.all -function core.raycast(pos1, pos2, objects, liquids, pointabilities) end - --- --------------------------------- Raycast -------------------------------- -- - ---[[ -WIPDOC -]] ----@class core.Raycast.nodes ----@operator call(): core.PointedThing.raycast.node -local RaycastNodes = {} - ---[[ -WIPDOC -]] ----@nodiscard ----@return core.PointedThing.raycast.node? -function RaycastNodes:next() end - ---[[ -WIPDOC -]] ----@class core.Raycast.objects ----@operator call(): core.PointedThing.raycast.object -local RaycastObjects = {} - ---[[ -WIPDOC -]] ----@nodiscard ----@return core.PointedThing.raycast.object? -function RaycastObjects:next() end - ---[[ -WIPDOC -]] ----@class core.Raycast.all ----@operator call(): core.PointedThing.raycast.all -local RaycastAll = {} - ---[[ -WIPDOC -]] ----@nodiscard ----@return core.PointedThing.raycast.all? -function RaycastAll:next() end \ No newline at end of file diff --git a/types/luanti_lsp_definitions/library/classes/SecureRandom.lua b/types/luanti_lsp_definitions/library/classes/SecureRandom.lua deleted file mode 100644 index 18acf5b7..00000000 --- a/types/luanti_lsp_definitions/library/classes/SecureRandom.lua +++ /dev/null @@ -1,40 +0,0 @@ ----@meta _ --- DRAFT 1 DONE --- luanti/doc/lua_api.md: Class reference > `SecureRandom` - --- ------------------------------- constructor ------------------------------ -- - ---[[ -WIPDOC -]] ----@nodiscard ----@return core.SecureRandom -function SecureRandom() end - --- ------------------------------ SecureRandom ------------------------------ -- - ---[[ -`SecureRandom` --------------- - -Interface for the operating system's crypto-secure PRNG. - -It can be created via `SecureRandom()`. The constructor throws an error if a -secure random device cannot be found on the system. - -### Methods - -* `next_bytes([count])`: return next `count` (default 1, capped at 2048) many - random bytes, as a string. -]] ----@class core.SecureRandom -SecureRandom = {} - ---[[ -* `next_bytes([count])`: return next `count` (default 1, capped at 2048) many - random bytes, as a string. -]] ----@nodiscard ----@param count integer ----@return string -function SecureRandom:next_bytes(count) end diff --git a/types/luanti_lsp_definitions/library/classes/Settings/LuantiSettings/LuantiSettings.lua b/types/luanti_lsp_definitions/library/classes/Settings/LuantiSettings/LuantiSettings.lua deleted file mode 100644 index 2928771c..00000000 --- a/types/luanti_lsp_definitions/library/classes/Settings/LuantiSettings/LuantiSettings.lua +++ /dev/null @@ -1,266 +0,0 @@ ----@meta _ --- DRAFT 1 DONE --- luanti/doc/lua_api.md: Class reference > `Settings` --- builtin/settingtypes.txt --- minetest.conf.example - ---[[ -WIPDOC -]] ----@type core.LuantiSettings -core.settings = nil - ---[[ -NOTE: types in a .conf settings file -- int -> integer -- string -> string -- bool -> boolean -- float -> number -- enum -> string -- path -> string -- filepath -> string -- key -> string -- flags -> flag table -- noise_params_2d -> noiseparams -- noise_params_3d -> noiseparams -- v3f -> vec -]] - ---[[ -WIPDOC -]] ----@class core.LuantiSettings.flags : string - ---[[ -WIPDOC -]] ----@alias core.LuantiSettings.path string - --- --------------------------- LuantiSettings.keys -------------------------- -- - ---[[ -WIPDOC -]] ----@alias core.LuantiSettings.keys.boolean ---- | _.LuantiSettings.advanced.keys.boolean ---- | _.LuantiSettings.client_and_server.keys.boolean ---- | string - ---[[ -WIPDOC -]] ----@alias core.LuantiSettings.keys.noise_params.2d ---- | _.LuantiSettings.mapgen.keys.noise_params.2d ---- | string - ---[[ -WIPDOC -]] ----@alias core.LuantiSettings.keys.noise_params.3d ---- | _.LuantiSettings.mapgen.keys.noise_params.3d ---- | string - ---[[ -WIPDOC -]] ----@alias core.LuantiSettings.keys.vector ---- | _.LuantiSettings.mapgen.keys.vector ---- | string - ---[[ -WIPDOC -]] ----@alias core.LuantiSettings.keys ---- | _.LuantiSettings.advanced.keys ---- | _.LuantiSettings.client_and_server.keys ---- | _.LuantiSettings.mapgen.keys ---- | string - --- ------------------------- LuantiSettings.tablefmt ------------------------ -- - ---[[ -WIPDOC -]] ----@class core.LuantiSettings.tablefmt : _.LuantiSettings.advanced.tablefmt, _.LuantiSettings.client_and_server.tablefmt, _.LuantiSettings.mapgen.tablefmt - --- ----------------------------- LuantiSettings ----------------------------- -- - ---[[ -### Format - -The settings have the format `key = value`. Example: - - foo = example text - bar = """ - Multiline - value - """ -]] ----@class core.LuantiSettings -local LuantiSettings = {} - ---[[ LuantiSettings:get() split off into ./settings_enums.lua ]]-- - ---[[ -* `get(key)`: returns a value - * Returns `nil` if `key` is not found. -]] ----@nodiscard ----@param key core.LuantiSettings.keys ----@return string? value -function LuantiSettings:get(key) end - ---[[ -* `get_bool(key, [default])`: returns a boolean - * `default` is the value returned if `key` is not found. - * Returns `nil` if `key` is not found and `default` not specified. -]] ----@nodiscard ----@param key core.LuantiSettings.keys.boolean ----@return boolean? value -function LuantiSettings:get_bool(key) end - ---[[ -* `get_bool(key, [default])`: returns a boolean - * `default` is the value returned if `key` is not found. - * Returns `nil` if `key` is not found and `default` not specified. -]] ----@nodiscard ----@generic T ----@param key core.LuantiSettings.keys.boolean ----@param default T ----@return boolean|T value -function LuantiSettings:get_bool(key, default) end - ---[[ -* `get_np_group(key)`: returns a NoiseParams table - * Returns `nil` if `key` is not found. -]] ----@nodiscard ----@param key core.LuantiSettings.keys.noise_params.2d ----@return core.NoiseParams.2d? value -function LuantiSettings:get_np_group(key) end - ---[[ -* `get_np_group(key)`: returns a NoiseParams table - * Returns `nil` if `key` is not found. -]] ----@nodiscard ----@param key core.LuantiSettings.keys.noise_params.3d ----@return core.NoiseParams.3d? value -function LuantiSettings:get_np_group(key) end - ---[[ LuantiSettings:get_flags() split off into ./settings_flags.lua ]]-- - ---[[ -* `get_flags(key)`: - * Returns `{flag = true/false, ...}` according to the set flags. - * Is currently limited to mapgen flags `mg_flags` and mapgen-specific - flags like `mgv5_spflags`. - * Returns `nil` if `key` is not found. -]] ----@nodiscard ----@param key string ----@return table? value -function LuantiSettings:get_flags(key) end - ---[[ -* `get_pos(key)`: - * Returns a `vector` - * Returns `nil` if no value is found or parsing failed. -]] ----@nodiscard ----@param key core.LuantiSettings.keys.vector ----@return vec? value -function LuantiSettings:get_pos(key) end - ---[[ LuantiSettings:set() split off into ./settings_enums.lua ]]-- - ---[[ -* `set(key, value)` - * Setting names can't contain whitespace or any of `="{}#`. - * Setting values can't contain the sequence `\n"""`. - * Setting names starting with "secure." can't be set on the main settings - object (`core.settings`). -]] ----@param key core.LuantiSettings.keys ----@param value string -function LuantiSettings:set(key, value) end - ---[[ -* `set_bool(key, value)` - * See documentation for `set()` above. -]] ----@param key core.LuantiSettings.keys.boolean ----@param value boolean -function LuantiSettings:set_bool(key, value) end - ---[[ -* `set_np_group(key, value)` - * `value` is a NoiseParams table. - * Also, see documentation for `set()` above. -]] ----@param key core.LuantiSettings.keys.noise_params.2d ----@param value core.NoiseParams.2d -function LuantiSettings:set_np_group(key, value) end - ---[[ -* `set_np_group(key, value)` - * `value` is a NoiseParams table. - * Also, see documentation for `set()` above. -]] ----@param key core.LuantiSettings.keys.noise_params.3d ----@param value core.NoiseParams.3d -function LuantiSettings:set_np_group(key, value) end - ---[[ -* `set_pos(key, value)` - * `value` is a `vector`. - * Also, see documentation for `set()` above. -]] ----@param key core.LuantiSettings.keys.vector ----@param value vector -function LuantiSettings:set_pos(key, value) end - ---[[ -* `remove(key)`: returns a boolean (`true`) for success -]] ----@nodiscard ----@param key core.LuantiSettings.keys ----@return boolean -function LuantiSettings:remove(key) end - ---[[ -* `get_names()`: returns `{key1,...}` -]] ----@nodiscard ----@return core.LuantiSettings.keys[] keys -function LuantiSettings:get_names() end - ---[[ -* `has(key)`: - * Returns a boolean indicating whether `key` exists. - * In contrast to the various getter functions, `has()` doesn't consider - any default values. - * This means that on the main settings object (`core.settings`), - `get(key)` might return a value even if `has(key)` returns `false`. -]] ----@nodiscard ----@param key core.LuantiSettings.keys ----@return boolean -function LuantiSettings:has(key) end - ---[[ -* `write()`: returns a boolean (`true` for success - * Writes changes to file. -]] ----@nodiscard ----@return boolean -function LuantiSettings:write() end - ---[[ -* `to_table()`: returns `{[key1]=value1,...}` -]] ----@nodiscard ----@return core.LuantiSettings.tablefmt -function LuantiSettings:to_table() end diff --git a/types/luanti_lsp_definitions/library/classes/Settings/LuantiSettings/advanced.lua b/types/luanti_lsp_definitions/library/classes/Settings/LuantiSettings/advanced.lua deleted file mode 100644 index 91d0a54b..00000000 --- a/types/luanti_lsp_definitions/library/classes/Settings/LuantiSettings/advanced.lua +++ /dev/null @@ -1,1398 +0,0 @@ ----@meta _ --- DRAFT 1 DONE --- builtin/settingtypes.txt --- minetest.conf.example - --- NOTE: because there's so much contexts used, it must be specified via ctx_* --- Section context mapping: --- * [Advanced] [*Developer options] [**Mod Security]: [server] --- * [Advanced] [*Developer options] [**Mod Profiler]: [server] --- * [Advanced] [*Developer options] [**Engine Profiler]: [common] --- * [Advanced] [*Advanced] [**Graphics]: [client] --- * [Advanced] [*Advanced] [**Sound]: [client] --- * [Advanced] [*Advanced] [**Font]: [client] --- * [Advanced] [*Advanced] [**Lighting]: [client] --- * [Advanced] [*Advanced] [**Server]: [server] --- * [Advanced] [*Advanced] [**Server/Env Performance]: [server] --- * [Advanced] [*Advanced] [**Mapgen]: [server] --- * [Advanced] [*Advanced] [**cURL]: [common] --- * [Advanced] [*Advanced] [**Client Debugging]: [client] --- * [Advanced] [*Gamepads]: [client] --- * [Advanced] [*Hide: Temporary Settings]: [common] - ----@alias _.LuantiSettings.advanced.keys.boolean ---- | "secure.enable_security" ---- | "random_mod_load_order" ---- | "enable_mod_channels" ---- | "profiler.load" ---- | "instrument.entity" ---- | "instrument.abm" ---- | "instrument.lbm" ---- | "instrument.chatcommand" ---- | "instrument.global_callback" ---- | "instrument.builtin" ---- | "instrument.profiler" ---- | "enable_ipv6" ---- | "ask_reconnect_on_crash" ---- | "unlimited_player_transfer_distance" ---- | "server_side_occlusion_culling" ---- | "enable_mapgen_debug_info" ---- | "enable_console" ---- | "ignore_world_load_errors" ---- | "enable_remote_media_server" ---- | "enable_minimap" ---- | "minimap_shape_round" ---- | "enable_damage" ---- | "creative_mode" ---- | "enable_pvp" ---- | "free_move" ---- | "pitch_move" ---- | "fast_move" ---- | "noclip" ---- | "continuous_forward" ---- | "cinematic" ---- | "show_technical_names" ---- | "show_advanced" - ----@alias _.LuantiSettings.advanced.keys ---- | "secure.enable_security" ---- | "secure.trusted_mods" ---- | "secure.http_mods" ---- | "debug_log_level" ---- | "debug_log_size_max" ---- | "deprecated_lua_api_handling" ---- | "random_mod_load_order" ---- | "enable_mod_channels" ---- | "profiler.load" ---- | "profiler.default_report_format" ---- | "profiler.report_path" ---- | "instrument.entity" ---- | "instrument.abm" ---- | "instrument.lbm" ---- | "instrument.chatcommand" ---- | "instrument.global_callback" ---- | "instrument.builtin" ---- | "instrument.profiler" ---- | "profiler_print_interval" ---- | "enable_ipv6" ---- | "max_packets_per_iteration" ---- | "prometheus_listener_address" ---- | "max_simultaneous_block_sends_per_client" ---- | "full_block_send_enable_min_time_from_building" ---- | "map_compression_level_net" ---- | "chat_message_format" ---- | "chatcommand_msg_time_threshold" ---- | "kick_msg_shutdown" ---- | "kick_msg_crash" ---- | "ask_reconnect_on_crash" ---- | "dedicated_server_step" ---- | "unlimited_player_transfer_distance" ---- | "player_transfer_distance" ---- | "active_object_send_range_blocks" ---- | "active_block_range" ---- | "max_block_send_distance" ---- | "max_forceloaded_blocks" ---- | "server_map_save_interval" ---- | "server_unload_unused_data_timeout" ---- | "max_objects_per_block" ---- | "active_block_mgmt_interval" ---- | "abm_interval" ---- | "abm_time_budget" ---- | "nodetimer_interval" ---- | "liquid_loop_max" ---- | "liquid_queue_purge_time" ---- | "liquid_update" ---- | "block_send_optimize_distance" ---- | "server_side_occlusion_culling" ---- | "block_cull_optimize_distance" ---- | "chunksize" ---- | "enable_mapgen_debug_info" ---- | "emergequeue_limit_total" ---- | "emergequeue_limit_diskonly" ---- | "emergequeue_limit_generate" ---- | "num_emerge_threads" ---- | "curl_timeout" ---- | "curl_parallel_limit" ---- | "curl_file_download_timeout" ---- | "enable_console" ---- | "clickable_chat_weblinks" ---- | "display_density_factor" ---- | "ignore_world_load_errors" ---- | "max_clearobjects_extra_loaded_blocks" ---- | "map-dir" ---- | "sqlite_synchronous" ---- | "map_compression_level_disk" ---- | "enable_remote_media_server" ---- | "serverlist_file" ---- | "texture_path" ---- | "enable_minimap" ---- | "minimap_shape_round" ---- | "address" ---- | "remote_port" ---- | "enable_damage" ---- | "creative_mode" ---- | "enable_pvp" ---- | "free_move" ---- | "pitch_move" ---- | "fast_move" ---- | "noclip" ---- | "continuous_forward" ---- | "cinematic" ---- | "show_technical_names" ---- | "show_advanced" - ----@class _.LuantiSettings.advanced.tablefmt : _.LuantiSettings.advanced.developer_options.mod_security.ctx_server, _.LuantiSettings.advanced.developer_options.debugging.ctx_server, _.LuantiSettings.advanced.developer_options.mod_profiler.ctx_server, _.LuantiSettings.advanced.developer_options.engine_profiler.ctx_server, _.LuantiSettings.advanced.advanced.networking.ctx_server, _.LuantiSettings.advanced.advanced.server.ctx_server, _.LuantiSettings.advanced.advanced.server_env_performance.ctx_server, _.LuantiSettings.advanced.advanced.mappgen.ctx_server, _.LuantiSettings.advanced.advanced.cURL.ctx_server, _.LuantiSettings.advanced.advanced.miscellaneous.ctx_server, _.LuantiSettings.advanced.hide_temporary_settings.ctx_server - --- ------------------------------- [Advanced] ------------------------------- -- - --- --------------------- [Advanced] [*Developer Options] -------------------- -- - ----@class _.LuantiSettings.advanced.developer_options.ctx_client ---[[ -# Enable Lua modding support on client. -# This support is experimental and API can change. -[client] -(Client modding) false -]] ----@field enable_client_modding boolean? ---[[ -# Replaces the default main menu with a custom one. -[client] -(Main menu script) -]] ----@field main_menu_script string? - --- ------------ [Advanced] [*Developer Options] [**Mod Security] ------------ -- - ----@class _.LuantiSettings.advanced.developer_options.mod_security.ctx_server ---[[ -# Prevent mods from doing insecure things like running shell commands. -[server] -(Enable mod security) true -]] ----@field ["secure.enable_security"] boolean? ---[[ -# Comma-separated list of trusted mods that are allowed to access insecure -# functions even when mod security is on (via request_insecure_environment()). -[server] -(Trusted mods) -]] ----@field ["secure.trusted_mods"] string? ---[[ -# Comma-separated list of mods that are allowed to access HTTP APIs, which -# allow them to upload and download data to/from the internet. -[server] -(HTTP mods) -]] ----@field ["secure.http_mods"] string? - --- -------------- [Advanced] [*Developer Options] [**Debugging] ------------- -- - ---[[ -WIPDOC -]] ----@alias core.LuantiSettings.enums.debug_log_level ---- | "" ---- | "none" ---- | "error" ---- | "warning" ---- | "action" ---- | "info" ---- | "verbose" ---- | "trace" - ---[[ -WIPDOC -]] ----@alias core.LuantiSettings.enums.deprecated_lua_api_handling ---- | "none" ---- | "log" ---- | "error" - ----@class _.LuantiSettings.advanced.developer_options.debugging.ctx_common ---[[ -# Level of logging to be written to debug.txt: -# - (no logging) -# - none (messages with no level) -# - error -# - warning -# - action -# - info -# - verbose -# - trace -[common] -(Debug log level) action ,none,error,warning,action,info,verbose,trace -]] ----@field debug_log_level core.LuantiSettings.enums.debug_log_level? ---[[ -# If the file size of debug.txt exceeds the number of megabytes specified in -# this setting when it is opened, the file is moved to debug.txt.1, -# deleting an older debug.txt.1 if it exists. -# debug.txt is only moved if this setting is positive. -[common] -(Debug log file size threshold) 50 1 -]] ----@field debug_log_size_max integer? ---[[ -# Handling for deprecated Lua API calls: -# - none: Do not log deprecated calls -# - log: mimic and log backtrace of deprecated call (default). -# - error: abort on usage of deprecated call (suggested for mod developers). -[common] -(Deprecated Lua API handling) log none,log,error -]] ----@field deprecated_lua_api_handling core.LuantiSettings.enums.deprecated_lua_api_handling? - ---[[ -WIPDOC -]] ----@alias core.LuantiSettings.enums.chat_log_level ---- | "" ---- | "none" ---- | "error" ---- | "warning" ---- | "action" ---- | "info" ---- | "verbose" ---- | "trace" - ----@class _.LuantiSettings.advanced.developer_options.debugging.ctx_client : _.LuantiSettings.advanced.developer_options.debugging.ctx_common ---[[ -# Minimal level of logging to be written to chat. -[client] -(Chat log level) error ,none,error,warning,action,info,verbose,trace -]] ----@field chat_log_level core.LuantiSettings.enums.chat_log_level? ---[[ -# Enable random user input (only used for testing). -[client] -(Random input) false -]] ----@field random_input boolean? - - ----@class _.LuantiSettings.advanced.developer_options.debugging.ctx_server : _.LuantiSettings.advanced.developer_options.debugging.ctx_common ---[[ -# Enable random mod loading (mainly used for testing). -[server] -(Random mod load order) false -]] ----@field random_mod_load_order boolean? ---[[ -# Enable mod channels support. -[server] -(Mod channels) false -]] ----@field enable_mod_channels boolean? - --- ------------ [Advanced] [*Developer Options] [**Mod Profiler] ------------ -- - ---[[ -WIPDOC -]] ----@alias core.LuantiSettings.enums.profiler.default_report_format ---- | "txt" ---- | "csv" ---- | "lua" ---- | "json" ---- | "json_pretty" - ----@class _.LuantiSettings.advanced.developer_options.mod_profiler.ctx_server ---[[ -# Load the game profiler to collect game profiling data. -# Provides a /profiler command to access the compiled profile. -# Useful for mod developers and server operators. -[server] -(Load the game profiler) false -]] ----@field ["profiler.load"] boolean? ---[[ -# The default format in which profiles are being saved, -# when calling `/profiler save [format]` without format. -[server] -(Default report format) txt txt,csv,lua,json,json_pretty -]] ----@field ["profiler.default_report_format"] core.LuantiSettings.enums.profiler.default_report_format? ---[[ -# The file path relative to your world path in which profiles will be saved to. -[server] -(Report path) -]] ----@field ["profiler.report_path"] string? ---[[ -# Instrument the methods of entities on registration. -[server] -(Entity methods) true -]] ----@field ["instrument.entity"] boolean? ---[[ -# Instrument the action function of Active Block Modifiers on registration. -[server] -(Active Block Modifiers) true -]] ----@field ["instrument.abm"] boolean? ---[[ -# Instrument the action function of Loading Block Modifiers on registration. -[server] -(Loading Block Modifiers) true -]] ----@field ["instrument.lbm"] boolean? ---[[ -# Instrument chat commands on registration. -[server] -(Chat commands) true -]] ----@field ["instrument.chatcommand"] boolean? ---[[ -# Instrument global callback functions on registration. -# (anything you pass to a core.register_*() function) -[server] -(Global callbacks) true -]] ----@field ["instrument.global_callback"] boolean? ---[[ -# Instrument builtin. -# This is usually only needed by core/builtin contributors -[server] -(Builtin) false -]] ----@field ["instrument.builtin"] boolean? ---[[ -# Have the profiler instrument itself: -# * Instrument an empty function. -# This estimates the overhead, that instrumentation is adding (+1 function call). -# * Instrument the sampler being used to update the statistics. -[server] -(Profiler) false -]] ----@field ["instrument.profiler"] boolean? - --- ----------- [Advanced] [*Developer Options] [**Engine Profiler] ---------- -- - ----@class _.LuantiSettings.advanced.developer_options.engine_profiler.ctx_common ---[[ -# Print the engine's profiling data in regular intervals (in seconds). -# 0 = disable. Useful for developers. -[common] -(Engine profiling data print interval) 0 0 -]] ----@field profiler_print_interval integer? - ----@class _.LuantiSettings.advanced.developer_options.engine_profiler.ctx_client : _.LuantiSettings.advanced.developer_options.engine_profiler.ctx_common - ----@class _.LuantiSettings.advanced.developer_options.engine_profiler.ctx_server : _.LuantiSettings.advanced.developer_options.engine_profiler.ctx_common - --- ------------------------- [Advanced] [*Advanced] ------------------------- -- - --- ------------------- [Advanced] [*Advanced] [**Graphics] ------------------ -- - ---[[ -WIPDOC -]] ----@alias core.LuantiSettings.enums.video_driver ---- | "" ---- | "opengl" ---- | "opengl3" ---- | "ogles2" - ----@class _.LuantiSettings.advanced.advanced.graphics.ctx_client ---[[ -# Enables debug and error-checking in the OpenGL driver. -[client] -(OpenGL debug) false -]] ----@field opengl_debug boolean? ---[[ -# Path to shader directory. If no path is defined, default location will be used. -[client] -(Shader path) -]] ----@field shader_path core.LuantiSettings.path? ---[[ -# The rendering back-end. -# Note: A restart is required after changing this! -# OpenGL is the default for desktop, and OGLES2 for Android. -[client] -(Video driver) ,opengl,opengl3,ogles2 -]] ----@field video_driver core.LuantiSettings.enums.video_driver? ---[[ -# Distance in nodes at which transparency depth sorting is enabled. -# Use this to limit the performance impact of transparency depth sorting. -# Set to 0 to disable it entirely. -[client] -(Transparency Sorting Distance) 16 0 128 -]] ----@field transparency_sorting_distance integer? ---[[ -# Draw transparency sorted triangles grouped by their mesh buffers. -# This breaks transparency sorting between mesh buffers, but avoids situations -# where transparency sorting would be very slow otherwise. -[client] -(Transparency Sorting Group by Buffers) true -]] ----@field transparency_sorting_group_by_buffers boolean? ---[[ -# Radius of cloud area stated in number of 64 node cloud squares. -# Values larger than 26 will start to produce sharp cutoffs at cloud area corners. -[client] -(Cloud radius) 12 8 62 -]] ----@field cloud_radius integer? ---[[ -# Delay between mesh updates on the client in ms. Increasing this will slow -# down the rate of mesh updates, which can help reduce jitter. -[client] -(Mapblock mesh generation delay) 0 0 25 -]] ----@field mesh_generation_interval integer? ---[[ -# Number of threads to use for mesh generation. -# Value of 0 (default) will let Luanti automatically choose the number of threads. -[client] -(Mapblock mesh generation threads) 0 0 8 -]] ----@field mesh_generation_threads integer? ---[[ -# All mesh buffers with less than this number of vertices will be merged -# during map rendering. This improves rendering performance. -[client] -(Minimum vertex count for mesh buffers) 300 0 1000 -]] ----@field mesh_buffer_min_vertices integer? ---[[ -# True = 256 -# False = 128 -# Usable to make minimap smoother on slower machines. -[client] -(Minimap scan height) true -]] ----@field minimap_double_scan_height boolean? - ---[[ -WIPDOC -]] ----@alias core.LuantiSettings.enums.world_aligned_mode ---- | "disable" ---- | "enable" ---- | "force_solid" ---- | "force_nodebox" - ----@class _.LuantiSettings.advanced.advanced.graphics.ctx_client ---[[ -# Textures on a node may be aligned either to the node or to the world. -# The former mode suits better things like machines, furniture, etc., while -# the latter makes stairs and microblocks fit surroundings better. -# However, as this possibility is new, thus may not be used by older servers, -# this option allows enforcing it for certain node types. Note though that -# that is considered EXPERIMENTAL and may not work properly. -[client] -(World-aligned textures mode) enable disable,enable,force_solid,force_nodebox -]] ----@field world_aligned_mode core.LuantiSettings.enums.world_aligned_mode? - ---[[ -WIPDOC -]] ----@alias core.LuantiSettings.enums.autoscale_mode ---- | "disable" ---- | "enable" ---- | "force" - ----@class _.LuantiSettings.advanced.advanced.graphics.ctx_client ---[[ -# World-aligned textures may be scaled to span several nodes. However, -# the server may not send the scale you want, especially if you use -# a specially-designed texture pack; with this option, the client tries -# to determine the scale automatically based on the texture size. -# See also texture_min_size. -# Warning: This option is EXPERIMENTAL! -[client] -(Autoscaling mode) disable disable,enable,force -]] ----@field autoscale_mode core.LuantiSettings.enums.autoscale_mode? ---[[ -# When using bilinear/trilinear filtering, low-resolution textures -# can be blurred, so this option automatically upscales them to preserve -# crisp pixels. This defines the minimum texture size for the upscaled textures; -# higher values look sharper, but require more memory. -# This setting is ONLY applied if any of the mentioned filters are enabled. -# This is also used as the base node texture size for world-aligned -# texture autoscaling. -[client] -(Base texture size) 192 192 16384 -]] ----@field texture_min_size integer? ---[[ -# Side length of a cube of map blocks that the client will consider together -# when generating meshes. -# Larger values increase the utilization of the GPU by reducing the number of -# draw calls, benefiting especially high-end GPUs. -# Systems with a low-end GPU (or no GPU) would benefit from smaller values. -[client] -(Client Mesh Chunksize) 1 1 16 -]] ----@field client_mesh_chunk integer? - ---[[ -WIPDOC -]] ----@alias core.LuantiSettings.enums.post_processing_texture_bits ---- | "8" ---- | "10" ---- | "16" - ----@class _.LuantiSettings.advanced.advanced.graphics.ctx_client ---[[ -# Decide the color depth of the texture used for the post-processing pipeline. -# Reducing this can improve performance, but some effects (e.g. debanding) -# require more than 8 bits to work. -# -# Requires: enable_post_processing -[client] -(Color depth for post-processing texture) 16 8,10,16 -]] ----@field post_processing_texture_bits core.LuantiSettings.enums.post_processing_texture_bits? ---[[ -# Enable Poisson disk filtering. -# On true uses Poisson disk to make "soft shadows". Otherwise uses PCF filtering. -# -# Requires: enable_dynamic_shadows, opengl -[client] -(Poisson filtering) true -]] ----@field shadow_poisson_filter boolean? ---[[ -# Spread a complete update of the shadow map over a given number of frames. -# Higher values might make shadows laggy, lower values -# will consume more resources. -# -# Requires: enable_dynamic_shadows, opengl -[client] -(Map shadows update frames) 16 1 32 -]] ----@field shadow_update_frames integer? ---[[ -# Set to true to render debugging breakdown of the bloom effect. -# In debug mode, the screen is split into 4 quadrants: -# top-left - processed base image, top-right - final image -# bottom-left - raw base image, bottom-right - bloom texture. -# -# Requires: enable_post_processing, enable_bloom -[client] -(Enable Bloom Debug) false -]] ----@field enable_bloom_debug boolean? - --- -------------------- [Advanced] [*Advanced] [**Sound] -------------------- -- - ----@class _.LuantiSettings.advanced.advanced.sound.ctx_client ---[[ -# Comma-separated list of AL and ALC extensions that should not be used. -# Useful for testing. See al_extensions.[h,cpp] for details. -[client] -(Sound Extensions Blacklist) -]] ----@field sound_extensions_blacklist string? - --- --------------------- [Advanced] [*Advanced] [**Font] -------------------- -- - ----@class _.LuantiSettings.advanced.advanced.font.ctx_client ---[[ -[client] -(Font bold by default) false -]] ----@field font_bold boolean? ---[[ -[client] -(Font italic by default) false -]] ----@field font_italic boolean? ---[[ -# Shadow offset (in pixels) of the default font. If 0, then shadow will not be drawn. -[client] -(Font shadow) 1 0 65535 -]] ----@field font_shadow integer? ---[[ -# Opaqueness (alpha) of the shadow behind the default font, between 0 and 255. -[client] -(Font shadow alpha) 127 0 255 -]] ----@field font_shadow_alpha integer? ---[[ -# Font size of the default font where 1 unit = 1 pixel at 96 DPI -[client] -(Font size) 16 5 72 -]] ----@field font_size integer? ---[[ -# For pixel-style fonts that do not scale well, this ensures that font sizes used -# with this font will always be divisible by this value, in pixels. For instance, -# a pixel font 16 pixels tall should have this set to 16, so it will only ever be -# sized 16, 32, 48, etc., so a mod requesting a size of 25 will get 32. -[client] -(Font size divisible by) 1 1 -]] ----@field font_size_divisible_by integer? ---[[ -# Path to the default font. Must be a TrueType font. -# The fallback font will be used if the font cannot be loaded. -[client] -(Regular font path) fonts/Arimo-Regular.ttf -]] ----@field font_path core.LuantiSettings.path? ---[[ -# Path to the default bold font. Must be a TrueType font. -# The fallback font will be used if the font cannot be loaded. -[client] -(Bold font path) fonts/Arimo-Bold.ttf -]] ----@field font_path_bold core.LuantiSettings.path? ---[[ -# Path to the default italic font. Must be a TrueType font. -# The fallback font will be used if the font cannot be loaded. -[client] -(Italic font path) fonts/Arimo-Italic.ttf -]] ----@field font_path_italic core.LuantiSettings.path? ---[[ -# Path to the default bold italic font. Must be a TrueType font. -# The fallback font will be used if the font cannot be loaded. -[client] -(Bold and Italic font path) fonts/Arimo-BoldItalic.ttf -]] ----@field font_path_bold_italic core.LuantiSettings.path? ---[[ -# Font size of the monospace font where 1 unit = 1 pixel at 96 DPI -[client] -(Monospace font size) 16 5 72 -]] ----@field mono_font_size integer? ---[[ -# For pixel-style fonts that do not scale well, this ensures that font sizes used -# with this font will always be divisible by this value, in pixels. For instance, -# a pixel font 16 pixels tall should have this set to 16, so it will only ever be -# sized 16, 32, 48, etc., so a mod requesting a size of 25 will get 32. -[client] -(Monospace font size divisible by) 1 1 -]] ----@field mono_font_size_divisible_by integer? ---[[ -# Path to the monospace font. Must be a TrueType font. -# This font is used for e.g. the console and profiler screen. -[client] -(Monospace font path) fonts/Cousine-Regular.ttf -]] ----@field mono_font_path core.LuantiSettings.path? ---[[ -# Path to the bold monospace font. Must be a TrueType font. -# This font is used for e.g. the console and profiler screen. -[client] -(Bold monospace font path) fonts/Cousine-Bold.ttf -]] ----@field mono_font_path_bold core.LuantiSettings.path? ---[[ -# Path to the italic monospace font. Must be a TrueType font. -# This font is used for e.g. the console and profiler screen. -[client] -(Italic monospace font path) fonts/Cousine-Italic.ttf -]] ----@field mono_font_path_italic core.LuantiSettings.path? ---[[ -# Path to the bold italic monospace font. Must be a TrueType font. -# This font is used for e.g. the console and profiler screen. -[client] -(Bold and italic monospace font path) fonts/Cousine-BoldItalic.ttf -]] ----@field mono_font_path_bold_italic core.LuantiSettings.path? ---[[ -# Path of the fallback font. Must be a TrueType font. -# This font will be used for certain languages or if the default font is unavailable. -[client] -(Fallback font path) fonts/DroidSansFallbackFull.ttf -]] ----@field fallback_font_path core.LuantiSettings.path? - --- ------------------- [Advanced] [*Advanced] [**Lighting] ------------------ -- - ----@class _.LuantiSettings.advanced.advanced.lighting.ctx_client ---[[ -# Gradient of light curve at minimum light level. -# Controls the contrast of the lowest light levels. -[client] -(Light curve low gradient) 0.0 0.0 3.0 -]] ----@field lighting_alpha number? ---[[ -# Gradient of light curve at maximum light level. -# Controls the contrast of the highest light levels. -[client] -(Light curve high gradient) 1.5 0.0 3.0 -]] ----@field lighting_beta number? ---[[ -# Strength of light curve boost. -# The 3 'boost' parameters define a range of the light -# curve that is boosted in brightness. -[client] -(Light curve boost) 0.2 0.0 0.4 -]] ----@field lighting_boost number? ---[[ -# Center of light curve boost range. -# Where 0.0 is minimum light level, 1.0 is maximum light level. -[client] -(Light curve boost center) 0.5 0.0 1.0 -]] ----@field lighting_boost_center number? ---[[ -# Spread of light curve boost range. -# Controls the width of the range to be boosted. -# Standard deviation of the light curve boost Gaussian. -[client] -(Light curve boost spread) 0.2 0.0 0.4 -]] ----@field lighting_boost_spread number? - --- ------------------ [Advanced] [*Advanced] [**Networking] ----------------- -- - ----@class _.LuantiSettings.advanced.advanced.networking.ctx_common ---[[ -# Enable IPv6 support (for both client and server). -# Required for IPv6 connections to work at all. -[common] -(IPv6) true -]] ----@field enable_ipv6 boolean? ---[[ -# Maximum number of packets sent per send step in the low-level networking code. -# You generally don't need to change this, however busy servers may benefit from a higher number. -[common] -(Max. packets per iteration) 1024 1 65535 -]] ----@field max_packets_per_iteration integer? - ----@class _.LuantiSettings.advanced.advanced.networking.ctx_server : _.LuantiSettings.advanced.advanced.networking.ctx_common ---[[ -# Prometheus listener address. -# If Luanti is compiled with Prometheus support, this setting -# enables the metrics listener for Prometheus on that address. -# By default you can fetch metrics from http://127.0.0.1:30000/metrics. -# An empty value disables the metrics listener. -[server] -(Prometheus listener address) 127.0.0.1:30000 -]] ----@field prometheus_listener_address string? ---[[ -# Maximum number of blocks that are simultaneously sent per client. -# The maximum total count is calculated dynamically: -# max_total = ceil((#clients + max_users) * per_client / 4) -[server] -(Maximum simultaneous block sends per client) 40 1 4294967295 -]] ----@field max_simultaneous_block_sends_per_client integer? ---[[ -# To reduce lag, block transfers are slowed down when a player is building something. -# This determines how long they are slowed down after placing or removing a node. -[server] -(Delay in sending blocks after building) 2.0 0.0 -]] ----@field full_block_send_enable_min_time_from_building number? ---[[ -# Compression level to use when sending mapblocks to the client. -# -1 - use default compression level -# 0 - least compression, fastest -# 9 - best compression, slowest -[server] -(Map Compression Level for Network Transfer) -1 -1 9 -]] ----@field map_compression_level_net integer? - ----@class _.LuantiSettings.advanced.advanced.networking.ctx_client : _.LuantiSettings.advanced.advanced.networking.ctx_common ---[[ -# Maximum size of the client's outgoing chat queue. -# 0 to disable queueing and -1 to make the queue size unlimited. -[client] -(Maximum size of the client's outgoing chat queue) 20 -1 32767 -]] ----@field max_out_chat_queue_size integer? ---[[ -# Timeout for client to remove unused map data from memory, in seconds. -[client] -(Mapblock unload timeout) 600.0 0.0 -]] ----@field client_unload_unused_data_timeout number? ---[[ -# Maximum number of mapblocks for client to be kept in memory. -# Note that there is an internal dynamic minimum number of blocks that -# won't be deleted, depending on the current view range. -# Set to -1 for no limit. -[client] -(Mapblock limit) 7500 -1 2147483647 -]] ----@field client_mapblock_limit integer? - --- -------------------- [Advanced] [*Advanced] [**Server] ------------------- -- - ----@class _.LuantiSettings.advanced.advanced.server.ctx_server ---[[ -# Format of player chat messages. The following strings are valid placeholders: -# @name, @message, @timestamp (optional) -[server] -(Chat message format) <@name> @message -]] ----@field chat_message_format string? ---[[ -# If the execution of a chat command takes longer than this specified time in -# seconds, add the time information to the chat command message -[server] -(Chat command time message threshold) 0.1 0.0 -]] ----@field chatcommand_msg_time_threshold number? ---[[ -# A message to be displayed to all clients when the server shuts down. -[server] -(Shutdown message) Server shutting down. -]] ----@field kick_msg_shutdown string? ---[[ -# A message to be displayed to all clients when the server crashes. -[server] -(Crash message) This server has experienced an internal error. You will now be disconnected. -]] ----@field kick_msg_crash string? ---[[ -# Whether to ask clients to reconnect after a (Lua) crash. -# Set this to true if your server is set up to restart automatically. -[server] -(Ask to reconnect after crash) false -]] ----@field ask_reconnect_on_crash boolean? - --- ------------ [Advanced] [*Advanced] [**Server/Env Performance] ----------- -- - ----@class _.LuantiSettings.advanced.advanced.server_env_performance.ctx_server ---[[ -# Length of a server tick (the interval at which everything is generally updated), -# stated in seconds. -# Does not apply to sessions hosted from the client menu. -# This is a lower bound, i.e. server steps may not be shorter than this, but -# they are often longer. -[server] -(Dedicated server step) 0.09 0.0 1.0 -]] ----@field dedicated_server_step number? ---[[ -# Whether players are shown to clients without any range limit. -# Deprecated, use the setting player_transfer_distance instead. -[server] -(Unlimited player transfer distance) true -]] ----@field unlimited_player_transfer_distance boolean? ---[[ -# Defines the maximal player transfer distance in blocks (0 = unlimited). -[server] -(Player transfer distance) 0 0 65535 -]] ----@field player_transfer_distance integer? ---[[ -# From how far clients know about objects, stated in mapblocks (16 nodes). -# -# Setting this larger than active_block_range will also cause the server -# to maintain active objects up to this distance in the direction the -# player is looking. (This can avoid mobs suddenly disappearing from view) -[server] -(Active object send range) 8 1 65535 -]] ----@field active_object_send_range_blocks integer? ---[[ -# The radius of the volume of blocks around every player that is subject to the -# active block stuff, stated in mapblocks (16 nodes). -# In active blocks objects are loaded and ABMs run. -# This is also the minimum range in which active objects (mobs) are maintained. -# This should be configured together with active_object_send_range_blocks. -[server] -(Active block range) 4 1 65535 -]] ----@field active_block_range integer? ---[[ -# From how far blocks are sent to clients, stated in mapblocks (16 nodes). -[server] -(Max block send distance) 12 1 65535 -]] ----@field max_block_send_distance integer? ---[[ -# Default maximum number of forceloaded mapblocks. -# Set this to -1 to disable the limit. -[server] -(Maximum forceloaded blocks) 16 -1 -]] ----@field max_forceloaded_blocks integer? ---[[ -# Interval of saving important changes in the world, stated in seconds. -[server] -(Map save interval) 5.3 0.001 -]] ----@field server_map_save_interval number? ---[[ -# How long the server will wait before unloading unused mapblocks, stated in seconds. -# Higher value is smoother, but will use more RAM. -[server] -(Unload unused server data) 29 0 4294967295 -]] ----@field server_unload_unused_data_timeout integer? ---[[ -# Maximum number of statically stored objects in a block. -[server] -(Maximum objects per block) 256 256 65535 -]] ----@field max_objects_per_block integer? ---[[ -# Length of time between active block management cycles, stated in seconds. -[server] -(Active block management interval) 2.0 0.0 -]] ----@field active_block_mgmt_interval number? ---[[ -# Length of time between Active Block Modifier (ABM) execution cycles, stated in seconds. -[server] -(ABM interval) 1.0 0.1 30.0 -]] ----@field abm_interval number? ---[[ -# The time budget allowed for ABMs to execute on each step -# (as a fraction of the ABM Interval) -[server] -(ABM time budget) 0.2 0.1 0.9 -]] ----@field abm_time_budget number? ---[[ -# Length of time between NodeTimer execution cycles, stated in seconds. -[server] -(NodeTimer interval) 0.2 0.1 1.0 -]] ----@field nodetimer_interval number? ---[[ -# Max liquids processed per step. -[server] -(Liquid loop max) 100000 1 4294967295 -]] ----@field liquid_loop_max integer? ---[[ -# The time (in seconds) that the liquids queue may grow beyond processing -# capacity until an attempt is made to decrease its size by dumping old queue -# items. A value of 0 disables the functionality. -[server] -(Liquid queue purge time) 0 0 65535 -]] ----@field liquid_queue_purge_time integer? ---[[ -# Liquid update interval in seconds. -[server] -(Liquid update tick) 1.0 0.001 -]] ----@field liquid_update number? ---[[ -# At this distance the server will aggressively optimize which blocks are sent to -# clients. -# Small values potentially improve performance a lot, at the expense of visible -# rendering glitches (some blocks might not be rendered correctly in caves). -# Setting this to a value greater than max_block_send_distance disables this -# optimization. -# Stated in MapBlocks (16 nodes). -[server] -(Block send optimize distance) 4 2 2047 -]] ----@field block_send_optimize_distance integer? ---[[ -# If enabled, the server will perform map block occlusion culling based on -# on the eye position of the player. This can reduce the number of blocks -# sent to the client by 50-80%. Clients will no longer receive most -# invisible blocks, so that the utility of noclip mode is reduced. -[server] -(Server-side occlusion culling) true -]] ----@field server_side_occlusion_culling boolean? ---[[ -# At this distance the server will perform a simpler and cheaper occlusion check. -# Smaller values potentially improve performance, at the expense of temporarily visible -# rendering glitches (missing blocks). -# This is especially useful for very large viewing range (upwards of 500). -# Stated in MapBlocks (16 nodes). -[server] -(Block cull optimize distance) 25 2 2047 -]] ----@field block_cull_optimize_distance integer? - --- -------------------- [Advanced] [*Advanced] [**Mapgen] ------------------- -- - ----@class _.LuantiSettings.advanced.advanced.mappgen.ctx_server ---[[ -# Size of mapchunks generated by mapgen, stated in mapblocks (16 nodes). -# WARNING: There is no benefit, and there are several dangers, in -# increasing this value above 5. -# Reducing this value increases cave and dungeon density. -# Altering this value is for special usage, leaving it unchanged is -# recommended. -[world_creation] -(Chunk size) 5 1 10 -]] ----@field chunksize integer? ---[[ -# Dump the mapgen debug information. -[server] -(Mapgen debug) false -]] ----@field enable_mapgen_debug_info boolean? ---[[ -# Maximum number of blocks that can be queued for loading. -[server] -(Absolute limit of queued blocks to emerge) 1024 1 1000000 -]] ----@field emergequeue_limit_total integer? ---[[ -# Maximum number of blocks to be queued that are to be loaded from file. -# This limit is enforced per player. -[server] -(Per-player limit of queued blocks load from disk) 128 1 1000000 -]] ----@field emergequeue_limit_diskonly integer? ---[[ -# Maximum number of blocks to be queued that are to be generated. -# This limit is enforced per player. -[server] -(Per-player limit of queued blocks to generate) 128 1 1000000 -]] ----@field emergequeue_limit_generate integer? ---[[ -# Number of emerge threads to use. -# Value 0: -# - Automatic selection. The number of emerge threads will be -# - 'number of processors - 2', with a lower limit of 1. -# Any other value: -# - Specifies the number of emerge threads, with a lower limit of 1. -# WARNING: Increasing the number of emerge threads increases engine mapgen -# speed, but this may harm game performance by interfering with other -# processes, especially in singleplayer and/or when running Lua code in -# 'on_generated'. For many users the optimum setting may be '1'. -[server] -(Number of emerge threads) 1 0 32767 -]] ----@field num_emerge_threads integer? - --- --------------------- [Advanced] [*Advanced] [**cURL] -------------------- -- - ----@class _.LuantiSettings.advanced.advanced.cURL.ctx_common ---[[ -# Maximum time an interactive request (e.g. server list fetch) may take, stated in milliseconds. -[common] -(cURL interactive timeout) 20000 1000 2147483647 -]] ----@field curl_timeout integer? ---[[ -# Limits number of parallel HTTP requests. Affects: -# - Media fetch if server uses remote_media setting. -# - Serverlist download and server announcement. -# - Downloads performed by main menu (e.g. mod manager). -# Only has an effect if compiled with cURL. -[common] -(cURL parallel limit) 8 1 2147483647 -]] ----@field curl_parallel_limit integer? ---[[ -# Maximum time a file download (e.g. a mod download) may take, stated in milliseconds. -[common] -(cURL file download timeout) 300000 5000 2147483647 -]] ----@field curl_file_download_timeout integer? - ----@class _.LuantiSettings.advanced.advanced.cURL.ctx_server : _.LuantiSettings.advanced.advanced.cURL.ctx_common - ----@class _.LuantiSettings.advanced.advanced.cURL.ctx_client : _.LuantiSettings.advanced.advanced.cURL.ctx_common - --- --------------- [Advanced] [*Advanced] [**Client Debugging] -------------- -- - ----@class _.LuantiSettings.advanced.advanced.client_debugging.ctx_client ---[[ -# Key for toggling the camera update. Only usable with 'debug' privilege. -[client] -(Toggle camera update) -]] ----@field keymap_toggle_update_camera _.LuantiSettings.key? ---[[ -# Key for switching to the previous entry in Quicktune. -[client] -(Quicktune: select previous entry) -]] ----@field keymap_quicktune_prev _.LuantiSettings.key? ---[[ -# Key for switching to the next entry in Quicktune. -[client] -(Quicktune: select next entry) -]] ----@field keymap_quicktune_next _.LuantiSettings.key? ---[[ -# Key for decrementing the selected value in Quicktune. -[client] -(Quicktune: decrement value) -]] ----@field keymap_quicktune_dec _.LuantiSettings.key? ---[[ -# Key for incrementing the selected value in Quicktune. -[client] -(Quicktune: increment value) -]] ----@field keymap_quicktune_inc _.LuantiSettings.key? - --- ---------------- [Advanced] [*Advanced] [**Miscellaneous] ---------------- -- - ----@class _.LuantiSettings.advanced.advanced.miscellaneous.ctx_common ---[[ -# Windows systems only: Start Luanti with the command line window in the background. -# Contains the same information as the file debug.txt (default name). -[common] -(Enable console window) false -]] ----@field enable_console boolean? - ----@class _.LuantiSettings.advanced.advanced.miscellaneous.ctx_client : _.LuantiSettings.advanced.advanced.miscellaneous.ctx_common ---[[ -# Clickable weblinks (middle-click or Ctrl+left-click) enabled in chat console output. -[client] -(Chat weblinks) true -]] ----@field clickable_chat_weblinks boolean? ---[[ -# Adjust the detected display density, used for scaling UI elements. -[client] -(Display Density Scaling Factor) 1 0.5 5.0 -]] ----@field display_density_factor number? - ---[[ -WIPDOC -]] ----@alias core.LuantiSettings.enums.sqlite_synchronous ---- | "0" ---- | "1" ---- | "2" - ----@class _.LuantiSettings.advanced.advanced.miscellaneous.ctx_server : _.LuantiSettings.advanced.advanced.miscellaneous.ctx_common ---[[ -# If enabled, invalid world data won't cause the server to shut down. -# Only enable this if you know what you are doing. -[server] -(Ignore world errors) false -]] ----@field ignore_world_load_errors boolean? ---[[ -# Number of extra blocks that can be loaded by /clearobjects at once. -# This is a trade-off between SQLite transaction overhead and -# memory consumption (4096=100MB, as a rule of thumb). -[server] -(Max. clearobjects extra blocks) 4096 0 4294967295 -]] ----@field max_clearobjects_extra_loaded_blocks integer? ---[[ -# World directory (everything in the world is stored here). -# Not needed if starting from the main menu. -[server] -(Map directory) -]] ----@field ["map-dir"] core.LuantiSettings.path? ---[[ -# See https://www.sqlite.org/pragma.html#pragma_synchronous -[server] -(Synchronous SQLite) 2 0,1,2 -]] ----@field sqlite_synchronous core.LuantiSettings.enums.sqlite_synchronous? ---[[ -# Compression level to use when saving mapblocks to disk. -# -1 - use default compression level -# 0 - least compression, fastest -# 9 - best compression, slowest -[server] -(Map Compression Level for Disk Storage) -1 -1 9 -]] ----@field map_compression_level_disk integer? ---[[ -# Enable usage of remote media server (if provided by server). -# Remote servers offer a significantly faster way to download media (e.g. textures) -# when connecting to the server. -[client] -(Connect to external media server) true -]] ----@field enable_remote_media_server boolean? ---[[ -# File in client/serverlist/ that contains your favorite servers displayed in the -# Multiplayer Tab. -[client] -(Serverlist file) favoriteservers.json -]] ----@field serverlist_file string? - --- ------------------------- [Advanced] [*Gamepads] ------------------------- -- - ---[[ -WIPDOC -]] ----@alias core.LuantiSettings.enums.joystick_type ---- | "auto" ---- | "generic" ---- | "xbox" ---- | "dragonrise_gamecube" - ----@class _.LuantiSettings.advanced.gamepads.ctx_client ---[[ -# Enable joysticks. Requires a restart to take effect -[client] -(Enable joysticks) false -]] ----@field enable_joysticks boolean? ---[[ -# The identifier of the joystick to use -[client] -(Joystick ID) 0 0 255 -]] ----@field joystick_id integer? ---[[ -# The type of joystick -[client] -(Joystick type) auto auto,generic,xbox,dragonrise_gamecube -]] ----@field joystick_type core.LuantiSettings.enums.joystick_type? ---[[ -# The time in seconds it takes between repeated events -# when holding down a joystick button combination. -[client] -(Joystick button repetition interval) 0.17 0.001 -]] ----@field repeat_joystick_button_time number? ---[[ -# The dead zone of the joystick -[client] -(Joystick dead zone) 2048 0 65535 -]] ----@field joystick_deadzone integer? ---[[ -# The sensitivity of the joystick axes for moving the -# in-game view frustum around. -[client] -(Joystick frustum sensitivity) 170.0 0.001 -]] ----@field joystick_frustum_sensitivity number? - --- ----------------- [Advanced] [*Hide: Temporary Settings] ----------------- -- - ----@class _.LuantiSettings.advanced.hide_temporary_settings.ctx_common ---[[ -# Path to texture directory. All textures are first searched from here. -[common] -(Texture path) -]] ----@field texture_path core.LuantiSettings.path? ---[[ -# Enables minimap. -[common] -(Minimap) true -]] ----@field enable_minimap boolean? ---[[ -# Shape of the minimap. Enabled = round, disabled = square. -[common] -(Round minimap) true -]] ----@field minimap_shape_round boolean? ---[[ -# Address to connect to. -# Leave this blank to start a local server. -# Note that the address field in the main menu overrides this setting. -[common] -(Server address) -]] ----@field address string? ---[[ -# Port to connect to (UDP). -# Note that the port field in the main menu overrides this setting. -[common] -(Remote port) 30000 1 65535 -]] ----@field remote_port integer? ---[[ -# Enable players getting damage and dying. -[common] -(Damage) false -]] ----@field enable_damage boolean? ---[[ -# Enable creative mode for all players -[common] -(Creative) false -]] ----@field creative_mode boolean? ---[[ -# Whether to allow players to damage and kill each other. -[common] -(Player versus player) true -]] ----@field enable_pvp boolean? ---[[ -# Player is able to fly without being affected by gravity. -# This requires the "fly" privilege on the server. -[common] -(Flying) false -]] ----@field free_move boolean? ---[[ -# If enabled, makes move directions relative to the player's pitch when flying or swimming. -[common] -(Pitch move mode) false -]] ----@field pitch_move boolean? ---[[ -# Fast movement (via the "Aux1" key). -# This requires the "fast" privilege on the server. -[common] -(Fast movement) false -]] ----@field fast_move boolean? ---[[ -# If enabled together with fly mode, player is able to fly through solid nodes. -# This requires the "noclip" privilege on the server. -[common] -(Noclip) false -]] ----@field noclip boolean? ---[[ -# Continuous forward movement, toggled by autoforward key. -# Press the autoforward key again or the backwards movement to disable. -[common] -(Continuous forward) false -]] ----@field continuous_forward boolean? ---[[ -# This can be bound to a key to toggle camera smoothing when looking around. -# Useful for recording videos -[common] -(Cinematic mode) false -]] ----@field cinematic boolean? ---[[ -# Affects mods and texture packs in the Content and Select Mods menus, as well as -# setting names. -# Controlled by a checkbox in the settings menu. -[common] -(Show technical names) false -]] ----@field show_technical_names boolean? ---[[ -# Controlled by a checkbox in the settings menu. -[common] -(Show advanced settings) false -]] ----@field show_advanced boolean? - ----@class _.LuantiSettings.advanced.hide_temporary_settings.ctx_server : _.LuantiSettings.advanced.hide_temporary_settings.ctx_common - ----@class _.LuantiSettings.advanced.hide_temporary_settings.ctx_client : _.LuantiSettings.advanced.hide_temporary_settings.ctx_common \ No newline at end of file diff --git a/types/luanti_lsp_definitions/library/classes/Settings/LuantiSettings/client_and_server.lua b/types/luanti_lsp_definitions/library/classes/Settings/LuantiSettings/client_and_server.lua deleted file mode 100644 index 6a13bf97..00000000 --- a/types/luanti_lsp_definitions/library/classes/Settings/LuantiSettings/client_and_server.lua +++ /dev/null @@ -1,490 +0,0 @@ ----@meta _ --- DRAFT 1 DONE --- builtin/settingtypes.txt --- minetest.conf.example - - --- Section context mapping: --- * [Client and Server] [*Client]: [client] --- * [Client and Server] [*Server]: [server] --- * [Client and Server] [*Server Security]: [server] --- * [Client and Server] [*Server Gameplay]: [server] - ----@alias _.LuantiSettings.client_and_server.keys.boolean ---- | "server_announce" ---- | "server_announce_send_players" ---- | "strict_protocol_version_checking" ---- | "ipv6_server" ---- | "disallow_empty_password" ---- | "enable_rollback_recording" ---- | "strip_color_codes" - ----@alias _.LuantiSettings.client_and_server.keys ---- | "serverlist_url" ---- | "name" ---- | "serverlist_url" ---- | "server_name" ---- | "server_description" ---- | "server_address" ---- | "server_url" ---- | "server_announce" ---- | "server_announce_send_players" ---- | "motd" ---- | "max_users" ---- | "static_spawnpoint" ---- | "port" ---- | "bind_address" ---- | "strict_protocol_version_checking" ---- | "protocol_version_min" ---- | "remote_media" ---- | "ipv6_server" ---- | "default_password" ---- | "disallow_empty_password" ---- | "default_privs" ---- | "basic_privs" ---- | "anticheat_flags" ---- | "anticheat_movement_tolerance" ---- | "enable_rollback_recording" ---- | "csm_restriction_flags" ---- | "csm_restriction_noderange" ---- | "strip_color_codes" ---- | "chat_message_max_size" ---- | "chat_message_limit_per_10sec" ---- | "chat_message_limit_trigger_kick" ---- | "time_speed" ---- | "world_start_time" ---- | "item_entity_ttl" ---- | "default_stack_max" ---- | "movement_acceleration_default" ---- | "movement_acceleration_air" ---- | "movement_acceleration_fast" ---- | "movement_speed_walk" ---- | "movement_speed_crouch" ---- | "movement_speed_fast" ---- | "movement_speed_climb" ---- | "movement_speed_jump" ---- | "movement_liquid_fluidity" ---- | "movement_liquid_fluidity_smooth" ---- | "movement_liquid_sink" ---- | "movement_gravity" - ----@class _.LuantiSettings.client_and_server.tablefmt : _.LuantiSettings.client_and_server.client.ctx_server, _.LuantiSettings.client_and_server.server, _.LuantiSettings.client_and_server.server.serverlist_and_motd.ctx_server, _.LuantiSettings.client_and_server.server.networking, _.LuantiSettings.client_and_server.server_security, _.luantisettings.client_and_server.server_security.client_side_modding, _.luantisettings.client_and_server.server_security.chat, _.luantisettings.client_and_server.server_gameplay, _.luantisettings.client_and_server.server_gameplay.physics - --- --------------------------- [Client and Server] -------------------------- -- - --- ---------------------- [Client and Server] [*Client] --------------------- -- - ----@class _.LuantiSettings.client_and_server.client.ctx_common ---[[ -# URL to the server list displayed in the Multiplayer Tab. -[common] -(Serverlist URL) https://servers.luanti.org -]] ----@field serverlist_url string? - ----@class _.LuantiSettings.client_and_server.client.ctx_client : _.LuantiSettings.client_and_server.client.ctx_common ---[[ -# Save the map received by the client on disk. -[client] -(Saving map received from server) false -]] ----@field enable_local_map_saving boolean? ---[[ -# If enabled, server account registration is separate from login in the UI. -# If disabled, connecting to a server will automatically register a new account. -[client] -(Enable split login/register) true -]] ----@field enable_split_login_register boolean? ---[[ -# URL to JSON file which provides information about the newest Luanti release. -# If this is empty the engine will never check for updates. -[client] -(Update information URL) https://www.luanti.org/release_info.json -]] ----@field update_information_url string? - ----@class _.LuantiSettings.client_and_server.client.ctx_server : _.LuantiSettings.client_and_server.client.ctx_common - --- ---------------------- [Client and Server] [*Server] --------------------- -- - ----@class _.LuantiSettings.client_and_server.server ---[[ -# Name of the player. -# When running a server, a client connecting with this name is admin. -# When starting from the main menu, this is overridden. -[server] -(Admin name) -]] ----@field name string? - - -- ---------- [Client and Server] [*Server] [**Serverlist and MOTD] --------- -- - ----@class _.LuantiSettings.client_and_server.server.serverlist_and_motd.ctx_common ---[[ -# Announce to this serverlist. -[common] -(Serverlist URL) https://servers.luanti.org -]] ----@field serverlist_url string? - ----@class _.LuantiSettings.client_and_server.server.serverlist_and_motd.ctx_server : _.LuantiSettings.client_and_server.server.serverlist_and_motd.ctx_common ---[[ -# Name of the server, to be displayed when players join and in the serverlist. -[server] -(Server name) Luanti server -]] ----@field server_name string? ---[[ -# Description of server, to be displayed when players join and in the serverlist. -[server] -(Server description) mine here -]] ----@field server_description string? ---[[ -# Domain name of server, to be displayed in the serverlist. -[server] -(Server address) game.example.net -]] ----@field server_address string? ---[[ -# Homepage of server, to be displayed in the serverlist. -[server] -(Server URL) https://game.example.net -]] ----@field server_url string? ---[[ -# Automatically report to the serverlist. -[server] -(Announce server) false -]] ----@field server_announce boolean? ---[[ -# Send names of online players to the serverlist. If disabled only the player count is revealed. -[server] -(Send player names to the server list) true -]] ----@field server_announce_send_players boolean? ---[[ -# Message of the day displayed to players connecting. -[server] -(Message of the day) -]] ----@field motd string? ---[[ -# Maximum number of players that can be connected simultaneously. -[server] -(Maximum users) 15 0 65535 -]] ----@field max_users integer? ---[[ -# If this is set, players will always (re)spawn at the given position. -[server] -(Static spawn point) -]] ----@field static_spawnpoint string? - ----@class _.LuantiSettings.client_and_server.server.serverlist_and_motd.ctx_client : _.LuantiSettings.client_and_server.server.serverlist_and_motd.ctx_common - - -- -------------- [Client and Server] [*Server] [**Networking] -------------- -- - ----@class _.LuantiSettings.client_and_server.server.networking ---[[ -# Network port to listen (UDP). -# This value will be overridden when starting from the main menu. -[server] -(Server port) 30000 1 65535 -]] ----@field port integer? ---[[ -# The network interface that the server listens on. -[server] -(Bind address) -]] ----@field bind_address string? ---[[ -# Enable to disallow old clients from connecting. -# Older clients are compatible in the sense that they will not crash when connecting -# to new servers, but they may not support all new features that you are expecting. -[server] -(Strict protocol checking) false -]] ----@field strict_protocol_version_checking boolean? ---[[ -# Define the oldest clients allowed to connect. -# Older clients are compatible in the sense that they will not crash when connecting -# to new servers, but they may not support all new features that you are expecting. -# This allows for more fine-grained control than strict_protocol_version_checking. -# Luanti still enforces its own internal minimum, and enabling -# strict_protocol_version_checking will effectively override this. -[server] -(Protocol version minimum) 1 1 65535 -]] ----@field protocol_version_min integer? ---[[ -# Specifies URL from which client fetches media instead of using UDP. -# $filename should be accessible from $remote_media$filename via cURL -# (obviously, remote_media should end with a slash). -# Files that are not present will be fetched the usual way. -[server] -(Remote media) -]] ----@field remote_media string? ---[[ -# Enable IPv6 support for server. -# Note that clients will be able to connect with both IPv4 and IPv6. -# Ignored if bind_address is set. -# -# Requires: enable_ipv6 -[server] -(IPv6 server) true -]] ----@field ipv6_server boolean? - --- ----------------- [Client and Server] [*Server Security] ----------------- -- - ---[[ -WIPDOC -]] ----@class core.LuantiSettings.flags.anticheat_flags ---[[ -WIPDOC -]] ----@field digging boolean? ---[[ -WIPDOC -]] ----@field nodigging boolean? ---[[ -WIPDOC -]] ----@field interaction boolean? ---[[ -WIPDOC -]] ----@field nointeraction boolean? ---[[ -WIPDOC -]] ----@field movement boolean? ---[[ -WIPDOC -]] ----@field nomovement boolean? - ----@class _.LuantiSettings.client_and_server.server_security ---[[ -# New users need to input this password. -[server] -(Default password) -]] ----@field default_password string? ---[[ -# If enabled, players cannot join without a password or change theirs to an empty password. -[server] -(Disallow empty passwords) false -]] ----@field disallow_empty_password boolean? ---[[ -# The privileges that new users automatically get. -# See /privs in game for a full list on your server and mod configuration. -[server] -(Default privileges) interact, shout -]] ----@field default_privs string? ---[[ -# Privileges that players with basic_privs can grant -[server] -(Basic privileges) interact, shout -]] ----@field basic_privs string? ---[[ -# Server anticheat configuration. -# Flags are positive. Uncheck the flag to disable corresponding anticheat module. -[server] -(Anticheat flags) digging,interaction,movement digging,interaction,movement -]] ----@field anticheat_flags core.LuantiSettings.flags? ---[[ -# Tolerance of movement cheat detector. -# Increase the value if players experience stuttery movement. -[server] -(Anticheat movement tolerance) 1.0 1.0 -]] ----@field anticheat_movement_tolerance number? ---[[ -# If enabled, actions are recorded for rollback. -# This option is only read when server starts. -[server] -(Rollback recording) false -]] ----@field enable_rollback_recording boolean? - --- ----- [Client and Server] [*Server Security] [**Client-side Modding] ----- -- - ----@class _.luantisettings.client_and_server.server_security.client_side_modding ---[[ -# Restricts the access of certain client-side functions on servers. -# Combine the byteflags below to restrict client-side features, or set to 0 -# for no restrictions: -# LOAD_CLIENT_MODS: 1 (disable loading client-provided mods) -# CHAT_MESSAGES: 2 (disable send_chat_message call client-side) -# READ_ITEMDEFS: 4 (disable get_item_def call client-side) -# READ_NODEDEFS: 8 (disable get_node_def call client-side) -# LOOKUP_NODES_LIMIT: 16 (limits get_node call client-side to -# csm_restriction_noderange) -# READ_PLAYERINFO: 32 (disable get_player_names call client-side) -[server] -(Client side modding restrictions) 62 0 63 -]] ----@field csm_restriction_flags integer? ---[[ -# If the CSM restriction for node range is enabled, get_node calls are limited -# to this distance from the player to the node. -[server] -(Client-side node lookup range restriction) 0 0 4294967295 -]] ----@field csm_restriction_noderange integer? - --- ------------- [Client and Server] [*Server Security] [**Chat] ------------ -- - ----@class _.luantisettings.client_and_server.server_security.chat ---[[ -# Remove color codes from incoming chat messages -# Use this to stop players from being able to use color in their messages -[server] -(Strip color codes) false -]] ----@field strip_color_codes boolean? ---[[ -# Set the maximum length of a chat message (in characters) sent by clients. -[server] -(Chat message max length) 500 10 65535 -]] ----@field chat_message_max_size integer? ---[[ -# Number of messages a player may send per 10 seconds. -[server] -(Chat message count limit) 8.0 1.0 -]] ----@field chat_message_limit_per_10sec number? ---[[ -# Kick players who sent more than X messages per 10 seconds. -[server] -(Chat message kick threshold) 50 1 65535 -]] ----@field chat_message_limit_trigger_kick integer? - --- ----------------- [Client and Server] [*Server Gameplay] ----------------- -- - ----@class _.luantisettings.client_and_server.server_gameplay ---[[ -# Controls length of day/night cycle. -# Examples: -# 72 = 20min, 360 = 4min, 1 = 24hour, 0 = day/night/whatever stays unchanged. -[server] -(Time speed) 72 0 -]] ----@field time_speed integer? ---[[ -# Time of day when a new world is started, in millihours (0-23999). -[world_creation] -(World start time) 6125 0 23999 -]] ----@field world_start_time integer? ---[[ -# Time in seconds for item entity (dropped items) to live. -# Setting it to -1 disables the feature. -[server] -(Item entity TTL) 900 -1 -]] ----@field item_entity_ttl integer? ---[[ -# Specifies the default stack size of nodes, items and tools. -# Note that mods or games may explicitly set a stack for certain (or all) items. -[server] -(Default stack size) 99 1 65535 -]] ----@field default_stack_max integer? - --- ----------- [Client and Server] [*Server Gameplay] [**Physics] ----------- -- - ----@class _.luantisettings.client_and_server.server_gameplay.physics ---[[ -# Horizontal and vertical acceleration on ground or when climbing, -# in nodes per second per second. -[server] -(Default acceleration) 3.0 0.0 -]] ----@field movement_acceleration_default number? ---[[ -# Horizontal acceleration in air when jumping or falling, -# in nodes per second per second. -[server] -(Acceleration in air) 2.0 0.0 -]] ----@field movement_acceleration_air number? ---[[ -# Horizontal and vertical acceleration in fast mode, -# in nodes per second per second. -[server] -(Fast mode acceleration) 10.0 0.0 -]] ----@field movement_acceleration_fast number? ---[[ -# Walking and flying speed, in nodes per second. -[server] -(Walking speed) 4.0 0.0 -]] ----@field movement_speed_walk number? ---[[ -# Sneaking speed, in nodes per second. -[server] -(Sneaking speed) 1.35 0.0 -]] ----@field movement_speed_crouch number? ---[[ -# Walking, flying and climbing speed in fast mode, in nodes per second. -[server] -(Fast mode speed) 20.0 0.0 -]] ----@field movement_speed_fast number? ---[[ -# Vertical climbing speed, in nodes per second. -[server] -(Climbing speed) 3.0 0.0 -]] ----@field movement_speed_climb number? ---[[ -# Initial vertical speed when jumping, in nodes per second. -[server] -(Jumping speed) 6.5 0.0 -]] ----@field movement_speed_jump number? ---[[ -# How much you are slowed down when moving inside a liquid. -# Decrease this to increase liquid resistance to movement. -[server] -(Liquid fluidity) 1.0 0.001 -]] ----@field movement_liquid_fluidity number? ---[[ -# Maximum liquid resistance. Controls deceleration when entering liquid at -# high speed. -[server] -(Liquid fluidity smoothing) 0.5 -]] ----@field movement_liquid_fluidity_smooth number? ---[[ -# Controls sinking speed in liquid when idling. Negative values will cause -# you to rise instead. -[server] -(Liquid sinking) 10.0 -]] ----@field movement_liquid_sink number? ---[[ -# Acceleration of gravity, in nodes per second per second. -[server] -(Gravity) 9.81 -]] ----@field movement_gravity number? \ No newline at end of file diff --git a/types/luanti_lsp_definitions/library/classes/Settings/LuantiSettings/controls.lua b/types/luanti_lsp_definitions/library/classes/Settings/LuantiSettings/controls.lua deleted file mode 100644 index e189bf5a..00000000 --- a/types/luanti_lsp_definitions/library/classes/Settings/LuantiSettings/controls.lua +++ /dev/null @@ -1,700 +0,0 @@ ----@meta _ --- DRAFT 1 DONE --- builtin/settingtypes.txt --- minetest.conf.example - --- NOTE: key type is not a type mods and games will have to deal with ----@class _.LuantiSettings.key - --- Section context mapping: --- * [Controls]: [client] - --- -------------------------- [Controls] [*General] ------------------------- -- - ----@class _.LuantiSettings.controls.general ---[[ -# Smooths rotation of camera, also called look or mouse smoothing. 0 to disable. -[client] -(Camera smoothing) 0.0 0.0 0.99 -]] ----@field camera_smoothing number? ---[[ -# Smooths rotation of camera when in cinematic mode, 0 to disable. Enter cinematic mode by using the key set in Controls. -# -# Requires: keyboard_mouse -[client] -(Camera smoothing in cinematic mode) 0.7 0.0 0.99 -]] ----@field cinematic_camera_smoothing number? ---[[ -# If enabled, you can place nodes at the position (feet + eye level) where you stand. -# This is helpful when working with nodeboxes in small areas. -[client] -(Build inside player) false -]] ----@field enable_build_where_you_stand boolean? ---[[ -# If enabled, "Aux1" key instead of "Sneak" key is used for climbing down and -# descending. -[client] -(Aux1 key for climbing/descending) false -]] ----@field aux1_descends boolean? ---[[ -# Double-tapping the jump key toggles fly mode. -[client] -(Double tap jump for fly) false -]] ----@field doubletap_jump boolean? ---[[ -# If disabled, "Aux1" key is used to fly fast if both fly and fast mode are -# enabled. -(Always fly fast) true -]] ----@field always_fly_fast boolean? ---[[ -# If enabled, the "Sneak" key will toggle when pressed. -# This functionality is ignored when fly is enabled. -[client] -(Toggle Sneak key) false -]] ----@field toggle_sneak_key boolean? ---[[ -# If enabled, the "Aux1" key will toggle when pressed. -[client] -(Toggle Aux1 key) false -]] ----@field toggle_aux1_key boolean? ---[[ -# The time in seconds it takes between repeated node placements when holding -# the place button. -# -# Requires: keyboard_mouse -[client] -(Place repetition interval) 0.25 0.16 2.0 -]] ----@field repeat_place_time number? ---[[ -# The minimum time in seconds it takes between digging nodes when holding -# the dig button. -[client] -(Minimum dig repetition interval) 0.0 0.0 2.0 -]] ----@field repeat_dig_time number? ---[[ -# Automatically jump up single-node obstacles. -[client] -(Automatic jumping) false -]] ----@field autojump boolean? ---[[ -# Prevent digging and placing from repeating when holding the respective buttons. -# Enable this when you dig or place too often by accident. -# On touchscreens, this only affects digging. -[client] -(Safe digging and placing) false -]] ----@field safe_dig_and_place boolean? - --- -------------------- [Controls] [*Keyboard and Mouse] -------------------- -- - ----@class _.LuantiSettings.controls.keyboard_and_mouse ---[[ -# Invert vertical mouse movement. -# -# Requires: keyboard_mouse -[client] -(Invert mouse) false -]] ----@field invert_mouse boolean? ---[[ -# Mouse sensitivity multiplier. -# -# Requires: keyboard_mouse -[client] -(Mouse sensitivity) 0.2 0.001 10.0 -]] ----@field mouse_sensitivity number? ---[[ -# Enable mouse wheel (scroll) for item selection in hotbar. -# -# Requires: keyboard_mouse -[client] -(Hotbar: Enable mouse wheel for selection) true -]] ----@field enable_hotbar_mouse_wheel boolean? ---[[ -# Invert mouse wheel (scroll) direction for item selection in hotbar. -# -# Requires: keyboard_mouse -[client] -(Hotbar: Invert mouse wheel direction) false -]] ----@field invert_hotbar_mouse_wheel boolean? - --- ------------ [Controls] [*Keyboard and Mouse] [**Keybindings] ------------ -- - ----@class _.LuantiSettings.controls.keyboard_and_mouse.keybindings ---[[ -# WIPDOC -[client] -(Move forward) SYSTEM_SCANCODE_26 -]] ----@field keymap_forward _.LuantiSettings.key? ---[[ -# Will also disable autoforward, when active. -[client] -(Move backward) SYSTEM_SCANCODE_22 -]] ----@field keymap_backward _.LuantiSettings.key? ---[[ -# WIPDOC -[client] -(Move left) SYSTEM_SCANCODE_4 -]] ----@field keymap_left _.LuantiSettings.key? ---[[ -# WIPDOC -[client] -(Move right) SYSTEM_SCANCODE_7 -]] ----@field keymap_right _.LuantiSettings.key? ---[[ -# WIPDOC -[client] -(Jump) SYSTEM_SCANCODE_44 -]] ----@field keymap_jump _.LuantiSettings.key? ---[[ -# Also used for climbing down and descending in water if aux1_descends is disabled. -[client] -(Sneak) SYSTEM_SCANCODE_225 -]] ----@field keymap_sneak _.LuantiSettings.key? ---[[ -# Key for digging, punching or using something. -# (Note: The actual meaning might vary on a per-game basis.) -[client] -(Dig/punch/use) KEY_LBUTTON -]] ----@field keymap_dig _.LuantiSettings.key? ---[[ -# Key for placing an item/block or for using something. -# (Note: The actual meaning might vary on a per-game basis.) -[client] -(Place/use) KEY_RBUTTON -]] ----@field keymap_place _.LuantiSettings.key? ---[[ -# WIPDOC -[client] -(Open inventory) SYSTEM_SCANCODE_12 -]] ----@field keymap_inventory _.LuantiSettings.key? ---[[ -# Key for moving fast in fast mode. -[client] -(Aux1) SYSTEM_SCANCODE_8 -]] ----@field keymap_aux1 _.LuantiSettings.key? ---[[ -# WIPDOC -[client] -(Open chat) SYSTEM_SCANCODE_23 -]] ----@field keymap_chat _.LuantiSettings.key? ---[[ -# Key for opening the chat window to type commands. -[client] -(Command) SYSTEM_SCANCODE_56 -]] ----@field keymap_cmd _.LuantiSettings.key? ---[[ -# Key for opening the chat window to type local commands. -[client] -(Local command) SYSTEM_SCANCODE_55 -]] ----@field keymap_cmd_local _.LuantiSettings.key? ---[[ -# WIPDOC -[client] -(Toggle unlimited view range) -]] ----@field keymap_rangeselect _.LuantiSettings.key? ---[[ -# WIPDOC -[client] -(Toggle fly) SYSTEM_SCANCODE_14 -]] ----@field keymap_freemove _.LuantiSettings.key? ---[[ -# WIPDOC -[client] -(Toggle pitchmove) -]] ----@field keymap_pitchmove _.LuantiSettings.key? ---[[ -# WIPDOC -[client] -(Toggle fast) SYSTEM_SCANCODE_13 -]] ----@field keymap_fastmove _.LuantiSettings.key? ---[[ -# WIPDOC -[client] -(Toggle noclip) SYSTEM_SCANCODE_11 -]] ----@field keymap_noclip _.LuantiSettings.key? ---[[ -# WIPDOC -[client] -(Hotbar: select next item) SYSTEM_SCANCODE_17 -]] ----@field keymap_hotbar_next _.LuantiSettings.key? ---[[ -# WIPDOC -[client] -(Hotbar: select previous item) SYSTEM_SCANCODE_5 -]] ----@field keymap_hotbar_previous _.LuantiSettings.key? ---[[ -# WIPDOC -[client] -(Mute) SYSTEM_SCANCODE_16 -]] ----@field keymap_mute _.LuantiSettings.key? ---[[ -# WIPDOC -[client] -(Increase volume) -]] ----@field keymap_increase_volume _.LuantiSettings.key? ---[[ -# WIPDOC -[client] -(Decrease volume) -]] ----@field keymap_decrease_volume _.LuantiSettings.key? ---[[ -# WIPDOC -[client] -(Toggle automatic forward) -]] ----@field keymap_autoforward _.LuantiSettings.key? ---[[ -# WIPDOC -[client] -(Toggle cinematic mode) -]] ----@field keymap_cinematic _.LuantiSettings.key? ---[[ -# WIPDOC -[client] -(Toggle minimap) SYSTEM_SCANCODE_25 -]] ----@field keymap_minimap _.LuantiSettings.key? ---[[ -# WIPDOC -[client] -(Screenshot) SYSTEM_SCANCODE_69 -]] ----@field keymap_screenshot _.LuantiSettings.key? ---[[ -# WIPDOC -[client] -(Toggle fullscreen) SYSTEM_SCANCODE_68 -]] ----@field keymap_fullscreen _.LuantiSettings.key? ---[[ -# WIPDOC -[client] -(Drop item) SYSTEM_SCANCODE_20 -]] ----@field keymap_drop _.LuantiSettings.key? ---[[ -# WIPDOC -[client] -(Zoom) SYSTEM_SCANCODE_29 -]] ----@field keymap_zoom _.LuantiSettings.key? ---[[ -# WIPDOC -[client] -(Toggle HUD) SYSTEM_SCANCODE_58 -]] ----@field keymap_toggle_hud _.LuantiSettings.key? ---[[ -# WIPDOC -[client] -(Toggle chat log) SYSTEM_SCANCODE_59 -]] ----@field keymap_toggle_chat _.LuantiSettings.key? ---[[ -# WIPDOC -[client] -(Toggle large chat console) SYSTEM_SCANCODE_67 -]] ----@field keymap_console _.LuantiSettings.key? ---[[ -# WIPDOC -[client] -(Toggle fog) SYSTEM_SCANCODE_60 -]] ----@field keymap_toggle_fog _.LuantiSettings.key? ---[[ -# WIPDOC -[client] -(Toggle debug info) SYSTEM_SCANCODE_62 -]] ----@field keymap_toggle_debug _.LuantiSettings.key? ---[[ -# Key for toggling the display of the profiler. Used for development. -[client] -(Toggle profiler) SYSTEM_SCANCODE_63 -]] ----@field keymap_toggle_profiler _.LuantiSettings.key? ---[[ -# Key for toggling the display of mapblock boundaries. -[client] -(Toggle block bounds) -]] ----@field keymap_toggle_block_bounds _.LuantiSettings.key? ---[[ -# WIPDOC -[client] -(Toggle camera mode) SYSTEM_SCANCODE_6 -]] ----@field keymap_camera_mode _.LuantiSettings.key? ---[[ -# WIPDOC -[client] -(Increase view range) SYSTEM_SCANCODE_46 -]] ----@field keymap_increase_viewing_range_min _.LuantiSettings.key? ---[[ -# WIPDOC -[client] -(Decrease view range) SYSTEM_SCANCODE_45 -]] ----@field keymap_decrease_viewing_range_min _.LuantiSettings.key? ---[[ -# Modifier key bind for closing your world. -# Requires ESC + the selected key to work. -[client] -(Return to Main Menu) -]] ----@field keymap_close_world _.LuantiSettings.key? ---[[ -# WIPDOC -[client] -(Hotbar slot 1) SYSTEM_SCANCODE_30 -]] ----@field keymap_slot1 _.LuantiSettings.key? ---[[ -# WIPDOC -[client] -(Hotbar slot 2) SYSTEM_SCANCODE_31 -]] ----@field keymap_slot2 _.LuantiSettings.key? ---[[ -# WIPDOC -[client] -(Hotbar slot 3) SYSTEM_SCANCODE_32 -]] ----@field keymap_slot3 _.LuantiSettings.key? ---[[ -# WIPDOC -[client] -(Hotbar slot 4) SYSTEM_SCANCODE_33 -]] ----@field keymap_slot4 _.LuantiSettings.key? ---[[ -# WIPDOC -[client] -(Hotbar slot 5) SYSTEM_SCANCODE_34 -]] ----@field keymap_slot5 _.LuantiSettings.key? ---[[ -# WIPDOC -[client] -(Hotbar slot 6) SYSTEM_SCANCODE_35 -]] ----@field keymap_slot6 _.LuantiSettings.key? ---[[ -# WIPDOC -[client] -(Hotbar slot 7) SYSTEM_SCANCODE_36 -]] ----@field keymap_slot7 _.LuantiSettings.key? ---[[ -# WIPDOC -[client] -(Hotbar slot 8) SYSTEM_SCANCODE_37 -]] ----@field keymap_slot8 _.LuantiSettings.key? ---[[ -# WIPDOC -[client] -(Hotbar slot 9) SYSTEM_SCANCODE_38 -]] ----@field keymap_slot9 _.LuantiSettings.key? ---[[ -# WIPDOC -[client] -(Hotbar slot 10) SYSTEM_SCANCODE_39 -]] ----@field keymap_slot10 _.LuantiSettings.key? ---[[ -# WIPDOC -[client] -(Hotbar slot 11) -]] ----@field keymap_slot11 _.LuantiSettings.key? ---[[ -# WIPDOC -[client] -(Hotbar slot 12) -]] ----@field keymap_slot12 _.LuantiSettings.key? ---[[ -# WIPDOC -[client] -(Hotbar slot 13) -]] ----@field keymap_slot13 _.LuantiSettings.key? ---[[ -# WIPDOC -[client] -(Hotbar slot 14) -]] ----@field keymap_slot14 _.LuantiSettings.key? ---[[ -# WIPDOC -[client] -(Hotbar slot 15) -]] ----@field keymap_slot15 _.LuantiSettings.key? ---[[ -# WIPDOC -[client] -(Hotbar slot 16) -]] ----@field keymap_slot16 _.LuantiSettings.key? ---[[ -# WIPDOC -[client] -(Hotbar slot 17) -]] ----@field keymap_slot17 _.LuantiSettings.key? ---[[ -# WIPDOC -[client] -(Hotbar slot 18) -]] ----@field keymap_slot18 _.LuantiSettings.key? ---[[ -# WIPDOC -[client] -(Hotbar slot 19) -]] ----@field keymap_slot19 _.LuantiSettings.key? ---[[ -# WIPDOC -[client] -(Hotbar slot 20) -]] ----@field keymap_slot20 _.LuantiSettings.key? ---[[ -# WIPDOC -[client] -(Hotbar slot 21) -]] ----@field keymap_slot21 _.LuantiSettings.key? ---[[ -# WIPDOC -[client] -(Hotbar slot 22) -]] ----@field keymap_slot22 _.LuantiSettings.key? ---[[ -# WIPDOC -[client] -(Hotbar slot 23) -]] ----@field keymap_slot23 _.LuantiSettings.key? ---[[ -# WIPDOC -[client] -(Hotbar slot 24) -]] ----@field keymap_slot24 _.LuantiSettings.key? ---[[ -# WIPDOC -[client] -(Hotbar slot 25) -]] ----@field keymap_slot25 _.LuantiSettings.key? ---[[ -# WIPDOC -[client] -(Hotbar slot 26) -]] ----@field keymap_slot26 _.LuantiSettings.key? ---[[ -# WIPDOC -[client] -(Hotbar slot 27) -]] ----@field keymap_slot27 _.LuantiSettings.key? ---[[ -# WIPDOC -[client] -(Hotbar slot 28) -]] ----@field keymap_slot28 _.LuantiSettings.key? ---[[ -# WIPDOC -[client] -(Hotbar slot 29) -]] ----@field keymap_slot29 _.LuantiSettings.key? ---[[ -# WIPDOC -[client] -(Hotbar slot 30) -]] ----@field keymap_slot30 _.LuantiSettings.key? ---[[ -# WIPDOC -[client] -(Hotbar slot 31) -]] ----@field keymap_slot31 _.LuantiSettings.key? ---[[ -# WIPDOC -[client] -(Hotbar slot 32) -]] ----@field keymap_slot32 _.LuantiSettings.key? - - --- ------------------------ [Controls] [*Touchscreen] ----------------------- -- - ---[[ -WIPDOC -]] ----@alias core.LuantiSettings.enums.touch_controls ---- | "auto" ---- | "true" ---- | "false" - ----@class _.LuantiSettings.controls.touchscreen ---[[ -# Enables the touchscreen controls, allowing you to play the game with a touchscreen. -# "auto" means that the touchscreen controls will be enabled and disabled -# automatically depending on the last used input method. -# -# Requires: touch_support -[client] -(Touchscreen controls) auto auto,true,false -]] ----@field touch_controls core.LuantiSettings.enums.touch_controls? - ---[[ -WIPDOC -]] ----@alias core.LuantiSettings.enums.touch_interaction_style ---- | "tap" ---- | "tap_crosshair" ---- | "buttons_crosshair" - ----@class _.LuantiSettings.controls.touchscreen ---[[ -# The kind of digging/placing controls used. -# -# * Tap -# Long/short tap anywhere on the screen to interact. -# Interaction happens at finger position. -# -# * Tap with crosshair -# Long/short tap anywhere on the screen to interact. -# Interaction happens at crosshair position. -# -# * Buttons with crosshair -# Use dedicated dig/place buttons to interact. -# Interaction happens at crosshair position. -# -# Requires: touchscreen -[client] -(Interaction style) tap tap,tap_crosshair,buttons_crosshair -]] ----@field touch_interaction_style core.LuantiSettings.enums.touch_interaction_style? - ---[[ -WIPDOC -]] ----@alias core.LuantiSettings.enums.touch_punch_gesture ---- | "short_tap" ---- | "long_tap" - ----@class _.LuantiSettings.controls.touchscreen ---[[ -# The gesture for punching players/entities. -# This can be overridden by games and mods. -# -# * Short tap -# Easy to use and well-known from other games that shall not be named. -# -# * Long tap -# Known from the classic Luanti mobile controls. -# Combat is more or less impossible. -# -# Requires: touchscreen, touch_interaction_style_tap -[client] -(Punch gesture) short_tap short_tap,long_tap -]] ----@field touch_punch_gesture core.LuantiSettings.enums.touch_punch_gesture? - ----@class _.LuantiSettings.controls.touchscreen ---[[ -# Touchscreen sensitivity multiplier. -# -# Requires: touchscreen -[client] -(Touchscreen sensitivity) 0.2 0.001 10.0 -]] ----@field touchscreen_sensitivity number? ---[[ -# The length in pixels after which a touch interaction is considered movement. -# -# Requires: touchscreen -[client] -(Movement threshold) 20 0 100 -]] ----@field touchscreen_threshold integer? ---[[ -# The delay in milliseconds after which a touch interaction is considered a long tap. -# -# Requires: touchscreen -[client] -(Threshold for long taps) 400 100 1000 -]] ----@field touch_long_tap_delay integer? ---[[ -# Fixes the position of virtual joystick. -# If disabled, virtual joystick will center to first-touch's position. -# -# Requires: touchscreen -[client] -(Fixed virtual joystick) false -]] ----@field fixed_virtual_joystick boolean? ---[[ -# Use virtual joystick to trigger "Aux1" button. -# If enabled, virtual joystick will also tap "Aux1" button when out of main circle. -# -# Requires: touchscreen -[client] -(Virtual joystick triggers Aux1 button) false -]] ----@field virtual_joystick_triggers_aux1 boolean? \ No newline at end of file diff --git a/types/luanti_lsp_definitions/library/classes/Settings/LuantiSettings/graphics_and_audio.lua b/types/luanti_lsp_definitions/library/classes/Settings/LuantiSettings/graphics_and_audio.lua deleted file mode 100644 index 87cfcce5..00000000 --- a/types/luanti_lsp_definitions/library/classes/Settings/LuantiSettings/graphics_and_audio.lua +++ /dev/null @@ -1,1032 +0,0 @@ ----@meta _ --- DRAFT 1 DONE --- builtin/settingtypes.txt --- minetest.conf.example - --- Section context mapping: --- * [Graphics and Audio]: [client] - - --- -------------------- [Graphics and Audio] [*Graphics] -------------------- -- - --- --------------- [Graphics and Audio] [*Graphics] [**Screen] -------------- -- - ----@class _.LuantiSettings.graphics_and_audio.graphics.screen ---[[ -# Width component of the initial window size. -# -# Requires: desktop -[client] -(Screen width) 1024 1 65535 -]] ----@field screen_w integer? ---[[ -# Height component of the initial window size. -# -# Requires: desktop -[client] -(Screen height) 600 1 65535 -]] ----@field screen_h integer? ---[[ -# Whether the window is maximized. -# -# Requires: desktop -[client] -(Window maximized) false -]] ----@field window_maximized boolean? ---[[ -# Save window size automatically when modified. -# If true, screen size is saved in screen_w and screen_h, and whether the window -# is maximized is stored in window_maximized. -# (Autosaving window_maximized only works if compiled with SDL.) -# -# Requires: desktop -[client] -(Remember screen size) true -]] ----@field autosave_screensize boolean? ---[[ -# Fullscreen mode. -# -# Requires: desktop -[client] -(Full screen) false -]] ----@field fullscreen boolean? ---[[ -# Open the pause menu when the window's focus is lost. Does not pause if a formspec is -# open. -# -# Requires: desktop -[client] -(Pause on lost window focus) false -]] ----@field pause_on_lost_focus boolean? - --- ---------------- [Graphics and Audio] [*Graphics] [**FPS] ---------------- -- - ----@class _.LuantiSettings.graphics_and_audio.graphics.fps ---[[ -# If FPS would go higher than this, limit it by sleeping -# to not waste CPU power for no benefit. -[client] -(Maximum FPS) 60 1 4294967295 -]] ----@field fps_max integer? ---[[ -# Vertical screen synchronization. Your system may still force VSync on even if this is disabled. -[client] -(VSync) false -]] ----@field vsync boolean? ---[[ -# Maximum FPS when the window is not focused. -[client] -(FPS when unfocused) 10 1 4294967295 -]] ----@field fps_max_unfocused integer? ---[[ -# View distance in nodes. -[client] -(Viewing range) 190 20 4000 -]] ----@field viewing_range integer? ---[[ -# Undersampling is similar to using a lower screen resolution, but it applies -# to the game world only, keeping the GUI intact. -# It should give a significant performance boost at the cost of less detailed image. -# Higher values result in a less detailed image. -# Note: Undersampling is currently not supported if the "3d_mode" setting is set -# to a non-default value. -[client] -(Undersampling) 1 1 8 -]] ----@field undersampling integer? - --- ----------------- [Graphics and Audio] [*Graphics] [**3D] ---------------- -- - ---[[ -WIPDOC -]] ----@alias core.LuantiSettings.enums.3d_mode ---- | "none" ---- | "anaglyph" ---- | "interlaced" ---- | "topbottom" ---- | "sidebyside" ---- | "crossview" - ----@class _.LuantiSettings.graphics_and_audio.graphics.3d ---[[ -# 3D support. -# Currently supported: -# - none: no 3d output. -# - anaglyph: cyan/magenta color 3d. -# - interlaced: odd/even line based polarization screen support. -# - topbottom: split screen top/bottom. -# - sidebyside: split screen side by side. -# - crossview: Cross-eyed 3d -[client] -(3D mode) none none,anaglyph,interlaced,topbottom,sidebyside,crossview -]] ----@field ["3d_mode"] core.LuantiSettings.enums.3d_mode? ---[[ -# Strength of 3D mode parallax. -[client] -(3D mode parallax strength) 0.025 -0.087 0.087 -]] ----@field ["3d_paralax_strength"] number? - --- -------------- [Graphics and Audio] [*Graphics] [**Bobbing] -------------- -- - ----@class _.LuantiSettings.graphics_and_audio.graphics.bobbing ---[[ -# Arm inertia, gives a more realistic movement of -# the arm when the camera moves. -[client] -(Arm inertia) true -]] ----@field arm_inertia boolean? ---[[ -# Enable view bobbing and amount of view bobbing. -# For example: 0 for no view bobbing; 1.0 for normal; 2.0 for double. -[client] -(View bobbing factor) 1.0 0.0 7.9 -]] ----@field view_bobbing_amount number? - --- --------------- [Graphics and Audio] [*Graphics] [**Camera] -------------- -- - ----@class _.LuantiSettings.graphics_and_audio.graphics.camera ---[[ -# Field of view in degrees. -[client] -(Field of view) 72 45 160 -]] ----@field fov integer? ---[[ -# Alters the light curve by applying 'gamma correction' to it. -# Higher values make middle and lower light levels brighter. -# Value '1.0' leaves the light curve unaltered. -# This only has significant effect on daylight and artificial -# light, it has very little effect on natural night light. -[client] -(Light curve gamma) 1.0 0.33 3.0 -]] ----@field display_gamma number? ---[[ -# The strength (darkness) of node ambient-occlusion shading. -# Lower is darker, Higher is lighter. The valid range of values for this -# setting is 0.25 to 4.0 inclusive. If the value is out of range it will be -# set to the nearest valid value. -[client] -(Ambient occlusion gamma) 1.8 0.25 4.0 -]] ----@field ambient_occlusion_gamma number? - --- ------------ [Graphics and Audio] [*Graphics] [**Screenshots] ------------ -- - ---[[ -WIPDOC -]] ----@alias core.LuantiSettings.enums.screenshot_format ---- | "png" ---- | "jpg" - ----@class _.LuantiSettings.graphics_and_audio.graphics.screenshots ---[[ -# Path to save screenshots at. Can be an absolute or relative path. -# The folder will be created if it doesn't already exist. -# -# Requires: desktop -[client] -(Screenshot folder) screenshots -]] ----@field screenshot_path core.LuantiSettings.path? ---[[ -# Format of screenshots. -# -# Requires: desktop -[client] -(Screenshot format) png png,jpg -]] ----@field screenshot_format core.LuantiSettings.enums.screenshot_format? ---[[ -# Screenshot quality. Only used for JPEG format. -# 1 means worst quality; 100 means best quality. -# Use 0 for default quality. -# -# Requires: desktop -[client] -(Screenshot quality) 0 0 100 -]] ----@field screenshot_quality integer? - --- ---- [Graphics and Audio] [*Graphics] [**Node and Entity Highlighting] --- -- - ---[[ -WIPDOC -]] ----@alias core.LuantiSettings.enums.node_highlighting ---- | "box" ---- | "halo" ---- | "none" - ----@class _.LuantiSettings.graphics_and_audio.graphics.node_and_entity_highlighting ---[[ -# Method used to highlight selected object. -[client] -(Node highlighting) box box,halo,none -]] ----@field node_highlighting core.LuantiSettings.enums.node_highlighting? ---[[ -# Show entity selection boxes -# A restart is required after changing this. -[client] -(Show entity selection boxes) false -]] ----@field show_entity_selectionbox boolean? ---[[ -# Selection box border color (R,G,B). -[client] -(Selection box color) (0,0,0) -]] ----@field selectionbox_color string? ---[[ -# Width of the selection box lines around nodes. -[client] -(Selection box width) 2 1 5 -]] ----@field selectionbox_width integer? ---[[ -# Crosshair color (R,G,B). -# Also controls the object crosshair color -[client] -(Crosshair color) (255,255,255) -]] ----@field crosshair_color string? ---[[ -# Crosshair alpha (opaqueness, between 0 and 255). -# This also applies to the object crosshair. -[client] -(Crosshair alpha) 255 0 255 -]] ----@field crosshair_alpha integer? - --- ---------------- [Graphics and Audio] [*Graphics] [**Fog] ---------------- -- - ----@class _.LuantiSettings.graphics_and_audio.graphics.fog ---[[ -# Whether to fog out the end of the visible area. -[client] -(Fog) true -]] ----@field enable_fog boolean? ---[[ -# Make fog and sky colors depend on daytime (dawn/sunset) and view direction. -# -# Requires: enable_fog -[client] -(Colored fog) true -]] ----@field directional_colored_fog boolean? ---[[ -# Fraction of the visible distance at which fog starts to be rendered -# -# Requires: enable_fog -[client] -(Fog start) 0.4 0.0 0.99 -]] ----@field fog_start number? - --- --------------- [Graphics and Audio] [*Graphics] [**Clouds] -------------- -- - ----@class _.LuantiSettings.graphics_and_audio.graphics.clouds ---[[ -# Allow clouds to look 3D instead of flat. -[client] -(3D clouds) true -]] ----@field enable_3d_clouds boolean? ---[[ -# Use smooth cloud shading. -# -# Requires: enable_3d_clouds -[client] -(Soft clouds) false -]] ----@field soft_clouds boolean? - --- ----- [Graphics and Audio] [*Graphics] [**Filtering and Antialiasing] ---- -- - ----@class _.LuantiSettings.graphics_and_audio.graphics.filtering_and_antialiasing ---[[ -# Use mipmaps when scaling textures. May slightly increase performance, -# especially when using a high-resolution texture pack. -# Gamma-correct downscaling is not supported. -[client] -(Mipmapping) false -]] ----@field mip_map boolean? ---[[ -# Use bilinear filtering when scaling textures. -[client] -(Bilinear filtering) false -]] ----@field bilinear_filter boolean? ---[[ -# Use trilinear filtering when scaling textures. -# If both bilinear and trilinear filtering are enabled, trilinear filtering -# is applied. -[client] -(Trilinear filtering) false -]] ----@field trilinear_filter boolean? ---[[ -# Use anisotropic filtering when looking at textures from an angle. -# This provides a significant improvement when used together with mipmapping. -[client] -(Anisotropic filtering) false -]] ----@field anisotropic_filter boolean? - ---[[ -WIPDOC -]] ----@alias core.LuantiSettings.enums.antialiasing ---- | "none" ---- | "fsaa" ---- | "fxaa" ---- | "ssaa" - ----@class _.LuantiSettings.graphics_and_audio.graphics.filtering_and_antialiasing ---[[ -# Select the antialiasing method to apply. -# -# * None - No antialiasing (default) -# -# * FSAA - Hardware-provided full-screen antialiasing -# A.K.A multi-sample antialiasing (MSAA) -# Smoothens out block edges but does not affect the insides of textures. -# -# If Post Processing is disabled, changing FSAA requires a restart. -# Also, if Post Processing is disabled, FSAA will not work together with -# undersampling or a non-default "3d_mode" setting. -# -# * FXAA - Fast approximate antialiasing -# Applies a post-processing filter to detect and smoothen high-contrast edges. -# Provides balance between speed and image quality. -# -# * SSAA - Super-sampling antialiasing -# Renders higher-resolution image of the scene, then scales down to reduce -# the aliasing effects. This is the slowest and the most accurate method. -[client] -(Antialiasing method) none none,fsaa,fxaa,ssaa -]] ----@field antialiasing core.LuantiSettings.enums.antialiasing? - ---[[ -WIPDOC -]] ----@alias core.LuantiSettings.enums.fsaa ---- | "2" ---- | "4" ---- | "8" ---- | "16" - ----@class _.LuantiSettings.graphics_and_audio.graphics.filtering_and_antialiasing ---[[ -# Defines the size of the sampling grid for FSAA and SSAA antialiasing methods. -# Value of 2 means taking 2x2 = 4 samples. -[client] -(Anti-aliasing scale) 2 2,4,8,16 -]] ----@field fsaa core.LuantiSettings.enums.fsaa? - --- --------- [Graphics and Audio] [*Graphics] [**Occlusion Culling] --------- -- - ---[[ -WIPDOC -]] ----@alias core.LuantiSettings.enums.occlusion_culler ---- | "bfs" ---- | "loops" - ---[[ -WIPDOC -]] ----@class _.LuantiSettings.graphics_and_audio.graphics.occlusion_culling ---[[ -# Type of occlusion_culler -# -# "loops" is the legacy algorithm with nested loops and O(n³) complexity -# "bfs" is the new algorithm based on breadth-first-search and side culling -# -# This setting should only be changed if you have performance problems. -[client] -(Occlusion Culler) bfs bfs,loops -]] ----@field occlusion_culler core.LuantiSettings.enums.occlusion_culler? ---[[ -# Use raytraced occlusion culling in the new culler. -# This flag enables use of raytraced occlusion culling test for -# client mesh sizes smaller than 4x4x4 map blocks. -[client] -(Enable Raytraced Culling) true -]] ----@field enable_raytraced_culling boolean? - --- --------------------- [Graphics and Audio] [*Effects] -------------------- -- - ---[[ -WIPDOC -]] ----@alias core.LuantiSettings.enums.leaves_style ---- | "fancy" ---- | "simple" ---- | "opaque" - ---[[ -WIPDOC -]] ----@class _.LuantiSettings.graphics_and_audio.effects ---[[ -# Allows liquids to be translucent. -[client] -(Translucent liquids) true -]] ----@field translucent_liquids boolean? ---[[ -# Leaves style: -# - Fancy: all faces visible -# - Simple: only outer faces -# - Opaque: disable transparency -[client] -(Leaves style) fancy fancy,simple,opaque -]] ----@field leaves_style core.LuantiSettings.enums.leaves_style? ---[[ -# Connects glass if supported by node. -[client] -(Connect glass) false -]] ----@field connected_glass boolean? ---[[ -# Enable smooth lighting with simple ambient occlusion. -[client] -(Smooth lighting) true -]] ----@field smooth_lighting boolean? ---[[ -# Enables tradeoffs that reduce CPU load or increase rendering performance -# at the expense of minor visual glitches that do not impact game playability. -[client] -(Tradeoffs for performance) false -]] ----@field performance_tradeoffs boolean? - - --- ------------ [Graphics and Audio] [*Effects] [**Waving Nodes] ------------ -- - - ---[[ -WIPDOC -]] ----@class _.LuantiSettings.graphics_and_audio.effects.waving_nodes ---[[ -# Set to true to enable waving leaves. -[client] -(Waving leaves) false -]] ----@field enable_waving_leaves boolean? ---[[ -# Set to true to enable waving plants. -[client] -(Waving plants) false -]] ----@field enable_waving_plants boolean? ---[[ -# Set to true to enable waving liquids (like water). -[client] -(Waving liquids) false -]] ----@field enable_waving_water boolean? ---[[ -# The maximum height of the surface of waving liquids. -# 4.0 = Wave height is two nodes. -# 0.0 = Wave doesn't move at all. -# Default is 1.0 (1/2 node). -# -# Requires: enable_waving_water -[client] -(Waving liquids wave height) 1.0 0.0 4.0 -]] ----@field water_wave_height number? ---[[ -# Length of liquid waves. -# -# Requires: enable_waving_water -[client] -(Waving liquids wavelength) 20.0 0.1 -]] ----@field water_wave_length number? ---[[ -# How fast liquid waves will move. Higher = faster. -# If negative, liquid waves will move backwards. -# -# Requires: enable_waving_water -[client] -(Waving liquids wave speed) 5.0 -]] ----@field water_wave_speed number? - --- ----------- [Graphics and Audio] [*Effects] [**Dynamic shadows] ---------- -- - ---[[ -WIPDOC -]] ----@class _.LuantiSettings.graphics_and_audio.effects.dynamic_shadows ---[[ -# Set to true to enable Shadow Mapping. -# -# Requires: opengl -[client] -(Dynamic shadows) false -]] ----@field enable_dynamic_shadows boolean? ---[[ -# Set the shadow strength gamma. -# Adjusts the intensity of in-game dynamic shadows. -# Lower value means lighter shadows, higher value means darker shadows. -# -# Requires: enable_dynamic_shadows, opengl -[client] -(Shadow strength gamma) 1.0 0.1 10.0 -]] ----@field shadow_strength_gamma number? ---[[ -# Maximum distance to render shadows. -# -# Requires: enable_dynamic_shadows, opengl -[client] -(Shadow map max distance in nodes to render shadows) 140.0 10.0 1000.0 -]] ----@field shadow_map_max_distance number? ---[[ -# Texture size to render the shadow map on. -# This must be a power of two. -# Bigger numbers create better shadows but it is also more expensive. -# -# Requires: enable_dynamic_shadows, opengl -[client] -(Shadow map texture size) 2048 128 8192 -]] ----@field shadow_map_texture_size integer? ---[[ -# Sets shadow texture quality to 32 bits. -# On false, 16 bits texture will be used. -# This can cause much more artifacts in the shadow. -# -# Requires: enable_dynamic_shadows, opengl -[client] -(Shadow map texture in 32 bits) true -]] ----@field shadow_map_texture_32bit boolean? - ---[[ -WIPDOC -]] ----@alias core.LuantiSettings.enums.shadow_filters ---- | "0" ---- | "1" ---- | "2" - ----@class _.LuantiSettings.graphics_and_audio.effects.dynamic_shadows ---[[ -# Define shadow filtering quality. -# This simulates the soft shadows effect by applying a PCF or Poisson disk -# but also uses more resources. -# -# Requires: enable_dynamic_shadows, opengl -[client] -(Shadow filter quality) 1 0,1,2 -]] ----@field shadow_filters core.LuantiSettings.enums.shadow_filters? ---[[ -# Enable colored shadows for transculent nodes. -# This is expensive. -# -# Requires: enable_dynamic_shadows, opengl -[client] -(Colored shadows) false -]] ----@field shadow_map_color boolean? ---[[ -# Set the soft shadow radius size. -# Lower values mean sharper shadows, bigger values mean softer shadows. -# Minimum value: 1.0; maximum value: 15.0 -# -# Requires: enable_dynamic_shadows, opengl -[client] -(Soft shadow radius) 5.0 1.0 15.0 -]] ----@field shadow_soft_radius number? ---[[ -# Set the default tilt of Sun/Moon orbit in degrees. -# Games may change orbit tilt via API. -# Value of 0 means no tilt / vertical orbit. -# -# Requires: enable_dynamic_shadows, opengl -[client] -(Sky Body Orbit Tilt) 0.0 -60.0 60.0 -]] ----@field shadow_sky_body_orbit_tilt number? - --- ----------- [Graphics and Audio] [*Effects] [**Post Processing] ---------- -- - ---[[ -WIPDOC -]] ----@class _.LuantiSettings.graphics_and_audio.effects.post_processing ---[[ -# Enables the post processing pipeline. -[client] -(Enable Post Processing) true -]] ----@field enable_post_processing boolean? ---[[ -# Enables Hable's 'Uncharted 2' filmic tone mapping. -# Simulates the tone curve of photographic film and how this approximates the -# appearance of high dynamic range images. Mid-range contrast is slightly -# enhanced, highlights and shadows are gradually compressed. -# -# Requires: enable_post_processing -[client] -(Filmic tone mapping) false -]] ----@field tone_mapping boolean? ---[[ -# Enable automatic exposure correction -# When enabled, the post-processing engine will -# automatically adjust to the brightness of the scene, -# simulating the behavior of human eye. -# -# Requires: enable_post_processing -[client] -(Enable Automatic Exposure) false -]] ----@field enable_auto_exposure boolean? ---[[ -# Set the exposure compensation in EV units. -# Value of 0.0 (default) means no exposure compensation. -# Range: from -1 to 1.0 -# -# Requires: enable_post_processing, enable_auto_exposure -[client] -(Exposure compensation) 0.0 -1.0 1.0 -]] ----@field exposure_compensation number? ---[[ -# Apply dithering to reduce color banding artifacts. -# Dithering significantly increases the size of losslessly-compressed -# screenshots and it works incorrectly if the display or operating system -# performs additional dithering or if the color channels are not quantized -# to 8 bits. -# With OpenGL ES, dithering only works if the shader supports high -# floating-point precision and it may have a higher performance impact. -# -# Requires: enable_post_processing -[client] -(Enable Debanding) true -]] ----@field debanding boolean? ---[[ -# Set to true to enable bloom effect. -# Bright colors will bleed over the neighboring objects. -# -# Requires: enable_post_processing -[client] -(Enable Bloom) false -]] ----@field enable_bloom boolean? ---[[ -# Set to true to enable volumetric lighting effect (a.k.a. "Godrays"). -# -# Requires: enable_post_processing, enable_bloom -[client] -(Volumetric lighting) false -]] ----@field enable_volumetric_lighting boolean? - --- ------------ [Graphics and Audio] [*Effects] [**Other Effects] ----------- -- - ---[[ -WIPDOC -]] ----@class _.LuantiSettings.graphics_and_audio.effects.other_effects ---[[ -# Simulate translucency when looking at foliage in the sunlight. -# -# Requires: enable_dynamic_shadows -[client] -(Translucent foliage) false -]] ----@field enable_translucent_foliage boolean? ---[[ -# When enabled, liquid reflections are simulated. -# -# Requires: enable_waving_water, enable_dynamic_shadows -[client] -(Liquid reflections) false -]] ----@field enable_water_reflections boolean? - --- ---------------------- [Graphics and Audio] [*Audio] --------------------- -- - ---[[ -WIPDOC -]] ----@class _.LuantiSettings.graphics_and_audio.audio ---[[ -# Volume of all sounds. -# Requires the sound system to be enabled. -[client] -(Volume) 0.8 0.0 1.0 -]] ----@field sound_volume number? ---[[ -# Volume multiplier when the window is unfocused. -[client] -(Volume when unfocused) 0.3 0.0 1.0 -]] ----@field sound_volume_unfocused number? ---[[ -# Whether to mute sounds. You can unmute sounds at any time. -# In-game, you can toggle the mute state with the mute key or by using the -# pause menu. -[client] -(Mute sound) false -]] ----@field mute_sound boolean? - --- ----------------- [Graphics and Audio] [*User Interfaces] ---------------- -- - ---[[ -WIPDOC -]] ----@alias core.LuantiSettings.enums.language ---- | "be" ---- | "bg" ---- | "ca" ---- | "cs" ---- | "da" ---- | "de" ---- | "el" ---- | "en" ---- | "eo" ---- | "es" ---- | "et" ---- | "eu" ---- | "fi" ---- | "fr" ---- | "gd" ---- | "gl" ---- | "hu" ---- | "id" ---- | "it" ---- | "ja" ---- | "jbo" ---- | "kk" ---- | "ko" ---- | "lt" ---- | "lv" ---- | "ms" ---- | "nb" ---- | "nl" ---- | "nn" ---- | "pl" ---- | "pt" ---- | "pt_BR" ---- | "ro" ---- | "ru" ---- | "sk" ---- | "sl" ---- | "sr_Cyrl" ---- | "sr_Latn" ---- | "sv" ---- | "sw" ---- | "tr" ---- | "uk" ---- | "vi" ---- | "zh_CN" ---- | "zh_TW" - ---[[ -WIPDOC -]] ----@class _.LuantiSettings.graphics_and_audio.user_interface ---[[ -# Set the language. By default, the system language is used. -# A restart is required after changing this. -[client] -(Language) ,be,bg,ca,cs,da,de,el,en,eo,es,et,eu,fi,fr,gd,gl,hu,id,it,ja,jbo,kk,ko,lt,lv,ms,nb,nl,nn,pl,pt,pt_BR,ro,ru,sk,sl,sr_Cyrl,sr_Latn,sv,sw,tr,uk,vi,zh_CN,zh_TW -]] ----@field language core.LuantiSettings.enums.language? - --- ------------- [Graphics and Audio] [*User Interface] [**GUI] ------------- -- - ---[[ -WIPDOC -]] ----@class _.LuantiSettings.graphics_and_audio.user_interface.gui ---[[ -# When enabled, the GUI is optimized to be more usable on touchscreens. -# Whether this is enabled by default depends on your hardware form-factor. -[client] -(Optimize GUI for touchscreens) false -]] ----@field touch_gui boolean? ---[[ -# Scale GUI by a user specified value. -# Use a nearest-neighbor-anti-alias filter to scale the GUI. -# This will smooth over some of the rough edges, and blend -# pixels when scaling down, at the cost of blurring some -# edge pixels when images are scaled by non-integer sizes. -[client] -(GUI scaling) 1.0 0.5 20 -]] ----@field gui_scaling number? ---[[ -# Enables smooth scrolling. -[client] -(Smooth scrolling) true -]] ----@field smooth_scrolling boolean? ---[[ -# Enables animation of inventory items. -[client] -(Inventory items animations) false -]] ----@field inventory_items_animations boolean? ---[[ -# Formspec full-screen background opacity (between 0 and 255). -[client] -(Formspec Full-Screen Background Opacity) 140 0 255 -]] ----@field formspec_fullscreen_bg_opacity integer? ---[[ -# Formspec full-screen background color (R,G,B). -[client] -(Formspec Full-Screen Background Color) (0,0,0) -]] ----@field formspec_fullscreen_bg_color string? ---[[ -# When gui_scaling_filter is true, all GUI images need to be -# filtered in software, but some images are generated directly -# to hardware (e.g. render-to-texture for nodes in inventory). -[client] -(GUI scaling filter) false -]] ----@field gui_scaling_filter boolean? ---[[ -# Delay showing tooltips, stated in milliseconds. -[client] -(Tooltip delay) 400 0 18446744073709551615 -]] ----@field tooltip_show_delay integer? ---[[ -# Append item name to tooltip. -[client] -(Append item name) false -]] ----@field tooltip_append_itemname boolean? ---[[ -# Use a cloud animation for the main menu background. -[client] -(Clouds in menu) true -]] ----@field menu_clouds boolean? - --- ------------- [Graphics and Audio] [*User Interface] [**HUD] ------------- -- - ---[[ -WIPDOC -]] ----@class _.LuantiSettings.graphics_and_audio.user_interface.hud ---[[ -# Modifies the size of the HUD elements. -[client] -(HUD scaling) 1.0 0.5 20 -]] ----@field hud_scaling number? ---[[ -# Whether name tag backgrounds should be shown by default. -# Mods may still set a background. -[client] -(Show name tag backgrounds by default) true -]] ----@field show_nametag_backgrounds boolean? ---[[ -# Whether to show the client debug info (has the same effect as hitting F5). -[client] -(Show debug info) false -]] ----@field show_debug boolean? ---[[ -# Radius to use when the block bounds HUD feature is set to near blocks. -[client] -(Block bounds HUD radius) 4 0 1000 -]] ----@field show_block_bounds_radius_near integer? ---[[ -# Maximum proportion of current window to be used for hotbar. -# Useful if there's something to be displayed right or left of hotbar. -[client] -(Maximum hotbar width) 1.0 0.001 1.0 -]] ----@field hud_hotbar_max_width number? - --- ------------- [Graphics and Audio] [*User Interface] [**Chat] ------------ -- - ---[[ -WIPDOC -]] ----@class _.LuantiSettings.graphics_and_audio.user_interface.chat ---[[ -# Maximum number of recent chat messages to show -[client] -(Recent Chat Messages) 6 2 20 -]] ----@field recent_chat_messages integer? ---[[ -# In-game chat console height, between 0.1 (10%) and 1.0 (100%). -[client] -(Console height) 0.6 0.1 1.0 -]] ----@field console_height number? ---[[ -# In-game chat console background color (R,G,B). -[client] -(Console color) (0,0,0) -]] ----@field console_color string? ---[[ -# In-game chat console background alpha (opaqueness, between 0 and 255). -[client] -(Console alpha) 200 0 255 -]] ----@field console_alpha integer? ---[[ -# Optional override for chat weblink color. -[client] -(Weblink color) #8888FF -]] ----@field chat_weblink_color string? ---[[ -# Font size of the recent chat text and chat prompt in point (pt). -# Value 0 will use the default font size. -[client] -(Chat font size) 0 0 72 -]] ----@field chat_font_size integer? - - --- ------ [Graphics and Audio] [*User Interface] [**Content Repository] ----- -- - ---[[ -WIPDOC -]] ----@class _.LuantiSettings.graphics_and_audio.user_interfaces.content_repository ---[[ -# The URL for the content repository -[client] -(ContentDB URL) https://content.luanti.org -]] ----@field contentdb_url string? ---[[ -# If enabled and you have ContentDB packages installed, Luanti may contact ContentDB to -# check for package updates when opening the mainmenu. -[client] -(Enable updates available indicator on content tab) true -]] ----@field contentdb_enable_updates_indicator boolean? ---[[ -# Comma-separated list of flags to hide in the content repository. -# "nonfree" can be used to hide packages which do not qualify as 'free software', -# as defined by the Free Software Foundation. -# You can also specify content ratings. -# These flags are independent from Luanti versions, -# so see a full list at https://content.luanti.org/help/content_flags/ -[client] -(ContentDB Flag Blacklist) nonfree, desktop_default -]] ----@field contentdb_flag_blacklist string? ---[[ -# Maximum number of concurrent downloads. Downloads exceeding this limit will be queued. -# This should be lower than curl_parallel_limit. -[client] -(ContentDB Max Concurrent Downloads) 3 1 -]] ----@field contentdb_max_concurrent_downloads integer? \ No newline at end of file diff --git a/types/luanti_lsp_definitions/library/classes/Settings/LuantiSettings/mapgen.lua b/types/luanti_lsp_definitions/library/classes/Settings/LuantiSettings/mapgen.lua deleted file mode 100644 index 1998e7e9..00000000 --- a/types/luanti_lsp_definitions/library/classes/Settings/LuantiSettings/mapgen.lua +++ /dev/null @@ -1,1888 +0,0 @@ ----@meta _ --- DRAFT 1 DONE --- builtin/settingtypes.txt --- minetest.conf.example - --- Section context mapping: --- * [Mapgen]: [world_creation] - ----@alias _.LuantiSettings.mapgen.keys.noise_params.2d ---- | "mg_biome_np_heat" ---- | "mg_biome_np_heat_blend" ---- | "mg_biome_np_humidity" ---- | "mg_biome_np_humidity_blend" ---- | "mgv5_np_filler_depth" ---- | "mgv5_np_factor" ---- | "mgv5_np_height" ---- | "mgv6_np_terrain_base" ---- | "mgv6_np_terrain_higher" ---- | "mgv6_np_steepness" ---- | "mgv6_np_height_select" ---- | "mgv6_np_mud" ---- | "mgv6_np_beach" ---- | "mgv6_np_biome" ---- | "mgv6_np_cave" ---- | "mgv6_np_humidity" ---- | "mgv6_np_trees" ---- | "mgv6_np_apple_trees" ---- | "mgv7_np_terrain_base" ---- | "mgv7_np_terrain_alt" ---- | "mgv7_np_terrain_persist" ---- | "mgv7_np_height_select" ---- | "mgv7_np_filler_depth" ---- | "mgv7_np_mount_height" ---- | "mgv7_np_ridge_uwater" ---- | "mgcarpathian_np_filler_depth" ---- | "mgcarpathian_np_height1" ---- | "mgcarpathian_np_height2" ---- | "mgcarpathian_np_height3" ---- | "mgcarpathian_np_height4" ---- | "mgcarpathian_np_hills_terrain" ---- | "mgcarpathian_np_ridge_terrain" ---- | "mgcarpathian_np_step_terrain" ---- | "mgcarpathian_np_hills" ---- | "mgcarpathian_np_ridge_mnt" ---- | "mgcarpathian_np_step_mnt" ---- | "mgcarpathian_np_rivers" ---- | "mgflat_np_terrain" ---- | "mgflat_np_filler_depth" ---- | "mgfractal_np_seabed" ---- | "mgfractal_np_filler_depth" ---- | "mgvalleys_np_filler_depth" ---- | "mgvalleys_np_rivers" ---- | "mgvalleys_np_terrain_height" ---- | "mgvalleys_np_valley_depth" ---- | "mgvalleys_np_valley_profile" ---- | "mgvalleys_np_inter_valley_slope" - ----@alias _.LuantiSettings.mapgen.keys.noise_params.3d ---- | "mgv5_np_cave1" ---- | "mgv5_np_cave2" ---- | "mgv5_np_cavern" ---- | "mgv5_np_ground" ---- | "mgv5_np_dungeons" ---- | "mgv7_np_mountain" ---- | "mgv7_np_ridge" ---- | "mgv7_np_floatland" ---- | "mgv7_np_cavern" ---- | "mgv7_np_cave1" ---- | "mgv7_np_cave2" ---- | "mgv7_np_dungeons" ---- | "mgcarpathian_np_mnt_var" ---- | "mgcarpathian_np_cave1" ---- | "mgcarpathian_np_cave2" ---- | "mgcarpathian_np_cavern" ---- | "mgcarpathian_np_dungeons" ---- | "mgflat_np_cave1" ---- | "mgflat_np_cave2" ---- | "mgflat_np_cavern" ---- | "mgflat_np_dungeons" ---- | "mgfractal_np_cave1" ---- | "mgfractal_np_cave2" ---- | "mgfractal_np_dungeons" ---- | "mgvalleys_np_cave1" ---- | "mgvalleys_np_cave2" ---- | "mgvalleys_np_cavern" ---- | "mgvalleys_np_inter_valley_fill" ---- | "mgvalleys_np_dungeons" - ----@alias _.LuantiSettings.mapgen.keys.vector ---- | "mgfractal_scale" ---- | "mgfractal_offset" - ----@alias _.LuantiSettings.mapgen.keys ---- | "fixed_map_seed" ---- | "mg_name" ---- | "water_level" ---- | "max_block_generate_distance" ---- | "mapgen_limit" ---- | "mg_flags" ---- | "mg_biome_np_heat" ---- | "mg_biome_np_heat_blend" ---- | "mg_biome_np_humidity" ---- | "mg_biome_np_humidity_blend" ---- | "mgv5_spflags" ---- | "mgv5_cave_width" ---- | "mgv5_large_cave_depth" ---- | "mgv5_small_cave_num_min" ---- | "mgv5_small_cave_num_max" ---- | "mgv5_large_cave_num_min" ---- | "mgv5_large_cave_num_max" ---- | "mgv5_large_cave_flooded" ---- | "mgv5_cavern_limit" ---- | "mgv5_cavern_taper" ---- | "mgv5_cavern_threshold" ---- | "mgv5_dungeon_ymin" ---- | "mgv5_dungeon_ymax" ---- | "mgv5_np_filler_depth" ---- | "mgv5_np_factor" ---- | "mgv5_np_height" ---- | "mgv5_np_cave1" ---- | "mgv5_np_cave2" ---- | "mgv5_np_cavern" ---- | "mgv5_np_ground" ---- | "mgv5_np_dungeons" ---- | "mgv6_spflags" ---- | "mgv6_freq_desert" ---- | "mgv6_freq_beach" ---- | "mgv6_dungeon_ymin" ---- | "mgv6_dungeon_ymax" ---- | "mgv6_np_terrain_base" ---- | "mgv6_np_terrain_higher" ---- | "mgv6_np_steepness" ---- | "mgv6_np_height_select" ---- | "mgv6_np_mud" ---- | "mgv6_np_beach" ---- | "mgv6_np_biome" ---- | "mgv6_np_cave" ---- | "mgv6_np_humidity" ---- | "mgv6_np_trees" ---- | "mgv6_np_apple_trees" ---- | "mgv7_spflags" ---- | "mgv7_mount_zero_level" ---- | "mgv7_floatland_ymin" ---- | "mgv7_floatland_ymax" ---- | "mgv7_floatland_taper" ---- | "mgv7_float_taper_exp" ---- | "mgv7_floatland_density" ---- | "mgv7_floatland_ywater" ---- | "mgv7_cave_width" ---- | "mgv7_large_cave_depth" ---- | "mgv7_small_cave_num_min" ---- | "mgv7_small_cave_num_max" ---- | "mgv7_large_cave_num_min" ---- | "mgv7_large_cave_num_max" ---- | "mgv7_large_cave_flooded" ---- | "mgv7_cavern_limit" ---- | "mgv7_cavern_taper" ---- | "mgv7_cavern_threshold" ---- | "mgv7_dungeon_ymin" ---- | "mgv7_dungeon_ymax" ---- | "mgv7_np_terrain_base" ---- | "mgv7_np_terrain_alt" ---- | "mgv7_np_terrain_persist" ---- | "mgv7_np_height_select" ---- | "mgv7_np_filler_depth" ---- | "mgv7_np_mount_height" ---- | "mgv7_np_ridge_uwater" ---- | "mgv7_np_mountain" ---- | "mgv7_np_ridge" ---- | "mgv7_np_floatland" ---- | "mgv7_np_cavern" ---- | "mgv7_np_cave1" ---- | "mgv7_np_cave2" ---- | "mgv7_np_dungeons" ---- | "mgcarpathian_spflags" ---- | "mgcarpathian_base_level" ---- | "mgcarpathian_river_width" ---- | "mgcarpathian_river_depth" ---- | "mgcarpathian_valley_width" ---- | "mgcarpathian_cave_width" ---- | "mgcarpathian_large_cave_depth" ---- | "mgcarpathian_small_cave_num_min" ---- | "mgcarpathian_small_cave_num_max" ---- | "mgcarpathian_large_cave_num_min" ---- | "mgcarpathian_large_cave_num_max" ---- | "mgcarpathian_large_cave_flooded" ---- | "mgcarpathian_cavern_limit" ---- | "mgcarpathian_cavern_taper" ---- | "mgcarpathian_cavern_threshold" ---- | "mgcarpathian_dungeon_ymin" ---- | "mgcarpathian_dungeon_ymax" ---- | "mgcarpathian_np_filler_depth" ---- | "mgcarpathian_np_height1" ---- | "mgcarpathian_np_height2" ---- | "mgcarpathian_np_height3" ---- | "mgcarpathian_np_height4" ---- | "mgcarpathian_np_hills_terrain" ---- | "mgcarpathian_np_ridge_terrain" ---- | "mgcarpathian_np_step_terrain" ---- | "mgcarpathian_np_hills" ---- | "mgcarpathian_np_ridge_mnt" ---- | "mgcarpathian_np_step_mnt" ---- | "mgcarpathian_np_rivers" ---- | "mgcarpathian_np_mnt_var" ---- | "mgcarpathian_np_cave1" ---- | "mgcarpathian_np_cave2" ---- | "mgcarpathian_np_cavern" ---- | "mgcarpathian_np_dungeons" ---- | "mgflat_spflags" ---- | "mgflat_ground_level" ---- | "mgflat_large_cave_depth" ---- | "mgflat_small_cave_num_min" ---- | "mgflat_small_cave_num_max" ---- | "mgflat_large_cave_num_min" ---- | "mgflat_large_cave_num_max" ---- | "mgflat_large_cave_flooded" ---- | "mgflat_cave_width" ---- | "mgflat_lake_threshold" ---- | "mgflat_lake_steepness" ---- | "mgflat_hill_threshold" ---- | "mgflat_hill_steepness" ---- | "mgflat_cavern_limit" ---- | "mgflat_cavern_taper" ---- | "mgflat_cavern_threshold" ---- | "mgflat_dungeon_ymin" ---- | "mgflat_dungeon_ymax" ---- | "mgflat_np_terrain" ---- | "mgflat_np_filler_depth" ---- | "mgflat_np_cave1" ---- | "mgflat_np_cave2" ---- | "mgflat_np_cavern" ---- | "mgflat_np_dungeons" ---- | "mgfractal_spflags" ---- | "mgfractal_cave_width" ---- | "mgfractal_large_cave_depth" ---- | "mgfractal_small_cave_num_min" ---- | "mgfractal_small_cave_num_max" ---- | "mgfractal_large_cave_num_min" ---- | "mgfractal_large_cave_num_max" ---- | "mgfractal_large_cave_flooded" ---- | "mgfractal_dungeon_ymin" ---- | "mgfractal_dungeon_ymax" ---- | "mgfractal_fractal" ---- | "mgfractal_iterations" ---- | "mgfractal_scale" ---- | "mgfractal_offset" ---- | "mgfractal_slice_w" ---- | "mgfractal_julia_x" ---- | "mgfractal_julia_y" ---- | "mgfractal_julia_z" ---- | "mgfractal_julia_w" ---- | "mgfractal_np_seabed" ---- | "mgfractal_np_filler_depth" ---- | "mgfractal_np_cave1" ---- | "mgfractal_np_cave2" ---- | "mgfractal_np_dungeons" ---- | "mgvalleys_spflags" ---- | "mgvalleys_altitude_chill" ---- | "mgvalleys_large_cave_depth" ---- | "mgvalleys_small_cave_num_min" ---- | "mgvalleys_small_cave_num_max" ---- | "mgvalleys_large_cave_num_min" ---- | "mgvalleys_large_cave_num_max" ---- | "mgvalleys_large_cave_flooded" ---- | "mgvalleys_cavern_limit" ---- | "mgvalleys_cavern_taper" ---- | "mgvalleys_cavern_threshold" ---- | "mgvalleys_river_depth" ---- | "mgvalleys_river_size" ---- | "mgvalleys_cave_width" ---- | "mgvalleys_dungeon_ymin" ---- | "mgvalleys_dungeon_ymax" ---- | "mgvalleys_np_cave1" ---- | "mgvalleys_np_cave2" ---- | "mgvalleys_np_filler_depth" ---- | "mgvalleys_np_cavern" ---- | "mgvalleys_np_rivers" ---- | "mgvalleys_np_terrain_height" ---- | "mgvalleys_np_valley_depth" ---- | "mgvalleys_np_inter_valley_fill" ---- | "mgvalleys_np_valley_profile" ---- | "mgvalleys_np_inter_valley_slope" ---- | "mgvalleys_np_dungeons" - ----@class _.LuantiSettings.mapgen.tablefmt : _.LuantiSettings.mapgen, _.LuantiSettings.mapgen.biome_api, _.LuantiSettings.mapgen.mapgen_v5, _.LuantiSettings.mapgen.mapgen_v5.noises, _.LuantiSettings.mapgen.mapgen_v6, _.LuantiSettings.mapgen.mapgen_v6.noises, _.LuantiSettings.mapgen.mapgen_v7, _.LuantiSettings.mapgen.mapgen_v7.noises, _.LuantiSettings.mapgen.mapgen_carpathian, _.LuantiSettings.mapgen.mapgen_carpathian.noises, _.LuantiSettings.mapgen.mapgen_flat, _.LuantiSettings.mapgen.mapgen_flat.noises, _.LuantiSettings.mapgen.mapgen_fractal, _.LuantiSettings.mapgen.mapgen_fractal.noises, _.LuantiSettings.mapgen.mapgen_valleys, _.LuantiSettings.mapgen.mapgen_valleys.noises - --- -------------------------------- [Mapgen] -------------------------------- -- - ---[[ -WIPDOC -]] ----@alias core.LuantiSettings.enums.mg_name ---- | "v7" ---- | "valleys" ---- | "carpathian" ---- | "v5" ---- | "flat" ---- | "fractal" ---- | "singlenode" ---- | "v6" - ----@class _.LuantiSettings.mapgen ---[[ -# A chosen map seed for a new map, leave empty for random. -# Will be overridden when creating a new world in the main menu. -[world_creation] -(Fixed map seed) -]] ----@field fixed_map_seed string? ---[[ -# Name of map generator to be used when creating a new world. -# Creating a world in the main menu will override this. -# Current mapgens in a highly unstable state: -# - The optional floatlands of v7 (disabled by default). -[world_creation] -(Mapgen name) v7 v7,valleys,carpathian,v5,flat,fractal,singlenode,v6 -]] ----@field mg_name core.LuantiSettings.enums.mg_name? ---[[ -# Water surface level of the world. -[world_creation] -(Water level) 1 -31000 31000 -]] ----@field water_level integer? ---[[ -# From how far blocks are generated for clients, stated in mapblocks (16 nodes). -[world_creation] -(Max block generate distance) [server] 10 1 32767 -]] ----@field max_block_generate_distance integer? ---[[ -# Limit of map generation, in nodes, in all 6 directions from (0, 0, 0). -# Only mapchunks completely within the mapgen limit are generated. -# Value is stored per-world. -[world_creation] -(Map generation limit) 31007 0 31007 -]] ----@field mapgen_limit integer? - ---[[ -WIPDOC -]] ----@class core.LuantiSettings.flags.mg_flags ---[[ -WIPDOC -]] ----@field caves boolean? ---[[ -WIPDOC -]] ----@field nocaves boolean? ---[[ -WIPDOC -]] ----@field dungeons boolean? ---[[ -WIPDOC -]] ----@field nodungeons boolean? ---[[ -WIPDOC -]] ----@field light boolean? ---[[ -WIPDOC -]] ----@field nolight boolean? ---[[ -WIPDOC -]] ----@field decorations boolean? ---[[ -WIPDOC -]] ----@field nodecorations boolean? ---[[ -WIPDOC -]] ----@field biomes boolean? ---[[ -WIPDOC -]] ----@field nobiomes boolean? ---[[ -WIPDOC -]] ----@field ores boolean? ---[[ -WIPDOC -]] ----@field noores boolean? - ----@class _.LuantiSettings.mapgen ---[[ -# Global map generation attributes. -# In Mapgen v6 the 'decorations' flag controls all decorations except trees -# and jungle grass, in all other mapgens this flag controls all decorations. -[world_creation] -(Mapgen flags) caves,dungeons,light,decorations,biomes,ores caves,dungeons,light,decorations,biomes,ores -]] ----@field mg_flags core.LuantiSettings.flags? - --- -------------------------- [Mapgen] [*Biome API] ------------------------- -- - ----@class _.LuantiSettings.mapgen.biome_api ---[[ -# Temperature variation for biomes. -[world_creation] -(Heat noise) 50, 50, (1000, 1000, 1000), 5349, 3, 0.5, 2.0, eased -]] ----@field mg_biome_np_heat core.NoiseParams.2d? ---[[ -# Small-scale temperature variation for blending biomes on borders. -[world_creation] -(Heat blend noise) 0, 1.5, (8, 8, 8), 13, 2, 1.0, 2.0, eased -]] ----@field mg_biome_np_heat_blend core.NoiseParams.2d? ---[[ -# Humidity variation for biomes. -[world_creation] -(Humidity noise) 50, 50, (1000, 1000, 1000), 842, 3, 0.5, 2.0, eased -]] ----@field mg_biome_np_humidity core.NoiseParams.2d? ---[[ -# Small-scale humidity variation for blending biomes on borders. -[world_creation] -(Humidity blend noise) 0, 1.5, (8, 8, 8), 90003, 2, 1.0, 2.0, eased -]] ----@field mg_biome_np_humidity_blend core.NoiseParams.2d? - --- -------------------------- [Mapgen] [*Mapgen V5] ------------------------- -- - ---[[ -WIPDOC -]] ----@class core.LuantiSettings.flags.mgv5_spflags ---[[ -WIPDOC -]] ----@field caverns boolean? ---[[ -WIPDOC -]] ----@field nocaverns boolean? - ----@class _.LuantiSettings.mapgen.mapgen_v5 ---[[ -# Map generation attributes specific to Mapgen v5. -[world_creation] -(Mapgen V5 specific flags) caverns caverns -]] ----@field mgv5_spflags core.LuantiSettings.flags? ---[[ -# Controls width of tunnels, a smaller value creates wider tunnels. -# Value >= 10.0 completely disables generation of tunnels and avoids the -# intensive noise calculations. -[world_creation] -(Cave width) 0.09 -]] ----@field mgv5_cave_width number? ---[[ -# Y of upper limit of large caves. -[world_creation] -(Large cave depth) -256 -31000 31000 -]] ----@field mgv5_large_cave_depth integer? ---[[ -# Minimum limit of random number of small caves per mapchunk. -[world_creation] -(Small cave minimum number) 0 0 256 -]] ----@field mgv5_small_cave_num_min integer? ---[[ -# Maximum limit of random number of small caves per mapchunk. -[world_creation] -(Small cave maximum number) 0 0 256 -]] ----@field mgv5_small_cave_num_max integer? ---[[ -# Minimum limit of random number of large caves per mapchunk. -[world_creation] -(Large cave minimum number) 0 0 64 -]] ----@field mgv5_large_cave_num_min integer? ---[[ -# Maximum limit of random number of large caves per mapchunk. -[world_creation] -(Large cave maximum number) 2 0 64 -]] ----@field mgv5_large_cave_num_max integer? ---[[ -# Proportion of large caves that contain liquid. -[world_creation] -(Large cave proportion flooded) 0.5 0.0 1.0 -]] ----@field mgv5_large_cave_flooded number? ---[[ -# Y-level of cavern upper limit. -[world_creation] -(Cavern limit) -256 -31000 31000 -]] ----@field mgv5_cavern_limit integer? ---[[ -# Y-distance over which caverns expand to full size. -[world_creation] -(Cavern taper) 256 0 32767 -]] ----@field mgv5_cavern_taper integer? ---[[ -# Defines full size of caverns, smaller values create larger caverns. -[world_creation] -(Cavern threshold) 0.7 -]] ----@field mgv5_cavern_threshold number? ---[[ -# Lower Y limit of dungeons. -[world_creation] -(Dungeon minimum Y) -31000 -31000 31000 -]] ----@field mgv5_dungeon_ymin integer? ---[[ -# Upper Y limit of dungeons. -[world_creation] -(Dungeon maximum Y) 31000 -31000 31000 -]] ----@field mgv5_dungeon_ymax integer? - --- -------------------- [Mapgen] [*Mapgen V5] [**Noises] -------------------- -- - ----@class _.LuantiSettings.mapgen.mapgen_v5.noises ---[[ -# Variation of biome filler depth. -[world_creation] -(Filler depth noise) 0, 1, (150, 150, 150), 261, 4, 0.7, 2.0, eased -]] ----@field mgv5_np_filler_depth core.NoiseParams.2d? ---[[ -# Variation of terrain vertical scale. -# When noise is < -0.55 terrain is near-flat. -[world_creation] -(Factor noise) 0, 1, (250, 250, 250), 920381, 3, 0.45, 2.0, eased -]] ----@field mgv5_np_factor core.NoiseParams.2d? ---[[ -# Y-level of average terrain surface. -[world_creation] -(Height noise) 0, 10, (250, 250, 250), 84174, 4, 0.5, 2.0, eased -]] ----@field mgv5_np_height core.NoiseParams.2d? ---[[ -# First of two 3D noises that together define tunnels. -[world_creation] -(Cave1 noise) 0, 12, (61, 61, 61), 52534, 3, 0.5, 2.0 -]] ----@field mgv5_np_cave1 core.NoiseParams.3d? ---[[ -# Second of two 3D noises that together define tunnels. -[world_creation] -(Cave2 noise) 0, 12, (67, 67, 67), 10325, 3, 0.5, 2.0 -]] ----@field mgv5_np_cave2 core.NoiseParams.3d? ---[[ -# 3D noise defining giant caverns. -[world_creation] -(Cavern noise) 0, 1, (384, 128, 384), 723, 5, 0.63, 2.0 -]] ----@field mgv5_np_cavern core.NoiseParams.3d? ---[[ -# 3D noise defining terrain. -[world_creation] -(Ground noise) 0, 40, (80, 80, 80), 983240, 4, 0.55, 2.0, eased -]] ----@field mgv5_np_ground core.NoiseParams.3d? ---[[ -# 3D noise that determines number of dungeons per mapchunk. -[world_creation] -(Dungeon noise) 0.9, 0.5, (500, 500, 500), 0, 2, 0.8, 2.0 -]] ----@field mgv5_np_dungeons core.NoiseParams.3d? - --- -------------------------- [Mapgen] [*Mapgen V6] ------------------------- -- - ---[[ -WIPDOC -]] ----@class core.LuantiSettings.flags.mgv6_spflags ---[[ -WIPDOC -]] ----@field jungles boolean? ---[[ -WIPDOC -]] ----@field nojungles boolean? ---[[ -WIPDOC -]] ----@field biomeblend boolean? ---[[ -WIPDOC -]] ----@field nobiomeblend boolean? ---[[ -WIPDOC -]] ----@field mudflow boolean? ---[[ -WIPDOC -]] ----@field nomudflow boolean? ---[[ -WIPDOC -]] ----@field snowbiomes boolean? ---[[ -WIPDOC -]] ----@field nosnowbiomes boolean? ---[[ -WIPDOC -]] ----@field flat boolean? ---[[ -WIPDOC -]] ----@field noflat boolean? ---[[ -WIPDOC -]] ----@field trees boolean? ---[[ -WIPDOC -]] ----@field notrees boolean? ---[[ -WIPDOC -]] ----@field temples boolean? ---[[ -WIPDOC -]] ----@field notemples boolean? - ----@class _.LuantiSettings.mapgen.mapgen_v6 ---[[ -# Map generation attributes specific to Mapgen v6. -# The 'snowbiomes' flag enables the new 5 biome system. -# When the 'snowbiomes' flag is enabled jungles are automatically enabled and -# the 'jungles' flag is ignored. -# The 'temples' flag disables generation of desert temples. Normal dungeons will appear instead. -[world_creation] -(Mapgen V6 specific flags) jungles,biomeblend,mudflow,snowbiomes,noflat,trees,temples jungles,biomeblend,mudflow,snowbiomes,flat,trees,temples -]] ----@field mgv6_spflags core.LuantiSettings.flags? ---[[ -# Deserts occur when np_biome exceeds this value. -# When the 'snowbiomes' flag is enabled, this is ignored. -[world_creation] -(Desert noise threshold) 0.45 -]] ----@field mgv6_freq_desert number? ---[[ -# Sandy beaches occur when np_beach exceeds this value. -[world_creation] -(Beach noise threshold) 0.15 -]] ----@field mgv6_freq_beach number? ---[[ -# Lower Y limit of dungeons. -[world_creation] -(Dungeon minimum Y) -31000 -31000 31000 -]] ----@field mgv6_dungeon_ymin integer? ---[[ -# Upper Y limit of dungeons. -[world_creation] -(Dungeon maximum Y) 31000 -31000 31000 -]] ----@field mgv6_dungeon_ymax integer? - --- -------------------- [Mapgen] [*Mapgen V6] [**Noises] -------------------- -- - ----@class _.LuantiSettings.mapgen.mapgen_v6.noises ---[[ -# Y-level of lower terrain and seabed. -[world_creation] -(Terrain base noise) -4, 20, (250, 250, 250), 82341, 5, 0.6, 2.0, eased -]] ----@field mgv6_np_terrain_base core.NoiseParams.2d? ---[[ -# Y-level of higher terrain that creates cliffs. -[world_creation] -(Terrain higher noise) 20, 16, (500, 500, 500), 85039, 5, 0.6, 2.0, eased -]] ----@field mgv6_np_terrain_higher core.NoiseParams.2d? ---[[ -# Varies steepness of cliffs. -[world_creation] -(Steepness noise) 0.85, 0.5, (125, 125, 125), -932, 5, 0.7, 2.0, eased -]] ----@field mgv6_np_steepness core.NoiseParams.2d? ---[[ -# Defines distribution of higher terrain. -[world_creation] -(Height select noise) 0.5, 1, (250, 250, 250), 4213, 5, 0.69, 2.0, eased -]] ----@field mgv6_np_height_select core.NoiseParams.2d? ---[[ -# Varies depth of biome surface nodes. -[world_creation] -(Mud noise) 4, 2, (200, 200, 200), 91013, 3, 0.55, 2.0, eased -]] ----@field mgv6_np_mud core.NoiseParams.2d? ---[[ -# Defines areas with sandy beaches. -[world_creation] -(Beach noise) 0, 1, (250, 250, 250), 59420, 3, 0.50, 2.0, eased -]] ----@field mgv6_np_beach core.NoiseParams.2d? ---[[ -# Temperature variation for biomes. -[world_creation] -(Biome noise) 0, 1, (500, 500, 500), 9130, 3, 0.50, 2.0, eased -]] ----@field mgv6_np_biome core.NoiseParams.2d? ---[[ -# Variation of number of caves. -[world_creation] -(Cave noise) 6, 6, (250, 250, 250), 34329, 3, 0.50, 2.0, eased -]] ----@field mgv6_np_cave core.NoiseParams.2d? ---[[ -# Humidity variation for biomes. -[world_creation] -(Humidity noise) 0.5, 0.5, (500, 500, 500), 72384, 3, 0.50, 2.0, eased -]] ----@field mgv6_np_humidity core.NoiseParams.2d? ---[[ -# Defines tree areas and tree density. -[world_creation] -(Trees noise) 0, 1, (125, 125, 125), 2, 4, 0.66, 2.0, eased -]] ----@field mgv6_np_trees core.NoiseParams.2d? ---[[ -# Defines areas where trees have apples. -[world_creation] -(Apple trees noise) 0, 1, (100, 100, 100), 342902, 3, 0.45, 2.0, eased -]] ----@field mgv6_np_apple_trees core.NoiseParams.2d? - --- -------------------------- [Mapgen] [*Mapgen V7] ------------------------- -- - ---[[ -WIPDOC -]] ----@class core.LuantiSettings.flags.mgv7_spflags ---[[ -WIPDOC -]] ----@field mountains boolean? ---[[ -WIPDOC -]] ----@field nomountains boolean? ---[[ -WIPDOC -]] ----@field ridges boolean? ---[[ -WIPDOC -]] ----@field noridges boolean? ---[[ -WIPDOC -]] ----@field floatlands boolean? ---[[ -WIPDOC -]] ----@field nofloatlands boolean? ---[[ -WIPDOC -]] ----@field caverns boolean? ---[[ -WIPDOC -]] ----@field nocaverns boolean? - ----@class _.LuantiSettings.mapgen.mapgen_v7 ---[[ -# Map generation attributes specific to Mapgen v7. -# 'ridges': Rivers. -# 'floatlands': Floating land masses in the atmosphere. -# 'caverns': Giant caves deep underground. -[world_creation] -(Mapgen V7 specific flags) mountains,ridges,nofloatlands,caverns mountains,ridges,floatlands,caverns -]] ----@field mgv7_spflags core.LuantiSettings.flags? ---[[ -# Y of mountain density gradient zero level. Used to shift mountains vertically. -[world_creation] -(Mountain zero level) 0 -31000 31000 -]] ----@field mgv7_mount_zero_level integer? ---[[ -# Lower Y limit of floatlands. -[world_creation] -(Floatland minimum Y) 1024 -31000 31000 -]] ----@field mgv7_floatland_ymin integer? ---[[ -# Upper Y limit of floatlands. -[world_creation] -(Floatland maximum Y) 4096 -31000 31000 -]] ----@field mgv7_floatland_ymax integer? ---[[ -# Y-distance over which floatlands taper from full density to nothing. -# Tapering starts at this distance from the Y limit. -# For a solid floatland layer, this controls the height of hills/mountains. -# Must be less than or equal to half the distance between the Y limits. -[world_creation] -(Floatland tapering distance) 256 0 32767 -]] ----@field mgv7_floatland_taper integer? ---[[ -# Exponent of the floatland tapering. Alters the tapering behavior. -# Value = 1.0 creates a uniform, linear tapering. -# Values > 1.0 create a smooth tapering suitable for the default separated -# floatlands. -# Values < 1.0 (for example 0.25) create a more defined surface level with -# flatter lowlands, suitable for a solid floatland layer. -[world_creation] -(Floatland taper exponent) 2.0 -]] ----@field mgv7_float_taper_exp number? ---[[ -# Adjusts the density of the floatland layer. -# Increase value to increase density. Can be positive or negative. -# Value = 0.0: 50% of volume is floatland. -# Value = 2.0 (can be higher depending on 'mgv7_np_floatland', always test -# to be sure) creates a solid floatland layer. -[world_creation] -(Floatland density) -0.6 -]] ----@field mgv7_floatland_density number? ---[[ -# Surface level of optional water placed on a solid floatland layer. -# Water is disabled by default and will only be placed if this value is set -# to above 'mgv7_floatland_ymax' - 'mgv7_floatland_taper' (the start of the -# upper tapering). -# ***WARNING, POTENTIAL DANGER TO WORLDS AND SERVER PERFORMANCE***: -# When enabling water placement, floatlands must be configured and tested -# to be a solid layer by setting 'mgv7_floatland_density' to 2.0 (or other -# required value depending on 'mgv7_np_floatland'), to avoid -# server-intensive extreme water flow and to avoid vast flooding of the -# world surface below. -[world_creation] -(Floatland water level) -31000 -31000 31000 -]] ----@field mgv7_floatland_ywater integer? ---[[ -# Controls width of tunnels, a smaller value creates wider tunnels. -# Value >= 10.0 completely disables generation of tunnels and avoids the -# intensive noise calculations. -[world_creation] -(Cave width) 0.09 -]] ----@field mgv7_cave_width number? ---[[ -# Y of upper limit of large caves. -[world_creation] -(Large cave depth) -33 -31000 31000 -]] ----@field mgv7_large_cave_depth integer? ---[[ -# Minimum limit of random number of small caves per mapchunk. -[world_creation] -(Small cave minimum number) 0 0 256 -]] ----@field mgv7_small_cave_num_min integer? ---[[ -# Maximum limit of random number of small caves per mapchunk. -[world_creation] -(Small cave maximum number) 0 0 256 -]] ----@field mgv7_small_cave_num_max integer? ---[[ -# Minimum limit of random number of large caves per mapchunk. -[world_creation] -(Large cave minimum number) 0 0 64 -]] ----@field mgv7_large_cave_num_min integer? ---[[ -# Maximum limit of random number of large caves per mapchunk. -[world_creation] -(Large cave maximum number) 2 0 64 -]] ----@field mgv7_large_cave_num_max integer? ---[[ -# Proportion of large caves that contain liquid. -[world_creation] -(Large cave proportion flooded) 0.5 0.0 1.0 -]] ----@field mgv7_large_cave_flooded number? ---[[ -# Y-level of cavern upper limit. -[world_creation] -(Cavern limit) -256 -31000 31000 -]] ----@field mgv7_cavern_limit integer? ---[[ -# Y-distance over which caverns expand to full size. -[world_creation] -(Cavern taper) 256 0 32767 -]] ----@field mgv7_cavern_taper integer? ---[[ -# Defines full size of caverns, smaller values create larger caverns. -[world_creation] -(Cavern threshold) 0.7 -]] ----@field mgv7_cavern_threshold number? ---[[ -# Lower Y limit of dungeons. -[world_creation] -(Dungeon minimum Y) -31000 -31000 31000 -]] ----@field mgv7_dungeon_ymin integer? ---[[ -# Upper Y limit of dungeons. -[world_creation] -(Dungeon maximum Y) 31000 -31000 31000 -]] ----@field mgv7_dungeon_ymax integer? - --- -------------------- [Mapgen] [*Mapgen V7] [**Noises] -------------------- -- - ----@class _.LuantiSettings.mapgen.mapgen_v7.noises ---[[ -# Y-level of higher terrain that creates cliffs. -[world_creation] -(Terrain base noise) 4, 70, (600, 600, 600), 82341, 5, 0.6, 2.0, eased -]] ----@field mgv7_np_terrain_base core.NoiseParams.2d? ---[[ -# Y-level of lower terrain and seabed. -[world_creation] -(Terrain alternative noise) 4, 25, (600, 600, 600), 5934, 5, 0.6, 2.0, eased -]] ----@field mgv7_np_terrain_alt core.NoiseParams.2d? ---[[ -# Varies roughness of terrain. -# Defines the 'persistence' value for terrain_base and terrain_alt noises. -[world_creation] -(Terrain persistence noise) 0.6, 0.1, (2000, 2000, 2000), 539, 3, 0.6, 2.0, eased -]] ----@field mgv7_np_terrain_persist core.NoiseParams.2d? ---[[ -# Defines distribution of higher terrain and steepness of cliffs. -[world_creation] -(Height select noise) -8, 16, (500, 500, 500), 4213, 6, 0.7, 2.0, eased -]] ----@field mgv7_np_height_select core.NoiseParams.2d? ---[[ -# Variation of biome filler depth. -[world_creation] -(Filler depth noise) 0, 1.2, (150, 150, 150), 261, 3, 0.7, 2.0, eased -]] ----@field mgv7_np_filler_depth core.NoiseParams.2d? ---[[ -# Variation of maximum mountain height (in nodes). -[world_creation] -(Mountain height noise) 256, 112, (1000, 1000, 1000), 72449, 3, 0.6, 2.0, eased -]] ----@field mgv7_np_mount_height core.NoiseParams.2d? ---[[ -# Defines large-scale river channel structure. -[world_creation] -(Ridge underwater noise) 0, 1, (1000, 1000, 1000), 85039, 5, 0.6, 2.0, eased -]] ----@field mgv7_np_ridge_uwater core.NoiseParams.2d? ---[[ -# 3D noise defining mountain structure and height. -# Also defines structure of floatland mountain terrain. -[world_creation] -(Mountain noise) -0.6, 1, (250, 350, 250), 5333, 5, 0.63, 2.0 -]] ----@field mgv7_np_mountain core.NoiseParams.3d? ---[[ -# 3D noise defining structure of river canyon walls. -[world_creation] -(Ridge noise) 0, 1, (100, 100, 100), 6467, 4, 0.75, 2.0 -]] ----@field mgv7_np_ridge core.NoiseParams.3d? ---[[ -# 3D noise defining structure of floatlands. -# If altered from the default, the noise 'scale' (0.7 by default) may need -# to be adjusted, as floatland tapering functions best when this noise has -# a value range of approximately -2.0 to 2.0. -[world_creation] -(Floatland noise) 0, 0.7, (384, 96, 384), 1009, 4, 0.75, 1.618 -]] ----@field mgv7_np_floatland core.NoiseParams.3d? ---[[ -# 3D noise defining giant caverns. -[world_creation] -(Cavern noise) 0, 1, (384, 128, 384), 723, 5, 0.63, 2.0 -]] ----@field mgv7_np_cavern core.NoiseParams.3d? ---[[ -# First of two 3D noises that together define tunnels. -[world_creation] -(Cave1 noise) 0, 12, (61, 61, 61), 52534, 3, 0.5, 2.0 -]] ----@field mgv7_np_cave1 core.NoiseParams.3d? ---[[ -# Second of two 3D noises that together define tunnels. -[world_creation] -(Cave2 noise) 0, 12, (67, 67, 67), 10325, 3, 0.5, 2.0 -]] ----@field mgv7_np_cave2 core.NoiseParams.3d? ---[[ -# 3D noise that determines number of dungeons per mapchunk. -[world_creation] -(Dungeon noise) 0.9, 0.5, (500, 500, 500), 0, 2, 0.8, 2.0 -]] ----@field mgv7_np_dungeons core.NoiseParams.3d? - --- ---------------------- [Mapgen] [*Mapgen Carpathian] --------------------- -- - ---[[ -WIPDOC -]] ----@class core.LuantiSettings.flags.mgcarpathian_spflags ---[[ -WIPDOC -]] ----@field caverns boolean? ---[[ -WIPDOC -]] ----@field nocaverns boolean? ---[[ -WIPDOC -]] ----@field rivers boolean? ---[[ -WIPDOC -]] ----@field norivers boolean? - ----@class _.LuantiSettings.mapgen.mapgen_carpathian ---[[ -# Map generation attributes specific to Mapgen Carpathian. -[world_creation] -(Mapgen Carpathian specific flags) caverns,norivers caverns,rivers -]] ----@field mgcarpathian_spflags core.LuantiSettings.flags? ---[[ -# Defines the base ground level. -[world_creation] -(Base ground level) 12.0 -]] ----@field mgcarpathian_base_level number? ---[[ -# Defines the width of the river channel. -[world_creation] -(River channel width) 0.05 -]] ----@field mgcarpathian_river_width number? ---[[ -# Defines the depth of the river channel. -[world_creation] -(River channel depth) 24.0 -]] ----@field mgcarpathian_river_depth number? ---[[ -# Defines the width of the river valley. -[world_creation] -(River valley width) 0.25 -]] ----@field mgcarpathian_valley_width number? ---[[ -# Controls width of tunnels, a smaller value creates wider tunnels. -# Value >= 10.0 completely disables generation of tunnels and avoids the -# intensive noise calculations. -[world_creation] -(Cave width) 0.09 -]] ----@field mgcarpathian_cave_width number? ---[[ -# Y of upper limit of large caves. -[world_creation] -(Large cave depth) -33 -31000 31000 -]] ----@field mgcarpathian_large_cave_depth integer? ---[[ -# Minimum limit of random number of small caves per mapchunk. -[world_creation] -(Small cave minimum number) 0 0 256 -]] ----@field mgcarpathian_small_cave_num_min integer? ---[[ -# Maximum limit of random number of small caves per mapchunk. -[world_creation] -(Small cave maximum number) 0 0 256 -]] ----@field mgcarpathian_small_cave_num_max integer? ---[[ -# Minimum limit of random number of large caves per mapchunk. -[world_creation] -(Large cave minimum number) 0 0 64 -]] ----@field mgcarpathian_large_cave_num_min integer? ---[[ -# Maximum limit of random number of large caves per mapchunk. -[world_creation] -(Large cave maximum number) 2 0 64 -]] ----@field mgcarpathian_large_cave_num_max integer? ---[[ -# Proportion of large caves that contain liquid. -[world_creation] -(Large cave proportion flooded) 0.5 0.0 1.0 -]] ----@field mgcarpathian_large_cave_flooded number? ---[[ -# Y-level of cavern upper limit. -[world_creation] -(Cavern limit) -256 -31000 31000 -]] ----@field mgcarpathian_cavern_limit integer? ---[[ -# Y-distance over which caverns expand to full size. -[world_creation] -(Cavern taper) 256 0 32767 -]] ----@field mgcarpathian_cavern_taper integer? ---[[ -# Defines full size of caverns, smaller values create larger caverns. -[world_creation] -(Cavern threshold) 0.7 -]] ----@field mgcarpathian_cavern_threshold number? ---[[ -# Lower Y limit of dungeons. -[world_creation] -(Dungeon minimum Y) -31000 -31000 31000 -]] ----@field mgcarpathian_dungeon_ymin integer? ---[[ -# Upper Y limit of dungeons. -[world_creation] -(Dungeon maximum Y) 31000 -31000 31000 -]] ----@field mgcarpathian_dungeon_ymax integer? - --- ---------------- [Mapgen] [*Mapgen Carpathian] [**Noises] ---------------- -- - ----@class _.LuantiSettings.mapgen.mapgen_carpathian.noises ---[[ -# Variation of biome filler depth. -[world_creation] -(Filler depth noise) 0, 1, (128, 128, 128), 261, 3, 0.7, 2.0, eased -]] ----@field mgcarpathian_np_filler_depth core.NoiseParams.2d? ---[[ -# First of 4 2D noises that together define hill/mountain range height. -[world_creation] -(Hilliness1 noise) 0, 5, (251, 251, 251), 9613, 5, 0.5, 2.0, eased -]] ----@field mgcarpathian_np_height1 core.NoiseParams.2d? ---[[ -# Second of 4 2D noises that together define hill/mountain range height. -[world_creation] -(Hilliness2 noise) 0, 5, (383, 383, 383), 1949, 5, 0.5, 2.0, eased -]] ----@field mgcarpathian_np_height2 core.NoiseParams.2d? ---[[ -# Third of 4 2D noises that together define hill/mountain range height. -[world_creation] -(Hilliness3 noise) 0, 5, (509, 509, 509), 3211, 5, 0.5, 2.0, eased -]] ----@field mgcarpathian_np_height3 core.NoiseParams.2d? ---[[ -# Fourth of 4 2D noises that together define hill/mountain range height. -[world_creation] -(Hilliness4 noise) 0, 5, (631, 631, 631), 1583, 5, 0.5, 2.0, eased -]] ----@field mgcarpathian_np_height4 core.NoiseParams.2d? ---[[ -# 2D noise that controls the size/occurrence of rolling hills. -[world_creation] -(Rolling hills spread noise) 1, 1, (1301, 1301, 1301), 1692, 3, 0.5, 2.0, eased -]] ----@field mgcarpathian_np_hills_terrain core.NoiseParams.2d? ---[[ -# 2D noise that controls the size/occurrence of ridged mountain ranges. -[world_creation] -(Ridge mountain spread noise) 1, 1, (1889, 1889, 1889), 3568, 3, 0.5, 2.0, eased -]] ----@field mgcarpathian_np_ridge_terrain core.NoiseParams.2d? ---[[ -# 2D noise that controls the size/occurrence of step mountain ranges. -[world_creation] -(Step mountain spread noise) 1, 1, (1889, 1889, 1889), 4157, 3, 0.5, 2.0, eased -]] ----@field mgcarpathian_np_step_terrain core.NoiseParams.2d? ---[[ -# 2D noise that controls the shape/size of rolling hills. -[world_creation] -(Rolling hill size noise) 0, 3, (257, 257, 257), 6604, 6, 0.5, 2.0, eased -]] ----@field mgcarpathian_np_hills core.NoiseParams.2d? ---[[ -# 2D noise that controls the shape/size of ridged mountains. -[world_creation] -(Ridged mountain size noise) 0, 12, (743, 743, 743), 5520, 6, 0.7, 2.0, eased -]] ----@field mgcarpathian_np_ridge_mnt core.NoiseParams.2d? ---[[ -# 2D noise that controls the shape/size of step mountains. -[world_creation] -(Step mountain size noise) 0, 8, (509, 509, 509), 2590, 6, 0.6, 2.0, eased -]] ----@field mgcarpathian_np_step_mnt core.NoiseParams.2d? ---[[ -# 2D noise that locates the river valleys and channels. -[world_creation] -(River noise) 0, 1, (1000, 1000, 1000), 85039, 5, 0.6, 2.0, eased -]] ----@field mgcarpathian_np_rivers core.NoiseParams.2d? ---[[ -# 3D noise for mountain overhangs, cliffs, etc. Usually small variations. -[world_creation] -(Mountain variation noise) 0, 1, (499, 499, 499), 2490, 5, 0.55, 2.0 -]] ----@field mgcarpathian_np_mnt_var core.NoiseParams.3d? ---[[ -# First of two 3D noises that together define tunnels. -[world_creation] -(Cave1 noise) 0, 12, (61, 61, 61), 52534, 3, 0.5, 2.0 -]] ----@field mgcarpathian_np_cave1 core.NoiseParams.3d? ---[[ -# Second of two 3D noises that together define tunnels. -[world_creation] -(Cave2 noise) 0, 12, (67, 67, 67), 10325, 3, 0.5, 2.0 -]] ----@field mgcarpathian_np_cave2 core.NoiseParams.3d? ---[[ -# 3D noise defining giant caverns. -[world_creation] -(Cavern noise) 0, 1, (384, 128, 384), 723, 5, 0.63, 2.0 -]] ----@field mgcarpathian_np_cavern core.NoiseParams.3d? ---[[ -# 3D noise that determines number of dungeons per mapchunk. -[world_creation] -(Dungeon noise) 0.9, 0.5, (500, 500, 500), 0, 2, 0.8, 2.0 -]] ----@field mgcarpathian_np_dungeons core.NoiseParams.3d? - --- ------------------------- [Mapgen] [*Mapgen Flat] ------------------------ -- - ---[[ -WIPDOC -]] ----@class core.LuantiSettings.flags.mgflat_spflags ---[[ -WIPDOC -]] ----@field lakes boolean? ---[[ -WIPDOC -]] ----@field nolakes boolean? ---[[ -WIPDOC -]] ----@field hills boolean? ---[[ -WIPDOC -]] ----@field nohills boolean? ---[[ -WIPDOC -]] ----@field caverns boolean? ---[[ -WIPDOC -]] ----@field nocaverns boolean? - ----@class _.LuantiSettings.mapgen.mapgen_flat ---[[ -# Map generation attributes specific to Mapgen Flat. -# Occasional lakes and hills can be added to the flat world. -[world_creation] -(Mapgen Flat specific flags) nolakes,nohills,nocaverns lakes,hills,caverns -]] ----@field mgflat_spflags core.LuantiSettings.flags? ---[[ -# Y of flat ground. -[world_creation] -(Ground level) 8 -31000 31000 -]] ----@field mgflat_ground_level integer? ---[[ -# Y of upper limit of large caves. -[world_creation] -(Large cave depth) -33 -31000 31000 -]] ----@field mgflat_large_cave_depth integer? ---[[ -# Minimum limit of random number of small caves per mapchunk. -[world_creation] -(Small cave minimum number) 0 0 256 -]] ----@field mgflat_small_cave_num_min integer? ---[[ -# Maximum limit of random number of small caves per mapchunk. -[world_creation] -(Small cave maximum number) 0 0 256 -]] ----@field mgflat_small_cave_num_max integer? ---[[ -# Minimum limit of random number of large caves per mapchunk. -[world_creation] -(Large cave minimum number) 0 0 64 -]] ----@field mgflat_large_cave_num_min integer? ---[[ -# Maximum limit of random number of large caves per mapchunk. -[world_creation] -(Large cave maximum number) 2 0 64 -]] ----@field mgflat_large_cave_num_max integer? ---[[ -# Proportion of large caves that contain liquid. -[world_creation] -(Large cave proportion flooded) 0.5 0.0 1.0 -]] ----@field mgflat_large_cave_flooded number? ---[[ -# Controls width of tunnels, a smaller value creates wider tunnels. -# Value >= 10.0 completely disables generation of tunnels and avoids the -# intensive noise calculations. -[world_creation] -(Cave width) 0.09 -]] ----@field mgflat_cave_width number? ---[[ -# Terrain noise threshold for lakes. -# Controls proportion of world area covered by lakes. -# Adjust towards 0.0 for a larger proportion. -[world_creation] -(Lake threshold) -0.45 -]] ----@field mgflat_lake_threshold number? ---[[ -# Controls steepness/depth of lake depressions. -[world_creation] -(Lake steepness) 48.0 -]] ----@field mgflat_lake_steepness number? ---[[ -# Terrain noise threshold for hills. -# Controls proportion of world area covered by hills. -# Adjust towards 0.0 for a larger proportion. -[world_creation] -(Hill threshold) 0.45 -]] ----@field mgflat_hill_threshold number? ---[[ -# Controls steepness/height of hills. -[world_creation] -(Hill steepness) 64.0 -]] ----@field mgflat_hill_steepness number? ---[[ -# Y-level of cavern upper limit. -[world_creation] -(Cavern limit) -256 -31000 31000 -]] ----@field mgflat_cavern_limit integer? ---[[ -# Y-distance over which caverns expand to full size. -[world_creation] -(Cavern taper) 256 0 32767 -]] ----@field mgflat_cavern_taper integer? ---[[ -# Defines full size of caverns, smaller values create larger caverns. -[world_creation] -(Cavern threshold) 0.7 -]] ----@field mgflat_cavern_threshold number? ---[[ -# Lower Y limit of dungeons. -[world_creation] -(Dungeon minimum Y) -31000 -31000 31000 -]] ----@field mgflat_dungeon_ymin integer? ---[[ -# Upper Y limit of dungeons. -[world_creation] -(Dungeon maximum Y) 31000 -31000 31000 -]] ----@field mgflat_dungeon_ymax integer? - --- ------------------- [Mapgen] [*Mapgen Flat] [**Noises] ------------------- -- - ----@class _.LuantiSettings.mapgen.mapgen_flat.noises ---[[ -# Defines location and terrain of optional hills and lakes. -[world_creation] -(Terrain noise) 0, 1, (600, 600, 600), 7244, 5, 0.6, 2.0, eased -]] ----@field mgflat_np_terrain core.NoiseParams.2d? ---[[ -# Variation of biome filler depth. -[world_creation] -(Filler depth noise) 0, 1.2, (150, 150, 150), 261, 3, 0.7, 2.0, eased -]] ----@field mgflat_np_filler_depth core.NoiseParams.2d? ---[[ -# First of two 3D noises that together define tunnels. -[world_creation] -(Cave1 noise) 0, 12, (61, 61, 61), 52534, 3, 0.5, 2.0 -]] ----@field mgflat_np_cave1 core.NoiseParams.3d? ---[[ -# Second of two 3D noises that together define tunnels. -[world_creation] -(Cave2 noise) 0, 12, (67, 67, 67), 10325, 3, 0.5, 2.0 -]] ----@field mgflat_np_cave2 core.NoiseParams.3d? ---[[ -# 3D noise defining giant caverns. -[world_creation] -(Cavern noise) 0, 1, (384, 128, 384), 723, 5, 0.63, 2.0 -]] ----@field mgflat_np_cavern core.NoiseParams.3d? ---[[ -# 3D noise that determines number of dungeons per mapchunk. -[world_creation] -(Dungeon noise) 0.9, 0.5, (500, 500, 500), 0, 2, 0.8, 2.0 -]] ----@field mgflat_np_dungeons core.NoiseParams.3d? - --- ----------------------- [Mapgen] [*Mapgen Fractal] ----------------------- -- - ---[[ -WIPDOC -]] ----@class core.LuantiSettings.flags.mgfractal_spflags ---[[ -WIPDOC -]] ----@field terrain boolean? ---[[ -WIPDOC -]] ----@field noterrain boolean? - ----@class _.LuantiSettings.mapgen.mapgen_fractal ---[[ -# Map generation attributes specific to Mapgen Fractal. -# 'terrain' enables the generation of non-fractal terrain: -# ocean, islands and underground. -[world_creation] -(Mapgen Fractal specific flags) terrain terrain -]] ----@field mgfractal_spflags core.LuantiSettings.flags? ---[[ -# Controls width of tunnels, a smaller value creates wider tunnels. -# Value >= 10.0 completely disables generation of tunnels and avoids the -# intensive noise calculations. -[world_creation] -(Cave width) 0.09 -]] ----@field mgfractal_cave_width number? ---[[ -# Y of upper limit of large caves. -[world_creation] -(Large cave depth) -33 -31000 31000 -]] ----@field mgfractal_large_cave_depth integer? ---[[ -# Minimum limit of random number of small caves per mapchunk. -[world_creation] -(Small cave minimum number) 0 0 256 -]] ----@field mgfractal_small_cave_num_min integer? ---[[ -# Maximum limit of random number of small caves per mapchunk. -[world_creation] -(Small cave maximum number) 0 0 256 -]] ----@field mgfractal_small_cave_num_max integer? ---[[ -# Minimum limit of random number of large caves per mapchunk. -[world_creation] -(Large cave minimum number) 0 0 64 -]] ----@field mgfractal_large_cave_num_min integer? ---[[ -# Maximum limit of random number of large caves per mapchunk. -[world_creation] -(Large cave maximum number) 2 0 64 -]] ----@field mgfractal_large_cave_num_max integer? ---[[ -# Proportion of large caves that contain liquid. -[world_creation] -(Large cave proportion flooded) 0.5 0.0 1.0 -]] ----@field mgfractal_large_cave_flooded number? ---[[ -# Lower Y limit of dungeons. -[world_creation] -(Dungeon minimum Y) -31000 -31000 31000 -]] ----@field mgfractal_dungeon_ymin integer? ---[[ -# Upper Y limit of dungeons. -[world_creation] -(Dungeon maximum Y) 31000 -31000 31000 -]] ----@field mgfractal_dungeon_ymax integer? ---[[ -# Selects one of 18 fractal types. -# 1 = 4D "Roundy" Mandelbrot set. -# 2 = 4D "Roundy" Julia set. -# 3 = 4D "Squarry" Mandelbrot set. -# 4 = 4D "Squarry" Julia set. -# 5 = 4D "Mandy Cousin" Mandelbrot set. -# 6 = 4D "Mandy Cousin" Julia set. -# 7 = 4D "Variation" Mandelbrot set. -# 8 = 4D "Variation" Julia set. -# 9 = 3D "Mandelbrot/Mandelbar" Mandelbrot set. -# 10 = 3D "Mandelbrot/Mandelbar" Julia set. -# 11 = 3D "Christmas Tree" Mandelbrot set. -# 12 = 3D "Christmas Tree" Julia set. -# 13 = 3D "Mandelbulb" Mandelbrot set. -# 14 = 3D "Mandelbulb" Julia set. -# 15 = 3D "Cosine Mandelbulb" Mandelbrot set. -# 16 = 3D "Cosine Mandelbulb" Julia set. -# 17 = 4D "Mandelbulb" Mandelbrot set. -# 18 = 4D "Mandelbulb" Julia set. -[world_creation] -(Fractal type) 1 1 18 -]] ----@field mgfractal_fractal integer? ---[[ -# Iterations of the recursive function. -# Increasing this increases the amount of fine detail, but also -# increases processing load. -# At iterations = 20 this mapgen has a similar load to mapgen V7. -[world_creation] -(Iterations) 11 1 65535 -]] ----@field mgfractal_iterations integer? ---[[ -# (X,Y,Z) scale of fractal in nodes. -# Actual fractal size will be 2 to 3 times larger. -# These numbers can be made very large, the fractal does -# not have to fit inside the world. -# Increase these to 'zoom' into the detail of the fractal. -# Default is for a vertically-squashed shape suitable for -# an island, set all 3 numbers equal for the raw shape. -[world_creation] -(Scale) (4096.0, 1024.0, 4096.0) -]] ----@field mgfractal_scale vec? ---[[ -# (X,Y,Z) offset of fractal from world center in units of 'scale'. -# Can be used to move a desired point to (0, 0) to create a -# suitable spawn point, or to allow 'zooming in' on a desired -# point by increasing 'scale'. -# The default is tuned for a suitable spawn point for Mandelbrot -# sets with default parameters, it may need altering in other -# situations. -# Range roughly -2 to 2. Multiply by 'scale' for offset in nodes. -[world_creation] -(Offset) (1.79, 0.0, 0.0) -]] ----@field mgfractal_offset vec? ---[[ -# W coordinate of the generated 3D slice of a 4D fractal. -# Determines which 3D slice of the 4D shape is generated. -# Alters the shape of the fractal. -# Has no effect on 3D fractals. -# Range roughly -2 to 2. -[world_creation] -(Slice w) 0.0 -]] ----@field mgfractal_slice_w number? ---[[ -# Julia set only. -# X component of hypercomplex constant. -# Alters the shape of the fractal. -# Range roughly -2 to 2. -[world_creation] -(Julia x) 0.33 -]] ----@field mgfractal_julia_x number? ---[[ -# Julia set only. -# Y component of hypercomplex constant. -# Alters the shape of the fractal. -# Range roughly -2 to 2. -[world_creation] -(Julia y) 0.33 -]] ----@field mgfractal_julia_y number? ---[[ -# Julia set only. -# Z component of hypercomplex constant. -# Alters the shape of the fractal. -# Range roughly -2 to 2. -[world_creation] -(Julia z) 0.33 -]] ----@field mgfractal_julia_z number? ---[[ -# Julia set only. -# W component of hypercomplex constant. -# Alters the shape of the fractal. -# Has no effect on 3D fractals. -# Range roughly -2 to 2. -[world_creation] -(Julia w) 0.33 -]] ----@field mgfractal_julia_w number? - --- ------------------ [Mapgen] [*Mapgen Fractal] [**Noises] ----------------- -- - ----@class _.LuantiSettings.mapgen.mapgen_fractal.noises ---[[ -# Y-level of seabed. -[world_creation] -(Seabed noise) -14, 9, (600, 600, 600), 41900, 5, 0.6, 2.0, eased -]] ----@field mgfractal_np_seabed core.NoiseParams.2d? ---[[ -# Variation of biome filler depth. -[world_creation] -(Filler depth noise) 0, 1.2, (150, 150, 150), 261, 3, 0.7, 2.0, eased -]] ----@field mgfractal_np_filler_depth core.NoiseParams.2d? ---[[ -# First of two 3D noises that together define tunnels. -[world_creation] -(Cave1 noise) 0, 12, (61, 61, 61), 52534, 3, 0.5, 2.0 -]] ----@field mgfractal_np_cave1 core.NoiseParams.3d? ---[[ -# Second of two 3D noises that together define tunnels. -[world_creation] -(Cave2 noise) 0, 12, (67, 67, 67), 10325, 3, 0.5, 2.0 -]] ----@field mgfractal_np_cave2 core.NoiseParams.3d? ---[[ -# 3D noise that determines number of dungeons per mapchunk. -[world_creation] -(Dungeon noise) 0.9, 0.5, (500, 500, 500), 0, 2, 0.8, 2.0 -]] ----@field mgfractal_np_dungeons core.NoiseParams.3d? - --- ----------------------- [Mapgen] [*Mapgen Valleys] ----------------------- -- - ---[[ -WIPDOC -]] ----@class core.LuantiSettings.flags.mgvalleys_spflags ---[[ -WIPDOC -]] ----@field altitude_chill boolean? ---[[ -WIPDOC -]] ----@field noaltitude_chill boolean? ---[[ -WIPDOC -]] ----@field humid_rivers boolean? ---[[ -WIPDOC -]] ----@field nohumid_rivers boolean? ---[[ -WIPDOC -]] ----@field vary_river_depth boolean? ---[[ -WIPDOC -]] ----@field novary_river_depth boolean? ---[[ -WIPDOC -]] ----@field altitude_dry boolean? ---[[ -WIPDOC -]] ----@field noaltitude_dry boolean? - ----@class _.LuantiSettings.mapgen.mapgen_valleys ---[[ -# Map generation attributes specific to Mapgen Valleys. -# 'altitude_chill': Reduces heat with altitude. -# 'humid_rivers': Increases humidity around rivers. -# 'vary_river_depth': If enabled, low humidity and high heat causes rivers -# to become shallower and occasionally dry. -# 'altitude_dry': Reduces humidity with altitude. -[world_creation] -(Mapgen Valleys specific flags) altitude_chill,humid_rivers,vary_river_depth,altitude_dry altitude_chill,humid_rivers,vary_river_depth,altitude_dry -]] ----@field mgvalleys_spflags core.LuantiSettings.flags? ---[[ -# The vertical distance over which heat drops by 20 if 'altitude_chill' is -# enabled. Also, the vertical distance over which humidity drops by 10 if -# 'altitude_dry' is enabled. -[world_creation] -(Altitude chill) 90 0 65535 -]] ----@field mgvalleys_altitude_chill integer? ---[[ -# Depth below which you'll find large caves. -[world_creation] -(Large cave depth) -33 -31000 31000 -]] ----@field mgvalleys_large_cave_depth integer? ---[[ -# Minimum limit of random number of small caves per mapchunk. -[world_creation] -(Small cave minimum number) 0 0 256 -]] ----@field mgvalleys_small_cave_num_min integer? ---[[ -# Maximum limit of random number of small caves per mapchunk. -[world_creation] -(Small cave maximum number) 0 0 256 -]] ----@field mgvalleys_small_cave_num_max integer? ---[[ -# Minimum limit of random number of large caves per mapchunk. -[world_creation] -(Large cave minimum number) 0 0 64 -]] ----@field mgvalleys_large_cave_num_min integer? ---[[ -# Maximum limit of random number of large caves per mapchunk. -[world_creation] -(Large cave maximum number) 2 0 64 -]] ----@field mgvalleys_large_cave_num_max integer? ---[[ -# Proportion of large caves that contain liquid. -[world_creation] -(Large cave proportion flooded) 0.5 0.0 1.0 -]] ----@field mgvalleys_large_cave_flooded number? ---[[ -# Depth below which you'll find giant caverns. -[world_creation] -(Cavern upper limit) -256 -31000 31000 -]] ----@field mgvalleys_cavern_limit integer? ---[[ -# Y-distance over which caverns expand to full size. -[world_creation] -(Cavern taper) 192 0 32767 -]] ----@field mgvalleys_cavern_taper integer? ---[[ -# Defines full size of caverns, smaller values create larger caverns. -[world_creation] -(Cavern threshold) 0.6 -]] ----@field mgvalleys_cavern_threshold number? ---[[ -# How deep to make rivers. -[world_creation] -(River depth) 4 0 65535 -]] ----@field mgvalleys_river_depth integer? ---[[ -# How wide to make rivers. -[world_creation] -(River size) 5 0 65535 -]] ----@field mgvalleys_river_size integer? ---[[ -# Controls width of tunnels, a smaller value creates wider tunnels. -# Value >= 10.0 completely disables generation of tunnels and avoids the -# intensive noise calculations. -[world_creation] -(Cave width) 0.09 -]] ----@field mgvalleys_cave_width number? ---[[ -# Lower Y limit of dungeons. -[world_creation] -(Dungeon minimum Y) -31000 -31000 31000 -]] ----@field mgvalleys_dungeon_ymin integer? ---[[ -# Upper Y limit of dungeons. -[world_creation] -(Dungeon maximum Y) 63 -31000 31000 -]] ----@field mgvalleys_dungeon_ymax integer? - --- ------------------ [Mapgen] [*Mapgen Valleys] [**Noises] ----------------- -- - ----@class _.LuantiSettings.mapgen.mapgen_valleys.noises ---[[ -# First of two 3D noises that together define tunnels. -[world_creation] -(Cave noise #1) 0, 12, (61, 61, 61), 52534, 3, 0.5, 2.0 -]] ----@field mgvalleys_np_cave1 core.NoiseParams.3d? ---[[ -# Second of two 3D noises that together define tunnels. -[world_creation] -(Cave noise #2) 0, 12, (67, 67, 67), 10325, 3, 0.5, 2.0 -]] ----@field mgvalleys_np_cave2 core.NoiseParams.3d? ---[[ -# Variation of biome filler depth. -[world_creation] -(Filler depth) 0, 1.2, (256, 256, 256), 1605, 3, 0.5, 2.0, eased -]] ----@field mgvalleys_np_filler_depth core.NoiseParams.2d? ---[[ -# 3D noise defining giant caverns. -[world_creation] -(Cavern noise) 0, 1, (768, 256, 768), 59033, 6, 0.63, 2.0 -]] ----@field mgvalleys_np_cavern core.NoiseParams.3d? ---[[ -# Defines large-scale river channel structure. -[world_creation] -(River noise) 0, 1, (256, 256, 256), -6050, 5, 0.6, 2.0, eased -]] ----@field mgvalleys_np_rivers core.NoiseParams.2d? ---[[ -# Base terrain height. -[world_creation] -(Terrain height) -10, 50, (1024, 1024, 1024), 5202, 6, 0.4, 2.0, eased -]] ----@field mgvalleys_np_terrain_height core.NoiseParams.2d? ---[[ -# Raises terrain to make valleys around the rivers. -[world_creation] -(Valley depth) 5, 4, (512, 512, 512), -1914, 1, 1.0, 2.0, eased -]] ----@field mgvalleys_np_valley_depth core.NoiseParams.2d? ---[[ -# Slope and fill work together to modify the heights. -[world_creation] -(Valley fill) 0, 1, (256, 512, 256), 1993, 6, 0.8, 2.0 -]] ----@field mgvalleys_np_inter_valley_fill core.NoiseParams.3d? ---[[ -# Amplifies the valleys. -[world_creation] -(Valley profile) 0.6, 0.5, (512, 512, 512), 777, 1, 1.0, 2.0, eased -]] ----@field mgvalleys_np_valley_profile core.NoiseParams.2d? ---[[ -# Slope and fill work together to modify the heights. -[world_creation] -(Valley slope) 0.5, 0.5, (128, 128, 128), 746, 1, 1.0, 2.0, eased -]] ----@field mgvalleys_np_inter_valley_slope core.NoiseParams.2d? ---[[ -# 3D noise that determines number of dungeons per mapchunk. -[world_creation] -(Dungeon noise) 0.9, 0.5, (500, 500, 500), 0, 2, 0.8, 2.0 -]] ----@field mgvalleys_np_dungeons core.NoiseParams.3d? \ No newline at end of file diff --git a/types/luanti_lsp_definitions/library/classes/Settings/LuantiSettings/settings_enums.lua b/types/luanti_lsp_definitions/library/classes/Settings/LuantiSettings/settings_enums.lua deleted file mode 100644 index 78218edc..00000000 --- a/types/luanti_lsp_definitions/library/classes/Settings/LuantiSettings/settings_enums.lua +++ /dev/null @@ -1,60 +0,0 @@ ----@meta _ --- DRAFT 1 DONE --- luanti/doc/lua_api.md: Class reference > `Settings` --- builtin/settingtypes.txt --- minetest.conf.example - ----@class core.LuantiSettings -local LuantiSettings = {} - --- -------------------------------- Advanced -------------------------------- -- - ----@nodiscard ----@param key "debug_log_level" ----@return core.LuantiSettings.enums.debug_log_level? value -function LuantiSettings:get(key) end - ----@param key "debug_log_level" ----@param value core.LuantiSettings.enums.debug_log_level? -function LuantiSettings:set(key, value) end - ----@nodiscard ----@param key "deprecated_lua_api_handling" ----@return core.LuantiSettings.enums.deprecated_lua_api_handling? value -function LuantiSettings:get(key) end - ----@param key "deprecated_lua_api_handling" ----@param value core.LuantiSettings.enums.deprecated_lua_api_handling? -function LuantiSettings:set(key, value) end - ----@nodiscard ----@param key "profiler.default_report_format" ----@return core.LuantiSettings.enums.profiler.default_report_format? value -function LuantiSettings:get(key) end - ----@nodiscard ----@param key "profiler.default_report_format" ----@param value core.LuantiSettings.enums.profiler.default_report_format? -function LuantiSettings:set(key, value) end - ----@nodiscard ----@param key "sqlite_synchronous" ----@return core.LuantiSettings.enums.sqlite_synchronous? value -function LuantiSettings:get(key) end - ----@nodiscard ----@param key "sqlite_synchronous" ----@param value core.LuantiSettings.enums.sqlite_synchronous? -function LuantiSettings:set(key, value) end - --- --------------------------------- Mapgen --------------------------------- -- - ----@nodiscard ----@param key "mg_name" ----@return core.LuantiSettings.enums.mg_name? value -function LuantiSettings:get(key) end - ----@nodiscard ----@param key "mg_name" ----@param value core.LuantiSettings.enums.mg_name? -function LuantiSettings:set(key, value) end \ No newline at end of file diff --git a/types/luanti_lsp_definitions/library/classes/Settings/LuantiSettings/settings_flags.lua b/types/luanti_lsp_definitions/library/classes/Settings/LuantiSettings/settings_flags.lua deleted file mode 100644 index 332d6469..00000000 --- a/types/luanti_lsp_definitions/library/classes/Settings/LuantiSettings/settings_flags.lua +++ /dev/null @@ -1,48 +0,0 @@ ----@meta _ --- DRAFT 1 DONE --- luanti/doc/lua_api.md: Class reference > `Settings` --- builtin/settingtypes.txt --- minetest.conf.example - ----@class core.LuantiSettings -local LuantiSettings = {} - ----@nodiscard ----@param key "mg_flags" ----@return core.LuantiSettings.flags.mg_flags? value -function LuantiSettings:get_flags(key) end - ----@nodiscard ----@param key "mgv5_spflags" ----@return core.LuantiSettings.flags.mgv5_spflags? value -function LuantiSettings:get_flags(key) end - ----@nodiscard ----@param key "mgv6_spflags" ----@return core.LuantiSettings.flags.mgv6_spflags? value -function LuantiSettings:get_flags(key) end - ----@nodiscard ----@param key "mgv7_spflags" ----@return core.LuantiSettings.flags.mgv7_spflags? value -function LuantiSettings:get_flags(key) end - ----@nodiscard ----@param key "mgcarpathian_spflags" ----@return core.LuantiSettings.flags.mgcarpathian_spflags? value -function LuantiSettings:get_flags(key) end - ----@nodiscard ----@param key "mgflat_spflags" ----@return core.LuantiSettings.flags.mgflat_spflags? value -function LuantiSettings:get_flags(key) end - ----@nodiscard ----@param key "mgfractal_spflags" ----@return core.LuantiSettings.flags.mgfractal_spflags? value -function LuantiSettings:get_flags(key) end - ----@nodiscard ----@param key "mgvalleys_spflags" ----@return core.LuantiSettings.flags.mgvalleys_spflags? value -function LuantiSettings:get_flags(key) end \ No newline at end of file diff --git a/types/luanti_lsp_definitions/library/classes/Settings/Settings.lua b/types/luanti_lsp_definitions/library/classes/Settings/Settings.lua deleted file mode 100644 index ca3c831a..00000000 --- a/types/luanti_lsp_definitions/library/classes/Settings/Settings.lua +++ /dev/null @@ -1,188 +0,0 @@ ----@meta _ --- DRAFT 1 DONE --- luanti/doc/lua_api.md: Class reference > `Settings` --- builtin/settingtype.txt - ---[[ -NOTE: types in a .conf settings file -- int -> integer -- string -> string -- bool -> boolean -- float -> number -- enum -> string -- path -> string -- filepath -> string -- key -> string -- flags -> flag table -- noise_params_2d -> noiseparams -- noise_params_3d -> noiseparams -- v3f -> vec -]] - --- ------------------------------- constructor ------------------------------ -- - ---[[ -WIPDOC -]] ----@nodiscard ----@param filename core.Path ----@return core.Settings -function Settings(filename) end - --- -------------------------------- Settings -------------------------------- -- - ---[[ -### Format - -The settings have the format `key = value`. Example: - - foo = example text - bar = """ - Multiline - value - """ -]] ----@class core.Settings -Settings = {} - ---[[ -* `get(key)`: returns a value - * Returns `nil` if `key` is not found. -]] ----@nodiscard ----@param key string ----@return string? value -function Settings:get(key) end - ---[[ -* `get_bool(key, [default])`: returns a boolean - * `default` is the value returned if `key` is not found. - * Returns `nil` if `key` is not found and `default` not specified. -]] ----@nodiscard ----@param key string ----@return boolean? value -function Settings:get_bool(key) end - ---[[ -* `get_bool(key, [default])`: returns a boolean - * `default` is the value returned if `key` is not found. - * Returns `nil` if `key` is not found and `default` not specified. -]] ----@nodiscard ----@generic T ----@param key string ----@param default T ----@return boolean|T value -function Settings:get_bool(key, default) end - ---[[ -* `get_np_group(key)`: returns a NoiseParams table - * Returns `nil` if `key` is not found. -]] ----@nodiscard ----@param key string ----@return core.NoiseParams? value -function Settings:get_np_group(key) end - ---[[ -* `get_flags(key)`: - * Returns `{flag = true/false, ...}` according to the set flags. - * Is currently limited to mapgen flags `mg_flags` and mapgen-specific - flags like `mgv5_spflags`. - * Returns `nil` if `key` is not found. -]] ----@nodiscard ----@param key string ----@return table? value -function Settings:get_flags(key) end - ---[[ -* `get_pos(key)`: - * Returns a `vector` - * Returns `nil` if no value is found or parsing failed. -]] ----@nodiscard ----@param key string ----@return vec? value -function Settings:get_pos(key) end - ---[[ -* `set(key, value)` - * Setting names can't contain whitespace or any of `="{}#`. - * Setting values can't contain the sequence `\n"""`. - * Setting names starting with "secure." can't be set on the main settings - object (`core.settings`). -]] ----@param key string ----@param value string -function Settings:set(key, value) end - ---[[ -* `set_bool(key, value)` - * See documentation for `set()` above. -]] ----@param key string ----@param value boolean -function Settings:set_bool(key, value) end - ---[[ -* `set_np_group(key, value)` - * `value` is a NoiseParams table. - * Also, see documentation for `set()` above. -]] ----@param key string ----@param value core.NoiseParams -function Settings:set_np_group(key, value) end - ---[[ -* `set_pos(key, value)` - * `value` is a `vector`. - * Also, see documentation for `set()` above. -]] ----@param key string ----@param value vector -function Settings:set_pos(key, value) end - ---[[ -* `remove(key)`: returns a boolean (`true` for success -]] ----@nodiscard ----@param key boolean ----@return boolean -function Settings:remove(key) end - ---[[ -* `get_names()`: returns `{key1,...}` -]] ----@nodiscard ----@return string[] keys -function Settings:get_names() end - ---[[ -* `has(key)`: - * Returns a boolean indicating whether `key` exists. - * In contrast to the various getter functions, `has()` doesn't consider - any default values. - * This means that on the main settings object (`core.settings`), - `get(key)` might return a value even if `has(key)` returns `false`. -]] ----@nodiscard ----@param key string ----@return boolean -function Settings:has(key) end - ---[[ -* `write()`: returns a boolean (`true` for success - * Writes changes to file. -]] ----@nodiscard ----@return boolean -function Settings:write() end - ---[[ -* `to_table()`: returns `{[key1]=value1,...}` -]] ----@nodiscard ----@return table -function Settings:to_table() end diff --git a/types/luanti_lsp_definitions/library/classes/StorageRef.lua b/types/luanti_lsp_definitions/library/classes/StorageRef.lua deleted file mode 100644 index f78787a4..00000000 --- a/types/luanti_lsp_definitions/library/classes/StorageRef.lua +++ /dev/null @@ -1,126 +0,0 @@ ----@meta _ --- DRAFT 1 DONE --- luanti/doc/lua_api.md: 'core' namespace reference > Storage API --- luanti/doc/lua_api.md: Class reference > `StorageRef` - --- NOTE: changes are linked to MetaDataRef, ItemStackMetaRef, NodeMetaRef, --- PlayerMetaRef and StorageRef - --- ------------------------------- constructor ------------------------------ -- - ---[[ -* `core.get_mod_storage()`: - * returns reference to mod private `StorageRef` - * must be called during mod load time -]] ----@nodiscard ----@return core.StorageRef -function core.get_mod_storage() end - --- ------------------------------- StorageRef ------------------------------- -- - ---[[ -`StorageRef` ------------- - -Mod metadata: per mod and world metadata, saved automatically. -Can be obtained via `core.get_mod_storage()` during load time. - -WARNING: This storage backend is incapable of saving raw binary data due -to restrictions of JSON. - -### Methods - -* All methods in MetaDataRef - -]] ----@class core.StorageRef : core.MetaDataRef -local StorageRef = {} - ---[[ -* `contains(key)`: Returns true if key present, otherwise false. - * Returns `nil` when the MetaData is inexistent. -]] ----@nodiscard ----@param key core.MetadataTable.fields.storage.keys ----@return boolean? -function StorageRef:contains(key) end - ---[[ -* `get(key)`: Returns `nil` if key not present, else the stored string. -]] ----@nodiscard ----@param key core.MetadataTable.fields.storage.keys ----@return string? value -function StorageRef:get(key) end - ---[[ -* `set_string(key, value)`: Value of `""` will delete the key. -]] ----@nodiscard ----@param key core.MetadataTable.fields.storage.keys ----@param value string -function StorageRef:set_string(key, value) end - ---[[ -* `get_string(key)`: Returns `""` if key not present. -]] ----@nodiscard ----@param key core.MetadataTable.fields.storage.keys ----@return string value -function StorageRef:get_string(key) end - ---[[ -* `set_int(key, value)` - * The range for the value is system-dependent (usually 32 bits). - The value will be converted into a string when stored. -]] ----@param key core.MetadataTable.fields.storage.keys.integer ----@param value integer -function StorageRef:set_int(key, value) end - ---[[ -* `get_int(key)`: Returns `0` if key not present. -]] ----@nodiscard ----@param key core.MetadataTable.fields.storage.keys.integer ----@return integer value -function StorageRef:get_int(key) end - ---[[ -* `set_float(key, value)` - * Store a number (a 64-bit float) exactly. - * The value will be converted into a string when stored. -]] ----@param key core.MetadataTable.fields.storage.keys.number ----@param value number -function StorageRef:set_float(key, value) end - ---[[ -WIPDOC -]] ----@nodiscard ----@param key core.MetadataTable.fields.storage.keys.number ----@return number value -function StorageRef:get_float(key) end - ---[[ -WIPDOC -]] ----@return core.MetadataTable.fields.storage.keys[] keys -function StorageRef:get_keys() end - ---[[ -WIPDOC -]] ----@nodiscard ----@param data core.MetadataTable.storage ----@return boolean? -function StorageRef:from_table(data) end - ---[[ -WIPDOC -]] ----@nodiscard ----@return core.MetadataTable.storage -function StorageRef:to_table() end diff --git a/types/luanti_lsp_definitions/library/classes/ValueNoise.lua b/types/luanti_lsp_definitions/library/classes/ValueNoise.lua deleted file mode 100644 index 25c505e7..00000000 --- a/types/luanti_lsp_definitions/library/classes/ValueNoise.lua +++ /dev/null @@ -1,171 +0,0 @@ ----@meta _ --- DRAFT 1 DONE --- luanti/doc/lua_api.md: Fractal Value Noise --- luanti/doc/lua_api.md: 'core' namespace reference > Environment access --- luanti/doc/lua_api.md: Class Reference > `ValueNoise` - --- ------------------------------ constructors ------------------------------ -- - ---[[ -`ValueNoise` -------------- - -A value noise generator. -It can be created via `ValueNoise()` or `core.get_value_noise()`. -For `core.get_value_noise()`, the actual seed used is the noiseparams seed -plus the world seed, to create world-specific noise. - -**Important**: These require the mapgen environment to be initalized, do not use at load time. - -* `ValueNoise(noiseparams)` -* `ValueNoise(seed, octaves, persistence, spread)` (deprecated) -* `core.get_value_noise(noiseparams)` -* `core.get_value_noise(seeddiff, octaves, persistence, spread)` (deprecated) - -These were previously called `PerlinNoise()` and `core.get_perlin()`, but the -implemented noise was not Perlin noise. They were renamed in 5.12.0. The old -names still exist as aliases. -]] ----@nodiscard ----@param noiseparams core.NoiseParams ----@return core.ValueNoise -function ValueNoise(noiseparams) end - ---[[ -WIPDOC -]] ----@nodiscard ----@param noiseparams core.NoiseParams ----@return core.ValueNoise -function PerlinNoise(noiseparams) end - ---[[ -* `core.get_value_noise(noiseparams)` - * Return world-specific value noise. - * The actual seed used is the noiseparams seed plus the world seed. - * **Important**: Requires the mapgen environment to be initalized, do not use at load time. -]] ----@nodiscard ----@param noiseparams core.NoiseParams ----@return core.ValueNoise -function core.get_value_noise(noiseparams) end - ---[[ -* `core.get_perlin(noiseparams)` - * Deprecated: renamed to `core.get_value_noise` in version 5.12.0. -]] ----@deprecated ----@nodiscard ----@param noiseparams core.NoiseParams ----@return core.ValueNoise -function core.get_perlin(noiseparams) end - --- ---------------------------- old constructors ---------------------------- -- - ---[[ -`ValueNoise` -------------- - -A value noise generator. -It can be created via `ValueNoise()` or `core.get_value_noise()`. -For `core.get_value_noise()`, the actual seed used is the noiseparams seed -plus the world seed, to create world-specific noise. - -**Important**: These require the mapgen environment to be initalized, do not use at load time. - -* `ValueNoise(noiseparams)` -* `ValueNoise(seed, octaves, persistence, spread)` (deprecated) -* `core.get_value_noise(noiseparams)` -* `core.get_value_noise(seeddiff, octaves, persistence, spread)` (deprecated) - -These were previously called `PerlinNoise()` and `core.get_perlin()`, but the -implemented noise was not Perlin noise. They were renamed in 5.12.0. The old -names still exist as aliases. -]] ----@deprecated ----@nodiscard ----@param seeddiff integer ----@param octaves integer ----@param persistence number ----@param spread vector|vec2.xy ----@return core.ValueNoise -function ValueNoise(seeddiff, octaves, persistence, spread) end - ---[[ -WIPDOC -]] ----@deprecated ----@nodiscard ----@param seeddiff integer ----@param octaves integer ----@param persistence number ----@param spread vector|vec2.xy ----@return core.ValueNoise -function PerlinNoise(seeddiff, octaves, persistence, spread) end - ---[[ -* `core.get_value_noise(seeddiff, octaves, persistence, spread)` - * Deprecated: use `core.get_value_noise(noiseparams)` instead. -]] ----@deprecated ----@nodiscard ----@param seeddiff integer ----@param octaves integer ----@param persistence number ----@param spread vector|vec2.xy ----@return core.ValueNoise -function core.get_value_noise(seeddiff, octaves, persistence, spread) end - ---[[ -* `core.get_perlin(seeddiff, octaves, persistence, spread)` - * Deprecated: renamed to `core.get_value_noise` in version 5.12.0. -]] ----@deprecated ----@nodiscard ----@param seeddiff integer ----@param octaves integer ----@param persistence number ----@param spread vector|vec2.xy ----@return core.ValueNoise -function core.get_perlin(seeddiff, octaves, persistence, spread) end - --- ------------------------------- ValueNoise ------------------------------- -- - ---[[ -`ValueNoise` -------------- - -A value noise generator. -It can be created via `ValueNoise()` or `core.get_value_noise()`. -For `core.get_value_noise()`, the actual seed used is the noiseparams seed -plus the world seed, to create world-specific noise. - -**Important**: These require the mapgen environment to be initalized, do not use at load time. - -* `ValueNoise(noiseparams)` -* `ValueNoise(seed, octaves, persistence, spread)` (deprecated) -* `core.get_value_noise(noiseparams)` -* `core.get_value_noise(seeddiff, octaves, persistence, spread)` (deprecated) - -These were previously called `PerlinNoise()` and `core.get_perlin()`, but the -implemented noise was not Perlin noise. They were renamed in 5.12.0. The old -names still exist as aliases. -]] ----@class core.ValueNoise -local ValueNoise = {} - ---[[ -* `get_2d(pos)`: returns 2D noise value at `pos={x=,y=}` -]] ----@nodiscard ----@param pos vec2.xy ----@return vec2.xy -function ValueNoise:get_2d(pos) end - ---[[ -* `get_3d(pos)`: returns 3D noise value at `pos={x=,y=,z=}` -]] ----@nodiscard ----@param pos vector ----@return vec -function ValueNoise:get_3d(pos) end \ No newline at end of file diff --git a/types/luanti_lsp_definitions/library/classes/ValueNoiseMap.lua b/types/luanti_lsp_definitions/library/classes/ValueNoiseMap.lua deleted file mode 100644 index 73448d32..00000000 --- a/types/luanti_lsp_definitions/library/classes/ValueNoiseMap.lua +++ /dev/null @@ -1,169 +0,0 @@ ----@meta _ --- DRAFT 1 DONE --- luanti/doc/lua_api.md: Fractal Value Noise --- luanti/doc/lua_api.md: Class Reference > `ValueNoiseMap` - --- ------------------------------ constructors ------------------------------ -- - ---[[ -WIPDOC -]] ----@nodiscard ----@param noiseparams core.NoiseParams ----@param size ivector|vec2i.xy ----@return core.ValueNoiseMap -function ValueNoiseMap(noiseparams, size) end - ---[[ -WIPDOC -]] ----@nodiscard ----@param noiseparams core.NoiseParams ----@param size ivector|vec2i.xy ----@return core.ValueNoiseMap -function core.get_value_noise_map(noiseparams, size) end - ---[[ -WIPDOC -]] ----@nodiscard ----@param noiseparams core.NoiseParams ----@param size ivector|vec2i.xy ----@return core.ValueNoiseMap -function PerlinNoiseMap(noiseparams, size) end - ---[[ -WIPDOC -]] ----@nodiscard ----@param noiseparams core.NoiseParams ----@param size ivector|vec2i.xy ----@return core.ValueNoiseMap -function core.get_perlin_noise_map(noiseparams, size) end - --- ------------------------------ ValueNoiseMap ----------------------------- -- - ---[[ -WIPDOC -]] ----@class core.ValueNoiseMap -local ValueNoiseMap = {} - ---[[ -* `get_2d_map(pos)`: returns a `` times `` 2D array of 2D noise - with values starting at `pos={x=,y=}` -]] ----@nodiscard ----@param pos vec2.xy ----@return number[][] -function ValueNoiseMap:get_2d_map(pos) end - ---[[ -* `get_3d_map(pos)`: returns a `` times `` times `` - 3D array of 3D noise with values starting at `pos={x=,y=,z=}`. -]] ----@nodiscard ----@param pos vector ----@return number[][][] -function ValueNoiseMap:get_3d_map(pos) end - ---[[ -* `get_2d_map_flat(pos, buffer)`: returns a flat `` element - array of 2D noise with values starting at `pos={x=,y=}` -]] ----@nodiscard ----@param pos vec2.xy ----@return number[] -function ValueNoiseMap:get_2d_map_flat(pos) end - ---[[ -* `get_2d_map_flat(pos, buffer)`: returns a flat `` element - array of 2D noise with values starting at `pos={x=,y=}` -]] ----@nodiscard ----@param pos vec2.xy ----@param buffer number[] ----@return nil -function ValueNoiseMap:get_2d_map_flat(pos, buffer) end - ---[[ -* `get_3d_map_flat(pos, buffer)`: Same as `get2dMap_flat`, but 3D noise -]] ----@nodiscard ----@param pos vector ----@return number[] -function ValueNoiseMap:get_3d_map_flat(pos) end - ---[[ -* `get_3d_map_flat(pos, buffer)`: Same as `get2dMap_flat`, but 3D noise -]] ----@nodiscard ----@param pos vector ----@param buffer number[] ----@return nil -function ValueNoiseMap:get_3d_map_flat(pos, buffer) end - ---[[ -* `calc_2d_map(pos)`: Calculates the 2d noise map starting at `pos`. The result - is stored internally. -]] ----@param pos vec2.xy -function ValueNoiseMap:calc_2d_map(pos) end - ---[[ -* `calc_3d_map(pos)`: Calculates the 3d noise map starting at `pos`. The result - is stored internally. -]] ----@param pos vector -function ValueNoiseMap:calc_3d_map(pos) end - ---[[ -* `get_map_slice(slice_offset, slice_size, buffer)`: In the form of an array, - returns a slice of the most recently computed noise results. The result slice - begins at coordinates `slice_offset` and takes a chunk of `slice_size`. - E.g., to grab a 2-slice high horizontal 2d plane of noise starting at buffer - offset `y = 20`: - ```lua - noisevals = noise:get_map_slice({y=20}, {y=2}) - ``` - It is important to note that `slice_offset` offset coordinates begin at 1, - and are relative to the starting position of the most recently calculated - noise. - To grab a single vertical column of noise starting at map coordinates - `x = 1023, y=1000, z = 1000`: - ```lua - noise:calc_3d_map({x=1000, y=1000, z=1000}) - noisevals = noise:get_map_slice({x=24, z=1}, {x=1, z=1}) - ``` -]] ----@nodiscard ----@param slice_offset vector ----@param slice_size vector ----@return number[] -function ValueNoiseMap:get_map_slice(slice_offset, slice_size, buffer) end - ---[[ -* `get_map_slice(slice_offset, slice_size, buffer)`: In the form of an array, - returns a slice of the most recently computed noise results. The result slice - begins at coordinates `slice_offset` and takes a chunk of `slice_size`. - E.g., to grab a 2-slice high horizontal 2d plane of noise starting at buffer - offset `y = 20`: - ```lua - noisevals = noise:get_map_slice({y=20}, {y=2}) - ``` - It is important to note that `slice_offset` offset coordinates begin at 1, - and are relative to the starting position of the most recently calculated - noise. - To grab a single vertical column of noise starting at map coordinates - `x = 1023, y=1000, z = 1000`: - ```lua - noise:calc_3d_map({x=1000, y=1000, z=1000}) - noisevals = noise:get_map_slice({x=24, z=1}, {x=1, z=1}) - ``` -]] ----@nodiscard ----@param slice_offset vector ----@param slice_size vector ----@param buffer number[] ----@return nil -function ValueNoiseMap:get_map_slice(slice_offset, slice_size, buffer) end \ No newline at end of file diff --git a/types/luanti_lsp_definitions/library/classes/VoxelArea.lua b/types/luanti_lsp_definitions/library/classes/VoxelArea.lua deleted file mode 100644 index d479473f..00000000 --- a/types/luanti_lsp_definitions/library/classes/VoxelArea.lua +++ /dev/null @@ -1,129 +0,0 @@ ----@meta _ --- DRAFT 1 DONE --- luanti/doc/lua_api.md: Map terminology and coordinates --- luanti/doc/lua_api.md: Lua Voxel Manipulator --- luanti/doc/lua_api.md: Class reference > `VoxelArea` - --- ------------------------------- constructor ------------------------------ -- - ---[[ -WIPDOC -]] ----@nodiscard ----@param pmin ivector ----@param pmax ivector ----@return VoxelArea -function VoxelArea(pmin, pmax) end - ---[[ -WIPDOC -]] ----@nodiscard ----@param arg {MinEdge:ivector, MaxEdge:ivector} ----@return VoxelArea -function VoxelArea:new(arg) end - --- -------------------------------- VoxelArea ------------------------------- -- - ---[[ -WIPDOC -]] ----@class VoxelArea -VoxelArea = {} - ---[[ -WIPDOC -]] ----@nodiscard ----@return ivec -function VoxelArea:getExtent() end - ---[[ -WIPDOC -]] ----@nodiscard ----@return integer -function VoxelArea:getVolume() end - ---[[ -* `index(x, y, z)`: returns the index of an absolute position in a flat array - starting at `1`. - * `x`, `y` and `z` must be integers to avoid an incorrect index result. - * The position (x, y, z) is not checked for being inside the area volume, - being outside can cause an incorrect index result. - * Useful for things like `VoxelManip`, raw Schematic specifiers, - `ValueNoiseMap:get2d`/`3dMap`, and so on. -]] ----@nodiscard ----@param x integer ----@param y integer ----@param z integer ----@return integer i -function VoxelArea:index(x, y, z) end - ---[[ -* `indexp(p)`: same functionality as `index(x, y, z)` but takes a vector. - * As with `index(x, y, z)`, the components of `p` must be integers, and `p` - is not checked for being inside the area volume. -]] ----@nodiscard ----@param p ivector ----@return integer i -function VoxelArea:indexp(p) end - ---[[ -* `position(i)`: returns the absolute position vector corresponding to index - `i`. -]] ----@nodiscard ----@param i integer ----@return ivec p -function VoxelArea:position(i) end - ---[[ -WIPDOC -]] ----@nodiscard ----@param x number ----@param y number ----@param z number ----@return boolean -function VoxelArea:contains(x, y, z) end - ---[[ -WIPDOC -]] ----@nodiscard ----@param p vector ----@return boolean -function VoxelArea:containsp(p) end - ---[[ -WIPDOC -]] ----@nodiscard ----@param i integer ----@return boolean -function VoxelArea:containsi(i) end - ---[[ -WIPDOC -]] ----@nodiscard ----@param minx integer ----@param miny integer ----@param minz integer ----@param maxx integer ----@param maxy integer ----@param maxz integer ----@return fun():integer? -function VoxelArea:iter(minx, miny, minz, maxx, maxy, maxz) end - ---[[ -WIPDOC -]] ----@nodiscard ----@param minp ivector ----@param maxp ivector ----@return fun():integer? -function VoxelArea:iterp(minp, maxp) end diff --git a/types/luanti_lsp_definitions/library/classes/VoxelManip.lua b/types/luanti_lsp_definitions/library/classes/VoxelManip.lua deleted file mode 100644 index 46d1361b..00000000 --- a/types/luanti_lsp_definitions/library/classes/VoxelManip.lua +++ /dev/null @@ -1,325 +0,0 @@ ----@meta _ --- DRAFT 1 DONE --- luanti/doc/lua_api.md: Map terminology and coordinates --- luanti/doc/lua_api.md: Lua Voxel Manipulator --- luanti/doc/lua_api.md: 'core' namespace reference > Environment access --- luanti/doc/lua_api.md: Class reference > `VoxelManip` - ---[[ -WIPDOC -]] -core.MAP_BLOCKSIZE = 16 - ---[[ -WIPDOC -]] ----@class core.ContentID: integer - ---[[ -WIPDOC -]] ----@type core.ContentID -core.CONTENT_UNKNOWN = 125 - ---[[ -WIPDOC -]] ----@type core.ContentID -core.CONTENT_AIR = 126 - ---[[ -WIPDOC -]] ----@type core.ContentID -core.CONTENT_IGNORE = 127 - --- ---------------------------- VoxelManip.light ---------------------------- -- - ---[[ -WIPDOC -]] ----@class core.VoxelManip.light -local VoxelManipLight = {} - ---[[ -WIPDOC -]] ----@type core.Light.part -VoxelManipLight.day = nil - ---[[ -WIPDOC -]] ----@type core.Light.part -VoxelManipLight.night = nil - --- ------------------------------- constructor ------------------------------ -- - ---[[ -WIPDOC -]] ----@nodiscard ----@param p1 ivector? ----@param p2 ivector? ----@return core.VoxelManip -function VoxelManip(p1, p2) end - ---[[ -WIPDOC -]] ----@nodiscard ----@param p1 ivector? ----@param p2 ivector? ----@return core.VoxelManip -function core.get_voxel_manip(p1, p2) end - --- ------------------------------- VoxelManip ------------------------------- -- - ---[[ -Unofficial note: Building the next worldedit eh? - -About VoxelManip ----------------- - -VoxelManip is a scripting interface to the internal 'Map Voxel Manipulator' -facility. The purpose of this object is for fast, low-level, bulk access to -reading and writing Map content. As such, setting map nodes through VoxelManip -will lack many of the higher level features and concepts you may be used to -with other methods of setting nodes. For example, nodes will not have their -construction and destruction callbacks run, and no rollback information is -logged. - -It is important to note that VoxelManip is designed for speed, and *not* ease -of use or flexibility. If your mod requires a map manipulation facility that -will handle 100% of all edge cases, or the use of high level node placement -features, perhaps `core.set_node()` is better suited for the job. - -In addition, VoxelManip might not be faster, or could even be slower, for your -specific use case. VoxelManip is most effective when setting large areas of map -at once - for example, if only setting a 3x3x3 node area, a -`core.set_node()` loop may be more optimal. Always profile code using both -methods of map manipulation to determine which is most appropriate for your -usage. - -A recent simple test of setting cubic areas showed that `core.set_node()` -is faster than a VoxelManip for a 3x3x3 node cube or smaller. -]] ----@class core.VoxelManip -local VoxelManip = {} - ---[[ -* `read_from_map(p1, p2)`: Loads a part of the map into the VoxelManip object - containing the region formed by `p1` and `p2`. - * returns actual emerged `pmin`, actual emerged `pmax` (MapBlock-aligned) - * Note that calling this multiple times will *add* to the area loaded in the - VoxelManip, and not reset it. -]] ----@nodiscard ----@param p1 ivector ----@param p2 ivector ----@return ivec pmin, ivec pmax -function VoxelManip:read_from_map(p1, p2) end - ---[[ -* `initialize(p1, p2, [node])`: Clears and resizes the VoxelManip object to - comprise the region formed by `p1` and `p2`. - * **No data** is read from the map, so you can use this to treat `VoxelManip` - objects as general containers of node data. - * `node`: if present the data will be filled with this node; if not it will - be uninitialized - * returns actual emerged `pmin`, actual emerged `pmax` (MapBlock-aligned) - * (introduced in 5.13.0) -]] ----@nodiscard ----@param p1 ivector ----@param p2 ivector ----@param node core.Node.set ----@return ivec pmin, ivec pmax -function VoxelManip:initialize(p1, p2, node) end - ---[[ -Unofficial note: If you can, try to not use this function for performance reasons (there is no alternative, but you can avoid using it by checking if vmanip data was modified, if yes then use it) - -* `write_to_map([light])`: Writes the data loaded from the `VoxelManip` back to - the map. - * **important**: you should call `set_data()` before this, or nothing will change. - * if `light` is true, then lighting is automatically recalculated. - The default value is true. - If `light` is false, no light calculations happen, and you should correct - all modified blocks with `core.fix_light()` as soon as possible. - Keep in mind that modifying the map where light is incorrect can cause - more lighting bugs. -]] ----@param light boolean? -function VoxelManip:write_to_map(light) end - ---[[ -Unofficial note: i don't think you should be using this for performance reasons, this is a function i would personally NEVER use -]] ----@nodiscard ----@param pos ivector ----@return core.Node.get -function VoxelManip:get_node_at(pos) end - ---[[ -Unofficial note: i don't think you should be using this for performance reasons, this is a function i would personally NEVER use -]] ----@param pos ivector ----@param node core.Node.set -function VoxelManip:set_node_at(pos, node) end - ---[[ -Retrieves the node content data loaded into the `VoxelManip` object, the `data` table will be used to store the result -]] ----@param data core.ContentID[] ----@return nil -function VoxelManip:get_data(data) end - ---[[ -Retrieves the node content data loaded into the `VoxelManip` object and returns it -Unofficial note: I would recommend doing VoxelManip.get_data(data) instead, as this form will make the garbage collector scream, in a way that you can't profile very well -]] ----@nodiscard ----@return core.ContentID[] data -function VoxelManip:get_data() end - ---[[ -WIPDOC -]] ----@param data core.ContentID[] ----@return nil -function VoxelManip:set_data(data) end - ---[[ -Unofficial note: In need of a noop? Instead of depending on modlib to do it, how -about using this pre-made function baked into the luanti api, written most -likely in C for super fast noop -Does nothing, kept for compatibility. -]] ----@deprecated -function VoxelManip:update_map() end - ---[[ -* `set_lighting(light, [p1, p2])`: Set the lighting within the `VoxelManip` to - a uniform value. - * `light` is a table, `{day=<0...15>, night=<0...15>}` - * To be used only by a `VoxelManip` object from - `core.get_mapgen_object`. - * (`p1`, `p2`) is the area in which lighting is set, defaults to the whole - area if left out. -]] ----@param light core.VoxelManip.light ----@param p1 ivector? ----@param p2 ivector? -function VoxelManip:set_lighting(light, p1, p2) end - ---[[ -* `get_light_data([buffer])`: Gets the light data read into the - `VoxelManip` object - * Returns an array (indices 1 to volume) of integers ranging from `0` to - `255`. - * Each value is the bitwise combination of day and night light values - (`0` to `15` each). - * `light = day + (night * 16)` - * If the param `buffer` is present, this table will be used to store the - result instead. -]] ----@param buffer core.Light[] ----@return nil -function VoxelManip:get_light_data(buffer) end - ---[[ -* `get_light_data([buffer])`: Gets the light data read into the - `VoxelManip` object - * Returns an array (indices 1 to volume) of integers ranging from `0` to - `255`. - * Each value is the bitwise combination of day and night light values - (`0` to `15` each). - * `light = day + (night * 16)` - * If the param `buffer` is present, this table will be used to store the - result instead. -]] ----@nodiscard ----@return core.Light[] light_data -function VoxelManip:get_light_data() end - ---[[ -* `set_light_data(light_data)`: Sets the `param1` (light) contents of each node - in the `VoxelManip`. - * expects lighting data in the same format that `get_light_data()` returns -]] ----@param light_data core.Light[] -function VoxelManip:set_light_data(light_data) end - ---[[ -WIPDOC -]] ----@nodiscard ----@return core.Param2[] param2_data -function VoxelManip:get_param2_data() end - ---[[ -WIPDOC -]] ----@param buffer core.Param2[]? ----@return nil -function VoxelManip:get_param2_data(buffer) end - ---[[ -WIPDOC -]] ----@param param2_data core.Param2[] -function VoxelManip:set_param2_data(param2_data) end - ---[[ -* `calc_lighting([p1, p2], [propagate_shadow])`: Calculate lighting within the - `VoxelManip`. - * To be used only with a `VoxelManip` object from `core.get_mapgen_object`. - * (`p1`, `p2`) is the area in which lighting is set, defaults to the whole - area if left out or nil. For almost all uses these should be left out - or nil to use the default. - * `propagate_shadow` is an optional boolean deciding whether shadows in a - generated mapchunk above are propagated down into the mapchunk, defaults - to `true` if left out. -]] ----@param p1 vector? ----@param p2 vector? ----@param propagate_shadow boolean? -function VoxelManip:calc_lighting(p1, p2, propagate_shadow) end - ---[[ -WIPDOC -]] -function VoxelManip:update_liquids() end - ---[[ -* `was_modified()`: Returns `true` if the data in the VoxelManip has been modified - since it was last read from the map. This means you have to call `get_data()` again. - This only applies to a `VoxelManip` object from `core.get_mapgen_object`, - where the engine will keep the map and the VM in sync automatically. - * Note: this doesn't do what you think it does and is subject to removal. Don't use it! -]] ----@deprecated ----@nodiscard ----@return boolean -function VoxelManip:was_modified() end - ---[[ -* `get_emerged_area()`: Returns actual emerged minimum and maximum positions. -* "Emerged" does not imply that this region was actually loaded from the map, - if `initialize()` has been used. -]] ----@nodiscard ----@return ivec emin, ivec emax -function VoxelManip:get_emerged_area() end - ---[[ -* `close()`: Frees the data buffers associated with the VoxelManip object. - It will become empty. - * Since Lua's garbage collector is not aware of the potentially significant - memory behind a VoxelManip, frequent VoxelManip usage can cause the server to - run out of RAM. Therefore it's recommend to call this method once you're done - with the VoxelManip. - * (introduced in 5.13.0) -]] -function VoxelManip:close() end diff --git a/types/luanti_lsp_definitions/library/core/async_environment.lua b/types/luanti_lsp_definitions/library/core/async_environment.lua deleted file mode 100644 index 0ce4e761..00000000 --- a/types/luanti_lsp_definitions/library/core/async_environment.lua +++ /dev/null @@ -1,38 +0,0 @@ ----@meta _ --- DRAFT 1 DONE --- luanti/doc/lua_api.md: 'core' namespace reference > Async environment - ---[[ -WIPDOC -]] ----@nodiscard ----@param f function ----@param callback function ----@param ... any ----@return core.AsyncJob -function core.handle_async(f, callback, ...) end - ---[[ -* `core.register_async_dofile(path)`: - * Register a path to a Lua file to be imported when an async environment - is initialized. You can use this to preload code which you can then call - later using `core.handle_async()`. -]] ----@param path core.Path -function core.register_async_dofile(path) end - ---[[ -WIPDOC -]] ----@class corelib.async -local async = { - settings = core.settings, - --- TODO async registered_* has functions and userdata set to true instead - registered_items = core.registered_items, - registered_nodes = core.registered_nodes, - registered_tools = core.registered_tools, - registered_craftitems = core.registered_craftitems, - registered_aliases = core.registered_aliases, --- TODO ... and more. WHY THE FUCK DON'T THEY JUST LIST THE GODDAMN FUNCTIONS -} \ No newline at end of file diff --git a/types/luanti_lsp_definitions/library/core/authentication.lua b/types/luanti_lsp_definitions/library/core/authentication.lua deleted file mode 100644 index bf9b9064..00000000 --- a/types/luanti_lsp_definitions/library/core/authentication.lua +++ /dev/null @@ -1,185 +0,0 @@ ----@meta _ --- DRAFT 1 DONE --- luanti/doc/lua_api.md: 'core' namespace reference > Authentication - ---[[ -* `core.string_to_privs(str[, delim])`: - * Converts string representation of privs into table form - * `delim`: String separating the privs. Defaults to `","`. - * Returns `{ priv1 = true, ... }` -]] ----@nodiscard ----@param str string ----@param delim string? ----@return core.PrivilegeSet -function core.string_to_privs(str, delim) end - ---[[ -* `core.privs_to_string(privs[, delim])`: - * Returns the string representation of `privs` - * `delim`: String to delimit privs. Defaults to `","`. -]] ----@nodiscard ----@param privs core.PrivilegeSet ----@param delim string? ----@return string -function core.privs_to_string(privs, delim) end - ---[[ -* `core.get_player_privs(name) -> {priv1=true,...}` - -`core.set_player_password`, `core.set_player_privs`, -`core.get_player_privs` and `core.auth_reload` call the authentication -handler. -]] ----@nodiscard ----@param name string ----@return core.PrivilegeSet -function core.get_player_privs(name) end - ---[[ -* `core.check_player_privs(player_or_name, ...)`: - returns `bool, missing_privs` - * A quickhand for checking privileges. - * `player_or_name`: Either a Player object or the name of a player. - * `...` is either a list of strings, e.g. `"priva", "privb"` or - a table, e.g. `{ priva = true, privb = true }`. -]] ----@nodiscard ----@param player_or_name core.PlayerRef|string ----@param privs core.PrivilegeSet ----@return boolean, core.PrivilegeSet missing_privs -function core.check_player_privs(player_or_name, privs) end - ---[[ -* `core.check_player_privs(player_or_name, ...)`: - returns `bool, missing_privs` - * A quickhand for checking privileges. - * `player_or_name`: Either a Player object or the name of a player. - * `...` is either a list of strings, e.g. `"priva", "privb"` or - a table, e.g. `{ priva = true, privb = true }`. -]] ----@nodiscard ----@param player_or_name core.PlayerRef|string ----@param ... core.PrivilegeSet.keys ----@return boolean, core.PrivilegeSet missing_privs -function core.check_player_privs(player_or_name, ...) end - ---[[ -* `core.check_password_entry(name, entry, password)` - * Returns true if the "password entry" for a player with name matches given - password, false otherwise. - * The "password entry" is the password representation generated by the - engine as returned as part of a `get_auth()` call on the auth handler. - * Only use this function for making it possible to log in via password from - external protocols such as IRC, other uses are frowned upon. -]] ----@param name string ----@param entry string ----@param password string ----@return boolean -function core.check_password_entry(name, entry, password) end - ---[[ -* `core.get_password_hash(name, raw_password)` - * Convert a name-password pair to a password hash that Luanti can use. - * The returned value alone is not a good basis for password checks based - on comparing the password hash in the database with the password hash - from the function, with an externally provided password, as the hash - in the db might use the new SRP verifier format. - * For this purpose, use `core.check_password_entry` instead. -]] ----@nodiscard ----@param name string ----@param raw_password string ----@return string -function core.get_password_hash(name, raw_password) end - ---[[ -* `core.get_player_ip(name)`: returns an IP address string for the player - `name`. - * The player needs to be online for this to be successful. -]] ----@nodiscard ----@param name string ----@return string? -function core.get_player_ip(name) end - ---[[ -* `core.get_auth_handler()`: Return the currently active auth handler - * Must be called *after* load time, to ensure that any custom auth handler was - already registered. - * See the [Authentication handler definition](#authentication-handler-definition) - * Use this to e.g. get the authentication data for a player: - `local auth_data = core.get_auth_handler().get_auth(playername)` -]] ----@nodiscard ----@return core.AuthenticationHandlerDef -function core.get_auth_handler() end - ---[[ -* `core.notify_authentication_modified(name)` - * Must be called by the authentication handler for privilege changes. - * `name`: string; if omitted, all auth data should be considered modified -]] ----@param name string? -function core.notify_authentication_modified(name) end - ---[[ -* `core.set_player_password(name, password_hash)`: Set password hash of - player `name`. - -`core.set_player_password`, `core.set_player_privs`, -`core.get_player_privs` and `core.auth_reload` call the authentication -handler. -]] ----@param name string ----@param password_hash string -function core.set_player_password(name, password_hash) end - ---[[ -* `core.set_player_privs(name, privs)`: Set privileges of player `name`. - * `privs` is a **set** of privileges: - A table where the keys are names of privileges and the values are `true`. - * Example: `core.set_player_privs("singleplayer", {interact = true, fly = true})`. - This **sets** the player privileges to `interact` and `fly`; - `singleplayer` will only have these two privileges afterwards. - -`core.set_player_password`, `core.set_player_privs`, -`core.get_player_privs` and `core.auth_reload` call the authentication -handler. ---]] ----@param name string ----@param privs core.PrivilegeSet -function core.set_player_privs(name, privs) end - ---[[ -* `core.change_player_privs(name, changes)`: Helper to grant or revoke privileges. - * `changes`: Table of changes to make. - A field `[privname] = true` grants a privilege, - whereas `[privname] = false` revokes a privilege. - * Example: `core.change_player_privs("singleplayer", {interact = true, fly = false})` - will grant singleplayer the `interact` privilege - and revoke singleplayer's `fly` privilege. - All other privileges will remain unchanged. - -**UNOFFICIAL** - -For directly replacing all of a player's set of privileges with -another set, see `core.set_player_privs(...)` -]] ----@param name string ----@param changes core.PrivilegeSet -function core.change_player_privs(name, changes) end - ---[[ -* `core.auth_reload()` - * See `reload()` in authentication handler definition - -`core.set_player_password`, `core.set_player_privs`, -`core.get_player_privs` and `core.auth_reload` call the authentication -handler. -]] ----@nodiscard ----@return boolean -function core.auth_reload() end \ No newline at end of file diff --git a/types/luanti_lsp_definitions/library/core/ban.lua b/types/luanti_lsp_definitions/library/core/ban.lua deleted file mode 100644 index a40a753d..00000000 --- a/types/luanti_lsp_definitions/library/core/ban.lua +++ /dev/null @@ -1,61 +0,0 @@ ----@meta _ --- DRAFT 1 DONE --- luanti/doc/lua_api.md: 'core' namespace reference > Bans - ---[[ -* `core.get_ban_list()`: returns a list of all bans formatted as string -]] ----@nodiscard ----@return string -function core.get_ban_list() end - ---[[ -* `core.get_ban_description(ip_or_name)`: returns list of bans matching - IP address or name formatted as string -]] ----@nodiscard ----@param ip_or_name string ----@return string -function core.get_ban_description(ip_or_name) end - ---[[ -* `core.ban_player(name)`: ban the IP of a currently connected player - * Returns boolean indicating success -]] ----@nodiscard ----@param name string ----@return boolean success -function core.ban_player(name) end - ---[[ -* `core.unban_player_or_ip(ip_or_name)`: remove ban record matching - IP address or name -]] ----@param ip_or_name string -function core.unban_player_or_ip(ip_or_name) end - ---[=[ -* `core.kick_player(name[, reason[, reconnect]])`: disconnect a player with an optional - reason. - * Returns boolean indicating success (false if player nonexistent) - * If `reconnect` is true, allow the user to reconnect. -]=] ----@nodiscard ----@param name string ----@param reason string? ----@param reconnect boolean? ----@return boolean success -function core.kick_player(name, reason, reconnect) end - ---[=[ -* `core.disconnect_player(name[, reason[, reconnect]])`: disconnect a player with an - optional reason, this will not prefix with 'Kicked: ' like kick_player. - If no reason is given, it will default to 'Disconnected.' - * Returns boolean indicating success (false if player nonexistent) -]=] ----@nodiscard ----@param name string ----@param reason string? ----@param reconnect boolean? ----@return boolean -function core.disconnect_player(name, reason, reconnect) end \ No newline at end of file diff --git a/types/luanti_lsp_definitions/library/core/chat.lua b/types/luanti_lsp_definitions/library/core/chat.lua deleted file mode 100644 index 890ea3d0..00000000 --- a/types/luanti_lsp_definitions/library/core/chat.lua +++ /dev/null @@ -1,30 +0,0 @@ ----@meta _ --- DRAFT 1 DONE --- luanti/doc/lua_api.md: 'core' namespace reference > Chat - ---[[ -WIPDOC -]] ----@param text string -function core.chat_send_all(text) end - ---[[ -WIPDOC -]] ----@param name string ----@param text string -function core.chat_send_player(name, text) end - ---[[ -* `core.format_chat_message(name, message)` - * Used by the server to format a chat message, based on the setting `chat_message_format`. - Refer to the documentation of the setting for a list of valid placeholders. - * Takes player name and message, and returns the formatted string to be sent to players. - * Can be redefined by mods if required, for things like colored names or messages. - * **Only** the first occurrence of each placeholder will be replaced. -]] ----@nodiscard ----@param name string ----@param message string ----@return string -function core.format_chat_message(name, message) end diff --git a/types/luanti_lsp_definitions/library/core/core.lua b/types/luanti_lsp_definitions/library/core/core.lua deleted file mode 100644 index b9897744..00000000 --- a/types/luanti_lsp_definitions/library/core/core.lua +++ /dev/null @@ -1,24 +0,0 @@ ----@meta _ --- DRAFT 1 DONE --- luanti/doc/lua_api.md: 'core' namespace reference --- luanti/doc/lua_api.md: 'core' namespace reference > Global objects - ---[[ -WIPDOC -]] ----@class corelib -core = {} - ---[[ -WIPDOC -]] ----@deprecated ----@type corelib -core.env = core - ---[[ -WIPDOC -]] ----@deprecated ----@class minetest: corelib -minetest = core diff --git a/types/luanti_lsp_definitions/library/core/defaults.lua b/types/luanti_lsp_definitions/library/core/defaults.lua deleted file mode 100644 index b349ae88..00000000 --- a/types/luanti_lsp_definitions/library/core/defaults.lua +++ /dev/null @@ -1,156 +0,0 @@ ----@meta _ --- DRAFT 1 DONE --- luanti/doc/lua_api.md: 'core' namespace reference > Defaults for the `on_place` and `on_drop` item definition functions --- luanti/doc/lua_api.md: 'core' namespace reference > Defaults for the `on_punch` and `on_dig` node definition callbacks - ---[[ -* `core.item_place_node(itemstack, placer, pointed_thing[, param2, prevent_after_place])` - * Place item as a node - * `param2` overrides `facedir` and wallmounted `param2` - * `prevent_after_place`: if set to `true`, `after_place_node` is not called - for the newly placed node to prevent a callback and placement loop - * returns `itemstack, position` - * `position`: the location the node was placed to. `nil` if nothing was placed. -]] ----@nodiscard ----@param itemstack core.ItemStack ----@param placer core.ObjectRef ----@param pointed_thing core.PointedThing ----@param param2 core.Param2? ----@param prevent_after_place boolean? ----@return core.ItemStack, ivec? -function core.item_place_node(itemstack, placer, pointed_thing, param2, prevent_after_place) end - ---[[ -* `core.item_place_object(itemstack, placer, pointed_thing)` - * Place item as-is - * returns the leftover itemstack - * **Note**: This function is deprecated and will never be called. -]] ----@deprecated ----@nodiscard ----@param itemstack core.ItemStack ----@param placer core.ObjectRef ----@param pointed_thing core.PointedThing ----@return core.ItemStack -function core.item_place_object(itemstack, placer, pointed_thing) end - ---[[ -* `core.item_place(itemstack, placer, pointed_thing[, param2])` - * Wrapper that calls `core.item_place_node` if appropriate - * Calls `on_rightclick` of `pointed_thing.under` if defined instead - * **Note**: is not called when wielded item overrides `on_place` - * `param2` overrides facedir and wallmounted `param2` - * returns `itemstack, position` - * `position`: the location the node was placed to. `nil` if nothing was placed. -]] ----@nodiscard ----@param itemstack core.ItemStack ----@param placer core.ObjectRef ----@param pointed_thing core.PointedThing ----@param param2 core.Param2? ----@return core.ItemStack, vec? -function core.item_place(itemstack, placer, pointed_thing, param2) end - ---[[ -* `core.item_pickup(itemstack, picker, pointed_thing, time_from_last_punch, ...)` - * Runs callbacks registered by `core.register_on_item_pickup` and adds - the item to the picker's `"main"` inventory list. - * Parameters and return value are the same as `on_pickup`. - * **Note**: is not called when wielded item overrides `on_pickup` -]] ----@nodiscard ----@param itemstack core.ItemStack ----@param picker core.ObjectRef ----@param pointed_thing core.PointedThing ----@param time_from_last_punch number ----@param tool_capabilities core.ToolCapabilities? ----@param dir vector ----@param damage integer? ----@return core.ItemStack -function core.item_pickup(itemstack, picker, pointed_thing, time_from_last_punch, tool_capabilities, dir, damage) end - ---[[ -* `core.item_secondary_use(itemstack, user)` - * Global secondary use callback. Does nothing. - * Parameters and return value are the same as `on_secondary_use`. - * **Note**: is not called when wielded item overrides `on_secondary_use` -]] ----@nodiscard ----@param itemstack core.ItemStack ----@param user core.ObjectRef? ----@return core.ItemStack? -function core.item_secondary_use(itemstack, user) end - ---[[ -* `core.item_drop(itemstack, dropper, pos)` - * Converts `itemstack` to an in-world Lua entity. - * `itemstack` (`ItemStack`) is modified (cleared) on success. - * In versions < 5.12.0, `itemstack` was cleared in all cases. - * `dropper` (`ObjectRef`) is optional. - * Returned values on success: - 1. leftover itemstack - 2. `ObjectRef` of the spawned object (provided since 5.12.0) -]] ----@nodiscard ----@param itemstack core.ItemStack ----@param dropper core.ObjectRef? ----@param pos vector ----@return core.ItemStack, core.ObjectRef -function core.item_drop(itemstack, dropper, pos) end - ---[[ -* `core.item_drop(itemstack, dropper, pos)` - * Converts `itemstack` to an in-world Lua entity. - * `itemstack` (`ItemStack`) is modified (cleared) on success. - * In versions < 5.12.0, `itemstack` was cleared in all cases. - * `dropper` (`ObjectRef`) is optional. - * Returned values on success: - 1. leftover itemstack - 2. `ObjectRef` of the spawned object (provided since 5.12.0) -]] ----@nodiscard ----@param itemstack core.ItemStack ----@param dropper core.ObjectRef? ----@param pos vector ----@return nil -function core.item_drop(itemstack, dropper, pos) end - ---[[ -WIPDOC -]] ----@alias core.fn.item_eat fun(itemstack:core.ItemStack, user:core.ObjectRef, pointed_thing:core.PointedThing):core.ItemStack? - ---[[ -* `core.item_eat(hp_change[, replace_with_item])` - * Returns `function(itemstack, user, pointed_thing)` as a - function wrapper for `core.do_item_eat`. - * `replace_with_item` is the itemstring which is added to the inventory. - If the player is eating a stack and `replace_with_item` doesn't fit onto - the eaten stack, then the remaining go to a different spot, or are dropped. -]] ----@nodiscard ----@param hp_change integer ----@param replace_with_item core.Item.stringfmt? ----@return core.fn.item_eat -function core.item_eat(hp_change, replace_with_item) end - ---[[ -* `core.node_punch(pos, node, puncher, pointed_thing)` - * Calls functions registered by `core.register_on_punchnode()` -]] ----@param pos ivector ----@param node core.Node.set ----@param puncher core.ObjectRef ----@param pointed_thing core.PointedThing -function core.node_punch(pos, node, puncher, pointed_thing) end - ---[[ -* `core.node_dig(pos, node, digger)` - * Checks if node can be dug, puts item into inventory, removes node - * Calls functions registered by `core.register_on_dignodes()` -]] ----@param pos ivector ----@param node core.Node.set ----@param digger core.ObjectRef -function core.node_dig(pos, node, digger) end \ No newline at end of file diff --git a/types/luanti_lsp_definitions/library/core/environment/biome_data.lua b/types/luanti_lsp_definitions/library/core/environment/biome_data.lua deleted file mode 100644 index cf4292a1..00000000 --- a/types/luanti_lsp_definitions/library/core/environment/biome_data.lua +++ /dev/null @@ -1,33 +0,0 @@ ----@meta _ --- DRAFT 1 DONE --- luanti/doc/lua_api.md: 'core' namespace reference > Environment access - ---[[ -WIPDOC -]] ----@class core.BiomeData ---[[ -WIPDOC -]] ----@field biome core.BiomeID ---[[ -WIPDOC -]] ----@field heat number ---[[ -WIPDOC -]] ----@field humidity number - ---[[ -* `core.get_biome_data(pos)` - * Returns a table containing: - * `biome` the biome id of the biome at that position - * `heat` the heat at the position - * `humidity` the humidity at the position - * Or returns `nil` on failure. -]] ----@nodiscard ----@param pos ivector ----@return core.BiomeData? -function core.get_biome_data(pos) end \ No newline at end of file diff --git a/types/luanti_lsp_definitions/library/core/environment/emerge_area.lua b/types/luanti_lsp_definitions/library/core/environment/emerge_area.lua deleted file mode 100644 index 57517914..00000000 --- a/types/luanti_lsp_definitions/library/core/environment/emerge_area.lua +++ /dev/null @@ -1,75 +0,0 @@ ----@meta _ --- DRAFT 1 DONE --- luanti/doc/lua_api.md: 'core' namespace reference > Environment access - --- ------------------------------- EMERGE enum ------------------------------ -- - ---[[ -WIPDOC -]] ----@class core.EmergeAction : integer - ---[[ -WIPDOC -]] ----@type core.EmergeAction -core.EMERGE_CANCELLED = nil - ---[[ -WIPDOC -]] ----@type core.EmergeAction -core.EMERGE_ERRORED = nil - ---[[ -WIPDOC -]] ----@type core.EmergeAction -core.EMERGE_FROM_MEMORY = nil - ---[[ -WIPDOC -]] ----@type core.EmergeAction -core.EMERGE_FROM_DISK = nil - ---[[ -WIPDOC -]] ----@type core.EmergeAction -core.EMERGE_GENERATED = nil - --- ---------------------------- core.* functions ---------------------------- -- - ---[[ -WIPDOC -]] ----@alias core.fn.emerge_area fun(blockpos:ivec, action:core.EmergeAction , calls_remaining:integer, param:any?) - ---[[ -* `core.emerge_area(pos1, pos2, [callback], [param])` - * Queue all blocks in the area from `pos1` to `pos2`, inclusive, to be - asynchronously fetched from memory, loaded from disk, or if inexistent, - generates them. - * If `callback` is a valid Lua function, this will be called for each block - emerged. - * The function signature of callback is: - `function EmergeAreaCallback(blockpos, action, calls_remaining, param)` - * `blockpos` is the *block* coordinates of the block that had been - emerged. - * `action` could be one of the following constant values: - * `core.EMERGE_CANCELLED` - * `core.EMERGE_ERRORED` - * `core.EMERGE_FROM_MEMORY` - * `core.EMERGE_FROM_DISK` - * `core.EMERGE_GENERATED` - * `calls_remaining` is the number of callbacks to be expected after - this one. - * `param` is the user-defined parameter passed to emerge_area (or - nil if the parameter was absent). -]] ----@param pos1 ivector ----@param pos2 ivector ----@param callback core.fn.emerge_area? ----@param param any? -function core.emerge_area(pos1, pos2, callback, param) end \ No newline at end of file diff --git a/types/luanti_lsp_definitions/library/core/environment/environment.lua b/types/luanti_lsp_definitions/library/core/environment/environment.lua deleted file mode 100644 index 834f54d7..00000000 --- a/types/luanti_lsp_definitions/library/core/environment/environment.lua +++ /dev/null @@ -1,946 +0,0 @@ ----@meta _ --- DRAFT 1 DONE --- luanti/doc/lua_api.md: 'core' namespace reference > Environment access - --- ---------------------------------- node ---------------------------------- -- - ---[[ -* `core.set_node(pos, node)` - * Set node at position `pos`. - * Any existing metadata is deleted. - * `node`: table `{name=string, param1=number, param2=number}` - If param1 or param2 is omitted, it's set to `0`. - * e.g. `core.set_node({x=0, y=10, z=0}, {name="default:wood"})` -]] ----@param pos ivector ----@param node core.Node.set -function core.set_node(pos, node) end - ---[[ -Alias to core.set_node -Unofficial note: I think you should be strict and only use `core.set_node` -]] -core.add_node = core.set_node - ---[[ -WIPDOC -]] ----@param posarr ivector[] ----@param node core.Node.set -function core.bulk_set_node(posarr, node) end - ---[[ -* `core.swap_node(pos, node)` - * Swap node at position with another. - * This keeps the metadata intact and will not run con-/destructor callbacks. -]] ----@param pos ivector ----@param node core.Node.set -function core.swap_node(pos, node) end - ---[[ -* `core.bulk_swap_node({pos1, pos2, pos3, ...}, node)` - * Equivalent to `core.swap_node` but in bulk. -]] ----@param posarr ivector[] ----@param node core.Node.set -function core.bulk_swap_node(posarr, node) end - ---[[ -* `core.remove_node(pos)`: Remove a node - * Equivalent to `core.set_node(pos, {name="air"})`, but a bit faster. -]] ----@param pos ivector -function core.remove_node(pos) end - ---[[ -* `core.get_node(pos)` - * Returns the node at the given position as table in the same format as `set_node`. - * This function never returns `nil` and instead returns - `{name="ignore", param1=0, param2=0}` for unloaded areas. -]] ----@nodiscard ----@param pos ivector ----@return core.Node.set -function core.get_node(pos) end - ---[[ -* `core.get_node_or_nil(pos)` - * Same as `get_node` but returns `nil` for unloaded areas. - * Note that even loaded areas can contain "ignore" nodes. -]] ----@nodiscard ----@param pos ivector ----@return core.Node.get? -function core.get_node_or_nil(pos) end - ---[[ -* `core.get_node_raw(x, y, z)` - * Same as `get_node` but a faster low-level API - * Returns `content_id`, `param1`, `param2`, and `pos_ok` - * The `content_id` can be mapped to a name using `core.get_name_from_content_id()` - * If `pos_ok` is false, the area is unloaded and `content_id == core.CONTENT_IGNORE` -]] ----@nodiscard ----@param x integer ----@param y integer ----@param z integer ----@return core.ContentID content_id, core.Param1 param1, core.Param2 param2, boolean pos_ok -function core.get_node_raw(x, y, z) end - ---[[ -* `core.get_node_light(pos[, timeofday])` - * Gets the light value at the given position. Note that the light value - "inside" the node at the given position is returned, so you usually want - to get the light value of a neighbor. - * `pos`: The position where to measure the light. - * `timeofday`: `nil` for current time, `0` for night, `0.5` for day - * Returns a number between `0` and `15` or `nil` - * `nil` is returned e.g. when the map isn't loaded at `pos` -]] ----@nodiscard ----@param pos ivector ----@param timeofday number? ----@return core.Light.part? -function core.get_node_light(pos, timeofday) end - ---[[ -* `core.get_natural_light(pos[, timeofday])` - * Figures out the sunlight (or moonlight) value at pos at the given time of - day. - * `pos`: The position of the node - * `timeofday`: `nil` for current time, `0` for night, `0.5` for day - * Returns a number between `0` and `15` or `nil` - * This function tests 203 nodes in the worst case, which happens very - unlikely -]] ----@param pos ivector ----@param timeofday number? ----@return core.Light.part? -function core.get_natural_light(pos, timeofday) end - ---[[ -* `core.get_artificial_light(param1)` - * Calculates the artificial light (light from e.g. torches) value from the - `param1` value. - * `param1`: The param1 value of a `paramtype = "light"` node. - * Returns a number between `0` and `15` - * Currently it's the same as `math.floor(param1 / 16)`, except that it - ensures compatibility. -]] ----@nodiscard ----@param param1 core.Param1 ----@return core.Light.part -function core.get_artificial_light(param1) end - ---[[ -* `core.place_node(pos, node[, placer])` - * Place node with the same effects that a player would cause - * `placer`: The ObjectRef that places the node (optional) -]] ----@nodiscard ----@param pos ivector ----@param node core.Node.get ----@param placer core.PlayerRef? ----@return boolean -function core.place_node(pos, node, placer) end - ---[[ -* `core.dig_node(pos[, digger])` - * Dig node with the same effects that a player would cause - * `digger`: The ObjectRef that digs the node (optional) - * Returns `true` if successful, `false` on failure (e.g. protected location) -]] ----@nodiscard ----@param pos ivector ----@param digger core.PlayerRef? ----@return boolean -function core.dig_node(pos, digger) end - ---[[ -* `core.punch_node(pos[, puncher])` - * Punch node with the same effects that a player would cause - * `puncher`: The ObjectRef that punches the node (optional) -]] ----@nodiscard ----@param pos ivector ----@param puncher core.PlayerRef? ----@return boolean -function core.punch_node(pos, puncher) end - ---[[ -* `core.spawn_falling_node(pos)` - * Change node into falling node - * Returns `true` and the ObjectRef of the spawned entity if successful, `false` on failure -]] ----@nodiscard ----@param pos ivector ----@return boolean -function core.spawn_falling_node(pos) end - ---[[ -* `core.find_nodes_with_meta(pos1, pos2)` - * Get a table of positions of nodes that have metadata within a region - {pos1, pos2}. -]] ----@nodiscard ----@param pos1 ivector ----@param pos2 ivector ----@return vec[] -function core.find_nodes_with_meta(pos1, pos2) end - ---[[ -WIPDOC -]] ----@nodiscard ----@param pos ivector ----@return core.NodeMetaRef -function core.get_meta(pos) end - ---[[ -WIPDOC -]] ----@nodiscard ----@param pos ivector ----@return core.NodeTimerRef -function core.get_node_timer(pos) end - --- --------------------------------- entity --------------------------------- -- - ---[[ -* `core.add_entity(pos, name, [staticdata])`: Spawn Lua-defined entity at - position. - * Returns `ObjectRef`, or `nil` if failed - * Entities with `static_save = true` can be added also - to unloaded and non-generated blocks. -]] ----@nodiscard ----@param pos vector ----@param name string ----@param staticdata string? ----@return core.EntityRef? -function core.add_entity(pos, name, staticdata) end - ---[[ -* `core.add_item(pos, item)`: Spawn item - * Returns `ObjectRef`, or `nil` if failed - * Items can be added also to unloaded and non-generated blocks. -]] ----@nodiscard ----@param pos vector ----@param item core.Item ----@return core.EntityRef? -function core.add_item(pos, item) end - ---[[ -* `core.get_player_by_name(name)`: Get an `ObjectRef` to a player - * Returns nothing in case of error (player offline, doesn't exist, ...). -]] ----@nodiscard ----@param name string ----@return core.PlayerRef? -function core.get_player_by_name(name) end - ---[[ -* `core.get_objects_inside_radius(center, radius)` - * returns a list of ObjectRefs - * `radius`: using a Euclidean metric - * **Warning**: Any kind of interaction with the environment or other APIs - can cause later objects in the list to become invalid while you're iterating it. - (e.g. punching an entity removes its children) - It is recommended to use `core.objects_inside_radius` instead, which - transparently takes care of this possibility. -]] ----@nodiscard ----@param center vector ----@param radius number ----@return core.ObjectRef[] -function core.get_objects_inside_radius(center, radius) end - ---[[ -* `core.objects_inside_radius(center, radius)` - * returns an iterator of valid objects - * example: `for obj in core.objects_inside_radius(center, radius) do obj:punch(...) end` -]] ----@nodiscard ----@param center vector ----@param radius number ----@return fun():core.ObjectRef? -function core.objects_inside_radius(center, radius) end - ---[[ -* `core.get_objects_in_area(min_pos, max_pos)` - * returns a list of ObjectRefs - * `min_pos` and `max_pos` are the min and max positions of the area to search - * **Warning**: The same warning as for `core.get_objects_inside_radius` applies. - Use `core.objects_in_area` instead to iterate only valid objects. -]] ----@nodiscard ----@param minp vector ----@param maxp vector ----@return core.ObjectRef[] -function core.get_objects_in_area(minp, maxp) end - ---[[ -* `core.objects_in_area(min_pos, max_pos)` - * returns an iterator of valid objects -]] ----@nodiscard ----@param minp vector ----@param maxp vector ----@return fun():core.ObjectRef? -function core.objects_in_area(minp, maxp) end - --- ---------------------------------- time ---------------------------------- -- - ---[[ -WIPDOC -]] ----@param val number -function core.set_timeofday(val) end - ---[[ -* `core.get_timeofday()`: get time of day -]] ----@nodiscard ----@return number -function core.get_timeofday() end - ---[[ -* `core.get_gametime()`: returns the time, in seconds, since the world was - created. The time is not available (`nil`) before the first server step. -]] ----@nodiscard ----@return number? -function core.get_gametime() end - ---[[ -* `core.get_day_count()`: returns number days elapsed since world was - created. - * Time changes are accounted for. -]] ----@nodiscard ----@return integer -function core.get_day_count() end - --- -------------------------------- find node ------------------------------- -- - ---[[ -Unofficial note: I think this function is a lot laggier than the alternatives -If you are simply trying to check if a node is in a big area, use `core.find_nodes_in_area` -Anyway, someone will need to fact check me on that claim! Anyway: The actual docs: -But you can notice that it doesn't have that pesky volume limit, so it's implemented differently - -* `core.find_node_near(pos, radius, nodenames, [search_center])`: returns - pos or `nil`. - * `radius`: using a maximum metric - * `nodenames`: e.g. `{"ignore", "group:tree"}` or `"default:dirt"` - * `search_center` is an optional boolean (default: `false`) - If true `pos` is also checked for the nodes -]] ----@nodiscard ----@param pos ivector ----@param radius integer ----@param nodenames OneOrMany ----@param search_center boolean? ----@return vec? -function core.find_node_near(pos, radius, nodenames, search_center) end - ---[[ -* `core.find_nodes_in_area(pos1, pos2, nodenames, [grouped])` - * `pos1` and `pos2` are the min and max positions of the area to search. - * `nodenames`: e.g. `{"ignore", "group:tree"}` or `"default:dirt"` - * If `grouped` is true the return value is a table indexed by node name - which contains lists of positions. - * If `grouped` is false or absent the return values are as follows: - first value: Table with all node positions - second value: Table with the count of each node with the node name - as index - * Area volume is limited to 150,000,000 nodes -]] ----@nodiscard ----@param pos1 ivector ----@param pos2 ivector ----@param nodenames OneOrMany ----@param grouped true ----@return table -function core.find_nodes_in_area(pos1, pos2, nodenames, grouped) end - ---[[ -WIPDOC -]] ----@nodiscard ----@param pos1 ivector ----@param pos2 ivector ----@param nodenames OneOrMany ----@param grouped false? ----@return ivec[], table -function core.find_nodes_in_area(pos1, pos2, nodenames, grouped) end - ---[[ -* `core.find_nodes_in_area_under_air(pos1, pos2, nodenames)`: returns a - list of positions. - * `nodenames`: e.g. `{"ignore", "group:tree"}` or `"default:dirt"` - * Return value: Table with all node positions with a node air above - * Area volume is limited to 150,000,000 nodes -]] ----@nodiscard ----@param pos1 ivector ----@param pos2 ivector ----@param nodenames OneOrMany ----@return ivec[] -function core.find_nodes_in_area_under_air(pos1, pos2, nodenames) end - --- ---------------------- mapblocks and map generation ---------------------- -- - ---[[ core.get_value_noise() .. core.get_perlin() split off into library/classes/ValueNoise.lua ]]-- - ---[[ core.get_voxel_manip() split off into library/classes/VoxelManip.lua ]]-- - ---[[ -* `core.set_gen_notify(flags, [deco_ids], [custom_ids])` - * Set the types of on-generate notifications that should be collected. - * `flags`: flag field, see [`gennotify`] for available generation notification types. - * The following parameters are optional: - * `deco_ids` is a list of IDs of decorations which notification - is requested for. - * `custom_ids` is a list of user-defined IDs (strings) which are - requested. By convention these should be the mod name with an optional - colon and specifier added, e.g. `"default"` or `"default:dungeon_loot"` -]] ----@param flags core.GenNotify.flags ----@param deco_ids core.DecorationID[]? ----@param custom_ids string[]? -function core.set_gen_notify(flags, deco_ids, custom_ids) end - ---[[ -* `core.get_gen_notify()` - * Returns a flagstring, a table with the `deco_id`s and a table with - user-defined IDs. -]] ----@nodiscard ----@return core.GenNotify.flags.stringfmt flags, core.DecorationID[] deco_ids, string[] custom_ids -function core.get_gen_notify() end - ---[[ -WIPDOC -]] ----@nodiscard ----@param decoration_name string ----@return core.DecorationID? -function core.get_decoration_id(decoration_name) end - ---[[ -WIPDOC -]] ----@nodiscard ----@param objectname "voxelmanip" ----@return core.VoxelManip, ivec emin, ivec emax -function core.get_mapgen_object(objectname) end - ---[[ -WIPDOC -]] ----@nodiscard ----@param objectname "heightmap" ----@return integer[] -function core.get_mapgen_object(objectname) end - ---[[ -WIPDOC -]] ----@nodiscard ----@param objectname "biomemap" ----@return core.BiomeID[] -function core.get_mapgen_object(objectname) end - ---[[ -WIPDOC -]] ----@nodiscard ----@param objectname "heatmap" ----@return number[] -function core.get_mapgen_object(objectname) end - ---[[ -WIPDOC -]] ----@nodiscard ----@param objectname "humiditymap" ----@return number[] -function core.get_mapgen_object(objectname) end - ---[[ -WIPDOC -]] ----@nodiscard ----@param objectname "gennotify" ----@return core.GenNotify -function core.get_mapgen_object(objectname) end - ---[[ -Unofficial note: this relates to the biome heat, idk override it and make your own custom mapgen if you dare -* `core.get_heat(pos)` - * Returns the heat at the position, or `nil` on failure. -]] ----@nodiscard ----@param pos ivector ----@return number? -function core.get_heat(pos) end - ---[[ -Unofficial note: this relates to the biome humidity, idk override it and make your own custom mapgen if you dare -* `core.get_humidity(pos)` - * Returns the humidity at the position, or `nil` on failure. -]] ----@nodiscard ----@param pos ivector ----@return number? -function core.get_humidity(pos) end - ---[[ core.get_biome_data() split off into ./biome_data.lua ]]-- - ---[[ -* `core.get_biome_id(biome_name)` - * Returns the biome id, as used in the biomemap Mapgen object and returned - by `core.get_biome_data(pos)`, for a given biome_name string. -]] ----@nodiscard ----@param biome_name string ----@return core.BiomeID -function core.get_biome_id(biome_name) end - ---[[ -* `core.get_biome_name(biome_id)` - * Returns the biome name string for the provided biome id, or `nil` on - failure. - * If no biomes have been registered, such as in mgv6, returns `default`. -]] ----@nodiscard ----@param biome_id core.BiomeID ----@return string? -function core.get_biome_name(biome_id) end - ---[[ core.get_mapgen_params() .. core.set_mapgen_params() split off into ./mapgen_params.lua ]]-- - ---[=[ -* `core.get_mapgen_edges([mapgen_limit[, chunksize]])` - * Returns the minimum and maximum possible generated node positions - in that order. - * `mapgen_limit` is an optional number. If it is absent, its value is that - of the *active* mapgen setting `"mapgen_limit"`. - * `chunksize` is an optional number. If it is absent, its value is that - of the *active* mapgen setting `"chunksize"`. -]=] ----@nodiscard ----@param mapgen_limit integer? ----@param chunksize integer? ----@return ivec min, ivec max -function core.get_mapgen_edges(mapgen_limit, chunksize) end - ---[[ -* `core.get_mapgen_chunksize()` - * Returns the currently active chunksize of the mapgen, as a vector. - The size is specified in blocks. -]] ----@nodiscard ----@return ivec -function core.get_mapgen_chunksize() end - ---[[ -* `core.get_mapgen_setting(name)` - * Gets the *active* mapgen setting (or nil if none exists) in string - format with the following order of precedence: - 1) Settings loaded from map_meta.txt or overrides set during mod - execution. - 2) Settings set by mods without a metafile override - 3) Settings explicitly set in the user config file, minetest.conf - 4) Settings set as the user config default -]] ----@nodiscard ----@param name _.LuantiSettings.mapgen.keys ----@return string? -function core.get_mapgen_setting(name) end - ---[[ -* `core.get_mapgen_setting_noiseparams(name)` - * Same as above, but returns the value as a NoiseParams table if the - setting `name` exists and is a valid NoiseParams. -]] ----@nodiscard ----@param name _.LuantiSettings.mapgen.keys.noise_params.3d ----@return core.NoiseParams.3d? -function core.get_mapgen_setting_noiseparams(name) end - ---[[ -* `core.get_mapgen_setting_noiseparams(name)` - * Same as above, but returns the value as a NoiseParams table if the - setting `name` exists and is a valid NoiseParams. -]] ----@nodiscard ----@param name _.LuantiSettings.mapgen.keys.noise_params.2d ----@return core.NoiseParams.2d? -function core.get_mapgen_setting_noiseparams(name) end - ---[[ -* `core.set_mapgen_setting(name, value, [override_meta])` - * Sets a mapgen param to `value`, and will take effect if the corresponding - mapgen setting is not already present in map_meta.txt. - * `override_meta` is an optional boolean (default: `false`). If this is set - to true, the setting will become the active setting regardless of the map - metafile contents. - * Note: to set the seed, use `"seed"`, not `"fixed_map_seed"`. -]] ----@param name _.LuantiSettings.mapgen.keys ----@param value string ----@param override_meta boolean? -function core.set_mapgen_setting(name, value, override_meta) end - ---[[ -* `core.set_mapgen_setting_noiseparams(name, value, [override_meta])` - * Same as above, except value is a NoiseParams table. -]] ----@param name _.LuantiSettings.mapgen.keys.noise_params.3d ----@param value core.NoiseParams.3d ----@param override_meta boolean? -function core.set_mapgen_setting_noiseparams(name, value, override_meta) end - ---[[ -* `core.set_mapgen_setting_noiseparams(name, value, [override_meta])` - * Same as above, except value is a NoiseParams table. -]] ----@param name _.LuantiSettings.mapgen.keys.noise_params.2d ----@param value core.NoiseParams.2d ----@param override_meta boolean? -function core.set_mapgen_setting_noiseparams(name, value, override_meta) end - ---[[ -* `core.set_noiseparams(name, noiseparams, set_default)` - * Sets the noiseparams setting of `name` to the noiseparams table specified - in `noiseparams`. - * `set_default` is an optional boolean (default: `true`) that specifies - whether the setting should be applied to the default config or current - active config. -]] ----@param name _.LuantiSettings.mapgen.keys.noise_params.3d ----@param noiseparams core.NoiseParams.3d ----@param set_default boolean? -function core.set_noiseparams(name, noiseparams, set_default) end - ---[[ -* `core.set_noiseparams(name, noiseparams, set_default)` - * Sets the noiseparams setting of `name` to the noiseparams table specified - in `noiseparams`. - * `set_default` is an optional boolean (default: `true`) that specifies - whether the setting should be applied to the default config or current - active config. -]] ----@param name _.LuantiSettings.mapgen.keys.noise_params.2d ----@param noiseparams core.NoiseParams.2d ----@param set_default boolean? -function core.set_noiseparams(name, noiseparams, set_default) end - ---[[ -WIPDOC -]] ----@nodiscard ----@param name _.LuantiSettings.mapgen.keys.noise_params.3d ----@return core.NoiseParams.3d -function core.get_noiseparams(name) end - ---[[ -WIPDOC -]] ----@nodiscard ----@param name _.LuantiSettings.mapgen.keys.noise_params.2d ----@return core.NoiseParams.2d -function core.get_noiseparams(name) end - ---[[ -* `core.generate_ores(vm, pos1, pos2)` - * Generate all registered ores within the VoxelManip `vm` and in the area - from `pos1` to `pos2`. - * `pos1` and `pos2` are optional and default to mapchunk minp and maxp. -]] ----@param vm core.VoxelManip ----@param pos1 ivector? ----@param pos2 ivector? -function core.generate_ores(vm, pos1, pos2) end - ---[=[ -* `core.generate_decorations(vm[, pos1, pos2, [use_mapgen_biomes]])` - * Generate all registered decorations within the VoxelManip `vm` and in the - area from `pos1` to `pos2`. - * `pos1` and `pos2` are optional and default to mapchunk minp and maxp. - * `use_mapgen_biomes` (optional boolean). For use in on_generated callbacks only. - If set to true, decorations are placed in respect to the biome map of the current chunk. - `pos1` and `pos2` must match the positions of the current chunk, or an error will be raised. - default: `false` -]=] ----@param vm core.VoxelManip ----@param pos1 ivector? ----@param pos2 ivector? ----@param use_mapgen_biomes boolean? -function core.generate_decorations(vm, pos1, pos2, use_mapgen_biomes) end - ---[[ -WIPDOC -]] ----@class core.ClearObjectsOptions ---[[ -WIPDOC -]] ----@field mode "full"|"quick" - ---[[ -* `core.clear_objects([options])` - * Clear all objects in the environment - * Takes an optional table as an argument with the field `mode`. - * mode = `"full"`: Load and go through every mapblock, clearing - objects (default). - * mode = `"quick"`: Clear objects immediately in loaded mapblocks, - clear objects in unloaded mapblocks only when the - mapblocks are next activated. -]] ----@param options core.ClearObjectsOptions? -function core.clear_objects(options) end - ---[[ -* `core.load_area(pos1[, pos2])` - * Load the mapblocks containing the area from `pos1` to `pos2`. - `pos2` defaults to `pos1` if not specified. - * This function does not trigger map generation. -]] ----@param pos1 ivector ----@param pos2 ivector? -function core.load_area(pos1, pos2) end - ---[[ core.emerge_area() split off into ./emerge_area.lua ]]-- - ---[[ -* `core.delete_area(pos1, pos2)` - * delete all mapblocks in the area from pos1 to pos2, inclusive -]] ----@param pos1 ivector ----@param pos2 ivector -function core.delete_area(pos1, pos2) end - --- ----------------------- ray casting and pathfinding ---------------------- -- - ---[[ -Unofficial note: The annoying thing about this little function is that it is hardcoded to check specifically for "air", nothing else -Though i am sure you can make it work out - -* `core.line_of_sight(pos1, pos2)`: returns `boolean, pos` - * Checks if there is anything other than air between pos1 and pos2. - * Returns false if something is blocking the sight. - * Returns the position of the blocking node when `false` - * `pos1`: First position - * `pos2`: Second position -]] ----@nodiscard ----@param pos1 ivector ----@param pos2 ivector ----@return true -function core.line_of_sight(pos1, pos2) end - ---[[ -Unofficial note: The annoying thing about this little function is that it is hardcoded to check specifically for "air", nothing else -Though i am sure you can make it work out - -* `core.line_of_sight(pos1, pos2)`: returns `boolean, pos` - * Checks if there is anything other than air between pos1 and pos2. - * Returns false if something is blocking the sight. - * Returns the position of the blocking node when `false` - * `pos1`: First position - * `pos2`: Second position -]] ----@nodiscard ----@param pos1 ivector ----@param pos2 ivector ----@return false, core.Node.get -function core.line_of_sight(pos1, pos2) end - ---[[ core.raycast() split off into classes/Raycast.lua ]]-- - ---[[ -* `core.find_path(pos1, pos2, searchdistance, max_jump, max_drop, algorithm)` - * returns table containing path that can be walked on - * returns a table of 3D points representing a path from `pos1` to `pos2` or - `nil` on failure. - * Reasons for failure: - * No path exists at all - * No path exists within `searchdistance` (see below) - * Start or end pos is buried in land - * `pos1`: start position - * `pos2`: end position - * `searchdistance`: maximum distance from the search positions to search in. - In detail: Path must be completely inside a cuboid. The minimum - `searchdistance` of 1 will confine search between `pos1` and `pos2`. - Larger values will increase the size of this cuboid in all directions - * `max_jump`: maximum height difference to consider walkable - * `max_drop`: maximum height difference to consider droppable - * `algorithm`: One of `"A*_noprefetch"` (default), `"A*"`, `"Dijkstra"`. - Difference between `"A*"` and `"A*_noprefetch"` is that - `"A*"` will pre-calculate the cost-data, the other will calculate it - on-the-fly -]] ----@nodiscard ----@param pos1 ivector ----@param pos2 ivector ----@param searchdistance integer ----@param max_jump integer ----@param max_drop integer ----@param algo "A*_noprefetch"|"A*"|"Dijkstra" ----@return ivec[]? -function core.find_path(pos1, pos2, searchdistance, max_jump, max_drop, algo) end - --- ------------------------------ L-system tree ----------------------------- -- - ---[[ -WIPDOC -]] ----@param pos ivector ----@param lsystem core.LSystemTreeDef -function core.spawn_tree(pos, lsystem) end - ---[[ -WIPDOC -]] ----@param vmanip core.VoxelManip ----@param pos ivector ----@param treedef core.LSystemTreeDef -function core.spawn_tree_on_vmanip(vmanip, pos, treedef) end - --- --------------------------------- liquid --------------------------------- -- - ---[[ -* `core.transforming_liquid_add(pos)` - * add node to liquid flow update queue -]] ----@param pos ivector -function core.transforming_liquid_add(pos) end - --- ------------------------------- node level ------------------------------- -- - ---[[ -* `core.get_node_max_level(pos)` - * get max available level for leveled node -]] ----@nodiscard ----@param pos ivector ----@return core.Param2.leveled -function core.get_node_max_level(pos) end - ---[[ -* `core.get_node_level(pos)` - * get level of leveled node (water, snow) -]] ----@nodiscard ----@param pos ivector ----@return core.Param2.leveled -function core.get_node_level(pos) end - ---[[ -* `core.set_node_level(pos, level)` - * set level of leveled node, default `level` equals `1` - * if `totallevel > maxlevel`, returns rest (`total-max`). -]] ----@nodiscard ----@param pos ivector ----@param level core.Param2.leveled ----@return core.Param2.leveled? -function core.set_node_level(pos, level) end - ---[[ -* `core.add_node_level(pos, level)` - * increase level of leveled node by level, default `level` equals `1` - * if `totallevel > maxlevel`, returns rest (`total-max`) - * `level` must be between -127 and 127 -]] ----@nodiscard ----@param pos ivector ----@param level core.Param2.leveled ----@return core.Param2.leveled? -function core.add_node_level(pos, level) end - --- ---------------------------------- misc ---------------------------------- -- - ---[[ -* `core.get_node_boxes(box_type, pos, [node])` - * `box_type` must be `"node_box"`, `"collision_box"` or `"selection_box"`. - * `pos` must be a node position. - * `node` can be a table in the form `{name=string, param1=number, param2=number}`. - If `node` is `nil`, the actual node at `pos` is used instead. - * Resolves any facedir-rotated boxes, connected boxes and the like into - actual boxes. - * Returns a list of boxes in the form - `{{x1, y1, z1, x2, y2, z2}, {x1, y1, z1, x2, y2, z2}, ...}`. Coordinates - are relative to `pos`. - * See also: [Node boxes](#node-boxes) -]] ----@param box_type "node_box"|"collision_box"|"selection_box" ----@param pos ivector ----@param node core.Node.get? ----@return core.NodeBox.box[] -function core.get_node_boxes(box_type, pos, node) end - ---[[ -* `core.fix_light(pos1, pos2)`: returns `true`/`false` - * resets the light in a cuboid-shaped part of - the map and removes lighting bugs. - * Loads the area if it is not loaded. - * `pos1` is the corner of the cuboid with the least coordinates - (in node coordinates), inclusive. - * `pos2` is the opposite corner of the cuboid, inclusive. - * The actual updated cuboid might be larger than the specified one, - because only whole map blocks can be updated. - The actual updated area consists of those map blocks that intersect - with the given cuboid. - * However, the neighborhood of the updated area might change - as well, as light can spread out of the cuboid, also light - might be removed. - * returns `false` if the area is not fully generated, - `true` otherwise -]] ----@nodiscard ----@param pos1 ivector ----@param pos2 ivector ----@return boolean -function core.fix_light(pos1, pos2) end - ---[[ -Unofficial note: You can override this one for your own custom cool falling blocks -* `core.check_single_for_falling(pos)` - * causes an unsupported `group:falling_node` node to fall and causes an - unattached `group:attached_node` node to fall. - * does not spread these updates to neighbors. -]] ----@param pos ivector -function core.check_single_for_falling(pos) end - ---[[ -* `core.check_for_falling(pos)` - * causes an unsupported `group:falling_node` node to fall and causes an - unattached `group:attached_node` node to fall. - * spread these updates to neighbors and can cause a cascade - of nodes to fall. -]] ----@param pos ivector -function core.check_for_falling(pos) end - ---[[ -* `core.get_spawn_level(x, z)` - * Returns a player spawn y coordinate for the provided (x, z) - coordinates, or `nil` for an unsuitable spawn point. - * For most mapgens a 'suitable spawn point' is one with y between - `water_level` and `water_level + 16`, and in mgv7 well away from rivers, - so `nil` will be returned for many (x, z) coordinates. - * The spawn level returned is for a player spawn in unmodified terrain. - * The spawn level is intentionally above terrain level to cope with - full-node biome 'dust' nodes. -]] ----@param x integer ----@param z integer ----@return integer? y -function core.get_spawn_level(x, z) end \ No newline at end of file diff --git a/types/luanti_lsp_definitions/library/core/environment/mapgen_params.lua b/types/luanti_lsp_definitions/library/core/environment/mapgen_params.lua deleted file mode 100644 index 06f946d2..00000000 --- a/types/luanti_lsp_definitions/library/core/environment/mapgen_params.lua +++ /dev/null @@ -1,69 +0,0 @@ ----@meta _ --- DRAFT 1 DONE --- luanti/doc/lua_api.md: 'core' namespace reference > Environment access - --- ------------------------------ MapgenParams ------------------------------ -- - ---[[ -WIPDOC -]] ----@class core.MapgenParams ---[[ -WIPDOC -]] ----@field mgname core.LuantiSettings.enums.mg_name ---[[ -WIPDOC -]] ----@field seed integer ---[[ -WIPDOC -]] ----@field chunksize integer ---[[ -WIPDOC -]] ----@field water_level integer ---[[ -WIPDOC -]] ----@field flags core.LuantiSettings.flags.mg_flags|core.LuantiSettings.flags - --- ---------------------------- core.* functions ---------------------------- -- - ---[[ -* `core.get_mapgen_params()` - * Deprecated: use `core.get_mapgen_setting(name)` instead. - * Returns a table containing: - * `mgname` - * `seed` - * `chunksize` - * `water_level` - * `flags` -]] ----@deprecated ----@nodiscard ----@return core.MapgenParams -function core.get_mapgen_params() end - ---[[ -* `core.set_mapgen_params(MapgenParams)` - * Deprecated: use `core.set_mapgen_setting(name, value, override)` - instead. - * Set map generation parameters. - * Function cannot be called after the registration period. - * Takes a table as an argument with the fields: - * `mgname` - * `seed` - * `chunksize` - * `water_level` - * `flags` - * Leave field unset to leave that parameter unchanged. - * `flags` contains a comma-delimited string of flags to set, or if the - prefix `"no"` is attached, clears instead. - * `flags` is in the same format and has the same options as `mg_flags` in - `minetest.conf`. -]] ----@deprecated ----@param MapgenParams core.MapgenParams -function core.set_mapgen_params(MapgenParams) end \ No newline at end of file diff --git a/types/luanti_lsp_definitions/library/core/escape_sequences.lua b/types/luanti_lsp_definitions/library/core/escape_sequences.lua deleted file mode 100644 index 5a7b3127..00000000 --- a/types/luanti_lsp_definitions/library/core/escape_sequences.lua +++ /dev/null @@ -1,66 +0,0 @@ ----@meta _ --- DRAFT 1 DONE --- luanti/doc/lua_api.md: Colors --- luanti/doc/lua_api.md: Escape sequences - ---[[ -The escape sequence sets the text color to color -(Unofficial note: this is mostly for formspec UI elements) -]] ----@nodiscard ----@param color core.ColorString ----@return string -function core.get_color_escape_sequence(color) end - ---[[ -Equivalent to: core.get_color_escape_sequence(color) .. message .. core.get_color_escape_sequence("#ffffff") -(Unofficial note: this is mostly for formspec UI elements) -]] ----@nodiscard ----@param color core.ColorString ----@param message string ----@return string -function core.colorize(color, message) end - ---[[ -The escape sequence sets the background of the whole text element to color. Only defined for item descriptions and tooltips. -]] ----@nodiscard ----@param color core.ColorString ----@return string -function core.get_background_escape_sequence(color) end - ---[[ -Removes foreground colors added by get_color_escape_sequence. -]] ----@nodiscard ----@param str string ----@return string -function core.strip_foreground_colors(str) end - ---[[ -Removes background colors added by get_background_escape_sequence. -]] ----@nodiscard ----@param str string ----@return string -function core.strip_background_colors(str) end - ---[[ -Removes all color escape sequences. -]] ----@nodiscard ----@param str string ----@return string -function core.strip_colors(str) end - ---[[ -* `core.strip_escapes(str)` - * Removes all escape sequences, including client-side translations and - any unknown or future escape sequences that Luanti might define. - * You can use this to clean text before logging or handing to an external system. -]] ----@nodiscard ----@param str string ----@return string -function core.strip_escape(str) end \ No newline at end of file diff --git a/types/luanti_lsp_definitions/library/core/formspec_functions.lua b/types/luanti_lsp_definitions/library/core/formspec_functions.lua deleted file mode 100644 index 0b2db293..00000000 --- a/types/luanti_lsp_definitions/library/core/formspec_functions.lua +++ /dev/null @@ -1,145 +0,0 @@ ----@meta _ --- DRAFT 1 DONE --- luanti/doc/lua_api.md: 'core' namespace reference > Formspec functions - ---[[ -* `core.show_formspec(playername, formname, formspec)` - * `playername`: name of player to show formspec - * `formname`: name passed to `on_player_receive_fields` callbacks. - * It should follow the `"modname:"` naming convention. - * If empty: Shows a custom, temporary inventory formspec. - * An inventory formspec shown this way will also be updated if - `ObjectRef:set_inventory_formspec` is called. - * Use `ObjectRef:set_inventory_formspec` to change the player's - inventory formspec for future opens. - * Supported if server AND client are both of version >= 5.13.0. - * `formspec`: formspec to display - * See also: `core.register_on_player_receive_fields` -]] ----@param playername string ----@param formname string ----@param formspec core.Formspec -function core.show_formspec(playername, formname, formspec) end - ---[[ -* `core.close_formspec(playername, formname)` - * `playername`: name of player to close formspec - * `formname`: has to exactly match the one given in `show_formspec`, or the - formspec will not close. - * calling `show_formspec(playername, formname, "")` is equal to this - expression. - * to close a formspec regardless of the formname, call - `core.close_formspec(playername, "")`. - **USE THIS ONLY WHEN ABSOLUTELY NECESSARY!** -]] ----@param playername string ----@param formname string -function core.close_formspec(playername, formname) end - ---[[ -* `core.hypertext_escape(string)`: returns a string - * escapes the characters "\", "<", and ">" to show text in a hypertext element. - * not safe for use with tag attributes. - * this function does not do formspec escaping, you will likely need to do - `core.formspec_escape(core.hypertext_escape(string))` if the hypertext is - not already being formspec escaped. -]] ----@nodiscard ----@param string string ----@return string -function core.hypertext_escape(string) end - ---[[ -WIPDOC -]] ----@class core.ExplodeEvent.table ---[[ -WIPDOC -]] ----@field type "INV"|"CHG"|"DCL" ---[[ -WIPDOC -]] ----@field row integer ---[[ -WIPDOC -]] ----@field column integer - ---[[ -* `core.explode_table_event(string)`: returns a table - * returns e.g. `{type="CHG", row=1, column=2}` - * `type` is one of: - * `"INV"`: no row selected - * `"CHG"`: selected - * `"DCL"`: double-click -]] ----@nodiscard ----@param string string ----@return core.ExplodeEvent.table -function core.explode_table_event(string) end - ---[[ -WIPDOC -]] ----@class core.ExplodeEvent.textlist ---[[ -WIPDOC -]] ----@field type "INV"|"CHG"|"DCL" ---[[ -WIPDOC -]] ----@field index integer - ---[[ -* `core.explode_textlist_event(string)`: returns a table - * returns e.g. `{type="CHG", index=1}` - * `type` is one of: - * `"INV"`: no row selected - * `"CHG"`: selected - * `"DCL"`: double-click -]] ----@nodiscard ----@param string string ----@return core.ExplodeEvent.textlist -function core.explode_textlist_event(string) end - ---[[ -WIPDOC -]] ----@class core.ExplodeEvent.scrollbar ---[[ -WIPDOC -]] ----@field type "INV"|"CHG"|"VAL" ---[[ -WIPDOC -]] ----@field value integer - ---[[ -* `core.explode_scrollbar_event(string)`: returns a table - * returns e.g. `{type="CHG", value=500}` - * `type` is one of: - * `"INV"`: something failed - * `"CHG"`: has been changed - * `"VAL"`: not changed -]] ----@nodiscard ----@param string string ----@return core.ExplodeEvent.scrollbar -function core.explode_scrollbar_event(string) end - ---[[ -* `core.show_death_screen(player, reason)` - * Called when the death screen should be shown. - * `player` is an ObjectRef, `reason` is a PlayerHPChangeReason table or nil. - * By default, this shows a simple formspec with the option to respawn. - Respawning is done via `ObjectRef:respawn`. - * You can override this to show a custom death screen. - * For general death handling, use `core.register_on_dieplayer` instead. -]] ----@param player core.PlayerRef ----@param reason core.PlayerHPChangeReason? -function core.show_death_screen(player, reason) end \ No newline at end of file diff --git a/types/luanti_lsp_definitions/library/core/global_tables.lua b/types/luanti_lsp_definitions/library/core/global_tables.lua deleted file mode 100644 index 3bf1799c..00000000 --- a/types/luanti_lsp_definitions/library/core/global_tables.lua +++ /dev/null @@ -1,332 +0,0 @@ ----@meta _ --- DRAFT 1 DONE --- luanti/doc/lua_api.md: 'core' namespace reference > Global tables ---[=[ -NOTE: manually searched from output log of below in a minimal game: -core.log(dump2(core, 'core')) -]=] - ---[[ -WIPDOC -]] ----@type core.fn.on_mods_loaded[] -core.registered_on_mods_loaded = {} - ---[[ -WIPDOC -]] ----@type core.fn.on_shutdown[] -core.registered_on_shutdown = {} - ---[[ -WIPDOC -]] ----@type core.fn.on_generated[] -core.registered_on_generateds = {} - ---[[ -WIPDOC -]] ----@type core.fn.on_newplayer[] -core.registered_on_newplayers = {} - ---[[ -WIPDOC -]] ----@type core.fn.on_dieplayer[] -core.registered_on_dieplayers = {} - ---[[ -WIPDOC -]] ----@type core.fn.on_respawnplayer[] -core.registered_on_respawnplayers = {} - ---[[ -WIPDOC -]] ----@type core.fn.on_prejoinplayer[] -core.registered_on_prejoinplayers = {} - ---[[ -WIPDOC -]] ----@type core.fn.on_joinplayer[] -core.registered_on_joinplayers = {} - ---[[ -WIPDOC -]] ----@type core.fn.on_leaveplayer[] -core.registered_on_leaveplayers = {} - ---[[ -WIPDOC -]] ----@type core.fn.on_player_receive_fields[] -core.registered_on_player_receive_fields = {} - ---[[ -WIPDOC -]] ----@type core.fn.on_cheat[] -core.registered_on_cheats = {} - ---[[ -WIPDOC -]] ----@type core.fn.on_protection_violation[] -core.registered_on_protection_violation = {} - ---[[ -WIPDOC -]] ----@type core.fn.on_punchplayer[] -core.registered_on_punchplayers = {} - ---[[ -WIPDOC -]] ----@type core.fn.on_priv_grant[] -core.registered_on_priv_grant = {} - ---[[ -WIPDOC -]] ----@type core.fn.on_priv_revoke[] -core.registered_on_priv_revoke = {} - ---[[ -WIPDOC -]] ----@type core.fn.on_authplayer[] -core.registered_on_authplayers = {} - ---[[ -WIPDOC -]] ----@type core.fn.can_bypass_userlimit[] -core.registered_can_bypass_userlimit = {} - ---[[ -WIPDOC -]] ----@type core.fn.on_modchannel_message[] -core.registered_on_modchannel_message = {} - ---[[ -WIPDOC -]] ----@type core.fn.on_player_inventory_action[] -core.registered_on_player_inventory_actions = {} - ---[[ -WIPDOC -]] ----@type core.fn.allow_player_inventory_action[] -core.registered_allow_player_inventory_actions = {} - ---[[ -WIPDOC -]] ----@type core.fn.on_rightclickplayer[] -core.registered_on_rightclickplayers = {} - ---[[ -WIPDOC -]] ----@type core.fn.on_liquid_transform[] -core.registered_on_liquid_transformed = {} - ---[[ -WIPDOC -]] ----@type core.fn.on_mapblocks_changed[] -core.registered_on_mapblocks_changed = {} - ---[[ -WIPDOC -]] ----@type table -core.registered_privileges = {} - ---[[ -WIPDOC -]] ----@type table -core.registered_chatcommands = {} - ---[[ -WIPDOC -]] ----@type table -core.registered_nodes = {} - ---[[ -WIPDOC -]] ----@type core.fn.on_craft[] -core.registered_on_crafts = {} - ---[[ -WIPDOC -]] ----@type core.fn.craft_predict[] -core.registered_craft_predicts = {} - ---[[ -WIPDOC -]] ----@type core.fn.on_item_pickup[] -core.registered_on_item_pickups = {} - ---[[ -WIPDOC -]] ----@type core.fn.on_item_eat[] -core.registered_on_item_eats = {} - ---[[ -WIPDOC -]] ----@type core.fn.on_dignode[] -core.registered_on_dignodes = {} - ---[[ -WIPDOC -]] ----@type core.fn.on_placenode[] -core.registered_on_placenodes = {} - ---[[ -WIPDOC -]] ----@type core.fn.on_punchnode[] -core.registered_on_punchnodes = {} - ---[[ -WIPDOC -]] ----@type table -core.objects_by_guid = {} - ---[[ -WIPDOC -]] ----@deprecated ----@type table -core.object_refs = {} - ---[[ -WIPDOC -]] ----@type table -core.luaentities = {} - ---[[ -WIPDOC -]] ----@type table -core.registered_aliases = {} - ---[[ -WIPDOC -]] ----@type table -core.registered_tools = {} - ---[[ -WIPDOC -]] ----@type table -core.registered_craftitems = {} - ---[[ -WIPDOC -]] ----@type table -core.registered_items = {} - ---[[ -WIPDOC -]] ----@type table -core.registered_entities = {} - ---[[ -WIPDOC -]] ----@type core.LBMDef[] -core.registered_lbms = {} - ---[[ -WIPDOC -]] ----@type core.ABMDef[] -core.registered_abms = {} - ---[[ -WIPDOC -]] ----@class core.reg.on_player_hpchanges -core.registered_on_player_hpchanges = {} - ---[[ -WIPDOC -]] ----@type core.fn.on_player_hpchange.modifier[] -core.registered_on_player_hpchanges.modifiers = {} - ---[[ -WIPDOC -]] ----@type core.fn.on_player_hpchange.logger[] -core.registered_on_player_hpchanges.loggers = {} - ---[[ -WIPDOC -]] ----@type table -core.registered_biomes = {} - ---[[ -WIPDOC -]] ----@type table -core.registered_ores = {} - ---[[ -WIPDOC -]] ----@type table -core.registered_decorations = {} - ---[[ -WIPDOC -]] ----@type core.fn.on_chat_message[] -core.registered_on_chat_messages = {} - ---[[ -WIPDOC -]] ----@type core.fn.on_chatcommand[] -core.registered_on_chatcommands = {} - ---[[ -WIPDOC -]] ----@type core.fn.globalstep[] -core.registered_globalsteps = {} - ---[[ -WIPDOC -]] ----@type core.fn.playerevent[] -core.registered_playerevents = {} - ---[[ -WIPDOC -]] ----@type table -core.detached_inventories = {} \ No newline at end of file diff --git a/types/luanti_lsp_definitions/library/core/http.lua b/types/luanti_lsp_definitions/library/core/http.lua deleted file mode 100644 index 2058856c..00000000 --- a/types/luanti_lsp_definitions/library/core/http.lua +++ /dev/null @@ -1,66 +0,0 @@ ----@meta _ --- DRAFT 1 DONE --- luanti/doc/lua_api.md: 'core' namespace reference > HTTP Requests - --- ------------------------------ HTTPApiTable ------------------------------ -- - ---[[ -WIPDOC -]] ----@alias core.HTTPApiTable.fetch.fn fun(res:core.HTTPRequestDef) - ---[[ -WIPDOC -]] ----@alias core.HTTPApiTable.fetch fun(req:core.HTTPRequestDef, callback:core.HTTPApiTable.fetch.fn) - ---[[ -WIPDOC -]] ----@class core.HTTPFetchAsyncID : integer - ---[[ -WIPDOC -]] ----@alias core.HTTPApiTable.fetch_async fun(req:core.HTTPRequestDef) - ---[[ -WIPDOC -]] ----@alias core.HTTPApiTable.fetch_async_get fun(handle:core.HTTPFetchAsyncID):core.HTTPRequestResultDef - ---[[ -WIPDOC -]] ----@class core.HTTPApiTable ---[[ -WIPDOC -]] ----@field fetch core.HTTPApiTable.fetch ---[[ -WIPDOC -]] ----@field fetch_async core.HTTPApiTable.fetch_async ---[[ -WIPDOC -]] ----@field fetch_async_get core.HTTPApiTable.fetch_async_get - --- ---------------------------- core.* functions ---------------------------- -- - ---[[ -* `core.request_http_api()`: - * returns `HTTPApiTable` containing http functions if the calling mod has - been granted access by being listed in the `secure.http_mods` or - `secure.trusted_mods` setting, otherwise returns `nil`. - * The returned table contains the functions `fetch`, `fetch_async` and - `fetch_async_get` described below. - * Only works at init time and must be called from the mod's main scope - (not from a function). - * Function only exists if Luanti server was built with cURL support. - * **DO NOT ALLOW ANY OTHER MODS TO ACCESS THE RETURNED TABLE, STORE IT IN - A LOCAL VARIABLE!** -]] ----@nodiscard ----@return core.HTTPApiTable? -function core.request_http_api() end diff --git a/types/luanti_lsp_definitions/library/core/inventory.lua b/types/luanti_lsp_definitions/library/core/inventory.lua deleted file mode 100644 index ecba285f..00000000 --- a/types/luanti_lsp_definitions/library/core/inventory.lua +++ /dev/null @@ -1,93 +0,0 @@ ----@meta _ --- DRAFT 1 DONE --- luanti/doc/lua_api.md: 'core' namespace reference > Inventory - --- ---------------------------- InventoryLocation --------------------------- -- - ---[[ -WIPDOC -]] ----@class core.InventoryLocation.node ---[[ -WIPDOC -]] ----@field type "node" ---[[ -WIPDOC -]] ----@field pos ivec - ---[[ -WIPDOC -]] ----@class core.InventoryLocation.player ---[[ -WIPDOC -]] ----@field type "player" ---[[ -WIPDOC -]] ----@field name string - ---[[ -WIPDOC -]] ----@class core.InventoryLocation.detached ---[[ -WIPDOC -]] ----@field type "detached" ---[[ -WIPDOC -]] ----@field name string - ---[[ -WIPDOC -]] ----@alias core.InventoryLocation ---- | core.InventoryLocation.node ---- | core.InventoryLocation.player ---- | core.InventoryLocation.detached - ---[[ -WIPDOC -]] ----@class core.InventoryLocation.undefined ---[[ -WIPDOC -]] ----@field type "undefined" - --- ---------------------------- core.* functions ---------------------------- -- - ---[[ -`core.get_inventory(location)`: returns an `InvRef` - -* `location` = e.g. - * `{type="player", name="celeron55"}` - * `{type="node", pos={x=, y=, z=}}` - * `{type="detached", name="creative"}` -]] ----@param location core.InventoryLocation ----@return core.InvRef -function core.get_inventory(location) end - ---[[ -WIPDOC -]] ----@nodiscard ----@param name string ----@param callbacks core.DetachedInventoryCallbacks ----@param player_name string? ----@return core.InvRef -function core.create_detached_inventory(name, callbacks, player_name) end - ---[[ -WIPDOC -]] ----@nodiscard ----@param name string ----@return boolean -function core.remove_detached_inventory(name) end \ No newline at end of file diff --git a/types/luanti_lsp_definitions/library/core/ipc.lua b/types/luanti_lsp_definitions/library/core/ipc.lua deleted file mode 100644 index e0cc9c93..00000000 --- a/types/luanti_lsp_definitions/library/core/ipc.lua +++ /dev/null @@ -1,69 +0,0 @@ ----@meta _ --- DRAFT 1 DONE --- luanti/doc/lua_api.md: 'core' namespace reference > IPC - ---[[ -* `core.ipc_get(key)`: - * Read a value from the shared data area. - * `key`: string, should use the `"modname:thing"` convention to avoid conflicts. - * returns an arbitrary Lua value, or `nil` if this key does not exist -]] ----@nodiscard ----@param key string ----@return core.Serializable? -function core.ipc_get(key) end - ---[[ -* `core.ipc_set(key, value)`: - * Write a value to the shared data area. - * `key`: as above - * `value`: an arbitrary Lua value, cannot be or contain userdata. - -Interacting with the shared data will perform an operation comparable to -(de)serialization on each access. -For that reason modifying references will not have any effect, as in this example: -```lua -core.ipc_set("test:foo", {}) -core.ipc_get("test:foo").subkey = "value" -- WRONG! -core.ipc_get("test:foo") -- returns an empty table -``` - -]] ----@param key string ----@param value core.Serializable -function core.ipc_set(key, value) end - ---[[ -* `core.ipc_cas(key, old_value, new_value)`: - * Write a value to the shared data area, but only if the previous value - equals what was given. - This operation is called Compare-and-Swap and can be used to implement - synchronization between threads. - * `key`: as above - * `old_value`: value compared to using `==` (`nil` compares equal for non-existing keys) - * `new_value`: value that will be set - * returns: true on success, false otherwise -]] ----@nodiscard ----@param key string ----@param old_value core.Serializable ----@param new_value core.Serializable ----@return boolean success -function core.ipc_cas(key, old_value, new_value) end - ---[[ -* `core.ipc_poll(key, timeout)`: - * Do a blocking wait until a value (other than `nil`) is present at the key. - * **IMPORTANT**: You usually don't need this function. Use this as a last resort - if nothing else can satisfy your use case! None of the Lua environments the - engine has are safe to block for extended periods, especially on the main - thread any delays directly translate to lag felt by players. - * `key`: as above - * `timeout`: maximum wait time, in milliseconds (positive values only) - * returns: true on success, false on timeout -]] ----@nodiscard ----@param key string ----@param timeout number ----@return boolean success -function core.ipc_poll(key, timeout) end \ No newline at end of file diff --git a/types/luanti_lsp_definitions/library/core/item_handling/craft_result.lua b/types/luanti_lsp_definitions/library/core/item_handling/craft_result.lua deleted file mode 100644 index 9c2e6f47..00000000 --- a/types/luanti_lsp_definitions/library/core/item_handling/craft_result.lua +++ /dev/null @@ -1,285 +0,0 @@ ----@meta _ --- DRAFT 1 DONE --- luanti/doc/lua_api.md: 'core' namespace reference > Item handling - ---[[ -WIPDOC -]] ----@class core.CraftRecipe.unknown ---[[ -WIPDOC -]] ----@field method "unknown" ---[[ -WIPDOC -]] ----@field width 0 ---[[ -WIPDOC -]] ----@field items nil - ---[[ -WIPDOC -]] ----@class core.CraftRecipe.normal.set ---[[ -WIPDOC -]] ----@field method "normal" ---[[ -WIPDOC -]] ----@field width integer? ---[[ -WIPDOC -]] ----@field items core.ItemList - ---[[ -WIPDOC -]] ----@class core.CraftRecipe.normal.get ---[[ -WIPDOC -]] ----@field method "normal" ---[[ -WIPDOC -]] ----@field width integer ---[[ -WIPDOC -]] ----@field items core.ItemList - ---[[ -WIPDOC -]] ----@class core.CraftRecipe.cooking ---[[ -WIPDOC -]] ----@field method "cooking" ---[[ -WIPDOC -]] ----@field items core.ItemList - ---[[ -WIPDOC -]] ----@class core.CraftRecipe.fuel ---[[ -WIPDOC -]] ----@field method "fuel" ---[[ -WIPDOC -]] ----@field items core.ItemList - ---[[ -WIPDOC -]] ----@alias core.CraftRecipe.set ---- | core.CraftRecipe.normal.set ---- | core.CraftRecipe.cooking ---- | core.CraftRecipe.fuel - ---[[ -WIPDOC -]] ----@alias core.CraftRecipe.get ---- | core.CraftRecipe.normal.get ---- | core.CraftRecipe.cooking ---- | core.CraftRecipe.fuel - --- ----------------------- CraftingRecipe.with_output ----------------------- -- - ----@class _.CraftRecipe.with_output ---[[ -WIPDOC -]] ----@field output core.Item.stringfmt - ---[[ -WIPDOC -]] ----@class core.CraftRecipe.with_output.unknown : core.CraftRecipe.unknown, _.CraftRecipe.with_output - ---[[ -WIPDOC -]] ----@class core.CraftRecipe.with_output.normal : core.CraftRecipe.normal.get, _.CraftRecipe.with_output - ---[[ -WIPDOC -]] ----@class core.CraftRecipe.with_output.cooking : core.CraftRecipe.cooking, _.CraftRecipe.with_output - ---[[ -WIPDOC -]] ----@class core.CraftRecipe.with_output.fuel : core.CraftRecipe.fuel, _.CraftRecipe.with_output - ---[[ -WIPDOC -]] ----@alias core.CraftRecipe.with_output ---- | core.CraftRecipe.with_output.unknown ---- | core.CraftRecipe.with_output.normal ---- | core.CraftRecipe.with_output.cooking ---- | core.CraftRecipe.with_output.fuel - --- ------------------------------- CraftOutput ------------------------------ -- - ---[[ -WIPDOC -]] ----@class core.CraftOutput.normal ---[[ -WIPDOC -]] ----@field item core.ItemStack ---[[ -WIPDOC -]] ----@field replacements SparseList - ---[[ -WIPDOC -]] ----@class core.CraftOutput.cooking ---[[ -WIPDOC -]] ----@field item core.ItemStack ---[[ -WIPDOC -]] ----@field replacements SparseList ---[[ -WIPDOC -]] ----@field time number - ---[[ -WIPDOC -]] ----@class core.CraftOutput.fuel ---[[ -WIPDOC -]] ----@field replacements SparseList ---[[ -WIPDOC -]] ----@field time number - ---[[ -WIPDOC -]] ----@alias core.CraftOutput ---- | core.CraftOutput.normal ---- | core.CraftOutput.cooking ---- | core.CraftOutput.fuel - --- ---------------------------- core.* functions ---------------------------- -- - ---[[ -* `core.get_craft_result(input)`: returns `output, decremented_input` - * `input.method` = `"normal"` or `"cooking"` or `"fuel"` - * `input.width` = for example `3` - * `input.items` = for example - `{stack1, stack2, stack3, stack4, stack 5, stack 6, stack 7, stack 8, stack 9}` - * `output.item` = `ItemStack`, if unsuccessful: empty `ItemStack` - * `output.time` = a number, if unsuccessful: `0` - * `output.replacements` = List of replacement `ItemStack`s that couldn't be - placed in `decremented_input.items`. Replacements can be placed in - `decremented_input` if the stack of the replaced item has a count of 1. - * `decremented_input` = like `input` -]] ----@nodiscard ----@param input core.CraftRecipe.normal.set ----@return core.CraftOutput.normal, core.CraftRecipe.normal.get -function core.get_craft_result(input) end - ---[[ -* `core.get_craft_result(input)`: returns `output, decremented_input` - * `input.method` = `"normal"` or `"cooking"` or `"fuel"` - * `input.width` = for example `3` - * `input.items` = for example - `{stack1, stack2, stack3, stack4, stack 5, stack 6, stack 7, stack 8, stack 9}` - * `output.item` = `ItemStack`, if unsuccessful: empty `ItemStack` - * `output.time` = a number, if unsuccessful: `0` - * `output.replacements` = List of replacement `ItemStack`s that couldn't be - placed in `decremented_input.items`. Replacements can be placed in - `decremented_input` if the stack of the replaced item has a count of 1. - * `decremented_input` = like `input` -]] ----@nodiscard ----@param input core.CraftRecipe.cooking ----@return core.CraftOutput.cooking, core.CraftRecipe.cooking -function core.get_craft_result(input) end - ---[[ -* `core.get_craft_result(input)`: returns `output, decremented_input` - * `input.method` = `"normal"` or `"cooking"` or `"fuel"` - * `input.width` = for example `3` - * `input.items` = for example - `{stack1, stack2, stack3, stack4, stack 5, stack 6, stack 7, stack 8, stack 9}` - * `output.item` = `ItemStack`, if unsuccessful: empty `ItemStack` - * `output.time` = a number, if unsuccessful: `0` - * `output.replacements` = List of replacement `ItemStack`s that couldn't be - placed in `decremented_input.items`. Replacements can be placed in - `decremented_input` if the stack of the replaced item has a count of 1. - * `decremented_input` = like `input` -]] ----@nodiscard ----@param input core.CraftRecipe.fuel ----@return core.CraftOutput.fuel, core.CraftRecipe.fuel -function core.get_craft_result(input) end - ---[[ -* `core.get_craft_recipe(output)`: returns input - * returns last registered recipe for output item (node) - * `output` is a node or item type such as `"default:torch"` - * `input.method` = `"normal"` or `"cooking"` or `"fuel"` - * `input.width` = for example `3` - * `input.items` = for example - `{stack1, stack2, stack3, stack4, stack 5, stack 6, stack 7, stack 8, stack 9}` - * `input.items` = `nil` if no recipe found -]] ----@nodiscard ----@param output core.Item.name ----@return core.CraftRecipe.get|core.CraftRecipe.unknown -function core.get_craft_recipe(output) end - ---[[ -* `core.get_all_craft_recipes(query item)`: returns a table or `nil` - * returns indexed table with all registered recipes for query item (node) - or `nil` if no recipe was found. - * recipe entry table: - * `method`: 'normal' or 'cooking' or 'fuel' - * `width`: 0-3, 0 means shapeless recipe - * `items`: indexed [1-9] table with recipe items - * `output`: string with item name and quantity - * Example result for `"default:gold_ingot"` with two recipes: - ```lua - { - { - method = "cooking", width = 3, - output = "default:gold_ingot", items = {"default:gold_lump"} - }, - { - method = "normal", width = 1, - output = "default:gold_ingot 9", items = {"default:goldblock"} - } - } - ``` -]] ----@nodiscard ----@param query_item core.Item.name ----@return core.CraftRecipe.with_output[] -function core.get_all_craft_recipes(query_item) end \ No newline at end of file diff --git a/types/luanti_lsp_definitions/library/core/item_handling/item_handling.lua b/types/luanti_lsp_definitions/library/core/item_handling/item_handling.lua deleted file mode 100644 index 4f0ae051..00000000 --- a/types/luanti_lsp_definitions/library/core/item_handling/item_handling.lua +++ /dev/null @@ -1,167 +0,0 @@ ----@meta _ --- DRAFT 1 DONE --- luanti/doc/lua_api.md: 'core' namespace reference > Item handling - ---[[ -WIPDOC -]] ----@nodiscard ----@param img1 core.Texture ----@param img2 core.Texture ----@param img3 core.Texture ----@return core.Texture -function core.inventorycube(img1, img2, img3) end - ---[[ -* `core.get_pointed_thing_position(pointed_thing, above)` - * Returns the position of a `pointed_thing` or `nil` if the `pointed_thing` - does not refer to a node or entity. - * If the optional `above` parameter is true and the `pointed_thing` refers - to a node, then it will return the `above` position of the `pointed_thing`. -]] ----@nodiscard ----@param pointed_thing core.PointedThing ----@param above boolean? ----@return vec? -function core.get_pointed_thing_position(pointed_thing, above) end - ---[[ -WIPDOC -]] ----@nodiscard ----@param dir vector ----@param is6d boolean? ----@return core.Param2.facedir -function core.dir_to_facedir(dir, is6d) end - ---[[ -WIPDOC -]] ----@nodiscard ----@param facedir core.Param2.facedir ----@return ivec -function core.facedir_to_dir(facedir) end - ---[[ -WIPDOC -]] ----@nodiscard ----@param dir vector ----@return core.Param2.4dir -function core.dir_to_fourdir(dir) end - ---[[ -WIPDOC -]] ----@nodiscard ----@param fourdir core.Param2.4dir ----@return ivec -function core.fourdir_to_dir(fourdir) end - ---[[ -WIPDOC -]] ----@nodiscard ----@param dir vector ----@return core.Param2.wallmounted -function core.dir_to_wallmounted(dir) end - ---[[ -WIPDOC -]] ----@nodiscard ----@param wallmounted core.Param2.wallmounted ----@return ivec -function core.wallmounted_to_dir(wallmounted) end - ---[[ -WIPDOC -]] ----@nodiscard ----@param dir vector ----@return number -function core.dir_to_yaw(dir) end - ---[[ -WIPDOC -]] ----@nodiscard ----@param yaw number ----@return vec -function core.yaw_to_dir(yaw) end - ---[[ -WIPDOC -]] ----@nodiscard ----@param param2 core.Param2 ----@param paramtype2 core.NodeDef.paramtype2.color ----@return core.Param2 -function core.strip_param2_color(param2, paramtype2) end - ---[[ -WIPDOC -]] ----@nodiscard ----@param param2 core.Param2 ----@param paramtype2 string ----@return nil -function core.strip_param2_color(param2, paramtype2) end - ---[[ -WIPDOC -]] ----@nodiscard ----@param node core.Node.name|core.Node.set ----@param toolname core.Tool.name? ----@param tool core.ItemStack? ----@param digger core.ObjectRef? ----@param pos ivector? ----@return core.Item.stringfmt[] -function core.get_node_drops(node, toolname, tool, digger, pos) end - ---[[ core.get_craft_result() .. core.get_all_craft_recipes() split off into ./craft_result.lua ]]-- - ---[[ -* `core.handle_node_drops(pos, drops, digger)` - * `drops`: list of itemstrings - * Handles drops from nodes after digging: Default action is to put them - into digger's inventory. - * Can be overridden to get different functionality (e.g. dropping items on - ground) -]] ----@param pos ivector ----@param drops core.Item.stringfmt[] ----@param digger core.ObjectRef -function core.handle_node_drops(pos, drops, digger) end - ---[[ -* `core.itemstring_with_palette(item, palette_index)`: returns an item - string. - * Creates an item string which contains palette index information - for hardware colorization. You can use the returned string - as an output in a craft recipe. - * `item`: the item stack which becomes colored. Can be in string, - table and native form. - * `palette_index`: this index is added to the item stack -]] ----@nodiscard ----@param item core.Item ----@param palette_index integer ----@return core.Item.stringfmt -function core.itemstring_with_palette(item, palette_index) end - ---[[ -* `core.itemstring_with_color(item, colorstring)`: returns an item string - * Creates an item string which contains static color information - for hardware colorization. Use this method if you wish to colorize - an item that does not own a palette. You can use the returned string - as an output in a craft recipe. - * `item`: the item stack which becomes colored. Can be in string, - table and native form. - * `colorstring`: the new color of the item stack -]] ----@param item core.Item ----@param colorstring core.ColorString ----@return core.Item.stringfmt -function core.itemstring_with_color(item, colorstring) end \ No newline at end of file diff --git a/types/luanti_lsp_definitions/library/core/logging.lua b/types/luanti_lsp_definitions/library/core/logging.lua deleted file mode 100644 index 6e70c68b..00000000 --- a/types/luanti_lsp_definitions/library/core/logging.lua +++ /dev/null @@ -1,35 +0,0 @@ ----@meta _ --- DRAFT 1 DONE --- luanti/doc/lua_api.md: 'core' namespace reference > Logging - ---[[ -WIPDOC -]] ----@alias core.LoggingLevel ---- | "none" ---- | "error" ---- | "warning" ---- | "action" ---- | "info" ---- | "verbose" - ---[[ -Unofficial note: I made it deprecated because this should NOT be in any production code, and you should use something better tbh, like dbg.pp (from lars's dbg mod) -* Equivalent to `core.log(table.concat({...}, "\t"))` -]] ----@deprecated ----@param ... any -function core.debug(...) end - ---[[ -WIPDOC -]] ----@param loglevel core.LoggingLevel ----@param text string -function core.log(loglevel, text) end - ---[[ -WIPDOC -]] ----@param text string -function core.log(text) end \ No newline at end of file diff --git a/types/luanti_lsp_definitions/library/core/mapgen_environment.lua b/types/luanti_lsp_definitions/library/core/mapgen_environment.lua deleted file mode 100644 index 2cc70480..00000000 --- a/types/luanti_lsp_definitions/library/core/mapgen_environment.lua +++ /dev/null @@ -1,70 +0,0 @@ ----@meta _ --- DRAFT 1 DONE --- luanti/doc/lua_api.md: 'core' namespace reference > Mapgen environment - ---[[ -WIPDOC -]] ----@param path core.Path -function core.register_mapgen_script(path) end - ---[[ -WIPDOC -]] ----@class corelib.mapgen : corelib.async -local mapgen = { - get_biome_id = core.get_biome_id, - get_biome_name = core.get_biome_name, - get_heat = core.get_heat, - get_humidity = core.get_humidity, - get_biome_data = core.get_biome_data, - get_mapgen_object = core.get_mapgen_object, - ---@diagnostic disable-next-line: deprecated - get_mapgen_params = core.get_mapgen_params, - get_mapgen_edges = core.get_mapgen_edges, - get_mapgen_setting = core.get_mapgen_setting, - get_noiseparams = core.get_noiseparams, - get_decoration_id = core.get_decoration_id, --- TODO ... and more. WHY THE FUCK DON'T THEY JUST LIST THE GODDAMN FUNCTIONS - - -- TODO each needs a disclaimer that it operates only in the current chunk. separate this later - get_node = core.get_node, - set_node = core.set_node, - find_node_near = core.find_node_near, - find_nodes_in_area = core.find_nodes_in_area, - spawn_tree = core.spawn_tree, --- TODO ... and more. WHY THE FUCK DON'T THEY JUST LIST THE GODDAMN FUNCTIONS - - settings = core.settings, - --- TODO async registered_* has functions and userdata set to true instead - registered_items = core.registered_items, - registered_nodes = core.registered_nodes, - registered_tools = core.registered_tools, - registered_craftitems = core.registered_craftitems, - registered_aliases = core.registered_aliases, --- TODO ... and more. WHY THE FUCK DON'T THEY JUST LIST THE GODDAMN FUNCTIONS - registered_biomes = core.registered_biomes, - registered_ores = core.registered_ores, - registered_decorations = core.registered_decorations, -} - ---[[ -WIPDOC -]] ----@alias mapgen.fn.on_generated fun(vmanip:core.VoxelManip, minp:ivec, maxp:ivec, blockseed:integer) - ---[[ -WIPDOC -]] ----@param f mapgen.fn.on_generated -function mapgen.register_on_generated(f) end - ---[[ -WIPDOC -]] ----@nodiscard ----@param id string ----@param data core.Serializable ----@return true? -function mapgen.register_on_generated(id, data) end diff --git a/types/luanti_lsp_definitions/library/core/misc/get_group.lua b/types/luanti_lsp_definitions/library/core/misc/get_group.lua deleted file mode 100644 index f71dbd21..00000000 --- a/types/luanti_lsp_definitions/library/core/misc/get_group.lua +++ /dev/null @@ -1,145 +0,0 @@ ----@meta _ --- DRAFT 1 DONE --- luanti/doc/lua_api.md: 'core' namespace reference > Misc. - ---[[ -* `core.get_item_group(name, group)`: returns a rating - * Get rating of a group of an item. (`0` means: not in group) -]] ----@nodiscard ----@param name core.Item.name ----@param group string ----@return integer -function core.get_item_group(name, group) end - ---[[ -* `core.get_item_group(name, group)`: returns a rating - * Get rating of a group of an item. (`0` means: not in group) -]] ----@nodiscard ----@param name core.Item.name ----@param group "not_in_creative_inventory" ----@return integer -function core.get_item_group(name, group) end - ---[[ -* `core.get_item_group(name, group)`: returns a rating - * Get rating of a group of an item. (`0` means: not in group) -]] ----@nodiscard ----@param name core.Item.name ----@param group "attached_node" ----@return core.Groups.special.attached_node -function core.get_item_group(name, group) end - ---[[ -* `core.get_item_group(name, group)`: returns a rating - * Get rating of a group of an item. (`0` means: not in group) -]] ----@nodiscard ----@param name core.Item.name ----@param group "bouncy" ----@return integer -function core.get_item_group(name, group) end - ---[[ -* `core.get_item_group(name, group)`: returns a rating - * Get rating of a group of an item. (`0` means: not in group) -]] ----@nodiscard ----@param name core.Item.name ----@param group "connect_to_raillike" ----@return integer -function core.get_item_group(name, group) end - ---[[ -* `core.get_item_group(name, group)`: returns a rating - * Get rating of a group of an item. (`0` means: not in group) -]] ----@nodiscard ----@param name core.Item.name ----@param group "dig_immediate" ----@return core.Groups.special.dig_immediate -function core.get_item_group(name, group) end - ---[[ -* `core.get_item_group(name, group)`: returns a rating - * Get rating of a group of an item. (`0` means: not in group) -]] ----@nodiscard ----@param name core.Item.name ----@param group "disable_jump" ----@return core.Groups.special.disable_jump -function core.get_item_group(name, group) end - ---[[ -* `core.get_item_group(name, group)`: returns a rating - * Get rating of a group of an item. (`0` means: not in group) -]] ----@nodiscard ----@param name core.Item.name ----@param group "disable_descend" ----@return core.Groups.special.disable_descend -function core.get_item_group(name, group) end - ---[[ -* `core.get_item_group(name, group)`: returns a rating - * Get rating of a group of an item. (`0` means: not in group) -]] ----@nodiscard ----@param name core.Item.name ----@param group "fall_damage_add_percent" ----@return integer -function core.get_item_group(name, group) end - ---[[ -* `core.get_item_group(name, group)`: returns a rating - * Get rating of a group of an item. (`0` means: not in group) -]] ----@nodiscard ----@param name core.Item.name ----@param group "falling_node" ----@return core.Groups.special.falling_node -function core.get_item_group(name, group) end - ---[[ -* `core.get_item_group(name, group)`: returns a rating - * Get rating of a group of an item. (`0` means: not in group) -]] ----@nodiscard ----@param name core.Item.name ----@param group "float" ----@return core.Groups.special.float -function core.get_item_group(name, group) end - ---[[ -* `core.get_item_group(name, group)`: returns a rating - * Get rating of a group of an item. (`0` means: not in group) -]] ----@nodiscard ----@param name core.Item.name ----@param group "slippery" ----@return integer -function core.get_item_group(name, group) end - ---[[ -* `core.get_item_group(name, group)`: returns a rating - * Get rating of a group of an item. (`0` means: not in group) -]] ----@nodiscard ----@param name core.Item.name ----@param group "level" ----@return integer -function core.get_item_group(name, group) end - --- NOTE: core.get_node_group don't get any completion. this is intentional - ---[[ -* `core.get_node_group(name, group)`: returns a rating - * Deprecated: An alias for the former. -]] ----@deprecated ----@param name core.Item.name ----@param group string ----@return integer -function core.get_node_group(name, group) end \ No newline at end of file diff --git a/types/luanti_lsp_definitions/library/core/misc/insecure_environment.lua b/types/luanti_lsp_definitions/library/core/misc/insecure_environment.lua deleted file mode 100644 index a0a7691c..00000000 --- a/types/luanti_lsp_definitions/library/core/misc/insecure_environment.lua +++ /dev/null @@ -1,26 +0,0 @@ ----@meta _ --- DRAFT 1 DONE --- luanti/doc/lua_api.md: 'core' namespace reference > Misc. - ---[[ -WIPDOC -]] ----@class corelib.insecure -local insecure = {} - --- TODO inspect what's inside an insecure environment --- TODO research what's different in an insecure environment - ---[[ -* `core.request_insecure_environment()`: returns an environment containing - insecure functions if the calling mod has been listed as trusted in the - `secure.trusted_mods` setting or security is disabled, otherwise returns - `nil`. - * Only works at init time and must be called from the mod's main scope - (ie: the init.lua of the mod, not from another Lua file or within a function). - * **DO NOT ALLOW ANY OTHER MODS TO ACCESS THE RETURNED ENVIRONMENT, STORE - IT IN A LOCAL VARIABLE!** -]] ----@nodiscard ----@return corelib.insecure? -function core.request_insecure_environment() end \ No newline at end of file diff --git a/types/luanti_lsp_definitions/library/core/misc/misc.lua b/types/luanti_lsp_definitions/library/core/misc/misc.lua deleted file mode 100644 index a6cc63c6..00000000 --- a/types/luanti_lsp_definitions/library/core/misc/misc.lua +++ /dev/null @@ -1,596 +0,0 @@ ----@meta _ --- DRAFT 1 DONE --- luanti/doc/lua_api.md: 'core' namespace reference > Misc. - --- --------------------------- Player and Entities -------------------------- -- - ---[[ -* `core.get_connected_players()`: returns list of `ObjectRefs` -]] ----@nodiscard ----@return core.PlayerRef[] -function core.get_connected_players() end - ---[[ -* `core.is_player(obj)`: boolean, whether `obj` is a player -]] ----@nodiscard ----@param obj core.ObjectRef ----@return boolean -function core.is_player(obj) end - ---[[ -* `core.is_player(obj)`: boolean, whether `obj` is a player -]] ----@nodiscard ----@param obj core.PlayerRef ----@return true -function core.is_player(obj) end - ---[[ -* `core.player_exists(name)`: boolean, whether player exists - (regardless of online status) -]] ----@nodiscard ----@param name string ----@return boolean -function core.player_exists(name) end - ---[[ -* `core.is_valid_player_name(name)`: boolean, whether the given name - could be used as a player name (regardless of whether said player exists). -]] ----@nodiscard ----@param name string ----@return boolean -function core.is_valid_player_name(name) end - ---[[ -* `core.hud_replace_builtin(name, hud_definition)` - * Replaces definition of a builtin hud element - * `name`: `"breath"`, `"health"`, `"minimap"` or `"hotbar"` - * `hud_definition`: definition to replace builtin definition -]] ----@param name "breath"|"health"|"minimap"|"hotbar" ----@param hud_definition core.HUDDef -function core.hud_replace_builtin(name, hud_definition) end - --- -------------------------------------------------------------------------- -- - ---[[ -* `core.parse_relative_number(arg, relative_to)`: returns number or nil - * Helper function for chat commands. - * For parsing an optionally relative number of a chat command - parameter, using the chat command tilde notation. - * `arg`: String snippet containing the number; possible values: - * `""`: return as number - * `"~"`: return `relative_to + ` - * `"~"`: return `relative_to` - * Anything else will return `nil` - * `relative_to`: Number to which the `arg` number might be relative to - * Examples: - * `core.parse_relative_number("5", 10)` returns 5 - * `core.parse_relative_number("~5", 10)` returns 15 - * `core.parse_relative_number("~", 10)` returns 10 -]] ----@nodiscard ----@param arg string ----@param relative_to vector ----@return vec? -function core.parse_relative_number(arg, relative_to) end - ---[[ -* `core.send_join_message(player_name)` - * This function can be overridden by mods to change the join message. -]] ----@param player_name string -function core.send_join_message(player_name) end - ---[[ -* `core.send_leave_message(player_name, timed_out)` - * This function can be overridden by mods to change the leave message. -]] ----@param player_name string ----@param timed_out boolean -function core.send_leave_message(player_name, timed_out) end - --- ------------------------------ position hash ----------------------------- -- - ---[[ -WIPDOC -]] ----@alias core.PosHash integer - ---[[ -* `core.hash_node_position(pos)`: returns a 48-bit integer - * `pos`: table {x=number, y=number, z=number}, - * Gives a unique numeric encoding for a node position (16+16+16=48bit) - * Despite the name, this is not a hash function (so it doesn't mix or produce collisions). -]] ----@nodiscard ----@param pos ivector ----@return core.PosHash -function core.hash_node_position(pos) end - ---[[ -* `core.get_position_from_hash(hash)`: returns a position - * Inverse transform of `core.hash_node_position` -]] ----@nodiscard ----@param hash core.PosHash ----@return ivec -function core.get_position_from_hash(hash) end - --- --------------------------------- groups --------------------------------- -- - ---[[ core.get_item_group() .. core.get_node_group() split off into ./get_group.lua ]]-- - ---[[ -* `core.raillike_group(name)`: returns a rating - * Returns rating of the connect_to_raillike group corresponding to name - * If name is not yet the name of a connect_to_raillike group, a new group - id is created, with that name. -]] ----@nodiscard ----@param name core.Node.name ----@return integer -function core.raillike_group(name) end - --- ------------------------------- content ID ------------------------------- -- - ---[[ -* `core.get_content_id(name)`: returns an integer - * Gets the internal content ID of `name` -]] ----@nodiscard ----@param name core.Node.name ----@return core.ContentID -function core.get_content_id(name) end - ---[[ -* `core.get_name_from_content_id(content_id)`: returns a string - * Gets the name of the content with that content ID -]] ----@nodiscard ----@param content_id core.ContentID ----@return core.Node.name -function core.get_name_from_content_id(content_id) end - --- ------------------------------ serialization ----------------------------- -- - ---[[ -* `core.parse_json(string[, nullvalue, return_error])`: returns something - * Convert a string containing JSON data into the Lua equivalent - * `nullvalue`: returned in place of the JSON null; defaults to `nil` - * On success returns a table, a string, a number, a boolean or `nullvalue` - * On failure: If `return_error` is not set or is `false`, - outputs an error message and returns `nil`. - Otherwise returns `nil, err` (error message). - * Example: `parse_json("[10, {\"a\":false}]")`, returns `{10, {a = false}}` -]] ----@nodiscard ----@param string string ----@param nullvalue any? ----@param return_error false? ----@return core.Serializable? -function core.parse_json(string, nullvalue, return_error) end - ---[[ -* `core.parse_json(string[, nullvalue, return_error])`: returns something - * Convert a string containing JSON data into the Lua equivalent - * `nullvalue`: returned in place of the JSON null; defaults to `nil` - * On success returns a table, a string, a number, a boolean or `nullvalue` - * On failure: If `return_error` is not set or is `false`, - outputs an error message and returns `nil`. - Otherwise returns `nil, err` (error message). - * Example: `parse_json("[10, {\"a\":false}]")`, returns `{10, {a = false}}` -]] ----@nodiscard ----@param string string ----@param nullvalue any? ----@param return_error true ----@return core.Serializable?, string? -function core.parse_json(string, nullvalue, return_error) end - ---[[ -* `core.write_json(data[, styled])`: returns a string or `nil` and an error - message. - * Convert a Lua table into a JSON string - * styled: Outputs in a human-readable format if this is set, defaults to - false. - * Unserializable things like functions and userdata will cause an error. - * **Warning**: JSON is more strict than the Lua table format. - 1. You can only use strings and positive integers of at least one as - keys. - 2. You cannot mix string and integer keys. - This is due to the fact that JSON has two distinct array and object - values. - * Example: `write_json({10, {a = false}})`, - returns `'[10, {"a": false}]'` -]] ----@nodiscard ----@param data core.Serializable ----@param styled boolean? ----@return string -function core.write_json(data, styled) end - ---[[ -* `core.serialize(table)`: returns a string - * Convert a value into string form readable by `core.deserialize`. - * Supports tables, strings, numbers, booleans and `nil`. - * Support for dumping function bytecode is **deprecated**. - * Note: To obtain a human-readable representation of a value, use `dump` instead. - * Example: `serialize({foo="bar"})`, returns `'return { ["foo"] = "bar" }'` -]] ----@nodiscard ----@param table core.Serializable ----@return string -function core.serialize(table) end - ---[[ -* `core.deserialize(string[, safe])`: returns a table - * Convert a string returned by `core.serialize` into a table - * `string` is loaded in an empty sandbox environment. - * Will load functions if `safe` is `false` or omitted. - Although these functions cannot directly access the global environment, - they could bypass this restriction with maliciously crafted Lua bytecode - if mod security is disabled. - * Will silently strip functions embedded via calls to `loadstring` - (typically bytecode dumped by `core.serialize`) if `safe` is `true`. - You should not rely on this if possible. - * Example: `core.deserialize("return loadstring('')", true)` will be `nil`. - * This function should not be used on untrusted data, regardless of the - value of `safe`. It is fine to serialize then deserialize user-provided - data, but directly providing user input to deserialize is always unsafe. - * Example: `deserialize('return { ["foo"] = "bar" }')`, - returns `{foo="bar"}` - * Example: `deserialize('print("foo")')`, returns `nil` - (function call fails), returns - `error:[string "print("foo")"]:1: attempt to call global 'print' (a nil value)` -]] ----@nodiscard ----@param string string ----@param safe boolean? ----@return core.Serializable -function core.deserialize(string, safe) end - --- ------------------------------- compression ------------------------------ -- - ---[[ -* `core.compress(data, method, ...)`: returns `compressed_data` - * Compress a string of data. - * `method` is a string identifying the compression method to be used. - * Supported compression methods: - * Deflate (zlib): `"deflate"` - * Zstandard: `"zstd"` - * `...` indicates method-specific arguments. Currently defined arguments - are: - * Deflate: `level` - Compression level, `0`-`9` or `nil`. - * Zstandard: `level` - Compression level. Integer or `nil`. Default `3`. - Note any supported Zstandard compression level could be used here, - but these are subject to change between Zstandard versions. -]] ----@nodiscard ----@param data string ----@param method "deflate" ----@param level 0|1|2|3|4|5|6|7|8|9? ----@return string -function core.compress(data, method, level) end - ---[[ -* `core.compress(data, method, ...)`: returns `compressed_data` - * Compress a string of data. - * `method` is a string identifying the compression method to be used. - * Supported compression methods: - * Deflate (zlib): `"deflate"` - * Zstandard: `"zstd"` - * `...` indicates method-specific arguments. Currently defined arguments - are: - * Deflate: `level` - Compression level, `0`-`9` or `nil`. - * Zstandard: `level` - Compression level. Integer or `nil`. Default `3`. - Note any supported Zstandard compression level could be used here, - but these are subject to change between Zstandard versions. -]] ----@nodiscard ----@param data string ----@param method "zstd" ----@param level integer? ----@return string -function core.compress(data, method, level) end - ---[[ -* `core.decompress(compressed_data, method, ...)`: returns data - * Decompress a string of data using the algorithm specified by `method`. - * See documentation on `core.compress()` for supported compression - methods. - * `...` indicates method-specific arguments. Currently, no methods use this -]] ----@nodiscard ----@param compressed_data string ----@param method "zstd"|"deflate" ----@return string -function core.decompress(compressed_data, method) end - --- -------------------------------------------------------------------------- -- - ---[[ -* `core.rgba(red, green, blue[, alpha])`: returns a string - * Each argument is an 8 Bit unsigned integer - * Returns the ColorString from rgb or rgba values - * Example: `core.rgba(10, 20, 30, 40)`, returns `"#0A141E28"` -]] ----@nodiscard ----@param red integer ----@param green integer ----@param blue integer ----@param alpha integer? ----@return core.ColorString -function core.rgba(red, green, blue, alpha) end - --- -------------------------------- encoding -------------------------------- -- - ---[[ -* `core.encode_base64(string)`: returns string encoded in base64 - * Encodes a string in base64. -]] ----@param string string ----@return string -function core.encode_base64(string) end - ---[[ -* `core.decode_base64(string)`: returns string or nil on failure - * Padding characters are only supported starting at version 5.4.0, where - 5.5.0 and newer perform proper checks. - * Decodes a string encoded in base64. -]] ----@param string string ----@return string -function core.decode_base64(string) end - --- ------------------------------- protection ------------------------------- -- - ---[[ -Unofficial note: Do NOT localize it, i know you want to, just don't -* `core.is_protected(pos, name)`: returns boolean - * Returning `true` restricts the player `name` from modifying (i.e. digging, - placing) the node at position `pos`. - * `name` will be `""` for non-players or unknown players. - * This function should be overridden by protection mods. It is highly - recommended to grant access to players with the `protection_bypass` privilege. - * Cache and call the old version of this function if the position is - not protected by the mod. This will allow using multiple protection mods. - * Example: - ```lua - local old_is_protected = core.is_protected - function core.is_protected(pos, name) - if mymod:position_protected_from(pos, name) then - return true - end - return old_is_protected(pos, name) - end - ``` -]] ----@nodiscard ----@param pos ivector ----@param name string ----@return boolean -function core.is_protected(pos, name) end - ---[[ -* `core.record_protection_violation(pos, name)` - * This function calls functions registered with - `core.register_on_protection_violation`. -]] ----@param pos ivector ----@param name string -function core.record_protection_violation(pos, name) end - ---[[ -* `core.is_creative_enabled(name)`: returns boolean - * Returning `true` means that Creative Mode is enabled for player `name`. - * `name` will be `""` for non-players or if the player is unknown. - * This function should be overridden by Creative Mode-related mods to - implement a per-player Creative Mode. - * By default, this function returns `true` if the setting - `creative_mode` is `true` and `false` otherwise. -]] ----@nodiscard ----@param name string ----@return boolean -function core.is_creative_enabled(name) end - ---[[ -* `core.is_area_protected(pos1, pos2, player_name, interval)` - * Returns the position of the first node that `player_name` may not modify - in the specified cuboid between `pos1` and `pos2`. - * Returns `false` if no protections were found. - * Applies `is_protected()` to a 3D lattice of points in the defined volume. - The points are spaced evenly throughout the volume and have a spacing - similar to, but no larger than, `interval`. - * All corners and edges of the defined volume are checked. - * `interval` defaults to 4. - * `interval` should be carefully chosen and maximized to avoid an excessive - number of points being checked. - * Like `core.is_protected`, this function may be extended or - overwritten by mods to provide a faster implementation to check the - cuboid for intersections. -]] ----@nodiscard ----@param pos1 ivector ----@param pos2 ivector ----@param player_name string ----@param interval integer ----@return boolean -function core.is_area_protected(pos1, pos2, player_name, interval) end - ---[[ -WIPDOC -]] ----@class core.RotateAndPlace.orient_flags ---[[ -WIPDOC -]] ----@field invert_wall boolean? ---[[ -WIPDOC -]] ----@field force_wall boolean? ---[[ -WIPDOC -]] ----@field force_ceiling boolean? ---[[ -WIPDOC -]] ----@field force_floor boolean? ---[[ -WIPDOC -]] ----@field force_facedir boolean? - ---[[ -* `core.rotate_and_place(itemstack, placer, pointed_thing[, infinitestacks, - orient_flags, prevent_after_place])` - * Attempt to predict the desired orientation of the facedir-capable node - defined by `itemstack`, and place it accordingly (on-wall, on the floor, - or hanging from the ceiling). - * `infinitestacks`: if `true`, the itemstack is not changed. Otherwise the - stacks are handled normally. - * `orient_flags`: Optional table containing extra tweaks to the placement code: - * `invert_wall`: if `true`, place wall-orientation on the ground and - ground-orientation on the wall. - * `force_wall`: if `true`, always place the node in wall orientation. - * `force_ceiling`: if `true`, always place on the ceiling. - * `force_floor`: if `true`, always place the node on the floor. - * `force_facedir`: if `true`, forcefully reset the facedir to north - when placing on the floor or ceiling. - * The first four options are mutually-exclusive; the last in the list - takes precedence over the first. - * `prevent_after_place` is directly passed to `core.item_place_node` - * Returns the new itemstack after placement -]] ----@nodiscard ----@param itemstack core.ItemStack ----@param placer core.ObjectRef ----@param pointed_thing core.PointedThing ----@param infinitestacks boolean? ----@param orient_flags core.RotateAndPlace.orient_flags? ----@param prevent_after_place boolean? ----@return core.ItemStack -function core.rotate_and_place(itemstack, placer, pointed_thing, infinitestacks, orient_flags, prevent_after_place) end - - ---[[ -* `core.rotate_node(itemstack, placer, pointed_thing)` - * calls `rotate_and_place()` with `infinitestacks` set according to the state - of the creative mode setting, checks for "sneak" to set the `invert_wall` - parameter and `prevent_after_place` set to `true` -]] ----@param itemstack core.ItemStack ----@param placer core.ObjectRef ----@param pointed_thing core.PointedThing -function core.rotate_node(itemstack, placer, pointed_thing) end - - ---[[ -* `core.calculate_knockback(player, hitter, time_from_last_punch, - tool_capabilities, dir, distance, damage)` - * Returns the amount of knockback applied on the punched player. - * Arguments are equivalent to `register_on_punchplayer`, except the following: - * `distance`: distance between puncher and punched player - * This function can be overridden by mods that wish to modify this behavior. - * You may want to cache and call the old function to allow multiple mods to - change knockback behavior. -]] ----@nodiscard ----@param player core.PlayerRef ----@param hitter core.ObjectRef ----@param time_from_last_punch number ----@param tool_capabilities core.ToolCapabilities ----@param dir vector ----@param distance number ----@param damage integer ----@return number -function core.calculate_knockback(player, hitter, time_from_last_punch, tool_capabilities, dir, distance, damage) end - --- ----------------------------- mapblock status ---------------------------- -- - ---[=[ -* `core.forceload_block(pos[, transient[, limit]])` - * forceloads the position `pos`. - * this means that the mapblock containing `pos` will always be kept in the - `"active"` state, regardless of nearby players or server settings. - * returns `true` if area could be forceloaded - * If `transient` is `false` or absent, the forceload will be persistent - (saved between server runs). If `true`, the forceload will be transient - (not saved between server runs). - * `limit` is an optional limit on the number of blocks that can be - forceloaded at once. If `limit` is negative, there is no limit. If it is - absent, the limit is the value of the setting `"max_forceloaded_blocks"`. - If the call would put the number of blocks over the limit, the call fails. -]=] ----@nodiscard ----@param pos ivector ----@param transient boolean? ----@param limit number? ----@return boolean -function core.forceload_block(pos, transient, limit) end - ---[[ -* `core.forceload_free_block(pos[, transient])` - * stops forceloading the position `pos` - * If `transient` is `false` or absent, frees a persistent forceload. - If `true`, frees a transient forceload. -]] ----@param pos ivector ----@param transient boolean? -function core.forceload_free_block(pos, transient) end - ---[[ -* `core.compare_block_status(pos, condition)` - * Checks whether the mapblock at position `pos` is in the wanted condition. - * `condition` may be one of the following values: - * `"unknown"`: not in memory - * `"emerging"`: in the queue for loading from disk or generating - * `"loaded"`: in memory but inactive (no ABMs are executed) - * `"active"`: in memory and active - * Other values are reserved for future functionality extensions - * Return value, the comparison status: - * `false`: Mapblock does not fulfill the wanted condition - * `true`: Mapblock meets the requirement - * `nil`: Unsupported `condition` value -]] ----@nodiscard ----@param pos ivector ----@param condition "unknown"|"emerging"|"loaded"|"active" ----@return boolean? -function core.compare_block_status(pos, condition) end - --- -------------------------------------------------------------------------- -- - ---[[ core.request_insecure_environment() split off into ./insecure_environment.lua ]]-- - ---[[ -* `core.global_exists(name)` - * Checks if a global variable has been set, without triggering a warning. -]] ----@nodiscard ----@param name string ----@return boolean -function core.global_exists(name) end - ---[[ -* `core.register_portable_metatable(name, mt)`: - * Register a metatable that should be preserved when Lua data is transferred - between environments (via IPC or `handle_async`). - * `name` is a string that identifies the metatable. It is recommended to - follow the `modname:name` convention for this identifier. - * `mt` is the metatable to register. - * Note that the same metatable can be registered under multiple names, - but multiple metatables must not be registered under the same name. - * You must register the metatable in both the main environment - and the async environment for this mechanism to work. -]] ----@param name string ----@param mt table -function core.register_portable_metatable(name, mt) end \ No newline at end of file diff --git a/types/luanti_lsp_definitions/library/core/mod_channels.lua b/types/luanti_lsp_definitions/library/core/mod_channels.lua deleted file mode 100644 index d2998b5c..00000000 --- a/types/luanti_lsp_definitions/library/core/mod_channels.lua +++ /dev/null @@ -1,11 +0,0 @@ ----@meta _ --- DRAFT 1 DONE --- luanti/doc/lua_api.md: 'core' namespace reference > Mod channels - ---[[ -WIPDOC -]] ----@nodiscard ----@param channel_name string ----@return core.ModChannel -function core.mod_channel_join(channel_name) end \ No newline at end of file diff --git a/types/luanti_lsp_definitions/library/core/particles.lua b/types/luanti_lsp_definitions/library/core/particles.lua deleted file mode 100644 index 49d6fdeb..00000000 --- a/types/luanti_lsp_definitions/library/core/particles.lua +++ /dev/null @@ -1,72 +0,0 @@ ----@meta _ --- DRAFT 1 DONE --- luanti/doc/lua_api.md: 'core' namespace reference > Particles - ---[[ -* `core.add_particle(particle definition)` - * Spawn a single particle - * Deprecated: `core.add_particle(pos, velocity, acceleration, - expirationtime, size, collisiondetection, texture, playername)` -]] ----@deprecated ----@param pos vector ----@param velocity vector ----@param acceleration vector ----@param expirationtime number ----@param size number ----@param collisiondetection boolean ----@param texture core.Texture ----@param playername string -function core.add_particle(pos, velocity, acceleration, - expirationtime, size, collisiondetection, texture, playername) end - ---[[ -Unofficial note: Prefer not doing 100 000 particles in a single globalstep -Because that will make the network scream, with no way to debug it -Instead, invest time into particlespawners, invest time into creating an issue on luanti github, invest time into creating a client side mod -]] ----@param particle_def core.ParticleDef.regular -function core.add_particle(particle_def) end - ---[[ -WIPDOC -]] ----@deprecated ----@nodiscard ----@param amount integer ----@param time number ----@param minpos vector ----@param maxpos vector ----@param minvel vector ----@param maxvel vector ----@param minacc vector ----@param maxacc vector ----@param minexptime number ----@param maxexptime number ----@param minsize number ----@param maxsize number ----@param collisiondetection boolean ----@param texture core.Texture ----@param playername string ----@return core.ParticleSpawnerID -function core.add_particlespawner(amount, time, minpos, maxpos, minvel, maxvel, minacc, maxacc, minexptime, maxexptime, minsize, maxsize, collisiondetection, texture, playername) end ---[[ -* Add a `ParticleSpawner`, an object that spawns an amount of particles - over `time` seconds. -* Returns an `id`, and -1 if adding didn't succeed -]] ----@nodiscard ----@param particlespawner_def core.ParticleSpawnerDef ----@return core.ParticleSpawnerID -function core.add_particlespawner(particlespawner_def) end - ---[[ -* `core.delete_particlespawner(id, player)` - * Delete `ParticleSpawner` with `id` (return value from - `core.add_particlespawner`). - * If playername is specified, only deletes on the player's client, - otherwise on all clients. -]] ----@param id core.ParticleSpawnerID ----@param player string? -function core.delete_particlespawner(id, player) end \ No newline at end of file diff --git a/types/luanti_lsp_definitions/library/core/register/cheat.lua b/types/luanti_lsp_definitions/library/core/register/cheat.lua deleted file mode 100644 index 7bb2e03b..00000000 --- a/types/luanti_lsp_definitions/library/core/register/cheat.lua +++ /dev/null @@ -1,48 +0,0 @@ ----@meta _ --- DRAFT 1 DONE --- luanti/doc/lua_api.md: 'core' namespace reference > Global callback registration functions - --- ---------------------------------- Cheat --------------------------------- -- - ---[[ -WIPDOC -]] ----@alias core.Cheat.type ---- | "moved_too_fast" ---- | "interacted_too_far" ---- | "interacted_with_self" ---- | "interacted_while_dead" ---- | "finished_unknown_dig" ---- | "dug_unbreakable" ---- | "dug_too_fast" - ---[[ -WIPDOC -]] ----@class core.Cheat ---[[ -WIPDOC -]] ----@field type core.Cheat.type - --- ---------------------------- core.* functions ---------------------------- -- - ---[[ -WIPDOC -]] ----@alias core.fn.on_cheat fun(ObjectRef:core.PlayerRef, cheat:core.Cheat) - ---[[ -* `core.register_on_cheat(function(ObjectRef, cheat))` - * Called when a player cheats - * `cheat`: `{type=}`, where `` is one of: - * `moved_too_fast` - * `interacted_too_far` - * `interacted_with_self` - * `interacted_while_dead` - * `finished_unknown_dig` - * `dug_unbreakable` - * `dug_too_fast` -]] ----@param f core.fn.on_cheat -function core.register_on_cheat(f) end \ No newline at end of file diff --git a/types/luanti_lsp_definitions/library/core/register/environment.lua b/types/luanti_lsp_definitions/library/core/register/environment.lua deleted file mode 100644 index c324ea79..00000000 --- a/types/luanti_lsp_definitions/library/core/register/environment.lua +++ /dev/null @@ -1,150 +0,0 @@ ----@meta _ --- DRAFT 1 DONE --- luanti/doc/lua_api.md: 'core' namespace reference > Registration functions > Environment - ---[[ -* Note: you must pass a clean table that hasn't already been used for - another registration to this function, as it will be modified. -]] ----@param name string ----@param node_def core.NodeDef -function core.register_node(name, node_def) end - ---[[ -* Note: you must pass a clean table that hasn't already been used for - another registration to this function, as it will be modified. -]] ----@param name string ----@param itemdef core.ItemDef -function core.register_craftitem(name, itemdef) end - ---[[ -* Note: you must pass a clean table that hasn't already been used for - another registration to this function, as it will be modified. -]] ----@param name string ----@param itemdef core.ItemDef -function core.register_tool(name, itemdef) end - ---[[ -* `core.override_item(name, redefinition, del_fields)` - * `redefinition` is a table of fields `[name] = new_value`, - overwriting fields of or adding fields to the existing definition. - * `del_fields` is a list of field names to be set - to `nil` ("deleted from") the original definition. - * Overrides fields of an item registered with register_node/tool/craftitem. - * Note: Item must already be defined. - * Example: `core.override_item("default:mese", - {light_source=core.LIGHT_MAX}, {"sounds"})`: - Overwrites the `light_source` field, - removes the sounds from the definition of the mese block. -]] ----@param name string ----@param redefinition core.ItemDef|core.NodeDef ----@param del_fields core.ItemDef.keys|core.NodeDef.keys -function core.override_item(name, redefinition, del_fields) end - ---[[ -WIPDOC -]] ----@param name string -function core.unregister_item(name) end - ---[[ -WIPDOC -]] ----@param name string ----@param entity_def core.EntityDef -function core.register_entity(name, entity_def) end - ---[[ -WIPDOC -]] ----@param abmdef core.ABMDef -function core.register_abm(abmdef) end - ---[[ -WIPDOC -]] ----@param lbmdef core.LBMDef -function core.register_lbm(lbmdef) end - ---[[ -Also use this to set the 'mapgen aliases' needed in a game for the code mapgens. -]] ----@param alias core.Alias ----@param original_name core.Item.name -function core.register_alias(alias, original_name) end - ---[[ -WIPDOC -]] ----@param alias core.Alias ----@param original_name core.Item.name -function core.register_alias_force(alias, original_name) end - ---[[ -WIPDOC -]] ----@nodiscard ----@param def core.OreDef ----@return core.OreID? -function core.register_ore(def) end - ---[[ -WIPDOC -]] ----@nodiscard ----@param biome_def core.BiomeDef ----@return core.BiomeID? -function core.register_biome(biome_def) end - ---[[ -* Unregisters the biome from the engine, and deletes the entry with key - `name` from `core.registered_biomes`. -* Warning: This alters the biome to biome ID correspondences, so any - decorations or ores using the 'biomes' field must afterwards be cleared - and re-registered. -]] ----@param name string -function core.unregister_biome(name) end - ---[[ -WIPDOC -]] ----@nodiscard ----@param decoration_def core.DecorationDef ----@return core.DecorationID? -function core.register_decoration(decoration_def) end - ---[[ -WIPDOC -]] ----@nodiscard ----@param schem_def core.SchematicDef ----@return core.SchematicID -function core.register_schematic(schem_def) end - ---[[ -* `core.clear_registered_biomes()` - * Clears all biomes currently registered. - * Warning: Clearing and re-registering biomes alters the biome to biome ID - correspondences, so any decorations or ores using the 'biomes' field must - afterwards be cleared and re-registered. -]] -function core.clear_registered_biomes() end - ---[[ -WIPDOC -]] -function core.clear_registered_decorations() end - ---[[ -WIPDOC -]] -function core.clear_registered_ores() end - ---[[ -WIPDOC -]] -function core.clear_registered_schematics() end diff --git a/types/luanti_lsp_definitions/library/core/register/gameplay.lua b/types/luanti_lsp_definitions/library/core/register/gameplay.lua deleted file mode 100644 index 10998425..00000000 --- a/types/luanti_lsp_definitions/library/core/register/gameplay.lua +++ /dev/null @@ -1,49 +0,0 @@ ----@meta _ --- DRAFT 1 DONE --- luanti/doc/lua_api.md: 'core' namespace reference > Registration functions > Gameplay - ---[[ -WIPDOC -]] ----@param craft_recipe core.CraftingRecipeDef -function core.register_craft(craft_recipe) end - ---[[ -WIPDOC -]] ----@param recipe core.CraftingRecipeDef.clear? -function core.clear_craft(recipe) end - ---[[ -WIPDOC -]] ----@param name string ----@param chatcommand_def core.ChatCommandDef -function core.register_chatcommand(name, chatcommand_def) end - ---[[ -WIPDOC -]] ----@param name string ----@param redef core.ChatCommandDef.override -function core.override_chatcommand(name, redef) end - ---[[ -WIPDOC -]] ----@param name string -function core.unregister_chatcommand(name) end - ---[[ -WIPDOC -]] ----@param name string ----@param def core.PrivilegeDef -function core.register_privilege(name, def) end - ---[[ -* Registers an auth handler that overrides the builtin one. -* This function can be called by a single mod once only. -]] ----@param auth_handler_def core.AuthenticationHandlerDef -function core.register_authentication_handler(auth_handler_def) end \ No newline at end of file diff --git a/types/luanti_lsp_definitions/library/core/register/global_callback.lua b/types/luanti_lsp_definitions/library/core/register/global_callback.lua deleted file mode 100644 index 1cf57444..00000000 --- a/types/luanti_lsp_definitions/library/core/register/global_callback.lua +++ /dev/null @@ -1,451 +0,0 @@ ----@meta _ --- DRAFT 1 DONE --- luanti/doc/lua_api.md: 'core' namespace reference > Global callback registration functions - --- ---------------------- server step, start, shutdown ---------------------- -- - ---[[ -WIPDOC -]] ----@alias core.fn.globalstep fun(dtime:number) - ---[[ -* Called every server step, usually interval of 0.1s. -* `dtime` is the time since last execution in seconds. -]] ----@param f core.fn.globalstep -function core.register_globalstep(f) end - ---[[ -WIPDOC -]] ----@alias core.fn.on_mods_loaded fun() - ---[[ -* Called after all mods have finished loading and before the media is cached - or aliases are handled. -]] ----@param f core.fn.on_mods_loaded -function core.register_on_mods_loaded(f) end - ---[[ -WIPDOC -]] ----@alias core.fn.on_shutdown fun() - ---[[ -* `core.register_on_shutdown(function())` - * Called during server shutdown before players are kicked. - * **Warning**: If the server terminates abnormally (i.e. crashes), the - registered callbacks will likely **not run**. Data should be saved at - semi-frequent intervals as well as on server shutdown. -]] ----@param f core.fn.on_shutdown -function core.register_on_shutdown(f) end - --- ------------------------------- node events ------------------------------ -- - ---[[ -WIPDOC -]] ----@alias core.fn.on_placenode fun(pos:ivec, newnode:core.Node.get, placer:core.ObjectRef?, oldnode:core.Node.get, itemstack:core.ItemStack, pointed_thing:core.PointedThing):boolean? - ---[[ -* `core.register_on_placenode(function(pos, newnode, placer, oldnode, itemstack, pointed_thing))` - * Called after a node has been placed. - * If `true` is returned no item is taken from `itemstack` - * `placer` may be any valid ObjectRef or nil. - * **Not recommended**; use `on_construct` or `after_place_node` in node - definition whenever possible. -]] ----@param f core.fn.on_placenode -function core.register_on_placenode(f) end - ---[[ -WIPDOC -]] ----@alias core.fn.on_dignode fun(pos:ivec, oldnode:core.Node.get, digger:core.ObjectRef?) - ---[[ -* `core.register_on_dignode(function(pos, oldnode, digger))` - * Called after a node has been dug. - * **Not recommended**; Use `on_destruct` or `after_dig_node` in node - definition whenever possible. -]] ----@param f core.fn.on_dignode ----@return nil -function core.register_on_dignode(f) end - ---[[ -WIPDOC -]] ----@alias core.fn.on_punchnode fun(pos:ivec, node:core.Node.get, puncher:core.ObjectRef?, pointed_thing:core.PointedThing) - ---[[ -* `core.register_on_punchnode(function(pos, node, puncher, pointed_thing))` - * Called after a node is punched -]] ----@param f core.fn.on_punchnode ----@return nil -function core.register_on_punchnode(f) end - ---[[ -WIPDOC -]] ----@alias core.fn.on_generated fun(minp:ivec, maxp:ivec, blockseed:integer) - ---[[ -* `core.register_on_generated(function(minp, maxp, blockseed))` - * Called after a piece of world between `minp` and `maxp` has been - generated and written into the map. - * **Avoid using this** whenever possible. As with other callbacks this blocks - the main thread and is prone to introduce noticeable latency/lag. - Consider [Mapgen environment](#mapgen-environment) as an alternative. -]] ----@deprecated ----@param f core.fn.on_generated -function core.register_on_generated(f) end - --- ------------------------------ player events ----------------------------- -- - ---[[ -WIPDOC -]] ----@alias core.fn.on_newplayer fun(ObjectRef:core.PlayerRef) - ---[[ -* `core.register_on_newplayer(function(player))` - * Called when a new player enters the world for the first time - * `player`: ObjectRef -]] ----@param f core.fn.on_newplayer -function core.register_on_newplayer(f) end - ---[[ -WIPDOC -]] ----@alias core.fn.on_punchplayer fun(player:core.PlayerRef, hitter:core.PlayerRef?, time_from_last_punch:number?, tool_capabilities:core.ToolCapabilities?, dir:vec, damage: integer):boolean? - ---[[ -* `core.register_on_punchplayer(function(player, hitter, time_from_last_punch, tool_capabilities, dir, damage))` - * Called when a player is punched - * Note: This callback is invoked even if the punched player is dead. - * `player`: ObjectRef - Player that was punched - * `hitter`: ObjectRef - Player that hit. Can be nil. - * `time_from_last_punch`: Meant for disallowing spamming of clicks - (can be nil). - * `tool_capabilities`: Capability table of used item (can be nil) - * `dir`: Unit vector of direction of punch. Always defined. Points from - the puncher to the punched. - * `damage`: Number that represents the damage calculated by the engine - * should return `true` to prevent the default damage mechanism -]] ----@param f core.fn.on_punchplayer -function core.register_on_punchplayer(f) end - ---[[ -WIPDOC -]] ----@alias core.fn.on_rightclickplayer fun(player:core.PlayerRef, clicker:core.PlayerRef) - ---[[ -* `core.register_on_rightclickplayer(function(player, clicker))` - * Called when the 'place/use' key was used while pointing a player - (not necessarily an actual rightclick) - * `player`: ObjectRef - Player that is acted upon - * `clicker`: ObjectRef - Object that acted upon `player`, may or may not be a player -]] ----@param f core.fn.on_rightclickplayer -function core.register_on_rightclickplayer(f) end - ---[[ core.register_on_player_hpchange() .. core.register_on_dieplayer() split off into ./hpchange.lua ]]-- - ---[[ -WIPDOC -]] ----@alias core.fn.on_respawnplayer fun(ObjectRef:core.PlayerRef):boolean? - ---[[ -WIPDOC -]] ----@param f core.fn.on_respawnplayer -function core.register_on_respawnplayer(f) end - ---[[ -WIPDOC -]] ----@alias core.fn.on_prejoinplayer fun(name:string, ip:string):string? - ---[[ -WIPDOC -]] ----@param f core.fn.on_prejoinplayer -function core.register_on_prejoinplayer(f) end - ---[[ -WIPDOC -]] ----@alias core.fn.on_joinplayer fun(ObjectRef:core.PlayerRef, last_login:integer) - ---[[ -WIPDOC -]] ----@param f core.fn.on_joinplayer -function core.register_on_joinplayer(f) end - ---[[ -WIPDOC -]] ----@alias core.fn.on_leaveplayer fun(ObjectRef:core.PlayerRef, timed_out:boolean) - ---[[ -WIPDOC -]] ----@param f core.fn.on_leaveplayer -function core.register_on_leaveplayer(f) end - ---[[ -WIPDOC -]] ----@alias core.fn.on_authplayer fun(name:string, ip:string, is_success:boolean) - ---[[ -* `core.register_on_authplayer(function(name, ip, is_success))` - * Called when a client attempts to log into an account. - * `name`: The name of the account being authenticated. - * `ip`: The IP address of the client - * `is_success`: Whether the client was successfully authenticated - * For newly registered accounts, `is_success` will always be true -]] ----@param f core.fn.on_authplayer -function core.register_on_authplayer(f) end - ---[[ -WIPDOC -]] ----@alias core.fn.on_auth_fail fun(name:string, ip:string) - ---[[ -* Deprecated: use `core.register_on_authplayer(name, ip, is_success)` instead. -]] ----@deprecated ----@param f core.fn.on_auth_fail -function core.register_on_auth_fail(f) end - ---[[ core.register_on_cheat() split into ./cheat.lua ]]-- - ---[[ core.register_playerevent() split into ./playerevent.lua ]]-- - --- ---------------------------------- chat ---------------------------------- -- - ---[[ -WIPDOC -]] ----@alias core.fn.on_chat_message fun(name:string, message:string):boolean? - ---[[ -* `core.register_on_chat_message(function(name, message))` - * Called always when a player says something - * Return `true` to mark the message as handled, which means that it will - not be sent to other players. -]] ----@param f core.fn.on_chat_message -function core.register_on_chat_message(f) end - ---[[ -WIPDOC -]] ----@alias core.fn.on_chatcommand fun(name:string, command:string, params:string) - ---[[ -* `core.register_on_chatcommand(function(name, command, params))` - * Called always when a chatcommand is triggered, before `core.registered_chatcommands` - is checked to see if the command exists, but after the input is parsed. - * Return `true` to mark the command as handled, which means that the default - handlers will be prevented. -]] ----@param f core.fn.on_chatcommand -function core.register_on_chatcommand(f) end - --- -------------------------------- formspec -------------------------------- -- - ---[[ core.register_on_player_receive_fields() split off into ./player_receive_fields.lua ]]-- - ---[[ -WIPDOC -]] ----@alias core.fn.on_craft fun(itemstack:core.ItemStack, player:core.PlayerRef, old_crafting_grid:core.Item.name[][], craft_inv:core.InvRef):core.ItemStack? - ---[[ -* `core.register_on_craft(function(itemstack, player, old_craft_grid, craft_inv))` - * Called when `player` crafts something - * `itemstack` is the output - * `old_craft_grid` contains the recipe (Note: the one in the inventory is - cleared). - * `craft_inv` is the inventory with the crafting grid - * Return either an `ItemStack`, to replace the output, or `nil`, to not - modify it. -]] ----@param f core.fn.on_craft -function core.register_on_craft(f) end - ---[[ -WIPDOC -]] ----@alias core.fn.craft_predict fun(itemstack:core.ItemStack, player:core.PlayerRef, old_crafting_grid:core.Item.name[][], craft_inv:core.InvRef):core.ItemStack? - ---[[ -* `core.register_craft_predict(function(itemstack, player, old_craft_grid, craft_inv))` - * The same as before, except that it is called before the player crafts, to - make craft prediction, and it should not change anything. -]] ----@param f core.fn.craft_predict -function core.register_craft_predict(f) end - ---[[ core.register_allow_player_inventory_action() .. core.register_on_player_inventory_action() split off into ./inventory_action.lua ]]-- - --- ------------------------------- protection ------------------------------- -- - ---[[ -WIPDOC -]] ----@alias core.fn.on_protection_violation fun(pos:ivec, name:string) - ---[[ -* `core.register_on_protection_violation(function(pos, name))` - * Called by `builtin` and mods when a player violates protection at a - position (eg, digs a node or punches a protected entity). - * The registered functions can be called using - `core.record_protection_violation`. - * The provided function should check that the position is protected by the - mod calling this function before it prints a message, if it does, to - allow for multiple protection mods. -]] ----@param f core.fn.on_protection_violation -function core.register_on_protection_violation(f) end - --- ------------------------------- item events ------------------------------ -- - ---[[ -WIPDOC -]] ----@alias core.fn.on_item_eat fun(hp_change:integer, replace_with_item:core.ItemStack?, itemstack:core.ItemStack, user:core.PlayerRef, pointed_thing:core.PointedThing):core.ItemStack? - ---[[ -* `core.register_on_item_eat(function(hp_change, replace_with_item, itemstack, user, pointed_thing))` - * Called when an item is eaten, by `core.item_eat` - * Return `itemstack` to cancel the default item eat response (i.e.: hp increase). -]] ----@param f core.fn.on_item_eat -function core.register_on_item_eat(f) end - ---[[ -WIPDOC -]] ----@alias core.fn.on_item_pickup fun(itemstack:core.ItemStack, picker:core.PlayerRef?, pointed_thing:core.PointedThing?, time_from_last_punch:number?, direction:vec?, damage:integer?):core.ItemStack? - ---[[ -* `core.register_on_item_pickup(function(itemstack, picker, pointed_thing, time_from_last_punch, ...))` - * Called by `core.item_pickup` before an item is picked up. - * Function is added to `core.registered_on_item_pickups`. - * Oldest functions are called first. - * Parameters are the same as in the `on_pickup` callback. - * Return an itemstack to cancel the default item pick-up response (i.e.: adding - the item into inventory). -]] ----@param f core.ItemDef.on_pickup -function core.register_on_item_pickup(f) end - --- ------------------------------- privileges ------------------------------- -- - ---[[ -WIPDOC -]] ----@alias core.fn.on_priv_grant fun(name:string, granter:core.PlayerRef?, priv:core.PrivilegeSet.keys) - ---[[ -* `core.register_on_priv_grant(function(name, granter, priv))` - * Called when `granter` grants the priv `priv` to `name`. - * Note that the callback will be called twice if it's done by a player, - once with granter being the player name, and again with granter being nil. -]] ----@param f core.fn.on_priv_grant -function core.register_on_priv_grant(f) end - ---[[ -WIPDOC -]] ----@alias core.fn.on_priv_revoke fun(name:string, revoker:core.PlayerRef?, priv:core.PrivilegeSet.keys) - ---[[ -* `core.register_on_priv_revoke(function(name, revoker, priv))` - * Called when `revoker` revokes the priv `priv` from `name`. - * Note that the callback will be called twice if it's done by a player, - once with revoker being the player name, and again with revoker being nil. -]] ----@param f core.fn.on_priv_revoke -function core.register_on_priv_revoke(f) end - --- -------------------------------------------------------------------------- -- - ---[[ -WIPDOC -]] ----@alias core.fn.can_bypass_userlimit fun(name:string, ip:string):boolean? - ---[[ -* `core.register_can_bypass_userlimit(function(name, ip))` - * Called when `name` user connects with `ip`. - * Return `true` to by pass the player limit -]] ----@param f core.fn.can_bypass_userlimit -function core.register_can_bypass_userlimit(f) end - ---[[ -WIPDOC -]] ----@alias core.fn.on_modchannel_message fun(channel_name:string, sender:string, message:string) - ---[[ -WIPDOC -]] ----@param f core.fn.on_modchannel_message -function core.register_on_modchannel_message(f) end - --- ------------------------------- map events ------------------------------- -- - ---[[ -WIPDOC -]] ----@alias core.fn.on_liquid_transform fun(pos_list: ivec[], node_list: core.Node.get[]) - ---[[ -* `core.register_on_liquid_transformed(function(pos_list, node_list))` - * Called after liquid nodes (`liquidtype ~= "none"`) are modified by the - engine's liquid transformation process. - * `pos_list` is an array of all modified positions. - * `node_list` is an array of the old node that was previously at the position - with the corresponding index in pos_list. -]] ----@param f core.fn.on_liquid_transform -function core.register_on_liquid_transformed(f) end - ---[[ -WIPDOC -]] ----@alias core.fn.on_mapblocks_changed fun(modified_blocks:table, modified_block_count:integer) - ---[[ -* `core.register_on_mapblocks_changed(function(modified_blocks, modified_block_count))` - * Called soon after any nodes or node metadata have been modified. No - modifications will be missed, but there may be false positives. - * Will never be called more than once per server step. - * `modified_blocks` is the set of modified mapblock position hashes. These - are in the same format as those produced by `core.hash_node_position`, - and can be converted to positions with `core.get_position_from_hash`. - The set is a table where the keys are hashes and the values are `true`. - * `modified_block_count` is the number of entries in the set. - * Note: callbacks must be registered at mod load time. -]] ----@param f core.fn.on_mapblocks_changed -function core.register_on_mapblocks_changed(f) end diff --git a/types/luanti_lsp_definitions/library/core/register/hpchange.lua b/types/luanti_lsp_definitions/library/core/register/hpchange.lua deleted file mode 100644 index 40f24781..00000000 --- a/types/luanti_lsp_definitions/library/core/register/hpchange.lua +++ /dev/null @@ -1,155 +0,0 @@ ----@meta _ --- DRAFT 1 DONE --- luanti/doc/lua_api.md: 'core' namespace reference > Global callback registration functions - --- -------------------------- PlayerHPChangeReason -------------------------- -- - ---[[ -WIPDOC -]] ----@alias core.PlayerHPChangeReason.regular.type ---- | "set_hp" ---- | "fall" ---- | "drown" ---- | "respawn" ---- | string - ---[[ -WIPDOC -]] ----@class core.PlayerHPChangeReason.regular : {[string]:any} ---[[ -WIPDOC -]] ----@field type core.PlayerHPChangeReason.regular.type ---[[ -WIPDOC -]] ----@field from "mod"|"engine" - ---[[ -WIPDOC -]] ----@class core.PlayerHPChangeReason.punch : core.PlayerHPChangeReason.regular ---[[ -WIPDOC -]] ----@field type "punch" ---[[ -WIPDOC -]] ----@field object core.ObjectRef? - ---[[ -WIPDOC -]] ----@class core.PlayerHPChangeReason.node_damage : core.PlayerHPChangeReason.regular ---[[ -WIPDOC -]] ----@field type "node_damage" ---[[ -WIPDOC -]] ----@field node core.Node.name? ---[[ -WIPDOC -]] ----@field node_pos vec? - ---[[ -WIPDOC -]] ----@alias core.PlayerHPChangeReason ---- | core.PlayerHPChangeReason.regular ---- | core.PlayerHPChangeReason.punch ---- | core.PlayerHPChangeReason.node_damage - --- ---------------------------- core.* functions ---------------------------- -- - ---[[ -WIPDOC -]] ----@alias core.fn.on_player_hpchange.logger fun(player:core.PlayerRef, hp_change:integer, reason:core.PlayerHPChangeReason) - ---[[ -* `core.register_on_player_hpchange(function(player, hp_change, reason), modifier)` - * Called when the player gets damaged or healed - * When `hp == 0`, damage doesn't trigger this callback. - * When `hp == hp_max`, healing does still trigger this callback. - * `player`: ObjectRef of the player - * `hp_change`: the amount of change. Negative when it is damage. - * Historically, the new HP value was clamped to [0, 65535] before - calculating the HP change. This clamping has been removed as of - version 5.10.0 - * `reason`: a PlayerHPChangeReason table. - * The `type` field will have one of the following values: - * `set_hp`: A mod or the engine called `set_hp` without - giving a type - use this for custom damage types. - * `punch`: Was punched. `reason.object` will hold the puncher, or nil if none. - * `fall` - * `node_damage`: `damage_per_second` from a neighboring node. - `reason.node` will hold the node name or nil. - `reason.node_pos` will hold the position of the node - * `drown` - * `respawn` - * Any of the above types may have additional fields from mods. - * `reason.from` will be `mod` or `engine`. - * `modifier`: when true, the function should return the actual `hp_change`. - Note: modifiers only get a temporary `hp_change` that can be modified by later modifiers. - Modifiers can return true as a second argument to stop the execution of further functions. - Non-modifiers receive the final HP change calculated by the modifiers. -]] ----@param f core.fn.on_player_hpchange.logger -function core.register_on_player_hpchange(f) end - ---[[ -WIPDOC -]] ----@alias core.fn.on_player_hpchange.modifier fun(player:core.PlayerRef, hp_change:integer, reason:core.PlayerHPChangeReason):integer, boolean? - ---[[ -* `core.register_on_player_hpchange(function(player, hp_change, reason), modifier)` - * Called when the player gets damaged or healed - * When `hp == 0`, damage doesn't trigger this callback. - * When `hp == hp_max`, healing does still trigger this callback. - * `player`: ObjectRef of the player - * `hp_change`: the amount of change. Negative when it is damage. - * Historically, the new HP value was clamped to [0, 65535] before - calculating the HP change. This clamping has been removed as of - version 5.10.0 - * `reason`: a PlayerHPChangeReason table. - * The `type` field will have one of the following values: - * `set_hp`: A mod or the engine called `set_hp` without - giving a type - use this for custom damage types. - * `punch`: Was punched. `reason.object` will hold the puncher, or nil if none. - * `fall` - * `node_damage`: `damage_per_second` from a neighboring node. - `reason.node` will hold the node name or nil. - `reason.node_pos` will hold the position of the node - * `drown` - * `respawn` - * Any of the above types may have additional fields from mods. - * `reason.from` will be `mod` or `engine`. - * `modifier`: when true, the function should return the actual `hp_change`. - Note: modifiers only get a temporary `hp_change` that can be modified by later modifiers. - Modifiers can return true as a second argument to stop the execution of further functions. - Non-modifiers receive the final HP change calculated by the modifiers. -]] ----@param f core.fn.on_player_hpchange.modifier ----@param modifier true -function core.register_on_player_hpchange(f, modifier) end - ---[[ -WIPDOC -]] ----@alias core.fn.on_dieplayer fun(ObjectRef:core.PlayerRef, reason: core.PlayerHPChangeReason) - ---[[ -* `core.register_on_dieplayer(function(ObjectRef, reason))` - * Called when a player dies - * `reason`: a PlayerHPChangeReason table, see register_on_player_hpchange - * For customizing the death screen, see `core.show_death_screen`. -]] ----@param f core.fn.on_dieplayer -function core.register_on_dieplayer(f) end \ No newline at end of file diff --git a/types/luanti_lsp_definitions/library/core/register/inventory_action.lua b/types/luanti_lsp_definitions/library/core/register/inventory_action.lua deleted file mode 100644 index e6ad2434..00000000 --- a/types/luanti_lsp_definitions/library/core/register/inventory_action.lua +++ /dev/null @@ -1,114 +0,0 @@ ----@meta _ --- DRAFT 1 DONE --- luanti/doc/lua_api.md: 'core' namespace reference > Global callback registration functions - --- ------------------------------ InventoryInfo ----------------------------- -- - ---[[ -WIPDOC -]] ----@class core.InventoryInfo.move ---[[ -WIPDOC -]] ----@field from_list core.InventoryList ---[[ -WIPDOC -]] ----@field to_list core.InventoryList ---[[ -WIPDOC -]] ----@field from_index integer ---[[ -WIPDOC -]] ----@field to_index integer ---[[ -WIPDOC -]] ----@field count integer - - ---[[ -WIPDOC -]] ----@class core.InventoryInfo.put_or_take ---[[ -WIPDOC -]] ----@field listname core.InventoryList ---[[ -WIPDOC -]] ----@field index integer ---[[ -WIPDOC -]] ----@field stack core.ItemStack - --- ---------------------------- core.* functions ---------------------------- -- - ---[[ -WIPDOC -]] ----@alias core.fn.allow_player_inventory_action.move fun(player:core.PlayerRef, action:"move", inventory:core.InvRef, inventory_info:core.InventoryInfo.move):integer - ---[[ -WIPDOC -]] ----@alias core.fn.allow_player_inventory_action.put fun(player:core.PlayerRef, action:"put", inventory:core.InvRef, inventory_info:core.InventoryInfo.put_or_take):integer - ---[[ -WIPDOC -]] ----@alias core.fn.allow_player_inventory_action.take fun(player:core.PlayerRef, action:"take", inventory:core.InvRef, inventory_info:core.InventoryInfo.put_or_take):integer - ---[[ -WIPDOC -]] ----@alias core.fn.allow_player_inventory_action ---- | core.fn.allow_player_inventory_action.move ---- | core.fn.allow_player_inventory_action.put ---- | core.fn.allow_player_inventory_action.take - ---[[ -* `core.register_allow_player_inventory_action(function(player, action, inventory, inventory_info))` - * Determines how much of a stack may be taken, put or moved to a - player inventory. - * Function arguments: see `core.register_on_player_inventory_action` - * Return a numeric value to limit the amount of items to be taken, put or - moved. A value of `-1` for `take` will make the source stack infinite. -]] ----@param f core.fn.allow_player_inventory_action -function core.register_allow_player_inventory_action(f) end - ---[[ -WIPDOC -]] ----@alias core.fn.on_player_inventory_action.move fun(player:core.PlayerRef, action:"move", inventory:core.InvRef, inventory_info:core.InventoryInfo.move) - ---[[ -WIPDOC -]] ----@alias core.fn.on_player_inventory_action.put fun(player:core.PlayerRef, action:"put", inventory:core.InvRef, inventory_info:core.InventoryInfo.put_or_take) - ---[[ -WIPDOC -]] ----@alias core.fn.on_player_inventory_action.take fun(player:core.PlayerRef, action:"take", inventory:core.InvRef, inventory_info:core.InventoryInfo.put_or_take) - ---[[ -WIPDOC -]] ----@alias core.fn.on_player_inventory_action ---- | core.fn.on_player_inventory_action.move ---- | core.fn.on_player_inventory_action.put ---- | core.fn.on_player_inventory_action.take - - ---[[ -WIPDOC -]] ----@param f core.fn.on_player_inventory_action -function core.register_on_player_inventory_action(f) end \ No newline at end of file diff --git a/types/luanti_lsp_definitions/library/core/register/player_receive_fields.lua b/types/luanti_lsp_definitions/library/core/register/player_receive_fields.lua deleted file mode 100644 index 69e62e96..00000000 --- a/types/luanti_lsp_definitions/library/core/register/player_receive_fields.lua +++ /dev/null @@ -1,73 +0,0 @@ ----@meta _ --- DRAFT 1 DONE --- luanti/doc/lua_api.md: 'core' namespace reference > Global callback registration functions - ---[[ -WIPDOC -]] ----@class core.FormspecFields : {[string]:string} ---[[ -WIPDOC -]] ----@field quit "true"? ---[[ -WIPDOC -]] ----@field try_quit "true"? ---[[ -WIPDOC -]] ----@field key_enter "true"? - ---[[ -WIPDOC -]] ----@alias core.fn.on_player_receive_fields fun(player:core.PlayerRef, formname:string, fields:core.FormspecFields):boolean? - ---[[ -* `core.register_on_player_receive_fields(function(player, formname, fields))` -* Called when the server received input from `player`. - Specifically, this is called on any of the - following events: - * a button was pressed, - * Enter was pressed while the focus was on a text field - * a checkbox was toggled, - * something was selected in a dropdown list, - * a different tab was selected, - * selection was changed in a textlist or table, - * an entry was double-clicked in a textlist or table, - * a scrollbar was moved, or - * the form was actively closed by the player. -* `formname` is the name passed to `core.show_formspec`. - Special case: The empty string refers to the player inventory - (the formspec set by the `set_inventory_formspec` player method). -* Fields are sent for formspec elements which define a field. `fields` - is a table containing each formspecs element value (as string), with - the `name` parameter as index for each. The value depends on the - formspec element type: - * `animated_image`: Returns the index of the current frame. - * `button` and variants: If pressed, contains the user-facing button - text as value. If not pressed, is `nil` - * `field`, `textarea` and variants: Text in the field - * `dropdown`: Either the index or value, depending on the `index event` - dropdown argument. - * `tabheader`: Tab index, starting with `"1"` (only if tab changed) - * `checkbox`: `"true"` if checked, `"false"` if unchecked - * `textlist`: See `core.explode_textlist_event` - * `table`: See `core.explode_table_event` - * `scrollbar`: See `core.explode_scrollbar_event` - * Special case: `["quit"]="true"` is sent when the user actively - closed the form by mouse click, keypress or through a `button_exit[]` - element. - * Special case: `["try_quit"]="true"` is sent when the user tries to - close the formspec, but the formspec used `allow_close[false]`. - * Special case: `["key_enter"]="true"` is sent when the user pressed - the Enter key and the focus was either nowhere (causing the formspec - to be closed) or on a button. If the focus was on a text field, - additionally, the index `key_enter_field` contains the name of the - text field. See also: `field_close_on_enter`. -* Newest functions are called first -* If function returns `true`, remaining functions are not called -]] ----@param f core.fn.on_player_receive_fields -function core.register_on_player_receive_fields(f) end \ No newline at end of file diff --git a/types/luanti_lsp_definitions/library/core/register/playerevent.lua b/types/luanti_lsp_definitions/library/core/register/playerevent.lua deleted file mode 100644 index dedca24d..00000000 --- a/types/luanti_lsp_definitions/library/core/register/playerevent.lua +++ /dev/null @@ -1,28 +0,0 @@ ----@meta _ --- DRAFT 1 DONE --- builtin/game/register.lua --- src/script/cpp_api/s_env.cpp - --- ------------------------------- PlayerEvent ------------------------------ -- - ---[[ -WIPDOC -]] ----@alias core.PlayerEvent ---- | "hud_changed" ---- | "properties_changed" ---- | "health_changed" ---- | "breath_changed" - --- ---------------------------- core.* functions ---------------------------- -- - ---[[ -WIPDOC -]] ----@alias core.fn.playerevent fun(player:core.PlayerRef, event:core.PlayerEvent) - ---[[ -WIPDOC -]] ----@param f core.fn.playerevent -function core.register_playerevent(f) end \ No newline at end of file diff --git a/types/luanti_lsp_definitions/library/core/rollback.lua b/types/luanti_lsp_definitions/library/core/rollback.lua deleted file mode 100644 index eb170c92..00000000 --- a/types/luanti_lsp_definitions/library/core/rollback.lua +++ /dev/null @@ -1,54 +0,0 @@ ----@meta _ --- DRAFT 1 DONE --- luanti/doc/lua_api.md: 'core' namespace reference > Rollback - ---[[ -WIPDOC -]] ----@class core.RollbackNodeAction ---[[ -WIPDOC -]] ----@field [1] string ---[[ -WIPDOC -]] ----@field [2] ivec ---[[ -WIPDOC -]] ----@field [3] number ---[[ -WIPDOC -]] ----@field [4] core.Node.get ---[[ -WIPDOC -]] ----@field [5] core.Node.get - ---[[ -* `core.rollback_get_node_actions(pos, range, seconds, limit)`: - returns `{{actor, pos, time, oldnode, newnode}, ...}` - * Find who has done something to a node, or near a node - * `actor`: `"player:"`, also `"liquid"`. -]] ----@nodiscard ----@param pos ivector ----@param range integer ----@param seconds number ----@param limit number ----@return core.RollbackNodeAction[] -function core.rollback_get_node_actions(pos, range, seconds, limit) end - ---[[ -* `core.rollback_revert_actions_by(actor, seconds)`: returns - `boolean, log_messages`. - * Revert latest actions of someone - * `actor`: `"player:"`, also `"liquid"`. -]] ----@nodiscard ----@param actor string|"liquid" ----@param seconds number ----@return boolean success, string[] log_messages -function core.rollback_revert_actions_by(actor, seconds) end \ No newline at end of file diff --git a/types/luanti_lsp_definitions/library/core/schematics.lua b/types/luanti_lsp_definitions/library/core/schematics.lua deleted file mode 100644 index dbdd178d..00000000 --- a/types/luanti_lsp_definitions/library/core/schematics.lua +++ /dev/null @@ -1,168 +0,0 @@ ----@meta _ --- DRAFT 1 DONE --- luanti/doc/lua_api.md: 'core' namespace reference > Schematics - ---[[ -WIPDOC -]] ----@class core.Schematic.probability_list ---[[ -WIPDOC -]] ----@field pos integer ---[[ -* A probability value of `0` or `1` means that node will never appear - (0% chance). -* A probability value of `254` or `255` means the node will always appear - (100% chance). -* If the probability value `p` is greater than `1`, then there is a - `(p / 256 * 100)` percent chance that node will appear when the schematic is - placed on the map. -]] ----@field prob integer - ---[[ -WIPDOC -]] ----@param p1 ivector ----@param p2 ivector ----@param probability_list core.Schematic.probability_list? ----@param filename core.Path ----@param slice_prob_list core.SchematicDef.yslice_prob? -function core.create_schematic(p1, p2, probability_list, filename, slice_prob_list) end - ---[[ -WIPDOC -]] ----@alias core.Schematic.rotation ---- | "0" ---- | "90" ---- | "180" ---- | "270" ---- | "random" - ---[[ -WIPDOC -]] ----@alias core.Schematic.replacements table - ---[[ -* `core.place_schematic(pos, schematic, rotation, replacements, force_placement, flags)` - * Place the schematic specified by schematic (see [Schematic specifier]) at - `pos`. - * `rotation` can equal `"0"`, `"90"`, `"180"`, `"270"`, or `"random"`. - * If the `rotation` parameter is omitted, the schematic is not rotated. - * `replacements` = `{["old_name"] = "convert_to", ...}` - * `force_placement` is a boolean indicating whether nodes other than `air` - and `ignore` are replaced by the schematic. - * Returns nil if the schematic could not be loaded. - * **Warning**: Once you have loaded a schematic from a file, it will be - cached. Future calls will always use the cached version and the - replacement list defined for it, regardless of whether the file or the - replacement list parameter have changed. The only way to load the file - anew is to restart the server. - * `flags` is a flag field with the available flags: - * place_center_x - * place_center_y - * place_center_z -]] ----@nodiscard ----@param pos ivector ----@param schematic core.Schematic ----@param rotation core.Schematic.rotation? ----@param replacements core.Schematic.replacements? ----@param force_placement boolean? ----@param flags core.Schematic.flags? ----@return boolean? -function core.place_schematic(pos, schematic, rotation, replacements, force_placement, flags) end - ---[[ -* `core.place_schematic_on_vmanip(vmanip, pos, schematic, rotation, replacement, force_placement, flags)`: - * This function is analogous to core.place_schematic, but places a - schematic onto the specified VoxelManip object `vmanip` instead of the - map. - * Returns false if any part of the schematic was cut-off due to the - VoxelManip not containing the full area required, and true if the whole - schematic was able to fit. - * Returns nil if the schematic could not be loaded. - * After execution, any external copies of the VoxelManip contents are - invalidated. - * `flags` is a flag field with the available flags: - * place_center_x - * place_center_y - * place_center_z -]] ----@nodiscard ----@param vmanip core.VoxelManip ----@param schematic core.Schematic ----@param rotation core.Schematic.rotation? ----@param replacements core.Schematic.replacements? ----@param force_placement boolean? ----@param flags core.Schematic.flags? ----@return boolean? -function core.place_schematic_on_vmanip(vmanip, pos, schematic, rotation, replacements, force_placement, flags) end - ---[[ -WIPDOC -]] ----@class core.SerializeSchematicOptions ---[[ -WIPDOC -]] ----@field lua_use_comments boolean? ---[[ -WIPDOC -]] ----@field lua_num_indent_spaces integer? - ---[[ -* `core.serialize_schematic(schematic, format, options)` - * Return the serialized schematic specified by schematic - (see [Schematic specifier]) - * in the `format` of either "mts" or "lua". - * "mts" - a string containing the binary MTS data used in the MTS file - format. - * "lua" - a string containing Lua code representing the schematic in table - format. - * `options` is a table containing the following optional parameters: - * If `lua_use_comments` is true and `format` is "lua", the Lua code - generated will have (X, Z) position comments for every X row - generated in the schematic data for easier reading. - * If `lua_num_indent_spaces` is a nonzero number and `format` is "lua", - the Lua code generated will use that number of spaces as indentation - instead of a tab character. -]] ----@nodiscard ----@param schematic core.Schematic ----@param format "mts"|"lua" ----@param options core.SerializeSchematicOptions? ----@return string -function core.serialize_schematic(schematic, format, options) end - ---[[ -WIPDOC -]] ----@class core.ReadSchematicOptions ---[[ -WIPDOC -]] ----@field write_yslice_prob "none"|"low"|"all"? - ---[[ -* `core.read_schematic(schematic, options)` - * Returns a Lua table representing the schematic (see: [Schematic specifier]) - * `schematic` is the schematic to read (see: [Schematic specifier]) - * `options` is a table containing the following optional parameters: - * `write_yslice_prob`: string value: - * `none`: no `write_yslice_prob` table is inserted, - * `low`: only probabilities that are not 254 or 255 are written in - the `write_yslice_prob` table, - * `all`: write all probabilities to the `write_yslice_prob` table. - * The default for this option is `all`. - * Any invalid value will be interpreted as `all`. -]] ----@nodiscard ----@param schematic core.Schematic ----@param options core.ReadSchematicOptions ----@return core.SchematicDef? -function core.read_schematic(schematic, options) end \ No newline at end of file diff --git a/types/luanti_lsp_definitions/library/core/server/dynamic_media.lua b/types/luanti_lsp_definitions/library/core/server/dynamic_media.lua deleted file mode 100644 index 3185d784..00000000 --- a/types/luanti_lsp_definitions/library/core/server/dynamic_media.lua +++ /dev/null @@ -1,69 +0,0 @@ ----@meta _ --- DRAFT 1 DONE --- luanti/doc/lua_api.md: 'core' namespace reference > Server - --- --------------------------- DynamicMediaOptions -------------------------- -- - ---[[ -WIPDOC -]] ----@class _.DynamicMediaOptions.__base ---[[ -WIPDOC -]] ----@field to_player string? ---[[ -WIPDOC -]] ----@field ephemeral boolean? ---[[ -WIPDOC -]] ----@field client_cache boolean? - ---[[ -WIPDOC -]] ----@class core.DynamicMediaOptions.filepath : _.DynamicMediaOptions.__base ---[[ -WIPDOC -]] ----@field filename string? ---[[ -WIPDOC -]] ----@field filepath core.Path - ---[[ -WIPDOC -]] ----@class core.DynamicMediaOptions.filedata : _.DynamicMediaOptions.__base ---[[ -WIPDOC -]] ----@field filename string ---[[ -WIPDOC -]] ----@field filedata string - ---[[ -WIPDOC -]] ----@alias core.DynamicMediaOptions ---- | core.DynamicMediaOptions.filepath ---- | core.DynamicMediaOptions.filedata - --- ---------------------------- core.* functions ---------------------------- -- - ---[[ -WIPDOC -]] ----@alias core.fn.dynamic_add_media fun(name:string):boolean - ---[[ -WIPDOC -]] ----@param options core.DynamicMediaOptions ----@param callback core.fn.dynamic_add_media -function core.dynamic_add_media(options, callback) end \ No newline at end of file diff --git a/types/luanti_lsp_definitions/library/core/server/server.lua b/types/luanti_lsp_definitions/library/core/server/server.lua deleted file mode 100644 index 7431343a..00000000 --- a/types/luanti_lsp_definitions/library/core/server/server.lua +++ /dev/null @@ -1,76 +0,0 @@ ----@meta _ --- DRAFT 1 DONE --- luanti/doc/lua_api.md: 'core' namespace reference > Server - ---[[ -* `core.request_shutdown([message],[reconnect],[delay])`: request for - server shutdown. Will display `message` to clients. - * `reconnect` == true displays a reconnect button - * `delay` adds an optional delay (in seconds) before shutdown. - Negative delay cancels the current active shutdown. - Zero delay triggers an immediate shutdown. -]] ----@param message string? ----@param reconnect boolean? ----@param delay number? -function core.request_shutdown(message, reconnect, delay) end - ---[[ -* `core.cancel_shutdown_requests()`: cancel current delayed shutdown -]] -function core.cancel_shutdown_requests() end - ---[[ -Unofficial note: This is really cool i didn't know this -* `core.get_server_status(name, joined)` - * Returns the server status string when a player joins or when the command - `/status` is called. Returns `nil` or an empty string when the message is - disabled. - * `joined`: Boolean value, indicates whether the function was called when - a player joined. - * This function may be overwritten by mods to customize the status message. -]] ----@nodiscard ----@param name string ----@param joined boolean ----@return string? -function core.get_server_status(name, joined) end - ---[[ -* `core.get_server_uptime()`: returns the server uptime in seconds -]] ----@nodiscard ----@return number -function core.get_server_uptime() end - ---[[ -* `core.get_server_max_lag()`: returns the current maximum lag - of the server in seconds or nil if server is not fully loaded yet -]] ----@nodiscard ----@return number? -function core.get_server_max_lag() end - ---[[ -* `core.remove_player(name)`: remove player from database (if they are not - connected). - * As auth data is not removed, `core.player_exists` will continue to - return true. Call the below method as well if you want to remove auth - data too. - * Returns a code (0: successful, 1: no such player, 2: player is connected) -]] ----@nodiscard ----@param name string ----@return 0|1|2 -function core.remove_player(name) end - ---[[ -* `core.remove_player_auth(name)`: remove player authentication data - * Returns boolean indicating success (false if player nonexistent) -]] ----@nodiscard ----@param name string ----@return boolean success -function core.remove_player_auth(name) end - ---[[ core.dynamic_add_media() split off into dynamic_media.lua ]]-- \ No newline at end of file diff --git a/types/luanti_lsp_definitions/library/core/settings.lua b/types/luanti_lsp_definitions/library/core/settings.lua deleted file mode 100644 index eeeadd5d..00000000 --- a/types/luanti_lsp_definitions/library/core/settings.lua +++ /dev/null @@ -1,14 +0,0 @@ ----@meta _ --- DRAFT 1 DONE --- luanti/doc/lua_api.md: 'core' namespace reference > Setting-related - ---[[ core.settings split off into library/classes/Settings/LuantiSettings.lua ]]-- - ---[[ -WIPDOC -]] ----@nodiscard ----@deprecated ----@param name core.LuantiSettings.keys.vector ----@return vec? -function core.setting_get_pos(name) end \ No newline at end of file diff --git a/types/luanti_lsp_definitions/library/core/sounds.lua b/types/luanti_lsp_definitions/library/core/sounds.lua deleted file mode 100644 index ef6f67f1..00000000 --- a/types/luanti_lsp_definitions/library/core/sounds.lua +++ /dev/null @@ -1,48 +0,0 @@ ----@meta _ --- DRAFT 1 DONE --- luanti/doc/lua_api.md: 'core' namespace reference > Sounds - ---[[ -WIPDOC -]] ----@class core.SoundID : integer - ---[[ -Unofficial note: i made ephemeral NOT be optional because it's a good idea to explicitly set it (most of the time you don't use that, so set it to true) -* `core.sound_play(spec, parameters, [ephemeral])`: returns a handle - * `spec` is a `SimpleSoundSpec` - * `parameters` is a sound parameter table - * `ephemeral` is a boolean (default: false) - Ephemeral sounds will not return a handle and can't be stopped or faded. - It is recommend to use this for short sounds that happen in response to - player actions (e.g. door closing). -]] ----@nodiscard ----@param spec core.SimpleSoundSpec ----@param parameters core.SoundParamter ----@param ephemeral boolean? ----@return core.SoundID? -function core.sound_play(spec, parameters, ephemeral) end - ---[[ -* `core.sound_stop(handle)` - * `handle` is a handle returned by `core.sound_play` -]] ----@param handle core.SoundID -function core.sound_stop(handle) end - ---[[ -* `core.sound_fade(handle, step, gain)` - * `handle` is a handle returned by `core.sound_play` - * `step` determines how fast a sound will fade. - The gain will change by this much per second, - until it reaches the target gain. - Note: Older versions used a signed step. This is deprecated, but old - code will still work. (the client uses abs(step) to correct it) - * `gain` the target gain for the fade. - Fading to zero will delete the sound. -]] ----@param handle core.SoundID ----@param step number ----@param gain number -function core.sound_fade(handle, step, gain) end \ No newline at end of file diff --git a/types/luanti_lsp_definitions/library/core/timing.lua b/types/luanti_lsp_definitions/library/core/timing.lua deleted file mode 100644 index bf585a5f..00000000 --- a/types/luanti_lsp_definitions/library/core/timing.lua +++ /dev/null @@ -1,32 +0,0 @@ ----@meta _ --- DRAFT 1 DONE --- luanti/doc/lua_api.md: 'core' namespace reference > Timing - ---[[ -WIPDOC -]] ----@class core.Job ---[[ -* `job:cancel()` - * Cancels the job function from being called -]] ----@field cancel fun() - ---[[ -* `core.after(time, func, ...)`: returns job table to use as below. - * Call the function `func` after `time` seconds, may be fractional - * Optional: Variable number of arguments that are passed to `func` - * Jobs set for earlier times are executed earlier. If multiple jobs expire - at exactly the same time, then they are executed in registration order. - * `time` is a lower bound. The job is executed in the first server-step that - started at least `time` seconds after the last time a server-step started, - measured with globalstep dtime. - * If `time` is `0`, the job is executed in the next step. -]] ----@nodiscard ----@param time number ----@param f function ----@param ... any ----@return core.Job -function core.after(time, f, ...) end - diff --git a/types/luanti_lsp_definitions/library/core/translations.lua b/types/luanti_lsp_definitions/library/core/translations.lua deleted file mode 100644 index 132fa488..00000000 --- a/types/luanti_lsp_definitions/library/core/translations.lua +++ /dev/null @@ -1,87 +0,0 @@ ----@meta _ --- DRAFT 1 DONE --- luanti/doc/lua_api.md: Translations - ---[[ -WIPDOC -]] ----@alias core.fn.translate_singular fun(str:string, ...:string):string - ---[[ -WIPDOC -]] ----@alias core.fn.translate_plural fun(str:string, str_plural:string, n:integer, ...:string):string - ---[[ -`core.get_translator(textdomain)` is a simple wrapper around -`core.translate` and `core.translate_n`. -After `local S, PS = core.get_translator(textdomain)`, we have -`S(str, ...)` equivalent to `core.translate(textdomain, str, ...)`, and -`PS(str, str_plural, n, ...)` to `core.translate_n(textdomain, str, str_plural, n, ...)`. -It is intended to be used in the following way, so that it avoids verbose -repetitions of `core.translate`: - -```lua -local S, PS = core.get_translator(textdomain) -S(str, ...) -``` - -As an extra commodity, if `textdomain` is nil, it is assumed to be "" instead. -]] ----@nodiscard ----@param textdomain string? ----@return core.fn.translate_singular S, core.fn.translate_plural PS -function core.get_translator(textdomain) end - ---[[ -* `core.translate(textdomain, str, ...)` translates the string `str` with - the given `textdomain` for disambiguation. The textdomain must match the - textdomain specified in the translation file in order to get the string - translated. This can be used so that a string is translated differently in - different contexts. - It is advised to use the name of the mod as textdomain whenever possible, to - avoid clashes with other mods. - This function must be given a number of arguments equal to the number of - arguments the translated string expects. - Arguments are literal strings -- they will not be translated. -]] ----@nodiscard ----@param textdomain string ----@param str string ----@param ... string ----@return string -function core.translate(textdomain, str, ...) end - ---[[ -WIPDOC -]] ----@nodiscard ----@param textdomain string ----@param str string ----@param str_plural string ----@param n integer ----@param ... string ----@return string -function core.translate_n(textdomain, str, str_plural, n, ...) end - ---[[ -On some specific cases, server translation could be useful. For example, filter -a list on labels and send results to client. A method is supplied to achieve -that: - -`core.get_translated_string(lang_code, string)`: resolves translations in -the given string just like the client would, using the translation files for -`lang_code`. For this to have any effect, the string needs to contain translation -markup, e.g. `core.get_translated_string("fr", S("Hello"))`. - -The `lang_code` to use for a given player can be retrieved from -the table returned by `core.get_player_information(name)`. - -IMPORTANT: This functionality should only be used for sorting, filtering or similar purposes. -You do not need to use this to get translated strings to show up on the client. -]] ----@nodiscard ----@param lang_code core.LuantiSettings.enums.language ----@param str string ----@return string -function core.get_translated_string(lang_code, str) end \ No newline at end of file diff --git a/types/luanti_lsp_definitions/library/core/utilities/dig_params.lua b/types/luanti_lsp_definitions/library/core/utilities/dig_params.lua deleted file mode 100644 index c0e9b6f0..00000000 --- a/types/luanti_lsp_definitions/library/core/utilities/dig_params.lua +++ /dev/null @@ -1,54 +0,0 @@ ----@meta _ --- DRAFT 1 DONE --- luanti/doc/lua_api.md: Helper functions - ---[[ -WIPDOC -]] ----@class core.DigParams.not_diggable ---[[ -WIPDOC -]] ----@field diggable false - ---[[ -WIPDOC -]] ----@class core.DigParams.item.diggable ---[[ -WIPDOC -]] ----@field diggable true ---[[ -WIPDOC -]] ----@field time number - ---[[ -WIPDOC -]] ----@class core.DigParams.tool.diggable : core.DigParams.item.diggable ---[[ -WIPDOC -]] ----@field wear core.Tool.wear - ---[[ -WIPDOC -]] ----@alias core.DigParams ---- | core.DigParams.not_diggable ---- | core.DigParams.item.diggable ---- | core.DigParams.tool.diggable - --- ---------------------------- core.* functions ---------------------------- -- - ---[[ -WIPDOC -]] ----@nodiscard ----@param groups core.Groups.node ----@param tool_capabilities core.ToolCapabilities ----@param wear core.Tool.wear? ----@return core.DigParams -function core.get_dig_params(groups, tool_capabilities, wear) end \ No newline at end of file diff --git a/types/luanti_lsp_definitions/library/core/utilities/engine_version.lua b/types/luanti_lsp_definitions/library/core/utilities/engine_version.lua deleted file mode 100644 index c3cef625..00000000 --- a/types/luanti_lsp_definitions/library/core/utilities/engine_version.lua +++ /dev/null @@ -1,48 +0,0 @@ ----@meta _ --- DRAFT 1 DONE --- luanti/doc/lua_api.md: 'core' namespace reference > Utilities - --- ------------------------------ EngineVersion ----------------------------- -- - ---[[ -Use this for informational purposes only. The information in the returned - table does not represent the capabilities of the engine, nor is it - reliable or verifiable. Compatible forks will have a different name and - version entirely. To check for the presence of engine features, test - whether the functions exported by the wanted features exist. For example: - `if core.check_for_falling then ... end`. -]] ----@class core.EngineVersion ---[[ -Name of the project, eg, "Luanti" -]] ----@field project "Luanti"|string ---[[ -Simple version, eg, "1.2.3-dev" -]] ----@field string string ---[[ -The minimum supported protocol version -]] ----@field proto_min core.Protocol ---[[ -The maximum supported protocol version -]] ----@field proto_max core.Protocol ---[[ -Full git version (only set if available), eg, "1.2.3-dev-01234567-dirty". -]] ----@field hash string ---[[ -Boolean value indicating whether it's a development build -]] ----@field is_dev boolean - --- ---------------------------- core.* functions ---------------------------- -- - ---[[ -WIPDOC -]] ----@nodiscard ----@return core.EngineVersion -function core.get_version() end \ No newline at end of file diff --git a/types/luanti_lsp_definitions/library/core/utilities/features.lua b/types/luanti_lsp_definitions/library/core/utilities/features.lua deleted file mode 100644 index 3b998aae..00000000 --- a/types/luanti_lsp_definitions/library/core/utilities/features.lua +++ /dev/null @@ -1,314 +0,0 @@ ----@meta _ --- DRAFT 1 DONE --- luanti/doc/lua_api.md: 'core' namespace reference > Utilities - --- ---------------------------- core.FeatureFlags --------------------------- -- - ---[[ -WIPDOC -]] ----@alias core.FeatureFlags.keys ---- | "glasslike_framed" ---- | "nodebox_as_selectionbox" ---- | "get_all_craft_recipes_works" ---- | "use_texture_alpha" ---- | "no_legacy_abms" ---- | "texture_names_parens" ---- | "area_store_custom_ids" ---- | "add_entity_with_staticdata" ---- | "no_chat_message_prediction" ---- | "object_use_texture_alpha" ---- | "object_independent_selectionbox" ---- | "httpfetch_binary_data" ---- | "formspec_version_element" ---- | "area_store_persistent_ids" ---- | "pathfinder_works" ---- | "object_step_has_moveresult" ---- | "direct_velocity_on_players" ---- | "use_texture_alpha_string_modes" ---- | "degrotate_240_steps" ---- | "abm_min_max_y" ---- | "dynamic_add_media_table" ---- | "particlespawner_tweenable" ---- | "get_sky_as_table" ---- | "get_light_data_buffer" ---- | "mod_storage_on_disk" ---- | "compress_zstd" ---- | "sound_params_start_time" ---- | "physics_overrides_v2" ---- | "hud_def_type_field" ---- | "random_state_restore" ---- | "after_order_expiry_registration" ---- | "wallmounted_rotate" ---- | "item_specific_pointabilities" ---- | "blocking_pointability_type" ---- | "dynamic_add_media_startup" ---- | "dynamic_add_media_filepath" ---- | "lsystem_decoration_type" ---- | "item_meta_range" ---- | "node_interaction_actor" ---- | "moveresult_new_pos" ---- | "override_item_remove_fields" ---- | "hotbar_hud_element" ---- | "bulk_lbms" ---- | "abm_without_neighbors" ---- | "biome_weights" ---- | "particle_blend_clip" ---- | "remove_item_match_meta" ---- | "httpfetch_additional_methods" ---- | "object_guids" ---- | "on_timer_four_args" ---- | "particlespawner_exclude_player" ---- | "generate_decorations_biomes" - ---[[ -WIPDOC -]] ----@class core.FeatureFlags -core.features = {} - ----@class core.FeatureFlags ---[[ -0.4.7 -]] ----@field glasslike_framed boolean? ---[[ -0.4.7 -]] ----@field nodebox_as_selectionbox boolean? ---[[ -0.4.7 -]] ----@field get_all_craft_recipes_works boolean? ---[[ -The transparency channel of textures can optionally be used on -nodes (0.4.7) -]] ----@field use_texture_alpha boolean? ---[[ -Tree and grass ABMs are no longer done from C++ (0.4.8) -]] ----@field no_legacy_abms boolean? ---[[ -Texture grouping is possible using parentheses (0.4.11) -]] ----@field texture_names_parens boolean? ---[[ -Unique Area ID for AreaStoreinsert_area (0.4.14) -]] ----@field area_store_custom_ids boolean? ---[[ -add_entity supports passing initial staticdata to on_activate --- (0.4.16) -]] ----@field add_entity_with_staticdata boolean? ---[[ -Chat messages are no longer predicted (0.4.16) -]] ----@field no_chat_message_prediction boolean? ---[[ -The transparency channel of textures can optionally be used on -objects (ie players and lua entities) (5.0.0) -]] ----@field object_use_texture_alpha boolean? ---[[ -Object selectionbox is settable independently from collisionbox -(5.0.0) -]] ----@field object_independent_selectionbox boolean? ---[[ -SpeeldQcifies whether binary data can be uploaded or downloaded using -the HTTP API (5.1.0) -]] ----@field httpfetch_binary_data boolean? ---[[ -Whether formspec_version[] may be used (5.1.0) -]] ----@field formspec_version_element boolean? ---[[ -Whether AreaStore's IDs are kept on save/load (5.1.0) -]] ----@field area_store_persistent_ids boolean? ---[[ -Whether core.find_path is functional (5.2.0) -]] ----@field pathfinder_works boolean? ---[[ -Whether Collision info is available to an objects' on_step (5.3.0) -]] ----@field object_step_has_moveresult boolean? ---[[ -Whether get_velocity() and add_velocity() can be used on players (5.4.0) -]] ----@field direct_velocity_on_players boolean? ---[[ -nodedef's use_texture_alpha accepts new string modes (5.4.0) -]] ----@field use_texture_alpha_string_modes boolean? ---[[ -degrotate param2 rotates in units of 1.5° instead of 2° -thus changing the range of values from 0-179 to 0-240 (5.5.0) -]] ----@field degrotate_240_steps boolean? ---[[ -ABM supports min_y and max_y fields in definition (5.5.0) -]] ----@field abm_min_max_y boolean? ---[[ -dynamic_add_media supports passing a table with options (5.5.0) -]] ----@field dynamic_add_media_table boolean? ---[[ -particlespawners support texpools and animation of properties, -particle textures support smooth fade and scale animations, and -sprite-sheet particle animations can by synced to the lifetime -of individual particles (5.6.0) -]] ----@field particlespawner_tweenable boolean? ---[[ -allows get_sky to return a table instead of separate values (5.6.0) -]] ----@field get_sky_as_table boolean? ---[[ -VoxelManipget_light_data accepts an optional buffer argument (5.7.0) -]] ----@field get_light_data_buffer boolean? ---[[ -When using a mod storage backend that is not "files" or "dummy", -the amount of data in mod storage is not constrained by -the amount of RAM available. (5.7.0) -]] ----@field mod_storage_on_disk boolean? ---[[ -"zstd" method for compress/decompress (5.7.0) -]] ----@field compress_zstd boolean? ---[[ -Sound parameter tables support start_time (5.8.0) -]] ----@field sound_params_start_time boolean? ---[[ -New fields for set_physics_override speed_climb, speed_crouch, -liquid_fluidity, liquid_fluidity_smooth, liquid_sink, -acceleration_default, acceleration_air (5.8.0) -]] ----@field physics_overrides_v2 boolean? ---[[ -In HUD definitions the field `type` is used and `hud_elem_type` is deprecated (5.9.0) -]] ----@field hud_def_type_field boolean? ---[[ -PseudoRandom and PcgRandom state is restorable -PseudoRandom has get_state method -PcgRandom has get_state and set_state methods (5.9.0) -]] ----@field random_state_restore boolean? ---[[ -core.after guarantees that coexisting jobs are executed primarily -in order of expiry and secondarily in order of registration (5.9.0) -]] ----@field after_order_expiry_registration boolean? ---[[ -wallmounted nodes mounted at floor or ceiling may additionally -be rotated by 90° with special param2 values (5.9.0) -]] ----@field wallmounted_rotate boolean? ---[[ -Availability of the `pointabilities` property in the item definition (5.9.0) -]] ----@field item_specific_pointabilities boolean? ---[[ -Nodes `pointable` property can be `"blocking"` (5.9.0) -]] ----@field blocking_pointability_type boolean? ---[[ -dynamic_add_media can be called at startup when leaving callback as `nil` (5.9.0) -]] ----@field dynamic_add_media_startup boolean? ---[[ -dynamic_add_media supports `filename` and `filedata` parameters (5.9.0) -]] ----@field dynamic_add_media_filepath boolean? ---[[ -L-system decoration type (5.9.0) -]] ----@field lsystem_decoration_type boolean? ---[[ -Overridable pointing range using the itemstack meta key `"range"` (5.9.0) -]] ----@field item_meta_range boolean? ---[[ -Allow passing an optional "actor" ObjectRef to the following functions -core.place_node, core.dig_node, core.punch_node (5.9.0) -]] ----@field node_interaction_actor boolean? ---[[ -"new_pos" field in entity moveresult (5.9.0) -]] ----@field moveresult_new_pos boolean? ---[[ -Allow removing definition fields in `core.override_item` (5.9.0) -]] ----@field override_item_remove_fields boolean? ---[[ -The predefined hotbar is a Lua HUD element of type `hotbar` (5.10.0) -]] ----@field hotbar_hud_element boolean? ---[[ -Bulk LBM support (5.10.0) -]] ----@field bulk_lbms boolean? ---[[ -ABM supports field without_neighbors (5.10.0) -]] ----@field abm_without_neighbors boolean? ---[[ -biomes have a weight parameter (5.11.0) -]] ----@field biome_weights boolean? ---[[ -Particles can specify a "clip" blend mode (5.11.0) -]] ----@field particle_blend_clip boolean? ---[[ -The `match_meta` optional parameter is available for `InvRefremove_item()` (5.12.0) -]] ----@field remove_item_match_meta boolean? ---[[ -The HTTP API supports the HEAD and PATCH methods (5.12.0) -]] ----@field httpfetch_additional_methods boolean? ---[[ -WIPDOC -]] ----@field object_guids boolean? ---[[ -The NodeTimer `on_timer` callback is passed additional `node` and `timeout` args (5.14.0) -]] ----@field on_timer_four_args boolean? ---[[ -`ParticleSpawner` definition supports `exclude_player` field (5.14.0) -]] ----@field particlespawner_exclude_player boolean? ---[[ -core.generate_decorations() supports `use_mapgen_biomes` parameter (5.14.0) -]] ----@field generate_decorations_biomes boolean? - --- ---------------------------- core.* functions ---------------------------- -- - ---[[ -WIPDOC -]] ----@nodiscard ----@param arg core.FeatureFlags ----@return boolean, {}? missing_features -function core.has_feature(arg) end - ---[[ -WIPDOC -]] ----@nodiscard ----@param arg core.FeatureFlags[] ----@return boolean, core.FeatureFlags missing_features -function core.has_feature(arg) end \ No newline at end of file diff --git a/types/luanti_lsp_definitions/library/core/utilities/game_info.lua b/types/luanti_lsp_definitions/library/core/utilities/game_info.lua deleted file mode 100644 index 0989e73b..00000000 --- a/types/luanti_lsp_definitions/library/core/utilities/game_info.lua +++ /dev/null @@ -1,35 +0,0 @@ ----@meta _ --- DRAFT 1 DONE --- luanti/doc/lua_api.md: 'core' namespace reference > Utilities - --- -------------------------------- GameInfo -------------------------------- -- - ---[[ -WIPDOC -]] ----@class core.GameInfo ---[[ -WIPDOC -]] ----@field id string ---[[ -WIPDOC -]] ----@field title string ---[[ -WIPDOC -]] ----@field author string ---[[ -WIPDOC -]] ----@field path core.Path - --- ---------------------------- core.* functions ---------------------------- -- - ---[[ -Unofficial: Path is the root directory of the game, useful if you are looking for it -]] ----@nodiscard ----@return core.GameInfo -function core.get_game_info() end \ No newline at end of file diff --git a/types/luanti_lsp_definitions/library/core/utilities/helpers.lua b/types/luanti_lsp_definitions/library/core/utilities/helpers.lua deleted file mode 100644 index 63bbeac9..00000000 --- a/types/luanti_lsp_definitions/library/core/utilities/helpers.lua +++ /dev/null @@ -1,102 +0,0 @@ ----@meta _ --- DRAFT 1 DONE --- luanti/doc/lua_api.md: Helper functions - --- NOTE: helpers not under core.* are in library/helpers.lua - ---[[ -WIPDOC -]] ----@nodiscard ----@param str string ----@param limit integer ----@param as_table boolean? ----@return string -function core.wrap_text(str, limit, as_table) end - ---[[ -WIPDOC -]] ----@nodiscard ----@param pos vector ----@param decimal_places integer? ----@return string -function core.pos_to_string(pos, decimal_places) end - ---[[ -WIPDOC -]] ----@nodiscard ----@param string string ----@return vec -function core.string_to_pos(string) end - ---[[ -returns two positions -Converts a string representing an area box into two positions -X1, Y1, ... Z2 are coordinates -relative_to: Optional. If set to a position, each coordinate can use the tilde notation for relative positions -"~": Relative coordinate -"~": Relative coordinate plus -Example: core.string_to_area("(1,2,3) (~5,~-5,~)", {x=10,y=10,z=10}) returns {x=1,y=2,z=3}, {x=15,y=5,z=10} -]] ----@nodiscard ----@param str string (X1, Y1, Z1) (X2, Y2, Z2) ----@param relative_to vector? ----@return vec?, vec? -function core.string_to_area(str, relative_to) end - ---[[ -escapes the characters "[", "]", "", "," and ";", which cannot be used in formspecs. -]] ----@nodiscard ----@param string string ----@return string -function core.formspec_escape(string) end - ---[[ -WIPDOC -]] ----@nodiscard ----@param arg string|number|boolean ----@return boolean -function core.is_yes(arg) end - ---[[ -WIPDOC -]] ----@nodiscard ----@param arg number ----@return boolean -function core.is_nan(arg) end - ---[[ -returns time with microsecond precision. May not return wall time. -Unofficial note: I think you should use os.clock() for benchmarking instead -]] ----@nodiscard ----@return integer -function core.get_us_time() end - ---[[ after table.* intermission ]]-- - ---[[ -WIPDOC -]] ----@nodiscard ----@param placer core.ObjectRef ----@param pointed_thing core.PointedThing ----@return vec -function core.pointed_thing_to_face_pos(placer, pointed_thing) end - ---[[ -WIPDOC -]] ----@param uses integer ----@param initial_wear core.Tool.wear? ----@return core.Tool.wear -function core.get_tool_wear_after_use(uses, initial_wear) end - ---[[ core.get_dig_params() split off into ./dig_params.lua ]]-- - ---[[ core.get_hit_params() split off into ./hit_params.lua ]]-- \ No newline at end of file diff --git a/types/luanti_lsp_definitions/library/core/utilities/hit_params.lua b/types/luanti_lsp_definitions/library/core/utilities/hit_params.lua deleted file mode 100644 index f1a6fbec..00000000 --- a/types/luanti_lsp_definitions/library/core/utilities/hit_params.lua +++ /dev/null @@ -1,41 +0,0 @@ ----@meta _ --- DRAFT 1 DONE --- luanti/doc/lua_api.md: Helper functions - ---[[ -WIPDOC -]] ----@class core.HitParams.item ---[[ -WIPDOC -]] ----@field hp integer - ---[[ -WIPDOC -]] ----@class core.HitParams.tool : core.HitParams.item ---[[ -WIPDOC -]] ----@field wear core.Tool.wear - ---[[ -WIPDOC -]] ----@alias core.HitParams ---- | core.HitParams.item ---- | core.HitParams.tool - --- ---------------------------- core.* functions ---------------------------- -- - ---[[ -WIPDOC -]] ----@nodiscard ----@param groups core.Groups.armor ----@param tool_capabilities core.ToolCapabilities ----@param time_from_last_punch number? ----@param wear core.Tool.wear? ----@return core.HitParams -function core.get_hit_params(groups, tool_capabilities, time_from_last_punch, wear) end \ No newline at end of file diff --git a/types/luanti_lsp_definitions/library/core/utilities/player_information.lua b/types/luanti_lsp_definitions/library/core/utilities/player_information.lua deleted file mode 100644 index 8850fbf8..00000000 --- a/types/luanti_lsp_definitions/library/core/utilities/player_information.lua +++ /dev/null @@ -1,131 +0,0 @@ ----@meta _ --- DRAFT 1 DONE --- luanti/doc/lua_api.md: 'core' namespace reference > Utilities - --- ----------------------------- core.PlayerInfo ---------------------------- -- - ---[[ -WIPDOC -]] ----@class core.PlayerInfo ---[[ -IP address of client -]] ----@field address string ---[[ -IPv4 / IPv6 -]] ----@field ip_version 4|6 ---[[ -seconds since client connected -]] ----@field connection_uptime number ---[[ -protocol version used by client -]] ----@field protocol_version core.Protocol ---[[ -supported formspec version -]] ----@field formspec_version integer ---[[ -Language code used for translation -]] ----@field lang_code core.LuantiSettings.enums.language ---[[ -minimum round trip time -]] ----@field min_rtt number? ---[[ -maximum round trip time -]] ----@field max_rtt number? ---[[ -average round trip time -]] ----@field avg_rtt number? ---[[ -minimum packet time jitter -]] ----@field min_jitter number? ---[[ -maximum packet time jitter -]] ----@field max_jitter number? ---[[ -average packet time jitter -]] ----@field avg_jitter number? ---[[ -The version information is provided by the client and may be spoofed -or inconsistent in engine forks. You must not use this for checking -feature availability of clients. Instead, do use the fields -`protocol_version` and `formspec_version` where it matters. -Use `core.protocol_versions` to map Luanti versions to protocol versions. -This version string is only suitable for analysis purposes. -full version string -]] ----@field version_string string - --- ---------------------------- PlayerWindowInfo ---------------------------- -- - ---[[ -Unofficial note: You can compute the pixel size from this, if you are crazy you can make a library based on this or something -Will only be present if the client sent this information (requires v5.7+) - -Note that none of these things are constant, they are likely to change during a client -connection as the player resizes the window and moves it between monitors - -real_gui_scaling and real_hud_scaling can be used instead of DPI. -OSes don't necessarily give the physical DPI, as they may allow user configuration. -real_*_scaling is just OS DPI / 96 but with another level of user configuration. -]] ----@class core.PlayerWindowInfo ---[[ -Current size of the in-game render target (pixels). - -This is usually the window size, but may be smaller in certain situations, -such as side-by-side mode. -]] ----@field size vec2i.xy ---[[ -Estimated maximum formspec size before Luanti will start shrinking the -formspec to fit. For a fullscreen formspec, use the size returned by -this table and `padding[0,0]`. `bgcolor[;true]` is also recommended. -]] ----@field max_formspec_size vec2i.xy ---[[ -GUI Scaling multiplier -Equal to the setting `gui_scaling` multiplied by `dpi / 96` -]] ----@field real_gui_scaling number ---[[ -HUD Scaling multiplier -Equal to the setting `hud_scaling` multiplied by `dpi / 96` -]] ----@field real_hud_scaling number ---[[ -Whether the touchscreen controls are enabled. -Usually (but not always) `true` on Android. -Requires at least version 5.9.0 on the client. For older clients, it -is always set to `false`. -]] ----@field touch_controls boolean - --- ---------------------------- core.* functions ---------------------------- -- - ---[[ -WIPDOC -]] ----@nodiscard ----@param player_name string ----@return core.PlayerInfo -function core.get_player_information(player_name) end - ---[[ -WIPDOC -]] ----@nodiscard ----@param player_name string ----@return core.PlayerWindowInfo? # Client must have version 5.7+ -function core.get_player_window_information(player_name) end \ No newline at end of file diff --git a/types/luanti_lsp_definitions/library/core/utilities/protocol_versions.lua b/types/luanti_lsp_definitions/library/core/utilities/protocol_versions.lua deleted file mode 100644 index 1685372b..00000000 --- a/types/luanti_lsp_definitions/library/core/utilities/protocol_versions.lua +++ /dev/null @@ -1,89 +0,0 @@ ----@meta _ --- DRAFT 1 DONE --- luanti/doc/lua_api.md: 'core' namespace reference > Utilities - ---[[ -WIPDOC -]] ----@alias core.Protocol ---- | 37 ---- | 38 ---- | 39 ---- | 40 ---- | 41 ---- | 42 ---- | 43 ---- | 44 ---- | 45 ---- | 46 ---- | 47 ---- | 48 ---- | 49 - ---[[ -WIPDOC -]] ----@class core.ProtocolVersions -core.protocol_versions = {} - ----@class core.ProtocolVersions : {[string]:core.Protocol} ---[[ -WIPDOC -]] ----@field ["5.0.0"] 37 ---[[ -WIPDOC -]] ----@field ["5.1.0"] 38 ---[[ -WIPDOC -]] ----@field ["5.2.0"] 39 ---[[ -WIPDOC -]] ----@field ["5.3.0"] 39 ---[[ -WIPDOC -]] ----@field ["5.4.0"] 39 ---[[ -WIPDOC -]] ----@field ["5.5.0"] 40 ---[[ -WIPDOC -]] ----@field ["5.6.0"] 41 ---[[ -WIPDOC -]] ----@field ["5.7.0"] 42 ---[[ -WIPDOC -]] ----@field ["5.8.0"] 43 ---[[ -WIPDOC -]] ----@field ["5.9.0"] 44 ---[[ -WIPDOC -]] ----@field ["5.9.1"] 45 ---[[ -WIPDOC -]] ----@field ["5.10.0"] 46 ---[[ -WIPDOC -]] ----@field ["5.11.0"] 47 ---[[ -WIPDOC -]] ----@field ["5.12.0"] 48 ---[[ -WIPDOC -]] ----@field ["5.13.0"] 49 \ No newline at end of file diff --git a/types/luanti_lsp_definitions/library/core/utilities/utilities.lua b/types/luanti_lsp_definitions/library/core/utilities/utilities.lua deleted file mode 100644 index b2d90562..00000000 --- a/types/luanti_lsp_definitions/library/core/utilities/utilities.lua +++ /dev/null @@ -1,208 +0,0 @@ ----@meta _ --- DRAFT 1 DONE --- luanti/doc/lua_api.md: 'core' namespace reference > Utilities - --- ------------------------- engine and client info ------------------------- -- - ---[[ -Returns currently loading mod's name WHEN LOADING A MOD -]] ----@nodiscard ----@return string -function core.get_current_modname() end - ---[[ -WIPDOC -]] ----@nodiscard ----@param modname string ----@return core.Path -function core.get_modpath(modname) end - ---[[ -WIPDOC -]] ----@return string[] ----@nodiscard -function core.get_modnames() end - ---[[ core.get_game_info() split off into ./game_info.lua ]]-- - ---[[ -WIPDOC -]] ----@nodiscard ----@return core.Path -function core.get_worldpath() end - ---[[ -WIPDOC -]] ----@nodiscard ----@return boolean -function core.is_singleplayer() end - ---[[ core.features .. core.has_features() split off into ./features.lua ]]-- - ---[[ core.get_player_information() split off into ./player_information.lua ]]-- - ---[[ core.protocol_versions.lua() split off into ./protocol_versions.lua ]]-- - ---[[ core.get_player_window_information() split off into ./player_information.lua ]]-- - --- ------------------------------- filesystem ------------------------------- -- - ---[[ -WIPDOC -]] ----@nodiscard ----@param path core.Path ----@return boolean success -function core.mkdir(path) end - ---[[ -WIPDOC -]] ----@nodiscard ----@param path core.Path ----@param recursive boolean? ----@return boolean success -function core.rmdir(path, recursive) end - ---[[ -WIPDOC -]] ----@nodiscard ----@param source core.Path ----@param destination core.Path ----@return boolean success -function core.cpdir(source, destination) end - ---[[ -WIPDOC -]] ----@nodiscard ----@param source core.Path ----@param destination core.Path ----@return boolean success -function core.mvdir(source, destination) end - ---[[ -* `core.get_dir_list(path, [is_dir])`: returns list of entry names - * is_dir is one of: - * nil: return all entries, - * true: return only subdirectory names, or - * false: return only file names. -]] ----@nodiscard ----@param path string ----@param is_dir nil|true|false ----@return core.Path[] -function core.get_dir_list(path, is_dir) end - ---[[ -* `core.safe_file_write(path, content)`: returns boolean indicating success - * Replaces contents of file at path with new contents in a safe (atomic) - way. Use this instead of below code when writing e.g. database files: - `local f = io.open(path, "wb"); f:write(content); f:close()` -]] ----@nodiscard ----@param path core.Path ----@param content string ----@return boolean success -function core.safe_file_write(path, content) end - --- ----------------------------- engine version ----------------------------- -- - ---[[ core.get_version() split off into ./engine_version.lua ]]-- - --- --------------------------------- hashing -------------------------------- -- - ---[[ -WIPDOC -]] ----@nodiscard ----@param data string ----@param raw boolean? raw bytes instead of hex digits, default: false ----@return string -function core.sha1(data, raw) end - ---[[ -WIPDOC -]] ----@nodiscard ----@param data string ----@param raw boolean? raw bytes instead of hex digits, default: false ----@return string -function core.sha256(data, raw) end - --- --------------------------------- colors --------------------------------- -- - ---[[ -Colorspec to hex basically -]] ----@nodiscard ----@param colorspec core.ColorSpec ----@return core.ColorString -function core.colorspec_to_colorstring(colorspec) end - ---[[ -Layout: RGBA -]] ----@nodiscard ----@return core.ColorSpec ----@param colorspec core.ColorSpec.numberfmt -function core.colorspec_to_bytes(colorspec) end - ---[[ -WIPDOC -]] ----@nodiscard ----@param colorspec core.ColorSpec ----@return core.ColorSpec.tablefmt -function core.colorspec_to_table(colorspec) end - --- ---------------------------------- misc ---------------------------------- -- - ---[[ -WIPDOC -]] ----@param time_of_day string ----@return number -function core.time_to_day_night_ratio(time_of_day) end - ---[[ -Unofficial note: shhh.... but you can do this in `core.handle_async` instead, get like a really good Promise library -Unofficial note: shh... but you can also use it real-time and it's real cool -Unofficial note: you can do "[png:"..core.encode_base64(core.encode_png(...)) to have a png -* `core.encode_png(width, height, data, [compression])`: Encode a PNG - image and return it in string form. - * `width`: Width of the image - * `height`: Height of the image - * `data`: Image data, one of: - * array table of ColorSpec, length must be width*height - * string with raw RGBA pixels, length must be width*height*4 - * `compression`: Optional zlib compression level, number in range 0 to 9. - The data is one-dimensional, starting in the upper left corner of the image - and laid out in scanlines going from left to right, then top to bottom. - You can use `colorspec_to_bytes` to generate raw RGBA values. - Palettes are not supported at the moment. - You may use this to procedurally generate textures during server init. -]] ----@nodiscard ----@param width integer ----@param height integer ----@param data string|core.ColorSpec[] ----@param compression integer? ----@return string -function core.encode_png(width, height, data, compression) end - ---[[ -* `core.urlencode(str)`: Encodes reserved URI characters by a - percent sign followed by two hex digits. See - [RFC 3986, section 2.3](https://datatracker.ietf.org/doc/html/rfc3986#section-2.3). -]] ----@nodiscard ----@param str string ----@return string -function core.urlencode(str) end \ No newline at end of file diff --git a/types/luanti_lsp_definitions/library/defs/HTTPRequest.lua b/types/luanti_lsp_definitions/library/defs/HTTPRequest.lua deleted file mode 100644 index 329281de..00000000 --- a/types/luanti_lsp_definitions/library/defs/HTTPRequest.lua +++ /dev/null @@ -1,60 +0,0 @@ ----@meta _ --- DRAFT 1 DONE --- luanti/doc/lua_api.md: Definition tables > `HTTPRequest` definition - ---[[ -WIPDOC -]] ----@alias core.HTTPRequestDef.method ---- | "GET" ---- | "HEAD" ---- | "POST" ---- | "PUT" ---- | "PATCH" ---- | "DELETE" - ---[[ -WIPDOC -]] ----@class core.HTTPRequestDef ---[[ -WIPDOC -]] ----@field url string? ---[[ -Timeout for request to be completed in seconds. Default depends on engine settings. -]] ----@field timeout number? ---[[ -The http method to use. Defaults to "GET". -]] ----@field method core.HTTPRequestDef.method? ---[[ -Data for the POST, PUT, PATCH or DELETE request. -Accepts both a string and a table. If a table is specified, encodes -table as x-www-form-urlencoded key-value pairs. -]] ----@field data string|table? ---[[ -Optional, if specified replaces the default Luanti user agent with -given string. -]] ----@field user_agent string? ---[[ -Optional, if specified adds additional headers to the HTTP request. -You must make sure that the header strings follow HTTP specification -("Key: Value"). -]] ----@field extra_headers string[]? ---[[ -Optional, if true performs a multipart HTTP request. -Default is false. -Not allowed for GET or HEAD method and `data` must be a table. -]] ----@field multipart boolean? ---[[ -Deprecated, use `data` instead. Forces `method = "POST"`. - -* @deprecated -]] ----@field post_data string|table? diff --git a/types/luanti_lsp_definitions/library/defs/HTTPRequestResult.lua b/types/luanti_lsp_definitions/library/defs/HTTPRequestResult.lua deleted file mode 100644 index baed5b34..00000000 --- a/types/luanti_lsp_definitions/library/defs/HTTPRequestResult.lua +++ /dev/null @@ -1,29 +0,0 @@ ----@meta _ --- DRAFT 1 DONE --- luanti/doc/lua_api.md: Definition tables > `HTTPRequestResult` definition - ---[[ -WIPDOC -]] ----@class core.HTTPRequestResultDef ---[[ -If true, the request has finished (either succeeded, failed or timed -out) -]] ----@field completed boolean? ---[[ -If true, the request was successful -]] ----@field succeeded boolean? ---[[ -If true, the request timed out -]] ----@field timeout boolean? ---[[ -HTTP status code -]] ----@field code integer? ---[[ -Response body -]] ----@field data string? diff --git a/types/luanti_lsp_definitions/library/defs/abm.lua b/types/luanti_lsp_definitions/library/defs/abm.lua deleted file mode 100644 index a2890757..00000000 --- a/types/luanti_lsp_definitions/library/defs/abm.lua +++ /dev/null @@ -1,76 +0,0 @@ ----@meta _ --- DRAFT 1 DONE --- luanti/doc/lua_api.md: Definition tables > ABM (ActiveBlockModifier) definition - ---[[ -WIPDOC -]] ----@alias core.ABMDef.action fun(pos:ivec, node:core.Node.get, active_object_count:integer, active_object_count_wider:integer) - ---[[ -ABM (ActiveBlockModifier) definition ------------------------------------- - -Used by `core.register_abm`. - -An active block modifier (ABM) is used to define a function that is continuously -and randomly called for specific nodes (defined by `nodenames` and other conditions) -in active mapblocks. -]] ----@class core.ABMDef ---[[ -Descriptive label for profiling purposes (optional). -Definitions with identical labels will be listed as one. -]] ----@field label string ---[[ -Apply `action` function to these nodes. -`group:groupname` can also be used here. -]] ----@field nodenames OneOrMany ---[[ -Only apply `action` to nodes that have one of, or any -combination of, these neighbors. -If left out or empty, any neighbor will do. -`group:groupname` can also be used here. -]] ----@field neighbors OneOrMany? ---[[ -Only apply `action` to nodes that have no one of these neighbors. -If left out or empty, it has no effect. -`group:groupname` can also be used here. -]] ----@field without_neighbors OneOrMany? ---[[ -Operation interval in seconds -]] ----@field interval number? ---[[ -Probability of triggering `action` per-node per-interval is 1.0 / chance (integers only) -]] ----@field chance integer? ---[[ -WIPDOC -]] ----@field min_y integer? ---[[ -WIPDOC -]] ----@field max_y integer? ---[[ -If true, catch-up behavior is enabled: The `chance` value is -temporarily reduced when returning to an area to simulate time lost -by the area being unattended. Note that the `chance` value can often -be reduced to 1. -]] ----@field catch_up boolean? ---[[ -Function triggered for each qualifying node. -`active_object_count` is number of active objects in the node's -mapblock. -`active_object_count_wider` is number of active objects in the node's -mapblock plus all 26 neighboring mapblocks. If any neighboring -mapblocks are unloaded an estimate is calculated for them based on -loaded mapblocks. -]] ----@field action core.ABMDef.action diff --git a/types/luanti_lsp_definitions/library/defs/aliases.lua b/types/luanti_lsp_definitions/library/defs/aliases.lua deleted file mode 100644 index eeb429bb..00000000 --- a/types/luanti_lsp_definitions/library/defs/aliases.lua +++ /dev/null @@ -1,71 +0,0 @@ ----@meta _ --- DRAFT 1 DONE --- luanti/doc/lua_api.md: Aliases > Mapgen aliases - --- ------------------------------- MapgenAlias ------------------------------ -- - ---[[ -WIPDOC -]] ----@alias core.MapgenAlias.essential ---- | "mapgen_stone" ---- | "mapgen_water_source" ---- | "mapgen_river_water_source" - ---[[ -WIPDOC -]] ----@alias core.MapgenAlias.optional ---- | "mapgen_lava_source" ---- | "mapgen_cobble" - ---[[ -WIPDOC -]] ----@alias core.MapgenAlias.v6.essential ---- | "mapgen_stone" ---- | "mapgen_water_source" ---- | "mapgen_lava_source" ---- | "mapgen_dirt" ---- | "mapgen_dirt_with_grass" ---- | "mapgen_sand" ---- | "mapgen_tree" ---- | "mapgen_leaves" ---- | "mapgen_apple" ---- | "mapgen_cobble" - ---[[ -WIPDOC -]] ----@alias core.MapgenAlias.v6.optional ---- | "mapgen_gravel" ---- | "mapgen_desert_stone" ---- | "mapgen_desert_sand" ---- | "mapgen_dirt_with_snow" ---- | "mapgen_snowblock" ---- | "mapgen_snow" ---- | "mapgen_ice" ---- | "mapgen_jungletree" ---- | "mapgen_jungleleaves" ---- | "mapgen_junglegrass" ---- | "mapgen_pine_tree" ---- | "mapgen_pine_needles" ---- | "mapgen_stair_cobble" ---- | "mapgen_mossycobble" ---- | "mapgen_stair_desert_stone" - ---[[ -WIPDOC -]] ----@alias core.MapgenAlias ---- | core.MapgenAlias.essential ---- | core.MapgenAlias.optional ---- | core.MapgenAlias.v6.essential ---- | core.MapgenAlias.v6.optional - ---[[ -WIPDOC -]] ----@alias core.Alias ---- | core.MapgenAlias ---- | string \ No newline at end of file diff --git a/types/luanti_lsp_definitions/library/defs/authentication_handler.lua b/types/luanti_lsp_definitions/library/defs/authentication_handler.lua deleted file mode 100644 index 75cd1441..00000000 --- a/types/luanti_lsp_definitions/library/defs/authentication_handler.lua +++ /dev/null @@ -1,106 +0,0 @@ ----@meta _ --- DRAFT 1 DONE --- luanti/doc/lua_api.md: Definition tables > Authentication handler definition - --- --------------------------- AuthenticationData --------------------------- -- - ---[[ -WIPDOC -]] ----@class core.AuthenticationData ---[[ -WIPDOC -]] ----@field password string ---[[ -WIPDOC -]] ----@field privileges core.PrivilegeSet ---[[ -WIPDOC -]] ----@field last_login number? - --- ------------------------ AuthenticationHandlerDef ------------------------ -- - ---[[ -WIPDOC -]] ----@alias core.AuthenticationHandlerDef.get_auth fun(name:string?): core.AuthenticationData - ---[[ -WIPDOC -]] ----@alias core.AuthenticationHandlerDef.create_auth fun(name:string, password:string) - ---[[ -WIPDOC -]] ----@alias core.AuthenticationHandlerDef.delete_auth fun(name:string): boolean - ---[[ -WIPDOC -]] ----@alias core.AuthenticationHandlerDef.set_password fun(name:string, password:string) - ---[[ -WIPDOC -]] ----@alias core.AuthenticationHandlerDef.set_privileges fun(name:string?, privileges:core.PrivilegeSet?) - ---[[ -WIPDOC -]] ----@alias core.AuthenticationHandlerDef.reload fun(): boolean - ---[[ -WIPDOC -]] ----@alias core.AuthenticationHandlerDef.record_login fun(name:string) - ---[[ -WIPDOC -]] ----@alias _.AuthenticationHandlerDef.iterate fun():string? - ---[[ -WIPDOC -]] ----@alias core.AuthenticationHandlerDef.iterate fun():_.AuthenticationHandlerDef.iterate - ---[[ -WIPDOC -]] ----@class core.AuthenticationHandlerDef ---[[ -WIPDOC -]] ----@field get_auth core.AuthenticationHandlerDef.get_auth ---[[ -WIPDOC -]] ----@field create_auth core.AuthenticationHandlerDef.create_auth ---[[ -WIPDOC -]] ----@field delete_auth core.AuthenticationHandlerDef.delete_auth ---[[ -WIPDOC -]] ----@field set_password core.AuthenticationHandlerDef.set_password ---[[ -WIPDOC -]] ----@field set_privileges core.AuthenticationHandlerDef.set_privileges ---[[ -WIPDOC -]] ----@field reload core.AuthenticationHandlerDef.reload ---[[ -WIPDOC -]] ----@field record_login core.AuthenticationHandlerDef.record_login ---[[ -WIPDOC -]] ----@field iterate core.AuthenticationHandlerDef.iterate \ No newline at end of file diff --git a/types/luanti_lsp_definitions/library/defs/biome.lua b/types/luanti_lsp_definitions/library/defs/biome.lua deleted file mode 100644 index 979fc7dd..00000000 --- a/types/luanti_lsp_definitions/library/defs/biome.lua +++ /dev/null @@ -1,143 +0,0 @@ ----@meta _ --- DRAFT 1 DONE --- luanti/doc/lua_api.md: Definition table > Biome definition - ---[[ -WIPDOC -]] ----@class core.BiomeID : integer - ---[[ -WIPDOC -]] ----@class core.BiomeDef ---[[ -Biome name -]] ----@field name string ---[[ -Node dropped onto upper surface after all else is generated -]] ----@field node_dust core.Node.name? ---[[ -Node forming surface layer of biome -]] ----@field node_top core.Node.name? ---[[ -Node forming surface layer of biome and thickness of this layer -]] ----@field depth_top integer? ---[[ -Node forming lower layer of biome -]] ----@field node_filler core.Node.name? ---[[ -Node forming lower layer of biome and thickness of this layer -]] ----@field depth_filler integer? ---[[ -Node that replaces all stone nodes between roughly y_min and y_max. -]] ----@field node_stone core.Node.name? ---[[ -Node forming a surface layer in seawater with the defined thickness -]] ----@field node_water_top core.Node.name? ---[[ -Node forming a surface layer in seawater with the defined thickness -]] ----@field depth_water_top integer? ---[[ -Node that replaces all seawater nodes not in the surface layer -]] ----@field node_water core.Node.name? ---[[ -Node that replaces river water in mapgens that use default:river_water -]] ----@field node_river_water core.Node.name? ---[[ -Node placed under river water and thickness of this layer -]] ----@field node_riverbed core.Node.name? ---[[ -Node placed under river water and thickness of this layer -]] ----@field depth_riverbed integer? ---[[ -Nodes placed inside 50% of the medium size caves. -Multiple nodes can be specified, each cave will use a randomly -chosen node from the list. -If this field is left out or 'nil', cave liquids fall back to -classic behavior of lava and water distributed using 3D noise. -For no cave liquid, specify "air". -]] ----@field node_cave_liquid core.Node.name|core.Node.name[]? ---[[ -Node used for primary dungeon structure. -If absent, dungeon nodes fall back to the 'mapgen_cobble' mapgen -alias, if that is also absent, dungeon nodes fall back to the biome -'node_stone'. -If present, the following two nodes are also used. -]] ----@field node_dungeon core.Node.name? ---[[ -Node used for randomly-distributed alternative structure nodes. -If alternative structure nodes are not wanted leave this absent. -]] ----@field node_dungeon_alt core.Node.name? ---[[ -Node used for dungeon stairs. -If absent, stairs fall back to 'node_dungeon'. -]] ----@field node_dungeon_stair core.Node.name? ---[[ -WIPDOC -]] ----@field y_max integer? ---[[ -WIPDOC -]] ----@field y_min integer? ---[[ -xyz limits for biome, an alternative to using 'y_min' and 'y_max'. -Biome is limited to a cuboid defined by these positions. -Any x, y or z field left undefined defaults to -31000 in 'min_pos' or -31000 in 'max_pos'. -]] ----@field max_pos ivector? ---[[ -xyz limits for biome, an alternative to using 'y_min' and 'y_max'. -Biome is limited to a cuboid defined by these positions. -Any x, y or z field left undefined defaults to -31000 in 'min_pos' or -31000 in 'max_pos'. -]] ----@field min_pos ivector? ---[[ -Vertical distance in nodes above 'y_max' over which the biome will -blend with the biome above. -Set to 0 for no vertical blend. Defaults to 0. -]] ----@field vertical_blend integer? ---[[ -Characteristic temperature and humidity for the biome. -These values create 'biome points' on a voronoi diagram with heat and -humidity as axes. The resulting voronoi cells determine the -distribution of the biomes. -Heat and humidity have average values of 50, vary mostly between -0 and 100 but can exceed these values. -]] ----@field heat_point integer ---[[ -Characteristic temperature and humidity for the biome. -These values create 'biome points' on a voronoi diagram with heat and -humidity as axes. The resulting voronoi cells determine the -distribution of the biomes. -Heat and humidity have average values of 50, vary mostly between -0 and 100 but can exceed these values. -]] ----@field humidity_point integer ---[[ -Relative weight of the biome in the Voronoi diagram. -A value of 0 (or less) is ignored and equivalent to 1.0. -]] ----@field weight number? \ No newline at end of file diff --git a/types/luanti_lsp_definitions/library/defs/chat_command.lua b/types/luanti_lsp_definitions/library/defs/chat_command.lua deleted file mode 100644 index 250c8895..00000000 --- a/types/luanti_lsp_definitions/library/defs/chat_command.lua +++ /dev/null @@ -1,92 +0,0 @@ ----@meta _ --- DRAFT 1 DONE --- luanti/doc/lua_api.md: Definition tables > Chat command definition - ---[[ -WIPDOC -]] ----@alias core.ChatCommandDef.keys ---- | "pulverize" ---- | "fixlight" ---- | "dump" ---- | "grantme" ---- | "rollback_check" ---- | "mods" ---- | "days" ---- | "last-login" ---- | "help" ---- | "privs" ---- | "clearinv" ---- | "status" ---- | "msg" ---- | "shutdown" ---- | "revokeme" ---- | "grant" ---- | "revoke" ---- | "admin" ---- | "ban" ---- | "kick" ---- | "giveme" ---- | "remove_player" ---- | "unban" ---- | "haspriv" ---- | "kill" ---- | "set" ---- | "rollback" ---- | "auth_reload" ---- | "clearobjects" ---- | "setpassword" ---- | "me" ---- | "emergeblocks" ---- | "teleport" ---- | "give" ---- | "time" ---- | "spawnentity" ---- | "clearpassword" ---- | "deleteblocks" ---- | string - ---[[ -WIPDOC -]] ----@alias core.ChatCommandDef.func fun(name:string, param:string): boolean?, string? - ---[[ -WIPDOC -]] ----@class core.ChatCommandDef ---[[ -Note that in params, the conventional use of symbols is as follows: - -* `<>` signifies a placeholder to be replaced when the command is used. For - example, when a player name is needed: `` -* `[]` signifies param is optional and not required when the command is used. - For example, if you require param1 but param2 is optional: - ` []` -* `|` signifies exclusive or. The command requires one param from the options - provided. For example: ` | ` -* `()` signifies grouping. For example, when param1 and param2 are both - required, or only param3 is required: `( ) | ` -]] ----@field params string? ---[[ -WIPDOC -]] ----@field description string? ---[[ -WIPDOC -]] ----@field privs core.PrivilegeSet? ---[[ -WIPDOC -]] ----@field func core.ChatCommandDef.func - ---[[ -WIPDOC -]] ----@class core.ChatCommandDef.override ---[[ -WIPDOC -]] ----@field func core.ChatCommandDef.func? \ No newline at end of file diff --git a/types/luanti_lsp_definitions/library/defs/colors.lua b/types/luanti_lsp_definitions/library/defs/colors.lua deleted file mode 100644 index 3c170b80..00000000 --- a/types/luanti_lsp_definitions/library/defs/colors.lua +++ /dev/null @@ -1,208 +0,0 @@ ----@meta --- DRAFT 1 DONE --- luanti/doc/lua_api.md: Colors - ---[[ -WIPDOC -]] ----@class core.ColorSpec.tablefmt ---[[ -WIPDOC -]] ----@field a integer? ---[[ -WIPDOC -]] ----@field r integer? ---[[ -WIPDOC -]] ----@field g integer? ---[[ -WIPDOC -]] ----@field b integer? - ---[[ -WIPDOC -]] ----@alias core.ColorString.CSSColors ---- | "aliceblue" ---- | "antiquewhite" ---- | "aqua" ---- | "aquamarine" ---- | "azure" ---- | "beige" ---- | "bisque" ---- | "black" ---- | "blanchedalmond" ---- | "blue" ---- | "blueviolet" ---- | "brown" ---- | "burlywood" ---- | "cadetblue" ---- | "chartreuse" ---- | "chocolate" ---- | "coral" ---- | "cornflowerblue" ---- | "cornsilk" ---- | "crimson" ---- | "cyan" ---- | "darkblue" ---- | "darkcyan" ---- | "darkgoldenrod" ---- | "darkgray" ---- | "darkgreen" ---- | "darkgrey" ---- | "darkkhaki" ---- | "darkmagenta" ---- | "darkolivegreen" ---- | "darkorange" ---- | "darkorchid" ---- | "darkred" ---- | "darksalmon" ---- | "darkseagreen" ---- | "darkslateblue" ---- | "darkslategray" ---- | "darkslategrey" ---- | "darkturquoise" ---- | "darkviolet" ---- | "deeppink" ---- | "deepskyblue" ---- | "dimgray" ---- | "dimgrey" ---- | "dodgerblue" ---- | "firebrick" ---- | "floralwhite" ---- | "forestgreen" ---- | "fuchsia" ---- | "gainsboro" ---- | "ghostwhite" ---- | "gold" ---- | "goldenrod" ---- | "gray" ---- | "green" ---- | "greenyellow" ---- | "grey" ---- | "honeydew" ---- | "hotpink" ---- | "indianred" ---- | "indigo" ---- | "ivory" ---- | "khaki" ---- | "lavender" ---- | "lavenderblush" ---- | "lawngreen" ---- | "lemonchiffon" ---- | "lightblue" ---- | "lightcoral" ---- | "lightcyan" ---- | "lightgoldenrodyellow" ---- | "lightgray" ---- | "lightgreen" ---- | "lightgrey" ---- | "lightpink" ---- | "lightsalmon" ---- | "lightseagreen" ---- | "lightskyblue" ---- | "lightslategray" ---- | "lightslategrey" ---- | "lightsteelblue" ---- | "lightyellow" ---- | "lime" ---- | "limegreen" ---- | "linen" ---- | "magenta" ---- | "maroon" ---- | "mediumaquamarine" ---- | "mediumblue" ---- | "mediumorchid" ---- | "mediumpurple" ---- | "mediumseagreen" ---- | "mediumslateblue" ---- | "mediumspringgreen" ---- | "mediumturquoise" ---- | "mediumvioletred" ---- | "midnightblue" ---- | "mintcream" ---- | "mistyrose" ---- | "moccasin" ---- | "navajowhite" ---- | "navy" ---- | "oldlace" ---- | "olive" ---- | "olivedrab" ---- | "orange" ---- | "orangered" ---- | "orchid" ---- | "palegoldenrod" ---- | "palegreen" ---- | "paleturquoise" ---- | "palevioletred" ---- | "papayawhip" ---- | "peachpuff" ---- | "peru" ---- | "pink" ---- | "plum" ---- | "powderblue" ---- | "purple" ---- | "rebeccapurple" ---- | "red" ---- | "rosybrown" ---- | "royalblue" ---- | "saddlebrown" ---- | "salmon" ---- | "sandybrown" ---- | "seagreen" ---- | "seashell" ---- | "sienna" ---- | "silver" ---- | "skyblue" ---- | "slateblue" ---- | "slategray" ---- | "slategrey" ---- | "snow" ---- | "springgreen" ---- | "steelblue" ---- | "tan" ---- | "teal" ---- | "thistle" ---- | "tomato" ---- | "turquoise" ---- | "violet" ---- | "wheat" ---- | "white" ---- | "whitesmoke" ---- | "yellow" ---- | "yellowgreen" - ---[[ -`#RGB` defines a color in hexadecimal format. - -`#RGBA` defines a color in hexadecimal format and alpha channel. - -`#RRGGBB` defines a color in hexadecimal format. - -`#RRGGBBAA` defines a color in hexadecimal format and alpha channel. - -Named colors are also supported and are equivalent to -[CSS Color Module Level 4](https://www.w3.org/TR/css-color-4/#named-color). -To specify the value of the alpha channel, append `#A` or `#AA` to the end of -the color name (e.g. `colorname#08`). -]] ----@alias core.ColorString ---- | string ---- | core.ColorString.CSSColors - ---[[ -WIPDOC -]] ----@alias core.ColorSpec.numberfmt integer - ---[[ -WIPDOC -]] ----@alias core.ColorSpec ---- | core.ColorSpec.tablefmt ---- | core.ColorString ---- | core.ColorSpec.numberfmt \ No newline at end of file diff --git a/types/luanti_lsp_definitions/library/defs/crafting/cooking.lua b/types/luanti_lsp_definitions/library/defs/crafting/cooking.lua deleted file mode 100644 index e53bda0f..00000000 --- a/types/luanti_lsp_definitions/library/defs/crafting/cooking.lua +++ /dev/null @@ -1,60 +0,0 @@ ----@meta _ --- DRAFT 1 DONE --- luanti/doc/lua_api.md: Groups > Groups in crafting recipes --- luanti/doc/lua_api.md: Definition tables > Crafting recipes - ---[[ -WIPDOC -]] ----@class core.CraftingRecipeDef.cooking.input ---[[ -* `type = "cooking"`: Mandatory -]] ----@field type "cooking" ---[[ -* `recipe`: An itemname of the single input item -]] ----@field recipe core.Item.namelike ---[[ -* `cooktime`: (optional) Time it takes to cook this item, in seconds. - A floating-point number. (default: 3.0) -Note: Games and mods are free to re-interpret the cooktime in special - -]] ----@field cooktime number ---[[ -* `replacements`: (optional) Allows you to replace input items with some other items - when something is crafted - * Provided as a list of item pairs of the form `{ old_item, new_item }` where - `old_item` is the input item to replace (same syntax as for a regular input - slot; groups are allowed) and `new_item` is an itemstring for the item stack - it will become - * When the output is crafted, Luanti iterates through the list - of input items if the crafting grid. For each input item stack, it checks if - it matches with an `old_item` in the item pair list. - * If it matches, the item will be replaced. Also, this item pair - will *not* be applied again for the remaining items - * If it does not match, the item is consumed (reduced by 1) normally - * The `new_item` will appear in one of 3 places: - * Crafting grid, if the input stack size was exactly 1 - * Player inventory, if input stack size was larger - * Drops as item entity, if it fits neither in craft grid or inventory - -Mods that utilize cooking recipes (e.g. for adding a furnace node) need to implement -replacements on their own -]] ----@field replacements [core.Item.namelike, core.Item.name][]? - ---[[ -### Cooking - -A cooking recipe has a single input item, a single output item stack -and a cooking time. It represents cooking/baking/smelting/etc. items in -an oven, furnace, or something similar; the exact meaning is up for games -to decide, if they choose to use cooking at all. - -The engine does not implement anything specific to cooking recipes, but -the recipes can be retrieved later using `core.get_craft_result` to -have a consistent interface across different games/mods. -]] ----@class core.CraftingRecipeDef.cooking : core.CraftingRecipeDef.cooking.input, core.CraftingRecipeDef.output \ No newline at end of file diff --git a/types/luanti_lsp_definitions/library/defs/crafting/crafting.lua b/types/luanti_lsp_definitions/library/defs/crafting/crafting.lua deleted file mode 100644 index 1f9a902f..00000000 --- a/types/luanti_lsp_definitions/library/defs/crafting/crafting.lua +++ /dev/null @@ -1,58 +0,0 @@ ----@meta _ --- DRAFT 1 DONE --- luanti/doc/lua_api.md: Groups > Groups in crafting recipes --- luanti/doc/lua_api.md: 'core' namespace reference > Registration functions > Gameplay --- luanti/doc/lua_api.md: Definition tables > Crafting recipes - ---[[ -WIPDOC -]] ----@class core.CraftingRecipeDef.output ---[[ -* `output`: Itemstring of output itemstack (item counts >= 1 are allowed) -]] ----@field output core.Item.stringfmt - ---[[ -WIPDOC -]] ----@alias core.CraftingRecipeDef.clear ---- | core.CraftingRecipeDef.shaped.input ---- | core.CraftingRecipeDef.shapeless.input ---- | core.CraftingRecipeDef.toolrepair ---- | core.CraftingRecipeDef.cooking.input ---- | core.CraftingRecipeDef.fuel ---- | core.CraftingRecipeDef.output - --- ---------------------------- CraftingRecipeDef --------------------------- -- - ---[[ -Crafting recipes ----------------- - -Crafting converts one or more inputs to one output itemstack of arbitrary -count (except for fuels, which don't have an output). The conversion reduces -each input ItemStack by 1. - -Craft recipes are registered by `core.register_craft` and use a -table format. The accepted parameters are listed below. - -Recipe input items can either be specified by item name (item count = 1) -or by group (see "Groups in crafting recipes" for details). -Only the item name (and groups) matter for matching a recipe, i.e. meta and count -are ignored. - -If multiple recipes match the input of a craft grid, one of them is chosen by the -following priority rules: - -* Shaped recipes are preferred over shapeless recipes, which in turn are preferred - over tool repair. -* Otherwise, recipes without groups are preferred over recipes with groups. -* Otherwise, earlier registered recipes are preferred. -]] ----@alias core.CraftingRecipeDef ---- | core.CraftingRecipeDef.shaped ---- | core.CraftingRecipeDef.shapeless ---- | core.CraftingRecipeDef.toolrepair ---- | core.CraftingRecipeDef.cooking ---- | core.CraftingRecipeDef.fuel diff --git a/types/luanti_lsp_definitions/library/defs/crafting/fuel.lua b/types/luanti_lsp_definitions/library/defs/crafting/fuel.lua deleted file mode 100644 index 4ef44ba4..00000000 --- a/types/luanti_lsp_definitions/library/defs/crafting/fuel.lua +++ /dev/null @@ -1,54 +0,0 @@ ----@meta _ --- DRAFT 1 DONE --- luanti/doc/lua_api.md: Groups > Groups in crafting recipes --- luanti/doc/lua_api.md: Definition tables > Crafting recipes - ---[[ -### Fuel - -A fuel recipe is an item associated with a "burning time" and an optional -item replacement. There is no output. This is usually used as fuel for -furnaces, ovens, stoves, etc. - -Like with cooking recipes, the engine does not do anything specific with -fuel recipes and it's up to games and mods to use them by retrieving -them via `core.get_craft_result`. -]] ----@class core.CraftingRecipeDef.fuel ---[[ -* `type = "fuel"`: Mandatory -]] ----@field type "fuel" ---[[ -* `recipe`: Itemname of the item to be used as fuel -]] ----@field recipe core.Item.namelike ---[[ -* `burntime`: (optional) Burning time this item provides, in seconds. - A floating-point number. (default: 1.0) -Note: Games and mods are free to re-interpret the burntime in special -cases, e.g. for an efficient furnace in which fuels burn twice as -long. -]] ----@field burntime number ---[[ -* `replacements`: (optional) Allows you to replace input items with some other items - when something is crafted - * Provided as a list of item pairs of the form `{ old_item, new_item }` where - `old_item` is the input item to replace (same syntax as for a regular input - slot; groups are allowed) and `new_item` is an itemstring for the item stack - it will become - * When the output is crafted, Luanti iterates through the list - of input items if the crafting grid. For each input item stack, it checks if - it matches with an `old_item` in the item pair list. - * If it matches, the item will be replaced. Also, this item pair - will *not* be applied again for the remaining items - * If it does not match, the item is consumed (reduced by 1) normally - * The `new_item` will appear in one of 3 places: - * Crafting grid, if the input stack size was exactly 1 - * Player inventory, if input stack size was larger - * Drops as item entity, if it fits neither in craft grid or inventory - -Mods that utilize fuels need to implement replacements on their own -]] ----@field replacements [core.Item.namelike, core.Item.name][]? \ No newline at end of file diff --git a/types/luanti_lsp_definitions/library/defs/crafting/shaped.lua b/types/luanti_lsp_definitions/library/defs/crafting/shaped.lua deleted file mode 100644 index a701c85f..00000000 --- a/types/luanti_lsp_definitions/library/defs/crafting/shaped.lua +++ /dev/null @@ -1,65 +0,0 @@ ----@meta _ --- DRAFT 1 DONE --- luanti/doc/lua_api.md: Groups > Groups in crafting recipes --- luanti/doc/lua_api.md: Definition tables > Crafting recipes - ---[[ -WIPDOC -]] ----@class core.CraftingRecipeDef.shaped.input ---[[ -* `type = "shaped"`: (optional) specifies recipe type as shaped -]] ----@field type "shaped"? ---[[ -* `recipe`: A 2-dimensional matrix of items, with a width *w* and height *h*. - * *w* and *h* are chosen by you, they don't have to be equal but must be at least 1 - - * The inner tables are the rows. There must be *h* tables, specified from the top to the bottom row - * Values inside of the inner table are the columns. - Each inner table must contain a list of *w* items, specified from left to right - * Empty slots *must* be filled with the empty string -]] ----@field recipe core.Item.namelike[][] ---[[ -* `replacements`: (optional) Allows you to replace input items with some other items - when something is crafted - * Provided as a list of item pairs of the form `{ old_item, new_item }` where - `old_item` is the input item to replace (same syntax as for a regular input - slot; groups are allowed) and `new_item` is an itemstring for the item stack - it will become - * When the output is crafted, Luanti iterates through the list - of input items if the crafting grid. For each input item stack, it checks if - it matches with an `old_item` in the item pair list. - * If it matches, the item will be replaced. Also, this item pair - will *not* be applied again for the remaining items - * If it does not match, the item is consumed (reduced by 1) normally - * The `new_item` will appear in one of 3 places: - * Crafting grid, if the input stack size was exactly 1 - * Player inventory, if input stack size was larger - * Drops as item entity, if it fits neither in craft grid or inventory -]] ----@field replacements [core.Item.namelike, core.Item.name][]? - ---[[ -### Shaped - -This is the default recipe type (when no `type` is specified). - -A shaped recipe takes one or multiple items as input and has -a single item stack as output. The input items must be specified -in a 2-dimensional matrix (see parameters below) to specify the -exact arrangement (the "shape") in which the player must place them -in the crafting grid. - -For example, for a 3x3 recipe, the `recipes` table must have -3 rows and 3 columns. - -In order to craft the recipe, the players' crafting grid must -have equal or larger dimensions (both width and height). - -Empty slots outside of the recipe's extents are ignored, e.g. a 3x3 -recipe where only the bottom right 2x2 slots are filled is the same -as the corresponding 2x2 recipe without the empty slots.\ -]] ----@class core.CraftingRecipeDef.shaped : core.CraftingRecipeDef.shaped.input, core.CraftingRecipeDef.output \ No newline at end of file diff --git a/types/luanti_lsp_definitions/library/defs/crafting/shapeless.lua b/types/luanti_lsp_definitions/library/defs/crafting/shapeless.lua deleted file mode 100644 index 2c2f6019..00000000 --- a/types/luanti_lsp_definitions/library/defs/crafting/shapeless.lua +++ /dev/null @@ -1,47 +0,0 @@ ----@meta _ --- DRAFT 1 DONE --- luanti/doc/lua_api.md: Groups > Groups in crafting recipes --- luanti/doc/lua_api.md: Definition tables > Crafting recipes - ---[[ -WIPDOC -]] ----@class core.CraftingRecipeDef.shapeless.input ---[[ -* `type = "shapeless"`: Mandatory -]] ----@field type "shapeless" ---[[ -* `recipe`: List of item names -]] ----@field recipe core.Item.namelike[] ---[[ -* `replacements`: (optional) Allows you to replace input items with some other items - when something is crafted - * Provided as a list of item pairs of the form `{ old_item, new_item }` where - `old_item` is the input item to replace (same syntax as for a regular input - slot; groups are allowed) and `new_item` is an itemstring for the item stack - it will become - * When the output is crafted, Luanti iterates through the list - of input items if the crafting grid. For each input item stack, it checks if - it matches with an `old_item` in the item pair list. - * If it matches, the item will be replaced. Also, this item pair - will *not* be applied again for the remaining items - * If it does not match, the item is consumed (reduced by 1) normally - * The `new_item` will appear in one of 3 places: - * Crafting grid, if the input stack size was exactly 1 - * Player inventory, if input stack size was larger - * Drops as item entity, if it fits neither in craft grid or inventory -]] ----@field replacements [core.Item.namelike, core.Item.name][]? - ---[[ -### Shapeless - -Takes a list of input items (at least 1). The order or arrangement -of input items does not matter. - -In order to craft the recipe, the players' crafting grid must have matching or -larger *count* of slots. The grid dimensions do not matter. -]] ----@class core.CraftingRecipeDef.shapeless : core.CraftingRecipeDef.shapeless.input, core.CraftingRecipeDef.output \ No newline at end of file diff --git a/types/luanti_lsp_definitions/library/defs/crafting/toolrepair.lua b/types/luanti_lsp_definitions/library/defs/crafting/toolrepair.lua deleted file mode 100644 index 1afbb8a8..00000000 --- a/types/luanti_lsp_definitions/library/defs/crafting/toolrepair.lua +++ /dev/null @@ -1,52 +0,0 @@ ----@meta _ --- DRAFT 1 DONE --- luanti/doc/lua_api.md: Groups > Groups in crafting recipes --- luanti/doc/lua_api.md: Definition tables > Crafting recipes - ---[[ -### Tool repair - -Syntax: - - { - type = "toolrepair", - additional_wear = -0.02, -- multiplier of 65536 - } - -Adds a shapeless recipe for *every* tool that doesn't have the `disable_repair=1` -group. If this recipe is used, repairing is possible with any crafting grid -with at least 2 slots. -The player can put 2 equal tools in the craft grid to get one "repaired" tool -back. -The wear of the output is determined by the wear of both tools, plus a -'repair bonus' given by `additional_wear`. To reduce the wear (i.e. 'repair'), -you want `additional_wear` to be negative. - -The formula used to calculate the resulting wear is: - - 65536 * (1 - ( (1 - tool_1_wear) + (1 - tool_2_wear) + additional_wear)) - -The result is rounded and can't be lower than 0. If the result is 65536 or higher, -no crafting is possible. -]] ----@class core.CraftingRecipeDef.toolrepair ---[[ -* `type = "toolrepair"`: Mandatory -]] ----@field type "toolrepair" ---[[ -**AMENDMENT** -* `additional_wear`: multiplier of 65536. When repairing by getting a - repaired tool from 2 same tools in the craft grid, the resulting wear is a - combination of the 2 tools and a repair bonus from `additional_wear`. More - precisely, the pseudocode determining the result is: - -```lua -result = 65536 * (1 - ( (1 - tool_1_wear) + (1 - tool_2_wear) + additional_wear ) ) -result = max(0, round(result)) -- rounded and can't be lower than 0 -if result >= 65536 then - -- craft made not possible -end -``` -]] ----@field additional_wear core.Tool.wear \ No newline at end of file diff --git a/types/luanti_lsp_definitions/library/defs/decoration/decoration.lua b/types/luanti_lsp_definitions/library/defs/decoration/decoration.lua deleted file mode 100644 index 1409fd4f..00000000 --- a/types/luanti_lsp_definitions/library/defs/decoration/decoration.lua +++ /dev/null @@ -1,259 +0,0 @@ ----@meta _ --- DRAFT 1 DONE --- luanti/doc/lua_api.md: Flag Specifier Format --- luanti/doc/lua_api.md: Decoration types --- luanti/doc/lua_api.md: Mapgen objects --- luanti/doc/lua_api.md: Definition tables > Decoration definition - ---[[ -WIPDOC -]] ----@class core.DecorationID : integer - --- ------------------------- DecorationDef partials ------------------------- -- - ----@class _.DecorationDef.fill_ratio.__partial ---[[ -The value determines 'decorations per surface node'. -Used only if noise_params is not specified. -If >= 10.0 complete coverage is enabled and decoration placement uses -a different and much faster method. -]] ----@field fill_ratio number? - ----@class _.DecorationDef.noise_params.__partial ---[[ -NoiseParams structure describing the noise used for decoration -distribution. -A noise value is calculated for each square division and determines -'decorations per surface node' within each division. -If the noise value >= 10.0 complete coverage is enabled and -decoration placement uses a different and much faster method. -]] ----@field noise_params core.NoiseParams.3d? - --- -------------------------- DecorationDef.__base -------------------------- -- - ---[[ -WIPDOC -]] ----@alias core.DecorationDef.check_offset ---- | -1 ---- | 0 ---- | 1 - ---[[ -WIPDOC -]] ----@alias core.DecorationDef.biome ---- | string ---- | core.BiomeID ---- | core.BiomeDef - ----@class _.DecorationDef.__base ---[[ -Node (or list of nodes) that the decoration can be placed on -]] ----@field place_on OneOrMany ---[[ -Size of the square (X / Z) divisions of the mapchunk being generated. -Determines the resolution of noise variation if used. -If the chunk size is not evenly divisible by sidelen, sidelen is made -equal to the chunk size. -]] ----@field sidelen integer ---[[ -List of biomes in which this decoration occurs. Occurs in all biomes -if this is omitted, and ignored if the Mapgen being used does not -support biomes. -Can be a list of (or a single) biome names, IDs, or definitions. -]] ----@field biomes OneOrMany? ---[[ -*@default* `-31000` - -Lower limit for decoration (inclusive). -Refer to the Y coordinate of the 'place_on' node. -]] ----@field y_min integer? ---[[ -*@default* `31000` - -Upper limit for decoration (inclusive). -Refer to the Y coordinate of the 'place_on' node. -]] ----@field y_max integer? ---[[ -Node (or list of nodes) that the decoration only spawns next to. -Checks the 8 neighboring nodes on the same height, -and also the ones at the height plus the check_offset, excluding both center nodes. -]] ----@field spawn_by OneOrMany? ---[[ -*@default* `0` - -Specifies the offset that spawn_by should also check -The default value of -1 is useful to e.g check for water next to the base node. -0 disables additional checks, valid values: {-1, 0, 1} -]] ----@field check_offset core.DecorationDef.check_offset? ---[[ -Number of spawn_by nodes that must be surrounding the decoration -position to occur. -If absent or -1, decorations occur next to any nodes. -]] ----@field num_spawn_by integer? ---[[ -Flags for all decoration types. -- "liquid_surface": Find the highest liquid (not solid) surface under - open air. Search stops and fails on the first solid node. - Cannot be used with "all_floors" or "all_ceilings" below. -- "force_placement": Nodes other than "air" and "ignore" are replaced - by the decoration. -- "all_floors", "all_ceilings": Instead of placement on the highest - surface in a mapchunk the decoration is placed on all floor and/or - ceiling surfaces, for example in caves and dungeons. - Ceiling decorations act as an inversion of floor decorations so the - effect of 'place_offset_y' is inverted. - Y-slice probabilities do not function correctly for ceiling - schematic decorations as the behavior is unchanged. - If a single decoration registration has both flags the floor and - ceiling decorations will be aligned vertically. -]] ----@field flags core.DecorationDef.flags? - --- -------------------------- DecorationDef.simple -------------------------- -- - ----@class _.DecorationDef.simple.fill_ratio : _.DecorationDef.__base, _.DecorationDef.fill_ratio.__partial, _.DecorationDef.simple.__partial ----@class _.DecorationDef.simple.noise_params : _.DecorationDef.__base, _.DecorationDef.noise_params.__partial, _.DecorationDef.simple.__partial - ---[[ -WIPDOC -]] ----@alias core.DecorationDef.simple ---- | _.DecorationDef.simple.fill_ratio ---- | _.DecorationDef.simple.noise_params - ----@class _.DecorationDef.simple.__partial ---[[ -Type. "simple", "schematic" or "lsystem" supported -]] ----@field deco_type "simple" ---[[ -The node name used as the decoration. -If instead a list of strings, a randomly selected node from the list -is placed as the decoration. -]] ----@field decoration OneOrMany ---[[ -*@default* `1` - -Decoration height in nodes. -If height_max is not 0, this is the lower limit of a randomly -selected height. -]] ----@field height integer? ---[[ -Upper limit of the randomly selected height. -If absent, the parameter 'height' is used as a constant. -]] ----@field height_max integer? ---[[ -*@default* `0` - -Param2 value of decoration nodes. -If param2_max is not 0, this is the lower limit of a randomly -selected param2. -]] ----@field param2 core.Param2? ---[[ -*@default* `0` - -Upper limit of the randomly selected param2. -If absent, the parameter 'param2' is used as a constant. -]] ----@field param2_max core.Param2? ---[[ -Y offset of the decoration base node relative to the standard base -node position. -Can be positive or negative. Default is 0. -Effect is inverted for "all_ceilings" decorations. -Ignored by 'y_min', 'y_max' and 'spawn_by' checks, which always refer -to the 'place_on' node. -]] ----@field place_offset_y integer? - --- ------------------------- DecorationDef.schematic ------------------------ -- - ----@class _.DecorationDef.schematic.fill_ratio : _.DecorationDef.__base, _.DecorationDef.fill_ratio.__partial, _.DecorationDef.schematic.__partial ----@class _.DecorationDef.schematic.noise_params : _.DecorationDef.__base, _.DecorationDef.noise_params.__partial, _.DecorationDef.schematic.__partial - ---[[ -WIPDOC -]] ----@alias core.DecorationDef.schematic ---- | _.DecorationDef.schematic.fill_ratio ---- | _.DecorationDef.schematic.noise_params - ----@class _.DecorationDef.schematic.__partial ---[[ -Type. "simple", "schematic" or "lsystem" supported -]] ----@field deco_type "schematic" ---[[ -If schematic is a string, it is the filepath relative to the current -working directory of the specified Luanti schematic file. -Could also be the ID of a previously registered schematic. -]] ----@field schematic core.Schematic ---[[ -Map of node names to replace in the schematic after reading it. -]] ----@field replacements table? ---[[ -Rotation can be "0", "90", "180", "270", or "random" -]] ----@field rotation core.Schematic.rotation? ---[[ -Y offset of the decoration base node relative to the standard base -node position. -Can be positive or negative. Default is 0. -Effect is inverted for "all_ceilings" decorations. -Ignored by 'y_min', 'y_max' and 'spawn_by' checks, which always refer -to the 'place_on' node. -]] ----@field place_offset_y integer? ---[[ -WIPDOC -]] ----@field flags core.DecorationDef.schematic.flags - --- -------------------------- DecorationDef.lsystem ------------------------- -- - ----@class _.DecorationDef.lsystem.fill_ratio : _.DecorationDef.__base, _.DecorationDef.fill_ratio.__partial, _.DecorationDef.lsystem.__partial ----@class _.DecorationDef.lsystem.noise_params : _.DecorationDef.__base, _.DecorationDef.noise_params.__partial, _.DecorationDef.lsystem.__partial - ---[[ -WIPDOC -]] ----@alias core.DecorationDef.lsystem ---- | _.DecorationDef.lsystem.fill_ratio ---- | _.DecorationDef.lsystem.noise_params - ----@class _.DecorationDef.lsystem.__partial ---[[ -Type. "simple", "schematic" or "lsystem" supported -]] ----@field deco_type "lsystem" ---[[ -Same as for `core.spawn_tree`. -See section [L-system trees] for more details. -]] ----@field treedef core.LSystemTreeDef - --- ------------------------------ DecorationDef ----------------------------- -- - ----@alias core.DecorationDef ---- | core.DecorationDef.simple ---- | core.DecorationDef.schematic ---- | core.DecorationDef.lsystem \ No newline at end of file diff --git a/types/luanti_lsp_definitions/library/defs/decoration/flags.lua b/types/luanti_lsp_definitions/library/defs/decoration/flags.lua deleted file mode 100644 index 3423fed6..00000000 --- a/types/luanti_lsp_definitions/library/defs/decoration/flags.lua +++ /dev/null @@ -1,96 +0,0 @@ ----@meta _ --- DRAFT 1 DONE --- luanti/doc/lua_api.md: Flag Specifier Format --- luanti/doc/lua_api.md: Decoration types --- luanti/doc/lua_api.md: Mapgen objects --- luanti/doc/lua_api.md: Definition tables > Decoration definition - --- --------------------------- DecorationDef.flags -------------------------- -- - ----@class _.DecorationDef.flags.tablefmt.__base ---[[ -WIPDOC -]] ----@field force_placement boolean? ---[[ -WIPDOC -]] ----@field noforce_placement boolean? - ----@class _.DecorationDef.flags.tablefmt.liquid_surface : _.DecorationDef.flags.tablefmt.__base ---[[ -WIPDOC -]] ----@field liquid_surface boolean? ---[[ -WIPDOC -]] ----@field noliquid_surface boolean? - ----@class _.DecorationDef.flags.tablefmt.all : _.DecorationDef.flags.tablefmt.__base ---[[ -WIPDOC -]] ----@field all_floors boolean? ---[[ -WIPDOC -]] ----@field noall_floors boolean? ---[[ -WIPDOC -]] ----@field all_ceilings boolean? ---[[ -WIPDOC -]] ----@field noall_ceilings boolean? - ---[[ -WIPDOC -]] ----@alias core.DecorationDef.flags.tablefmt ---- | _.DecorationDef.flags.tablefmt.liquid_surface ---- | _.DecorationDef.flags.tablefmt.all - ---[[ -WIPDOC -]] ----@alias core.DecorationDef.flags.stringfmt string - ---[[ -WIPDOC -]] ----@alias core.DecorationDef.flags ---- | core.DecorationDef.flags.tablefmt ---- | core.DecorationDef.flags.stringfmt - --- ------------------- core.DecorationDef.schematic.flags ------------------- -- - ---[[ -WIPDOC -]] ----@class core.DecorationDef.schematic.flags.tablefmt.liquid_surface : _.DecorationDef.flags.tablefmt.liquid_surface, core.Schematic.flags.tablefmt - ---[[ -WIPDOC -]] ----@class core.DecorationDef.schematic.flags.tablefmt.all : _.DecorationDef.flags.tablefmt.all, core.Schematic.flags.tablefmt - ---[[ -WIPDOC -]] ----@alias core.DecorationDef.schematic.flags.tablefmt ---- | core.DecorationDef.schematic.flags.tablefmt.liquid_surface ---- | core.DecorationDef.schematic.flags.tablefmt.all - ---[[ -WIPDOC -]] ----@alias core.DecorationDef.schematic.flags.stringfmt string - ---[[ -WIPDOC -]] ----@alias core.DecorationDef.schematic.flags ---- | core.DecorationDef.schematic.flags.tablefmt ---- | core.DecorationDef.schematic.flags.stringfmt \ No newline at end of file diff --git a/types/luanti_lsp_definitions/library/defs/detached_inventory.lua b/types/luanti_lsp_definitions/library/defs/detached_inventory.lua deleted file mode 100644 index 9f5b190e..00000000 --- a/types/luanti_lsp_definitions/library/defs/detached_inventory.lua +++ /dev/null @@ -1,62 +0,0 @@ ----@meta _ --- DRAFT 1 DONE --- luanti/doc/lua_api.md: Definition tables > Detached inventory callbacks - ---[[ -WIPDOC -]] ----@alias core.DetachedInventoryCallbacks.allow_move fun(inv:core.InvRef, from_list:core.InventoryList, from_index:integer, to_list:core.InventoryList, to_index:integer, count:integer, player:core.PlayerRef):integer? - ---[[ -WIPDOC -]] ----@alias core.DetachedInventoryCallbacks.allow_put fun(inv:core.InvRef, listname:core.InventoryList, index:integer, stack:core.ItemStack, player:core.PlayerRef):integer? - ---[[ -WIPDOC -]] ----@alias core.DetachedInventoryCallbacks.allow_take fun(inv:core.InvRef, listname:core.InventoryList, index:integer, stack:core.ItemStack, player:core.PlayerRef):integer? - ---[[ -WIPDOC -]] ----@alias core.DetachedInventoryCallbacks.on_move fun(inv:core.InvRef, from_list:core.InventoryList, from_index:integer, to_list:core.InventoryList, to_index:integer, count:integer, player:core.PlayerRef) - ---[[ -WIPDOC -]] ----@alias core.DetachedInventoryCallbacks.on_put fun(inv:core.InvRef, listname:core.InventoryList, index:integer, stack:core.ItemStack, player:core.PlayerRef) - ---[[ -WIPDOC -]] ----@alias core.DetachedInventoryCallbacks.on_take fun(inv:core.InvRef, listname:core.InventoryList, index:integer, stack:core.ItemStack, player:core.PlayerRef) - ---[[ -WIPDOC -]] ----@class core.DetachedInventoryCallbacks ---[[ -WIPDOC -]] ----@field allow_move core.DetachedInventoryCallbacks.allow_move? ---[[ -WIPDOC -]] ----@field allow_put core.DetachedInventoryCallbacks.allow_put? ---[[ -WIPDOC -]] ----@field allow_take core.DetachedInventoryCallbacks.allow_take? ---[[ -WIPDOC -]] ----@field on_move core.DetachedInventoryCallbacks.on_move? ---[[ -WIPDOC -]] ----@field on_put core.DetachedInventoryCallbacks.on_put? ---[[ -WIPDOC -]] ----@field on_take core.DetachedInventoryCallbacks.on_take? diff --git a/types/luanti_lsp_definitions/library/defs/entity/collision.lua b/types/luanti_lsp_definitions/library/defs/entity/collision.lua deleted file mode 100644 index 86b55423..00000000 --- a/types/luanti_lsp_definitions/library/defs/entity/collision.lua +++ /dev/null @@ -1,62 +0,0 @@ ----@meta _ --- DRAFT 1 DONE --- luanti/doc/lua_api.md: Registered entities - --- ------------------------- Entity.collision.__base ------------------------ -- - ----@class _.Entity.collision.__base ---[[ -WIPDOC -]] ----@field axis "x"|"y"|"z" ---[[ -WIPDOC -]] ----@field new_pos vector ---[[ -WIPDOC -]] ----@field old_velocity vector ---[[ -WIPDOC -]] ----@field new_velocity vector - --- -------------------------- Entity.collision.node ------------------------- -- - ---[[ -WIPDOC -]] ----@class core.Entity.collision.node : _.Entity.collision.__base ---[[ -WIPDOC -]] ----@field type "node" ---[[ -WIPDOC -]] ----@field node_pos vector - --- ------------------------- Entity.collision.object ------------------------ -- - ---[[ -WIPDOC -]] ----@class core.Entity.collision.object : _.Entity.collision.__base ---[[ -WIPDOC -]] ----@field type "object" ---[[ -WIPDOC -]] ----@field object core.ObjectRef - --- ---------------------------- Entity.collision ---------------------------- -- - ---[[ -WIPDOC -]] ----@alias core.Entity.collision ---- | core.Entity.collision.node ---- | core.Entity.collision.object \ No newline at end of file diff --git a/types/luanti_lsp_definitions/library/defs/entity/entity.lua b/types/luanti_lsp_definitions/library/defs/entity/entity.lua deleted file mode 100644 index ea16f9e2..00000000 --- a/types/luanti_lsp_definitions/library/defs/entity/entity.lua +++ /dev/null @@ -1,140 +0,0 @@ ----@meta _ --- DRAFT 1 DONE --- luanti/doc/lua_api.md: Registered entities --- luanti/doc/lua_api.md: Definition tables > Entity definition - ---[[ -WIPDOC -]] ----@alias core.Entity.name string - ---[[ -WIPDOC -]] ----@alias core.Entity.namelike ---- | core.Groups.armor ---- | core.Entity.name - --- -------------------------------- EntityDef ------------------------------- -- - ---[[ -WIPDOC -]] ----@alias core.EntityDef.on_activate fun(self:core.Entity, staticdata:string, dtime_s:number) - ---[[ -WIPDOC -]] ----@alias core.EntityDef.on_deactivate fun(self:core.Entity, removal:boolean) - ---[[ -WIPDOC -]] ----@alias core.EntityDef.on_step fun(self:core.Entity, dtime:number, moveresult:core.Entity.moveresult?) - ---[[ -WIPDOC -]] ----@alias core.EntityDef.on_punch fun(self:core.Entity, puncher:core.EntityRef?, ime_from_last_punch:number?, tool_capabilities:core.ToolCapabilities?, dir:vector, damage:integer):boolean - ---[[ -WIPDOC -]] ----@alias core.EntityDef.on_death fun(self:core.Entity, killer:core.EntityRef?) - ---[[ -WIPDOC -]] ----@alias core.EntityDef.on_rightclick fun(self:core.Entity, clicker:core.EntityRef) - ---[[ -WIPDOC -]] ----@alias core.EntityDef.on_attach_child fun(self:core.Entity, child:core.EntityRef) - ---[[ -WIPDOC -]] ----@alias core.EntityDef.on_detach_child fun(self:core.Entity, child:core.EntityRef) - ---[[ -WIPDOC -]] ----@alias core.EntityDef.on_detach fun(self:core.Entity, parent:core.EntityRef) - ---[[ -WIPDOC -]] ----@alias core.EntityDef.get_staticdata fun(self:core.Entity):string - ---[[ -WIPDOC -]] ----@class core.EntityDef ---[[ -WIPDOC -]] ----@field initial_properties core.ObjectProperties.set ---[[ -WIPDOC -]] ----@field on_activate core.EntityDef.on_activate? ---[[ -WIPDOC -]] ----@field on_deactivate core.EntityDef.on_deactivate? ---[[ -WIPDOC -]] ----@field on_step core.EntityDef.on_step? ---[[ -WIPDOC -]] ----@field on_punch core.EntityDef.on_punch? ---[[ -WIPDOC -]] ----@field on_death core.EntityDef.on_death? ---[[ -WIPDOC -]] ----@field on_rightclick core.EntityDef.on_rightclick? ---[[ -WIPDOC -]] ----@field on_attach_child core.EntityDef.on_attach_child? ---[[ -WIPDOC -]] ----@field on_detach_child core.EntityDef.on_detach_child? ---[[ -WIPDOC -]] ----@field on_detach core.EntityDef.on_detach? ---[[ -WIPDOC -]] ----@field get_staticdata core.EntityDef.get_staticdata? - --- --------------------------------- Entity --------------------------------- -- - ---[[ -Functions receive a "luaentity" table as `self`: - -* It has the member `name`, which is the registered name `("mod:thing")` -* It has the member `object`, which is an `core.EntityRef` pointing to the object -* The original prototype is visible directly via a metatable -]] ----@class core.Entity : core.EntityDef ---[[ -WIPDOC -]] ----@field initial_properties core.ObjectProperties.set ---[[ -WIPDOC -]] ----@field name core.Entity.name ---[[ -WIPDOC -]] ----@field object core.EntityRef diff --git a/types/luanti_lsp_definitions/library/defs/entity/moveresult.lua b/types/luanti_lsp_definitions/library/defs/entity/moveresult.lua deleted file mode 100644 index 665f8350..00000000 --- a/types/luanti_lsp_definitions/library/defs/entity/moveresult.lua +++ /dev/null @@ -1,26 +0,0 @@ ----@meta _ --- DRAFT 1 DONE --- luanti/doc/lua_api.md: Registered entities - --- ---------------------------- Entity.moveresult --------------------------- -- - ---[[ -WIPDOC -]] ----@class core.Entity.moveresult ---[[ -WIPDOC -]] ----@field touching_ground boolean ---[[ -WIPDOC -]] ----@field collides boolean ---[[ -WIPDOC -]] ----@field standing_on_object boolean ---[[ -WIPDOC -]] ----@field collisions core.Entity.collision[] diff --git a/types/luanti_lsp_definitions/library/defs/formspec.lua b/types/luanti_lsp_definitions/library/defs/formspec.lua deleted file mode 100644 index a81b5212..00000000 --- a/types/luanti_lsp_definitions/library/defs/formspec.lua +++ /dev/null @@ -1,8 +0,0 @@ ----@meta _ --- DRAFT 1 DONE --- luanti/doc/lua_api.md: Formspec - ---[[ -WIPDOC -]] ----@alias core.Formspec string \ No newline at end of file diff --git a/types/luanti_lsp_definitions/library/defs/group.lua b/types/luanti_lsp_definitions/library/defs/group.lua deleted file mode 100644 index a10f1d7a..00000000 --- a/types/luanti_lsp_definitions/library/defs/group.lua +++ /dev/null @@ -1,172 +0,0 @@ ----@meta _ --- DRAFT 1 DONE --- luanti/doc/lua_api.md: Groups - --- ------------------------------- Groups.item ------------------------------ -- - ---[[ -WIPDOC -]] ----@class core.Groups.item : {[string]:integer} ---[[ -WIPDOC -]] ----@field not_in_creative_inventory integer? - --- ------------------------------- Groups.node ------------------------------ -- - ---[[ -WIPDOC -]] ----@alias core.Groups.special.attached_node ---- | 0 ---- | 1 ---- | 2 ---- | 3 ---- | 4 ---- | integer - ---[[ -WIPDOC -]] ----@alias core.Groups.special.dig_immediate ---- | 0 ---- | 1 ---- | 2 ---- | 3 ---- | integer - ---[[ -WIPDOC -]] ----@alias core.Groups.special.disable_jump ---- | 0 ---- | 1 ---- | integer - ---[[ -WIPDOC -]] ----@alias core.Groups.special.disable_descend ---- | 0 ---- | 1 ---- | integer - ---[[ -WIPDOC -]] ----@alias core.Groups.special.falling_node ---- | 0 ---- | 1 ---- | integer - ---[[ -WIPDOC -]] ----@alias core.Groups.special.float ---- | 0 ---- | 1 ---- | integer - ---[[ -WIPDOC -]] ----@class core.Groups.node : core.Groups.item ---[[ -WIPDOC -]] ----@field attached_node core.Groups.special.attached_node? ---[[ -WIPDOC -]] ----@field bouncy integer? ---[[ -WIPDOC -]] ----@field connect_to_raillike integer? ---[[ -WIPDOC -]] ----@field dig_immediate core.Groups.special.dig_immediate? ---[[ -WIPDOC -]] ----@field disable_jump core.Groups.special.disable_jump? ---[[ -WIPDOC -]] ----@field disable_descend core.Groups.special.disable_descend? ---[[ -WIPDOC -]] ----@field fall_damage_add_percent integer? ---[[ -WIPDOC -]] ----@field falling_node core.Groups.special.falling_node? ---[[ -WIPDOC -]] ----@field float core.Groups.special.float? ---[[ -WIPDOC -]] ----@field level integer? ---[[ -WIPDOC -]] ----@field slippery integer? - --- ------------------------------- Groups.tool ------------------------------ -- - ---[[ -WIPDOC -]] ----@alias core.Groups.special.disable_repair ---- | 0 ---- | 1 ---- | integer - ---[[ -WIPDOC -]] ----@class core.Groups.tool : core.Groups.item ---[[ -WIPDOC -]] ----@field disable_repair core.Groups.special.disable_repair? - --- ------------------------------ Groups.armor ------------------------------ -- - ---[[ -WIPDOC -]] ----@alias core.Groups.special.immortal ---- | 0 ---- | 1 ---- | integer - ---[[ -WIPDOC -]] ----@alias core.Groups.special.punch_operable ---- | 0 ---- | 1 ---- | integer - ---[[ -WIPDOC -]] ----@class core.Groups.armor : {[string]:integer} ---[[ -WIPDOC -]] ----@field immortal core.Groups.special.immortal? ---[[ -WIPDOC -]] ----@field fall_damage_add_percent integer? ---[[ -WIPDOC -]] ----@field punch_operable core.Groups.special.punch_operable? \ No newline at end of file diff --git a/types/luanti_lsp_definitions/library/defs/hud/compass.lua b/types/luanti_lsp_definitions/library/defs/hud/compass.lua deleted file mode 100644 index c71c96ed..00000000 --- a/types/luanti_lsp_definitions/library/defs/hud/compass.lua +++ /dev/null @@ -1,65 +0,0 @@ ----@meta _ --- DRAFT 1 DONE --- luanti/doc/lua_api.md: HUD --- luanti/doc/lua_api.md: Definition tables > HUD Definition - ---[[ -WIPDOC -]] ----@alias core.HUDDef.compass.regular.direction ---- | 0 ---- | 1 - ---[[ -WIPDOC -]] ----@alias core.HUDDef.compass.scalable.direction ---- | 2 ---- | 3 - ---[[ -WIPDOC -]] ----@class core.HUDDef.compass.regular : _.HUDDef.__base, _.HUDDef.position, _.HUDDef.alignment ---[[ -WIPDOC -]] ----@field type "compass" ---[[ -* `direction`: How the image is rotated/translated: - * 0 - Rotate as heading direction - * 1 - Rotate in reverse direction - * 2 - Translate as landscape direction - * 3 - Translate in reverse direction - -If translation is chosen, texture is repeated horizontally to fill the whole element. -]] ----@field direction core.HUDDef.compass.regular.direction? ---[[ -WIPDOC -]] ----@field text string ---[[ -WIPDOC -]] ----@field size vec2.xy - ---[[ -WIPDOC -]] ----@class core.HUDDef.compass.scalable ---[[ -WIPDOC -]] ----@field scale vec2.xy? ---[[ -WIPDOC -]] ----@field direction core.HUDDef.compass.scalable.direction - ---[[ -WIPDOC -]] ----@alias core.HUDDef.compass ---- | core.HUDDef.compass.regular ---- | core.HUDDef.compass.scalable \ No newline at end of file diff --git a/types/luanti_lsp_definitions/library/defs/hud/hotbar.lua b/types/luanti_lsp_definitions/library/defs/hud/hotbar.lua deleted file mode 100644 index 818ee4c5..00000000 --- a/types/luanti_lsp_definitions/library/defs/hud/hotbar.lua +++ /dev/null @@ -1,13 +0,0 @@ ----@meta _ --- DRAFT 1 DONE --- luanti/doc/lua_api.md: HUD --- luanti/doc/lua_api.md: Definition tables > HUD Definition - ---[[ -WIPDOC -]] ----@class core.HUDDef.hotbar : _.HUDDef.__base, _.HUDDef.position, _.HUDDef.direction, _.HUDDef.alignment ---[[ -WIPDOC -]] ----@field type "hotbar" diff --git a/types/luanti_lsp_definitions/library/defs/hud/hud.lua b/types/luanti_lsp_definitions/library/defs/hud/hud.lua deleted file mode 100644 index cb3b2152..00000000 --- a/types/luanti_lsp_definitions/library/defs/hud/hud.lua +++ /dev/null @@ -1,100 +0,0 @@ ----@meta _ --- DRAFT 1 DONE --- luanti/doc/lua_api.md: HUD --- luanti/doc/lua_api.md: Definition tables > HUD Definition - ---[[ -WIPDOC -]] ----@class core.HUDID : integer - ---[[ -WIPDOC -]] ----@alias core.HUDDef.keys ---- | "position" ---- | "name" ---- | "scale" ---- | "text" ---- | "text2" ---- | "number" ---- | "item" ---- | "direction" ---- | "alignment" ---- | "offset" ---- | "world_pos" ---- | "size" ---- | "z_index" ---- | "style" ---- | "precision" - --- ------------------------------ HUDDef.__base ----------------------------- -- - ----@class _.HUDDef.__base ---[[ -WIPDOC -]] ----@field type "image" ---[[ -WIPDOC -]] ----@field name string ---[[ -WIPDOC -]] ----@field offset vec2.xy? ---[[ -WIPDOC -]] ----@field z_index integer - --- ----------------------------- HUDDef partials ---------------------------- -- - ----@class _.HUDDef.position ---[[ -Top left corner position of element -]] ----@field position vec2.xy - ---[[ -WIPDOC -]] ----@alias core.HUDDef.direction ---- | 0 ---- | 1 ---- | 2 ---- | 3 - ----@class _.HUDDef.direction ---[[ -WIPDOC -]] ----@field direction core.HUDDef.direction? - ----@class _.HUDDef.alignment ---[[ -WIPDOC -]] ----@field alignment vec2.xy? - ----@class _.HUDDef.world_pos ---[[ -WIPDOC -]] ----@field world_pos vec? - --- --------------------------------- HUDDef --------------------------------- -- - ---[[ -WIPDOC -]] ----@alias core.HUDDef ---- | core.HUDDef.image ---- | core.HUDDef.text ---- | core.HUDDef.statbar ---- | core.HUDDef.inventory ---- | core.HUDDef.hotbar ---- | core.HUDDef.waypoint ---- | core.HUDDef.image_waypoint ---- | core.HUDDef.compass ---- | core.HUDDef.minimap \ No newline at end of file diff --git a/types/luanti_lsp_definitions/library/defs/hud/image.lua b/types/luanti_lsp_definitions/library/defs/hud/image.lua deleted file mode 100644 index 80c4756f..00000000 --- a/types/luanti_lsp_definitions/library/defs/hud/image.lua +++ /dev/null @@ -1,21 +0,0 @@ ----@meta _ --- DRAFT 1 DONE --- luanti/doc/lua_api.md: HUD --- luanti/doc/lua_api.md: Definition tables > HUD Definition - ---[[ -WIPDOC -]] ----@class core.HUDDef.image : _.HUDDef.__base, _.HUDDef.position, _.HUDDef.alignment ---[[ -WIPDOC -]] ----@field type "image" ---[[ -WIPDOC -]] ----@field scale vec2.xy? ---[[ -WIPDOC -]] ----@field text string diff --git a/types/luanti_lsp_definitions/library/defs/hud/image_waypoint.lua b/types/luanti_lsp_definitions/library/defs/hud/image_waypoint.lua deleted file mode 100644 index ce170979..00000000 --- a/types/luanti_lsp_definitions/library/defs/hud/image_waypoint.lua +++ /dev/null @@ -1,24 +0,0 @@ ----@meta _ --- DRAFT 1 DONE --- luanti/doc/lua_api.md: HUD --- luanti/doc/lua_api.md: Definition tables > HUD Definition - --- NOTE: while it *might* look like image_waypoint should derive from waypoint, --- that is false. It's instead derived from image - ---[[ -WIPDOC -]] ----@class core.HUDDef.image_waypoint : _.HUDDef.__base, _.HUDDef.alignment, _.HUDDef.world_pos ---[[ -WIPDOC -]] ----@field type "image_waypoint" ---[[ -WIPDOC -]] ----@field scale vec2.xy? ---[[ -WIPDOC -]] ----@field text string diff --git a/types/luanti_lsp_definitions/library/defs/hud/inventory.lua b/types/luanti_lsp_definitions/library/defs/hud/inventory.lua deleted file mode 100644 index 1d4aec1a..00000000 --- a/types/luanti_lsp_definitions/library/defs/hud/inventory.lua +++ /dev/null @@ -1,25 +0,0 @@ ----@meta _ --- DRAFT 1 DONE --- luanti/doc/lua_api.md: HUD --- luanti/doc/lua_api.md: Definition tables > HUD Definition - ---[[ -WIPDOC -]] ----@class core.HUDDef.inventory : _.HUDDef.__base, _.HUDDef.position, _.HUDDef.direction, _.HUDDef.alignment ---[[ -WIPDOC -]] ----@field type "inventory" ---[[ -WIPDOC -]] ----@field text string ---[[ -WIPDOC -]] ----@field number integer? ---[[ -WIPDOC -]] ----@field item integer? diff --git a/types/luanti_lsp_definitions/library/defs/hud/minimap.lua b/types/luanti_lsp_definitions/library/defs/hud/minimap.lua deleted file mode 100644 index 562693b3..00000000 --- a/types/luanti_lsp_definitions/library/defs/hud/minimap.lua +++ /dev/null @@ -1,17 +0,0 @@ ----@meta _ --- DRAFT 1 DONE --- luanti/doc/lua_api.md: HUD --- luanti/doc/lua_api.md: Definition tables > HUD Definition - ---[[ -WIPDOC -]] ----@class core.HUDDef.minimap : _.HUDDef.__base, _.HUDDef.position, _.HUDDef.alignment ---[[ -WIPDOC -]] ----@field type "minimap" ---[[ -WIPDOC -]] ----@field size vec2.xy? diff --git a/types/luanti_lsp_definitions/library/defs/hud/statbar.lua b/types/luanti_lsp_definitions/library/defs/hud/statbar.lua deleted file mode 100644 index 7a03834d..00000000 --- a/types/luanti_lsp_definitions/library/defs/hud/statbar.lua +++ /dev/null @@ -1,33 +0,0 @@ ----@meta _ --- DRAFT 1 DONE --- luanti/doc/lua_api.md: HUD --- luanti/doc/lua_api.md: Definition tables > HUD Definition - ---[[ -WIPDOC -]] ----@class core.HUDDef.statbar : _.HUDDef.__base, _.HUDDef.position, _.HUDDef.direction ---[[ -WIPDOC -]] ----@field type "statbar" ---[[ -WIPDOC -]] ----@field text string ---[[ -WIPDOC -]] ----@field text2 string? ---[[ -WIPDOC -]] ----@field number integer ---[[ -WIPDOC -]] ----@field item integer ---[[ -WIPDOC -]] ----@field size vec2.xy? diff --git a/types/luanti_lsp_definitions/library/defs/hud/text.lua b/types/luanti_lsp_definitions/library/defs/hud/text.lua deleted file mode 100644 index 60239905..00000000 --- a/types/luanti_lsp_definitions/library/defs/hud/text.lua +++ /dev/null @@ -1,46 +0,0 @@ ----@meta _ --- DRAFT 1 DONE --- luanti/doc/lua_api.md: HUD --- luanti/doc/lua_api.md: Definition tables > HUD Definition - ---[[ -WIPDOC -]] ----@alias core.HUDDef.text.style ---- | 0 ---- | 1 ---- | 2 ---- | 3 ---- | 4 ---- | 5 ---- | 6 ---- | 7 - ---[[ -WIPDOC -]] ----@class core.HUDDef.text : _.HUDDef.__base, _.HUDDef.position, _.HUDDef.alignment ---[[ -WIPDOC -]] ----@field type "text" ---[[ -WIPDOC -]] ----@field scale vec2.xy ---[[ -WIPDOC -]] ----@field text string ---[[ -WIPDOC -]] ----@field number integer? ---[[ -WIPDOC -]] ----@field size vec2.xy? ---[[ -WIPDOC -]] ----@field style core.HUDDef.text.style? diff --git a/types/luanti_lsp_definitions/library/defs/hud/waypoint.lua b/types/luanti_lsp_definitions/library/defs/hud/waypoint.lua deleted file mode 100644 index aa18999e..00000000 --- a/types/luanti_lsp_definitions/library/defs/hud/waypoint.lua +++ /dev/null @@ -1,25 +0,0 @@ ----@meta _ --- DRAFT 1 DONE --- luanti/doc/lua_api.md: HUD --- luanti/doc/lua_api.md: Definition tables > HUD Definition - ---[[ -WIPDOC -]] ----@class core.HUDDef.waypoint : _.HUDDef.__base, _.HUDDef.position, _.HUDDef.alignment, _.HUDDef.world_pos ---[[ -WIPDOC -]] ----@field type "waypoint" ---[[ -WIPDOC -]] ----@field text string? ---[[ -WIPDOC -]] ----@field precision integer? ---[[ -WIPDOC -]] ----@field number integer? diff --git a/types/luanti_lsp_definitions/library/defs/inventory.lua b/types/luanti_lsp_definitions/library/defs/inventory.lua deleted file mode 100644 index 4304d3fa..00000000 --- a/types/luanti_lsp_definitions/library/defs/inventory.lua +++ /dev/null @@ -1,83 +0,0 @@ ----@meta _ --- DRAFT 1 DONE --- luanti/doc/lua_api.md: Inventory --- luanti/doc/lua_api.md: Class reference > `InvRef` --- luanti/doc/lua_api.md: Class reference > `MetaDataRef` - --- ------------------------------ InventoryList ----------------------------- -- - ---[[ -WIPDOC -]] ----@alias core.InventoryList ---- | "main" ---- | "craft" ---- | "craftpreview" ---- | "craftresult" ---- | "hand" ---- | string - --- -------------------------------- InventoryTable -------------------------------- -- - ---[[ -WIPDOC -]] ----@alias core.ItemList.stringfmt SparseList - ---[[ -WIPDOC -]] ----@class core.InventoryTable.stringfmt : {[core.InventoryList]:core.ItemList.stringfmt?} ---[[ -WIPDOC -]] ----@field main core.ItemList.stringfmt? ---[[ -WIPDOC -]] ----@field craft core.ItemList.stringfmt? ---[[ -WIPDOC -]] ----@field craftpreview core.ItemList.stringfmt? ---[[ -WIPDOC -]] ----@field craftresult core.ItemList.stringfmt? ---[[ -WIPDOC -]] ----@field hand core.ItemList.stringfmt? - ---[[ -WIPDOC -]] ----@alias core.ItemList SparseList - ---[[ -* inventory table keys are inventory list names -* inventory table values are item tables -* item table keys are slot IDs (starting with 1) -* item table values are ItemStacks -]] ----@class core.InventoryTable : {[core.InventoryList]:core.ItemList} ---[[ -WIPDOC -]] ----@field main core.ItemList? ---[[ -WIPDOC -]] ----@field craft core.ItemList? ---[[ -WIPDOC -]] ----@field craftpreview core.ItemList? ---[[ -WIPDOC -]] ----@field craftresult core.ItemList? ---[[ -WIPDOC -]] ----@field hand core.ItemList? \ No newline at end of file diff --git a/types/luanti_lsp_definitions/library/defs/item/item.lua b/types/luanti_lsp_definitions/library/defs/item/item.lua deleted file mode 100644 index 09c4db21..00000000 --- a/types/luanti_lsp_definitions/library/defs/item/item.lua +++ /dev/null @@ -1,70 +0,0 @@ ----@meta _ --- DRAFT 1 DONE --- luanti/doc/lua_api.md: Items - ---[[ -WIPDOC -]] ----@alias core.Tool.name ---- | string - ---[[ -WIPDOC -]] ----@alias core.Item.name ---- | "" ---- | core.Tool.name ---- | core.Node.name - ---[[ -WIPDOC -]] ----@alias core.Item.namelike ---- | core.Groups.item ---- | core.Groups.tool ---- | core.Item.name - ---[[ -WIPDOC -]] ----@alias core.Tool.wear integer - ---[[ -WIPDOC -]] ----@class core.Item.tablefmt ---[[ -WIPDOC -]] ----@field name core.Item.name ---[[ -WIPDOC -]] ----@field count integer? ---[[ -WIPDOC -]] ----@field wear core.Tool.wear? ---[[ -WIPDOC -]] ----@field metadata string? - ---[[ -WIPDOC -]] ----@alias core.Item.stringfmt string - ---[[ -WIPDOC -]] ----@alias core.Item.simple ---- | core.Item.tablefmt ---- | core.Item.stringfmt - ---[[ -WIPDOC -]] ----@alias core.Item ---- | core.Item.simple ---- | core.ItemStack \ No newline at end of file diff --git a/types/luanti_lsp_definitions/library/defs/item/itemdef.lua b/types/luanti_lsp_definitions/library/defs/item/itemdef.lua deleted file mode 100644 index d01e9717..00000000 --- a/types/luanti_lsp_definitions/library/defs/item/itemdef.lua +++ /dev/null @@ -1,282 +0,0 @@ ----@meta _ --- DRAFT 1 DONE --- luanti/doc/lua_api.md: Items --- luanti/doc/lua_api.md: Definition tables > Item definition - ---[[ -WIPDOC -]] ----@alias core.ItemDef.keys ---- | "description" ---- | "short_description" ---- | "groups" ---- | "inventory_image" ---- | "inventory_overlay" ---- | "wield_image" ---- | "wield_overlay" ---- | "wield_scale" ---- | "palette" ---- | "color" ---- | "stack_max" ---- | "range" ---- | "liquids_pointable" ---- | "pointabilities" ---- | "light_source" ---- | "tool_capabilities" ---- | "wear_color" ---- | "node_placement_prediction" ---- | "node_dig_prediction" ---- | "touch_interaction" ---- | "sounds" ---- | "on_place" ---- | "on_secondary_use" ---- | "on_drop" ---- | "on_pickup" ---- | "on_use" ---- | "after_use" - --- --------------------------------- ToolDef -------------------------------- -- ---[[ -WIPDOC -]] ----@class core.ToolDef : core.ItemDef ---[[ -WIPDOC -]] ----@field tool_capabilities core.ToolCapabilities - --- ------------------------------- description ------------------------------ -- - ---[[ -WIPDOC -]] ----@class core.ItemDef ---[[ -Can contain new lines. "\n" has to be used as new line character. -See also: `get_description` in [`ItemStack`] -]] ----@field description string? ---[[ -Must not contain new lines. -Defaults to nil. -Use an [`ItemStack`] to get the short description, e.g.: - ItemStack(itemname):get_short_description() -]] ----@field short_description string? - --- -------------------------------------------------------------------------- -- - ----@class core.ItemDef ---[[ -key = name, value = rating; rating = . -If rating not applicable, use 1. -e.g. {wool = 1, fluffy = 3} - {soil = 2, outerspace = 1, crumbly = 1} - {bendy = 2, snappy = 1}, - {hard = 1, metal = 1, spikes = 1} -]] ----@field groups core.Groups.item? - - --- ------------------------ inventory and wield image ----------------------- -- - ----@class core.ItemDef ---[[ -Texture shown in the inventory GUI -Defaults to a 3D rendering of the node if left empty. -]] ----@field inventory_image core.Texture? ---[[ -An overlay texture which is not affected by colorization -]] ----@field inventory_overlay core.Texture? ---[[ -Texture shown when item is held in hand -Defaults to a 3D rendering of the node if left empty. -]] ----@field wield_image core.Texture? ---[[ -Like inventory_overlay but only used in the same situation as wield_image -]] ----@field wield_overlay core.Texture? ---[[ -Scale for the item when held in hand -]] ----@field wield_scale vector? ---[[ -An image file containing the palette of a node. -You can set the currently used color as the "palette_index" field of -the item stack metadata. -The palette is always stretched to fit indices between 0 and 255, to -ensure compatibility with "colorfacedir" (and similar) nodes. -]] ----@field palette core.Texture? ---[[ -Color the item is colorized with. The palette overrides this. -]] ----@field color core.ColorSpec? - --- -------------------------------------------------------------------------- -- - ----@class core.ItemDef ---[[ -Maximum amount of items that can be in a single stack. -The default can be changed by the setting `default_stack_max` -]] ----@field stack_max integer? - --- ----------------------------- pointabilities ----------------------------- -- - ----@class core.ItemDef ---[[ -Range of node and object pointing that is possible with this item held -Can be overridden with itemstack meta. -]] ----@field range number? ---[[ -If true, item can point to all liquid nodes (`liquidtype ~= "none"`), -even those for which `pointable = false` -]] ----@field liquids_pointable boolean? - ---[[ ItemDef.pointabilities split off into ./pointabilities.lua ]]-- - --- -------------------------------------------------------------------------- -- - ---[[ -WIPDOC -]] -core.LIGHT_MAX = 14 - ----@class core.ItemDef ---[[ -When used for nodes: Defines amount of light emitted by node. -Otherwise: Defines texture glow when viewed as a dropped item -To set the maximum (14), use the value 'core.LIGHT_MAX'. -A value outside the range 0 to core.LIGHT_MAX causes undefined -behavior. -]] ----@field light_source core.Light.source? ---[[ -See "Tool Capabilities" section for an example including explanation -]] ----@field tool_capabilities core.ToolCapabilities? ---[[ -Set wear bar color of the tool by setting color stops and blend mode -See "Wear Bar Color" section for further explanation including an example -]] ----@field wear_color core.WearBarColor? ---[[ -If nil and item is node, prediction is made automatically. -If nil and item is not a node, no prediction is made. -If "" and item is anything, no prediction is made. -Otherwise should be name of node which the client immediately places -on ground when the player places the item. Server will always update -with actual result shortly. -]] ----@field node_placement_prediction core.Node.name? ---[[ -if "", no prediction is made. -if "air", node is removed. -Otherwise should be name of node which the client immediately places -upon digging. Server will always update with actual result shortly. -]] ----@field node_dig_prediction core.Node.name? - ---[[ ItemDef.touch_interaction split off into ./touch_interaction.lua ]]-- - ---[[ ItemDef.sound split off into ./sound.lua ]]-- - --- -------------------------------- callbacks ------------------------------- -- - ---[[ -When the 'place' key was pressed with the item in hand -and a node was pointed at. -Shall place item and return the leftover itemstack -or nil to not modify the inventory. -The placer may be any ObjectRef or nil. -default: core.item_place -]] ----@alias core.ItemDef.on_place fun(itemstack:core.ItemStack, placer:core.ObjectRef?, pointed_thing:core.PointedThing): core.ItemStack? - ---[[ -Same as on_place but called when not pointing at a node. -Function must return either nil if inventory shall not be modified, -or an itemstack to replace the original itemstack. -The user may be any ObjectRef or nil. -default: nil -]] ----@alias core.ItemDef.on_secondary_use fun(itemstack:core.ItemStack, user:core.ObjectRef?, pointed_thing:core.PointedThing): core.ItemStack? - ---[[ -Shall drop item and return the leftover itemstack. -The dropper may be any ObjectRef or nil. -default: core.item_drop -]] ----@alias core.ItemDef.on_drop fun(itemstack:core.ItemStack, dropper:core.ObjectRef?, pos:vec): core.ItemStack? - ---[[ -Called when a dropped item is punched by a player. -Shall pick-up the item and return the leftover itemstack or nil to not -modify the dropped item. -Parameters: -* `itemstack`: The `ItemStack` to be picked up. -* `picker`: Any `ObjectRef` or `nil`. -* `pointed_thing` (optional): The dropped item (a `"__builtin:item"` - luaentity) as `type="object"` `pointed_thing`. -* `time_from_last_punch, ...` (optional): Other parameters from - `luaentity:on_punch`. -default: `core.item_pickup` -]] ----@alias core.ItemDef.on_pickup fun(itemstack: core.ItemStack, picker:core.ObjectRef?, pointed_thing:core.PointedThing?, time_from_last_punch:number?, tool_capabilities:core.ToolCapabilities?, dir:vec?, damage:integer?): core.ItemStack? - ---[[ -default: nil -When user pressed the 'punch/mine' key with the item in hand. -Function must return either nil if inventory shall not be modified, -or an itemstack to replace the original itemstack. -e.g. itemstack:take_item(); return itemstack -Otherwise, the function is free to do what it wants. -The user may be any ObjectRef or nil. -The default functions handle regular use cases. -]] ----@alias core.ItemDef.on_use fun(itemstack:core.ItemStack, user:core.ObjectRef?, pointed_thing:core.PointedThing): core.ItemStack? - ---[[ -default: nil -If defined, should return an itemstack and will be called instead of -wearing out the item (if tool). If returns nil, does nothing. -If after_use doesn't exist, it is the same as: - function(itemstack, user, node, digparams) - itemstack:add_wear(digparams.wear) - return itemstack - end -The user may be any ObjectRef or nil. -]] ----@alias core.ItemDef.after_use fun(itemstack:core.ItemStack, user:core.ObjectRef?, node:core.Node.get, digparams:core.DigParams): core.ItemStack? - ----@class core.ItemDef ---[[ -WIPDOC -]] ----@field on_place core.ItemDef.on_place? ---[[ -WIPDOC -]] ----@field on_secondary_use core.ItemDef.on_secondary_use? ---[[ -WIPDOC -]] ----@field on_drop core.ItemDef.on_drop? ---[[ -WIPDOC -]] ----@field on_pickup core.ItemDef.on_pickup? ---[[ -WIPDOC -]] ----@field on_use core.ItemDef.on_use? ---[[ -WIPDOC -]] ----@field after_use core.ItemDef.after_use? \ No newline at end of file diff --git a/types/luanti_lsp_definitions/library/defs/item/pointabilities.lua b/types/luanti_lsp_definitions/library/defs/item/pointabilities.lua deleted file mode 100644 index 67326ac9..00000000 --- a/types/luanti_lsp_definitions/library/defs/item/pointabilities.lua +++ /dev/null @@ -1,43 +0,0 @@ ----@meta _ --- DRAFT 1 DONE --- luanti/doc/lua_api.md: Definition tables > Item definition - --- ------------------------- ItemDef.pointabilities ------------------------- -- - ---[[ -WIPDOC -]] ----@alias core.ItemDef.pointabilities.value ---- | boolean ---- | "blocking" - ---[[ -WIPDOC -]] ----@class core.ItemDef.pointabilities ---[[ -WIPDOC -]] ----@field nodes table ---[[ -WIPDOC -]] ----@field objects table> - - --- ----------------------------- ItemDef fields ----------------------------- -- - ----@class core.ItemDef ---[[ -Contains lists to override the `pointable` property of nodes and objects. -The index can be a node/entity name or a group with the prefix `"group:"`. -(For objects `armor_groups` are used and for players the entity name is irrelevant.) -If multiple fields fit, the following priority order is applied: -1. value of matching node/entity name -2. `true` for any group -3. `false` for any group -4. `"blocking"` for any group -5. `liquids_pointable` if it is a liquid node -6. `pointable` property of the node or object -]] ----@field pointabilities core.ItemDef.pointabilities? diff --git a/types/luanti_lsp_definitions/library/defs/item/sound.lua b/types/luanti_lsp_definitions/library/defs/item/sound.lua deleted file mode 100644 index 4ae7e52f..00000000 --- a/types/luanti_lsp_definitions/library/defs/item/sound.lua +++ /dev/null @@ -1,34 +0,0 @@ ----@meta _ --- DRAFT 1 DONE --- luanti/doc/lua_api.md: Definition tables > Item definition - --- ------------------------------ ItemDef.sound ----------------------------- -- - ---[[ -WIPDOC -]] ----@class core.ItemDef.sound ---[[ -WIPDOC -]] ----@field breaks core.SimpleSoundSpec? ---[[ -WIPDOC -]] ----@field eat core.SimpleSoundSpec? ---[[ -WIPDOC -]] ----@field punch_use core.SimpleSoundSpec? ---[[ -WIPDOC -]] ----@field punch_use_air core.SimpleSoundSpec? - --- ----------------------------- ItemDef fields ----------------------------- -- - ----@class core.ItemDef ---[[ -WIPDOC -]] ----@field sound core.ItemDef.sound? diff --git a/types/luanti_lsp_definitions/library/defs/item/touch_interaction.lua b/types/luanti_lsp_definitions/library/defs/item/touch_interaction.lua deleted file mode 100644 index 1998a121..00000000 --- a/types/luanti_lsp_definitions/library/defs/item/touch_interaction.lua +++ /dev/null @@ -1,55 +0,0 @@ ----@meta _ --- DRAFT 1 DONE --- luanti/doc/lua_api.md: Definition tables > Item definition - --- ------------------------ ItemDef.touch_interaction ----------------------- -- - ----@alias core.ItemDef.touch_interaction.mode ---- | "long_dig_short_place" ---- | "short_dig_long_place" ---- | "user" - ----@class core.ItemDef.touch_interaction.pointed_thing ---[[ -WIPDOC -]] ----@field pointed_nothing core.ItemDef.touch_interaction.mode? ---[[ -WIPDOC -]] ----@field pointed_node core.ItemDef.touch_interaction.mode? ---[[ -WIPDOC -]] ----@field pointed_object core.ItemDef.touch_interaction.mode? - ---[[ -WIPDOC -]] ----@alias core.ItemDef.touch_interaction ---- | core.ItemDef.touch_interaction.mode ---- | core.ItemDef.touch_interaction.pointed_thing - --- ----------------------------- ItemDef fields ----------------------------- -- - ----@class core.ItemDef ---[[ -Only affects touchscreen clients. -Defines the meaning of short and long taps with the item in hand. -If specified as a table, the field to be used is selected according to -the current `pointed_thing`. -There are three possible TouchInteractionMode values: -* "long_dig_short_place" (long tap = dig, short tap = place) -* "short_dig_long_place" (short tap = dig, long tap = place) -* "user": - * For `pointed_object`: Equivalent to "short_dig_long_place" if the - client-side setting "touch_punch_gesture" is "short_tap" (the - default value) and the item is able to punch (i.e. has no on_use - callback defined). - Equivalent to "long_dig_short_place" otherwise. - * For `pointed_node` and `pointed_nothing`: - Equivalent to "long_dig_short_place". - * The behavior of "user" may change in the future. -The default value is "user". -]] ----@field touch_interaction core.ItemDef.touch_interaction? diff --git a/types/luanti_lsp_definitions/library/defs/lbm.lua b/types/luanti_lsp_definitions/library/defs/lbm.lua deleted file mode 100644 index 5714a51a..00000000 --- a/types/luanti_lsp_definitions/library/defs/lbm.lua +++ /dev/null @@ -1,96 +0,0 @@ ----@meta _ --- DRAFT 1 DONE --- luanti/doc/lua_api.md: Definition tables > LBM (LoadingBlockModifier) definition - --- ------------------------------ LBMDef.__base ----------------------------- -- - ---[[ -LBM (LoadingBlockModifier) definition -------------------------------------- - -Used by `core.register_lbm`. - -A loading block modifier (LBM) is used to define a function that is called for -specific nodes (defined by `nodenames`) when a mapblock which contains such nodes -gets **activated** (**not loaded!**). - -*Note*: LBMs operate on a "snapshot" of node positions taken once before they are triggered. -That means if an LBM callback adds a node, it won't be taken into account. -However the engine guarantees that at the point in time when the callback is called -that all given positions contain a matching node. - -For `run_at_every_load = false` to work, both mapblocks and LBMs have timestamps -associated with them: - -* Each mapblock has a "last active" timestamp. It is also updated when the - mapblock is generated. -* For each LBM, an introduction timestamp is stored in the world data, identified - by the LBM's `name` field. If an LBM disappears, the corresponding timestamp - is cleared. - -When a mapblock is activated, only LBMs whose introduction timestamp is newer -than the mapblock's timestamp are run. - -*Note*: For maps generated in 5.11.0 or older, many newly generated mapblocks -did not get a timestamp set. This means LBMs introduced between generation time -and time of first activation will never run. -Currently the only workaround is to use `run_at_every_load = true`. -]] ----@class _.LBMDef.__base ---[[ -Descriptive label for profiling purposes (optional). -Definitions with identical labels will be listed as one. -]] ----@field label string? ---[[ -Identifier of the LBM, should follow the modname: convention -]] ----@field name string? ---[[ -List of node names to trigger the LBM on. -]] ----@field nodenames core.Node.namelike[]? ---[[ -If `false`: The LBM only runs on mapblocks the first time they are -activated after the LBM was introduced. -It never runs on mapblocks generated after the LBM's introduction. -See above for details. - -If `true`: The LBM runs every time a mapblock is activated. -]] ----@field run_at_every_load boolean? - --- --------------------------------- LBMDef --------------------------------- -- - ---[[ -WIPDOC -]] ----@alias core.LBMDef.action.fn fun(pos:ivec, node:core.Node.get, dtime_s:number) - ----@class core.LBMDef.action : _.LBMDef.__base ---[[ -Function triggered for each qualifying node. - -`dtime_s` is the in-game time (in seconds) elapsed since the mapblock -was last active (available since 5.7.0). -]] ----@field action core.LBMDef.action.fn - ---[[ -WIPDOC -]] ----@alias core.LBMDef.bulk_action.fn fun(pos_list:ivec[], dtime_s:number) - ----@class core.LBMDef.bulk_action : _.LBMDef.__base ---[[ -Function triggered with a list of all applicable node positions at once. - -This can be provided as an alternative to `action` (not both). -Available since `core.features.bulk_lbms` (5.10.0) -`dtime_s`: as above -]] ----@field bulk_action core.LBMDef.bulk_action.fn - ----@alias core.LBMDef ---- | core.LBMDef.action ---- | core.LBMDef.bulk_action \ No newline at end of file diff --git a/types/luanti_lsp_definitions/library/defs/lsystem.lua b/types/luanti_lsp_definitions/library/defs/lsystem.lua deleted file mode 100644 index b9415cfe..00000000 --- a/types/luanti_lsp_definitions/library/defs/lsystem.lua +++ /dev/null @@ -1,126 +0,0 @@ ----@meta _ --- DRAFT 1 DONE --- luanti/doc/lua_api.md: L-system trees - ---[[ -## Key for special L-System symbols - -* `G`: move forward one unit with the pen up -* `F`: move forward one unit with the pen down drawing trunks and branches -* `f`: move forward one unit with the pen down drawing leaves (100% chance) -* `T`: move forward one unit with the pen down drawing trunks only -* `R`: move forward one unit with the pen down placing fruit -* `A`: replace with rules set A -* `B`: replace with rules set B -* `C`: replace with rules set C -* `D`: replace with rules set D -* `a`: replace with rules set A, chance 90% -* `b`: replace with rules set B, chance 80% -* `c`: replace with rules set C, chance 70% -* `d`: replace with rules set D, chance 60% -* `+`: yaw the turtle right by `angle` parameter -* `-`: yaw the turtle left by `angle` parameter -* `&`: pitch the turtle down by `angle` parameter -* `^`: pitch the turtle up by `angle` parameter -* `/`: roll the turtle to the right by `angle` parameter -* `*`: roll the turtle to the left by `angle` parameter -* `[`: save in stack current state info -* `]`: recover from stack state info - -[L-System Trees on docs.luanti.org](https://docs.luanti.org/for-creators/l-system-trees/) -]] ----@alias core.LsystemTreeDef.rules string - ---[[ -WIPDOC -]] ----@alias core.LSystemTreeDef.trunk_type ---- | "single" ---- | "double" ---- | "crossed" - ---[[ -**LIBDEF REVISION** - -L-system trees in Luanti are procedurally generated trees defined by a set of -rules rather than fixed shapes. They use an axiom (starting string) and -recursive replacement rules based on L-systems. One way to interpret is to -compare it to turtle graphics. This allows complex, natural-looking trees with -branching, leaves, and fruit to be created from relatively small definitions. - -[L-System Trees on docs.luanti.org](https://docs.luanti.org/for-creators/l-system-trees/) -]] ----@class core.LSystemTreeDef ---[[ -Initial tree axiom -]] ----@field axiom core.LsystemTreeDef.rules ---[[ -Rules set A -]] ----@field rules_a core.LsystemTreeDef.rules? ---[[ -Rules set B -]] ----@field rules_b core.LsystemTreeDef.rules? ---[[ -Rules set C -]] ----@field rules_c core.LsystemTreeDef.rules? ---[[ -Rules set D -]] ----@field rules_d core.LsystemTreeDef.rules? ---[[ -Trunk node name (default: `"ignore"`) -]] ----@field trunk core.Node.name? ---[[ -Leaves node name (default: `"ignore"`) -]] ----@field leaves core.Node.name? ---[[ -Secondary leaves node name (default: `"ignore"`) -]] ----@field leaves2 core.Node.name? ---[[ -Chance (0-100) to replace leaves with leaves2 (default: 0) -]] ----@field leaves2_chance integer? ---[[ -Angle in deg (default: 0) -]] ----@field angle integer? ---[[ -Max # of iterations, usually 2 -5 (default 0) -]] ----@field iterations integer? ---[[ -Factor to lower number of iterations, usually 0 - 3 (default: 0) -]] ----@field random_level integer? ---[[ -**LIBDEF REVISION** - -Type of trunk: -- `"single"` (default): 1 node -- `"double"`: 2x2 nodes -- `"crossed"`: 3x3 in cross shape -]] ----@field trunk_type core.LSystemTreeDef.trunk_type? ---[[ -Whether to use thin (1 node) branches (default: `false`) -]] ----@field thin_branches boolean? ---[[ -Fruit node name. (default: `"air"`) -]] ----@field fruit core.Node.name? ---[[ -Chance (0-100) to replace leaves with fruit node (default: 0) -]] ----@field fruit_chance integer? ---[[ -Random seed, if no seed is provided, the engine will create one. -]] ----@field seed integer \ No newline at end of file diff --git a/types/luanti_lsp_definitions/library/defs/mapgen_objects.lua b/types/luanti_lsp_definitions/library/defs/mapgen_objects.lua deleted file mode 100644 index ee7c203d..00000000 --- a/types/luanti_lsp_definitions/library/defs/mapgen_objects.lua +++ /dev/null @@ -1,158 +0,0 @@ ----@meta _ --- DRAFT 1 DONE --- luanti/doc/lua_api.md: Mapgen objects - --- ----------------------------- GenNotify.flags ---------------------------- -- - ---[[ -WIPDOC -]] ----@class core.GenNotify.flags.tablefmt : {[string]:boolean?} ---[[ -WIPDOC -]] ----@field dungeon boolean? ---[[ -WIPDOC -]] ----@field nodungeon boolean? ---[[ -WIPDOC -]] ----@field temple boolean? ---[[ -WIPDOC -]] ----@field notemple boolean? ---[[ -WIPDOC -]] ----@field cave_begin boolean? ---[[ -WIPDOC -]] ----@field nocave_begin boolean? ---[[ -WIPDOC -]] ----@field cave_end boolean? ---[[ -WIPDOC -]] ----@field nocave_end boolean? ---[[ -WIPDOC -]] ----@field large_cave_begin boolean? ---[[ -WIPDOC -]] ----@field nolarge_cave_begin boolean? ---[[ -WIPDOC -]] ----@field large_cave_end boolean? ---[[ -WIPDOC -]] ----@field nolarge_cave_end boolean? ---[[ -WIPDOC -]] ----@field custom boolean? ---[[ -WIPDOC -]] ----@field nocustom boolean? ---[[ -WIPDOC -]] ----@field decoration boolean? ---[[ -WIPDOC -]] ----@field nodecoration boolean? - ---[[ -WIPDOC -]] ----@alias core.GenNotify.flags.stringfmt string - ---[[ -WIPDOC -]] ----@alias core.GenNotify.flags ---- | core.GenNotify.flags.tablefmt ---- | core.GenNotify.flags.stringfmt - --- -------------------------------- GenNotify ------------------------------- -- - ---[[ -WIPDOC -]] ----@alias core.GenNotify.key.decoration string - ---[[ -Returns a table. You need to announce your interest in a specific -field by calling `core.set_gen_notify()` *before* map generation happens. - -* key = string: generation notification type -* value = list of positions (usually) - * Exceptions are denoted in the listing below. - -Available generation notification types: - -* `dungeon`: bottom center position of dungeon rooms -* `temple`: as above but for desert temples (mgv6 only) -* `cave_begin` -* `cave_end` -* `large_cave_begin` -* `large_cave_end` -* `custom`: data originating from [Mapgen environment](#mapgen-environment) (Lua API) - * This is a table. - * key = user-defined ID (string) - * value = arbitrary Lua value -* `decoration#id`: decorations - * (see below) - -Decorations have a key in the format of `"decoration#id"`, where `id` is the -numeric unique decoration ID as returned by `core.get_decoration_id()`. -For example, `decoration#123`. - -The returned positions are the ground surface 'place_on' nodes, -not the decorations themselves. A 'simple' type decoration is often 1 -node above the returned position and possibly displaced by 'place_offset_y'. -]] ----@class core.GenNotify ---[[ -WIPDOC -]] ----@field dungeon ivec? ---[[ -WIPDOC -]] ----@field temple ivec? ---[[ -WIPDOC -]] ----@field cave_begin ivec? ---[[ -WIPDOC -]] ----@field cave_end ivec? ---[[ -WIPDOC -]] ----@field large_cave_begin ivec? ---[[ -WIPDOC -]] ----@field large_cave_end ivec? ---[[ -WIPDOC -]] ----@field custom table ---[[ -WIPDOC -]] ----@field [core.GenNotify.key.decoration] ivec? \ No newline at end of file diff --git a/types/luanti_lsp_definitions/library/defs/metadata/item.lua b/types/luanti_lsp_definitions/library/defs/metadata/item.lua deleted file mode 100644 index 99693335..00000000 --- a/types/luanti_lsp_definitions/library/defs/metadata/item.lua +++ /dev/null @@ -1,120 +0,0 @@ ----@meta _ --- DRAFT 1 DONE --- luanti/doc/lua_api.md: Metadata --- luanti/doc/lua_api.md: Class reference > `MetaDataRef` - --- ------------------- MetadataTable.*.item special fields ------------------ -- ---[[ -WIPDOC -]] ----@alias core.MetadataTable.fields.item.keys.special ---- | "description" ---- | "short_description" ---- | "inventory_image" ---- | "inventory_overlay" ---- | "wield_image" ---- | "wield_overlay" ---- | "wield_scale" ---- | "color" ---- | "palette_index" ---- | "count_meta" ---- | "count_alignment" ---- | "range" - ---[[ -WIPDOC -]] ----@alias core.MetadataTable.fields.item.keys ---- | core.MetadataTable.fields.item.keys.special ---- | string - ---[[ -WIPDOC -]] ----@alias core.MetadataTable.fields.item.keys.integer.special ---- | "palette_index" ---- | "count_alignment" - ---[[ -WIPDOC -]] ----@alias core.MetadataTable.fields.item.keys.integer ---- | core.MetadataTable.fields.item.keys.integer.special ---- | string - ---[[ -WIPDOC -]] ----@alias core.MetadataTable.fields.item.keys.number.special ---- | "range" - ---[[ -WIPDOC -]] ----@alias core.MetadataTable.fields.item.keys.number ---- | core.MetadataTable.fields.item.keys.number.special ---- | string - --- --------------------------- MetadataTable.item --------------------------- -- - ---[[ -WIPDOC -]] ----@class core.MetadataTable.fields.item : {[string]:string?} ---[[ -WIPDOC -]] ----@field description string? ---[[ -WIPDOC -]] ----@field short_description string? ---[[ -WIPDOC -]] ----@field inventory_image core.Texture? ---[[ -WIPDOC -]] ----@field inventory_overlay core.Texture? ---[[ -WIPDOC -]] ----@field wield_image core.Texture? ---[[ -WIPDOC -]] ----@field wield_overlay core.Texture? ---[[ -WIPDOC -]] ----@field wield_scale core.MetadataTable.vector? ---[[ -WIPDOC -]] ----@field color core.ColorString? ---[[ -WIPDOC -]] ----@field palette_index integer? ---[[ -WIPDOC -]] ----@field count_meta string? ---[[ -WIPDOC -]] ----@field count_alignment integer? ---[[ -WIPDOC -]] ----@field range number? - ---[[ -WIPDOC -]] ----@class core.MetadataTable.item ---[[ -WIPDOC -]] ----@field fields core.MetadataTable.fields.item? \ No newline at end of file diff --git a/types/luanti_lsp_definitions/library/defs/metadata/metadata.lua b/types/luanti_lsp_definitions/library/defs/metadata/metadata.lua deleted file mode 100644 index 6ff20bfd..00000000 --- a/types/luanti_lsp_definitions/library/defs/metadata/metadata.lua +++ /dev/null @@ -1,50 +0,0 @@ ----@meta _ --- DRAFT 1 DONE --- luanti/doc/lua_api.md: Metadata --- luanti/doc/lua_api.md: Class reference > `MetaDataRef` - ---[[ -WIPDOC -]] ----@alias core.MetadataTable.vector string - ---[[ -WIPDOC -]] ----@alias core.MetadataTable.fields.keys ---- | core.MetadataTable.fields.item.keys ---- | core.MetadataTable.fields.node.keys ---- | core.MetadataTable.fields.player.keys ---- | core.MetadataTable.fields.storage.keys - ---[[ -WIPDOC -]] ----@alias core.MetadataTable.fields.keys.integer ---- | core.MetadataTable.fields.item.keys.integer ---- | core.MetadataTable.fields.node.keys.integer ---- | core.MetadataTable.fields.player.keys.integer ---- | core.MetadataTable.fields.storage.keys.integer - ---[[ -WIPDOC -]] ----@alias core.MetadataTable.fields.keys.number ---- | core.MetadataTable.fields.item.keys.number ---- | core.MetadataTable.fields.node.keys.number ---- | core.MetadataTable.fields.player.keys.number ---- | core.MetadataTable.fields.storage.keys.number - ---[[ -WIPDOC -]] ----@alias core.MetadataTable.set ---- | core.MetadataTable.node.set ---- | core.MetadataTable.item - ---[[ -WIPDOC -]] ----@alias core.MetadataTable.get ---- | core.MetadataTable.node.get ---- | core.MetadataTable.item \ No newline at end of file diff --git a/types/luanti_lsp_definitions/library/defs/metadata/node.lua b/types/luanti_lsp_definitions/library/defs/metadata/node.lua deleted file mode 100644 index 2a1d44f5..00000000 --- a/types/luanti_lsp_definitions/library/defs/metadata/node.lua +++ /dev/null @@ -1,87 +0,0 @@ ----@meta _ --- DRAFT 1 DONE --- luanti/doc/lua_api.md: Metadata --- luanti/doc/lua_api.md: Class reference > `MetaDataRef` - --- ------------------- MetadataTable.*.node special fields ------------------ -- - ---[[ -WIPDOC -]] ----@alias core.MetadataTable.fields.node.keys.special ---- | "formpsec" ---- | "infotext" - ---[[ -WIPDOC -]] ----@alias core.MetadataTable.fields.node.keys ---- | core.MetadataTable.fields.node.keys.special ---- | string - ---[[ -WIPDOC -]] ----@alias core.MetadataTable.fields.node.keys.integer.special ---- | string - ---[[ -WIPDOC -]] ----@alias core.MetadataTable.fields.node.keys.integer ---- | core.MetadataTable.fields.node.keys.integer.special ---- | string - ---[[ -WIPDOC -]] ----@alias core.MetadataTable.fields.node.keys.number.special ---- | string - ---[[ -WIPDOC -]] ----@alias core.MetadataTable.fields.node.keys.number ---- | core.MetadataTable.fields.node.keys.number.special ---- | string - --- --------------------------- MetadataTable.node --------------------------- -- - ---[[ -WIPDOC -]] ----@class core.MetadataTable.fields.node : {[string]:string?} ---[[ -WIPDOC -]] ----@field formspec core.Formspec? ---[[ -WIPDOC -]] ----@field infotext string? - ---[[ -WIPDOC -]] ----@class core.MetadataTable.node.set ---[[ -WIPDOC -]] ----@field fields core.MetadataTable.fields.node? ---[[ -WIPDOC -]] ----@field inventory core.InventoryTable? - ---[[ -WIPDOC -]] ----@class core.MetadataTable.node.get ---[[ -WIPDOC -]] ----@field fields core.MetadataTable.fields.node? ---[[ -WIPDOC -]] ----@field inventory core.InventoryTable.stringfmt? \ No newline at end of file diff --git a/types/luanti_lsp_definitions/library/defs/metadata/player.lua b/types/luanti_lsp_definitions/library/defs/metadata/player.lua deleted file mode 100644 index 77e7dafc..00000000 --- a/types/luanti_lsp_definitions/library/defs/metadata/player.lua +++ /dev/null @@ -1,61 +0,0 @@ ----@meta _ --- DRAFT 1 DONE --- luanti/doc/lua_api.md: Metadata --- luanti/doc/lua_api.md: Class reference > `MetaDataRef` - --- ------------------ MetadataTable.*.player special fields ----------------- -- - ---[[ -WIPDOC -]] ----@alias core.MetadataTable.fields.player.keys.special ---- | string - ---[[ -WIPDOC -]] ----@alias core.MetadataTable.fields.player.keys ---- | core.MetadataTable.fields.player.keys.special ---- | string - ---[[ -WIPDOC -]] ----@alias core.MetadataTable.fields.player.keys.integer.special ---- | string - ---[[ -WIPDOC -]] ----@alias core.MetadataTable.fields.player.keys.integer ---- | core.MetadataTable.fields.player.keys.integer.special ---- | string - ---[[ -WIPDOC -]] ----@alias core.MetadataTable.fields.player.keys.number.special ---- | string - ---[[ -WIPDOC -]] ----@alias core.MetadataTable.fields.player.keys.number ---- | core.MetadataTable.fields.player.keys.number.special ---- | string - --- -------------------------- MetadataTable.player -------------------------- -- - ---[[ -WIPDOC -]] ----@class core.MetadataTable.fields.player : {[string]:string?} - ---[[ -WIPDOC -]] ----@class core.MetadataTable.player ---[[ -WIPDOC -]] ----@field fields core.MetadataTable.fields.player? \ No newline at end of file diff --git a/types/luanti_lsp_definitions/library/defs/metadata/storage.lua b/types/luanti_lsp_definitions/library/defs/metadata/storage.lua deleted file mode 100644 index 5c29d7f2..00000000 --- a/types/luanti_lsp_definitions/library/defs/metadata/storage.lua +++ /dev/null @@ -1,61 +0,0 @@ ----@meta _ --- DRAFT 1 DONE --- luanti/doc/lua_api.md: Metadata --- luanti/doc/lua_api.md: Class reference > `MetaDataRef` - --- ----------------- MetadataTable.*.storage special fields ----------------- -- - ---[[ -WIPDOC -]] ----@alias core.MetadataTable.fields.storage.keys.special ---- | string - ---[[ -WIPDOC -]] ----@alias core.MetadataTable.fields.storage.keys ---- | core.MetadataTable.fields.storage.keys.special ---- | string - ---[[ -WIPDOC -]] ----@alias core.MetadataTable.fields.storage.keys.integer.special ---- | string - ---[[ -WIPDOC -]] ----@alias core.MetadataTable.fields.storage.keys.integer ---- | core.MetadataTable.fields.storage.keys.integer.special ---- | string - ---[[ -WIPDOC -]] ----@alias core.MetadataTable.fields.storage.keys.number.special ---- | string - ---[[ -WIPDOC -]] ----@alias core.MetadataTable.fields.storage.keys.number ---- | core.MetadataTable.fields.storage.keys.number.special ---- | string - --- -------------------------- MetadataTable.storage ------------------------- -- - ---[[ -WIPDOC -]] ----@class core.MetadataTable.fields.storage : {[string]:string?} - ---[[ -WIPDOC -]] ----@class core.MetadataTable.storage ---[[ -WIPDOC -]] ----@field fields core.MetadataTable.fields.storage? \ No newline at end of file diff --git a/types/luanti_lsp_definitions/library/defs/node/drawtype.lua b/types/luanti_lsp_definitions/library/defs/node/drawtype.lua deleted file mode 100644 index b64e8cec..00000000 --- a/types/luanti_lsp_definitions/library/defs/node/drawtype.lua +++ /dev/null @@ -1,37 +0,0 @@ ----@meta _ --- DRAFT 1 DONE --- luanti/doc/lua_api.md: Nodes > Node drawtypes --- luanti/doc/lua_api.md: Definition tables > Node definition - --- ---------------------------- NodeDef.drawtype ---------------------------- -- - ---[[ -WIPDOC -]] ----@alias core.NodeDef.drawtype ---- | "normal" ---- | "airlike" ---- | "liquid" ---- | "flowingliquid" ---- | "glasslike" ---- | "glasslike_framed" ---- | "glasslike_framed_optional" ---- | "allfaces" ---- | "allfaces_optional" ---- | "torchlike" ---- | "signlike" ---- | "plantlike" ---- | "firelike" ---- | "fencelike" ---- | "raillike" ---- | "nodebox" ---- | "mesh" ---- | "plantlike_rooted" - --- ----------------------------- NodeDef fields ----------------------------- -- - ----@class core.NodeDef ---[[ -WIPDOC -]] ----@field drawtype core.NodeDef.drawtype? diff --git a/types/luanti_lsp_definitions/library/defs/node/drop.lua b/types/luanti_lsp_definitions/library/defs/node/drop.lua deleted file mode 100644 index eb06728e..00000000 --- a/types/luanti_lsp_definitions/library/defs/node/drop.lua +++ /dev/null @@ -1,61 +0,0 @@ ----@meta _ --- DRAFT 1 DONE --- luanti/doc/lua_api.md: Definition tables > Node definition - --- --------------------------- NodeDef.drop.items --------------------------- -- - ---[[ -WIPDOC -]] ----@class core.NodeDef.drop.item ---[[ -WIPDOC -]] ----@field rarity integer? ---[[ -WIPDOC -]] ----@field items core.Item.name[]? ---[[ -WIPDOC -* @deprecated 5.X Use `tool_groups` instead -]] ----@field tools core.Tool.name[]? ---[[ -WIPDOC -]] ----@field tool_groups OneOrMany[]? ---[[ -WIPDOC -]] ----@field inherit_color boolean? - --- ------------------------------ NodeDef.drop ------------------------------ -- - ---[[ -WIPDOC -]] ----@class core.NodeDef.drop.tablefmt ---[[ -WIPDOC -]] ----@field max_items integer? ---[[ -WIPDOC -]] ----@field items core.NodeDef.drop.item? - ---[[ -WIPDOC -]] ----@alias core.NodeDef.drop ---- | core.NodeDef.drop.tablefmt ---- | core.Item.stringfmt - --- ----------------------------- NodeDef fields ----------------------------- -- - ----@class core.NodeDef ---[[ -WIPDOC -]] ----@field drop core.NodeDef.drop diff --git a/types/luanti_lsp_definitions/library/defs/node/node.lua b/types/luanti_lsp_definitions/library/defs/node/node.lua deleted file mode 100644 index 14d1ad28..00000000 --- a/types/luanti_lsp_definitions/library/defs/node/node.lua +++ /dev/null @@ -1,155 +0,0 @@ ----@meta _ --- DRAFT 1 DONE --- luanti/doc/lua_api.md: Nodes --- luanti/doc/lua_api.md: Nodes > Node paramtypes - ---[[ -WIPDOC -]] ----@alias core.Node.name ---- | "unknown" ---- | "air" ---- | "ignore" ---- | string - ---[[ -WIPDOC -]] ----@alias core.Node.namelike ---- | core.Groups.node ---- | core.Node.name - --- ------------------------------- Node.param1 ------------------------------ -- - ---[[ -WIPDOC -]] ----@alias core.Light integer - ---[[ -WIPDOC -]] ----@alias core.Light.part integer - ---[[ -WIPDOC -]] ----@alias core.Light.source integer - ---[[ -WIPDOC -]] ----@alias core.Param1 integer - --- ------------------------------- Node.param2 ------------------------------ -- - ---[[ -WIPDOC -]] ----@alias core.Param2.wallmounted integer - ---[[ -WIPDOC -]] ----@alias core.Param2.facedir integer - ---[[ -WIPDOC -]] ----@alias core.Param2.4dir integer - ---[[ -WIPDOC -]] ----@alias core.Param2.leveled integer - ---[[ -WIPDOC -]] ----@alias core.Param2.leveled.rooted_plantlike integer - ---[[ -WIPDOC -]] ----@alias core.Param2.degrotate integer - ---[[ -WIPDOC -]] ----@alias core.Param2.meshoptions.plantlike integer - ---[[ -WIPDOC -]] ----@alias core.Param2.facedir.color integer - ---[[ -WIPDOC -]] ----@alias core.Param2.4dir.color integer - ---[[ -WIPDOC -]] ----@alias core.Param2.wallmounted.color integer - ---[[ -WIPDOC -]] ----@alias core.Param2.glasslikeliquidlevel.liquid integer - ---[[ -WIPDOC -]] ----@alias core.Param2.glasslikeliquidlevel.frame integer - ---[[ -WIPDOC -]] ----@alias core.Param2.glasslikeliquidlevel integer - ---[[ -WIPDOC -]] ----@alias core.Param2.degrotate.color integer - ---[[ -WIPDOC -]] ----@alias core.Param2 integer - --- ---------------------------------- Node ---------------------------------- -- - ---[[ -WIPDOC -]] ----@class core.Node.get ---[[ -WIPDOC -]] ----@field name string ---[[ -WIPDOC -]] ----@field param1 core.Param1 ---[[ -WIPDOC -]] ----@field param2 core.Param2 - ---[[ -WIPDOC -]] ----@class core.Node.set ---[[ -WIPDOC -]] ----@field name string ---[[ -WIPDOC -]] ----@field param1 core.Param1? ---[[ -WIPDOC -]] ----@field param2 core.Param2? diff --git a/types/luanti_lsp_definitions/library/defs/node/nodebox.lua b/types/luanti_lsp_definitions/library/defs/node/nodebox.lua deleted file mode 100644 index 65e8bd3b..00000000 --- a/types/luanti_lsp_definitions/library/defs/node/nodebox.lua +++ /dev/null @@ -1,182 +0,0 @@ ----@meta _ --- DRAFT 1 DONE --- luanti/doc/lua_api.md: Nodes > Node boxes - --- ------------------------------- NodeBox.box ------------------------------ -- - ---[[ -WIPDOC -]] ----@class core.NodeBox.box.strict ---[[ -WIPDOC -]] ----@field [1] number ---[[ -WIPDOC -]] ----@field [2] number ---[[ -WIPDOC -]] ----@field [3] number ---[[ -WIPDOC -]] ----@field [4] number ---[[ -WIPDOC -]] ----@field [5] number ---[[ -WIPDOC -]] ----@field [6] number - ---[[ -WIPDOC -]] ----@alias core.NodeBox.box ---- | number[] ---- | core.NodeBox.box.strict - ---[[ -WIPDOC -]] ----@alias core.NodeBox.boxes ---- | core.NodeBox.box ---- | core.NodeBox.box[] - --- ----------------------------- NodeBox.regular ---------------------------- -- - ---[[ -WIPDOC -]] ----@class core.NodeBox.regular ---[[ -WIPDOC -]] ----@field type "regular"? - - --- ------------------------------ NodeBox.fixed ----------------------------- -- - ---[[ -WIPDOC -]] ----@class core.NodeBox.fixed ---[[ -WIPDOC -]] ----@field type "fixed"|"leveled" ---[[ -WIPDOC -]] ----@field fixed core.NodeBox.boxes - --- --------------------------- NodeBox.wallmounted -------------------------- -- - ---[[ -WIPDOC -]] ----@class core.NodeBox.wallmounted ---[[ -WIPDOC -]] ----@field type "wallmounted" ---[[ -WIPDOC -]] ----@field wall_top core.NodeBox.box ---[[ -WIPDOC -]] ----@field wall_bottom core.NodeBox.box ---[[ -WIPDOC -]] ----@field wall_side core.NodeBox.box - - --- ---------------------------- NodeBox.connected --------------------------- -- - ---[[ -WIPDOC -]] ----@class core.NodeBox.connected ---[[ -WIPDOC -]] ----@field type "connected" ---[[ -WIPDOC -]] ----@field fixed core.NodeBox.boxes ---[[ -WIPDOC -]] ----@field connect_top core.NodeBox.boxes? ---[[ -WIPDOC -]] ----@field connect_bottom core.NodeBox.boxes? ---[[ -WIPDOC -]] ----@field connect_front core.NodeBox.boxes? ---[[ -WIPDOC -]] ----@field connect_left core.NodeBox.boxes? ---[[ -WIPDOC -]] ----@field connect_back core.NodeBox.boxes? ---[[ -WIPDOC -]] ----@field connect_right core.NodeBox.boxes? ---[[ -WIPDOC -]] ----@field disconnected_top core.NodeBox.boxes? ---[[ -WIPDOC -]] ----@field disconnected_bottom core.NodeBox.boxes? ---[[ -WIPDOC -]] ----@field disconnected_front core.NodeBox.boxes? ---[[ -WIPDOC -]] ----@field disconnected_left core.NodeBox.boxes? ---[[ -WIPDOC -]] ----@field disconnected_back core.NodeBox.boxes? ---[[ -WIPDOC -]] ----@field disconnected_right core.NodeBox.boxes? ---[[ -WIPDOC -]] ----@field disconnected core.NodeBox.boxes? ---[[ -WIPDOC -]] ----@field disconnected_sides core.NodeBox.boxes? - - --- --------------------------------- NodeBox -------------------------------- -- - ---[[ -WIPDOC -]] ----@alias core.NodeBox ---- | core.NodeBox.regular ---- | core.NodeBox.fixed ---- | core.NodeBox.wallmounted ---- | core.NodeBox.connected \ No newline at end of file diff --git a/types/luanti_lsp_definitions/library/defs/node/nodedef.lua b/types/luanti_lsp_definitions/library/defs/node/nodedef.lua deleted file mode 100644 index 62be0fc0..00000000 --- a/types/luanti_lsp_definitions/library/defs/node/nodedef.lua +++ /dev/null @@ -1,821 +0,0 @@ ----@meta _ --- DRAFT 1 DONE --- luanti/doc/lua_api.md: Nodes --- luanti/doc/lua_api.md: Definition tables > Node definition - --- NOTE: not practical to separate out every mutually exclusive fields as there --- are too many states resulting in too many permutations. - ---[[ -WIPDOC -]] ----@alias core.NodeDef.keys ---- | core.ItemDef.keys ---- | "light_source" ---- | "drawtype" ---- | "visual_scale" ---- | "tiles" ---- | "overlay_tiles" ---- | "special_tiles" ---- | "color" ---- | "use_texture_alpha" ---- | "palette" ---- | "post_effect_color" ---- | "post_effect_color_shaded" ---- | "paramtype" ---- | "paramtype2" ---- | "place_param2" ---- | "wallmounted_rotate_vertical" ---- | "is_ground_content" ---- | "sunlight_propagates" ---- | "walkable" ---- | "pointable" ---- | "diggable" ---- | "climbable" ---- | "move_resistance" ---- | "buildable_to" ---- | "floodable" ---- | "liquidtype" ---- | "liquid_alternative_flowing" ---- | "liquid_alternative_source" ---- | "liquid_viscosity" ---- | "liquid_renewable" ---- | "liquid_move_physics" ---- | "air_equivalent" ---- | "leveled" ---- | "leveled_max" ---- | "liquid_range" ---- | "drowning" ---- | "damage_per_second" ---- | "node_box" ---- | "connects_to" ---- | "connect_sides" ---- | "mesh" ---- | "selection_box" ---- | "collision_box" ---- | "legacy_wallmounted" ---- | "legacy_facedir_simple" ---- | "waving" ---- | "mod_origin" ---- | "sounds" ---- | "drop" ---- | "on_construct" ---- | "on_destruct" ---- | "after_destruct" ---- | "on_flood" ---- | "preserve_metadata" ---- | "after_place_node" ---- | "after_dig_node" ---- | "can_dig" ---- | "on_punch" ---- | "on_rightclick" ---- | "on_dig" ---- | "on_timer" ---- | "on_receive_fields" ---- | "allow_metadata_inventory_move" ---- | "allow_metadata_inventory_put" ---- | "allow_metadata_inventory_take" ---- | "on_metadata_inventory_move" ---- | "on_metadata_inventory_put" ---- | "on_metadata_inventory_take" ---- | "on_blast" - --- -------------------------------------------------------------------------- -- - ---[[ NodeDef.drawtype split off into ./drawtype.lua ]]-- - ---[[ -WIPDOC -]] ----@class core.NodeDef: core.ItemDef ---[[ -When used for nodes: Defines amount of light emitted by node. -Otherwise: Defines texture glow when viewed as a dropped item -To set the maximum (14), use the value 'core.LIGHT_MAX'. -A value outside the range 0 to core.LIGHT_MAX causes undefined -behavior. -]] ----@field light_source core.Light.source? ---[[ -visual_scale = 1.0, -Supported for drawtypes "plantlike", "signlike", "torchlike", -"firelike", "mesh", "nodebox", "allfaces". -For plantlike and firelike, the image will start at the bottom of the -node. For torchlike, the image will start at the surface to which the -node "attaches". For the other drawtypes the image will be centered -on the node. -]] ----@field visual_scale number? - ---[[ NodeDef.tiles .. NodeDef.special_tiles split off into ./tiles.lua ]]-- - --- ------------------------- color and transparency ------------------------- -- - ---[[ -WIPDOC -]] ----@alias core.NodeDef.use_texture_alpha ---- | "opaque" ---- | "clip" ---- | "blend" - ----@class core.NodeDef ---[[ -color = ColorSpec, -The node's original color will be multiplied with this color. -If the node has a palette, then this setting only has an effect in -the inventory and on the wield item. -]] ----@field color core.ColorSpec? ---[[ -use_texture_alpha = ..., -Specifies how the texture's alpha channel will be used for rendering. -Possible values: -* "opaque": - Node is rendered opaque regardless of alpha channel. -* "clip": - A given pixel is either fully see-through or opaque - depending on the alpha channel being below/above 50% in value. - Use this for nodes with fully transparent and fully opaque areas. -* "blend": - The alpha channel specifies how transparent a given pixel - of the rendered node is. This comes at a performance cost. - Only use this when correct rendering - among semitransparent nodes is necessary. -The default is "opaque" for drawtypes normal, liquid and flowingliquid, -mesh and nodebox or "clip" otherwise. -If set to a boolean value (deprecated): true either sets it to blend -or clip, false sets it to clip or opaque mode depending on the drawtype. - -* @deprecated 5.X `true` may blend or clip, `false` had special handling depending on drawtype -]] ----@field use_texture_alpha core.NodeDef.use_texture_alpha? ---[[ -palette = "", -The node's `param2` is used to select a pixel from the image. -Pixels are arranged from left to right and from top to bottom. -The node's color will be multiplied with the selected pixel's color. -Tiles can override this behavior. -Only when `paramtype2` supports palettes. -]] ----@field palette core.Texture? ---[[ -post_effect_color = "#00000000", -Screen tint if a player is inside this node, see `ColorSpec`. -Color is alpha-blended over the screen. -]] ----@field post_effect_color core.ColorSpec? ---[[ -post_effect_color_shaded = false, -Determines whether `post_effect_color` is affected by lighting. -]] ----@field post_effect_color_shaded boolean? - --- ---------------------------------- param --------------------------------- -- - ---[[ NodeDef.paramtype .. NodeDef.paramtype2 split off into ./paramtype2.lua ]]-- - ----@class core.NodeDef ---[[ -place_param2 = 0, -Value for param2 that is set when player places node -]] ----@field place_param2 core.Param2? ---[[ -wallmounted_rotate_vertical = false, -If true, place_param2 is nil, and this is a wallmounted node, -this node might use the special 90° rotation when placed -on the floor or ceiling, depending on the direction. -See the explanation about wallmounted for details. -Otherwise, the rotation is always the same on vertical placement. -]] ----@field wallmounted_rotate_vertical boolean? - - --- -------------------------------------------------------------------------- -- - ---[[ -WIPDOC -]] ----@alias core.NodeDef.move_resistance ---- | 0 ---- | 1 ---- | 2 ---- | 3 ---- | 4 ---- | 5 ---- | 6 ---- | 7 ---- | integer - ----@class core.NodeDef ---[[ -is_ground_content = true, -If false, the cave generator and dungeon generator will not carve -through this node. -Specifically, this stops mod-added nodes being removed by caves and -dungeons when those generate in a neighbor mapchunk and extend out -beyond the edge of that mapchunk. -]] ----@field is_ground_content boolean? ---[[ -sunlight_propagates = false, -If true, sunlight will go infinitely through this node -]] ----@field sunlight_propagates boolean? ---[[ -walkable = true, -- If true, objects collide with node -]] ----@field walkable boolean? ---[[ -pointable = true, -Can be `true` if it is pointable, `false` if it can be pointed through, -or `"blocking"` if it is pointable but not selectable. -Clients older than 5.9.0 interpret `pointable = "blocking"` as `pointable = true`. -Can be overridden by the `pointabilities` of the held item. -A client may be able to point non-pointable nodes, since it isn't checked server-side. -]] ----@field pointable boolean? ---[[ -diggable = true, -- If false, can never be dug -]] ----@field diggable boolean? ---[[ -climbable = false, -- If true, can be climbed on like a ladder -]] ----@field climbable boolean? ---[[ -move_resistance = 0, -Slows down movement of players through this node (max. 7). -If this is nil, it will be equal to liquid_viscosity. -Note: If liquid movement physics apply to the node -(see `liquid_move_physics`), the movement speed will also be -affected by the `movement_liquid_*` settings. -]] ----@field move_resistance core.NodeDef.move_resistance? ---[[ -buildable_to = false, -- If true, placed nodes can replace this node -]] ----@field buildable_to boolean? ---[[ -floodable = false, -If true, liquids flow into and replace this node. -Warning: making a liquid node 'floodable' will cause problems. -]] ----@field floodable boolean? - - --- ---------------------------- liquid properties --------------------------- -- - ---[[ -WIPDOC -]] ----@alias core.NodeDef.liquidtype ---- | "none" ---- | "source" ---- | "flowing" - ---[[ -WIPDOC -]] ----@alias core.NodeDef.liquid_viscosity ---- | 0 ---- | 1 ---- | 2 ---- | 3 ---- | 4 ---- | 5 ---- | 6 ---- | 7 ---- | integer - ----@class core.NodeDef ---[[ -liquidtype = "none", -- specifies liquid flowing physics -* "none": no liquid flowing physics -* "source": spawns flowing liquid nodes at all 4 sides and below; - recommended drawtype: "liquid". -* "flowing": spawned from source, spawns more flowing liquid nodes - around it until `liquid_range` is reached; - will drain out without a source; - recommended drawtype: "flowingliquid". -If it's "source" or "flowing", then the -`liquid_alternative_*` fields _must_ be specified -]] ----@field liquidtype core.NodeDef.liquidtype? ---[[ -`liquid_alternative_flowing` may contain the node name that represents -the flowing version of a liquid. - -This field is required if `liquidtype ~= "none"` or -`drawtype == "flowingliquid"`. - -Liquids consist of up to two nodes: source and flowing. - -There are two ways to define a liquid: -1) Source node and flowing node. This requires both fields to be - specified for both nodes. -2) Standalone source node (cannot flow). `liquid_alternative_source` - must be specified and `liquid_range` must be set to 0. - -Example: - liquid_alternative_flowing = "example:water_flowing", -]] ----@field liquid_alternative_flowing string? ---[[ -`liquid_alternative_source` may contain the node name that represents -the source version of a liquid. - -This field is required if `liquidtype ~= "none"` or -`drawtype == "flowingliquid"`. - -Liquids consist of up to two nodes: source and flowing. - -There are two ways to define a liquid: -1) Source node and flowing node. This requires both fields to be - specified for both nodes. -2) Standalone source node (cannot flow). `liquid_alternative_source` - must be specified and `liquid_range` must be set to 0. - -Example: - liquid_alternative_source = "example:water_source", -]] ----@field liquid_alternative_source string? ---[[ -liquid_viscosity = 0, -Controls speed at which the liquid spreads/flows (max. 7). -0 is fastest, 7 is slowest. -By default, this also slows down movement of players inside the node -(can be overridden using `move_resistance`) -]] ----@field liquid_viscosity core.NodeDef.liquid_viscosity? ---[[ -liquid_renewable = true, -If true, a new liquid source can be created by placing two or more -sources nearby -]] ----@field liquid_renewable boolean? ---[[ -liquid_move_physics = nil, -- specifies movement physics if inside node -* false: No liquid movement physics apply. -* true: Enables liquid movement physics. Enables things like - ability to "swim" up/down, sinking slowly if not moving, - smoother speed change when falling into, etc. The `movement_liquid_*` - settings apply. -* nil: Will be treated as true if `liquidtype ~= "none"` - and as false otherwise. -]] ----@field liquid_move_physics boolean? ---[[ -air_equivalent = nil, -unclear meaning, the engine sets this to true for 'air' and 'ignore' -deprecated. -Unofficial note: But what else are you supposed to do? i guess make an is_air function lmao - -* @deprecated 5.X -]] ----@field air_equivalent boolean? - --- --------------------------------- leveled -------------------------------- -- - ----@class core.NodeDef ---[[ -leveled = 0, -Only valid for "nodebox" drawtype with 'type = "leveled"'. -Allows defining the nodebox height without using param2. -The nodebox height is 'leveled' / 64 nodes. -The maximum value of 'leveled' is `leveled_max`. -]] ----@field leveled core.Param2.leveled? ---[[ -leveled_max = 127, -Maximum value for `leveled` (0-127), enforced in -`core.set_node_level` and `core.add_node_level`. -Values above 124 might causes collision detection issues. -]] ----@field leveled_max core.Param2.leveled? - --- -------------------------------------------------------------------------- -- - ---[[ -WIPDOC -]] ----@alias core.NodeDef.liquid_range ---- | 0 ---- | 1 ---- | 2 ---- | 3 ---- | 4 ---- | 5 ---- | 6 ---- | 7 ---- | 8 - ----@class core.NodeDef ---[[ -liquid_range = 8, -Maximum distance that flowing liquid nodes can spread around -source on flat land; -maximum = 8; set to 0 to disable liquid flow -]] ----@field liquid_range core.NodeDef.liquid_range? ---[[ -drowning = 0, -Player will take this amount of damage if no bubbles are left -]] ----@field drowning integer? ---[[ -damage_per_second = 0, -If player is inside node, this damage is caused -]] ----@field damage_per_second integer? - --- -------------------------- node shape properties ------------------------- -- - ---[[ -WIPDOC -]] ----@alias core.NodeDef.connect_side ---- | "top" ---- | "bottom" ---- | "front" ---- | "left" ---- | "back" ---- | "right" - ----@class core.NodeDef ---[[ -node_box = {type = "regular"}, -- See "Node boxes" -]] ----@field node_box core.NodeBox? ---[[ -connects_to = {}, -Used for nodebox nodes with the type == "connected". -Specifies to what neighboring nodes connections will be drawn. -e.g. `{"group:fence", "default:wood"}` or `"default:stone"` -]] ----@field connects_to OneOrMany? ---[[ -connect_sides = {}, -Tells connected nodebox nodes to connect only to these sides of this -node. possible: "top", "bottom", "front", "left", "back", "right" -]] ----@field connect_sides core.NodeDef.connect_side[]? ---[[ -mesh = "", -File name of mesh when using "mesh" drawtype -The center of the node is the model origin. -For legacy reasons, this uses a different scale depending on the mesh: -1. For glTF models: 10 units = 1 node (consistent with the scale for entities). -2. For obj models: 1 unit = 1 node. -3. For b3d and x models: 1 unit = 1 node if static, otherwise 10 units = 1 node. -Using static glTF or obj models is recommended. -You can use the `visual_scale` multiplier to achieve the expected scale. -]] ----@field mesh core.Path? ---[[ -selection_box = { -see [Node boxes] for possibilities -}, -Custom selection box definition. Multiple boxes can be defined. -If "nodebox" drawtype is used and selection_box is nil, then node_box -definition is used for the selection box. -]] ----@field selection_box core.NodeBox? ---[[ -collision_box = { -see [Node boxes] for possibilities -}, -Custom collision box definition. Multiple boxes can be defined. -If "nodebox" drawtype is used and collision_box is nil, then node_box -definition is used for the collision box. -]] ----@field collision_box core.NodeBox? - --- -------------------------------------------------------------------------- -- - ---[[ -WIPDOC -]] ----@alias core.NodeDef.waving ---- | 0 ---- | 1 ---- | 2 ---- | 3 - ----@class core.NodeDef ---[[ -Support maps made in and before January 2012 -]] ----@field legacy_wallmounted boolean? ---[[ -Support maps made in and before January 2012 -]] ----@field legacy_facedir_simple boolean? ---[[ -waving = 0, -Valid for drawtypes: -mesh, nodebox, plantlike, allfaces_optional, liquid, flowingliquid. -1 - wave node like plants (node top moves side-to-side, bottom is fixed) -2 - wave node like leaves (whole node moves side-to-side) -3 - wave node like liquids (whole node moves up and down) -Not all models will properly wave. -plantlike drawtype can only wave like plants. -allfaces_optional drawtype can only wave like leaves. -liquid, flowingliquid drawtypes can only wave like liquids. -]] ----@field waving core.NodeDef.waving? - ---[[ NodeDefBase.sounds split off into ./sounds.lua ]]-- - ---[[ NodeDef.drop split off into ./drop.lua ]]-- - ----@class core.NodeDef ---[[ -mod_origin = "modname", -stores which mod actually registered a node -If the source could not be determined it contains "??" -Useful for getting which mod truly registered something -example: if a node is registered as ":othermodname:nodename", -nodename will show "othermodname", but mod_origin will say "modname" -]] ----@field mod_origin string? - --- -------------------------------- callbacks ------------------------------- -- - ---[[ -WIPDOC -]] ----@alias core.NodeDef.on_construct fun(pos:ivec) - ---[[ -WIPDOC -]] ----@alias core.NodeDef.on_destruct fun(pos:ivec?) - ---[[ -WIPDOC -]] ----@alias core.NodeDef.after_destruct fun(pos:ivec, oldnode:core.Node.get) - ---[[ -WIPDOC -]] ----@alias core.NodeDef.on_flood fun(pos:ivec, oldnode:core.Node.get, newnode:core.Node.get):boolean? - ---[[ -WIPDOC -]] ----@alias core.NodeDef.preserve_metadata fun(pos:ivec, oldnode:core.Node.get, oldmeta:core.MetadataTable.node.get) - ---[[ -WIPDOC -]] ----@alias core.NodeDef.after_place_node fun(pos:ivec, placer:core.ObjectRef?, itemstack:core.ItemStack, pointed_thing:core.PointedThing) - ---[[ -WIPDOC -]] ----@alias core.NodeDef.after_dig_node fun(pos:ivec, oldnode:core.Node.get, oldmetadata:core.MetadataTable.node.get, digger:core.ObjectRef?) - ---[[ -WIPDOC -]] ----@alias core.NodeDef.can_dig fun(pos:ivec, player:core.ObjectRef?):boolean - ---[[ -WIPDOC -]] ----@alias core.NodeDef.on_punch fun(pos:ivec, node:core.Node.get, puncher:core.ObjectRef?, pointed_thing:core.PointedThing) - ---[[ -WIPDOC -]] ----@alias core.NodeDef.on_rightclick fun(pos:ivec, node:core.Node.get, clicker:core.ObjectRef?, itemstack:core.ItemStack, pointed_thing:core.PointedThing?):core.ItemStack? - ---[[ -WIPDOC - -* @deprecated 5.X returning `nil` is the same are `true` -]] ----@alias core.NodeDef.on_dig fun(pos:ivec, node:core.Node.get, digger:core.ObjectRef?):boolean - ---[[ -WIPDOC -]] ----@alias core.NodeDef.on_timer fun(pos:ivec, elapsed:number, node:core.Node.get, timeout:number):boolean? - ---[[ -WIPDOC -]] ----@alias core.NodeDef.on_receive_fields fun(pos:ivec, formname:"", fields: core.FormspecFields, sender:core.ObjectRef) - ---[[ -WIPDOC -]] ----@alias core.NodeDef.allow_metadata_inventory_move fun(pos:ivec, from_list:core.InventoryList, from_index:integer, to_list:core.InventoryList, to_index:integer, count:integer, player:core.ObjectRef):integer - ---[[ -WIPDOC -]] ----@alias core.NodeDef.allow_metadata_inventory_put fun(pos:ivec, listname:core.InventoryList, index:integer, stack:core.ItemStack, player:core.ObjectRef):integer - ---[[ -WIPDOC -]] ----@alias core.NodeDef.allow_metadata_inventory_take fun(pos:ivec, listname:core.InventoryList, index:integer, stack:core.ItemStack, player:core.ObjectRef):integer - ---[[ -WIPDOC -]] ----@alias core.NodeDef.on_metadata_inventory_move fun(pos:ivec, from_list:core.InventoryList, from_index:integer, to_list:core.InventoryList, to_index:integer, count:integer, player:core.ObjectRef):nil - ---[[ -WIPDOC -]] ----@alias core.NodeDef.on_metadata_inventory_put fun(pos:ivec, listname:core.InventoryList, index:integer, stack:core.ItemStack, player:core.ObjectRef):nil - ---[[ -WIPDOC -]] ----@alias core.NodeDef.on_metadata_inventory_take fun(pos:ivec, listname:core.InventoryList, index:integer, stack:core.ItemStack, player:core.ObjectRef):nil - ---[[ -WIPDOC -]] ----@alias core.NodeDef.on_blast fun(pos:ivec, intensity:number?) - ----@class core.NodeDef ---[[ -on_construct = function(pos), -Node constructor; called after adding node. -Can set up metadata and stuff like that. -Not called for bulk node placement (i.e. schematics and VoxelManip). -Note: Within an on_construct callback, core.set_node can cause an -infinite loop if it invokes the same callback. - Consider using core.swap_node instead. -default: nil -]] ----@field on_construct core.NodeDef.on_construct? ---[[ -on_destruct = function(pos), -Node destructor; called before removing node. -Not called for bulk node placement. -default: nil -]] ----@field on_destruct core.NodeDef.on_destruct? ---[[ -after_destruct = function(pos, oldnode), -Node destructor; called after removing node. -Not called for bulk node placement. -default: nil -]] ----@field after_destruct core.NodeDef.after_destruct? ---[[ -on_flood = function(pos, oldnode, newnode), -Called when a liquid (newnode) is about to flood oldnode, if it has -`floodable = true` in the nodedef. Not called for bulk node placement -(i.e. schematics and VoxelManip) or air nodes. If return true the -node is not flooded, but on_flood callback will most likely be called -over and over again every liquid update interval. -Default: nil -Warning: making a liquid node 'floodable' will cause problems. -]] ----@field on_flood core.NodeDef.on_flood? ---[[ -preserve_metadata = function(pos, oldnode, oldmeta, drops), -Called when `oldnode` is about be converted to an item, but before the -node is deleted from the world or the drops are added. This is -generally the result of either the node being dug or an attached node -becoming detached. -* `pos`: node position -* `oldnode`: node table of node before it was deleted -* `oldmeta`: metadata of node before it was deleted, as a metadata table -* `drops`: a table of `ItemStack`s, so any metadata to be preserved can - be added directly to one or more of the dropped items. See - "ItemStackMetaRef". -default: `nil` -]] ----@field preserve_metadata core.NodeDef.preserve_metadata? ---[[ -after_place_node = function(pos, placer, itemstack, pointed_thing), -Called after constructing node when node was placed using -core.item_place_node / core.place_node. -If return true no item is taken from itemstack. -`placer` may be any valid ObjectRef or nil. -default: nil -]] ----@field after_place_node core.NodeDef.after_place_node? ---[[ -after_dig_node = function(pos, oldnode, oldmetadata, digger), -Called after destructing the node when node was dug using -`core.node_dig` / `core.dig_node`. -* `pos`: node position -* `oldnode`: node table of node before it was dug -* `oldmetadata`: metadata of node before it was dug, - as a metadata table -* `digger`: ObjectRef of digger -default: nil -]] ----@field after_dig_node core.NodeDef.after_dig_node? ---[[ -can_dig = function(pos, [player]), -Returns true if node can be dug, or false if not. -default: nil -]] ----@field can_dig core.NodeDef.can_dig? ---[[ -on_punch = function(pos, node, puncher, pointed_thing), -default: core.node_punch -Called when puncher (an ObjectRef) punches the node at pos. -By default calls core.register_on_punchnode callbacks. -]] ----@field on_punch core.NodeDef.on_punch? ---[[ -on_rightclick = function(pos, node, clicker, itemstack, pointed_thing), -default: nil -Called when clicker (an ObjectRef) used the 'place/build' key -(not necessarily an actual rightclick) -while pointing at the node at pos with 'node' being the node table. -itemstack will hold clicker's wielded item. -Shall return the leftover itemstack. -Note: pointed_thing can be nil, if a mod calls this function. -This function does not get triggered by clients <=0.4.16 if the -"formspec" node metadata field is set. -]] ----@field on_rightclick core.NodeDef.on_rightclick? ---[[ -on_dig = function(pos, node, digger), -default: core.node_dig -By default checks privileges, wears out item (if tool) and removes node. -return true if the node was dug successfully, false otherwise. -Deprecated: returning nil is the same as returning true. -]] ----@field on_dig core.NodeDef.on_dig? ---[[ -on_timer = function(pos, elapsed), -default: nil -called by NodeTimers, see core.get_node_timer and NodeTimerRef. -elapsed is the total time passed since the timer was started. -return true to run the timer for another cycle with the same timeout -value. -]] ----@field on_timer core.NodeDef.on_timer? ---[[ -on_receive_fields = function(pos, formname, fields, sender), -fields = {name1 = value1, name2 = value2, ...} -formname should be the empty string; you **must not** use formname. -Called when an UI form (e.g. sign text input) returns data. -See core.register_on_player_receive_fields for more info. -default: nil -]] ----@field on_receive_fields core.NodeDef.on_receive_fields? ---[[ -allow_metadata_inventory_move = function(pos, from_list, from_index, to_list, to_index, count, player), -Called when a player wants to move items inside the inventory. -Return value: number of items allowed to move. -]] ----@field allow_metadata_inventory_move core.NodeDef.allow_metadata_inventory_move? ---[[ -allow_metadata_inventory_put = function(pos, listname, index, stack, player), -Called when a player wants to put something into the inventory. -Return value: number of items allowed to put. -Return value -1: Allow and don't modify item count in inventory. -]] ----@field allow_metadata_inventory_put core.NodeDef.allow_metadata_inventory_put? ---[[ -allow_metadata_inventory_take = function(pos, listname, index, stack, player), -Called when a player wants to take something out of the inventory. -Return value: number of items allowed to take. -Return value -1: Allow and don't modify item count in inventory. -]] ----@field allow_metadata_inventory_take core.NodeDef.allow_metadata_inventory_take? ---[[ -on_metadata_inventory_move = function(pos, from_list, from_index, to_list, to_index, count, player), -Called after the actual action has happened, according to what was -allowed. -No return value. -]] ----@field on_metadata_inventory_move core.NodeDef.on_metadata_inventory_move? ---[[ -on_metadata_inventory_put = function(pos, listname, index, stack, player), -Called after the actual action has happened, according to what was -allowed. -No return value. -]] ----@field on_metadata_inventory_put core.NodeDef.on_metadata_inventory_put? ---[[ -on_metadata_inventory_take = function(pos, listname, index, stack, player), -Called after the actual action has happened, according to what was -allowed. -No return value. -]] ----@field on_metadata_inventory_take core.NodeDef.on_metadata_inventory_take? ---[[ -on_blast = function(pos, intensity), -intensity: 1.0 = mid range of regular TNT. -If defined, called when an explosion touches the node, instead of -removing the node. -Unofficial note: this is a custom field, just documented in lua_api.md i assume because TNT mods usually don't handle indestructible nodes/whatever very well -]] ----@field on_blast core.NodeDef.on_blast? \ No newline at end of file diff --git a/types/luanti_lsp_definitions/library/defs/node/paramtype.lua b/types/luanti_lsp_definitions/library/defs/node/paramtype.lua deleted file mode 100644 index ae5811a6..00000000 --- a/types/luanti_lsp_definitions/library/defs/node/paramtype.lua +++ /dev/null @@ -1,72 +0,0 @@ ----@meta _ --- DRAFT 1 DONE --- luanti/doc/lua_api.md: Nodes > Node paramtypes --- luanti/doc/lua_api.md: Definition tables > Node definition - --- --------------------------- NodeDef.paramtype2 --------------------------- -- - ---[[ -WIPDOC -]] ----@alias core.NodeDef.paramtype ---- | "light" ---- | "none" - ---[[ -WIPDOC -]] ----@alias core.NodeDef.paramtype2.color ---- | "color" ---- | "colorfacedir" ---- | "color4dir" ---- | "colorwallmounted" ---- | "colordegrotate" - ---[[ -WIPDOC -]] ----@alias core.NodeDef.paramtype2 ---- | "flowingliquid" ---- | "wallmounted" ---- | "facedir" ---- | "4dir" ---- | "leveled" ---- | "degrotate" ---- | "meshoptions" ---- | "color" ---- | "colorfacedir" ---- | "color4dir" ---- | "colorwallmounted" ---- | "glasslikeliquidlevel" ---- | "colordegrotate" ---- | "none" - --- ----------------------------- NodeDef fields ----------------------------- -- - ----@class core.NodeDef ---[[ -paramtype = "none", -- See "Nodes" -* `paramtype = "light"` - * The value stores light with and without sun in its lower and upper 4 bits - respectively. - * Required by a light source node to enable spreading its light. - * Required by the following drawtypes as they determine their visual - brightness from their internal light value: - * torchlike - * signlike - * firelike - * fencelike - * raillike - * nodebox - * mesh - * plantlike - * plantlike_rooted -* `paramtype = "none"` - * `param1` will not be used by the engine and can be used to store - an arbitrary value -]] ----@field paramtype core.NodeDef.paramtype? ---[[ -WIPDOC -]] ----@field paramtype2 core.NodeDef.paramtype2? diff --git a/types/luanti_lsp_definitions/library/defs/node/sounds.lua b/types/luanti_lsp_definitions/library/defs/node/sounds.lua deleted file mode 100644 index ec9e855e..00000000 --- a/types/luanti_lsp_definitions/library/defs/node/sounds.lua +++ /dev/null @@ -1,42 +0,0 @@ ----@meta _ --- DRAFT 1 DONE --- luanti/doc/lua_api.md: Definition tables > Node definition - --- ----------------------------- NodeDef.sounds ----------------------------- -- - ---[[ -WIPDOC -]] ----@class core.NodeDef.sounds ---[[ -WIPDOC -]] ----@field footstep core.SimpleSoundSpec? ---[[ -WIPDOC -]] ----@field dig core.SimpleSoundSpec|"__group"? ---[[ -WIPDOC -]] ----@field dug core.SimpleSoundSpec? ---[[ -WIPDOC -]] ----@field place core.SimpleSoundSpec? ---[[ -WIPDOC -]] ----@field place_failed core.SimpleSoundSpec? ---[[ -WIPDOC -]] ----@field fall core.SimpleSoundSpec? - --- ----------------------------- NodeDef fields ----------------------------- -- - ----@class core.NodeDef ---[[ -WIPDOC -]] ----@field sounds core.NodeDef.sounds diff --git a/types/luanti_lsp_definitions/library/defs/node/tiles.lua b/types/luanti_lsp_definitions/library/defs/node/tiles.lua deleted file mode 100644 index 5a76da56..00000000 --- a/types/luanti_lsp_definitions/library/defs/node/tiles.lua +++ /dev/null @@ -1,85 +0,0 @@ ----@meta _ --- DRAFT 1 DONE --- luanti/doc/lua_api.md: Definition tables > Node definition - --- ------------------------------ NodeDef.tiles ----------------------------- -- - ---[[ -WIPDOC -]] ----@class core.NodeDef.tiles.strict ---[[ -WIPDOC -]] ----@field [1] core.TileDef? ---[[ -WIPDOC -]] ----@field [2] core.TileDef? ---[[ -WIPDOC -]] ----@field [3] core.TileDef? ---[[ -WIPDOC -]] ----@field [4] core.TileDef? ---[[ -WIPDOC -]] ----@field [5] core.TileDef? ---[[ -WIPDOC -]] ----@field [6] core.TileDef? - ---[[ -WIPDOC -]] ----@alias core.NodeDef.tiles ---- | core.NodeDef.tiles.strict ---- | core.TileDef[] - --- -------------------------- NodeDef.special_tiles ------------------------- -- - ----@class core.NodeDef.special_tiles.strict ---[[ -WIPDOC -]] ----@field [1] core.TileDef? ---[[ -WIPDOC -]] ----@field [2] core.TileDef? - ---[[ -WIPDOC -]] ----@alias core.NodeDef.special_tiles ---- | core.NodeDef.special_tiles.strict ---- | core.TileDef[] - --- ----------------------------- NodeDef fields ----------------------------- -- - ----@class core.NodeDef ---[[ -tiles = {tile definition 1, def2, def3, def4, def5, def6}, -Textures of node; +Y, -Y, +X, -X, +Z, -Z -List can be shortened to needed length. -]] ----@field tiles core.NodeDef.tiles? ---[[ -overlay_tiles = {tile definition 1, def2, def3, def4, def5, def6}, -Same as `tiles`, but these textures are drawn on top of the base -tiles. You can use this to colorize only specific parts of your -texture. If the texture name is an empty string, that overlay is not -drawn. Since such tiles are drawn twice, it is not recommended to use -overlays on very common nodes. -]] ----@field overlay_tiles core.NodeDef.tiles? ---[[ -special_tiles = {tile definition 1, Tile definition 2}, -Special textures of node; used rarely. -List can be shortened to needed length. -]] ----@field special_tiles core.NodeDef.special_tiles? \ No newline at end of file diff --git a/types/luanti_lsp_definitions/library/defs/noiseparams.lua b/types/luanti_lsp_definitions/library/defs/noiseparams.lua deleted file mode 100644 index c313643f..00000000 --- a/types/luanti_lsp_definitions/library/defs/noiseparams.lua +++ /dev/null @@ -1,209 +0,0 @@ ----@meta _ --- DRAFT 1 DONE --- luanti/doc/lua_api.md: Fractal Value Noise --- luanti/doc/lua_api.md: Flag Specifier Format - --- ---------------------------- NoiseParams.flags --------------------------- -- - ---[[ -WIPDOC -]] ----@class core.NoiseParams.flags.tablefmt ---[[ -WIPDOC -]] ----@field defaults boolean ---[[ -WIPDOC -]] ----@field nodefaults boolean ---[[ -WIPDOC -]] ----@field eased boolean ---[[ -WIPDOC -]] ----@field noeased boolean ---[[ -WIPDOC -]] ----@field absvalue boolean ---[[ -WIPDOC -]] ----@field noabsvalue boolean - ---[[ -WIPDOC -]] ----@alias core.NoiseParams.flags.stringfmt string - ---[[ -WIPDOC -]] ----@alias core.NoiseParams.flags ---- | core.NoiseParams.flags.tablefmt ---- | core.NoiseParams.flags.stringfmt - --- --------------------------- NoiseParams.__base --------------------------- -- - ----@class _.NoiseParams.__base ---[[ -After the multiplication by `scale` this is added to the result and is the final -step in creating the noise value. -Can be positive or negative. -]] ----@field offset number ---[[ -Once all octaves have been combined, the result is multiplied by this. -Can be positive or negative. -]] ----@field scale number ---[[ -This is a whole number that determines the entire pattern of the noise -variation. Altering it enables different noise patterns to be created. -With other parameters equal, different seeds produce different noise patterns -and identical seeds produce identical noise patterns. - -For this parameter you can randomly choose any whole number. Usually it is -preferable for this to be different from other seeds, but sometimes it is useful -to be able to create identical noise patterns. - -In some noise APIs the world seed is added to the seed specified in noise -parameters. This is done to make the resulting noise pattern vary in different -worlds, and be 'world-specific'. -]] ----@field seed integer ---[[ -The number of simple noise generators that are combined. -A whole number, 1 or more. -Each additional octave adds finer detail to the noise but also increases the -noise calculation load. -3 is a typical minimum for a high quality, complex and natural-looking noise -variation. 1 octave has a slight 'gridlike' appearance. - -Choose the number of octaves according to the `spread` and `lacunarity`, and the -size of the finest detail you require. For example: -if `spread` is 512 nodes, `lacunarity` is 2.0 and finest detail required is 16 -nodes, octaves will be 6 because the 'wavelengths' of the octaves will be -512, 256, 128, 64, 32, 16 nodes. -Warning: If the 'wavelength' of any octave falls below 1 an error will occur. -]] ----@field octaves integer ---[[ -Each additional octave has an amplitude that is the amplitude of the previous -octave multiplied by `persistence`, to reduce the amplitude of finer details, -as is often helpful and natural to do so. -Since this controls the balance of fine detail to large-scale detail -`persistence` can be thought of as the 'roughness' of the noise. - -A positive or negative non-zero number, often between 0.3 and 1.0. -A common medium value is 0.5, such that each octave has half the amplitude of -the previous octave. -This may need to be tuned when altering `lacunarity`; when doing so consider -that a common medium value is 1 / lacunarity. - -Instead of `persistence`, the key `persist` may be used to the same effect. -]] ----@field persistence number? ---[[ -WIPDOC -]] ----@field persist number? ---[[ -Each additional octave has a 'wavelength' that is the 'wavelength' of the -previous octave multiplied by 1 / lacunarity, to create finer detail. -'lacunarity' is often 2.0 so 'wavelength' often halves per octave. - -A positive number no smaller than 1.0. -Values below 2.0 create higher quality noise at the expense of requiring more -octaves to cover a particular range of 'wavelengths'. -]] ----@field lacunarity number? ---[[ -Leave this field unset for no special handling. -Currently supported are `defaults`, `eased` and `absvalue`: -]] ----@field flags core.NoiseParams.flags? - --- ------------------------------- NoiseParams ------------------------------ -- - ---[[ -### Format example - -For 2D or 3D value noise or value noise maps: - -```lua -np_terrain = { - offset = 0, - scale = 1, - spread = {x = 500, y = 500, z = 500}, - seed = 571347, - octaves = 5, - persistence = 0.63, - lacunarity = 2.0, - flags = "defaults, absvalue", -} -``` - -For 2D noise the Z component of `spread` is still defined but is ignored. -A single noise parameter table can be used for 2D or 3D noise. -]] ----@class core.NoiseParams.2d : _.NoiseParams.__base ---[[ -For octave1, this is roughly the change of input value needed for a very large -variation in the noise value generated by octave1. It is almost like a -'wavelength' for the wavy noise variation. -Each additional octave has a 'wavelength' that is smaller than the previous -octave, to create finer detail. `spread` will therefore roughly be the typical -size of the largest structures in the final noise variation. - -`spread` is a vector with values for x, y, z to allow the noise variation to be -stretched or compressed in the desired axes. -Values are positive numbers. -]] ----@field spread vec2.xy - ---[[ -### Format example - -For 2D or 3D value noise or value noise maps: - -```lua -np_terrain = { - offset = 0, - scale = 1, - spread = {x = 500, y = 500, z = 500}, - seed = 571347, - octaves = 5, - persistence = 0.63, - lacunarity = 2.0, - flags = "defaults, absvalue", -} -``` - -For 2D noise the Z component of `spread` is still defined but is ignored. -A single noise parameter table can be used for 2D or 3D noise. -]] ----@class core.NoiseParams.3d : _.NoiseParams.__base ---[[ -For octave1, this is roughly the change of input value needed for a very large -variation in the noise value generated by octave1. It is almost like a -'wavelength' for the wavy noise variation. -Each additional octave has a 'wavelength' that is smaller than the previous -octave, to create finer detail. `spread` will therefore roughly be the typical -size of the largest structures in the final noise variation. - -`spread` is a vector with values for x, y, z to allow the noise variation to be -stretched or compressed in the desired axes. -Values are positive numbers. -]] ----@field spread vector - ---[[ -WIPDOC -]] ----@alias core.NoiseParams ---- | core.NoiseParams.2d ---- | core.NoiseParams.3d \ No newline at end of file diff --git a/types/luanti_lsp_definitions/library/defs/object_properties/box.lua b/types/luanti_lsp_definitions/library/defs/object_properties/box.lua deleted file mode 100644 index 65d1bfdf..00000000 --- a/types/luanti_lsp_definitions/library/defs/object_properties/box.lua +++ /dev/null @@ -1,109 +0,0 @@ ----@meta _ --- DRAFT 1 DONE --- luanti/doc/lua_api.md: Definition tables > Object properties - --- ------------------ ObjectProperties.collisionbox.strict ------------------ -- - ---[[ -WIPDOC -]] ----@class core.ObjectProperties.collisionbox.strict ---[[ -WIPDOC -]] ----@field [1] number ---[[ -WIPDOC -]] ----@field [2] number ---[[ -WIPDOC -]] ----@field [3] number ---[[ -WIPDOC -]] ----@field [4] number ---[[ -WIPDOC -]] ----@field [5] number ---[[ -WIPDOC -]] ----@field [6] number - ---[[ -WIPDOC -]] ----@alias core.ObjectProperties.collisionbox ---- | core.ObjectProperties.collisionbox.strict ---- | number[] - --- ------------------ ObjectProperties.selectionbox.strict ------------------ -- - ---[[ -WIPDOC ---]] ----@class core.ObjectProperties.selectionbox.strict.set : core.ObjectProperties.collisionbox.strict ---[[ -WIPDOC -]] ----@field rotate boolean? - ---[[ -WIPDOC ---]] ----@class core.ObjectProperties.selectionbox.strict.get : core.ObjectProperties.collisionbox.strict ---[[ -WIPDOC -]] ----@field rotate boolean - ---[[ -WIPDOC -]] ----@alias core.ObjectProperties.selectionbox.set ---- | core.ObjectProperties.selectionbox.strict.set ---- | number[] - ---[[ -WIPDOC -]] ----@alias core.ObjectProperties.selectionbox.get ---- | core.ObjectProperties.selectionbox.strict.get ---- | number[] - --- ----------------------- ObjectPropertiesBase fields ---------------------- -- - ----@class _.ObjectProperties.__base.set ---[[ -{ xmin, ymin, zmin, xmax, ymax, zmax } in nodes from object position. -Collision boxes cannot rotate, setting `rotate = true` on it has no effect. -If not set, the selection box copies the collision box, and will also not rotate. -]] ----@field collisionbox core.ObjectProperties.collisionbox? ---[[ -If `rotate = false`, the selection box will not rotate with the object itself, remaining fixed to the axes. -If `rotate = true`, it will match the object's rotation and any attachment rotations. -Raycasts use the selection box and object's rotation, but do *not* obey attachment rotations. -For server-side raycasts to work correctly, -the selection box should extend at most 5 units in each direction. -]] ----@field selectionbox core.ObjectProperties.selectionbox.set? - ----@class _.ObjectProperties.__base.get ---[[ -{ xmin, ymin, zmin, xmax, ymax, zmax } in nodes from object position. -Collision boxes cannot rotate, setting `rotate = true` on it has no effect. -If not set, the selection box copies the collision box, and will also not rotate. -]] ----@field collisionbox core.ObjectProperties.collisionbox ---[[ -If `rotate = false`, the selection box will not rotate with the object itself, remaining fixed to the axes. -If `rotate = true`, it will match the object's rotation and any attachment rotations. -Raycasts use the selection box and object's rotation, but do *not* obey attachment rotations. -For server-side raycasts to work correctly, -the selection box should extend at most 5 units in each direction. -]] ----@field selectionbox core.ObjectProperties.selectionbox.get diff --git a/types/luanti_lsp_definitions/library/defs/object_properties/object_properties.lua b/types/luanti_lsp_definitions/library/defs/object_properties/object_properties.lua deleted file mode 100644 index d90eb566..00000000 --- a/types/luanti_lsp_definitions/library/defs/object_properties/object_properties.lua +++ /dev/null @@ -1,300 +0,0 @@ ----@meta _ --- DRAFT 1 DONE --- luanti/doc/lua_api.md: Entity damage mechanism --- luanti/doc/lua_api.md: Definition tables > Object properties - --- Default values are injected, so nil value does not persist -> .set and .get - --- INTERPRETATION: follow the same interpretation in ObjectRef. ObjectProperties --- assumes it's an entity, and its fields overridden by PlayerProperties. If --- there were any entity exclusive fields, EntityProperties would exist - ---[[ -WIPDOC -]] -core.PLAYER_MAX_HP_DEFAULT = 20 - ---[[ -WIPDOC -]] -core.PLAYER_MAX_BREATH_DEFAULT = 10 - --- ------------------------- ObjectProperties.__base ------------------------ -- - ----@class _.ObjectProperties.__base.set ---[[ -Defines the maximum and default HP of the object. -For Lua entities, the maximum is not enforced. -For players, this defaults to `core.PLAYER_MAX_HP_DEFAULT` (20). -For Lua entities, the default is 10. -]] ----@field hp_max integer? - ----@class _.ObjectProperties.__base.get ---[[ -Defines the maximum and default HP of the object. -For Lua entities, the maximum is not enforced. -For players, this defaults to `core.PLAYER_MAX_HP_DEFAULT` (20). -For Lua entities, the default is 10. -]] ----@field hp_max integer - --- -------------------------------- collision ------------------------------- -- - ----@class _.ObjectProperties.__base.set ---[[ -Collide with `walkable` nodes. -]] ----@field physical boolean? ---[[ -Collide with other objects if physical = true -]] ----@field collide_with_objects boolean? - - ----@class _.ObjectProperties.__base.get ---[[ -Collide with `walkable` nodes. -]] ----@field physical boolean ---[[ -Collide with other objects if physical = true -]] ----@field collide_with_objects boolean - ---[[ ObjectPropertiesBaseSet.collisionbox .. ObjectPropertiesBaseGet.selectionbox split off into box.lua ]]-- - --- -------------------------------------------------------------------------- -- - ----@class _.ObjectProperties.__base.set ---[[ -Can be `true` if it is pointable, `false` if it can be pointed through, -or `"blocking"` if it is pointable but not selectable. -Clients older than 5.9.0 interpret `pointable = "blocking"` as `pointable = true`. -Can be overridden by the `pointabilities` of the held item. -]] ----@field pointable "blocking"|boolean? ---[[ -Multipliers for the visual size. If `z` is not specified, `x` will be used -to scale the entity along both horizontal axes. -]] ----@field visual_size vector? ---[[ -Currently unused. -]] ----@field colors {}? ---[[ -If false, object is invisible and can't be pointed. -]] ----@field is_visible boolean? ---[[ -If true, object is able to make footstep sounds of nodes -(see node sound definition for details). -]] ----@field makes_footstep_sound boolean? ---[[ -Set constant rotation in radians per second, positive or negative. -Object rotates along the local Y-axis, and works with set_rotation. -Set to 0 to disable constant rotation. -]] ----@field automatic_rotate number? ---[[ -If positive number, object will climb upwards when it moves -horizontally against a `walkable` node, if the height difference -is within `stepheight` and if the object current max Y in the world -is greater or equal than the node min Y. -]] ----@field stepheight number? ---[[ -Automatically set yaw to movement direction, offset in degrees. -'false' to disable. -]] ----@field automatic_face_movement_dir number|false? ---[[ -Limit automatic rotation to this value in degrees per second. -No limit if value <= 0. -]] ----@field automatic_face_movement_max_rotation_per_sec number? ---[[ -Add this much extra lighting when calculating texture color. -Value < 0 disables light's effect on texture color. -For faking self-lighting, UI style entities, or programmatic coloring -in mods. -]] ----@field glow core.Light.source? - ----@class _.ObjectProperties.__base.get ---[[ -Can be `true` if it is pointable, `false` if it can be pointed through, -or `"blocking"` if it is pointable but not selectable. -Clients older than 5.9.0 interpret `pointable = "blocking"` as `pointable = true`. -Can be overridden by the `pointabilities` of the held item. -]] ----@field pointable "blocking"|boolean ---[[ -Multipliers for the visual size. If `z` is not specified, `x` will be used -to scale the entity along both horizontal axes. -]] ----@field visual_size vector ---[[ -Currently unused. -]] ----@field colors {} ---[[ -If false, object is invisible and can't be pointed. -]] ----@field is_visible boolean ---[[ -If true, object is able to make footstep sounds of nodes -(see node sound definition for details). -]] ----@field makes_footstep_sound boolean ---[[ -Set constant rotation in radians per second, positive or negative. -Object rotates along the local Y-axis, and works with set_rotation. -Set to 0 to disable constant rotation. -]] ----@field automatic_rotate number ---[[ -If positive number, object will climb upwards when it moves -horizontally against a `walkable` node, if the height difference -is within `stepheight` and if the object current max Y in the world -is greater or equal than the node min Y. -]] ----@field stepheight number ---[[ -Automatically set yaw to movement direction, offset in degrees. -'false' to disable. -]] ----@field automatic_face_movement_dir number|false ---[[ -Limit automatic rotation to this value in degrees per second. -No limit if value <= 0. -]] ----@field automatic_face_movement_max_rotation_per_sec number ---[[ -Add this much extra lighting when calculating texture color. -Value < 0 disables light's effect on texture color. -For faking self-lighting, UI style entities, or programmatic coloring -in mods. -]] ----@field glow core.Light.source - --- --------------------------------- nametag -------------------------------- -- - ----@class _.ObjectProperties.__base.set ---[[ -The name to display on the head of the object. By default empty. -If the object is a player, a nil or empty nametag is replaced by the player's name. -For all other objects, a nil or empty string removes the nametag. -To hide a nametag, set its color alpha to zero. That will disable it entirely. -]] ----@field nametag string? ---[[ -Sets text color of nametag -]] ----@field nametag_color core.ColorSpec? ---[[ -Sets background color of nametag -`false` will cause the background to be set automatically based on user settings. -Default: false -]] ----@field nametag_bgcolor core.ColorSpec? ---[[ -Sets the font size of the nametag in pixels. -`false` will cause the size to be set automatically based on user settings. -Default: false -]] ----@field nametag_fontsize integer|false? ---[[ -Sets the font size of the nametag in pixels. -`false` will cause the size to be set automatically based on user settings. -Default: false -]] ----@field nametag_scale_z boolean? - ----@class _.ObjectProperties.__base.get ---[[ -The name to display on the head of the object. By default empty. -If the object is a player, a nil or empty nametag is replaced by the player's name. -For all other objects, a nil or empty string removes the nametag. -To hide a nametag, set its color alpha to zero. That will disable it entirely. -]] ----@field nametag string ---[[ -Sets text color of nametag -]] ----@field nametag_color core.ColorSpec ---[[ -Sets background color of nametag -`false` will cause the background to be set automatically based on user settings. -Default: false -]] ----@field nametag_bgcolor core.ColorSpec - - --- -------------------------------------------------------------------------- -- - ----@class _.ObjectProperties.__base.set ---[[ -Same as infotext for nodes. Empty by default -]] ----@field infotext string? ---[[ -If false, never save this object statically. It will simply be -deleted when the block gets unloaded. -The get_staticdata() callback is never called then. -Defaults to 'true'. -]] ----@field static_save boolean? ---[[ -Texture modifier to be applied for a short duration when object is hit -]] ----@field damage_texture_modifier core.Texture? ---[[ -Defaults to true for players, false for other entities. -If set to true the entity will show as a marker on the minimap. -]] ----@field show_on_minimap boolean? - ----@class _.ObjectProperties.__base.get ---[[ -Same as infotext for nodes. Empty by default -]] ----@field infotext string ---[[ -If false, never save this object statically. It will simply be -deleted when the block gets unloaded. -The get_staticdata() callback is never called then. -Defaults to 'true'. -]] ----@field static_save boolean ---[[ -Texture modifier to be applied for a short duration when object is hit -]] ----@field damage_texture_modifier core.Texture ---[[ -Defaults to true for players, false for other entities. -If set to true the entity will show as a marker on the minimap. -]] ----@field show_on_minimap boolean - --- ---------------------------- ObjectProperties ---------------------------- -- - ----@alias core.ObjectProperties.set ---- | core.ObjectProperties.cube.set ---- | core.ObjectProperties.sprite.set ---- | core.ObjectProperties.upright_sprite.set ---- | core.ObjectProperties.mesh.set ---- | core.ObjectProperties.wielditem.set ---- | core.ObjectProperties.item.set ---- | core.ObjectProperties.node.set - ----@alias core.ObjectProperties.get ---- | core.ObjectProperties.cube.get ---- | core.ObjectProperties.sprite.get ---- | core.ObjectProperties.upright_sprite.get ---- | core.ObjectProperties.mesh.get ---- | core.ObjectProperties.wielditem.get ---- | core.ObjectProperties.item.get ---- | core.ObjectProperties.node.get \ No newline at end of file diff --git a/types/luanti_lsp_definitions/library/defs/object_properties/partial/backface_clling.lua b/types/luanti_lsp_definitions/library/defs/object_properties/partial/backface_clling.lua deleted file mode 100644 index e9877322..00000000 --- a/types/luanti_lsp_definitions/library/defs/object_properties/partial/backface_clling.lua +++ /dev/null @@ -1,17 +0,0 @@ ----@meta _ --- DRAFT 1 DONE --- luanti/doc/lua_api.md: Definition tables > Object properties - ----@class _.ObjectProperties.backface_culling.set.__partial ---[[ -Set to false to disable backface_culling for model -Note: only used by "mesh" and "cube" visual -]] ----@field backface_culling boolean? - ----@class _.ObjectProperties.backface_culling.get.__partial ---[[ -Set to false to disable backface_culling for model -Note: only used by "mesh" and "cube" visual -]] ----@field backface_culling boolean \ No newline at end of file diff --git a/types/luanti_lsp_definitions/library/defs/object_properties/partial/shaded.lua b/types/luanti_lsp_definitions/library/defs/object_properties/partial/shaded.lua deleted file mode 100644 index f1a803eb..00000000 --- a/types/luanti_lsp_definitions/library/defs/object_properties/partial/shaded.lua +++ /dev/null @@ -1,19 +0,0 @@ ----@meta _ --- DRAFT 1 DONE --- luanti/doc/lua_api.md: Definition tables > Object properties - ----@class _.ObjectProperties.shaded.set.__partial ---[[ -Setting this to 'false' disables diffuse lighting of entity -Note: ignored for "item", "wielditem" and "node" visual -]] ----@field shaded boolean? - ----@class _.ObjectProperties.shaded.get.__partial ---[[ -Setting this to 'false' disables diffuse lighting of entity -Note: ignored for "item", "wielditem" and "node" visual -]] ----@field shaded boolean - - diff --git a/types/luanti_lsp_definitions/library/defs/object_properties/partial/spritesheet.lua b/types/luanti_lsp_definitions/library/defs/object_properties/partial/spritesheet.lua deleted file mode 100644 index a0054f15..00000000 --- a/types/luanti_lsp_definitions/library/defs/object_properties/partial/spritesheet.lua +++ /dev/null @@ -1,33 +0,0 @@ ----@meta _ --- DRAFT 1 DONE --- luanti/doc/lua_api.md: Definition tables > Object properties - ----@class _.ObjectProperties.spritesheet.set.__partial ---[[ -Used with spritesheet textures for animation and/or frame selection -according to position relative to player. -Defines the number of columns and rows in the spritesheet: -{columns, rows}. -]] ----@field spritediv vec2i.xy? ---[[ -Used with spritesheet textures. -Defines the {column, row} position of the initially used frame in the -spritesheet. -]] ----@field initial_sprite_basepos vec2i.xy? - ----@class _.ObjectProperties.spritesheet.get.__partial ---[[ -Used with spritesheet textures for animation and/or frame selection -according to position relative to player. -Defines the number of columns and rows in the spritesheet: -{columns, rows}. -]] ----@field spritediv vec2i.xy ---[[ -Used with spritesheet textures. -Defines the {column, row} position of the initially used frame in the -spritesheet. -]] ----@field initial_sprite_basepos vec2i.xy diff --git a/types/luanti_lsp_definitions/library/defs/object_properties/player_properties.lua b/types/luanti_lsp_definitions/library/defs/object_properties/player_properties.lua deleted file mode 100644 index 3b32273d..00000000 --- a/types/luanti_lsp_definitions/library/defs/object_properties/player_properties.lua +++ /dev/null @@ -1,111 +0,0 @@ ----@meta _ --- DRAFT 1 DONE --- luanti/doc/lua_api.md: Definition tables > Object properties - --- ------------------------- PlayerProperties.__base ------------------------ -- - ---[[ -WIPDOC -]] ----@class _.PlayerProperties.__base.set : _.ObjectProperties.__base.set ---[[ -For players only. Defines the maximum amount of "breath" for the player. -Defaults to `core.PLAYER_MAX_BREATH_DEFAULT` (10). -]] ----@field breath_max integer? ---[[ -For players only. Zoom FOV in degrees. -Note that zoom loads and/or generates world beyond the server's -maximum send and generate distances, so acts like a telescope. -Smaller zoom_fov values increase the distance loaded/generated. -Defaults to 15 in creative mode, 0 in survival mode. -zoom_fov = 0 disables zooming for the player. -]] ----@field zoom_fov number? ---[[ -For players only. Camera height above feet position in nodes. -]] ----@field eye_height number? ---[[ -The name to display on the head of the object. By default empty. -If the object is a player, a nil or empty nametag is replaced by the player's name. -For all other objects, a nil or empty string removes the nametag. -To hide a nametag, set its color alpha to zero. That will disable it entirely. -]] ----@field nametag string? ---[[ -Defaults to true for players, false for other entities. -If set to true the entity will show as a marker on the minimap. -]] ----@field show_on_minimap boolean? - ---[[ -WIPDOC -]] ----@class _.PlayerProperties.__base.get : _.ObjectProperties.__base.get ---[[ -For players only. Defines the maximum amount of "breath" for the player. -Defaults to `core.PLAYER_MAX_BREATH_DEFAULT` (10). -]] ----@field breath_max integer ---[[ -For players only. Zoom FOV in degrees. -Note that zoom loads and/or generates world beyond the server's -maximum send and generate distances, so acts like a telescope. -Smaller zoom_fov values increase the distance loaded/generated. -Defaults to 15 in creative mode, 0 in survival mode. -zoom_fov = 0 disables zooming for the player. -]] ----@field zoom_fov number ---[[ -For players only. Camera height above feet position in nodes. -]] ----@field eye_height number ---[[ -The name to display on the head of the object. By default empty. -If the object is a player, a nil or empty nametag is replaced by the player's name. -For all other objects, a nil or empty string removes the nametag. -To hide a nametag, get its color alpha to zero. That will disable it entirely. -]] ----@field nametag string ---[[ -Defaults to true for players, false for other entities. -If get to true the entity will show as a marker on the minimap. -]] ----@field show_on_minimap boolean - --- ---------------------------- PlayerProperties ---------------------------- -- - ----@class core.PlayerProperties.cube.set : _.PlayerProperties.__base.set, _.ObjectProperties.cube.set.__partial ----@class core.PlayerProperties.sprite.set : _.PlayerProperties.__base.set, _.ObjectProperties.sprite.set.__partial ----@class core.PlayerProperties.upright_sprite.set : _.PlayerProperties.__base.set, _.ObjectProperties.upright_sprite.set.__partial ----@class core.PlayerProperties.mesh.set : _.PlayerProperties.__base.set, _.ObjectProperties.mesh.set.__partial ----@class core.PlayerProperties.wielditem.set : _.PlayerProperties.__base.set, _.ObjectProperties.wielditem.set.__partial ----@class core.PlayerProperties.item.set : _.PlayerProperties.__base.set, _.ObjectProperties.item.__partial ----@class core.PlayerProperties.node.set : _.PlayerProperties.__base.set, _.ObjectProperties.node.set.__partial - ----@alias core.PlayerProperties.set ---- | core.PlayerProperties.cube.set ---- | core.PlayerProperties.sprite.set ---- | core.PlayerProperties.upright_sprite.set ---- | core.PlayerProperties.mesh.set ---- | core.PlayerProperties.wielditem.set ---- | core.PlayerProperties.item.set ---- | core.PlayerProperties.node.set - ----@class core.PlayerProperties.cube.get : _.PlayerProperties.__base.get, _.ObjectProperties.cube.get.__partial ----@class core.PlayerProperties.sprite.get : _.PlayerProperties.__base.get, _.ObjectProperties.sprite.get.__partial ----@class core.PlayerProperties.upright_sprite.get : _.PlayerProperties.__base.get, _.ObjectProperties.upright_sprite.get.__partial ----@class core.PlayerProperties.mesh.get : _.PlayerProperties.__base.get, _.ObjectProperties.mesh.get.__partial ----@class core.PlayerProperties.wielditem.get : _.PlayerProperties.__base.get, _.ObjectProperties.wielditem.get.__partial ----@class core.PlayerProperties.item.get : _.PlayerProperties.__base.get, _.ObjectProperties.item.__partial ----@class core.PlayerProperties.node.get : _.PlayerProperties.__base.get, _.ObjectProperties.node.get.__partial - ----@alias core.PlayerProperties.get ---- | core.PlayerProperties.cube.get ---- | core.PlayerProperties.sprite.get ---- | core.PlayerProperties.upright_sprite.get ---- | core.PlayerProperties.mesh.get ---- | core.PlayerProperties.wielditem.get ---- | core.PlayerProperties.item.get ---- | core.PlayerProperties.node.get \ No newline at end of file diff --git a/types/luanti_lsp_definitions/library/defs/object_properties/types/cube.lua b/types/luanti_lsp_definitions/library/defs/object_properties/types/cube.lua deleted file mode 100644 index 7a4ab614..00000000 --- a/types/luanti_lsp_definitions/library/defs/object_properties/types/cube.lua +++ /dev/null @@ -1,85 +0,0 @@ ----@meta _ --- DRAFT 1 DONE --- luanti/doc/lua_api.md: Definition tables > Object properties - --- ------------------ ObjectProperties.cube.textures.strict ----------------- -- - ---[[ -WIPDOC -]] ----@class core.ObjectProperties.cube.textures.strict ---[[ -WIPDOC -]] ----@field [1] core.Texture ---[[ -WIPDOC -]] ----@field [2] core.Texture ---[[ -WIPDOC -]] ----@field [3] core.Texture ---[[ -WIPDOC -]] ----@field [4] core.Texture ---[[ -WIPDOC -]] ----@field [5] core.Texture ---[[ -WIPDOC -]] ----@field [6] core.Texture - ---[[ -WIPDOC -]] ----@alias core.ObjectProperties.cube.textures ---- | core.ObjectProperties.cube.textures.strict ---- | string[] - --- -------------------------- ObjectProperties.cube ------------------------- -- - ---[[ -WIPDOC -]] ----@class core.ObjectProperties.cube.set : _.ObjectProperties.__base.set, _.ObjectProperties.cube.set.__partial - ---[[ -WIPDOC -]] ----@class core.ObjectProperties.cube.get : _.ObjectProperties.__base.get, _.ObjectProperties.cube.get.__partial - ----@class _.ObjectProperties.cube.set.__partial : _.ObjectProperties.backface_culling.set.__partial, _.ObjectProperties.shaded.set.__partial ---[[ -WIPDOC -]] ----@field visual "cube" ---[[ -Number of required textures depends on visual: -"cube" uses 6 textures just like a node, but all 6 must be defined. -"sprite" uses 1 texture. -"upright_sprite" uses 2 textures: {front, back}. -"mesh" requires one texture for each mesh buffer/material (in order) -Deprecated usage of "wielditem" expects 'textures = {itemname}' (see 'visual' above). -Unofficial note: I *guessed* that it's string[] but i am not sure -]] ----@field textures core.ObjectProperties.cube.textures? - ----@class _.ObjectProperties.cube.get.__partial : _.ObjectProperties.backface_culling.get.__partial, _.ObjectProperties.shaded.get.__partial ---[[ -WIPDOC -]] ----@field visual "cube" ---[[ -Number of required textures depends on visual: -"cube" uses 6 textures just like a node, but all 6 must be defined. -"sprite" uses 1 texture. -"upright_sprite" uses 2 textures: {front, back}. -"mesh" requires one texture for each mesh buffer/material (in order) -Deprecated usage of "wielditem" expects 'textures = {itemname}' (see 'visual' above). -Unofficial note: I *guessed* that it's string[] but i am not sure -]] ----@field textures core.ObjectProperties.cube.textures diff --git a/types/luanti_lsp_definitions/library/defs/object_properties/types/item.lua b/types/luanti_lsp_definitions/library/defs/object_properties/types/item.lua deleted file mode 100644 index 54dd93a1..00000000 --- a/types/luanti_lsp_definitions/library/defs/object_properties/types/item.lua +++ /dev/null @@ -1,19 +0,0 @@ ----@meta _ --- DRAFT 1 DONE --- luanti/doc/lua_api.md: Definition tables > Object properties - ---[[ -WIPDOC -]] ----@class core.ObjectProperties.item.set : _.ObjectProperties.__base.set, _.ObjectProperties.item.__partial - ---[[ -WIPDOC -]] ----@class core.ObjectProperties.item.get : _.ObjectProperties.__base.get, _.ObjectProperties.item.__partial - ----@class _.ObjectProperties.item.__partial ---[[ -WIPDOC -]] ----@field visual "item" diff --git a/types/luanti_lsp_definitions/library/defs/object_properties/types/mesh.lua b/types/luanti_lsp_definitions/library/defs/object_properties/types/mesh.lua deleted file mode 100644 index 130a6495..00000000 --- a/types/luanti_lsp_definitions/library/defs/object_properties/types/mesh.lua +++ /dev/null @@ -1,55 +0,0 @@ ----@meta _ --- DRAFT 1 DONE --- luanti/doc/lua_api.md: Definition tables > Object properties - ---[[ -WIPDOC -]] ----@class core.ObjectProperties.mesh.set : _.ObjectProperties.__base.set, _.ObjectProperties.mesh.set.__partial - ---[[ -WIPDOC -]] ----@class core.ObjectProperties.mesh.get : _.ObjectProperties.__base.get, _.ObjectProperties.mesh.get.__partial - ----@class _.ObjectProperties.mesh.set.__partial : _.ObjectProperties.backface_culling.set.__partial, _.ObjectProperties.shaded.set.__partial ---[[ -WIPDOC -]] ----@field visual "mesh" ---[[ -File name of mesh when using "mesh" visual. -For legacy reasons, this uses a 10x scale for meshes: 10 units = 1 node. -]] ----@field mesh core.Path? ---[[ -Number of required textures depends on visual: -"cube" uses 6 textures just like a node, but all 6 must be defined. -"sprite" uses 1 texture. -"upright_sprite" uses 2 textures: {front, back}. -"mesh" requires one texture for each mesh buffer/material (in order) -Deprecated usage of "wielditem" expects 'textures = {itemname}' (see 'visual' above). -Unofficial note: I *guessed* that it's string[] but i am not sure -]] ----@field textures core.Texture[]? - ----@class _.ObjectProperties.mesh.get.__partial : _.ObjectProperties.backface_culling.get.__partial, _.ObjectProperties.shaded.get.__partial ---[[ -WIPDOC -]] ----@field visual "mesh" ---[[ -File name of mesh when using "mesh" visual. -For legacy reasons, this uses a 10x scale for meshes: 10 units = 1 node. -]] ----@field mesh core.Path ---[[ -Number of required textures depends on visual: -"cube" uses 6 textures just like a node, but all 6 must be defined. -"sprite" uses 1 texture. -"upright_sprite" uses 2 textures: {front, back}. -"mesh" requires one texture for each mesh buffer/material (in order) -Deprecated usage of "wielditem" expects 'textures = {itemname}' (see 'visual' above). -Unofficial note: I *guessed* that it's string[] but i am not sure -]] ----@field textures core.Texture[] diff --git a/types/luanti_lsp_definitions/library/defs/object_properties/types/node.lua b/types/luanti_lsp_definitions/library/defs/object_properties/types/node.lua deleted file mode 100644 index 79a3de1f..00000000 --- a/types/luanti_lsp_definitions/library/defs/object_properties/types/node.lua +++ /dev/null @@ -1,33 +0,0 @@ ----@meta _ --- DRAFT 1 DONE --- luanti/doc/lua_api.md: Definition tables > Object properties - ---[[ -WIPDOC -]] ----@class core.ObjectProperties.node.set : _.ObjectProperties.__base.set, _.ObjectProperties.node.set.__partial - ---[[ -WIPDOC -]] ----@class core.ObjectProperties.node.get : _.ObjectProperties.__base.get, _.ObjectProperties.node.get.__partial - ----@class _.ObjectProperties.node.set.__partial ---[[ -WIPDOC -]] ----@field visual "node" ---[[ -Node to show when using the "node" visual -]] ----@field node core.Node.set? - ----@class _.ObjectProperties.node.get.__partial ---[[ -WIPDOC -]] ----@field visual "node" ---[[ -Node to show when using the "node" visual -]] ----@field node core.Node.get diff --git a/types/luanti_lsp_definitions/library/defs/object_properties/types/sprite.lua b/types/luanti_lsp_definitions/library/defs/object_properties/types/sprite.lua deleted file mode 100644 index 6ecf7d33..00000000 --- a/types/luanti_lsp_definitions/library/defs/object_properties/types/sprite.lua +++ /dev/null @@ -1,64 +0,0 @@ ----@meta _ --- DRAFT 1 DONE --- luanti/doc/lua_api.md: Definition tables > Object properties - --- ----------------- ObjectProperties.sprite.textures.strict ---------------- -- - ---[[ -WIPDOC -]] ----@class core.ObjectProperties.sprite.textures.strict ---[[ -WIPDOC -]] ----@field [1] number - ---[[ -WIPDOC -]] ----@alias core.ObjectProperties.sprite.textures ---- | core.ObjectProperties.sprite.textures.strict ---- | string[] - --- ------------------------- ObjectProperties.sprite ------------------------ -- ---[[ -WIPDOC -]] ----@class core.ObjectProperties.sprite.set : _.ObjectProperties.__base.set, _.ObjectProperties.sprite.set.__partial - ---[[ -WIPDOC -]] ----@class core.ObjectProperties.sprite.get : _.ObjectProperties.__base.get, _.ObjectProperties.sprite.get.__partial - ----@class _.ObjectProperties.sprite.set.__partial : _.ObjectProperties.spritesheet.set.__partial, _.ObjectProperties.spritesheet.set.__partial ---[[ -WIPDOC -]] ----@field visual "sprite" ---[[ -Number of required textures depends on visual: -"cube" uses 6 textures just like a node, but all 6 must be defined. -"sprite" uses 1 texture. -"upright_sprite" uses 2 textures: {front, back}. -"mesh" requires one texture for each mesh buffer/material (in order) -Deprecated usage of "wielditem" expects 'textures = {itemname}' (see 'visual' above). -Unofficial note: I *guessed* that it's string[] but i am not sure -]] ----@field textures core.ObjectProperties.sprite.textures? - ----@class _.ObjectProperties.sprite.get.__partial : _.ObjectProperties.spritesheet.get.__partial, _.ObjectProperties.spritesheet.get.__partial ---[[ -WIPDOC -]] ----@field visual "sprite" ---[[ -Number of required textures depends on visual: -"cube" uses 6 textures just like a node, but all 6 must be defined. -"sprite" uses 1 texture. -"upright_sprite" uses 2 textures: {front, back}. -"mesh" requires one texture for each mesh buffer/material (in order) -Deprecated usage of "wielditem" expects 'textures = {itemname}' (see 'visual' above). -Unofficial note: I *guessed* that it's string[] but i am not sure -]] ----@field textures core.ObjectProperties.sprite.textures diff --git a/types/luanti_lsp_definitions/library/defs/object_properties/types/upright_sprite.lua b/types/luanti_lsp_definitions/library/defs/object_properties/types/upright_sprite.lua deleted file mode 100644 index dc28b81e..00000000 --- a/types/luanti_lsp_definitions/library/defs/object_properties/types/upright_sprite.lua +++ /dev/null @@ -1,69 +0,0 @@ ----@meta _ --- DRAFT 1 DONE --- luanti/doc/lua_api.md: Definition tables > Object properties - --- ------------- ObjectProperties.upright_sprite.textures.strict ------------ -- - ---[[ -WIPDOC -]] ----@class core.ObjectProperties.upright_sprite.textures.strict ---[[ -WIPDOC -]] ----@field [1] number ---[[ -WIPDOC -]] ----@field [2] number - ---[[ -WIPDOC -]] ----@alias core.ObjectProperties.upright_sprite.textures ---- | core.ObjectProperties.upright_sprite.textures.strict ---- | string[] - --- ------------------- ObjectProperties.upright_sprite.set ------------------ -- - ---[[ -WIPDOC -]] ----@class core.ObjectProperties.upright_sprite.set : _.ObjectProperties.__base.set, _.ObjectProperties.upright_sprite.set.__partial - ---[[ -WIPDOC -]] ----@class core.ObjectProperties.upright_sprite.get : _.ObjectProperties.__base.get, _.ObjectProperties.upright_sprite.get.__partial - ----@class _.ObjectProperties.upright_sprite.set.__partial : _.ObjectProperties.spritesheet.set.__partial, _.ObjectProperties.shaded.set.__partial ---[[ -WIPDOC -]] ----@field visual "upright_sprite" ---[[ -Number of required textures depends on visual: -"cube" uses 6 textures just like a node, but all 6 must be defined. -"sprite" uses 1 texture. -"upright_sprite" uses 2 textures: {front, back}. -"mesh" requires one texture for each mesh buffer/material (in order) -Deprecated usage of "wielditem" expects 'textures = {itemname}' (see 'visual' above). -Unofficial note: I *guessed* that it's string[] but i am not sure -]] ----@field textures core.ObjectProperties.upright_sprite.textures? - ----@class _.ObjectProperties.upright_sprite.get.__partial : _.ObjectProperties.spritesheet.get.__partial, _.ObjectProperties.shaded.get.__partial ---[[ -WIPDOC -]] ----@field visual "upright_sprite" ---[[ -Number of required textures depends on visual: -"cube" uses 6 textures just like a node, but all 6 must be defined. -"sprite" uses 1 texture. -"upright_sprite" uses 2 textures: {front, back}. -"mesh" requires one texture for each mesh buffer/material (in order) -Deprecated usage of "wielditem" expects 'textures = {itemname}' (see 'visual' above). -Unofficial note: I *guessed* that it's string[] but i am not sure -]] ----@field textures core.ObjectProperties.upright_sprite.textures diff --git a/types/luanti_lsp_definitions/library/defs/object_properties/types/wielditem.lua b/types/luanti_lsp_definitions/library/defs/object_properties/types/wielditem.lua deleted file mode 100644 index 178e642a..00000000 --- a/types/luanti_lsp_definitions/library/defs/object_properties/types/wielditem.lua +++ /dev/null @@ -1,66 +0,0 @@ ----@meta _ --- DRAFT 1 DONE --- luanti/doc/lua_api.md: Definition tables > Object properties - --- --------------- ObjectProperties.wielditem.textures.strict --------------- -- - ---[[ -WIPDOC -]] ----@class core.ObjectProperties.wielditem.textures.strict ---[[ -WIPDOC -]] ----@field [1] number - ---[[ -WIPDOC -]] ----@alias core.ObjectProperties.wielditem.textures ---- | core.ObjectProperties.wielditem.textures.strict ---- | string[] - --- ----------------------- ObjectProperties.wielditem ----------------------- -- - ---[[ -WIPDOC -]] ----@class core.ObjectProperties.wielditem.set : _.ObjectProperties.__base.set, _.ObjectProperties.wielditem.set.__partial - ---[[ -WIPDOC -]] ----@class core.ObjectProperties.wielditem.get : _.ObjectProperties.__base.get, _.ObjectProperties.wielditem.get.__partial - ----@class _.ObjectProperties.wielditem.set.__partial ---[[ -WIPDOC -]] ----@field visual "wielditem" ---[[ -WIPDOC -]] ----@field wield_item core.Item.name ---[[ -WIPDOC - -* @deprecated -]] ----@field textures core.ObjectProperties.wielditem.textures? - ----@class _.ObjectProperties.wielditem.get.__partial ---[[ -WIPDOC -]] ----@field visual "wielditem" ---[[ -WIPDOC -]] ----@field wield_item core.Item.name ---[[ -WIPDOC - -* @deprecated 5.X -]] ----@field textures core.ObjectProperties.wielditem.textures - diff --git a/types/luanti_lsp_definitions/library/defs/ore/blob.lua b/types/luanti_lsp_definitions/library/defs/ore/blob.lua deleted file mode 100644 index ebd22a28..00000000 --- a/types/luanti_lsp_definitions/library/defs/ore/blob.lua +++ /dev/null @@ -1,43 +0,0 @@ ----@meta _ --- DRAFT 1 DONE --- luanti/doc/lua_api.md: Ores --- luanti/doc/lua_api.md: Definition tables > Ore Definition - ---[[ -WIPDOC -]] ----@class core.OreDef.blob : _.OreDef.__base ---[[ -WIPDOC -]] ----@field ore_type "blob" ---[[ -Ore has a 1 out of clust_scarcity chance of spawning in a node. -If the desired average distance between ores is 'd', set this to -d * d * d. -]] ----@field clust_scarcity integer? ---[[ -Number of ores in a clust -]] ----@field clust_num_ores integer? ---[[ -Size of the bounding box of the cluster. -In this example, there is a 3 * 3 * 3 cluster where 8 out of the 27 -nodes are coal ore. -]] ----@field clust_size integer? ---[[ -If noise is above this threshold, ore is placed. Not needed for a -uniform distribution. -]] ----@field noise_threshold number? ---[[ -NoiseParams structure describing one of the noises used for -ore distribution. -Needed by "sheet", "puff", "blob" and "vein" ores. -Omit from "scatter" ore for a uniform ore distribution. -Omit from "stratum" ore for a simple horizontal strata from y_min to -y_max. -]] ----@field noise_params core.NoiseParams.3d diff --git a/types/luanti_lsp_definitions/library/defs/ore/ore.lua b/types/luanti_lsp_definitions/library/defs/ore/ore.lua deleted file mode 100644 index eb062f15..00000000 --- a/types/luanti_lsp_definitions/library/defs/ore/ore.lua +++ /dev/null @@ -1,58 +0,0 @@ ----@meta _ --- DRAFT 1 DONE --- luanti/doc/lua_api.md: Ores --- luanti/doc/lua_api.md: Definition tables > Ore Definition - ---[[ -WIPDOC -]] ----@class core.OreID : integer - --- ------------------------------ OreDef.__base ----------------------------- -- - ----@class _.OreDef.__base ---[[ -WIPDOC -]] ----@field name string? ---[[ -Ore node to place -]] ----@field ore core.Node.name ---[[ -Param2 to set for ore (e.g. facedir rotation) -]] ----@field ore_param2 core.Param2? ---[[ -Node to place ore in. Multiple are possible by passing a list. -]] ----@field wherein OneOrMany ---[[ -WIPDOC -]] ----@field y_min integer? ---[[ -WIPDOC -]] ----@field y_max integer? ---[[ -List of biomes in which this ore occurs. -Occurs in all biomes if this is omitted, and ignored if the Mapgen -being used does not support biomes. -Can be a list of (or a single) biome names, IDs, or definitions. -]] ----@field biomes OneOrMany? - --- --------------------------------- OreDef --------------------------------- -- - ---[[ -WIPDOC -]] ----@alias core.OreDef ---- | core.OreDef.scatter.uniform ---- | core.OreDef.scatter.nonuniform ---- | core.OreDef.sheet ---- | core.OreDef.puff ---- | core.OreDef.blob ---- | core.OreDef.vein ---- | core.OreDef.stratum \ No newline at end of file diff --git a/types/luanti_lsp_definitions/library/defs/ore/puff.lua b/types/luanti_lsp_definitions/library/defs/ore/puff.lua deleted file mode 100644 index 70d67b54..00000000 --- a/types/luanti_lsp_definitions/library/defs/ore/puff.lua +++ /dev/null @@ -1,92 +0,0 @@ ----@meta _ --- DRAFT 1 DONE --- luanti/doc/lua_api.md: Flag Specifier Format --- luanti/doc/lua_api.md: Ores --- luanti/doc/lua_api.md: Definition tables > Ore Definition - --- ---------------------------- OreDef.puff.flags --------------------------- -- - ---[[ -WIPDOC -]] ----@class core.OreDef.puff.flags.tablefmt ---[[ -WIPDOC -]] ----@field puff_cliffs boolean? ---[[ -WIPDOC -]] ----@field nopuff_cliffs boolean? ---[[ -WIPDOC -]] ----@field puff_additive_composition boolean? ---[[ -WIPDOC -]] ----@field nopuff_additive_composition boolean? ---[[ -WIPDOC -]] ----@alias core.OreDef.puff.flags.stringfmt string - ---[[ -WIPDOC -]] ----@alias core.OreDef.puff.flags ---- | core.OreDef.puff.flags.tablefmt ---- | core.OreDef.puff.flags.stringfmt - --- ------------------------------- OreDef.puff ------------------------------ -- - ---[[ -WIPDOC -]] ----@class core.OreDef.puff : _.OreDef.__base ---[[ -WIPDOC -]] ----@field ore_type "puff" ---[[ -WIPDOC -]] ----@field flags core.OreDef.puff.flags? ---[[ -Ore has a 1 out of clust_scarcity chance of spawning in a node. -If the desired average distance between ores is 'd', set this to -d * d * d. -]] ----@field clust_scarcity integer? ---[[ -Number of ores in a cluster -]] ----@field clust_num_ores integer? ---[[ -Size of the bounding box of the cluster. -In this example, there is a 3 * 3 * 3 cluster where 8 out of the 27 -nodes are coal ore. -]] ----@field clust_size integer? ---[[ -If noise is above this threshold, ore is placed. Not needed for a -uniform distribution. -]] ----@field noise_threshold number? ---[[ -NoiseParams structure describing one of the noises used for -ore distribution. -Needed by "sheet", "puff", "blob" and "vein" ores. -Omit from "scatter" ore for a uniform ore distribution. -Omit from "stratum" ore for a simple horizontal strata from y_min to -y_max. -]] ----@field noise_params core.NoiseParams.3d ---[[ -"puff" type -]] ----@field np_puff_top core.NoiseParams.3d? ---[[ -WIPDOC -]] ----@field np_puff_bottom core.NoiseParams.3d? \ No newline at end of file diff --git a/types/luanti_lsp_definitions/library/defs/ore/scatter.lua b/types/luanti_lsp_definitions/library/defs/ore/scatter.lua deleted file mode 100644 index a9ba2870..00000000 --- a/types/luanti_lsp_definitions/library/defs/ore/scatter.lua +++ /dev/null @@ -1,55 +0,0 @@ ----@meta _ --- DRAFT 1 DONE --- luanti/doc/lua_api.md: Ores - - --- ------------------------ OreDef.scatter.__partial ------------------------ -- - ----@class _.OreDef.scatter.__partial ---[[ -WIPDOC -]] ----@field ore_type "scatter" ---[[ -Ore has a 1 out of clust_scarcity chance of spawning in a node. -If the desired average distance between ores is 'd', set this to -d * d * d. -]] ----@field clust_scarcity integer? ---[[ -Number of ores in a cluster -]] ----@field clust_num_ores integer? ---[[ -Size of the bounding box of the cluster. -In this example, there is a 3 * 3 * 3 cluster where 8 out of the 27 -nodes are coal ore. -]] ----@field clust_size integer? - --- ----------------------------- OreDef.scatter ----------------------------- -- - - ---[[ -WIPDOC -]] ----@class core.OreDef.scatter.uniform : _.OreDef.__base, _.OreDef.scatter.__partial - ---[[ -WIPDOC -]] ----@class core.OreDef.scatter.nonuniform : _.OreDef.__base, _.OreDef.scatter.__partial ---[[ -If noise is above this threshold, ore is placed. Not needed for a -uniform distribution. -]] ----@field noise_threshold number? ---[[ -NoiseParams structure describing one of the noises used for -ore distribution. -Needed by "sheet", "puff", "blob" and "vein" ores. -Omit from "scatter" ore for a uniform ore distribution. -Omit from "stratum" ore for a simple horizontal strata from y_min to -y_max. -]] ----@field noise_params core.NoiseParams.3d diff --git a/types/luanti_lsp_definitions/library/defs/ore/sheet.lua b/types/luanti_lsp_definitions/library/defs/ore/sheet.lua deleted file mode 100644 index 12c21544..00000000 --- a/types/luanti_lsp_definitions/library/defs/ore/sheet.lua +++ /dev/null @@ -1,45 +0,0 @@ ----@meta _ --- DRAFT 1 DONE --- luanti/doc/lua_api.md: Ores --- luanti/doc/lua_api.md: Definition tables > Ore Definition - ---[[ -WIPDOC -]] ----@class core.OreDef.sheet : _.OreDef.__base ---[[ -WIPDOC -]] ----@field ore_type "sheet" ---[[ -Size of the bounding box of the cluster. -In this example, there is a 3 * 3 * 3 cluster where 8 out of the 27 -nodes are coal ore. -]] ----@field clust_size integer? ---[[ -If noise is above this threshold, ore is placed. Not needed for a -uniform distribution. -]] ----@field noise_threshold number? ---[[ -NoiseParams structure describing one of the noises used for -ore distribution. -Needed by "sheet", "puff", "blob" and "vein" ores. -Omit from "scatter" ore for a uniform ore distribution. -Omit from "stratum" ore for a simple horizontal strata from y_min to -y_max. -]] ----@field noise_params core.NoiseParams.3d ---[[ -"sheet" type -]] ----@field column_height_min integer? ---[[ -"sheet" type -]] ----@field column_height_max integer? ---[[ -"sheet" type -]] ----@field column_midpoint_factor number? \ No newline at end of file diff --git a/types/luanti_lsp_definitions/library/defs/ore/stratum.lua b/types/luanti_lsp_definitions/library/defs/ore/stratum.lua deleted file mode 100644 index afa4edb0..00000000 --- a/types/luanti_lsp_definitions/library/defs/ore/stratum.lua +++ /dev/null @@ -1,35 +0,0 @@ ----@meta _ --- DRAFT 1 DONE --- luanti/doc/lua_api.md: Ores --- luanti/doc/lua_api.md: Definition tables > Ore Definition - ---[[ -WIPDOC -]] ----@class core.OreDef.stratum : _.OreDef.__base ---[[ -WIPDOC -]] ----@field ore_type "stratum" ---[[ -If noise is above this threshold, ore is placed. Not needed for a -uniform distribution. -]] ----@field noise_threshold number? ---[[ -NoiseParams structure describing one of the noises used for -ore distribution. -Needed by "sheet", "puff", "blob" and "vein" ores. -Omit from "scatter" ore for a uniform ore distribution. -Omit from "stratum" ore for a simple horizontal strata from y_min to -y_max. -]] ----@field noise_params core.NoiseParams.3d? ---[[ -WIPDOC -]] ----@field np_stratum_thickness core.NoiseParams.3d? ---[[ -WIPDOC -]] ----@field stratum_thickness integer? \ No newline at end of file diff --git a/types/luanti_lsp_definitions/library/defs/ore/vein.lua b/types/luanti_lsp_definitions/library/defs/ore/vein.lua deleted file mode 100644 index 8f39303b..00000000 --- a/types/luanti_lsp_definitions/library/defs/ore/vein.lua +++ /dev/null @@ -1,31 +0,0 @@ ----@meta _ --- DRAFT 1 DONE --- luanti/doc/lua_api.md: Ores --- luanti/doc/lua_api.md: Definition tables > Ore Definition - ---[[ -WIPDOC -]] ----@class core.OreDef.vein : _.OreDef.__base ---[[ -WIPDOC -]] ----@field ore_type "vein" ---[[ -If noise is above this threshold, ore is placed. Not needed for a -uniform distribution. -]] ----@field noise_threshold number? ---[[ -NoiseParams structure describing one of the noises used for -ore distribution. -Needed by "sheet", "puff", "blob" and "vein" ores. -Omit from "scatter" ore for a uniform ore distribution. -Omit from "stratum" ore for a simple horizontal strata from y_min to -y_max. -]] ----@field noise_params core.NoiseParams.3d? ---[[ -"vein" type -]] ----@field random_factor number? diff --git a/types/luanti_lsp_definitions/library/defs/particle/ParticleSpawner.lua b/types/luanti_lsp_definitions/library/defs/particle/ParticleSpawner.lua deleted file mode 100644 index 9b6439db..00000000 --- a/types/luanti_lsp_definitions/library/defs/particle/ParticleSpawner.lua +++ /dev/null @@ -1,197 +0,0 @@ ----@meta _ --- DRAFT 1 DONE --- luanti/doc/lua_api.md: Definition tables > `ParticleSpawner` definition - --- NOTE: only the modern ParticleSpawner definition is annotated. However, --- interested contributors seeking to additionally annotate the legacy --- ParticleSpawner definition is welcome to submit a complete PR/patch - ---[[ -WIPDOC -]] ----@class core.ParticleSpawnerID : integer - --- ----------------------- ParticleSpawnerDef.regular ----------------------- -- - ---[[ -WIPDOC -]] ----@class core.ParticleSpawnerDef.regular ---[[ -Number of particles spawned over the time period `time`. -]] ----@field amount integer ---[[ -Lifespan of spawner in seconds. -If time is 0 spawner has infinite lifespan and spawns the `amount` on -a per-second basis. -]] ----@field time number ---[[ -If true collide with `walkable` nodes and, depending on the -`object_collision` field, objects too. -]] ----@field collisiondetection boolean? ---[[ -If true particles are removed when they collide. -Requires collisiondetection = true to have any effect. -]] ----@field collision_removal boolean? ---[[ -If true particles collide with objects that are defined as -`physical = true,` and `collide_with_objects = true,`. -Requires collisiondetection = true to have any effect. -]] ----@field object_collision boolean? ---[[ -If defined, particle positions, velocities and accelerations are -relative to this object's position and yaw -]] ----@field attached core.ObjectRef? ---[[ -If true face player using y axis only -]] ----@field vertical boolean? ---[[ -The texture of the particle -v5.6.0 and later: also supports the table format described in the -following section. -]] ----@field texture core.ParticleTexture? ---[[ -TODO separate both fields -Optional, if specified spawns particles only for this player -Can't be used together with `exclude_player`. -]] ----@field playername string? ---[[ -TODO separate both fields -Optional, if specified spawns particles not for this player -Added in v5.14.0. Can't be used together with `playername`. -]] ----@field exclude_player string? ---[[ -Optional, specifies how to animate the particles' texture -v5.6.0 and later: set length to -1 to synchronize the length -of the animation with the expiration time of individual particles. -(-2 causes the animation to be played twice, and so on) -]] ----@field animation core.TileAnimationDef? ---[[ -Optional, specify particle self-luminescence in darkness. -Values 0-14. -]] ----@field glow core.Light.source? - --- -------------------- modern ParticleSpawner properties ------------------- -- - ----@class core.ParticleSpawnerDef.regular ---[[ -WIPDOC -]] ----@field pos core.ParticleSpawner.vec3_range? ---[[ -WIPDOC -]] ----@field pos_tween core.ParticleSpawner.tween.vec3_range? ---[[ -WIPDOC -]] ----@field vel core.ParticleSpawner.vec3_range? ---[[ -WIPDOC -]] ----@field vel_tween core.ParticleSpawner.tween.vec3_range? ---[[ -WIPDOC -]] ----@field acc core.ParticleSpawner.vec3_range? ---[[ -WIPDOC -]] ----@field acc_tween core.ParticleSpawner.vec3_range? ---[[ -WIPDOC -]] ----@field size core.ParticleSpawner.float_range? ---[[ -WIPDOC -]] ----@field size_tween core.ParticleSpawner.tween.float_range? ---[[ -WIPDOC -]] ----@field jitter core.ParticleSpawner.vec3_range? ---[[ -WIPDOC -]] ----@field jitter_tween core.ParticleSpawner.tween.vec3_range? ---[[ -WIPDOC -]] ----@field drag core.ParticleSpawner.vec3_range? ---[[ -WIPDOC -]] ----@field drag_tween core.ParticleSpawner.tween.vec3_range? ---[[ -WIPDOC -]] ----@field bounce core.ParticleSpawner.float_range? ---[[ -WIPDOC -]] ----@field bounce_tween core.ParticleSpawner.tween.float_range? ---[[ -WIPDOC -]] ----@field exptime core.ParticleSpawner.float_range? ---[[ -WIPDOC -]] ----@field exptime_tween core.ParticleSpawner.tween.float_range? ---[[ -WIPDOC -]] ----@field attract core.ParticleSpawner.attract? ---[[ -WIPDOC -]] ----@field radius core.ParticleSpawner.vec3_range? ---[[ -WIPDOC -]] ----@field radius_tween core.ParticleSpawner.tween.vec3_range? ---[[ -WIPDOC -]] ----@field texpool core.ParticleTexture? - --- ------------------------- ParticleSpawnerDef.node ------------------------ -- - ---[[ -WIPDOC -]] ----@class core.ParticleSpawnerDef.node ---[[ -Optional, if specified the particles will have the same appearance as -node dig particles for the given node. -`texture` and `animation` will be ignored if this is set. -]] ----@field node core.Node.set? ---[[ -Optional, only valid in combination with `node` -If set to a valid number 1-6, specifies the tile from which the -particle texture is picked. -Otherwise, the default behavior is used. (currently: any random tile) -]] ----@field node_tile integer? - --- ----------------------------- ParticleSpawner ---------------------------- -- - ---[[ -WIPDOC -]] ----@alias core.ParticleSpawnerDef ---- | core.ParticleSpawnerDef.regular ---- | core.ParticleSpawnerDef.node \ No newline at end of file diff --git a/types/luanti_lsp_definitions/library/defs/particle/attract.lua b/types/luanti_lsp_definitions/library/defs/particle/attract.lua deleted file mode 100644 index 84010c97..00000000 --- a/types/luanti_lsp_definitions/library/defs/particle/attract.lua +++ /dev/null @@ -1,57 +0,0 @@ ----@meta _ --- DRAFT 1 DONE --- luanti/doc/lua_api.md: Definition tables > `ParticleSpawner` definition - ---[[ -WIPDOC -]] ----@alias core.ParticleSpawner.kind ---- | "none" ---- | "point" ---- | "line" ---- | "plane" - ---[[ -WIPDOC -]] ----@class core.ParticleSpawner.attract ---[[ -WIPDOC -]] ----@field kind core.ParticleSpawner.kind ---[[ -WIPDOC -]] ----@field strength core.ParticleSpawner.float_range ---[[ -WIPDOC -]] ----@field strength_tween core.ParticleSpawner.tween.float_range? ---[[ -WIPDOC -]] ----@field origin core.ParticleSpawner.vec3? ---[[ -WIPDOC -]] ----@field origin_tween core.ParticleSpawner.tween.vec3? ---[[ -WIPDOC -]] ----@field direction core.ParticleSpawner.vec3? ---[[ -WIPDOC -]] ----@field direction_tween core.ParticleSpawner.tween.vec3? ---[[ -WIPDOC -]] ----@field origin_attached core.ObjectRef? ---[[ -WIPDOC -]] ----@field direction_attached core.ObjectRef? ---[[ -WIPDOC -]] ----@field die_on_contact boolean? \ No newline at end of file diff --git a/types/luanti_lsp_definitions/library/defs/particle/particle.lua b/types/luanti_lsp_definitions/library/defs/particle/particle.lua deleted file mode 100644 index 504c6faf..00000000 --- a/types/luanti_lsp_definitions/library/defs/particle/particle.lua +++ /dev/null @@ -1,115 +0,0 @@ ----@meta _ --- DRAFT 1 DONE --- luanti/doc/lua_api.md: Definition tables > Particle definition --- luanti/doc/lua_api.md: Definition tables > `ParticleSpawner` definition - --- --------------------------- ParticleDef.regular -------------------------- -- - ----@class core.ParticleDef.regular ---[[ -WIPDOC -]] ----@field pos vector ---[[ -WIPDOC -]] ----@field velocity vector? ---[[ -WIPDOC -]] ----@field acceleration vector? ---[[ -WIPDOC -]] ----@field expirationtime number ---[[ -Scales the visual size of the particle texture. -If `node` is set, size can be set to 0 to spawn a randomly-sized -particle (just like actual node dig particles). -]] ----@field size number? ---[[ -If true collides with `walkable` nodes and, depending on the -`object_collision` field, objects too. -]] ----@field collisiondetection boolean? ---[[ -If true particle is removed when it collides. -Requires collisiondetection = true to have any effect. -]] ----@field collision_removal boolean? ---[[ -If true particle collides with objects that are defined as -`physical = true,` and `collide_with_objects = true,`. -Requires collisiondetection = true to have any effect. -]] ----@field object_collision boolean? ---[[ -If true faces player using y axis only -]] ----@field vertical boolean? ---[[ -The texture of the particle -v5.6.0 and later: also supports the table format described in the -following section, but due to a bug this did not take effect -(beyond the texture name). -v5.9.0 and later: fixes the bug. -Note: "texture.animation" is ignored here. Use "animation" below instead. -]] ----@field texture core.ParticleTexture? ---[[ -Optional, if specified spawns particle only on the player's client -]] ----@field playername string? ---[[ -Optional, specifies how to animate the particle texture -]] ----@field animation core.TileAnimationDef? ---[[ -Optional, specify particle self-luminescence in darkness. -Values 0-14. -]] ----@field glow number? ---[[ -v5.6.0 and later: Optional drag value, consult the following section -Note: Only a vector is supported here. Alternative forms like a single -number are not supported. -]] ----@field drag vector? ---[[ -v5.6.0 and later: Optional jitter range, consult the following section -]] ----@field jitter core.ParticleSpawner.vec3_range? ---[[ -v5.6.0 and later: Optional bounce range, consult the following section -]] ----@field bounce core.ParticleSpawner.vec3_range? - --- ---------------------------- ParticleDef.node ---------------------------- -- - ---[[ -WIPDOC -]] ----@class core.ParticleDef.node : core.ParticleDef.regular ---[[ -Optional, if specified the particle will have the same appearance as -node dig particles for the given node. -`texture` and `animation` will be ignored if this is set. -]] ----@field node core.Node.set? ---[[ -Optional, only valid in combination with `node` -If set to a valid number 1-6, specifies the tile from which the -particle texture is picked. -Otherwise, the default behavior is used. (currently: any random tile) -]] ----@field node_tile number? - --- ------------------------------- ParticleDef ------------------------------ -- - ---[[ -WIPDOC -]] ----@alias core.ParticleDef ---- | core.ParticleDef.regular ---- | core.ParticleDef.node \ No newline at end of file diff --git a/types/luanti_lsp_definitions/library/defs/particle/texture.lua b/types/luanti_lsp_definitions/library/defs/particle/texture.lua deleted file mode 100644 index 0d34f89d..00000000 --- a/types/luanti_lsp_definitions/library/defs/particle/texture.lua +++ /dev/null @@ -1,58 +0,0 @@ ----@meta _ --- DRAFT 1 DONE --- luanti/doc/lua_api.md: Definition tables > `ParticleSpawner` definition - ---[[ -WIPDOC -]] ----@alias core.ParticleTexture.blend ---- | "alpha" ---- | "clip" ---- | "add" ---- | "screen" ---- | "sub" - ---[[ -WIPDOC -]] ----@class core.ParticleTexture.tablefmt ---[[ -WIPDOC -]] ----@field name core.Texture ---[[ -WIPDOC -]] ----@field alpha number? ---[[ -WIPDOC -]] ----@field alpha_tween core.ParticleSpawner.tween.float? ---[[ -WIPDOC -]] ----@field scale core.ParticleSpawner.vec2? ---[[ -WIPDOC -]] ----@field scale_tween core.ParticleSpawner.tween.vec2? ---[[ -WIPDOC -]] ----@field blend core.ParticleTexture.blend? ---[[ -WIPDOC -]] ----@field animation core.TileAnimationDef? - ---[[ -WIPDOC -]] ----@class core.ParticleTexture.stringfmt - ---[[ -WIPDOC -]] ----@alias core.ParticleTexture ---- | core.ParticleTexture.tablefmt ---- | core.ParticleTexture.stringfmt \ No newline at end of file diff --git a/types/luanti_lsp_definitions/library/defs/particle/type.lua b/types/luanti_lsp_definitions/library/defs/particle/type.lua deleted file mode 100644 index bd9f67dd..00000000 --- a/types/luanti_lsp_definitions/library/defs/particle/type.lua +++ /dev/null @@ -1,133 +0,0 @@ ----@meta _ --- DRAFT 1 DONE --- luanti/doc/lua_api.md: Definition tables > `ParticleSpawner` definition - --- -------------------------- ParticleSpawner.vec2 -------------------------- -- - ---[[ -WIPDOC -]] ----@alias core.ParticleSpawner.vec2 ---- | vec2.xy ---- | number - --- -------------------------- ParticleSpawner.vec3 -------------------------- -- - ----@alias core.ParticleSpawner.vec3 ---- | vector ---- | number - --- ----------------------- ParticleSpawner.float_range ---------------------- -- - ----@class _.ParticleSpawner.float_range ---[[ -WIPDOC -]] ----@field min number ---[[ -WIPDOC -]] ----@field max number - ---[[ -WIPDOC -]] ----@alias core.ParticleSpawner.float_range ---- | _.ParticleSpawner.float_range ---- | number - --- ----------------------- ParticleSpawner.vec2_range ----------------------- -- - ----@class _.ParticleSpawner.vec2_range ---[[ -WIPDOC -]] ----@field min vec2.xy ---[[ -WIPDOC -]] ----@field max vec2.xy ---[[ -WIPDOC -]] ----@field bias number? - ---[[ -WIPDOC -]] ----@alias core.ParticleSpawner.vec2_range ---- | _.ParticleSpawner.vec2_range ---- | core.ParticleSpawner.vec2 - --- ----------------------- ParticleSpawner.vec3_range ----------------------- -- - ----@class _.ParticleSpawner.vec3_range ---[[ -WIPDOC -]] ----@field min vector ---[[ -WIPDOC -]] ----@field max vector ---[[ -WIPDOC -]] ----@field bias number? - ---[[ -WIPDOC -]] ----@alias core.ParticleSpawner.vec3_range ---- | _.ParticleSpawner.vec3_range ---- | core.ParticleSpawner.vec3 - --- -------------------------- ParticleSpawner.tween ------------------------- -- - ---[[ -WIPDOC -]] ----@alias core.ParticleSpawner.tween.style ---- | "fwd" ---- | "rev" ---- | "pulse" ---- | "flicker" - ----@class _.ParticleSpawner.tween.__base ---[[ -WIPDOC -]] ----@field style core.ParticleSpawner.tween.style? ---[[ -WIPDOC -]] ----@field reps number? ---[[ -WIPDOC -]] ----@field start number? - ---[[ -WIPDOC -]] ----@class core.ParticleSpawner.tween.float : {[integer]:number}, _.ParticleSpawner.tween.__base - ---[[ -WIPDOC -]] ----@class core.ParticleSpawner.tween.vec2 : {[integer]:core.ParticleSpawner.vec2}, _.ParticleSpawner.tween.__base - ---[[ -WIPDOC -]] ----@class core.ParticleSpawner.tween.vec3 : {[integer]:core.ParticleSpawner.vec3}, _.ParticleSpawner.tween.__base - ---[[ -WIPDOC -]] ----@class core.ParticleSpawner.tween.float_range : {[integer]:core.ParticleSpawner.float_range}, _.ParticleSpawner.tween.__base - ---[[ -WIPDOC -]] ----@class core.ParticleSpawner.tween.vec3_range : {[integer]:core.ParticleSpawner.vec3_range}, _.ParticleSpawner.tween.__base \ No newline at end of file diff --git a/types/luanti_lsp_definitions/library/defs/pointed_thing.lua b/types/luanti_lsp_definitions/library/defs/pointed_thing.lua deleted file mode 100644 index cb8f26b2..00000000 --- a/types/luanti_lsp_definitions/library/defs/pointed_thing.lua +++ /dev/null @@ -1,99 +0,0 @@ ----@meta _ --- DRAFT 1 DONE --- luanti/doc/lua_api.md: Representations of simple things - --- -------------------------- PointedThing.nothing -------------------------- -- - ---[[ -WIPDOC -]] ----@class core.PointedThing.nothing ---[[ -WIPDOC -]] ----@field type "nothing" - --- ---------------------------- PointedThing.node --------------------------- -- - ---[[ -WIPDOC -]] ----@class core.PointedThing.node ---[[ -WIPDOC -]] ----@field type "node" ---[[ -WIPDOC -]] ----@field under ivector ---[[ -WIPDOC -]] ----@field above ivector - --- --------------------------- PointedThing.object -------------------------- -- - ---[[ -WIPDOC -]] ----@class core.PointedThing.object ---[[ -WIPDOC -]] ----@field type "object" ---[[ -WIPDOC -]] ----@field ref core.ObjectRef - ---[[ -WIPDOC -]] ----@alias core.PointedThing ---- | core.PointedThing.nothing ---- | core.PointedThing.node ---- | core.PointedThing.object - --- -------------------------- PointedThing.raycast -------------------------- -- - ----@class _.PointedThing.raycast.__partial ---[[ -Only raycast supports this -* `pointed_thing.intersection_point`: The absolute world coordinates of the - point on the selection box which is pointed at. May be in the selection box - if the pointer is in the box too. -]] ----@field intersection_point vector ---[[ -Only raycast supports this -* `pointed_thing.box_id`: The ID of the pointed selection box (counting starts - from 1). -]] ----@field box_id integer ---[[ -Only raycast supports this -* `pointed_thing.intersection_normal`: Unit vector, points outwards of the - selected selection box. This specifies which face is pointed at. - Is a null vector `vector.zero()` when the pointer is inside the selection box. - For entities with rotated selection boxes, this will be rotated properly - by the entity's rotation - it will always be in absolute world space. -]] ----@field intersection_normal vector - ---[[ -WIPDOC -]] ----@class core.PointedThing.raycast.node : core.PointedThing.node, _.PointedThing.raycast.__partial - ---[[ -WIPDOC -]] ----@class core.PointedThing.raycast.object : core.PointedThing.object, _.PointedThing.raycast.__partial - ---[[ -WIPDOC -]] ----@alias core.PointedThing.raycast.all ---- | core.PointedThing.raycast.node ---- | core.PointedThing.raycast.object \ No newline at end of file diff --git a/types/luanti_lsp_definitions/library/defs/privilege.lua b/types/luanti_lsp_definitions/library/defs/privilege.lua deleted file mode 100644 index 0f60df25..00000000 --- a/types/luanti_lsp_definitions/library/defs/privilege.lua +++ /dev/null @@ -1,152 +0,0 @@ ----@meta _ --- DRAFT 1 DONE --- luanti/doc/lua_api.md: Definition tables > Privilege definition - --- ------------------------------ PrivilegeSet ------------------------------ -- - ---[[ -WIPDOC -]] ----@alias core.PrivilegeSet.keys ---- | "shout" ---- | "interact" ---- | "fast" ---- | "fly" ---- | "noclip" ---- | "teleport" ---- | "bring" ---- | "give" ---- | "settime" ---- | "debug" ---- | "privs" ---- | "basic_privs" ---- | "kick" ---- | "ban" ---- | "password" ---- | "protection_bypass" ---- | "server" ---- | "rollback" ---- | string - ---[[ -WIPDOC -]] ----@class core.PrivilegeSet : {[string]:boolean?} ---[[ -WIPDOC -]] ----@field shout boolean? ---[[ -WIPDOC -]] ----@field interact boolean? ---[[ -WIPDOC -]] ----@field fast boolean? ---[[ -WIPDOC -]] ----@field fly boolean? ---[[ -WIPDOC -]] ----@field noclip boolean? ---[[ -WIPDOC -]] ----@field teleport boolean? ---[[ -WIPDOC -]] ----@field bring boolean? ---[[ -WIPDOC -]] ----@field give boolean? ---[[ -WIPDOC -]] ----@field settime boolean? ---[[ -WIPDOC -]] ----@field debug boolean? ---[[ -WIPDOC -]] ----@field privs boolean? ---[[ -WIPDOC -]] ----@field basic_privs boolean? ---[[ -WIPDOC -]] ----@field kick boolean? ---[[ -WIPDOC -]] ----@field ban boolean? ---[[ -WIPDOC -]] ----@field password boolean? ---[[ -WIPDOC -]] ----@field protection_bypass boolean? ---[[ -WIPDOC -]] ----@field server boolean? ---[[ -WIPDOC -]] ----@field rollback boolean? - --- ------------------------------ PrivilegeDef ------------------------------ -- - ---[[ -WIPDOC -]] ----@alias core.PrivilegeDef.on_grant fun(name:string, granter_name:string): boolean? - ---[[ -WIPDOC -]] ----@alias core.PrivilegeDef.on_revoke fun(name:string, revoker_name:string): boolean? - ---[[ -WIPDOC -]] ----@class core.PrivilegeDef ---[[ -WIPDOC -]] ----@field description string? ---[[ -WIPDOC -]] ----@field give_to_singleplayer boolean? ---[[ -Whether to grant the privilege to the server admin. -Uses value of 'give_to_singleplayer' by default. -]] ----@field give_to_admin boolean? ---[[ -Note that the above two callbacks will be called twice if a player is -responsible, once with the player name, and then with a nil player -name. -Return true in the above callbacks to stop register_on_priv_grant or -revoke being called. -]] ----@field on_grant core.PrivilegeDef.on_grant? ---[[ -Note that the above two callbacks will be called twice if a player is -responsible, once with the player name, and then with a nil player -name. -Return true in the above callbacks to stop register_on_priv_grant or -revoke being called. -]] ----@field on_revoke core.PrivilegeDef.on_revoke? diff --git a/types/luanti_lsp_definitions/library/defs/schematics.lua b/types/luanti_lsp_definitions/library/defs/schematics.lua deleted file mode 100644 index 3fc78f29..00000000 --- a/types/luanti_lsp_definitions/library/defs/schematics.lua +++ /dev/null @@ -1,155 +0,0 @@ ----@meta _ --- DRAFT 1 DONE --- luanti/doc/lua_api.md: Schematics - --- ----------------------------- Schematic.flag ----------------------------- -- - ---[[ -WIPDOC -]] ----@class core.Schematic.flags.tablefmt ---[[ -WIPDOC -]] ----@field place_center_x boolean? ---[[ -WIPDOC -]] ----@field noplace_center_x boolean? ---[[ -WIPDOC -]] ----@field place_center_y boolean? ---[[ -WIPDOC -]] ----@field noplace_center_y boolean? ---[[ -WIPDOC -]] ----@field place_center_z boolean? ---[[ -WIPDOC -]] ----@field noplace_center_z boolean? - ---[[ -WIPDOC -]] ----@alias core.Schematic.flags.stringfmt string - ---[[ -WIPDOC -]] ----@alias core.Schematic.flags ---- | core.Schematic.flags.tablefmt ---- | core.Schematic.flags.stringfmt - --- ------------------------ SchematicDef.yslice_prob ------------------------ -- - ---[[ -WIPDOC -]] ----@class core.SchematicDef.yslice_prob ---[[ -WIPDOC -]] ----@field ypos integer ---[[ -* A probability value of `0` or `1` means that node will never appear - (0% chance). -* A probability value of `254` or `255` means the node will always appear - (100% chance). -* If the probability value `p` is greater than `1`, then there is a - `(p / 256 * 100)` percent chance that node will appear when the schematic is - placed on the map. -]] ----@field prob integer - --- ---------------------------- SchematicDef.node --------------------------- -- - ---[[ -WIPDOC -]] ----@class core.SchematicDef.Node ---[[ - * `name`: the name of the map node to place (required) -]] ----@field name string ---[[ - * `param2`: the raw param2 value of the node being placed onto the map - (default: 0) -]] ----@field param2 core.Param2? ---[[ - * `force_place`: boolean representing if the node should forcibly overwrite - any previous contents (default: false) -]] ----@field force_place boolean? ---[[ - * `prob` (alias `param1`): the probability of this node being placed - (default: 255) -]] ----@field prob integer? ---[[ - * `prob` (alias `param1`): the probability of this node being placed - (default: 255) - -* @deprecated -]] ----@field param1 integer? - --- -------------------------------- Schematic ------------------------------- -- - ---[[ -WIPDOC -]] ----@class core.SchematicID - ---[[ -A schematic specifier identifies a schematic by either a filename to a -Luanti Schematic file (`.mts`) or through raw data supplied through Lua, -in the form of a table. -]] ----@class core.SchematicDef ---[[ -* The `size` field is a 3D vector containing the dimensions of the provided - schematic. (required field) -]] ----@field size ivector ---[[ -* The `yslice_prob` field is a table of {ypos, prob} slice tables. A slice table - sets the probability of a particular horizontal slice of the schematic being - placed. (optional field) - `ypos` = 0 for the lowest horizontal slice of a schematic. - The default of `prob` is 255. - * A probability value of `0` or `1` means that node will never appear - (0% chance). - * A probability value of `254` or `255` means the node will always appear - (100% chance). - * If the probability value `p` is greater than `1`, then there is a - `(p / 256 * 100)` percent chance that node will appear when the schematic is - placed on the map. -]] ----@field yslice_prob core.SchematicDef.yslice_prob ---[=[ -* The `data` field is a flat table of Node tables making up the schematic, - in the order of `[z [y [x]]]`. (required field) - Each Node table contains: - * `name`: the name of the map node to place (required) - * `prob` (alias `param1`): the probability of this node being placed - (default: 255) - * `param2`: the raw param2 value of the node being placed onto the map - (default: 0) - * `force_place`: boolean representing if the node should forcibly overwrite - any previous contents (default: false) -]=] ----@field data core.SchematicDef.Node[] - ---[[ -WIPDOC -]] ----@alias core.Schematic ---- | core.SchematicID ---- | core.Path ---- | core.SchematicDef \ No newline at end of file diff --git a/types/luanti_lsp_definitions/library/defs/sound.lua b/types/luanti_lsp_definitions/library/defs/sound.lua deleted file mode 100644 index 1507af5a..00000000 --- a/types/luanti_lsp_definitions/library/defs/sound.lua +++ /dev/null @@ -1,81 +0,0 @@ ----@meta _ --- DRAFT 1 DONE --- luanti/doc/lua_api.md: Sounds - ---[[ -WIPDOC -]] ----@class core.SimpleSoundSpec.tablefmt ---[[ -WIPDOC -]] ----@field name string ---[[ -WIPDOC -]] ----@field gain number? ---[[ -WIPDOC -]] ----@field pitch number? ---[[ -WIPDOC -]] ----@field fade number? - ---[[ -WIPDOC -]] ----@alias core.SimpleSoundSpec.stringfmt string - ---[[ -WIPDOC -]] ----@alias core.SimpleSoundSpec ---- | core.SimpleSoundSpec.tablefmt ---- | core.SimpleSoundSpec.stringfmt - ---[[ -WIPDOC -]] ----@class core.SoundParamter ---[[ -WIPDOC -]] ----@field gain number? ---[[ -WIPDOC -]] ----@field pitch number? ---[[ -WIPDOC -]] ----@field fade number? ---[[ -WIPDOC -]] ----@field start_time number? ---[[ -WIPDOC -]] ----@field loop boolean? ---[[ -WIPDOC -]] ----@field pos vector? ---[[ -WIPDOC -]] ----@field object core.ObjectRef? ---[[ -WIPDOC -]] ----@field to_player string? ---[[ -WIPDOC -]] ----@field exclude_player string? ---[[ -WIPDOC -]] ----@field max_hear_distance number? \ No newline at end of file diff --git a/types/luanti_lsp_definitions/library/defs/textures.lua b/types/luanti_lsp_definitions/library/defs/textures.lua deleted file mode 100644 index 0911ef4a..00000000 --- a/types/luanti_lsp_definitions/library/defs/textures.lua +++ /dev/null @@ -1,8 +0,0 @@ ----@meta _ --- DRAFT 1 DONE --- luanti/doc/lua_api.md: Textures - ---[[ -WIPDOC -]] ----@alias core.Texture string \ No newline at end of file diff --git a/types/luanti_lsp_definitions/library/defs/tile.lua b/types/luanti_lsp_definitions/library/defs/tile.lua deleted file mode 100644 index bed85327..00000000 --- a/types/luanti_lsp_definitions/library/defs/tile.lua +++ /dev/null @@ -1,134 +0,0 @@ ----@meta _ --- DRAFT 1 DONE --- luanti/doc/lua_api.md: Definition tables > Tile definition --- luanti/doc/lua_api.md: Definition tables > Tile animation definition - --- -------------------- TileAnimationDef.vertical_frames -------------------- -- - ---[[ -WIPDOC -]] ----@class core.TileAnimationDef.vertical_frames ---[[ -WIPDOC -]] ----@field type "vertical_frames" ---[[ -WIPDOC -]] ----@field aspect_w integer ---[[ -WIPDOC -]] ----@field aspect_h integer ---[[ -WIPDOC -]] ----@field length number - --- ------------------------ TileAnimationDef.sheet_2d ----------------------- -- - ---[[ -WIPDOC -]] ----@class core.TileAnimationDef.sheet_2d ---[[ -WIPDOC -]] ----@field type "sheet_2d" ---[[ -WIPDOC -]] ----@field frames_w integer ---[[ -WIPDOC -]] ----@field frames_h integer ---[[ -WIPDOC -]] ----@field frame_length number - --- ---------------------------- TileAnimationDef ---------------------------- -- - ---[[ -WIPDOC -]] ----@alias core.TileAnimationDef ---- | core.TileAnimationDef.vertical_frames ---- | core.TileAnimationDef.sheet_2d - --- ----------------------------- TileDef.__base ----------------------------- -- - ----@class _.TileDef.__base ---[[ -WIPDOC -]] ----@field name core.Texture ---[[ -WIPDOC - -* @deprecated 5.X -]] ----@field image string? - --- ---------------------------- TileDef.animation --------------------------- -- - ---[[ -WIPDOC -]] ----@class core.TileDef.animation : _.TileDef.__base ---[[ -WIPDOC -]] ----@field animation core.TileAnimationDef - - --- ----------------------------- TileDef.regular ---------------------------- -- - ---[[ -WIPDOC -]] ----@alias core.TileDef.align_style ---- | "node" ---- | "world" ---- | "user" - ---[[ -WIPDOC -]] ----@class core.TileDef.regular : _.TileDef.__base ---[[ -WIPDOC -]] ----@field backface_culling boolean? ---[[ -WIPDOC -]] ----@field align_style core.TileDef.align_style? ---[[ -WIPDOC -]] ----@field scale integer? - --- ------------------------------ TileDef.color ----------------------------- -- - ---[[ -WIPDOC -]] ----@class core.TileDef.color : _.TileDef.__base ---[[ -WIPDOC -]] ----@field color core.ColorSpec - --- --------------------------------- TileDef -------------------------------- -- - ---[[ -WIPDOC -]] ----@alias core.TileDef ---- | core.Texture ---- | core.TileDef.animation ---- | core.TileDef.regular ---- | core.TileDef.color \ No newline at end of file diff --git a/types/luanti_lsp_definitions/library/defs/tool_capabilities.lua b/types/luanti_lsp_definitions/library/defs/tool_capabilities.lua deleted file mode 100644 index f8635953..00000000 --- a/types/luanti_lsp_definitions/library/defs/tool_capabilities.lua +++ /dev/null @@ -1,96 +0,0 @@ ----@meta _ --- DRAFT 1 DONE --- luanti/doc/lua_api.md: Tool Capabilities - --- ---------------------- ToolCapabilities.*.groupcaps ---------------------- -- - ---[[ -WIPDOC -]] ----@class core.ToolCapabilities.item.groupcap ---[[ -WIPDOC -]] ----@field times number[]? ---[[ -WIPDOC -]] ----@field maxlevel integer? - ---[[ -WIPDOC -]] ----@alias core.ToolCapabilities.item.groupcaps table - ---[[ -WIPDOC -]] ----@class core.ToolCapabilities.tool.groupcap : core.ToolCapabilities.item.groupcap ---[[ -WIPDOC -]] ----@field uses integer? - ---[[ -WIPDOC -]] ----@alias core.ToolCapabilities.tool.groupcaps table - --- --------------------- ToolCapabilities.damage_groups --------------------- -- - ---[[ -WIPDOC -]] ----@alias core.ToolCapabilities.damage_groups table - --- -------------------------- ToolCapabilities.item ------------------------- -- - ---[[ -WIPDOC -]] ----@class core.ToolCapabilities.item ---[[ -WIPDOC -]] ----@field full_punch_interval number? ---[[ -WIPDOC -]] ----@field max_drop_level integer? ---[[ -WIPDOC -]] ----@field groupcaps core.ToolCapabilities.item.groupcaps? ---[[ -WIPDOC -]] ----@field damage_groups core.ToolCapabilities.damage_groups? - --- -------------------------- ToolCapabilities.tool ------------------------- -- - ---[[ -WIPDOC -]] ----@class core.ToolCapabilities.tool : core.ToolCapabilities.item ---[[ -WIPDOC -]] ----@field groupcaps core.ToolCapabilities.item.groupcaps? ---[[ -Amount of uses this tool has for attacking players and entities -by punching them (0 = infinite uses). -For compatibility, this is automatically set from the first -suitable groupcap using the formula "uses * 3^(maxlevel - 1)". -It is recommend to set this explicitly instead of relying on the -fallback behavior. -]] ----@field punch_attack_uses integer? - --- ---------------------------- ToolCapabilities ---------------------------- -- - ---[[ -WIPDOC -]] ----@alias core.ToolCapabilities ---- | core.ToolCapabilities.item ---- | core.ToolCapabilities.tool \ No newline at end of file diff --git a/types/luanti_lsp_definitions/library/defs/wear_bar_color.lua b/types/luanti_lsp_definitions/library/defs/wear_bar_color.lua deleted file mode 100644 index c8120991..00000000 --- a/types/luanti_lsp_definitions/library/defs/wear_bar_color.lua +++ /dev/null @@ -1,23 +0,0 @@ ----@meta _ --- DRAFT 1 DONE --- luanti/doc/lua_api.md: Definition tables > Wear Bar Color - ---[[ -WIPDOC -]] ----@class core.WearBarColor.tablefmt ---[[ -WIPDOC -]] ----@field blend "linear"|"constant" ---[[ -WIPDOC -]] ----@field color_stops table - ---[[ -WIPDOC -]] ----@alias core.WearBarColor ---- | core.ColorSpec ---- | core.WearBarColor.tablefmt \ No newline at end of file diff --git a/types/luanti_lsp_definitions/library/helpers.lua b/types/luanti_lsp_definitions/library/helpers.lua deleted file mode 100644 index ab0f6e33..00000000 --- a/types/luanti_lsp_definitions/library/helpers.lua +++ /dev/null @@ -1,203 +0,0 @@ ----@meta _ --- Helper functions in the global namespace or extends Lua's stdlib --- luanti/doc/lua_api.md: Helper functions - --- NOTE: core.* helpers are in library/core/utilities/helpers.lua - ---[[ -Returns `obj` as a human-readable string assigned to `name`. Handles reference -loops. Table format resembles flattened JSON representation. - -* @see luanti/builtin/common/misc_helpers.lua -]] ----@param obj any ----@param name string? #@default(`"_"`) ----@param dumped table? #@default(`{}`) ----@return string -function dump2(obj, name, dumped) end - ---[[ -Returns `value` as a human-readable string. Handles reference loops. Table -format resembles JSON. - -* @see luanti/builtin/common/misc_helpers.lua -]] ----@param value any ----@param indent string? ----@return string -function dump(value, indent) end - --- ---------------------------------- math ---------------------------------- -- - ---[[ -Returns hypotenuse of a triangle with legs x and y. Useful to obtain distance. - -* @see luanti/builtin/common/math.lua -]] ----@nodiscard ----@param x number ----@param y number ----@return number -function math.hypot(x, y) end - ---[[ -Returns the sign of a number. - -* @see luanti/builtin/common/math.lua -]] ----@nodiscard ----@param x number ----@param tolerance number? #@default(`0`) anchor where the zero would be ----@return -1|0|1 #@hint(`[-1, 1]`) -function math.sign(x, tolerance) end - ---[[ -Returns factorial of `x` - -* @see luanti/builtin/common/math.lua -]] ----@nodiscard ----@param x integer #@hint(`[0,171]`) ----@return integer -function math.factorial(x) end - ---[[ -Returns `x` rounded to the nearest integer - -* @see luanti/builtin/common/math.lua -]] ----@nodiscard ----@param x number ----@return integer -function math.round(x) end - --- --------------------------------- string --------------------------------- -- - ---[[ -Splits given string into a list. - -* @see luanti/builtin/common/misc_helpers.lua -]] ----@nodiscard ----@param str string ----@param separator string? #@default(`","`) @hint(`not empty`) ----@param include_empty boolean? #@default(`false`) ----@param max_splits integer? #@default(`-1`) Unlimited if negative ----@param sep_is_pattern boolean? #@default(`false`) `separator` is lua pattern or plain string ----@return string[] -function string.split(str, separator, include_empty, max_splits, sep_is_pattern) end - ---[[ -Trim whitespace out of given string at beginning and end. Uses the `%s` lua -pattern item. - -* @see luanti/builtin/common/misc_helpers.lua -]] ----@nodiscard ----@param str string ----@return string -function string.trim(str) end - --- ---------------------------------- table --------------------------------- -- - --- NOTE: SparseList doesn't work here because these list operations work on --- #list or ipairs(list) - ---[[ -Returns a deep copy of given table. Metatables are ignored. - -* @see luanti/builtin/common/misc_helpers.lua -]] ----@nodiscard ----@generic T : table ----@param table `T` ----@return T -function table.copy(table) end - ---[[ -Returns a deep copy of given table. Metatables are included. - -* @added 5.12 -* @see luanti/builtin/common/misc_helpers.lua -]] ----@nodiscard ----@generic T : table ----@param table `T` ----@return T -function table.copy_with_metatables(table) end - ---[[ -Returns first smallest index of `val` in given list. Ignores non-array part of -list. List must not have negative indices. - -If not found, returns -1 instead. - -* @see luanti/builtin/common/misc_helpers.lua -]] ----@nodiscard ----@generic T ----@param val T ----@param list T[] ----@return integer -function table.indexof(list, val) end - ---[[ -Returns a key of `val` in given table. Not specified which key is returned if -many has `val` - -If not found, returns `nil` instead - -* @see luanti/builtin/common/misc_helpers.lua -]] ----@nodiscard ----@generic T ----@param table table ----@param val any ----@return T? -function table.keyof(table, val) end - ---[[ -Inserts all values from `other_list` into `list`. Returns `list`. - -* @see luanti/builtin/common/misc_helpers.lua -]] ----@nodiscard ----@generic T ----@param list T[] ----@param other_list T[] ----@return T[] -function table.insert_all(list, other_list) end - ---[[ -Returns a table with keys and values of given table swapped. Not specified -value would map to which keys if many keys has the same value. - -* @see luanti/builtin/common/misc_helpers.lua -]] ----@nodiscard ----@param t table ----@return table -function table.key_value_swap(t) end - ---[[ -Function accepts two positive integers and must return a value inclusively -between the integers. - -* @hint int1 `0` -* @hint int2 `>=1` -* @hint return `[int1,int2]` -* @see luanti/builtin/common/misc_helpers.lua -]] ----@alias table.random_func fun(int1:integer, int2:integer): integer - ---[[ -Shuffles elements in given list from `from` to `to` in place. - -* @see luanti/builtin/common/misc_helpers.lua -]] ----@generic T ----@param list T[] ----@param from integer? #@default(`1`) ----@param to integer? #@default(`#list`) ----@param random_func table.random_func? #@default(`math.random`) -function table.shuffle(list, from, to, random_func) end \ No newline at end of file diff --git a/types/luanti_lsp_definitions/library/misc.lua b/types/luanti_lsp_definitions/library/misc.lua deleted file mode 100644 index e8928734..00000000 --- a/types/luanti_lsp_definitions/library/misc.lua +++ /dev/null @@ -1,66 +0,0 @@ ----@meta _ --- Miscellaneous. No cohesive grouping --- luanti/doc/lua_api.md: Definition tables > Bit Library - ---[[ -Called on uncaught errors to transform error objects into string to display. - -By default this is a backtrace from `debug.traceback`. Error object is first -converted with `tostring` if it's not a string. This means that you can use -tables as error objects so long as you give them `__tostring` metamethods. - -* @overrideable -* @see luanti/builtin/init.lua -]] ----@nodiscard ----@param err any ----@param level integer #@hint(`>=0`) ----@return string -function core.error_handler(err, level) end - ---[[ -Path separator - -* @deprecated 5.X Recommended to use the forward slash `/` instead -* @see -]] ----@deprecated ----@type "/"|"\\" -DIR_DELIM = nil - ---[[ -Luanti provids the bitop library. Avoid using this unless you really need bit -manipulation as it's not faster than JIT traced arithmetic operations. - -* @see for more information about the specifics in LuaJIT -* @see luanti/lib/bitop/ for its implementation -]] ----@type bitlib -bit = bit - ---[[ -Full absolute path to a file or directory. -]] ----@alias core.Path string - ---[[ -Partial path or filename corresponding to a file within the current mod. -]] ----@alias core.ModAsset string - ---[[ -Serializable types -]] ----@alias core.Serializable nil|boolean|number|string|table - ---[[ -Helper type: `T` or a list of `T` -]] ----@generic T ----@alias OneOrMany T|T[] - ---[[ -Helper type: accepts a sparse list of `T` with holes -]] ----@generic T ----@alias SparseList {[integer]:T}|T[] \ No newline at end of file diff --git a/types/luanti_lsp_definitions/library/vector/vec.lua b/types/luanti_lsp_definitions/library/vector/vec.lua deleted file mode 100644 index b599f2ac..00000000 --- a/types/luanti_lsp_definitions/library/vector/vec.lua +++ /dev/null @@ -1,95 +0,0 @@ ----@meta _ --- DRAFT 1 DONE --- luanti/doc/lua_api.md: Spatial Vectors - --- ---------------------------------- vec2 ---------------------------------- -- - ---[[ -WIPDOC -]] ----@class vec2i.xy ----@field x integer ----@field y integer - ---[[ -WIPDOC -]] ----@class vec2i.12 ----@field [1] number ----@field [2] number - ---[[ -WIPDOC -]] ----@alias vec2i ---- | vec2i.xy ---- | vec2i.12 - ---[[ -WIPDOC -]] ----@class vec2.xy ----@field x number ----@field y number - ---[[ -WIPDOC -]] ----@class vec2.12 ----@field [1] number ----@field [2] number - ---[[ -WIPDOC -]] ----@alias vec2 ---- | vec2.xy ---- | vec2.12 - --- ---------------------------------- vec3 ---------------------------------- -- - ---[[ -WIPDOC -]] ----@class vec3i.xyz ----@field x integer ----@field y integer ----@field z integer - ---[[ -WIPDOC -]] ----@class vec3i.123 ----@field [1] integer ----@field [2] integer ----@field [3] integer - ---[[ -WIPDOC -]] ----@alias vec3i ---- | vec3i.xyz ---- | vec3i.123 - ---[[ -WIPDOC -]] ----@class vec3.xyz ----@field x number ----@field y number ----@field z number - ---[[ -WIPDOC -]] ----@class vec3.123 ----@field [1] number ----@field [2] number ----@field [3] number - ---[[ -WIPDOC -]] ----@alias vec3 ---- | vec3.xyz ---- | vec3.123 \ No newline at end of file diff --git a/types/luanti_lsp_definitions/library/vector/vector.lua b/types/luanti_lsp_definitions/library/vector/vector.lua deleted file mode 100644 index 0144ca7a..00000000 --- a/types/luanti_lsp_definitions/library/vector/vector.lua +++ /dev/null @@ -1,35 +0,0 @@ ----@meta _ --- DRAFT 1 DONE --- luanti/doc/lua_api.md: Spatial Vectors - ----@class _.vec.__base : core.VectorLib ----@field metatable core.VectorLib ----@operator unm(vector):vector ----@operator add(vector):vector ----@operator sub(vector):vector ----@operator div(vector):vector ----@operator mul(vector):vector - ---[[ -WIPDOC -]] ----@class ivec: vec3i.xyz, _.vec.__base - ---[[ -WIPDOC -]] ----@class vec: vec3.xyz, _.vec.__base - ---[[ -WIPDOC -]] ----@alias ivector ---- | vec3i.xyz ---- | ivec - ---[[ -WIPDOC -]] ----@alias vector ---- | vec3.xyz ---- | vec \ No newline at end of file diff --git a/types/luanti_lsp_definitions/library/vector/vectorlib.lua b/types/luanti_lsp_definitions/library/vector/vectorlib.lua deleted file mode 100644 index d70afa9e..00000000 --- a/types/luanti_lsp_definitions/library/vector/vectorlib.lua +++ /dev/null @@ -1,377 +0,0 @@ ----@meta _ --- DRAFT 1 DONE --- luanti/doc/lua_api.md: Spatial Vectors - ---[[ -WIPDOC -]] ----@class core.VectorLib -vector = {} - --- ------------------------------ constructors ------------------------------ -- - ---[[ -Returns a new vector `(a, b, c)` -]] ----@nodiscard ----@param a number ----@param b number ----@param c number ----@return vec -function vector.new(a, b, c) end - ---[[ -Returns a new vector `(a, a, a)` -]] ----@nodiscard ----@param a number ----@return vec -function vector.new(a) end - ---[[ -`vector.new(v)` does the same as `vector.copy(v)` -]] ----@deprecated ----@nodiscard ----@param a vector ----@return vec -function vector.new(a) end - ---[[ -`vector.new()` does the same as `vector.zero()` -]] ----@deprecated ----@nodiscard ----@return vec -function vector.new() end - ---[[ -Returns a new vector `(0, 0, 0)` -]] ----@nodiscard ----@return vec -function vector.zero() end - ---[[ -Returns a new vector of length 1, pointing into a direction chosen uniformly at random. -]] ----@nodiscard ----@return vec -function vector.random_direction() end - ---[[ -Returns a copy of the vector `v`. -]] ----@nodiscard ----@param v vector ----@return vec -function vector.copy(v) end - --- ---------------------------- string conversion --------------------------- -- - ---[[ -Returns v, np, where v is a vector read from the given string s and np is the -next position in the string after the vector. -Returns nil on failure. -]] ----@nodiscard ----@param s string Has to begin with a substring of the form `"(x, y, z)"`. Additional spaces, leaving away commas, and adding an additional comma to the end is allowed. ----@param init number? Starts looking for the vector at this string index ----@return vec? v, integer? np -function vector.from_string(s, init) end - ---[[ -Returns a string of the form `"(x, y, z)"` -`tostring(v)` does the same -]] ----@nodiscard ----@param v vector ----@return vec -function vector.to_string(v) end - --- -------------------------------------------------------------------------- -- - ---[[ -Returns a vector of length 1 with direction p1 to p2. -If p1 and p2 are identical, returns (0, 0, 0). -]] ----@nodiscard ----@param p1 vector ----@param p2 vector ----@return vec -function vector.direction(p1, p2) end - ---[[ -Returns zero or a positive number, the distance between p1 and p2. -]] ----@nodiscard ----@param p1 vector ----@param p2 vector ----@return number -function vector.distance(p1, p2) end - ---[[ -Returns zero or a positive number, the length of vector v. -]] ----@nodiscard ----@param v vector ----@return number -function vector.length(v) end - ---[[ -Returns a vector of length 1 with direction of vector v. -If v has zero length, returns (0, 0, 0). -]] ----@nodiscard ----@param v vector ----@return vec -function vector.normalize(v) end - --- -------------------------- rounding and signness ------------------------- -- - ---[[ -Returns a vector, each dimension rounded down. -]] ----@nodiscard ----@param v vector ----@return ivec -function vector.floor(v) end - ---[[ -Returns a vector, each dimension rounded up. -]] ----@nodiscard ----@param v vector ----@return ivec -function vector.ceil(v) end - ---[[ -Returns a vector, each dimension rounded to the nearest integer. -At a multiple of 0.5, rounds away from zero. -]] ----@nodiscard ----@param v vector ----@return ivec -function vector.round(v) end - ---[[ -Returns a vector where `math.sign` was called for each component -]] ----@nodiscard ----@param v vector ----@param tolerance number? ----@return ivec -function vector.sign(v, tolerance) end - ---[[ -Returns a vector with absolute values for each component -]] ----@nodiscard ----@param v vector ----@return vec -function vector.abs(v) end - --- -------------------------------------------------------------------------- -- - ---[[ -Applies `func` to each component -]] ----@nodiscard ----@param v vector ----@param func fun(n: number): number ----@param ... any Optional arguments passed to `func` ----@return vec -function vector.apply(v, func, ...) end - ---[[ -Returns a vector where the function `func` has combined both components of `v` -and `w` for each component -]] ----@nodiscard ----@param v vector ----@param w vector ----@param func fun(x:number, y:number):number ----@return vec -function vector.combine(v, w, func) end - ---[[ -Returns true if the vectors are identical, false if not -]] ----@nodiscard ----@param v1 vector ----@param v2 vector ----@return vec -function vector.equals(v1, v2) end - ---[[ -Returns in order minp, maxp vectors of the cuboid defined by v1, v2. -(Unofficial note: In other words, each component of the minp is smaller than component in maxp) -]] ----@nodiscard ----@param v1 vector ----@param v2 vector ----@return vec, vec -function vector.sort(v1, v2) end - --- -------------------------------------------------------------------------- -- - ---[[ -Returns the angle between v1 and v2 in radians -]] ----@nodiscard ----@param v1 vector ----@param v2 vector ----@return number -function vector.angle(v1, v2) end - ---[[ -Returns the dot product -]] ----@nodiscard ----@param v1 vector ----@param v2 vector ----@return number -function vector.dot(v1, v2) end - ---[[ -Returns the cross product -]] ----@nodiscard ----@param v1 vector ----@param v2 vector ----@return vec -function vector.cross(v1, v2) end - ---[[ -Returns the sum of vectors `v` and `(x,y,z)` -]] ----@nodiscard ----@param v vector ----@param x number ----@param y number ----@param z number ----@return vec -function vector.offset(v, x, y, z) end - ---[[ -Checks if `v` is a vector, returns false even for tables like {x=,y=,z=}, has to be created with a vector function -]] ----@nodiscard ----@param v vector ----@return boolean -function vector.check(v) end - ---[[ -Checks if `pos` is inside an area formed by `min` and `max` -`min` and `max` are inclusive -If min is bigger than max on some axis, function always returns false. -You can use vector.sort if you have two vectors and don't know which are the minimum and the maximum. -]] ----@nodiscard ----@param pos vector ----@param min vector ----@param max vector ----@return boolean -function vector.in_area(pos, min, max) end - ---[[ -Returns a random integer position in area formed by min and max -min and max are inclusive. -You can use vector.sort if you have two vectors and don't know which are the minimum and the maximum. -]] ----@nodiscard ----@param min vector ----@param max vector ----@return vec -function vector.random_in_area(min, max) end - --- ------------------------- arithmetic and products ------------------------ -- - ---[[ -WIPDOC -]] ----@nodiscard ----@param v vector ----@param x vector|number ----@return vec -function vector.add(v, x) end - ---[[ -WIPDOC -]] ----@nodiscard ----@param v vector ----@param x vector|number ----@return vec -function vector.subtract(v, x) end - ---[[ -WIPDOC -]] ----@nodiscard ----@param v vector ----@param x number ----@return vec -function vector.multiply(v, x) end - ---[[ -WIPDOC -]] ----@nodiscard ----@param v vector ----@param x number ----@return vec -function vector.divide(v, x) end - ---[[ -WIPDOC -]] ----@deprecated ----@nodiscard ----@param v vector ----@param x vector ----@return vec -function vector.multiply(v, x) end - ---[[ -WIPDOC -]] ----@deprecated ----@nodiscard ----@param v vector ----@param x vector ----@return vec -function vector.divide(v, x) end - --- ----------------------- rotation-related functions ----------------------- -- - ---[[ -Applies the rotation r to v and returns the result. -vector.rotate(vector.new(0, 0, 1), r) and vector.rotate(vector.new(0, 1, 0), r) return vectors pointing forward and up relative to an entity's rotation r. -]] ----@nodiscard ----@param v vector ----@param r vector Rotation vector {x=, y=, z=} ----@return vec -function vector.rotate(v, r) end - ---[[ -Returns v1 rotated around axis v2 by a radians according to the right hand rule. -]] ----@nodiscard ----@param v1 vector ----@param v2 vector ----@param a number radians ----@return vec -function vector.rotate_around_axis(v1, v2, a) end - ---[[ -Returns a rotation vector for direction pointing forward using up as the up vector. -If up is omitted, the roll of the returned vector defaults to zero. -Otherwise direction and up need to be vectors in a 90 degree angle to each other. -]] ----@nodiscard ----@param up vector? ----@param direction vector ----@return vec -function vector.dir_to_rotation(direction, up) end \ No newline at end of file diff --git a/types/luanti_lsp_definitions/utils/.cspell-luanti.txt b/types/luanti_lsp_definitions/utils/.cspell-luanti.txt deleted file mode 100644 index 28396964..00000000 --- a/types/luanti_lsp_definitions/utils/.cspell-luanti.txt +++ /dev/null @@ -1,40 +0,0 @@ -bgcolor -dtime -emax -emin -hpchange -hypot -indexof -irrlicht -lbm -lbmdef -lbms -lsystem -luals -luanti -luma -manip -maxp -maxx -maxy -maxz -minp -minx -miny -minz -mymod -nodiscard -noiseparam -noiseparams -pmax -pmin -priv -privs -prng -schem -unregister -unregisters -vmanip -xslice -yslice -zslice diff --git a/types/luanti_lsp_definitions/utils/.cspell-misc.txt b/types/luanti_lsp_definitions/utils/.cspell-misc.txt deleted file mode 100644 index 6d658b38..00000000 --- a/types/luanti_lsp_definitions/utils/.cspell-misc.txt +++ /dev/null @@ -1,7 +0,0 @@ -emmylua -fgaz -luarc -nvim -burnti -FFFFFAFFBF -voronoi \ No newline at end of file diff --git a/types/luanti_lsp_definitions/utils/LGPLv2.1..txt b/types/luanti_lsp_definitions/utils/LGPLv2.1..txt deleted file mode 100644 index f6683e74..00000000 --- a/types/luanti_lsp_definitions/utils/LGPLv2.1..txt +++ /dev/null @@ -1,501 +0,0 @@ - GNU LESSER GENERAL PUBLIC LICENSE - Version 2.1, February 1999 - - Copyright (C) 1991, 1999 Free Software Foundation, Inc. - - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - -[This is the first released version of the Lesser GPL. It also counts - as the successor of the GNU Library Public License, version 2, hence - the version number 2.1.] - - Preamble - - The licenses for most software are designed to take away your -freedom to share and change it. By contrast, the GNU General Public -Licenses are intended to guarantee your freedom to share and change -free software--to make sure the software is free for all its users. - - This license, the Lesser General Public License, applies to some -specially designated software packages--typically libraries--of the -Free Software Foundation and other authors who decide to use it. You -can use it too, but we suggest you first think carefully about whether -this license or the ordinary General Public License is the better -strategy to use in any particular case, based on the explanations below. - - When we speak of free software, we are referring to freedom of use, -not price. Our General Public Licenses are designed to make sure that -you have the freedom to distribute copies of free software (and charge -for this service if you wish); that you receive source code or can get -it if you want it; that you can change the software and use pieces of -it in new free programs; and that you are informed that you can do -these things. - - To protect your rights, we need to make restrictions that forbid -distributors to deny you these rights or to ask you to surrender these -rights. These restrictions translate to certain responsibilities for -you if you distribute copies of the library or if you modify it. - - For example, if you distribute copies of the library, whether gratis -or for a fee, you must give the recipients all the rights that we gave -you. You must make sure that they, too, receive or can get the source -code. If you link other code with the library, you must provide -complete object files to the recipients, so that they can relink them -with the library after making changes to the library and recompiling -it. And you must show them these terms so they know their rights. - - We protect your rights with a two-step method: (1) we copyright the -library, and (2) we offer you this license, which gives you legal -permission to copy, distribute and/or modify the library. - - To protect each distributor, we want to make it very clear that -there is no warranty for the free library. Also, if the library is -modified by someone else and passed on, the recipients should know -that what they have is not the original version, so that the original -author's reputation will not be affected by problems that might be -introduced by others. - - Finally, software patents pose a constant threat to the existence of -any free program. We wish to make sure that a company cannot -effectively restrict the users of a free program by obtaining a -restrictive license from a patent holder. Therefore, we insist that -any patent license obtained for a version of the library must be -consistent with the full freedom of use specified in this license. - - Most GNU software, including some libraries, is covered by the -ordinary GNU General Public License. This license, the GNU Lesser -General Public License, applies to certain designated libraries, and -is quite different from the ordinary General Public License. We use -this license for certain libraries in order to permit linking those -libraries into non-free programs. - - When a program is linked with a library, whether statically or using -a shared library, the combination of the two is legally speaking a -combined work, a derivative of the original library. The ordinary -General Public License therefore permits such linking only if the -entire combination fits its criteria of freedom. The Lesser General -Public License permits more lax criteria for linking other code with -the library. - - We call this license the "Lesser" General Public License because it -does Less to protect the user's freedom than the ordinary General -Public License. It also provides other free software developers Less -of an advantage over competing non-free programs. These disadvantages -are the reason we use the ordinary General Public License for many -libraries. However, the Lesser license provides advantages in certain -special circumstances. - - For example, on rare occasions, there may be a special need to -encourage the widest possible use of a certain library, so that it becomes -a de-facto standard. To achieve this, non-free programs must be -allowed to use the library. A more frequent case is that a free -library does the same job as widely used non-free libraries. In this -case, there is little to gain by limiting the free library to free -software only, so we use the Lesser General Public License. - - In other cases, permission to use a particular library in non-free -programs enables a greater number of people to use a large body of -free software. For example, permission to use the GNU C Library in -non-free programs enables many more people to use the whole GNU -operating system, as well as its variant, the GNU/Linux operating -system. - - Although the Lesser General Public License is Less protective of the -users' freedom, it does ensure that the user of a program that is -linked with the Library has the freedom and the wherewithal to run -that program using a modified version of the Library. - - The precise terms and conditions for copying, distribution and -modification follow. Pay close attention to the difference between a -"work based on the library" and a "work that uses the library". The -former contains code derived from the library, whereas the latter must -be combined with the library in order to run. - - GNU LESSER GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. This License Agreement applies to any software library or other -program which contains a notice placed by the copyright holder or -other authorized party saying it may be distributed under the terms of -this Lesser General Public License (also called "this License"). -Each licensee is addressed as "you". - - A "library" means a collection of software functions and/or data -prepared so as to be conveniently linked with application programs -(which use some of those functions and data) to form executables. - - The "Library", below, refers to any such software library or work -which has been distributed under these terms. A "work based on the -Library" means either the Library or any derivative work under -copyright law: that is to say, a work containing the Library or a -portion of it, either verbatim or with modifications and/or translated -straightforwardly into another language. (Hereinafter, translation is -included without limitation in the term "modification".) - - "Source code" for a work means the preferred form of the work for -making modifications to it. For a library, complete source code means -all the source code for all modules it contains, plus any associated -interface definition files, plus the scripts used to control compilation -and installation of the library. - - Activities other than copying, distribution and modification are not -covered by this License; they are outside its scope. The act of -running a program using the Library is not restricted, and output from -such a program is covered only if its contents constitute a work based -on the Library (independent of the use of the Library in a tool for -writing it). Whether that is true depends on what the Library does -and what the program that uses the Library does. - - 1. You may copy and distribute verbatim copies of the Library's -complete source code as you receive it, in any medium, provided that -you conspicuously and appropriately publish on each copy an -appropriate copyright notice and disclaimer of warranty; keep intact -all the notices that refer to this License and to the absence of any -warranty; and distribute a copy of this License along with the -Library. - - You may charge a fee for the physical act of transferring a copy, -and you may at your option offer warranty protection in exchange for a -fee. - - 2. You may modify your copy or copies of the Library or any portion -of it, thus forming a work based on the Library, and copy and -distribute such modifications or work under the terms of Section 1 -above, provided that you also meet all of these conditions: - - a) The modified work must itself be a software library. - - b) You must cause the files modified to carry prominent notices - stating that you changed the files and the date of any change. - - c) You must cause the whole of the work to be licensed at no - charge to all third parties under the terms of this License. - - d) If a facility in the modified Library refers to a function or a - table of data to be supplied by an application program that uses - the facility, other than as an argument passed when the facility - is invoked, then you must make a good faith effort to ensure that, - in the event an application does not supply such function or - table, the facility still operates, and performs whatever part of - its purpose remains meaningful. - - (For example, a function in a library to compute square roots has - a purpose that is entirely well-defined independent of the - application. Therefore, Subsection 2d requires that any - application-supplied function or table used by this function must - be optional: if the application does not supply it, the square - root function must still compute square roots.) - -These requirements apply to the modified work as a whole. If -identifiable sections of that work are not derived from the Library, -and can be reasonably considered independent and separate works in -themselves, then this License, and its terms, do not apply to those -sections when you distribute them as separate works. But when you -distribute the same sections as part of a whole which is a work based -on the Library, the distribution of the whole must be on the terms of -this License, whose permissions for other licensees extend to the -entire whole, and thus to each and every part regardless of who wrote -it. - -Thus, it is not the intent of this section to claim rights or contest -your rights to work written entirely by you; rather, the intent is to -exercise the right to control the distribution of derivative or -collective works based on the Library. - -In addition, mere aggregation of another work not based on the Library -with the Library (or with a work based on the Library) on a volume of -a storage or distribution medium does not bring the other work under -the scope of this License. - - 3. You may opt to apply the terms of the ordinary GNU General Public -License instead of this License to a given copy of the Library. To do -this, you must alter all the notices that refer to this License, so -that they refer to the ordinary GNU General Public License, version 2, -instead of to this License. (If a newer version than version 2 of the -ordinary GNU General Public License has appeared, then you can specify -that version instead if you wish.) Do not make any other change in -these notices. - - Once this change is made in a given copy, it is irreversible for -that copy, so the ordinary GNU General Public License applies to all -subsequent copies and derivative works made from that copy. - - This option is useful when you wish to copy part of the code of -the Library into a program that is not a library. - - 4. You may copy and distribute the Library (or a portion or -derivative of it, under Section 2) in object code or executable form -under the terms of Sections 1 and 2 above provided that you accompany -it with the complete corresponding machine-readable source code, which -must be distributed under the terms of Sections 1 and 2 above on a -medium customarily used for software interchange. - - If distribution of object code is made by offering access to copy -from a designated place, then offering equivalent access to copy the -source code from the same place satisfies the requirement to -distribute the source code, even though third parties are not -compelled to copy the source along with the object code. - - 5. A program that contains no derivative of any portion of the -Library, but is designed to work with the Library by being compiled or -linked with it, is called a "work that uses the Library". Such a -work, in isolation, is not a derivative work of the Library, and -therefore falls outside the scope of this License. - - However, linking a "work that uses the Library" with the Library -creates an executable that is a derivative of the Library (because it -contains portions of the Library), rather than a "work that uses the -library". The executable is therefore covered by this License. -Section 6 states terms for distribution of such executables. - - When a "work that uses the Library" uses material from a header file -that is part of the Library, the object code for the work may be a -derivative work of the Library even though the source code is not. -Whether this is true is especially significant if the work can be -linked without the Library, or if the work is itself a library. The -threshold for this to be true is not precisely defined by law. - - If such an object file uses only numerical parameters, data -structure layouts and accessors, and small macros and small inline -functions (ten lines or less in length), then the use of the object -file is unrestricted, regardless of whether it is legally a derivative -work. (Executables containing this object code plus portions of the -Library will still fall under Section 6.) - - Otherwise, if the work is a derivative of the Library, you may -distribute the object code for the work under the terms of Section 6. -Any executables containing that work also fall under Section 6, -whether or not they are linked directly with the Library itself. - - 6. As an exception to the Sections above, you may also combine or -link a "work that uses the Library" with the Library to produce a -work containing portions of the Library, and distribute that work -under terms of your choice, provided that the terms permit -modification of the work for the customer's own use and reverse -engineering for debugging such modifications. - - You must give prominent notice with each copy of the work that the -Library is used in it and that the Library and its use are covered by -this License. You must supply a copy of this License. If the work -during execution displays copyright notices, you must include the -copyright notice for the Library among them, as well as a reference -directing the user to the copy of this License. Also, you must do one -of these things: - - a) Accompany the work with the complete corresponding - machine-readable source code for the Library including whatever - changes were used in the work (which must be distributed under - Sections 1 and 2 above); and, if the work is an executable linked - with the Library, with the complete machine-readable "work that - uses the Library", as object code and/or source code, so that the - user can modify the Library and then relink to produce a modified - executable containing the modified Library. (It is understood - that the user who changes the contents of definitions files in the - Library will not necessarily be able to recompile the application - to use the modified definitions.) - - b) Use a suitable shared library mechanism for linking with the - Library. A suitable mechanism is one that (1) uses at run time a - copy of the library already present on the user's computer system, - rather than copying library functions into the executable, and (2) - will operate properly with a modified version of the library, if - the user installs one, as long as the modified version is - interface-compatible with the version that the work was made with. - - c) Accompany the work with a written offer, valid for at - least three years, to give the same user the materials - specified in Subsection 6a, above, for a charge no more - than the cost of performing this distribution. - - d) If distribution of the work is made by offering access to copy - from a designated place, offer equivalent access to copy the above - specified materials from the same place. - - e) Verify that the user has already received a copy of these - materials or that you have already sent this user a copy. - - For an executable, the required form of the "work that uses the -Library" must include any data and utility programs needed for -reproducing the executable from it. However, as a special exception, -the materials to be distributed need not include anything that is -normally distributed (in either source or binary form) with the major -components (compiler, kernel, and so on) of the operating system on -which the executable runs, unless that component itself accompanies -the executable. - - It may happen that this requirement contradicts the license -restrictions of other proprietary libraries that do not normally -accompany the operating system. Such a contradiction means you cannot -use both them and the Library together in an executable that you -distribute. - - 7. You may place library facilities that are a work based on the -Library side-by-side in a single library together with other library -facilities not covered by this License, and distribute such a combined -library, provided that the separate distribution of the work based on -the Library and of the other library facilities is otherwise -permitted, and provided that you do these two things: - - a) Accompany the combined library with a copy of the same work - based on the Library, uncombined with any other library - facilities. This must be distributed under the terms of the - Sections above. - - b) Give prominent notice with the combined library of the fact - that part of it is a work based on the Library, and explaining - where to find the accompanying uncombined form of the same work. - - 8. You may not copy, modify, sublicense, link with, or distribute -the Library except as expressly provided under this License. Any -attempt otherwise to copy, modify, sublicense, link with, or -distribute the Library is void, and will automatically terminate your -rights under this License. However, parties who have received copies, -or rights, from you under this License will not have their licenses -terminated so long as such parties remain in full compliance. - - 9. You are not required to accept this License, since you have not -signed it. However, nothing else grants you permission to modify or -distribute the Library or its derivative works. These actions are -prohibited by law if you do not accept this License. Therefore, by -modifying or distributing the Library (or any work based on the -Library), you indicate your acceptance of this License to do so, and -all its terms and conditions for copying, distributing or modifying -the Library or works based on it. - - 10. Each time you redistribute the Library (or any work based on the -Library), the recipient automatically receives a license from the -original licensor to copy, distribute, link with or modify the Library -subject to these terms and conditions. You may not impose any further -restrictions on the recipients' exercise of the rights granted herein. -You are not responsible for enforcing compliance by third parties with -this License. - - 11. If, as a consequence of a court judgment or allegation of patent -infringement or for any other reason (not limited to patent issues), -conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot -distribute so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you -may not distribute the Library at all. For example, if a patent -license would not permit royalty-free redistribution of the Library by -all those who receive copies directly or indirectly through you, then -the only way you could satisfy both it and this License would be to -refrain entirely from distribution of the Library. - -If any portion of this section is held invalid or unenforceable under any -particular circumstance, the balance of the section is intended to apply, -and the section as a whole is intended to apply in other circumstances. - -It is not the purpose of this section to induce you to infringe any -patents or other property right claims or to contest validity of any -such claims; this section has the sole purpose of protecting the -integrity of the free software distribution system which is -implemented by public license practices. Many people have made -generous contributions to the wide range of software distributed -through that system in reliance on consistent application of that -system; it is up to the author/donor to decide if he or she is willing -to distribute software through any other system and a licensee cannot -impose that choice. - -This section is intended to make thoroughly clear what is believed to -be a consequence of the rest of this License. - - 12. If the distribution and/or use of the Library is restricted in -certain countries either by patents or by copyrighted interfaces, the -original copyright holder who places the Library under this License may add -an explicit geographical distribution limitation excluding those countries, -so that distribution is permitted only in or among countries not thus -excluded. In such case, this License incorporates the limitation as if -written in the body of this License. - - 13. The Free Software Foundation may publish revised and/or new -versions of the Lesser General Public License from time to time. -Such new versions will be similar in spirit to the present version, -but may differ in detail to address new problems or concerns. - -Each version is given a distinguishing version number. If the Library -specifies a version number of this License which applies to it and -"any later version", you have the option of following the terms and -conditions either of that version or of any later version published by -the Free Software Foundation. If the Library does not specify a -license version number, you may choose any version ever published by -the Free Software Foundation. - - 14. If you wish to incorporate parts of the Library into other free -programs whose distribution conditions are incompatible with these, -write to the author to ask for permission. For software which is -copyrighted by the Free Software Foundation, write to the Free -Software Foundation; we sometimes make exceptions for this. Our -decision will be guided by the two goals of preserving the free status -of all derivatives of our free software and of promoting the sharing -and reuse of software generally. - - NO WARRANTY - - 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO -WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. -EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR -OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY -KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE -LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME -THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. - - 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN -WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY -AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU -FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR -CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE -LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING -RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A -FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF -SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH -DAMAGES. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Libraries - - If you develop a new library, and you want it to be of the greatest -possible use to the public, we recommend making it free software that -everyone can redistribute and change. You can do so by permitting -redistribution under these terms (or, alternatively, under the terms of the -ordinary General Public License). - - To apply these terms, attach the following notices to the library. It is -safest to attach them to the start of each source file to most effectively -convey the exclusion of warranty; and each file should have at least the -"copyright" line and a pointer to where the full notice is found. - - - Copyright (C) - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, see . - -Also add information on how to contact you by electronic and paper mail. - -You should also get your employer (if you work as a programmer) or your -school, if any, to sign a "copyright disclaimer" for the library, if -necessary. Here is a sample; alter the names: - - Yoyodyne, Inc., hereby disclaims all copyright interest in the - library `Frob' (a library for tweaking knobs) written by James Random Hacker. - - , 1 April 1990 - Moe Ghoul, President of Vice - -That's all there is to it! From 9a3d42e2fb9b4e3a9cbc2b210863bdcd5cea7762 Mon Sep 17 00:00:00 2001 From: TheEt1234 Date: Fri, 3 Oct 2025 19:58:23 +0200 Subject: [PATCH 10/28] Submodules experiment #03 --- .gitmodules | 15 + mods/fakelib | 1 + mods/fakelib/.gitattributes | 6 - mods/fakelib/.github/workflows/luacheck.yml | 10 - mods/fakelib/API.md | 137 ----- mods/fakelib/LICENSE | 21 - mods/fakelib/README.md | 26 - mods/fakelib/init.lua | 53 -- mods/fakelib/inventory.lua | 301 ----------- mods/fakelib/metadata.lua | 134 ----- mods/fakelib/misc.lua | 10 - mods/fakelib/mod.conf | 3 - mods/fakelib/player.lua | 496 ------------------ mods/fakelib/tests.lua | 324 ------------ mods/libox | 1 + mods/libox/.github/workflows/luacheck.yml | 34 -- mods/libox/LICENSE.md | 170 ------ mods/libox/README.md | 39 -- mods/libox/api.md | 150 ------ mods/libox/autohook/.gitignore | 6 - .../autohook/.xmake/linux/x86_64/cache/config | 9 - .../.xmake/linux/x86_64/cache/cxxmodules | 1 - .../autohook/.xmake/linux/x86_64/cache/detect | 355 ------------- .../.xmake/linux/x86_64/cache/history | 19 - .../autohook/.xmake/linux/x86_64/cache/option | 1 - .../.xmake/linux/x86_64/cache/package | 23 - .../.xmake/linux/x86_64/cache/project | 1 - .../.xmake/linux/x86_64/cache/references | 3 - .../.xmake/linux/x86_64/cache/repository | 12 - .../.xmake/linux/x86_64/cache/toolchain | 133 ----- .../autohook/.xmake/linux/x86_64/project.lock | 0 .../autohook/.xmake/linux/x86_64/xmake.conf | 26 - mods/libox/autohook/README.md | 98 ---- mods/libox/autohook/autohook.c | 191 ------- mods/libox/autohook/autohook.h | 3 - mods/libox/autohook/autohook.h.in | 6 - .../5a/5a0144f26e0ed456ec3c30593cb46ff4 | Bin 1256 -> 0 bytes .../9e/9e19e71a9cd69ef70589b2dd347fcfee | Bin 9248 -> 0 bytes .../9e/9e19e71a9cd69ef70589b2dd347fcfee.txt | 14 - .../ad/addd798cbb6e56df5c2e6a9cb4a13da6 | Bin 17288 -> 0 bytes .../ad/addd798cbb6e56df5c2e6a9cb4a13da6.txt | 14 - .../cd/cdd7dc4994587146ed446897d780874d | Bin 1536 -> 0 bytes .../cd/cdd7dc4994587146ed446897d780874d.txt | 14 - .../linux/x86_64/release/autohook.c.o.d | 35 -- .../linux/x86_64/release/autohook.h.in.d | 5 - .../linux/x86_64/release/libautohook.so.d | 15 - .../autohook/linux/x86_64/release/utils.c.o.d | 35 -- .../linux/x86_64/release/autohook.c.o | Bin 17288 -> 0 bytes .../autohook/linux/x86_64/release/utils.c.o | Bin 9248 -> 0 bytes mods/libox/autohook/hash.ps1 | 15 - mods/libox/autohook/hash.sh | 5 - mods/libox/autohook/helpers.lua | 42 -- mods/libox/autohook/libautohook.so | Bin 25944 -> 0 bytes mods/libox/autohook/module-version.txt | 1 - mods/libox/autohook/utils.c | 179 ------- mods/libox/autohook/xmake.lua | 119 ----- mods/libox/coroutine.lua | 364 ------------- mods/libox/env.lua | 292 ----------- mods/libox/env_docs.md | 99 ---- mods/libox/init.lua | 82 --- mods/libox/main.lua | 18 - mods/libox/mod.conf | 6 - mods/libox/normal.lua | 51 -- mods/libox/pat.lua | 484 ----------------- mods/libox/settingtypes.txt | 24 - mods/libox/test/basic_testing.lua | 81 --- mods/libox/test/coroutine.test.lua | 273 ---------- mods/libox/test/normal.test.lua | 227 -------- mods/libox/utils.lua | 282 ---------- mods/player_api | 1 + mods/player_api/README.txt | 27 - mods/player_api/api.lua | 239 --------- mods/player_api/init.lua | 26 - mods/player_api/license.txt | 60 --- mods/player_api/mod.conf | 2 - mods/player_api/models/character.b3d | Bin 73433 -> 0 bytes mods/player_api/models/character.blend | Bin 632100 -> 0 bytes mods/player_api/models/character.png | Bin 2754 -> 0 bytes mods/player_api/textures/player.png | Bin 142 -> 0 bytes mods/player_api/textures/player_back.png | Bin 140 -> 0 bytes mods/sethome | 1 + mods/sethome/README.txt | 7 - mods/sethome/init.lua | 114 ---- mods/sethome/license.txt | 24 - mods/sethome/locale/sethome.de.tr | 9 - mods/sethome/locale/sethome.eo.tr | 9 - mods/sethome/locale/sethome.es.tr | 9 - mods/sethome/locale/sethome.fr.tr | 9 - mods/sethome/locale/sethome.id.tr | 9 - mods/sethome/locale/sethome.it.tr | 9 - mods/sethome/locale/sethome.ja.tr | 9 - mods/sethome/locale/sethome.jbo.tr | 9 - mods/sethome/locale/sethome.ms.tr | 9 - mods/sethome/locale/sethome.pl.tr | 9 - mods/sethome/locale/sethome.pt_BR.tr | 9 - mods/sethome/locale/sethome.ru.tr | 9 - mods/sethome/locale/sethome.sk.tr | 9 - mods/sethome/locale/sethome.sv.tr | 9 - mods/sethome/locale/sethome.uk.tr | 9 - mods/sethome/locale/sethome.zh_CN.tr | 9 - mods/sethome/locale/sethome.zh_TW.tr | 9 - mods/sethome/locale/template.txt | 9 - mods/sethome/mod.conf | 2 - mods/unified_inventory_plus | 1 + .../.github/workflows/luacheck.yml | 10 - mods/unified_inventory_plus/LICENSE | 168 ------ mods/unified_inventory_plus/MEDIA_LICENSE.txt | 121 ----- mods/unified_inventory_plus/README.md | 45 -- mods/unified_inventory_plus/craft_all.lua | 150 ------ mods/unified_inventory_plus/craft_clear.lua | 43 -- .../unified_inventory_plus/craft_organize.lua | 170 ------ mods/unified_inventory_plus/craft_rotate.lua | 52 -- mods/unified_inventory_plus/init.lua | 57 -- mods/unified_inventory_plus/mod.conf | 4 - mods/unified_inventory_plus/settings.lua | 11 - mods/unified_inventory_plus/settingtypes.txt | 8 - .../textures/pattern_1.png | Bin 116 -> 0 bytes .../textures/pattern_3.png | Bin 117 -> 0 bytes .../textures/pattern_3b.png | Bin 116 -> 0 bytes .../textures/pattern_4.png | Bin 118 -> 0 bytes .../textures/pattern_5.png | Bin 120 -> 0 bytes .../textures/pattern_6.png | Bin 119 -> 0 bytes .../textures/pattern_6b.png | Bin 117 -> 0 bytes .../textures/pattern_6c.png | Bin 116 -> 0 bytes .../textures/pattern_7.png | Bin 119 -> 0 bytes .../textures/pattern_8.png | Bin 120 -> 0 bytes .../textures/pattern_9.png | Bin 113 -> 0 bytes .../textures/pattern_clear.png | Bin 391 -> 0 bytes .../textures/pattern_rotate.png | Bin 900 -> 0 bytes .../textures/pattern_rotate2.png | Bin 343 -> 0 bytes .../textures/ui_crafting_long_arrow.png | Bin 1419 -> 0 bytes 131 files changed, 20 insertions(+), 7079 deletions(-) create mode 160000 mods/fakelib delete mode 100644 mods/fakelib/.gitattributes delete mode 100644 mods/fakelib/.github/workflows/luacheck.yml delete mode 100644 mods/fakelib/API.md delete mode 100644 mods/fakelib/LICENSE delete mode 100644 mods/fakelib/README.md delete mode 100644 mods/fakelib/init.lua delete mode 100644 mods/fakelib/inventory.lua delete mode 100644 mods/fakelib/metadata.lua delete mode 100644 mods/fakelib/misc.lua delete mode 100644 mods/fakelib/mod.conf delete mode 100644 mods/fakelib/player.lua delete mode 100644 mods/fakelib/tests.lua create mode 160000 mods/libox delete mode 100644 mods/libox/.github/workflows/luacheck.yml delete mode 100644 mods/libox/LICENSE.md delete mode 100644 mods/libox/README.md delete mode 100644 mods/libox/api.md delete mode 100644 mods/libox/autohook/.gitignore delete mode 100644 mods/libox/autohook/.xmake/linux/x86_64/cache/config delete mode 100644 mods/libox/autohook/.xmake/linux/x86_64/cache/cxxmodules delete mode 100644 mods/libox/autohook/.xmake/linux/x86_64/cache/detect delete mode 100644 mods/libox/autohook/.xmake/linux/x86_64/cache/history delete mode 100644 mods/libox/autohook/.xmake/linux/x86_64/cache/option delete mode 100644 mods/libox/autohook/.xmake/linux/x86_64/cache/package delete mode 100644 mods/libox/autohook/.xmake/linux/x86_64/cache/project delete mode 100644 mods/libox/autohook/.xmake/linux/x86_64/cache/references delete mode 100644 mods/libox/autohook/.xmake/linux/x86_64/cache/repository delete mode 100644 mods/libox/autohook/.xmake/linux/x86_64/cache/toolchain delete mode 100644 mods/libox/autohook/.xmake/linux/x86_64/project.lock delete mode 100644 mods/libox/autohook/.xmake/linux/x86_64/xmake.conf delete mode 100644 mods/libox/autohook/README.md delete mode 100644 mods/libox/autohook/autohook.c delete mode 100644 mods/libox/autohook/autohook.h delete mode 100644 mods/libox/autohook/autohook.h.in delete mode 100644 mods/libox/autohook/build/.build_cache/5a/5a0144f26e0ed456ec3c30593cb46ff4 delete mode 100644 mods/libox/autohook/build/.build_cache/9e/9e19e71a9cd69ef70589b2dd347fcfee delete mode 100644 mods/libox/autohook/build/.build_cache/9e/9e19e71a9cd69ef70589b2dd347fcfee.txt delete mode 100644 mods/libox/autohook/build/.build_cache/ad/addd798cbb6e56df5c2e6a9cb4a13da6 delete mode 100644 mods/libox/autohook/build/.build_cache/ad/addd798cbb6e56df5c2e6a9cb4a13da6.txt delete mode 100644 mods/libox/autohook/build/.build_cache/cd/cdd7dc4994587146ed446897d780874d delete mode 100644 mods/libox/autohook/build/.build_cache/cd/cdd7dc4994587146ed446897d780874d.txt delete mode 100644 mods/libox/autohook/build/.deps/autohook/linux/x86_64/release/autohook.c.o.d delete mode 100644 mods/libox/autohook/build/.deps/autohook/linux/x86_64/release/autohook.h.in.d delete mode 100644 mods/libox/autohook/build/.deps/autohook/linux/x86_64/release/libautohook.so.d delete mode 100644 mods/libox/autohook/build/.deps/autohook/linux/x86_64/release/utils.c.o.d delete mode 100644 mods/libox/autohook/build/.objs/autohook/linux/x86_64/release/autohook.c.o delete mode 100644 mods/libox/autohook/build/.objs/autohook/linux/x86_64/release/utils.c.o delete mode 100644 mods/libox/autohook/hash.ps1 delete mode 100644 mods/libox/autohook/hash.sh delete mode 100644 mods/libox/autohook/helpers.lua delete mode 100755 mods/libox/autohook/libautohook.so delete mode 100644 mods/libox/autohook/module-version.txt delete mode 100644 mods/libox/autohook/utils.c delete mode 100644 mods/libox/autohook/xmake.lua delete mode 100644 mods/libox/coroutine.lua delete mode 100644 mods/libox/env.lua delete mode 100644 mods/libox/env_docs.md delete mode 100644 mods/libox/init.lua delete mode 100644 mods/libox/main.lua delete mode 100644 mods/libox/mod.conf delete mode 100644 mods/libox/normal.lua delete mode 100644 mods/libox/pat.lua delete mode 100644 mods/libox/settingtypes.txt delete mode 100644 mods/libox/test/basic_testing.lua delete mode 100644 mods/libox/test/coroutine.test.lua delete mode 100644 mods/libox/test/normal.test.lua delete mode 100644 mods/libox/utils.lua create mode 160000 mods/player_api delete mode 100644 mods/player_api/README.txt delete mode 100644 mods/player_api/api.lua delete mode 100644 mods/player_api/init.lua delete mode 100644 mods/player_api/license.txt delete mode 100644 mods/player_api/mod.conf delete mode 100644 mods/player_api/models/character.b3d delete mode 100644 mods/player_api/models/character.blend delete mode 100644 mods/player_api/models/character.png delete mode 100644 mods/player_api/textures/player.png delete mode 100644 mods/player_api/textures/player_back.png create mode 160000 mods/sethome delete mode 100644 mods/sethome/README.txt delete mode 100644 mods/sethome/init.lua delete mode 100644 mods/sethome/license.txt delete mode 100644 mods/sethome/locale/sethome.de.tr delete mode 100644 mods/sethome/locale/sethome.eo.tr delete mode 100644 mods/sethome/locale/sethome.es.tr delete mode 100644 mods/sethome/locale/sethome.fr.tr delete mode 100644 mods/sethome/locale/sethome.id.tr delete mode 100644 mods/sethome/locale/sethome.it.tr delete mode 100644 mods/sethome/locale/sethome.ja.tr delete mode 100644 mods/sethome/locale/sethome.jbo.tr delete mode 100644 mods/sethome/locale/sethome.ms.tr delete mode 100644 mods/sethome/locale/sethome.pl.tr delete mode 100644 mods/sethome/locale/sethome.pt_BR.tr delete mode 100644 mods/sethome/locale/sethome.ru.tr delete mode 100644 mods/sethome/locale/sethome.sk.tr delete mode 100644 mods/sethome/locale/sethome.sv.tr delete mode 100644 mods/sethome/locale/sethome.uk.tr delete mode 100644 mods/sethome/locale/sethome.zh_CN.tr delete mode 100644 mods/sethome/locale/sethome.zh_TW.tr delete mode 100644 mods/sethome/locale/template.txt delete mode 100644 mods/sethome/mod.conf create mode 160000 mods/unified_inventory_plus delete mode 100644 mods/unified_inventory_plus/.github/workflows/luacheck.yml delete mode 100644 mods/unified_inventory_plus/LICENSE delete mode 100644 mods/unified_inventory_plus/MEDIA_LICENSE.txt delete mode 100644 mods/unified_inventory_plus/README.md delete mode 100644 mods/unified_inventory_plus/craft_all.lua delete mode 100644 mods/unified_inventory_plus/craft_clear.lua delete mode 100644 mods/unified_inventory_plus/craft_organize.lua delete mode 100644 mods/unified_inventory_plus/craft_rotate.lua delete mode 100644 mods/unified_inventory_plus/init.lua delete mode 100644 mods/unified_inventory_plus/mod.conf delete mode 100644 mods/unified_inventory_plus/settings.lua delete mode 100644 mods/unified_inventory_plus/settingtypes.txt delete mode 100644 mods/unified_inventory_plus/textures/pattern_1.png delete mode 100644 mods/unified_inventory_plus/textures/pattern_3.png delete mode 100644 mods/unified_inventory_plus/textures/pattern_3b.png delete mode 100644 mods/unified_inventory_plus/textures/pattern_4.png delete mode 100644 mods/unified_inventory_plus/textures/pattern_5.png delete mode 100644 mods/unified_inventory_plus/textures/pattern_6.png delete mode 100644 mods/unified_inventory_plus/textures/pattern_6b.png delete mode 100644 mods/unified_inventory_plus/textures/pattern_6c.png delete mode 100644 mods/unified_inventory_plus/textures/pattern_7.png delete mode 100644 mods/unified_inventory_plus/textures/pattern_8.png delete mode 100644 mods/unified_inventory_plus/textures/pattern_9.png delete mode 100644 mods/unified_inventory_plus/textures/pattern_clear.png delete mode 100644 mods/unified_inventory_plus/textures/pattern_rotate.png delete mode 100644 mods/unified_inventory_plus/textures/pattern_rotate2.png delete mode 100644 mods/unified_inventory_plus/textures/ui_crafting_long_arrow.png diff --git a/.gitmodules b/.gitmodules index fdcc0588..2d3bc13b 100644 --- a/.gitmodules +++ b/.gitmodules @@ -4,3 +4,18 @@ [submodule "luanti_lsp_definitions"] path = luanti_lsp_definitions url = https://github.com/corpserot/luanti_lsp_definitions/ +[submodule "mods/unified_inventory_plus"] + path = mods/unified_inventory_plus + url = https://github.com/mt-mods/unified_inventory_plus +[submodule "mods/libox"] + path = mods/libox + url = https://github.com/TheEt1234/libox +[submodule "mods/fakelib"] + path = mods/fakelib + url = https://github.com/OgelGames/fakelib +[submodule "mods/player_api"] + path = mods/player_api + url = https://github.com/minetest-game/player_api +[submodule "mods/sethome"] + path = mods/sethome + url = https://github.com/minetest-game/sethome diff --git a/mods/fakelib b/mods/fakelib new file mode 160000 index 00000000..b565ca2c --- /dev/null +++ b/mods/fakelib @@ -0,0 +1 @@ +Subproject commit b565ca2c408d06fb4c5dc617f647f70c5b9751e8 diff --git a/mods/fakelib/.gitattributes b/mods/fakelib/.gitattributes deleted file mode 100644 index adcbd9a2..00000000 --- a/mods/fakelib/.gitattributes +++ /dev/null @@ -1,6 +0,0 @@ -# Auto detect text files and perform LF normalization -* text=auto - -# Exclusions for release export. -.* export-ignore -tests.lua export-ignore diff --git a/mods/fakelib/.github/workflows/luacheck.yml b/mods/fakelib/.github/workflows/luacheck.yml deleted file mode 100644 index 18088bce..00000000 --- a/mods/fakelib/.github/workflows/luacheck.yml +++ /dev/null @@ -1,10 +0,0 @@ -name: luacheck -on: [push, pull_request] -jobs: - luacheck: - runs-on: ubuntu-latest - steps: - - name: Checkout - uses: actions/checkout@main - - name: Luacheck - uses: lunarmodules/luacheck@master diff --git a/mods/fakelib/API.md b/mods/fakelib/API.md deleted file mode 100644 index 92d3636f..00000000 --- a/mods/fakelib/API.md +++ /dev/null @@ -1,137 +0,0 @@ -# API Documentation - -## Quick Links - -- [`fakelib.is_player(x)`](#fakelibis_playerx) -- [`fakelib.is_metadata(x)`](#fakelibis_metadatax) -- [`fakelib.is_inventory(x)`](#fakelibis_inventoryx) -- [`fakelib.is_vector(x, [add_metatable])`](#fakelibis_vectorx-add_metatable) -- [`fakelib.create_player([options])`](#fakelibcreate_playeroptions) -- [`fakelib.create_inventory([sizes])`](#fakelibcreate_inventorysizes) -- [`fakelib.create_metadata([data])`](#fakelibcreate_metadatadata) - - -## Type checks - -#### **`fakelib.is_player(x)`** - -Checks if a value is a player. Only returns true for real players and `fakelib`'s fake players. - -**Arguments** - -- `x` - Any value. The value to be checked. - -#### **`fakelib.is_inventory(x)`** - -Checks if a value is an inventory. Only returns true for real inventories and `fakelib`'s fake inventories. - -**Arguments** - -- `x` - Any value. The value to be checked. - -#### **`fakelib.is_metadata(x)`** - -Checks if a value is metadata. Only returns true for real metadata and `fakelib`'s fake metadata. - -**Arguments** - -- `x` - Any value. The value to be checked. - -#### **`fakelib.is_vector(x, [add_metatable])`** - -Checks if a value is a vector. Returns true for any table with `x`, `y`, and `z` values that are numbers. - -**Arguments** - -- `x` - Any value. The value to be checked. -- `add_metatable` - Boolean, optional. Add the vector metatable to basic vectors. - - -## Creation - -#### **`fakelib.create_player([options])`** - -Creates a new fake player. - -**Arguments** - -- `options` - Definition table, optional. Specifies player data. See [`options`](#options) below. Can also be a string as shorthand to set the player name only. - -#### **`fakelib.create_inventory([sizes])`** - -Creates a new fake player. - -**Arguments** - -- `sizes` - Definition table, optional. Specifies list names and sizes. See [`sizes`](#sizes) below. - -#### **`fakelib.create_metadata([data])`** - -Creates a new fake player. - -**Arguments** - -- `data` - Definition table, optional. Specifies metadata keys and values. See [`data`](#data) below. - - -## Definition tables. - - -#### **`options`** - -Specifies player data. Used by [`fakelib.create_player([options])`](#fakelibcreate_playeroptions). - -All values are optional. - -- `name` - String. Player name. Unlike real player names, this can contain any characters. -- `position` - Vector. Player position. -- `direction` - Vector. Player look direction. -- `controls` - Table. Player controls. Uses the same format returned by `player:get_player_controls()`. -- `metadata` - Metadata. Player metadata. Can be fake metadata or a reference to real metadata. -- `inventory` - Inventory. Player inventory. Can be a fake inventory or a reference to a real inventory. -- `wield_list` - String. Selected inventory list. Must be a list that exists in the player's inventory. -- `wield_index` - Number. Selected list index. Must be an index that exists in the selected list. - -Example: -```lua -local options = { - name = "sam", - position = vector.new(1, 5, 3), - direction = vector(1, 0, 0), - controls = {sneak = true}, -} -local player = fakelib.create_player(options) -``` - -#### **`sizes`** - -Specifies list names and sizes. Used by [`fakelib.create_inventory([sizes])`](#fakelibcreate_inventorysizes). - -List names must be strings, and list sizes must be numbers greater than zero. - -Example: -```lua -local sizes = { - main = 32, - craft = 9, - craftpreview = 1, - craftresult = 1, -} -local inv = fakelib.create_inventory(sizes) - -``` - -#### **`data`** - -Specifies metadata keys and values. Used by [`fakelib.create_metadata([data])`](#fakelibcreate_metadatadata). - -Keys must be strings, and values must be strings or numbers. - -Example: -```lua -local data = { - enabled = "true", - energy = 300, -} -local meta = fakelib.create_metadata(data) -``` \ No newline at end of file diff --git a/mods/fakelib/LICENSE b/mods/fakelib/LICENSE deleted file mode 100644 index 20046852..00000000 --- a/mods/fakelib/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -MIT License - -Copyright (c) 2024 OgelGames - -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. diff --git a/mods/fakelib/README.md b/mods/fakelib/README.md deleted file mode 100644 index eac86277..00000000 --- a/mods/fakelib/README.md +++ /dev/null @@ -1,26 +0,0 @@ -# Minetest fake userdata library [fakelib] - -[![luacheck](https://github.com/OgelGames/fakelib/workflows/luacheck/badge.svg)](https://github.com/OgelGames/fakelib/actions) -[![License](https://img.shields.io/badge/License-MIT-green.svg)](LICENSE.md) -[![Minetest](https://img.shields.io/badge/Minetest-5.0+-blue.svg)](https://www.minetest.net) -[![ContentDB](https://content.minetest.net/packages/OgelGames/fakelib/shields/downloads/)](https://content.minetest.net/packages/OgelGames/fakelib/) - -## Overview - -This mod is a code library for creating fake userdata (players, inventories and metadata), replicating their functionality as closely as possible. - -## Usage - -Simply add `fakelib` to your mod's dependencies, and call any of the API functions from your code. - -See [API.md](API.md) for detailed documentation. - -## Installation - -Download the [master branch](https://github.com/OgelGames/fakelib/archive/master.zip) or the [latest release](https://github.com/OgelGames/fakelib/releases), and follow [the usual installation steps](https://wiki.minetest.net/Installing_Mods). - -Alternatively, you can download and install the mod from [ContentDB](https://content.minetest.net/packages/OgelGames/fakelib) or the online content tab in Minetest. - -## License - -All code is licensed under the [MIT License](LICENSE). diff --git a/mods/fakelib/init.lua b/mods/fakelib/init.lua deleted file mode 100644 index ef0cf9d5..00000000 --- a/mods/fakelib/init.lua +++ /dev/null @@ -1,53 +0,0 @@ - -fakelib = {} - -local function check(n, v, a, b) - local t = type(v) - if t == a or t == b then - return v - end - local info = debug.getinfo(2, "n") - local f = info.name or "?" - if info.namewhat ~= "method" then - -- Offset argument number when called using '.' instead of ':' - n = n + 1 - end - error(string.format("bad argument #%i to '%s' (%s expected, got %s)", n, f, a, t), 3) -end - -local function secure_table(t, index, id) - setmetatable(t, { - __index = index, - __newindex = {}, - __metatable = id, - }) - return t -end - -local path = minetest.get_modpath("fakelib") - -for _,file in pairs({"metadata", "inventory", "player"}) do - loadfile(path.."/"..file..".lua")(check, secure_table) -end - -dofile(path.."/misc.lua") - --- Tests are not included in releases, so check for them before registering the command. - -local tests = loadfile(path.."/tests.lua") - -if tests and minetest.is_singleplayer() then - minetest.register_chatcommand("fakelib_test", { - description = "Test fakelib's API.", - params = "[]", - func = function(_, param) - local start_time = minetest.get_us_time() - local success = tests(param == "true") - local end_time = minetest.get_us_time() - if success then - return true, string.format("Testing completed in %i us", end_time - start_time) - end - return true, "Testing failed. See console for errors." - end, - }) -end diff --git a/mods/fakelib/inventory.lua b/mods/fakelib/inventory.lua deleted file mode 100644 index 64cfde4d..00000000 --- a/mods/fakelib/inventory.lua +++ /dev/null @@ -1,301 +0,0 @@ -local fake_inventory = {} -local identifier = "fakelib:inventory" -local check, secure_table = ... - --- API functions ----------------------------------------- - -function fakelib.is_inventory(x) - if type(x) == "userdata" and x.get_lists then - return true - elseif type(x) == "table" and getmetatable(x) == identifier then - return true - end - return false -end - -function fakelib.create_inventory(sizes) - local lists = {} - if type(sizes) == "table" then - for listname, size in pairs(sizes) do - if type(listname) == "string" and type(size) == "number" and size > 0 then - local list = {} - for i = 1, size do - list[i] = ItemStack() - end - lists[listname] = list - end - end - end - return secure_table({ lists = lists }, fake_inventory, identifier) -end - --- Helper functions ----------------------------------------- - -local function copy_list(list) - local copy = {} - for i = 1, #list do - copy[i] = ItemStack(list[i]) - end - return copy -end - -local function stack_matches(a, b, match_meta) - if a:get_name() ~= b:get_name() then - return false - end - if match_meta then - if a:get_wear() ~= b:get_wear() then - return false - end - return a:get_meta():equals(b:get_meta()) - end - return true -end - --- Inventory functions ----------------------------------------- - -function fake_inventory:is_empty(listname) - check(1, listname, "string", "number") - local list = self.lists[tostring(listname)] - if not list or #list == 0 then - return true - end - for _, stack in ipairs(list) do - if not stack:is_empty() then - return false - end - end - return true -end - -function fake_inventory:get_size(listname) - check(1, listname, "string", "number") - local list = self.lists[tostring(listname)] - return list and #list or 0 -end - -function fake_inventory:set_size(listname, size) - check(1, listname, "string", "number") - check(2, size, "number") - listname = tostring(listname) - if size ~= size or size < 0 then - return false - end - size = math.floor(size) - if size == 0 then - self.lists[listname] = nil - return true - end - local list = self.lists[listname] or {} - if #list < size then - for i = #list + 1, size do - list[i] = ItemStack() - end - elseif #list > size then - for i = size + 1, #list do - list[i] = nil - end - end - self.lists[listname] = list - return true -end - -function fake_inventory:get_width(listname) - check(1, listname, "string", "number") - local list = self.lists[tostring(listname)] - return list and list.width or 0 -end - -function fake_inventory:set_width(listname, width) - check(1, listname, "string", "number") - check(2, width, "number") - local list = self.lists[tostring(listname)] - if not list or width ~= width or width < 0 then - return false - end - width = math.floor(width) - list.width = width > 0 and width or nil - return true -end - -function fake_inventory:get_stack(listname, i) - check(1, listname, "string", "number") - check(2, i, "number") - i = math.floor(i) - local list = self.lists[tostring(listname)] - if not list or not list[i] then - return ItemStack() - end - return ItemStack(list[i]) -end - -function fake_inventory:set_stack(listname, i, stack) - check(1, listname, "string", "number") - check(2, i, "number") - stack = ItemStack(stack) - i = math.floor(i) - local list = self.lists[tostring(listname)] - if not list or not list[i] or stack:is_empty() then - return false - end - list[i] = stack - return true -end - -function fake_inventory:get_list(listname) - check(1, listname, "string", "number") - local list = self.lists[tostring(listname)] - return list and copy_list(list) or nil -end - -function fake_inventory:set_list(listname, list) - check(1, listname, "string", "number") - listname = tostring(listname) - if list == nil then - self.lists[listname] = nil - return - end - check(2, list, "table") - local new_list, size = {}, 0 - for i, s in pairs(list) do - check(4, i, "number") - if i > size then - size = i - end - new_list[i] = ItemStack(s) - end - for i = 1, size do - if not new_list[i] then - new_list[i] = ItemStack() - end - end - self.lists[listname] = new_list -end - -function fake_inventory:get_lists() - local lists = {} - for listname, list in pairs(self.lists) do - lists[listname] = copy_list(list) - end - return lists -end - -function fake_inventory:set_lists(lists) - check(1, lists, "table") - local new_lists = {} - for listname, list in pairs(lists) do - check(3, listname, "string", "number") - check(3, list, "table") - listname = tostring(listname) - local new_list, size = {}, 0 - for i, s in pairs(list) do - check(5, i, "number") - if i > size then - size = i - end - new_list[i] = ItemStack(s) - end - for i = 1, size do - if not new_list[i] then - new_list[i] = ItemStack() - end - end - new_lists[listname] = new_list - end - self.lists = new_lists -end - -function fake_inventory:add_item(listname, stack) - check(1, listname, "string", "number") - stack = ItemStack(stack) - local list = self.lists[tostring(listname)] - if not list or #list == 0 or stack:is_empty() then - return stack - end - local empty = {} - for _, s in ipairs(list) do - if s:is_empty() then - table.insert(empty, s) - else - stack = s:add_item(stack) - if stack:is_empty() then - return stack - end - end - end - for _, s in ipairs(empty) do - stack = s:add_item(stack) - if stack:is_empty() then - return stack - end - end - return stack -end - -function fake_inventory:room_for_item(listname, stack) - check(1, listname, "string", "number") - stack = ItemStack(stack) - local list = self.lists[tostring(listname)] - if not list or #list == 0 or stack:is_empty() then - return false - end - for _, s in ipairs(copy_list(list)) do - stack = s:add_item(stack) - if stack:is_empty() then - return true - end - end - return false -end - -function fake_inventory:contains_item(listname, stack, match_meta) - check(1, listname, "string", "number") - stack = ItemStack(stack) - local list = self.lists[tostring(listname)] - if not list or stack:is_empty() or stack:is_empty() then - return false - end - local count = stack:get_count() - for _, s in ipairs(list) do - if stack_matches(stack, s, match_meta) then - count = count - s:get_count() - if count <= 0 then - return true - end - end - end - return false -end - -function fake_inventory:remove_item(listname, stack) - check(1, listname, "string", "number") - stack = ItemStack(stack) - local list = self.lists[tostring(listname)] - if not list or #list == 0 or stack:is_empty() then - return ItemStack() - end - local name, remaining, removed = stack:get_name(), stack:get_count() - for i = #list, 1, -1 do - local s = list[i] - if s:get_name() == name then - s = s:take_item(remaining) - remaining = remaining - s:get_count() - if not removed then - removed = s - else - removed:set_count(removed:get_count() + s:get_count()) - end - if remaining == 0 then - break - end - end - end - return removed or ItemStack() -end - -function fake_inventory.get_location() - return { type = "undefined" } -end diff --git a/mods/fakelib/metadata.lua b/mods/fakelib/metadata.lua deleted file mode 100644 index cfcde2a1..00000000 --- a/mods/fakelib/metadata.lua +++ /dev/null @@ -1,134 +0,0 @@ - -local fake_metadata = {} -local identifier = "fakelib:metadata" -local check, secure_table = ... - --- API functions ----------------------------------------- - -function fakelib.is_metadata(x) - if type(x) == "userdata" and x.get_keys then - return true - elseif type(x) == "table" and getmetatable(x) == identifier then - return true - end - return false -end - -function fakelib.create_metadata(data) - local fields = {} - if type(data) == "table" then - for k,v in pairs(data) do - if type(k) == "string" and type(v) == "string" then - fields[k] = v - end - end - end - return secure_table({fields = fields}, fake_metadata, identifier) -end - --- Metadata functions ----------------------------------------- - -function fake_metadata:contains(key) - check(1, key, "string", "number") - key = tostring(key) - return self.fields[key] ~= nil -end - -function fake_metadata:get(key) - check(1, key, "string", "number") - key = tostring(key) - return self.fields[key] -end - -function fake_metadata:set_string(key, value) - check(1, key, "string", "number") - check(2, value, "string", "number") - key = tostring(key) - value = tostring(value) - if value == "" then - self.fields[key] = nil - end - self.fields[key] = value -end - -function fake_metadata:get_string(key) - check(1, key, "string", "number") - key = tostring(key) - return self.fields[key] or "" -end - -function fake_metadata:set_int(key, value) - check(1, key, "string", "number") - check(2, value, "number") - key = tostring(key) - if value >= 2^31 then - value = 0 - end - self.fields[key] = string.format("%i", value) -end - -function fake_metadata:get_int(key) - check(1, key, "string", "number") - key = tostring(key) - return tonumber(self.fields[key]) or 0 -end - -function fake_metadata:set_float(key, value) - check(1, key, "string", "number") - check(2, value, "number") - key = tostring(key) - self.fields[key] = string.format("%s", value) -end - -function fake_metadata:get_float(key) - check(1, key, "string", "number") - key = tostring(key) - return tonumber(self.fields[key]) or 0 -end - -function fake_metadata:get_keys() - local keys = {} - for key in pairs(self.fields) do - table.insert(keys, key) - end - return keys -end - -function fake_metadata:to_table() - return {fields = table.copy(self.fields)} -end - -function fake_metadata:from_table(data) - if type(data) ~= "table" or type(data.fields) ~= "table" then - self.fields = {} - return true - end - local fields = {} - for k,v in pairs(data.fields) do - check(4, k, "string") - check(5, v, "string", "number") - fields[k] = tostring(v) - end - self.fields = fields - return true -end - -function fake_metadata:equals(other) - if not fakelib.is_metadata(other) then - check(1, other, "MetaDataRef") - end - local fields = other:to_table().fields - for k,v in pairs(self.fields) do - if fields[k] == v then - fields[k] = nil - elseif fields[k] ~= nil then - return false - end - end - if next(fields) == nil then - return true - end - return false -end diff --git a/mods/fakelib/misc.lua b/mods/fakelib/misc.lua deleted file mode 100644 index ece4c528..00000000 --- a/mods/fakelib/misc.lua +++ /dev/null @@ -1,10 +0,0 @@ - -function fakelib.is_vector(x, add_metatable) - if type(x) ~= "table" or type(x.x) ~= "number" or type(x.y) ~= "number" or type(x.z) ~= "number" then - return false - end - if add_metatable and getmetatable(x) ~= vector.metatable then - setmetatable(x, vector.metatable) - end - return true -end diff --git a/mods/fakelib/mod.conf b/mods/fakelib/mod.conf deleted file mode 100644 index 19784a68..00000000 --- a/mods/fakelib/mod.conf +++ /dev/null @@ -1,3 +0,0 @@ -name = fakelib -description = Minetest fake userdata library -min_minetest_version = 5.0 diff --git a/mods/fakelib/player.lua b/mods/fakelib/player.lua deleted file mode 100644 index 28e816ce..00000000 --- a/mods/fakelib/player.lua +++ /dev/null @@ -1,496 +0,0 @@ - -local fake_player = {is_fake_player = true} -local identifier = "fakelib:player" -local check, secure_table = ... - -local player_controls = { - up = 1, down = 2, left = 4, right = 8, jump = 16, - aux1 = 32, sneak = 64, dig = 128, place = 256, zoom = 512, -} - --- API functions ----------------------------------------- - -function fakelib.is_player(x) - if type(x) == "userdata" and x.is_player and x:is_player() then - return true - elseif type(x) == "table" and getmetatable(x) == identifier then - return true - end - return false -end - -function fakelib.create_player(options) - local data = {} - if type(options) == "table" then - if type(options.name) == "string" then - data.name = options.name - end - if fakelib.is_vector(options.position) then - data.position = vector.copy(options.position) - end - if fakelib.is_vector(options.direction) then - local dir = vector.normalize(options.direction) - data.pitch = -math.asin(dir.y) - data.yaw = math.atan2(-dir.x, dir.z) % (math.pi * 2) - end - if type(options.controls) == "table" then - data.controls = {} - for name in pairs(player_controls) do - data.controls[name] = options.controls[name] == true - end - data.controls.dig = data.controls.dig or options.controls.LMB - data.controls.place = data.controls.place or options.controls.RMB - end - if fakelib.is_metadata(options.metadata) then - data.metadata = options.metadata - end - if fakelib.is_inventory(options.inventory) then - data.inventory = options.inventory - end - local size = 32 - if data.inventory and type(options.wield_list) == "string" then - size = data.inventory:get_size(options.wield_list) - if size > 0 then - data.wield_list = options.wield_list - end - end - if type(options.wield_index) == "number" then - if options.wield_index > 0 and options.wield_index <= size then - data.wield_index = options.wield_index - end - end - elseif type(options) == "string" then - data.name = options - end - return secure_table({data = data}, fake_player, identifier) -end - --- Helper functions ----------------------------------------- - -local function check_vector(v) - local t = type(v) - if t ~= "table" then - error(string.format("\"Invalid vector (expected table got %s).\"", t), 3) - end - for _,c in ipairs({"x", "y", "z"}) do - t = type(v[c]) - if t ~= "number" then - error(string.format("\"Invalid vector coordinate %s (expected number got %s).\"", c, t), 3) - end - end -end - --- Dynamic get/set functions ----------------------------------------- - -function fake_player:get_player_name() - return self.data.name or "" -end - -function fake_player:get_inventory() - if not self.data.inventory then - self.data.inventory = fakelib.create_inventory({ - main = 32, craft = 9, craftpreview = 1, craftresult = 1 - }) - end - return self.data.inventory -end - -function fake_player:get_meta() - if not self.data.metadata then - self.data.metadata = fakelib:create_metadata() - end - return self.data.metadata -end - -function fake_player:get_look_dir() - local p, y = self.data.pitch or 0, self.data.yaw or 0 - return vector.new(math.sin(-y) * math.cos(p), math.sin(-p), math.cos(y) * math.cos(p)) -end - -function fake_player:get_look_horizontal() - return self.data.yaw or 0 -end - -function fake_player:set_look_horizontal(value) - check(1, value, "number") - self.data.yaw = value % (math.pi * 2) -end - -function fake_player:get_look_vertical() - return self.data.pitch or 0 -end - -function fake_player:set_look_vertical(value) - check(1, value, "number") - self.data.pitch = math.max(-math.pi / 2, math.min(value, math.pi / 2)) -end - -function fake_player:get_player_control() - local controls = {} - if self.data.controls then - for name in pairs(player_controls) do - controls[name] = self.data.controls[name] - end - else - for name in pairs(player_controls) do - controls[name] = false - end - end - controls.LMB = controls.dig - controls.RMB = controls.place - return controls -end - -function fake_player:get_player_control_bits() - if not self.data.controls then - return 0 - end - local total = 0 - for name, value in pairs(player_controls) do - total = total + self.data.controls[name] and value or 0 - end - return total -end - -function fake_player:get_pos() - if self.data.position then - return vector.copy(self.data.position) - end - return vector.zero() -end - -function fake_player:set_pos(pos) - check_vector(pos) - self.data.position = vector.copy(pos) -end -fake_player.move_to = fake_player.set_pos - -function fake_player:add_pos(pos) - check_vector(pos) - if self.data.position then - self.data.position = vector.add(self.data.position, pos) - else - self.data.position = vector.copy(pos) - end -end - -function fake_player:get_wield_index() - return self.data.wield_index or 1 -end - -function fake_player:get_wield_list() - return self.data.wield_list or "main" -end - -function fake_player:get_wielded_item() - if self.data.inventory then - return self.data.inventory:get_stack(self:get_wield_list(), self:get_wield_index()) - end - return ItemStack() -end - -function fake_player:set_wielded_item(stack) - stack = ItemStack(stack) - if not self.data.inventory and stack:is_empty() then - return true - end - self:get_inventory():set_stack(self:get_wield_list(), self:get_wield_index(), stack) - return true -end - --- Static get functions ----------------------------------------- - -function fake_player.is_player() - return true -end - -function fake_player.get_animation() - return {x = 1, y = 1}, 15, 0, true -end - -function fake_player.get_armor_groups() - return {immortal = 1} -end - -function fake_player.get_bone_override() - return { - position = {absolute = false, vec = vector.zero(), interpolation = 0}, - rotation = {absolute = false, vec = vector.zero(), interpolation = 0}, - scale = {absolute = false, vec = vector.new(1, 1, 1), interpolation = 0}, - } -end - -function fake_player.get_bone_overrides() - return {} -end - -function fake_player.get_bone_position() - return vector.zero(), vector.zero() -end - -function fake_player.get_breath() - return 10 -end - -function fake_player.get_children() - return {} -end - -function fake_player.get_clouds() - return { - ambient = {r = 0, g = 0, b = 0, a = 255}, - color = {r = 240, g = 240, b = 255, a = 229}, - density = 0.4, - height = 120, - speed = {x = 0, y = -2}, - thickness = 16, - } -end - -function fake_player.get_eye_offset() - return vector.zero(), vector.zero(), vector.zero() -end - -function fake_player.get_formspec_prepend() - return "" -end - -function fake_player.get_fov() - return 0, false, 0 -end - -function fake_player.get_hp() - return 20 -end - -function fake_player.get_inventory_formspec() - return "" -end - -function fake_player.get_lighting() - return { - exposure = { - speed_bright_dark = 1000, - center_weight_power = 1, - luminance_min = -3, - luminance_max = -3, - exposure_correction = 0, - speed_dark_bright = 1000 - }, - saturation = 1, - shadows = {intensity = 0}, - volumetric_light = {strength = 0}, - } -end - -function fake_player.get_local_animation() - return {x = 0, y = 0}, {x = 0, y = 0}, {x = 0, y = 0}, {x = 0, y = 0}, 0 -end - -function fake_player.get_moon() - return { - scale = 1, - texture = "moon.png", - tonemap = "moon_tonemap.png", - visible = true, - } -end - -function fake_player.get_nametag_attributes() - return { - bgcolor = false, - color = {r = 255, g = 255, b = 255, a = 255}, - text = "", - } -end - -function fake_player.get_physics_override() - return { - acceleration_air = 1, acceleration_default = 1, acceleration_fast = 1, - gravity = 1, jump = 1, speed = 1, - liquid_fluidity = 1, liquid_fluidity_smooth = 1, liquid_sink = 1, - speed_climb = 1, speed_crouch = 1, speed_fast = 1, speed_walk = 1, - new_move = true, sneak = true, sneak_glitch = false, - } -end - -function fake_player.get_properties() - return { - automatic_face_movement_dir = false, - automatic_face_movement_max_rotation_per_sec = -1, - automatic_rotate = 0, - backface_culling = false, - breath_max = 10, - collide_with_objects = true, - collisionbox = {-0.5, -0.5, -0.5, 0.5, 0.5, 0.5}, - colors = {{r = 255, g = 255, b = 255, a = 255}}, - damage_texture_modifier = "^[brighten", - eye_height = 0, - glow = 0, - hp_max = 20, - infotext = "", - initial_sprite_basepos = {x = 0, y = 0}, - is_visible = true, - makes_footstep_sound = true, - mesh = "", - nametag = "", - nametag_bgcolor = false, - nametag_color = {r = 255, g = 255, b = 255, a = 255}, - physical = false, - pointable = true, - selectionbox = {-0.5, -0.5, -0.5, 0.5, 0.5, 0.5, rotate = false}, - shaded = true, - show_on_minimap = true, - spritediv = {x = 1, y = 1}, - static_save = true, - stepheight = 0.6, - textures = {"blank.png"}, - use_texture_alpha = false, - visual = "cube", - visual_size = vector.new(1, 1, 1), - wield_item = "", - zoom_fov = 15, - } -end - -function fake_player.get_sky_color() - return fake_player.get_sky(true).sky_color -end - -function fake_player.get_sky(as_table) - if as_table then - return { - base_color = {r = 255, g = 255, b = 255, a = 255}, - clouds = true, - fog = {fog_distance = -1, fog_start = -1}, - sky_color = { - day_sky = {r = 97, g = 181, b = 245, a = 255}, - day_horizon = {r = 144, g = 211, b = 246, a = 255}, - dawn_sky = {r = 180, g = 186, b = 250, a = 255}, - dawn_horizon = {r = 186, g = 193, b = 240, a = 255}, - night_sky = {r = 0, g = 107, b = 255, a = 255}, - night_horizon = {r = 64, g = 144, b = 255, a = 255}, - indoors = {r = 100, g = 100, b = 100, a = 255}, - fog_sun_tint = {r = 244, g = 125, b = 29, a = 255}, - fog_moon_tint = {r = 128, g = 153, b = 204, a = 255}, - fog_tint_type = "default", - }, - textures = {}, - type = "regular", - } - end - return {r = 255, g = 255, b = 255, a = 255}, "regular", {}, true -end - -function fake_player.get_stars() - return { - count = 1000, - day_opacity = 0, - scale = 1, - star_color = {r = 235, g = 235, b = 255, a = 105}, - visible = true, - } -end - -function fake_player.get_sun() - return { - scale = 1, - sunrise = "sunrisebg.png", - sunrise_visible = true, - texture = "sun.png", - tonemap = "sun_tonemap.png", - visible = true, - } -end - -function fake_player.get_velocity() - return vector.zero() -end - -function fake_player.hud_get_all() - return {} -end - -function fake_player.hud_get_flags() - return { - basic_debug = false, - breathbar = false, - chat = false, - crosshair = false, - healthbar = false, - hotbar = false, - minimap = false, - minimap_radar = false, - wielditem = false, - } -end - -function fake_player.hud_get_hotbar_image() - return "" -end - -function fake_player.hud_get_hotbar_itemcount() - return 8 -end - -function fake_player.hud_get_hotbar_selected_image() - return "" -end - -function fake_player.is_valid() - return true -end - --- No-op functions ----------------------------------------- -do - local functions = { - -- Lua entity only (no-op for players) - "get_acceleration", "get_entity_name", "get_luaentity", "get_rotation", - "get_texture_mod", "get_yaw", "getacceleration", "getyaw", "remove", - "set_acceleration", "set_rotation", "set_sprite", "set_texture_mod", - "set_velocity", "set_yaw", "setacceleration", "setsprite", - "settexturemod", "setvelocity", "setyaw", - -- Non-functional get/set functions - "add_velocity", "get_attach", "get_attribute", "get_day_night_ratio", - "hud_add", "hud_change", "hud_get", "hud_remove", "hud_set_flags", - "hud_set_hotbar_image", "hud_set_hotbar_itemcount", - "hud_set_hotbar_selected_image", "override_day_night_ratio", - "set_animation", "set_animation_frame_speed", "set_armor_groups", - "set_attach", "set_attribute", "set_bone_override", "set_bone_position", - "set_breath", "set_clouds", "set_detach", "set_eye_offset", - "set_formspec_prepend", "set_fov", "set_hp", "set_inventory_formspec", - "set_lighting", "set_local_animation", "set_minimap_modes", "set_moon", - "set_nametag_attributes", "set_physics_override", - "set_properties", "set_sky", "set_stars", "set_sun", - -- Other functions that do nothing - "punch", "respawn", "right_click", "send_mapblock", - } - for _,func in ipairs(functions) do - fake_player[func] = function() end - end -end - --- Deprecated functions ----------------------------------------- - -function fake_player:get_look_pitch() - return self:get_look_vertical() * -1 -end - -function fake_player:get_look_yaw() - return self:get_look_horizontal() + math.pi / 2 -end - -fake_player.set_look_pitch = fake_player.set_look_vertical -fake_player.set_look_yaw = fake_player.set_look_horizontal -fake_player.getpos = fake_player.get_pos -fake_player.setpos = fake_player.set_pos -fake_player.moveto = fake_player.set_pos -fake_player.getvelocity = fake_player.get_velocity -fake_player.add_player_velocity = fake_player.add_velocity -fake_player.get_player_velocity = fake_player.get_velocity diff --git a/mods/fakelib/tests.lua b/mods/fakelib/tests.lua deleted file mode 100644 index ef163b6c..00000000 --- a/mods/fakelib/tests.lua +++ /dev/null @@ -1,324 +0,0 @@ - -local error_tests = ... -local success = true - --- Helper functions ------------------------------- - -local function round(x) - if x >= 0 then - return math.floor(x + 0.5) - end - return math.ceil(x - 0.5) -end - -local function is_equal(a, b) - local ta, tb = type(a), type(b) - -- Compare table values recursively - if ta == "table" and tb == "table" then - if next(a) == nil and next(b) == nil then - return true - end - local keys = {} - for k in pairs(a) do - keys[k] = true - end - for k in pairs(b) do - keys[k] = true - end - for k in pairs(keys) do - if not is_equal(a[k], b[k]) then - return false - end - end - return true - end - -- Get rid of floating point errors - if ta == "number" and tb == "number" then - a = round(a * 1000) / 1000 - b = round(b * 1000) / 1000 - end - return a == b -end - -local function test(real, fake, func, ...) - local rvals_real = {pcall(real[func], real, ...)} - local rvals_fake = {pcall(fake[func], fake, ...)} - local i = 1 - while true do - if rvals_real[i] == nil and rvals_fake[i] == nil then - break - end - if not is_equal(rvals_real[i], rvals_fake[i]) then - success = false - print(string.format("[fakelib] Test failed with function '%s' and return value #%i", func, i-1)) - if #{...} > 0 then - print(" > Function arguments: ", ...) - end - local a = type(rvals_real[i]) == "table" and dump(rvals_real[i]) or tostring(rvals_real[i]) - print(string.format(" > Real return value: %s", a)) - local b = type(rvals_fake[i]) == "table" and dump(rvals_fake[i]) or tostring(rvals_fake[i]) - print(string.format(" > Fake return value: %s", b)) - end - i = i + 1 - end -end - -local test_values = {"abc", "", 0, -1, {}, {true}, true, function() end, 0/0, nil} - -local function iter_values() - local i = 0 - return function () - i = i + 1 - if i <= 1 then return test_values[i] end - end -end - --- Player tests ------------------------------- - -local real_player = minetest.get_player_by_name("singleplayer") -local fake_player = fakelib.create_player("singleplayer") - --- Type check -if not fakelib.is_player(real_player) then - success = false - print("[fakelib] Real player is not a player.") -end -if not fakelib.is_player(fake_player) then - success = false - print("[fakelib] Fake player is not a player.") -end -for value in iter_values() do - if fakelib.is_player(value) then - print(string.format("[fakelib] Value '%s' is a player.", tostring(value))) - end -end - --- Function check -for func in pairs(getmetatable(real_player)) do - if not fake_player[func] then - success = false - print(string.format("[fakelib] Missing function '%s'", func)) - end -end - --- Functional tests -test(real_player, fake_player, "get_player_name") -test(real_player, fake_player, "get_player_control") -test(real_player, fake_player, "get_player_control_bits") -test(real_player, fake_player, "set_pos", vector.zero()) -test(real_player, fake_player, "add_pos", vector.new(1, 1, 1)) -test(real_player, fake_player, "get_pos") -test(real_player, fake_player, "set_look_horizontal", 0.6) -test(real_player, fake_player, "set_look_vertical", 0.3) -test(real_player, fake_player, "get_look_dir") -test(real_player, fake_player, "get_look_horizontal") -test(real_player, fake_player, "get_look_pitch") -test(real_player, fake_player, "get_look_yaw") -test(real_player, fake_player, "set_wielded_item", ItemStack("air 99")) -test(real_player, fake_player, "get_wielded_item") - --- Error tests -if error_tests then - for value in iter_values() do - -- Only test dynamic functions, no-op functions don't check arguments - test(real_player, fake_player, "set_pos", value) - test(real_player, fake_player, "add_pos", value) - test(real_player, fake_player, "set_look_horizontal", value) - test(real_player, fake_player, "set_look_vertical", value) - test(real_player, fake_player, "set_wielded_item", value) - end -end - --- Inventory tests ------------------------------- - -local real_inv = real_player:get_inventory() -local fake_inv = fakelib.create_inventory() - --- Type check -if not fakelib.is_inventory(real_inv) then - success = false - print("[fakelib] Real inventory is not an inventory.") -end -if not fakelib.is_inventory(fake_inv) then - success = false - print("[fakelib] Fake inventory is not an inventory.") -end -for value in iter_values() do - if fakelib.is_inventory(value) then - print(string.format("[fakelib] Value '%s' is an inventory.", tostring(value))) - end -end - --- Function check -for func in pairs(getmetatable(real_inv)) do - if not fake_inv[func] then - success = false - print(string.format("[fakelib] Missing function '%s'", func)) - end -end - --- Save and clear -local old_inv = real_inv:get_lists() -real_inv:set_lists({}) - -local test_item = ItemStack({name = "air", meta = {test = "abc"}}) -local test_list = {"", "air 50", test_item, "", "air 50", test_item} - --- Functional tests -test(real_inv, fake_inv, "set_list", "test", test_list) -test(real_inv, fake_inv, "is_empty", "test") -test(real_inv, fake_inv, "set_lists", {test = test_list}) -test(real_inv, fake_inv, "set_size", "test", 10) -test(real_inv, fake_inv, "get_size", "test") -test(real_inv, fake_inv, "set_width", "test", 3) -test(real_inv, fake_inv, "get_width", "test") -test(real_inv, fake_inv, "set_stack", "test", 1.5, "air") -test(real_inv, fake_inv, "get_stack", "test", 1) -test(real_inv, fake_inv, "get_list", "test") -test(real_inv, fake_inv, "add_item", "test", "air") -test(real_inv, fake_inv, "room_for_item", "test", "air 99") -test(real_inv, fake_inv, "contains_item", "test", "air 99") -test(real_inv, fake_inv, "contains_item", "test", test_item, true) -test(real_inv, fake_inv, "remove_item", "test", "air 99") -test(real_inv, fake_inv, "get_lists") - --- Error tests -if error_tests then - for value in iter_values() do - test(real_inv, fake_inv, "set_list", value, {}) - test(real_inv, fake_inv, "set_list", "test", value) - test(real_inv, fake_inv, "is_empty", value) - test(real_inv, fake_inv, "set_lists", value) - test(real_inv, fake_inv, "set_size", value, 1) - test(real_inv, fake_inv, "set_size", "test", value) - test(real_inv, fake_inv, "get_size", value) - test(real_inv, fake_inv, "set_width", value, 1) - test(real_inv, fake_inv, "set_width", "test", value) - test(real_inv, fake_inv, "get_width", value) - test(real_inv, fake_inv, "set_stack", value, 1, "test") - test(real_inv, fake_inv, "set_stack", "test", value, "test") - test(real_inv, fake_inv, "set_stack", "test", 1, value) - test(real_inv, fake_inv, "get_stack", value, 1) - test(real_inv, fake_inv, "get_stack", "test", value) - test(real_inv, fake_inv, "get_list", value) - test(real_inv, fake_inv, "add_item", value, "test") - test(real_inv, fake_inv, "add_item", "test", value) - test(real_inv, fake_inv, "room_for_item", value, "test") - test(real_inv, fake_inv, "room_for_item", "test", value) - test(real_inv, fake_inv, "contains_item", value, "test") - test(real_inv, fake_inv, "contains_item", "test", value) - test(real_inv, fake_inv, "contains_item", "test", "test", value) - test(real_inv, fake_inv, "remove_item", value, "test") - test(real_inv, fake_inv, "remove_item", "test", value) - end -end - --- Reset -real_inv:set_lists(old_inv) - - --- Metadata tests ------------------------------- - -local real_meta = real_player:get_meta() -local fake_meta = fakelib.create_metadata() - --- Type check -if not fakelib.is_metadata(real_meta) then - success = false - print("[fakelib] Real metadata is not metadata.") -end -if not fakelib.is_metadata(fake_meta) then - success = false - print("[fakelib] Fake metadata is not metadata.") -end -for value in iter_values() do - if fakelib.is_metadata(value) then - print(string.format("[fakelib] Value '%s' is metadata.", tostring(value))) - end -end - --- Function check -for func in pairs(getmetatable(real_meta)) do - if not fake_meta[func] then - success = false - print(string.format("[fakelib] Missing function '%s'", func)) - end -end - --- Save and clear -local old_meta = real_meta:to_table() -real_meta:from_table({}) - -local test_data = {fields = {test = "abc"}} - --- Functional tests -test(real_meta, fake_meta, "from_table", test_data) -test(real_meta, fake_meta, "contains", "test") -test(real_meta, fake_meta, "get", "test") -test(real_meta, fake_meta, "set_string", "test", "xyz") -test(real_meta, fake_meta, "get_string", "test") -test(real_meta, fake_meta, "set_int", "test", 123) -test(real_meta, fake_meta, "get_int", "test") -test(real_meta, fake_meta, "set_float", "test", 123.456789) -test(real_meta, fake_meta, "get_float", "test") -test(real_meta, fake_meta, "get_keys") -test(real_meta, fake_meta, "to_table") -test(real_meta, fake_meta, "equals", real_meta) - --- Error tests -if error_tests then - for value in iter_values() do - test(real_meta, fake_meta, "from_table", value) - test(real_meta, fake_meta, "contains", value) - test(real_meta, fake_meta, "get", value) - test(real_meta, fake_meta, "set_string", value, "test") - test(real_meta, fake_meta, "set_string", "test", value) - test(real_meta, fake_meta, "get_string", value) - test(real_meta, fake_meta, "set_int", value, 0) - test(real_meta, fake_meta, "set_int", "test", value) - test(real_meta, fake_meta, "get_int", value) - test(real_meta, fake_meta, "set_float", value, 0) - test(real_meta, fake_meta, "set_float", "test", value) - test(real_meta, fake_meta, "get_float", value) - test(real_meta, fake_meta, "equals", value) - end -end - --- Reset -real_meta:from_table(old_meta) - - --- Misc tests ------------------------------- - -local basic_vector = {x = 1, y = 1, z = 1} - --- Vector type check -if not fakelib.is_vector({x = 1, y = 1, z = 1}) then - success = false - print("[fakelib] Basic vector is not a vector.") -end -if not fakelib.is_vector(vector.new(1, 1, 1)) then - success = false - print("[fakelib] Vector is not a vector.") -end -for value in iter_values() do - if fakelib.is_vector(value) then - print(string.format("[fakelib] Value '%s' is a vector.", tostring(value))) - end -end - --- Vector metatable -if fakelib.is_vector(basic_vector, true) then - if not basic_vector.add then - print("[fakelib] Failed to add vector metatable to basic vector.") - end -end - ------------------------------- - -return success diff --git a/mods/libox b/mods/libox new file mode 160000 index 00000000..4cd98f7b --- /dev/null +++ b/mods/libox @@ -0,0 +1 @@ +Subproject commit 4cd98f7b262b32d03dba7d59e62fefa65b036b5d diff --git a/mods/libox/.github/workflows/luacheck.yml b/mods/libox/.github/workflows/luacheck.yml deleted file mode 100644 index 26f8e1fb..00000000 --- a/mods/libox/.github/workflows/luacheck.yml +++ /dev/null @@ -1,34 +0,0 @@ -# The MIT License (MIT) -# -# Copyright (c) 2024 mt-mods -# -# 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. - - - -name: luacheck -on: [push, pull_request] -jobs: - luacheck: - runs-on: ubuntu-latest - steps: - - name: Checkout - uses: actions/checkout@main - - name: Luacheck - uses: lunarmodules/luacheck@master \ No newline at end of file diff --git a/mods/libox/LICENSE.md b/mods/libox/LICENSE.md deleted file mode 100644 index 4be85568..00000000 --- a/mods/libox/LICENSE.md +++ /dev/null @@ -1,170 +0,0 @@ - -pat.lua is licensed under the MIT license, see pat.lua for the license itself - -github/workflows/luacheck.yml is licensed under the MIT license, see the file for the license itself - -path shortening is in utils.lua, licensed under the MIT license, see utils.lua for the license itself - -os.date is in env.lua, the code for that was made by OgelGames (in the mooncontroller project), licensed under LGPLv3 (see below for the copy of the lgplv3 license) - -The LGPLv3 applies to all code (unless a different license is mentioned) in this project. - -============================= - -# GNU LESSER GENERAL PUBLIC LICENSE - -Version 3, 29 June 2007 - -Copyright (C) 2007 Free Software Foundation, Inc. - - -Everyone is permitted to copy and distribute verbatim copies of this -license document, but changing it is not allowed. - -This version of the GNU Lesser General Public License incorporates the -terms and conditions of version 3 of the GNU General Public License, -supplemented by the additional permissions listed below. - -## 0. Additional Definitions. - -As used herein, "this License" refers to version 3 of the GNU Lesser -General Public License, and the "GNU GPL" refers to version 3 of the -GNU General Public License. - -"The Library" refers to a covered work governed by this License, other -than an Application or a Combined Work as defined below. - -An "Application" is any work that makes use of an interface provided -by the Library, but which is not otherwise based on the Library. -Defining a subclass of a class defined by the Library is deemed a mode -of using an interface provided by the Library. - -A "Combined Work" is a work produced by combining or linking an -Application with the Library. The particular version of the Library -with which the Combined Work was made is also called the "Linked -Version". - -The "Minimal Corresponding Source" for a Combined Work means the -Corresponding Source for the Combined Work, excluding any source code -for portions of the Combined Work that, considered in isolation, are -based on the Application, and not on the Linked Version. - -The "Corresponding Application Code" for a Combined Work means the -object code and/or source code for the Application, including any data -and utility programs needed for reproducing the Combined Work from the -Application, but excluding the System Libraries of the Combined Work. - -## 1. Exception to Section 3 of the GNU GPL. - -You may convey a covered work under sections 3 and 4 of this License -without being bound by section 3 of the GNU GPL. - -## 2. Conveying Modified Versions. - -If you modify a copy of the Library, and, in your modifications, a -facility refers to a function or data to be supplied by an Application -that uses the facility (other than as an argument passed when the -facility is invoked), then you may convey a copy of the modified -version: - -- a) under this License, provided that you make a good faith effort - to ensure that, in the event an Application does not supply the - function or data, the facility still operates, and performs - whatever part of its purpose remains meaningful, or -- b) under the GNU GPL, with none of the additional permissions of - this License applicable to that copy. - -## 3. Object Code Incorporating Material from Library Header Files. - -The object code form of an Application may incorporate material from a -header file that is part of the Library. You may convey such object -code under terms of your choice, provided that, if the incorporated -material is not limited to numerical parameters, data structure -layouts and accessors, or small macros, inline functions and templates -(ten or fewer lines in length), you do both of the following: - -- a) Give prominent notice with each copy of the object code that - the Library is used in it and that the Library and its use are - covered by this License. -- b) Accompany the object code with a copy of the GNU GPL and this - license document. - -## 4. Combined Works. - -You may convey a Combined Work under terms of your choice that, taken -together, effectively do not restrict modification of the portions of -the Library contained in the Combined Work and reverse engineering for -debugging such modifications, if you also do each of the following: - -- a) Give prominent notice with each copy of the Combined Work that - the Library is used in it and that the Library and its use are - covered by this License. -- b) Accompany the Combined Work with a copy of the GNU GPL and this - license document. -- c) For a Combined Work that displays copyright notices during - execution, include the copyright notice for the Library among - these notices, as well as a reference directing the user to the - copies of the GNU GPL and this license document. -- d) Do one of the following: - - 0) Convey the Minimal Corresponding Source under the terms of - this License, and the Corresponding Application Code in a form - suitable for, and under terms that permit, the user to - recombine or relink the Application with a modified version of - the Linked Version to produce a modified Combined Work, in the - manner specified by section 6 of the GNU GPL for conveying - Corresponding Source. - - 1) Use a suitable shared library mechanism for linking with - the Library. A suitable mechanism is one that (a) uses at run - time a copy of the Library already present on the user's - computer system, and (b) will operate properly with a modified - version of the Library that is interface-compatible with the - Linked Version. -- e) Provide Installation Information, but only if you would - otherwise be required to provide such information under section 6 - of the GNU GPL, and only to the extent that such information is - necessary to install and execute a modified version of the - Combined Work produced by recombining or relinking the Application - with a modified version of the Linked Version. (If you use option - 4d0, the Installation Information must accompany the Minimal - Corresponding Source and Corresponding Application Code. If you - use option 4d1, you must provide the Installation Information in - the manner specified by section 6 of the GNU GPL for conveying - Corresponding Source.) - -## 5. Combined Libraries. - -You may place library facilities that are a work based on the Library -side by side in a single library together with other library -facilities that are not Applications and are not covered by this -License, and convey such a combined library under terms of your -choice, if you do both of the following: - -- a) Accompany the combined library with a copy of the same work - based on the Library, uncombined with any other library - facilities, conveyed under the terms of this License. -- b) Give prominent notice with the combined library that part of it - is a work based on the Library, and explaining where to find the - accompanying uncombined form of the same work. - -## 6. Revised Versions of the GNU Lesser General Public License. - -The Free Software Foundation may publish revised and/or new versions -of the GNU Lesser General Public License from time to time. Such new -versions will be similar in spirit to the present version, but may -differ in detail to address new problems or concerns. - -Each version is given a distinguishing version number. If the Library -as you received it specifies that a certain numbered version of the -GNU Lesser General Public License "or any later version" applies to -it, you have the option of following the terms and conditions either -of that published version or of any later version published by the -Free Software Foundation. If the Library as you received it does not -specify a version number of the GNU Lesser General Public License, you -may choose any version of the GNU Lesser General Public License ever -published by the Free Software Foundation. - -If the Library as you received it specifies that a proxy can decide -whether future versions of the GNU Lesser General Public License shall -apply, that proxy's public statement of acceptance of any version is -permanent authorization for you to choose that version for the -Library. diff --git a/mods/libox/README.md b/mods/libox/README.md deleted file mode 100644 index aa0f0b0a..00000000 --- a/mods/libox/README.md +++ /dev/null @@ -1,39 +0,0 @@ -# Libox - -A minetest sandboxing library, offering a basic environment, utilities, normal sandbox and a "coroutine" sandbox - -Everything is avaliable in the async environment except the coroutine sandbox (due to minetest limitations) - -See [api.md](https://github.com/TheEt1234/libox/blob/master/api.md) for documentation and definitions - -See [env_docs.md](https://github.com/TheEt1234/libox/blob/master/env_docs.md) for documentation of the sandbox environment - -# Notice! - -Libox (optionally) requires insecure environment to weigh local variables and upvalues in the coroutine sandbox. **Without this someone can overfill your memory with local variables/upvalues** -***the libox mod will expose debug.getlocal and debug.getupvalue to all mods*** - -Also if you are using coroutine sandboxes, please use luaJIT (default) instead of PUC lua, as there are a lot of differences between them - -# Security - -- *Somewhat* fixes mesecons issue #516 by limiting based on time not instructions -- ***May introduce new bugs, only time can test that*** -- Some of the responsibility is also on the mods that use libox as well (such as not doing something dumb like calling functions straight from the environment), the purpose of libox should be to also handle some of the more common stuff - -# Optional dependancies -dbg - not actually used for debugging, just used to provide `dbg.shorten_path`, if unavaliable it will fallback to the copied implementation - -# Credits - see License.md for the actual licenses - -Code (unless mentioned somewhere differently) - LGPLv3 - -`libox.shorten_path` - [The minetest dbg mod's shorten_path.lua](https://github.com/appgurueu/dbg/blob/master/src/shorten_path.lua) - MIT licensed - -`pat.lua`: [source](https://notabug.org/pgimeno/patlua/src/master/pat.lua) [and the mesecons issue](https://github.com/minetest-mods/mesecons/issues/456) - MIT licensed - -`github/workflows/luacheck.yml` - from mt-mods, [original source here ](https://github.com/mt-mods/mt-mods/blob/master/snippets/luacheck.yml) - MIT licensed - -`os.date` in the environment - from mooncontroller [original repo here](https://github.com/mt-mods/mooncontroller) - -Inspiration: [Luacontrollers](https://github.com/minetest-mods/mesecons/tree/master/mesecons_luacontroller) \ No newline at end of file diff --git a/mods/libox/api.md b/mods/libox/api.md deleted file mode 100644 index 7c1d0a48..00000000 --- a/mods/libox/api.md +++ /dev/null @@ -1,150 +0,0 @@ -# Api docs - -## Disclaimers -- ***DO NOT EVER CALL FUNCTIONS FROM THE ENVIRONMENT (once the environment is defined) AND DO NOT CALL ANY FUNCTIONS RETURNED BY THE SANDBOX*** that will just bypass the debug hook and allow someone to `repeat until false` and *stop* the server that way -- anything coming out of the sandbox should *not* be called, and be checked for every single detail (like you are writing a digiline device) - -## Definitions -- microsecond: milisecond * 1000 -- hook: a lua function that runs every `n` instructions -- environment: The values that the sandboxed code can work with -- string sandbox: when the `__index` field of a string's metatable gets replaced with the sandboxes `string` (basically, a thing to prevent the sandbox from using unsafe string functions through `"":unsafe_function()`) - -## Differences from luac-like sandboxing -- The basic environment is much more permissive (but still maintains safety) -- You get limited not by instructions (luacontroller calls them events for some reason??? even if it calls *triggers* events too??? this is so dumb) but by time *by default* -- You get a traceback *by default* - -## Utilities -`libox.get_default_hook(max_time)` - Get the hook function that will terminate the program in `max_time` microseconds - -`libox.traceback(...)` - a function that gives a friendlier traceback, now safe to expose to sandbox - -`msg, cost = libox.digiline_sanitize(input, allow_functions, wrap)` - use this instead of your own clean_and_weigh_digiline_message implementation, `wrap` is a function that accepts a function and returns another one, this gets called on user functions - -`libox.sandbox_lib_f(f, ...)` - use this if you want to escape the string sandbox (do this if you are not 100% sure that your code is free of `"":this_stuff()`) **don't use this on functions that run user - -`libox.disabled = true/false` - use when you want to disable libox (e.g. when using jitprofiler) - -`libox.has_autohook = true/false` - Is autohook available or not? - -**functions** - -`libox.type_check(thing, check)` -- `thing` = untrusted data -- `check` a function or a table with the following format: -```lua - { - something = function(value) return true end, - a_table = { - other_key = libox.type("number"), - x = libox.type_vector, -- this is how type_vector is supposed to be used, don't do libox.type_vector() in this case - } - } -``` -- runs a series of checks on the `thing` using the check table -- if the `thing` table contains an extra property, not defined in the `check` table, it will return false too -- if the `thing` table lacks a property in the `check` table, it will return false -- returns a boolean, and a string (success, faulty element) - -`libox.type(type)` - returns a function that checks a type -- for example, when given `"number"`, it returns a function: `function(x) return type(x) == "number" end` - -`libox.type_vector(x)` - is a function that checks if `x` is a vector, use `vector.check` if you want to also check the vector metatable - -`libox.shorten_path(path)` - use this to shorten a path, it will convert `/home/user/blabla/.minetest/modname/x.lua` into `modname:x.lua` - if the `dbg` mod is avaliable, it will simply use `dbg.shorten_path` -## Environment -`libox.create_basic_environment()` - get a basic secure environment already set up for you - -`libox.supply_additional_environment(env)` - a function that lets other mods extend the environment, gets called after environment creation, by default is `function(...) return ... end` - -`libox.safe.*` - safe functions/classes, used in libox.create_basic_environment, used internally, you shouldn't modify this table - -## "Normal" sandbox - -`libox.normal_sandbox(def)` -- A sandbox that executes lua code securely based on parameters in `def` (table) -### The def table -- `def.code` - the code... -- `def.env` - The environment of the function -- `def.error_handler` - A function inside the `xpcall`, by default `libox.traceback` -- `def.in_hook` - The hook function, by default `libox.get_default_hook(def.max_time)` -- `def.max_time` - Maximum allowed execution time, in microseconds, only used if `def.in_hook` was not defined -- `def.hook_time` - The hook function will execute every `def.hook_time` instructions, by default 50 -- `def.function_wrap` - transforms a function, by default `function(f) return f end` - -## "Coroutine" sandbox -- Optionally requires trusted environment for weighing local variables and upvalues - - without it someone can overfill your memory, but libox has protections against that *somewhat, though i don't think it's a good idea to rely on them* - -### What is it? -A sandbox that allows the user to **yield** => temporarily stop execution; then be able to resume from that point - -### garbage collection -`libox.coroutine.settings` -- memory_treshold: in gigabytes, if lua's memory reaches above this limit, the hook will error, the user is meant to configure this to their needs *also this is what i meant about those overfill protections, not exactly reliable* -- gc settings: - - time_treshold: if a sandbox has been untouched for this long, collect it, in seconds - - number_of_sandboxes: the garbage collection will trigger if the number of stored sandboxes is above this limit - - auto: if true, garbage collection will automatically activate, i don't think this is nessesary if you have trusted the libox mod - - interval: in seconds, when to trigger the garbage collection - -All of theese are configurable by the user - -`libox.coroutine.garbage_collect()` - trigger the garbage collection - -### the docs -- When libox is a trusted mod, it exposes `debug.getlocal` and `debug.getupvalue` - -`libox.coroutine.active_sandboxes` - A table containing all the active sandboxes, where the key is the sandbox's id, and the value is the sandbox definition and thread - -`libox.coroutine.create_sandbox(def)` -- returns an ID to the sandbox (can be used in libox.coroutine.* functions or just be able to see the sandbox yourself with `libox.coroutine.active_sandboxes[id]`) - -- `def.ID` - A custom id, by default random text -- `def.code` - the code -- `def.is_garbage_collected` - if this sandbox should be garbage collected, by default true -- `def.env` - the environment, by default a blank table -- `def.in_hook` - hook builder function, by default `libox.coroutine.get_default_hook(def.time_limit or libox.default_time_limit)` or `nil` if autohook is available+enabled. See `libox.coroutine.get_default_hook` on how to use, it is different to how normal sandbox handles it. -- `def.time_limit` - used if `debug.in_hook` is not avaliable, by default 3000 -- `last_ran` - not set by you, but is the last time the sandbox was ran, used for garbage collection -- `def.hook_time` - The hook function will execute every `def.hook_time` instructions, by default 10 -- `def.size_limit` - in *bytes*, the size limit of the sandbox, if trusted then upvalues and local variables are counted in too, by default 5 *megabytes*, aka `1024*1024*5` bytes -- `def.function_wrap` - transforms a function, by default `function(f) return f end` -- `def.autohook` - enables/disables auto-yielding inside sandboxes, respecting `def.hook_time` and `def.time_limit`. `def.in_hook` behaves a bit differently. Please read `autohook/README.md` document for more info. By default, this is disabled (`false`). - -`libox.coroutine.get_default_hook(max_time)` - returns a hook builder function. The created hook performs a time limit check whether to raise an error or not. Raising an error kills the sandbox. - -`libox.coroutine.run_sandbox(ID, value_passed)` -- `value_passed` - the value passed to the coroutine.resume function, so that in the sandbox it could: `local vals = coroutine.yield("blabla")` -- Returns ok, errmsg_or_value (the `"blabla"` in `coroutine.yield("blabla")`) - -`libox.coroutine.size_check(env, lim, thread)` -- `env` - environment of the thread -- `lim` - the limit -- `thread` - the thread -- returns if its size (computed using `get_size`) is less than the lim -- used internally - -`libox.coroutine.get_size(env, seen, thread, recursed)` -- get the size in bytes of a thread, used by size_check -- normal usage: `libox.coroutine.get_size(env, {}, thread, false)` - -`libox.coroutine.is_sandbox_dead(id)` -- detects if the sandbox is dead - - -# Async -- everything else other than the coroutine sandbox is avaliable in both sync and async environments - -coroutine sandbox is not avaliable in async because - -1) I cannot import the debug.getlocal and debug.getupvalue functions into the async environment -2) I cannot import a coroutine in the async environment - -# Examples -- [libox controller](https://github.com/TheEt1234/libox_controller) - -# Todos -- proper examples -- ~~Maybe automatic yielding? depends on how possible that is~~ it's not really... \ No newline at end of file diff --git a/mods/libox/autohook/.gitignore b/mods/libox/autohook/.gitignore deleted file mode 100644 index 7b42cc7b..00000000 --- a/mods/libox/autohook/.gitignore +++ /dev/null @@ -1,6 +0,0 @@ -.xmake -build -compile_commands.json -autohook.h -*.dll -*.so \ No newline at end of file diff --git a/mods/libox/autohook/.xmake/linux/x86_64/cache/config b/mods/libox/autohook/.xmake/linux/x86_64/cache/config deleted file mode 100644 index 44311624..00000000 --- a/mods/libox/autohook/.xmake/linux/x86_64/cache/config +++ /dev/null @@ -1,9 +0,0 @@ -{ - recheck = false, - options = { - clean = true - }, - mtimes = { - ["xmake.lua"] = 1748874796 - } -} \ No newline at end of file diff --git a/mods/libox/autohook/.xmake/linux/x86_64/cache/cxxmodules b/mods/libox/autohook/.xmake/linux/x86_64/cache/cxxmodules deleted file mode 100644 index 6f31cf5a..00000000 --- a/mods/libox/autohook/.xmake/linux/x86_64/cache/cxxmodules +++ /dev/null @@ -1 +0,0 @@ -{ } \ No newline at end of file diff --git a/mods/libox/autohook/.xmake/linux/x86_64/cache/detect b/mods/libox/autohook/.xmake/linux/x86_64/cache/detect deleted file mode 100644 index ed9250f6..00000000 --- a/mods/libox/autohook/.xmake/linux/x86_64/cache/detect +++ /dev/null @@ -1,355 +0,0 @@ -{ - find_program_gcc_arch_x86_64_plat_linux_checktoolld = { - ["g++"] = "/usr/bin/g++" - }, - find_programver = { - ["/usr/bin/gcc"] = "15.1.1", - ["/usr/bin/g++"] = "15.1.1" - }, - find_program = { - gzip = "/usr/bin/gzip", - git = "/usr/bin/git", - emerge = false, - tar = "/usr/bin/tar", - gcc = "/usr/bin/gcc", - sh = "/usr/bin/sh", - pacman = "/usr/bin/pacman", - brew = false, - ["/usr/bin/gcc"] = "/usr/bin/gcc", - ["/usr/bin/g++"] = "/usr/bin/g++", - nim = false, - ["pkg-config"] = "/usr/bin/pkg-config" - }, - ["core.tools.gcc.has_cflags"] = { - ["/usr/bin/gcc_15.1.1"] = { - ["-print-multi-directory"] = true, - ["-print-sysroot"] = true, - ["-save-temps"] = true, - ["-pass-exit-codes"] = true, - ["-o"] = true, - ["-print-search-dirs"] = true, - ["--help"] = true, - ["-S"] = true, - ["-print-multi-lib"] = true, - ["-time"] = true, - ["-dumpmachine"] = true, - ["--param"] = true, - ["-no-canonical-prefixes"] = true, - ["-x"] = true, - ["-Xassembler"] = true, - ["-dumpversion"] = true, - ["-print-multiarch"] = true, - ["-pie"] = true, - ["--version"] = true, - ["-c"] = true, - ["-print-multi-os-directory"] = true, - ["-print-libgcc-file-name"] = true, - ["-dumpspecs"] = true, - ["--target-help"] = true, - ["-Xlinker"] = true, - ["-E"] = true, - ["-B"] = true, - ["-v"] = true, - ["-Xpreprocessor"] = true, - ["-shared"] = true, - ["-pipe"] = true, - ["-print-sysroot-headers-suffix"] = true - } - }, - find_package_linux_x86_64_fetch_package_system = { - luajit_aaeb029456e54f29b904a191c96508d2_release_external = { - sysincludedirs = { - "/usr/include/luajit-2.1" - }, - shared = true, - version = "2.1.1741730670", - libfiles = { - "/usr/lib/libluajit-5.1.so" - }, - links = { - "luajit-5.1" - } - } - }, - ["detect.sdks.find_vcpkgdir"] = false, - find_program_gcc_arch_x86_64_plat_linux_checktoolsh = { - ["g++"] = "/usr/bin/g++" - }, - ["core.tools.gcc.has_ldflags"] = { - ["/usr/bin/g++_15.1.1"] = { - ["--gc-sections"] = true, - ["--major-image-version"] = true, - ["--map-whole-files"] = true, - ["--wrap"] = true, - ["--no-accept-unknown-input-arch"] = true, - ["--relax"] = true, - ["--no-relax"] = true, - ["--warn-rwx-segments"] = true, - ["--gc-keep-exported"] = true, - ["--pop-state"] = true, - ["--no-export-dynamic"] = true, - ["-G"] = true, - ["--disable-large-address-aware"] = true, - ["-nostdlib"] = true, - ["--verbose"] = true, - ["--enable-auto-image-base"] = true, - ["--section-start"] = true, - ["--retain-symbols-file"] = true, - ["--stack"] = true, - ["-Qy"] = true, - ["-Trodata-segment"] = true, - ["--warn-alternate-em"] = true, - ["--export-dynamic-symbol"] = true, - ["--add-stdcall-alias"] = true, - ["--out-implib"] = true, - ["-l"] = true, - ["-Bshareable"] = true, - ["-debug"] = true, - ["--reduce-memory-overheads"] = true, - ["--print-gc-sections"] = true, - ["--error-rwx-segments"] = true, - ["--just-symbols"] = true, - ["--split-by-file"] = true, - ["--trace-symbol"] = true, - ["--task-link"] = true, - ["--strip-all"] = true, - ["-plugin-opt"] = true, - ["-O"] = true, - ["--error-execstack"] = true, - ["--enable-reloc-section"] = true, - ["--script"] = true, - ["--undefined-version"] = true, - ["--no-warnings"] = true, - ["--rosegment"] = true, - ["--exclude-symbols"] = true, - ["--ld-generated-unwind-info"] = true, - ["-dT"] = true, - ["-L"] = true, - ["--no-dynamic-linker"] = true, - ["--format"] = true, - ["-e"] = true, - ["--no-fatal-warnings"] = true, - ["--no-error-rwx-segments"] = true, - ["--defsym"] = true, - ["--disable-stdcall-fixup"] = true, - ["--demangle"] = true, - ["--traditional-format"] = true, - ["--trace"] = true, - ["--discard-all"] = true, - ["--disable-reloc-section"] = true, - ["--version-script"] = true, - ["-Bgroup"] = true, - ["--strip-discarded"] = true, - ["--subsystem"] = true, - ["--strip-debug"] = true, - ["--no-eh-frame-hdr"] = true, - ["-Bno-symbolic"] = true, - ["--warn-textrel"] = true, - ["--filter"] = true, - ["--dependency-file"] = true, - ["--enable-auto-import"] = true, - ["-A"] = true, - ["--default-symver"] = true, - ["-I"] = true, - ["--no-warn-rwx-segments"] = true, - ["--warn-common"] = true, - ["--push-state"] = true, - ["-assert"] = true, - ["--minor-image-version"] = true, - ["--support-old-code"] = true, - ["--export-dynamic"] = true, - ["--library"] = true, - ["--no-allow-shlib-undefined"] = true, - ["--discard-locals"] = true, - ["-f"] = true, - ["--no-demangle"] = true, - ["-Map"] = true, - ["--exclude-modules-for-implib"] = true, - ["--fatal-warnings"] = true, - ["-fini"] = true, - ["--whole-archive"] = true, - ["--no-define-common"] = true, - ["-T"] = true, - ["-Y"] = true, - ["--omagic"] = true, - ["--default-script"] = true, - ["--error-unresolved-symbols"] = true, - ["-EB"] = true, - ["--spare-dynamic-tags"] = true, - ["--dynamic-list-data"] = true, - ["-no-pie"] = true, - ["-Ttext"] = true, - ["--no-strip-discarded"] = true, - ["--no-print-map-locals"] = true, - ["--no-ctf-variables"] = true, - ["--force-exe-suffix"] = true, - ["-rpath-link"] = true, - ["-plugin-save-temps"] = true, - ["-F"] = true, - ["--major-subsystem-version"] = true, - ["--large-address-aware"] = true, - ["--enable-non-contiguous-regions-warnings"] = true, - ["-plugin"] = true, - ["-soname"] = true, - ["--allow-shlib-undefined"] = true, - ["--oformat"] = true, - ["--no-whole-archive"] = true, - ["--relocatable"] = true, - ["-u"] = true, - ["--remap-inputs"] = true, - ["--enable-linker-version"] = true, - ["--auxiliary"] = true, - ["--disable-auto-image-base"] = true, - ["-Tdata"] = true, - ["-Tldata-segment"] = true, - ["--accept-unknown-input-arch"] = true, - ["--no-warn-mismatch"] = true, - ["--no-print-map-discarded"] = true, - ["--print-output-format"] = true, - ["-z"] = true, - ["-dp"] = true, - ["--enable-extra-pep-debug"] = true, - ["--as-needed"] = true, - ["--end-group"] = true, - ["--sort-section"] = true, - ["--copy-dt-needed-entries"] = true, - ["-P"] = true, - ["--file-alignment"] = true, - ["--no-print-gc-sections"] = true, - ["--cref"] = true, - ["-V"] = true, - ["--version-exports-section"] = true, - ["-EL"] = true, - ["-g"] = true, - ["--no-warn-search-mismatch"] = true, - ["--no-warn-execstack"] = true, - ["-h"] = true, - ["--enable-non-contiguous-regions"] = true, - ["--dynamic-list-cpp-new"] = true, - ["--architecture"] = true, - ["--no-check-sections"] = true, - ["--dynamic-list-cpp-typeinfo"] = true, - ["--section-ordering-file"] = true, - ["--disable-long-section-names"] = true, - ["--disable-linker-version"] = true, - ["--check-sections"] = true, - ["--output"] = true, - ["--disable-auto-import"] = true, - ["--no-ld-generated-unwind-info"] = true, - ["--help"] = true, - ["--ignore-unresolved-symbol"] = true, - ["-o"] = true, - ["--export-all-symbols"] = true, - ["--nmagic"] = true, - ["--sort-common"] = true, - ["--print-map-discarded"] = true, - ["-R"] = true, - ["--image-base"] = true, - ["--no-gc-sections"] = true, - ["--warn-multiple-gp"] = true, - ["-Bsymbolic-functions"] = true, - ["--version"] = true, - ["-c"] = true, - ["--default-imported-symver"] = true, - ["--library-path"] = true, - ["--warn-execstack-objects"] = true, - ["-static"] = true, - ["-Ttext-segment"] = true, - ["--warn-section-align"] = true, - ["--eh-frame-hdr"] = true, - ["--start-group"] = true, - ["--split-by-reloc"] = true, - ["--print-sysroot"] = true, - ["--disable-new-dtags"] = true, - ["--enable-stdcall-fixup"] = true, - ["--exclude-all-symbols"] = true, - ["--warn-duplicate-exports"] = true, - ["--orphan-handling"] = true, - ["--require-defined"] = true, - ["--gpsize"] = true, - ["--error-handling-script"] = true, - ["--undefined"] = true, - ["--remap-inputs-file"] = true, - ["--print-map"] = true, - ["--no-as-needed"] = true, - ["-Tbss"] = true, - ["--no-copy-dt-needed-entries"] = true, - ["--enable-long-section-names"] = true, - ["--minor-subsystem-version"] = true, - ["--entry"] = true, - ["-Ur"] = true, - ["--kill-at"] = true, - ["--dll"] = true, - ["-b"] = true, - ["--warn-execstack"] = true, - ["--print-memory-usage"] = true, - ["-qmagic"] = true, - ["--print-map-locals"] = true, - ["--enable-extra-pe-debug"] = true, - ["--output-def"] = true, - ["--no-undefined-version"] = true, - ["--unique"] = true, - ["-init"] = true, - ["--dynamic-linker"] = true, - ["--ctf-variables"] = true, - ["--heap"] = true, - ["--allow-multiple-definition"] = true, - ["--warn-once"] = true, - ["--enable-runtime-pseudo-reloc"] = true, - ["--force-group-allocation"] = true, - ["--major-os-version"] = true, - ["--compat-implib"] = true, - ["--export-dynamic-symbol-list"] = true, - ["--stats"] = true, - ["-rpath"] = true, - ["-a"] = true, - ["--section-alignment"] = true, - ["--no-error-execstack"] = true, - ["--discard-none"] = true, - ["-y"] = true, - ["--no-rosegment"] = true, - ["--no-undefined"] = true, - ["--no-keep-memory"] = true, - ["-Bsymbolic"] = true, - ["--disable-multiple-abs-defs"] = true, - ["--pic-executable"] = true, - ["--no-omagic"] = true, - ["--emit-relocs"] = true, - ["--enable-new-dtags"] = true, - ["--disable-runtime-pseudo-reloc"] = true, - ["--minor-os-version"] = true, - ["--target-help"] = true, - ["--dynamic-list"] = true, - ["--exclude-libs"] = true, - ["--warn-unresolved-symbols"] = true, - ["--mri-script"] = true, - ["--no-map-whole-files"] = true, - ["-flto"] = true, - ["-m"] = true - } - }, - find_program_gcc_arch_x86_64_plat_linux_checktoolcc = { - gcc = "/usr/bin/gcc" - }, - ["lib.detect.has_flags"] = { - ["linux_x86_64_/usr/bin/gcc_15.1.1_cc_cflags_-m64_-Wno-newline-eof"] = true, - ["linux_x86_64_/usr/bin/gcc_15.1.1_cc_cflags_-m64_-Wno-unused-parameter"] = true, - ["linux_x86_64_/usr/bin/gcc_15.1.1_cc_cflags_-m64_-Wextra"] = true, - ["linux_x86_64_/usr/bin/gcc_15.1.1_cc__-m64_-fPIC"] = true, - ["linux_x86_64_/usr/bin/gcc_15.1.1_cc_cflags_-m64_-Wno-declaration-after-statement"] = true, - ["linux_x86_64_/usr/bin/gcc_15.1.1_cc_cflags_-m64_-Wpedantic"] = true, - ["linux_x86_64_/usr/bin/gcc_15.1.1_cc_cflags_-m64_-Wno-unused-function"] = true, - ["linux_x86_64_/usr/bin/gcc_15.1.1_cc_cflags_-m64_-Wno-missing-prototypes"] = true, - ["linux_x86_64_/usr/bin/gcc_15.1.1_cc_cxflags_-m64_-fdiagnostics-color=always"] = true, - ["linux_x86_64_/usr/bin/gcc_15.1.1_cc_cflags_-m64_-Wno-switch-default"] = true, - ["linux_x86_64_/usr/bin/gcc_15.1.1_cc_cxflags_-m64_-MMD -MF"] = true, - ["linux_x86_64_/usr/bin/gcc_15.1.1_cc_cxflags_-m64_-Wno-gnu-line-marker -Werror"] = true, - ["linux_x86_64_/usr/bin/gcc_15.1.1_cc_cflags_-m64_-Wall"] = true, - ["linux_x86_64_/usr/bin/gcc_15.1.1_cc_cflags_-m64_-Wno-unused-macros"] = true, - ["linux_x86_64_/usr/bin/g++_15.1.1_sh__-shared -m64 -m64_-fPIC"] = true, - ["linux_x86_64_/usr/bin/gcc_15.1.1_cc_cflags_-m64_-Wno-gnu-zero-variadic-macro-arguments"] = true, - ["linux_x86_64_/usr/bin/gcc_15.1.1_cc_cflags_-m64_-Wno-unsafe-buffer-usage"] = true, - ["linux_x86_64_/usr/bin/g++_15.1.1_ld__-m64 -m64_-fPIC"] = true, - ["linux_x86_64_/usr/bin/gcc_15.1.1_cc_cflags_-m64_-Wno-extra-semi-stmt"] = true - } -} \ No newline at end of file diff --git a/mods/libox/autohook/.xmake/linux/x86_64/cache/history b/mods/libox/autohook/.xmake/linux/x86_64/cache/history deleted file mode 100644 index c886198c..00000000 --- a/mods/libox/autohook/.xmake/linux/x86_64/cache/history +++ /dev/null @@ -1,19 +0,0 @@ -{ - cmdlines = { - "xmake lua /usr/share/xmake/modules/private/utils/statistics.lua", - "xmake config -c", - "xmake config -c", - "xmake config -c -vD", - "xmake config -c -vD", - "xmake config -c -vD", - "xmake config -c -vD", - "xmake config -c -vD", - "xmake config -c -vD", - "xmake config -c -vD", - "xmake config -c -vD", - "xmake config -c -vD", - "xmake config -c", - "xmake ", - "xmake lua /usr/share/xmake/actions/build/cleaner.lua" - } -} \ No newline at end of file diff --git a/mods/libox/autohook/.xmake/linux/x86_64/cache/option b/mods/libox/autohook/.xmake/linux/x86_64/cache/option deleted file mode 100644 index 6f31cf5a..00000000 --- a/mods/libox/autohook/.xmake/linux/x86_64/cache/option +++ /dev/null @@ -1 +0,0 @@ -{ } \ No newline at end of file diff --git a/mods/libox/autohook/.xmake/linux/x86_64/cache/package b/mods/libox/autohook/.xmake/linux/x86_64/cache/package deleted file mode 100644 index 520c6268..00000000 --- a/mods/libox/autohook/.xmake/linux/x86_64/cache/package +++ /dev/null @@ -1,23 +0,0 @@ -{ - luajit = { - __requirestr = "luajit", - shared = true, - envs = { - PATH = { - "/home/et/.xmake/packages/l/luajit/v2.1.0-beta3/aaeb029456e54f29b904a191c96508d2/bin" - } - }, - __requireconfs = { - optional = true, - configs = { - shared = false - }, - system = true - }, - __enabled = true, - libfiles = "/usr/lib/libluajit-5.1.so", - sysincludedirs = "/usr/include/luajit-2.1", - version = "2.1.1741730670", - links = "luajit-5.1" - } -} \ No newline at end of file diff --git a/mods/libox/autohook/.xmake/linux/x86_64/cache/project b/mods/libox/autohook/.xmake/linux/x86_64/cache/project deleted file mode 100644 index 6f31cf5a..00000000 --- a/mods/libox/autohook/.xmake/linux/x86_64/cache/project +++ /dev/null @@ -1 +0,0 @@ -{ } \ No newline at end of file diff --git a/mods/libox/autohook/.xmake/linux/x86_64/cache/references b/mods/libox/autohook/.xmake/linux/x86_64/cache/references deleted file mode 100644 index eb6e941c..00000000 --- a/mods/libox/autohook/.xmake/linux/x86_64/cache/references +++ /dev/null @@ -1,3 +0,0 @@ -{ - packages = { } -} \ No newline at end of file diff --git a/mods/libox/autohook/.xmake/linux/x86_64/cache/repository b/mods/libox/autohook/.xmake/linux/x86_64/cache/repository deleted file mode 100644 index 06504c14..00000000 --- a/mods/libox/autohook/.xmake/linux/x86_64/cache/repository +++ /dev/null @@ -1,12 +0,0 @@ -{ - artifacts_urls = { - "https://gitlab.com/xmake-mirror/build-artifacts.git", - "https://github.com/xmake-mirror/build-artifacts.git", - "https://gitee.com/xmake-mirror/build-artifacts.git" - }, - mainurls = { - "https://gitlab.com/tboox/xmake-repo.git", - "https://github.com/xmake-io/xmake-repo.git", - "https://gitee.com/tboox/xmake-repo.git" - } -} \ No newline at end of file diff --git a/mods/libox/autohook/.xmake/linux/x86_64/cache/toolchain b/mods/libox/autohook/.xmake/linux/x86_64/cache/toolchain deleted file mode 100644 index 0fa5bfa3..00000000 --- a/mods/libox/autohook/.xmake/linux/x86_64/cache/toolchain +++ /dev/null @@ -1,133 +0,0 @@ -{ - gfortran_arch_x86_64_plat_linux = { - plat = "linux", - arch = "x86_64", - __global = true, - __checked = true - }, - envs_arch_x86_64_plat_linux = { - plat = "linux", - arch = "x86_64", - __global = true, - __checked = true - }, - fpc_arch_x86_64_plat_linux = { - plat = "linux", - arch = "x86_64", - __global = true, - __checked = true - }, - tool_target_autohook_linux_x86_64_sh = { - toolchain_info = { - name = "gcc", - plat = "linux", - arch = "x86_64", - cachekey = "gcc_arch_x86_64_plat_linux" - }, - toolname = "gxx", - program = "/usr/bin/g++" - }, - yasm_arch_x86_64_plat_linux = { - plat = "linux", - arch = "x86_64", - __global = true, - __checked = true - }, - tool_platform_linux_x86_64_ld = { - toolchain_info = { - name = "gcc", - cachekey = "gcc_arch_x86_64_plat_linux", - arch = "x86_64", - plat = "linux" - }, - toolname = "gxx", - program = "/usr/bin/g++" - }, - cuda_arch_x86_64_plat_linux = { - plat = "linux", - arch = "x86_64", - __global = true, - __checked = true - }, - nasm_arch_x86_64_plat_linux = { - plat = "linux", - arch = "x86_64", - __global = true, - __checked = true - }, - nim_arch_x86_64_plat_linux = { - plat = "linux", - arch = "x86_64", - __global = true, - __checked = false - }, - swift_arch_x86_64_plat_linux = { - plat = "linux", - arch = "x86_64", - __global = true, - __checked = true - }, - go_arch_x86_64_plat_linux = { - plat = "linux", - arch = "x86_64", - __global = true, - __checked = true - }, - tool_platform_linux_x86_64_cc = { - toolchain_info = { - name = "gcc", - cachekey = "gcc_arch_x86_64_plat_linux", - arch = "x86_64", - plat = "linux" - }, - toolname = "gcc", - program = "/usr/bin/gcc" - }, - gcc_arch_x86_64_plat_linux = { - plat = "linux", - arch = "x86_64", - __global = true, - __checked = { - name = "gcc", - program = "/usr/bin/gcc" - } - }, - cross_arch_x86_64_plat_linux = { - plat = "linux", - arch = "x86_64", - __global = true, - __checked = false - }, - fasm_arch_x86_64_plat_linux = { - plat = "linux", - arch = "x86_64", - __global = true, - __checked = true - }, - tool_target_autohook_linux_x86_64_ld = { - toolchain_info = { - name = "gcc", - plat = "linux", - arch = "x86_64", - cachekey = "gcc_arch_x86_64_plat_linux" - }, - toolname = "gxx", - program = "/usr/bin/g++" - }, - tool_target_autohook_linux_x86_64_cc = { - toolchain_info = { - name = "gcc", - plat = "linux", - arch = "x86_64", - cachekey = "gcc_arch_x86_64_plat_linux" - }, - toolname = "gcc", - program = "/usr/bin/gcc" - }, - rust_arch_x86_64_plat_linux = { - plat = "linux", - arch = "x86_64", - __global = true, - __checked = true - } -} \ No newline at end of file diff --git a/mods/libox/autohook/.xmake/linux/x86_64/project.lock b/mods/libox/autohook/.xmake/linux/x86_64/project.lock deleted file mode 100644 index e69de29b..00000000 diff --git a/mods/libox/autohook/.xmake/linux/x86_64/xmake.conf b/mods/libox/autohook/.xmake/linux/x86_64/xmake.conf deleted file mode 100644 index 949bcba1..00000000 --- a/mods/libox/autohook/.xmake/linux/x86_64/xmake.conf +++ /dev/null @@ -1,26 +0,0 @@ -{ - arch = "x86_64", - buildir = "build", - ccache = true, - clean = true, - host = "linux", - Iluajit = false, - kind = "static", - Lluajit = false, - mode = "release", - ndk_stdcxx = true, - plat = "linux", - __toolchains_linux_x86_64 = { - "envs", - "gcc", - "yasm", - "nasm", - "fasm", - "cuda", - "go", - "rust", - "swift", - "gfortran", - "fpc" - } -} \ No newline at end of file diff --git a/mods/libox/autohook/README.md b/mods/libox/autohook/README.md deleted file mode 100644 index f28620ed..00000000 --- a/mods/libox/autohook/README.md +++ /dev/null @@ -1,98 +0,0 @@ -# Autohook -Autohook is a feature that allows coroutine sandboxes to automatically yield once they've reached their limits, controlled by `def.time_limit` in coroutine sandbox spec. The way this works is by hooking to the Lua runtime through its C API in order to bypass `yield across C-call boundary` limitation by yielding in C instead of Lua. Because of this, the C module is a bit system-dependent and may require knowledge in C and the general build process to troubleshoot it. - -To enable this feature, game and mod developers need to do a couple of things: - -1. Enable (`def.autohook = true`) when creating your sandbox. It's disabled by default. -2. Ask players to put libox in trusted mods list. An error message will be logged if libox found the C module but encountered problems loading it. -3. Ask players to compile the `libautohook.so/.dll` linking with the same LuaJIT library used with Luanti. Players, please read further below on how to compile it. - -If any of the conditions needed for autohook to work is unfulfilled, autohook is NOT available. As such, libox will safely fallback to regular coroutine sandbox behaviour where manual `yield()` is required. Check `libox.has_autohook`. - -# C Hook behaviour -The autohook uses `def.hook_time` in a normal way to set the C hook, being instruction counts needed to trigger the hook. The default autohook checks if the sandbox has elapsed `def.time_limit` and yields it. It is the auto-yielding form of `libox.coroutine.get_default_hook(def.time_limit or libox.default_time_limit)`. - -If `def.in_hook` is a function, then the C hook will call it instead of its default behaviour. Whenever `def.in_hook` throws an error, the C hook will yield. To kill the sandbox from `def.in_hook`, start your error message with `SANDBOX KILL`. This means that by default, `def.in_hook` unaware of the kill command will always yield. Please update `def.in_hook` accordingly when you enable autohook. - -# Compile the autohook C module -## Compile: Linux/Unix-like systems -1. Get [xmake](https://xmake.io/) either through its installer script or through your package manager. -2. Install LuaJIT. You may install LuaJIT using your system's package manager, or with [xrepo](https://xrepo.xmake.io/). -3. Go to this directory: `libox/autohook/` (the directory where this file is in) -4. `xmake config -c && xmake` - - `--Iluajit=...` is an `xmake config` option specifying where to find LuaJIT header files - - `--Lluajit=...` is an `xmake config` option specifying where to find LuaJIT libraries -5. Done! You can clean up by deleting these directories and files: `rm -r .xmake build` - -## Compile: Windows -The official release of luanti on Windows is cross-compiled from [Ubuntu LTS 22.04](https://releases.ubuntu.com/jammy/) through the [LLVM-MinGW toolchain with Clang under Window's Universal C Runtime](https://github.com/mstorsjo/llvm-mingw/) linked with [pre-compiled libraries by the Luanti team](https://github.com/luanti-org/luanti/blob/5.12.0/util/buildbot/buildwin64.sh#31). This makes it difficult and hard to translate the CMake build scripts for autohook's C module. Currently, no one has yet to successfully build a working autohook DLL with the same approach, hence why `libautohook.dll` isn't vendored directly for Windows. A PRs to fix this is welcome. Please compare with [prior attempt by Acorp/corpserot](https://github.com/corpserot/luanti-win-clang64). - -For now, we'll be going with a simpler setup on Windows natively. You will build luanti from scratch and playing on that build instead of the official release. This is a bit complicated but should be easy to follow. There's a shortcut: Use (and trust) [ACorp's/corpserot's luanti build](https://github.com/corpserot/luanti-win-clang64) which includes a pre-built `libautohook.dll`. Of course, it's always more secure to compile `libautohook.dll` on your own. - -1. Download the source code for the Luanti version you want to play on. For example, click the **Source code** (zip or tar.gz) asset in the [github release page for version 5.12.0](https://github.com/luanti-org/luanti/releases/tag/5.12.0). Extract it. - -2. Follow instructions in the official documentation for engine devs to [compile Luanti on Windows using MSYS2 + Clang64 environment](https://docs.luanti.org/for-engine-devs/compiling/windows/). Don't use the MSVC + vcpkg approach, it's not really well-maintained as other methods. (e.g. using a really, really years old LuaJIT) - - **WARNING**: the typical size of the tools installed is ~2GB. - -3. With luanti compiled, it's recommended you bundle your DLLs since right now it will only run in the Clang64 environment. Follow the [instructions to bundle the DLLs](https://docs.luanti.org/for-engine-devs/compiling/windows/#bundling-dlls) in the same document. You'll be using [rollerozxa's bundledll bash script](https://github.com/rollerozxa/msys2-bundledlls) - -4. Install xmake (and LuaJIT if you haven't): `pacman -Syu mingw-w64-clang-x86_64-luajit mingw-w64-clang-x86_64-xmake`. - -5. Build the C module by running `xmake config --toolchain=clang -c && xmake`. For more advanced needs/wants, here are extra options you can use: - - `--Iluajit=...` is an `xmake config` option specifying where to find LuaJIT header files - - `--Lluajit=...` is an `xmake config` option specifying where to find LuaJIT libraries - -6. Done! You may even uninstall MSYS2 if you like, but I suggest keeping it for future Luanti versions. You can also clean up by deleting these directories and files: `rm -r .xmake build*` - -# For developers -## C module versioning -`module-version.txt` tracks the current C source hash, so always re-build the C module -for any change. OR if you can't (or too lazy) do that, just do something like: - -```sh -cat autohook.c utils.c | sha256sum | awk '{ print $1 }' >module-version.txt -``` - -or on powershell: - -```pwsh -pwsh hash.ps1 autohook.c utils.c > module-version.txt -``` - -## Debug builds -On release builds, the C module disables its own logging capabilities. Logging -occurs through `core.log`, bypassing the sandbox. Logging capabilities is -available in debug builds. So, if you want to log things from the autohook, you -should create a debug build: - -```sh -xmake config -m debug -c && xmake -``` - -## All diagnostics when building -By default, xmake cuts off the diagnostics to a certain number of lines. To see -all of them: - -```sh -xmake config -c && xmake -D -``` - -## Verbose xmake configure and building -In order to debug and inspect what might go wrong in the xmake configuration and -build steps, you can use flags like so: - -```sh -xmake config -c -vD && xmake -vD -``` - -It is very noisy, so perhaps you should each step one-by-one. - -## Obtaining `compile_commands.json` -Pretty much all C/C++ LSPs/IDEs make use of this in order to know all the -required C source code, headers, library, etc. needed to build your target. It's -how any build system can "communicate" with your LSP. You can generate one by running: - -```sh -xmake project -k compile_commands -``` \ No newline at end of file diff --git a/mods/libox/autohook/autohook.c b/mods/libox/autohook/autohook.c deleted file mode 100644 index 5a54750c..00000000 --- a/mods/libox/autohook/autohook.c +++ /dev/null @@ -1,191 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include "autohook.h" -#include "utils.c" - -// module-version.txt tracks the current C source hash, so always re-build the C module -// for any change. OR if you can't (or too lazy) do that, just do something like: -// cat autohook.c utils.c | sha256sum | awk '{ print $1 }' >module-version.txt -// or on powershell: hash.ps1 autohook.c utils.c > module-version.txt - -static double prev_time = 0; -static double get_time_ms(void) { - // On Windows, clock_t is 32-bit, meaning after 24 days and 20 hours it - // becomes UB. So uh... don't run your server for longer than that. - ACorp - clock_t now = clock(); - return ((double)now) / CLOCKS_PER_SEC * 1000.0; -} - -static double time_limit = 0; -static int attempts = 0; // THIS is to avoid a "yield across C-call boundary" error -#define MAX_ATTEMPTS 10 - -static lua_Subidx module_idx = LUA_NOREF; -enum ModuleIdxs { - IN_HOOK_IDX = 1, - MAX_IDX, -}; - -#define KILL_CMD "SANDBOX KILL" - -// checks error message (stack peek) starts with given msg -// lua errors is in this format ":: " -static bool lua_error_startswith(lua_State *L, lua_Idx idx, cstr msg, size_t count) { - assert_ptr(msg, 3); - L_assert_string(idx); - - // lua manages the string, so we don't need to free() it ourselves :D - size_t errfull_count; - cstr errfull = lua_tolstring(L, idx, &errfull_count); - - if (errfull_count < count) { return false; } - if (errfull_count == count ) { - return string_eq(errfull, errfull_count, msg, count); - } - - // 0: initial search - // 1: past : - // 2: past : - int state = 0; - cstr errmsg = errfull; - for (size_t i = 0; state < 3 && i < errfull_count - count; ++i) { - switch (state) { - case 0: - case 1: - if (errfull[i] == ':') { - ++state; - if (i < errfull_count - count) { - errmsg = errfull + i + 1; // if there's no whitespace, just search here - } - } - break; - - case 2: - if (errfull[i] != ' ') { - ++state; - errmsg = errfull + i; - } - break; - } - } - - return string_startswith(errmsg, - errfull_count - (size_t)(errmsg - errfull), msg, count); -} - -#ifdef DEBUG -// lua: $globals.core.log(level, msg) -static void luanti_log(lua_State *L, cstr restrict level, cstr restrict msg) { - assert_str(level, 2); - assert_ptr(msg, 4); - - if (L_deepget_field(LUA_GLOBALS, "core", "log")) { - luaL_error(L, "Unable to deep get $global.core.log"); - } - lua_pushstring(L, level); - lua_pushstring(L, msg); - lua_call(L, 2, 0); -} -#else -#define luanti_log(...) -#endif - -static void hookf(lua_State *L, lua_Debug *ar) { - const lua_Idx reset = lua_gettop(L); - - if (L_deepget_subi(LUA_CREGISTRY, module_idx, IN_HOOK_IDX)) { - luaL_error(L, "Unable to deep get $module[IN_HOOK_IDX]"); - } - if (lua_isfunction(L, -1)) { - // lua: errcode, (stack push) = pcall(in_hook) - const int errcode = lua_pcall(L, 0, 0, 0); - if (errcode != 0) { - // lua: errmsg_len, errmsg = #(stack peek), (stack peek) - if (lua_error_startswith(L, -1, KILL_CMD, CSTR_COUNT(KILL_CMD))) { - lua_error(L); - // lua: else debug.sethook(); yield(); end - } else { - if (lua_isyieldable(L) || attempts >= MAX_ATTEMPTS) { - lua_settop(L, reset); - lua_sethook(L, nil, 0, 0); - lua_yield(L, 0); - return; - } else { - ++attempts; - } - return; - } - } - return; - } - - if (get_time_ms() - prev_time > time_limit) { - if (lua_isyieldable(L) || attempts >= MAX_ATTEMPTS) { - prev_time = get_time_ms(); - lua_settop(L, reset); - lua_sethook(L, nil, 0, 0); - lua_yield(L, 0); - } else { - ++attempts; - } - } -} - -/// autohook(int hook_time, double time_limit, lua_function|nil|none in_hook) -/// hook_time: same as in libox.coroutine.create_sandbox. Instructions per hook trigger -/// time_limit: same as in libox.coroutine.create_sandbox, but in ms. -/// Allowed execution time limit for the coroutine sandbox in milliseconds(!) -static int autohook(lua_State *L) { - const lua_Idx n = lua_gettop(L); - if (n < 2 || n > 3) { - luaL_error(L, "attach autohook() takes 2 or 3 arguments"); - } - - int hook_time; - L_assert_number(1); - L_assert_number(2); - if ((hook_time = (int)lua_tointeger(L, 1)) < 0) { - L_arg_expect_ll(1, "positive number", "negative number"); - } - if ((time_limit = lua_tonumber(L, 2)) < 0) { - L_arg_expect_ll(2, "positive number", "negative number"); - } - - if (lua_isfunction(L, 3)) { - if (L_deepset_subi(LUA_CREGISTRY, module_idx, IN_HOOK_IDX)) { - luaL_error(L, "Unable to deep set $module[IN_HOOK_IDX]"); - } - } else if (!lua_isnoneornil(L, 3)) { - L_arg_expect_la(3, "function or nil"); - } - lua_settop(L, 0); - - prev_time = get_time_ms(); - attempts = 0; - lua_sethook(L, hookf, LUA_MASKCOUNT, hook_time); - return 0; -} - -static int version(lua_State *L) { - lua_pushstring(L, AUTOHOOK_HASH); - lua_pushstring(L, LUAJIT_VERSION); - return 2; -} - -// the autohook module's table -static const luaL_Reg funcs [] = { - {"autohook", autohook}, - {"version", version}, - {nil, nil} -}; - -int luaopen_autohook(lua_State *L) {; - lua_createtable(L, MAX_IDX, 0); - module_idx = L_stack2ref(); - luaL_register(L, "autohook", funcs); - return 1; -} diff --git a/mods/libox/autohook/autohook.h b/mods/libox/autohook/autohook.h deleted file mode 100644 index 30daba3a..00000000 --- a/mods/libox/autohook/autohook.h +++ /dev/null @@ -1,3 +0,0 @@ -// This number is tied to the latest commit's UNIX time -#define AUTOHOOK_HASH "69d0480c1b562e26fc1668c3348c3c6071c4d41ffe410c4373cc70859b23fe19" -#define DEBUG 0 \ No newline at end of file diff --git a/mods/libox/autohook/autohook.h.in b/mods/libox/autohook/autohook.h.in deleted file mode 100644 index 9ab0e98c..00000000 --- a/mods/libox/autohook/autohook.h.in +++ /dev/null @@ -1,6 +0,0 @@ -// This number is tied to the latest commit's UNIX time -#define AUTOHOOK_HASH "${AUTOHOOK_HASH}" -${define DEBUG} -#if DEBUG == 0 -#undef DEBUG -#endif \ No newline at end of file diff --git a/mods/libox/autohook/build/.build_cache/5a/5a0144f26e0ed456ec3c30593cb46ff4 b/mods/libox/autohook/build/.build_cache/5a/5a0144f26e0ed456ec3c30593cb46ff4 deleted file mode 100644 index e974cfc5a6a3d3aebf9307e21e5d1ab993d3a69f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1256 zcmbVL%TC)+5FIC!M|lV$7D%u#3&cZkWb=mHbU?#a^+^clMNONcA%$%7k&-Hy}&rWC>uxRiJ-XcZ;e#gL4 z4=%w3jKjfh_gDAsdAHm7^Nrxz57@D+Eq!I@%fYIiHbq*b^^B1*ja+`T-S7 zAOYHU!nnPr#Iu+q(Qd1tT~BNC6Cj&K`CXTIaP(X@9v^T?!cH>`9h$vFBhGUk19`64=mB^i*ms>B?s{AEng zUf;`KM=td=P~*b$`7Lpd=d-1^%RbkT<^9Gn^3~c3Vk4;k>>lGbDv5e8^$pjshI*>} zC&WmKeG{E3{}40upOvDDzSEEwos;+&TDm9m86Py8C_m{yIqsbRAJNi|R6g}pcSn?> ZoWDjvOe7p3Gw2QCKgh!KsIu><{8u+PPv8Im diff --git a/mods/libox/autohook/build/.build_cache/9e/9e19e71a9cd69ef70589b2dd347fcfee b/mods/libox/autohook/build/.build_cache/9e/9e19e71a9cd69ef70589b2dd347fcfee deleted file mode 100644 index faa6274ea32b36cc929056941440927e7457f66d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 9248 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 diff --git a/mods/libox/autohook/build/.build_cache/ad/addd798cbb6e56df5c2e6a9cb4a13da6.txt b/mods/libox/autohook/build/.build_cache/ad/addd798cbb6e56df5c2e6a9cb4a13da6.txt deleted file mode 100644 index f08861a6..00000000 --- a/mods/libox/autohook/build/.build_cache/ad/addd798cbb6e56df5c2e6a9cb4a13da6.txt +++ /dev/null @@ -1,14 +0,0 @@ -{ - errdata = "\27[01m\27[Kcc1:\27[m\27[K \27[01;35m\27[Kwarning: \27[m\27[Kcommand-line option ‘\27[01m\27[K-Weffc++\27[m\27[K’ is valid for C++/ObjC++ but not for C\ -\27[01m\27[Kcc1:\27[m\27[K \27[01;36m\27[Knote: \27[m\27[Kunrecognized command-line option ‘\27[01m\27[K-Wno-unsafe-buffer-usage\27[m\27[K’ may have been intended to silence earlier diagnostics\ -\27[01m\27[Kcc1:\27[m\27[K \27[01;36m\27[Knote: \27[m\27[Kunrecognized command-line option ‘\27[01m\27[K-Wno-gnu-zero-variadic-macro-arguments\27[m\27[K’ may have been intended to silence earlier diagnostics\ -\27[01m\27[Kcc1:\27[m\27[K \27[01;36m\27[Knote: \27[m\27[Kunrecognized command-line option ‘\27[01m\27[K-Wno-newline-eof\27[m\27[K’ may have been intended to silence earlier diagnostics\ -\27[01m\27[Kcc1:\27[m\27[K \27[01;36m\27[Knote: \27[m\27[Kunrecognized command-line option ‘\27[01m\27[K-Wno-extra-semi-stmt\27[m\27[K’ may have been intended to silence earlier diagnostics\ -\27[01m\27[Kcc1:\27[m\27[K \27[01;35m\27[Kwarning: \27[m\27[Kcommand-line option ‘\27[01m\27[K-Weffc++\27[m\27[K’ is valid for C++/ObjC++ but not for C\ -\27[01m\27[Kcc1:\27[m\27[K \27[01;36m\27[Knote: \27[m\27[Kunrecognized command-line option ‘\27[01m\27[K-Wno-gnu-line-marker\27[m\27[K’ may have been intended to silence earlier diagnostics\ -\27[01m\27[Kcc1:\27[m\27[K \27[01;36m\27[Knote: \27[m\27[Kunrecognized command-line option ‘\27[01m\27[K-Wno-unsafe-buffer-usage\27[m\27[K’ may have been intended to silence earlier diagnostics\ -\27[01m\27[Kcc1:\27[m\27[K \27[01;36m\27[Knote: \27[m\27[Kunrecognized command-line option ‘\27[01m\27[K-Wno-gnu-zero-variadic-macro-arguments\27[m\27[K’ may have been intended to silence earlier diagnostics\ -\27[01m\27[Kcc1:\27[m\27[K \27[01;36m\27[Knote: \27[m\27[Kunrecognized command-line option ‘\27[01m\27[K-Wno-newline-eof\27[m\27[K’ may have been intended to silence earlier diagnostics\ -\27[01m\27[Kcc1:\27[m\27[K \27[01;36m\27[Knote: \27[m\27[Kunrecognized command-line option ‘\27[01m\27[K-Wno-extra-semi-stmt\27[m\27[K’ may have been intended to silence earlier diagnostics\ -" -} \ No newline at end of file diff --git a/mods/libox/autohook/build/.build_cache/cd/cdd7dc4994587146ed446897d780874d b/mods/libox/autohook/build/.build_cache/cd/cdd7dc4994587146ed446897d780874d deleted file mode 100644 index feb21449aec5543f1f344c830e200319710bed93..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1536 zcmbtU&2Q6C40qbG4Y5rHA%qx*T!sL_BMC{`azJgfkANl)6FZNr3yhDnRgy{@2!Vuz z)C1CP@TYK`!~yt2CUM{}?vsX{Ja_3+cL7T;wtx1|cAnF|TUuQ%X&SI-a34-QMgiWJ zPV7czHee2BVcj1b_#b{(25*o2LI2SIbcTZd;QKGqU+MAl+iE{}_~5Z_2~(I=+pOL- z+^PYv;(7P<>no4eZ|J5&G2JpO$FMC2U;>Fc9x8_!Py%hAFrH0Q{EHYP(O$2Cwo}pO zXQrn2F!?HCbVwHH(VVM%EP1n&PcVV}Q-u0Vz@OuB;qq{b(P%lFb`+zY7Yg~=42a#t zQyERoy$#QBZM$A;dZt^qTVAcXY`IG<+gV(6s;28UMH`~vc?Wv^G@;tL(0a;vj*fG= zB5}Gix7bfnX+CY3S`>GOSan7<$P z=h2`$YA_)6zD&f=G?R1qB#6J6%Q+0!Bu;lpy|Y%5zn3`xGpMPL%BPy@?ukPGT_ksMHGE2V T=$}Vx9DiC~NIJ~S4VC{F8s~HE diff --git a/mods/libox/autohook/build/.build_cache/cd/cdd7dc4994587146ed446897d780874d.txt b/mods/libox/autohook/build/.build_cache/cd/cdd7dc4994587146ed446897d780874d.txt deleted file mode 100644 index f08861a6..00000000 --- a/mods/libox/autohook/build/.build_cache/cd/cdd7dc4994587146ed446897d780874d.txt +++ /dev/null @@ -1,14 +0,0 @@ -{ - errdata = "\27[01m\27[Kcc1:\27[m\27[K \27[01;35m\27[Kwarning: \27[m\27[Kcommand-line option ‘\27[01m\27[K-Weffc++\27[m\27[K’ is valid for C++/ObjC++ but not for C\ -\27[01m\27[Kcc1:\27[m\27[K \27[01;36m\27[Knote: \27[m\27[Kunrecognized command-line option ‘\27[01m\27[K-Wno-unsafe-buffer-usage\27[m\27[K’ may have been intended to silence earlier diagnostics\ -\27[01m\27[Kcc1:\27[m\27[K \27[01;36m\27[Knote: \27[m\27[Kunrecognized command-line option ‘\27[01m\27[K-Wno-gnu-zero-variadic-macro-arguments\27[m\27[K’ may have been intended to silence earlier diagnostics\ -\27[01m\27[Kcc1:\27[m\27[K \27[01;36m\27[Knote: \27[m\27[Kunrecognized command-line option ‘\27[01m\27[K-Wno-newline-eof\27[m\27[K’ may have been intended to silence earlier diagnostics\ -\27[01m\27[Kcc1:\27[m\27[K \27[01;36m\27[Knote: \27[m\27[Kunrecognized command-line option ‘\27[01m\27[K-Wno-extra-semi-stmt\27[m\27[K’ may have been intended to silence earlier diagnostics\ -\27[01m\27[Kcc1:\27[m\27[K \27[01;35m\27[Kwarning: \27[m\27[Kcommand-line option ‘\27[01m\27[K-Weffc++\27[m\27[K’ is valid for C++/ObjC++ but not for C\ -\27[01m\27[Kcc1:\27[m\27[K \27[01;36m\27[Knote: \27[m\27[Kunrecognized command-line option ‘\27[01m\27[K-Wno-gnu-line-marker\27[m\27[K’ may have been intended to silence earlier diagnostics\ -\27[01m\27[Kcc1:\27[m\27[K \27[01;36m\27[Knote: \27[m\27[Kunrecognized command-line option ‘\27[01m\27[K-Wno-unsafe-buffer-usage\27[m\27[K’ may have been intended to silence earlier diagnostics\ -\27[01m\27[Kcc1:\27[m\27[K \27[01;36m\27[Knote: \27[m\27[Kunrecognized command-line option ‘\27[01m\27[K-Wno-gnu-zero-variadic-macro-arguments\27[m\27[K’ may have been intended to silence earlier diagnostics\ -\27[01m\27[Kcc1:\27[m\27[K \27[01;36m\27[Knote: \27[m\27[Kunrecognized command-line option ‘\27[01m\27[K-Wno-newline-eof\27[m\27[K’ may have been intended to silence earlier diagnostics\ -\27[01m\27[Kcc1:\27[m\27[K \27[01;36m\27[Knote: \27[m\27[Kunrecognized command-line option ‘\27[01m\27[K-Wno-extra-semi-stmt\27[m\27[K’ may have been intended to silence earlier diagnostics\ -" -} \ No newline at end of file diff --git a/mods/libox/autohook/build/.deps/autohook/linux/x86_64/release/autohook.c.o.d b/mods/libox/autohook/build/.deps/autohook/linux/x86_64/release/autohook.c.o.d deleted file mode 100644 index 95a6e69d..00000000 --- a/mods/libox/autohook/build/.deps/autohook/linux/x86_64/release/autohook.c.o.d +++ /dev/null @@ -1,35 +0,0 @@ -{ - depfiles = "autohook.o: autohook.c autohook.h utils.c\ -", - depfiles_format = "gcc", - files = { - "autohook.c" - }, - values = { - "/usr/bin/gcc", - { - "-m64", - "-fPIC", - "-std=c11", - "-Ibuild/.gens/autohook/linux/x86_64/release/platform/windows/idl", - "-isystem", - "/usr/include/luajit-2.1", - "-Wall", - "-Wextra", - "-Wpedantic", - "-Wall", - "-Wextra", - "-Weffc++", - "-Wno-extra-semi-stmt", - "-Wno-newline-eof", - "-Wno-declaration-after-statement", - "-Wno-unused-parameter", - "-Wno-unused-function", - "-Wno-missing-prototypes", - "-Wno-unused-macros", - "-Wno-switch-default", - "-Wno-gnu-zero-variadic-macro-arguments", - "-Wno-unsafe-buffer-usage" - } - } -} \ No newline at end of file diff --git a/mods/libox/autohook/build/.deps/autohook/linux/x86_64/release/autohook.h.in.d b/mods/libox/autohook/build/.deps/autohook/linux/x86_64/release/autohook.h.in.d deleted file mode 100644 index 0e18c858..00000000 --- a/mods/libox/autohook/build/.deps/autohook/linux/x86_64/release/autohook.h.in.d +++ /dev/null @@ -1,5 +0,0 @@ -{ - files = { - "autohook.h.in" - } -} \ No newline at end of file diff --git a/mods/libox/autohook/build/.deps/autohook/linux/x86_64/release/libautohook.so.d b/mods/libox/autohook/build/.deps/autohook/linux/x86_64/release/libautohook.so.d deleted file mode 100644 index 5d893c60..00000000 --- a/mods/libox/autohook/build/.deps/autohook/linux/x86_64/release/libautohook.so.d +++ /dev/null @@ -1,15 +0,0 @@ -{ - files = { - "build/.objs/autohook/linux/x86_64/release/autohook.c.o", - "build/.objs/autohook/linux/x86_64/release/utils.c.o" - }, - values = { - "/usr/bin/g++", - { - "-shared", - "-m64", - "-fPIC", - "-lluajit-5.1" - } - } -} \ No newline at end of file diff --git a/mods/libox/autohook/build/.deps/autohook/linux/x86_64/release/utils.c.o.d b/mods/libox/autohook/build/.deps/autohook/linux/x86_64/release/utils.c.o.d deleted file mode 100644 index 1654d89c..00000000 --- a/mods/libox/autohook/build/.deps/autohook/linux/x86_64/release/utils.c.o.d +++ /dev/null @@ -1,35 +0,0 @@ -{ - depfiles = "utils.o: utils.c\ -", - depfiles_format = "gcc", - files = { - "utils.c" - }, - values = { - "/usr/bin/gcc", - { - "-m64", - "-fPIC", - "-std=c11", - "-Ibuild/.gens/autohook/linux/x86_64/release/platform/windows/idl", - "-isystem", - "/usr/include/luajit-2.1", - "-Wall", - "-Wextra", - "-Wpedantic", - "-Wall", - "-Wextra", - "-Weffc++", - "-Wno-extra-semi-stmt", - "-Wno-newline-eof", - "-Wno-declaration-after-statement", - "-Wno-unused-parameter", - "-Wno-unused-function", - "-Wno-missing-prototypes", - "-Wno-unused-macros", - "-Wno-switch-default", - "-Wno-gnu-zero-variadic-macro-arguments", - "-Wno-unsafe-buffer-usage" - } - } -} \ No newline at end of file diff --git a/mods/libox/autohook/build/.objs/autohook/linux/x86_64/release/autohook.c.o b/mods/libox/autohook/build/.objs/autohook/linux/x86_64/release/autohook.c.o deleted file mode 100644 index 6acc417fdbfa4d4128406ea541890accd132cded..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 17288 zcmdT~3vgW3dA=**2gb09aljKBxCTG5CF^C`#s=h?HR~W7jH8JIc9zv@SK4^JD|YW1 zD}!vqN-mp?irqqo7SnMvLsO<{$Km1FE^%c-kwPgWCWfdpq-YwF$dxA;+f9^?LH+;p zxclwhy$%j;XL@G#KECsx?|+>CoO{l_yW7{aw#?%(bnzH>82LMm8pacM=C2#YWusAH zc#UR%_80za*N8ux9`q5KA-72|EV>Rj^k-%S7omGJc}MbGc-Q#&-RaSJW650*B?t?^MsFe zo#%$uO?2^VzPL`c&Az9}GGh}+8Aob#f{1%&*kkilb01~XAL=g3HGfFfjL6pe#>dAq zXFT0~)}{iSP0YTQm*aas0lim?D{Al0zD??dHsKJ}=GIGQu8>%!YtTsF;qU#TXw|zk z-}s$lR|v{N23F`7mH~05Ysi(P{1Qk!>6?k4QnaGTP@(PAAd?9Tr1@Fj8Mg+U)*{{y zaD(F%MZ0IIGprf8W^Ss2%wEghd6>X4fA92vW=L>**q$N|90Wtj1EL2DgQ0BtWOk6o=|EG~*Y|{PFxPyNxQApebWpHGb#V1P+HIo7k`txiH{L;*wA$Nn|eciCl0PDthXazsxY+@coKA zX{cb}W+_93WjaSr(``v2(bSO{-tNC7SG|XQzmkz&Ntc7-GX2FO`JO&&X0Dm}A@b6^ z7byA2Jf0|rj(-Z-$G|bp%;U0~)Iel0G=;?6Y##7uMm+v3YaSunAsVSd-?>zjRP;p7~@CU!W^m+IKwXqZ7|8^d}lquA89(H*qyUfF! z2z{IgC8yyvmo^QT;34`FGtysBw}1Xw`1#8)3zs&zcoP11nW#Jo>!jsbNF;5cga4Zz zzeHAi-Z@yAjPoX~cW?@x?wo?3Id4zFC7eg5-!lVOsI{tZEaLsB@2uZ@t8eVAw?eE> zBi;oAXT4v4lkRyvVx0AU?Swsb-$%=*fo%G9T16kB1=OKdf9{I83%F0{NmlK1sE$|g`IT<2`E}~M0l6Au3wrv}v@Cak;#mMf1&&6~0618~nL6ZQ0fzqK(`ULeKEzJofSU_^J0utlxK% zEtWX#0sDO-(xbaGT_-)eC)3gBoH81tbD6brw3Rq`MjsKIL1Wcz=?xj*NwJ#oFY+BC zeIuz=qQ3V&`Dmu)M%FhxI^WUIv}VYLHk}YF-#6;nM@co}VTHS=5!H|;_C6lv^-_*D zth`xW#E!h@U-$;NHq5SN$u*K1YxOUhE_&LUAY8IjLaeB1^GlXB50FQWd?>l|p-J$a zV>G9Iw$&~@muPcLTg~Dv)TI$+x-P@AxmSz|j<4Uo9P#%y4~yt3zmD@3mBY7-!bjW6 znR@fbJ>bZ9iteCnYwu(U8YqHjMa#K$T*XcF!akDXu8~16?3%|;9}*G%;b!jW>?`-t z$=N@-9$Bf@7d;&$)87-LBbPUNw$afT-AL~3u{XV{Nq!vVdfFJS4u+9=)8>3;bGofFRSxQOT@4hp3$JsdJhW&~+8eSY%5 zX#fqqmv(ihzC@wRiSEnx>?EcAJ&)3n7x(_&rx{RI=?0 ztFMXPo>QzrI(U>W4cU);#c|_vw#Op%nIH1e@OF2QO@+FSP9-UuIZlgYisy9OUdeK5 zIkzk9Q;OqN(&xGMU2?*^_uC|VQDe7^tk+b2so=6%KRV4}I!~1DLn(8*n%^4~ zjUFD%dTBnA=^F9uqE}uc<-0CE+-W5ya!xhn#~bM`1hf3s3HG~~*Q~YZ@m9nj0Gumq zJqZ3`dXS+=an^S_({47w2>2qrM2`$&Lb=BE@P^AqG)qY-0MW zYJB_7^!v`sku9EyL+i4GN4d2edwTa0KgR>f+ug&tsNT<&n4(A9h0Um}r*D_+H3a{# zXd;8qL&n%M!^pbdsNtjn)Gvk_i|`_^cWH&(mk-gCXEL-CQzA{7?hoz?N@?2s$(NG6 z4}|HUBzlD7XFvC4b81)oR3aw|U-QbY)w=Arr=-$;iij6FKmL(n@G_RYvw|(Lu$f4j z9jS1-HBlLjw}y9`;hi1fkQHuSY_=sVb8gBoT7s=+Fxi&g9*$e)EpsELl`z+sk#sy{ zMH6vz{@m1jbHR>aEZS;zB%*OEoOF=Hqp>9$nwy#yvewVY*O5p?t>})h8BcF-A;v_+ zj6}n+)|7*rjdO~8PCcn~OSIJ)h(bM5WTBC=lF@jZ!z7N`XZACmh*yTUcUYZfNiM8f zXoM2Uun|kNN&e=z=s@a?)^NDPYztfFoVHk^B^aw>!73KqWGsk9TM|3XR50F3=i8`h zdm^#T45vcDj&Q4KwTE@xZ0c<@XqmC_j&RJJOPwC!zN8ECvaKzgOc~L5Bw>`&yFJmG zj)fmww;|xa_uhK~>+agT)!4Lp!(D%L?`HF!bxlodanQ1Yp>{Kvwi0Z@f`z6P+!jum zwVZ=>c8aA8)t|+gDE)S%Mxj_d+!lnq;T8^iQyiyK_SzXu=1|JI^r~SrtZ1#SUtS%m zX<6D(8?J4LglZZZmWS%<>gf<_s9shRs&B2YiA2KnHPxZ|x@C2t(6Z{~OINhi)ch!oA{j_o!K9UXBx<#DTWS}#q5(S(8QarcwVKaH=7na>QVxn)TV1=fy1rI?$1(V2kx4(EmPyDcGdz8a@xzCUN8Mj3 zZ;k2d?D^*XhG%DmXXeyNllPJEEW-K6CB}!<*Hr8+TXXfqvNn>Cb*mVs;#R*!RvSzB ztlNJ>G#A{Ds``ysU)E&vA5iuFg8DUf{i~{e5= zpz5zEXg}`J^|Msab``YmwA-&z^(&Z1^IO6^p?{02zqWw?8r!}{RsFMk*6qvx+}3|U z)!$Q~f328)~)3G6n?Fee^SXW znj`^{i*$LAe#}3t#cIFBvn|E1y=V}P(PP#oD#QwfUo9^tbH zXZhb&@SO8zNjkQgIW_ZE!>=J`McSd0zAc`wTNi=0SQ;O`S; z{X_}Eu~F#Ft!l%)A`B;q?@r}Qi-^5`WxrB_ zDH(i(bVvERDUgm+d<1NDcF=Z)R=Io;50Zs^(~(ZKM`TQ81KN8EQ{5kxuglvz?Gf*o#I>jqSJ9N*D2W?O z?7S&Z>MmcEpx6fN%?0V_sI)~>w6~M9{R*0wxbWj>HvKNp`vETN0lyjWy@1~WxL%tv z58|gmeh$e0M&UI4j46OmVSozr%%z{U=SINi0lrw_n&*Iebk{j>*3G2}c#uB?_#Kv z1n@;5p936uMgYGBnF|gs?v9-gMSVyqp}%z zkUs%9_Dh$8NAq_(aJ?sc4tS9NWx$dDCx9;|`*i=F1svn=nIPN{;{x+x7U0;Am4IWv zY<0ntfMfsecfr34cqQ0>1n?@r2LVTaE7X#d-A4Oo1CI7@bipHlqy0TD__Khc{oex| z?SCC`wBI`^-!F)pfTKNafTLfJ06que_L#zTp6fh$8sz7K{0o531N;XLp7+&wIqtw& zH~@3aPD{HuLB(UHv&Ez^tJ(xW9LMRkY9GsfAx{V3sCN(G*zey`xU=8?3gj_vF9MGJ-sj{|{oe1u zb-xb-5Ay#OaO{@}Qwsa{g5sa*z;(aRRk*X?R{@Uv4*<^ZLUg`$0*>*20`P?({~f@w zA726-`{m~@_!!`~0{`__$v8Osy%KPoXYK$T=b2`}(ch;4NBf@#9PNMC1^-XL(f%u^ zmbU*Uz|sC{z|sD@0Z04yyWrme9PK#_cs0cNErsiGaTf=i%KHwyN#WOBE$g-XEQR0T zz~@LYqe0;;hWWo9aLmuI171UIbbh7)$9~BG&N{Wc{A!n97v1TR2K_b2qdl(xj^q7J zz-xj3+%=Mq{i*|eo>$^JKJ_d>rP6`3tz6bBoW;Kj1hYjw)Q+IjsEx`3B&>UcG?T^8caaHz}O`S_bkv9P;Ad z0#yGkkjMBx<&a;(il}@aaDKFCe?J18r{sDiKT*B7cEv4ft~4e^BAt-z|#& zk3pW_F>8CC1)RULYW#WNVVl%6Wt;$cocBHed?oOl1AG)1DEKM|&;+j`m!wK8SFf?*M;qP`KuQS@~N9^2l>1;QXya$N3)M zVIBPAvdIN+1)S#%tv3z)sCO^m7`OevQ%*eEp0@yJ{tuO3!@z_2a}IFipRC?fvp z0DKPUy;SQ$kU}L{1|2VCzbs=evGqj{oPMJmgx(Ilz&Fa&!BrQT3&w-GzBU-R0;~D(SgU* z{X-61e}CTN!1ed%gAQDOf9`YO2iY(x!{V5?M}JQihEpBe$Uptv*i`K_uD=gAI&l5H z_aO(aztiq<;QD*)K?knCyY@M79sgkmuH!6>2K)8*C8H|Uxt+c;(Ai4LbGyDuhGW4h zE4PXV-{-o7OT&yA79*89Q!^-6-CXsLmCOXI()%^yQ=ek;jOWztZ>59i*qm9Um zgFG2h*{SA1-o9{KJq~n!^Bl#vN_)DJWgm<$jq#avVOdN!%;{|ZjB2kQUv?9%UjsFC z!TLELvFP^t{j#pp<5l1Dv#*r>XE-oas^!T(n)a2v;I(F{_|4#lJe7yU(J(lE+(+7e z9lwo)vHl`Gvk0W3PV$D1EXzfoAAoC7p$@B@4Hd52Y1wbk#U%PU-LY+ z1#>#vcc}I=92L&?UDUQz{C2AN?NJ7E{P-1#Zm;84N;ioaPu$2yimMtJyv?3XKWBS> oedf$Pf{Y_`_-GhEci6AYk(G4h?M|uoW1Lu2zAaDo(b@ig09Vwyg8%>k diff --git a/mods/libox/autohook/build/.objs/autohook/linux/x86_64/release/utils.c.o b/mods/libox/autohook/build/.objs/autohook/linux/x86_64/release/utils.c.o deleted file mode 100644 index faa6274ea32b36cc929056941440927e7457f66d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 9248 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/dev/null 2>/dev/null; then - cat "$@" | sha256sum | awk '{ print $1 }' -elif command -v shasum >/dev/null 2>/dev/null; then - cat "$@" | shasum | awk '{ print $1 }' -fi \ No newline at end of file diff --git a/mods/libox/autohook/helpers.lua b/mods/libox/autohook/helpers.lua deleted file mode 100644 index aa3859e9..00000000 --- a/mods/libox/autohook/helpers.lua +++ /dev/null @@ -1,42 +0,0 @@ -if core ~= nil then error('DO NOT RUN THIS FROM LUANTI') end - -function get_sha256(filepaths) - if type(filepaths) == 'string' then - if not os.isfile(filepaths) then - raise('[get_sha256] File not found: ' ..filepaths) - end - filepaths = {filepaths} - elseif type(filepaths) == 'table' then - for i=1, #filepaths do - local filepath = filepaths[i] - if not os.isfile(filepath) then - raise('[get_sha256] File not found: ' ..filepath) - end - end - else - raise('[get_sha256] bad argument #1 (string or table expected, got ' ..type(filepaths) ..')') - end - - -- find_program caches its results, so it's fine to repeatedly call this - import('lib.detect.find_program') - local cmd - local args = {} - if os.is_host('windows') or os.shell() == 'pwsh' then - -- also for pwsh linux user... crazy!! - cmd = find_program('pwsh') or find_program('powershell') - table.join2(args, {'hash.ps1'}, filepaths) - else - cmd = find_program('sh') - table.join2(args, {'hash.sh'}, filepaths) - end - - -- this is so so so cursed, and without select() it's not possible to bring pcall back... - local result - try { function() - result = os.iorunv(cmd, args) - end, catch { function(errors) - print("Failed to compute SHA256: " .. errors) - end } - } - return result:trim() -end \ No newline at end of file diff --git a/mods/libox/autohook/libautohook.so b/mods/libox/autohook/libautohook.so deleted file mode 100755 index dcadd1be40d44bd4a88e772018d032e763b72c39..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 25944 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 f2~&_TlNR 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 HSna<7)IMN| diff --git a/mods/libox/autohook/module-version.txt b/mods/libox/autohook/module-version.txt deleted file mode 100644 index f8b4079a..00000000 --- a/mods/libox/autohook/module-version.txt +++ /dev/null @@ -1 +0,0 @@ -35d53973f1de456e9432d5d69003d54d116507f5b90832ea04f677b7cd3327cd \ No newline at end of file diff --git a/mods/libox/autohook/utils.c b/mods/libox/autohook/utils.c deleted file mode 100644 index 5c9adee7..00000000 --- a/mods/libox/autohook/utils.c +++ /dev/null @@ -1,179 +0,0 @@ -#include -#include -#include -#include -#include - -// a bit of macros never hurt nobody -// also, it's safe to assume that most compilers handle , ##__VA_ARGS__ like GCC -#define MAX_VA_ARGS(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,...) a18 -#define VA_COUNT(...) MAX_VA_ARGS(dummy, ##__VA_ARGS__, 16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0) - -typedef const char* cstr; -typedef char* cstr_mut; -#define CSTR_COUNT(x) sizeof(x)-1 - -// like home -#define nil NULL - -static bool string_eq( - cstr restrict s1, size_t count1, - cstr restrict s2, size_t count2) { - - if (count1 != count2) { return false; } - for (size_t i = 0; i < count1; ++i) { - if (s1[i] != s2[i]) { return false; } - } - return true; -} - -static bool string_startswith( - cstr restrict long_str, size_t long_count, - cstr restrict short_str, size_t short_count) { - - if (long_count < short_count) { return false; } - for (size_t i = 0; i < short_count; ++i) { - if (long_str[i] != short_str[i]) { return false; } - } - return true; -} - -#define LUA_CREGISTRY LUA_REGISTRYINDEX -#define LUA_GLOBALS LUA_GLOBALSINDEX - -// indexes the stack, or a pseudo-index -typedef int lua_Idx; - -// indexes a lua list/array/table, including the tables from pseudo-indices -typedef int lua_Subidx; - -#define L_arg_expect_xx(idx, expect, got) luaL_argerror(L, (idx), \ - lua_pushfstring(L, "%s expected, got %s", (expect), (got))) -#define L_arg_expect_lx(idx, expect, got) luaL_argerror(L, (idx), \ - lua_pushfstring(L, expect " expected, got %s", (got))) -#define L_arg_expect_ll(idx, expect, got) luaL_argerror(L, (idx), expect "expected, got " got) -#define L_arg_expect_xa(idx, expect) luaL_argerror(L, (idx), \ - lua_pushfstring(L, "%s expected, got %s", (expect), luaL_typename(L, (idx)))) -#define L_arg_expect_la(idx, expect) luaL_argerror(L, (idx), \ - lua_pushfstring(L, expect " expected, got %s", luaL_typename(L, (idx)))) - -#define L_carg_expect_xxx(narg, expect, got) \ - luaL_error(L, lua_pushfstring(L, "bad argument #%f to C function '%s' (%s expected, got %s)", (narg), __func__, (expect), (got))) -#define L_carg_expect_xll(narg, expect, got) \ - luaL_error(L, lua_pushfstring(L, "bad argument #%f to C function '%s' (" expect " expected, got " got ")", (narg), __func__)) - -// checks if the pointer is nil/NULL. raise error to Lua runtime -#define assert_ptr(p, narg) \ - if ((p) == nil) { L_carg_expect_xll(narg, "valid pointer", "nil/NULL"); } -// check nil AND non-empty -#define assert_str(p, narg) assert_ptr(p, narg); \ - if ((p)[0] == '\0') { L_carg_expect_xll(narg, "non-empty string", "empty string"); } - -#define L_stack2ref() luaL_ref(L, LUA_CREGISTRY) -static bool lua_ref2stack(lua_State* L, const lua_Subidx ref) { - if (ref == LUA_NOREF || ref == LUA_REFNIL) { return false; } - lua_rawgeti(L, LUA_CREGISTRY, ref); - luaL_unref(L, LUA_CREGISTRY, ref); - return true; -} -#define L_ref2stack(ref) lua_ref2stack(L, ref) - -static bool lua_is_container(lua_State *L, const lua_Idx idx) { - return idx == LUA_CREGISTRY || idx == LUA_GLOBALS || lua_istable(L, idx); -} -#define L_assert_container(idx) \ - if (!lua_is_container(L, (idx))) { L_arg_expect_la(idx, "table or pseudo-index"); } - -#define L_assert_number(idx) \ - if (!lua_isnumber(L, (idx))) { L_arg_expect_la(idx, "number"); } - -#define L_assert_string(idx) \ - if (!lua_isstring(L, (idx))) { L_arg_expect_la(idx, "string"); } - -/* ------------------------ deep getters and setters ------------------------ */ - -static bool lua_deepget_subi(lua_State *L, lua_Idx idx, size_t count, const lua_Subidx* subis) { - L_assert_container(idx); - assert_ptr(subis, 4); - if (count < 1) { - L_carg_expect_xll(3, "positive number of subidx", "bad number of subidx"); - } - if (count == 1) { - lua_rawgeti(L, idx, subis[0]); - // waste of compute... bro just use rawgeti - return false; - } - - const lua_Idx reset = lua_gettop(L); - lua_rawgeti(L, idx, subis[0]); - for (size_t i = 1; i < count; ++i) { - if (!lua_istable(L, -1)) { - lua_settop(L, reset); - return true; - } - lua_rawgeti(L, -1, subis[i]); - } - const lua_Idx got = L_stack2ref(); - lua_settop(L, reset); - L_ref2stack(got); - return false; -} -// lua: (push stack) = (table at idx)[subi1][subi2][subi3][...] -#define L_deepget_subi(idx, ...) \ - lua_deepget_subi(L, (idx), VA_COUNT(__VA_ARGS__), (lua_Subidx[]){ __VA_ARGS__ }) - -static bool lua_deepset_subi(lua_State *L, lua_Idx idx, bool fill_in, size_t count, const lua_Subidx* subis) { - L_assert_container(idx); - assert_ptr(subis, 4); - if (count < 1) { - L_carg_expect_xll(3, "positive number of subidx", "bad number of subidx"); - } - if (count == 1) { - lua_rawseti(L, idx, subis[0]); - // waste of compute... bro just use rawseti - return true; - } - - bool filling_in = false; - const lua_Idx value = L_stack2ref(); - const lua_Idx reset = lua_gettop(L); - lua_rawgeti(L, idx, subis[0]); - if (!lua_istable(L, -1)) { - if (!(filling_in || (fill_in && lua_isnil(L, -1)))) { - lua_settop(L, reset); - return true; - } - filling_in = true; - lua_pop(L, 1); - lua_createtable(L, 0, 1); - lua_pushvalue(L, -1); - lua_rawseti(L, idx, subis[0]); - } - - const size_t last = count - 1; - for (size_t i = 1; i < last; ++i) { - lua_rawgeti(L, -1, subis[i]); - if (!lua_istable(L, -1)) { - if (!(filling_in || (fill_in && lua_isnil(L, -1)))) { - lua_settop(L, reset); - return true; - } - filling_in = true; - lua_pop(L, 1); - lua_createtable(L, 0, 1); - lua_pushvalue(L, -1); - lua_rawseti(L, -2, subis[0]); - } - } - L_ref2stack(value); - lua_rawseti(L, -2, subis[last]); - lua_settop(L, reset); - return false; -} -// lua: (table at idx)[subi1][subi2][subi3][...] = (stack pop) -#define L_deepset_subi(idx, ...) \ - lua_deepset_subi(L, (idx), false, VA_COUNT(__VA_ARGS__), (lua_Subidx[]){ __VA_ARGS__ }) -// lua: (table at idx)[subi1][subi2][subi3][...] = (stack pop) -// fills the subtable in if it's created yet. good for initializing table -#define L_deepset_fill_subi(idx, ...) \ - lua_deepset_subi(L, (idx), true, VA_COUNT(__VA_ARGS__), (lua_Subidx[]){ __VA_ARGS__ }) diff --git a/mods/libox/autohook/xmake.lua b/mods/libox/autohook/xmake.lua deleted file mode 100644 index de19a7b4..00000000 --- a/mods/libox/autohook/xmake.lua +++ /dev/null @@ -1,119 +0,0 @@ -if core ~= nil then error('DO NOT RUN THIS FROM LUANTI') end - - -option('Iluajit') - set_showmenu(true) - set_description('Custom LuaJIT includes/ directory') -option_end() - -option('Lluajit') - set_showmenu(true) - set_description('Custom LuaJIT libs/ directory') -option_end() - -add_requires('luajit', { system = true, configs = { shared = false }, optional = true}) - -local clang_flags = { - "-Wall", "-Wextra", "-Wpedantic", "-Weverything", - -- useless/meh warnings -- - "-Wno-extra-semi-stmt", "-Wno-newline-eof", - "-Wno-declaration-after-statement", "-Wno-unused-parameter", - "-Wno-unused-function", "-Wno-missing-prototypes", "-Wno-unused-macros", - "-Wno-switch-default", - -- other warnings -- - -- only a problem if you're using some wacky compiler - "-Wno-gnu-zero-variadic-macro-arguments", - - -- C + Lua doesn't provide easy ways to protect from this. ignoring... - "-Wno-unsafe-buffer-usage" -} -local gcc_flags = { - "-Wall", "-Wextra", "-Wpedantic", - -- uhh idk -} - -target('autohook') - set_kind('shared') - set_basename('autohook') - set_targetdir('.') - add_files('autohook.c', 'utils.c') - set_configdir('.') - add_configfiles('autohook.h.in') - - set_languages("c11") - - add_packages('luajit') - - on_load(function(target) - import('core.tool.compiler') - local cc = compiler.compargv('dummy.c', { target = target }) - if cc and path.basename(cc):match('clang') then - for i=1,#clang_flags do - target:add('cflags', clang_flags[i]) - end - else - for i=1,#gcc_flags do - target:add('cflags', gcc_flags[i]) - end - end - - local luajit_include = get_config('Iluajit') - if luajit_include then - assert(os.isfile(path.join(luajit_include, 'luajit.h')), - ('Failed finding LuaJIT headers in '):format(luajit_include)) - target:add('includedirs', luajit_include) - end - - local luajit_lib = get_config('Lluajit') - if luajit_lib then - import('lib.detect.find_library') - local found_lib_51 = find_library('luajit-5.1', { luajit_lib }, { kind = 'static' }) - local found_lib_simple = find_library('luajit', { luajit_lib }, { kind = 'static' }) - - assert(found_lib_51 or found_lib_simple, - ('Failed finding LuaJIT library in : '):format(luajit_lib)) - target:add('linkdirs', luajit_lib) - if found_lib_51 then target:add('links', 'luajit-5.1') end - if found_lib_simple then target:add('links', 'luajit') end - end - - import('helpers') - local hash = helpers.get_sha256{'autohook.c', 'utils.c'} - target:set('configvar', 'AUTOHOOK_HASH', hash) - io.writefile("module-version.txt", hash) - end) - - - before_build(function(target) - printf('checking for LuaJIT version ... ') - - local get_luajit_version = [[ -#include -#include -int main(int argc, char** argv) { - puts(LUAJIT_VERSION); - return 0; -}]] - local ok, luajit_version = target:check_csnippets({ test = get_luajit_version }, { - tryrun = true, - output = true, - -- includes = {"path/to/headers.h"}, - configs = {languages = 'c11'}}) - - local errmsg = ('Outdated LuaJIT version! Please update it or build a LuaJIT rolling release (current: %s)'):format(luajit_version) - - -- must at least be 2.1.* - assert(luajit_version:startswith('LuaJIT 2.1.'), errmsg) - - -- this is exactly how LuaJIT developer wants downstream users to check - -- the rolling release versions. the beta versions are 2.1.0. but it's - -- more robust if we can just put which commit to cut off support. Also - -- people might build LuaJIT version that default to 2.1.ROLLING cuz - -- they didn't allow the build script to determine the last commit - -- timestamp. - local supported = 1692580715 -- commit c3459468 first 2.1.ROLLING release - assert(luajit_version == 'LuaJIT 2.1.ROLLING' - or tonumber(luajit_version:sub(12):match('^%d+')) >= supported, errmsg) - - cprint('${bright green}' ..luajit_version) - end) \ No newline at end of file diff --git a/mods/libox/coroutine.lua b/mods/libox/coroutine.lua deleted file mode 100644 index 3cdaa4d7..00000000 --- a/mods/libox/coroutine.lua +++ /dev/null @@ -1,364 +0,0 @@ -local active_sandboxes = {} -local api = {} - - -api.settings = { - memory_treshold = 5, - gc = { - time_treshold = 10 * 60, -- if a sandbox has been untouched then collect it - number_of_sandboxes = 60, - auto = false, - interval = 60 - }, -} - -local settings = minetest.settings - -local function setting(v, thing) - local t = type(v) - local number = function(n) return n end -- noop - if t == "number" then - number = tonumber - end - - if t ~= "boolean" then - return number(settings:get(thing)) - else - return settings:get_bool(thing) - end -end - -local function do_the_settings_thing(name, table) - for k, v in pairs(table) do - if type(v) == "table" then - do_the_settings_thing(name .. "." .. k, v) - else - table[k] = setting(v, name .. "." .. k) or v - end - end -end - -do_the_settings_thing("libox", api.settings) - -local attach_autohook = libox_autohook_module and libox_autohook_module.autohook -local function attach_hook(sandbox) - if sandbox.autohook and attach_autohook then - local hook - if sandbox.in_hook then - hook = sandbox.in_hook() - end - attach_autohook( - sandbox.hook_time or libox.default_hook_time, - (sandbox.time_limit or libox.default_time_limit) / 1000, - hook) - else - debug.sethook(sandbox.in_hook(), "", sandbox.hook_time or libox.default_hook_time) - end -end - -local BYTE_A, BYTE_Z = string.byte("A"), string.byte("Z") -local function rand_text(n) - local out = "" - for _ = 1, n do - out = out .. string.char(math.random(BYTE_A, BYTE_Z)) -- [A-Z] - end - return out -end - - - -function api.create_sandbox(def) - local ID = def.ID or rand_text(10) - local in_hook = def.in_hook - if not (def.autohook and attach_autohook) then - in_hook = in_hook or libox.coroutine.get_default_hook(def.time_limit or libox.default_time_limit) - end - active_sandboxes[ID] = { - code = def.code, - is_garbage_collected = def.is_garbage_collected or true, - env = def.env or {}, - in_hook = in_hook, - function_wrap = def.function_wrap or function(f) return f end, - last_ran = os.clock(), -- for gc and logging - hook_time = def.hook_time or libox.default_hook_time, - size_limit = def.size_limit or 1024 * 1024 * 5, -- 5 megabytes - autohook = def.autohook or false, - } - return ID -end - -function api.create_thread(sandbox) - -- prohibited by mod security anyway, basically bytecode is fancy stuff that allows rce and we dont want that - if sandbox.code:byte(1) == 27 then - return false, "Bytecode was not allowed." - -- *mod security would prevent it anyway* but just in case someone turned that off - end - - local f, msg = loadstring(sandbox.code, "(libox sandbox: coroutine)") - if not f then - return false, msg - end - - - setfenv(f, sandbox.env) - - if rawget(_G, "jit") then - jit.off(f, true) - -- turn jit off for that function and yes this is needed or the user can repeat until false, sorry - end - - f = sandbox.function_wrap(f) - sandbox.thread = coroutine.create(f) - return true -end - -function api.is_sandbox_dead(id) - local sandbox = active_sandboxes[id] - if sandbox == nil then return true end - if sandbox.thread == nil then return false end -- api.run_sandbox will work just fine - if coroutine.status(sandbox.thread) == "dead" then return true end - return false -end - -function api.locals(val, f_thread) - local ret = { - _F = "", -- the function itself, weighed and put using string.dump, if thread this is ignored - _L = {}, -- Locals - _U = {} -- Upvalues - } - - local getinfo, getlocal, getupvalue = debug.getinfo, debug.getlocal, debug.getupvalue - - local index - if type(val) == "thread" then - local level = getinfo(val, 1, "u") - if level ~= nil then - index = 1 - while true do - local k, v = getlocal(val, 1, index) - if k ~= nil then - ret._L[k] = v - else - break - end - index = index + 1 - end - - if level.nups > 0 then - index = 1 - local f = getinfo(val, 1, "f").func - while true do - local k, v = getupvalue(f, index) - if k ~= nil then - ret._U[k] = v - else - break - end - index = index + 1 - end - end - end - elseif type(val) == "function" then - local func_info = getinfo(f_thread, val, "Su") - if not func_info or func_info.what == "C" then - -- C functions are not weighed because... well... they can't be - return {} - end - local f_size = string.dump(val) - ret._F = f_size - index = 1 - while true do - local k, v = getlocal(val, index) - if k ~= nil then - ret._L[k] = v - else - break - end - index = index + 1 - end - if func_info.nups > 0 then - index = 1 - while true do - local k, v = getupvalue(val, index) - if k ~= nil then - ret._U[k] = v - else - break - end - index = index + 1 - end - end - end - return ret -end - -function api.get_size(env, seen, thread, recursed) - local deferred_weigh_locals = {} - if not recursed then - deferred_weigh_locals[#deferred_weigh_locals + 1] = thread - end - - local function internal(x, seen) -- luacheck: ignore - local t = type(x) - if t == "string" then - return #x + 25 - elseif t == "number" then - return 8 - elseif t == "boolean" then - return 1 - elseif t == "table" and not seen[x] then - local cost = 8 - seen[x] = true - for k, v in pairs(x) do - local k_cost = internal(k, seen) - local v_cost = internal(v, seen) - cost = cost + k_cost + v_cost - end - return cost - elseif t == "function" and not seen[x] then - -- oh the fun! - seen[x] = true - deferred_weigh_locals[#deferred_weigh_locals + 1] = x - return 0 -- deffered - elseif t == "thread" and not seen[x] then - seen[x] = true - deferred_weigh_locals[#deferred_weigh_locals + 1] = x - return 0 -- deffered - else - return 0 - end - end - - local retv = internal(env, seen) - if debug.getlocal ~= nil and debug.getupvalue ~= nil then - for i = 1, #deferred_weigh_locals do - local v = deferred_weigh_locals[i] - if not seen[v] then - local their_locals = api.locals(v, thread) - - local size = api.get_size(their_locals, seen, thread, true) - retv = retv + size - end - end - end - - return retv -end - -function api.size_check(env, lim, thread) - if thread == nil then error("Thread is nil! you can't check the size!") end - local size = api.get_size(env, {}, thread, false) - return size < lim -end - -function api.get_default_hook(max_time) - return function() - local time = minetest.get_us_time - - local start_time = time() - return function() - if time() - start_time > max_time then - debug.sethook() - error("Code timed out! Reason: Time limit exceeded, the limit:" .. - tostring(max_time / 1000) .. "ms, the program took:" .. ((time() - start_time) / 1000), 2) - end - end - end -end - -function api.run_sandbox(ID, value_passed) - if libox.disabled then - return false, "Libox is disabled. Please wait until the server admins re-enable it." - end - - local sandbox = active_sandboxes[ID] - if sandbox == nil then - return false, "Sandbox not found. (Garbage collected?)" - end - - sandbox.last_ran = os.clock() - - if sandbox.thread == nil then - local ok, errmsg = api.create_thread(sandbox) - if ok == false then - return false, errmsg - end - end - - local thread = sandbox.thread - if coroutine.status(thread) == "dead" then - return false, "The coroutine is dead, nothing to do." - end - - - local ok, errmsg_or_value - local pcall_ok, pcall_errmsg - -- "nested pcall just in case" i knowww its bad and it sounds bad but yeah i had crashes when there wasnt a pcall adn yeaah - local no_strange_bug_happened = pcall(function() - pcall_ok, pcall_errmsg = pcall(function() - attach_hook(sandbox) - getmetatable("").__index = sandbox.env.string - ok, errmsg_or_value = coroutine.resume(thread, value_passed) - debug.sethook() - end) - debug.sethook() - getmetatable("").__index = string - end) - debug.sethook() - getmetatable("").__index = string - - if not no_strange_bug_happened then - return false, "Strange bug happened, but yes - the sandbox timed out." - end - - local size_check = api.size_check(sandbox.env, sandbox.size_limit, thread) - if not size_check then return false, "Out of memory!" end - - if not pcall_ok then - return false, pcall_errmsg - end - - if not ok then - return false, errmsg_or_value - else - return true, errmsg_or_value - end -end - -function api.garbage_collect() - local number_of_sandboxes = 0 - local to_be_collected = {} - local current_time = os.clock() - - for k, v in pairs(active_sandboxes) do - if v.is_garbage_collected then - number_of_sandboxes = number_of_sandboxes + 1 - - local difftime = current_time - v.last_ran - if difftime > api.settings.gc.time_treshold then - to_be_collected[#to_be_collected + 1] = k - end - end - end - - if number_of_sandboxes < api.settings.gc.number_of_sandboxes then return false end - for i = 1, #to_be_collected do - active_sandboxes[to_be_collected[i]] = nil - end - - return #to_be_collected -end - --- export -api.active_sandboxes = active_sandboxes -libox.coroutine = api - -local function start_timer() - minetest.after(api.settings.gc.interval, function() - api.garbage_collect() - start_timer() - end) -end -if api.settings.gc.auto then - start_timer() -end diff --git a/mods/libox/env.lua b/mods/libox/env.lua deleted file mode 100644 index c3829b45..00000000 --- a/mods/libox/env.lua +++ /dev/null @@ -1,292 +0,0 @@ -local BYTECODE_CHAR = 27 - -local function wrap(f, obj) - return function(...) - return f(obj, ...) - end -end - -function libox.safe.rep(str, n) - if #str * n > 64000 then - error("string length overflow", 2) - end - return string.rep(str, n) -end - -function libox.safe.PcgRandom(seed, seq) - if seq and #seq > 1000 then error("Sequence too large, size limit is 1000", 2) end - local pcg = PcgRandom(seed, seq) - - -- now make the interface - local interface = { - next = wrap(pcg.next, pcg), - rand_normal_dist = function(min, max, num_trials) - if num_trials and num_trials > 50 then - error("too many trials", 2) - end - return pcg:rand_normal_dist(min, max, num_trials) - end - } - return interface -end - -function libox.safe.PerlinNoise(noiseparams) - if type(noiseparams) ~= "table" then return false, "noiseparams is a table, deprecated syntax is not supported." end - - noiseparams.persistence = noiseparams.persistence or noiseparams.persist - noiseparams.persist = nil - local check, element = libox.type_check(noiseparams, { - offset = libox.type("number"), - scale = libox.type("number"), - spread = libox.type_vector, - seed = libox.type("number"), - octaves = libox.type("number"), - persistence = libox.type("number"), - lacunarity = libox.type("number"), - flags = function(x) - if x ~= nil then - return type(x) == "string" - else - return true - end - end, - }) - - if not check then - return false, element - end - - local core = PerlinNoise(noiseparams) - local interface = { - get_2d = wrap(core.get_2d, core), - get_3d = wrap(core.get_3d, core) - } - return interface -end - -function libox.safe.pcall(f, ...) - local ret_values = { pcall(f, ...) } - if not debug.gethook() then - error("Code timed out!", 2) - end - return unpack(ret_values) -end - -function libox.safe.xpcall(f, handler, ...) - local ret_values = { - xpcall(f, function(...) - if not debug.gethook() then - error("Code timed out!", 2) - return - end - return handler(...) - end, ...) - } - - if not debug.gethook() then - error("Code timed out!", 2) - end - - return unpack(ret_values) -end - -function libox.safe.get_loadstring(env) -- chunkname is ignored - return function(code, chunkname) - if chunkname ~= nil then - error("Adding a chunkname is forbidden", 2) - end - if type(code) == "string" and #code > 64000 then error("Code too long :/", 2) end - if string.byte(code, 1) == BYTECODE_CHAR then - error("dont sneak in bytecode (mod security will prevent you anyway)", 2) - end - local f, errmsg = loadstring(code) - if f == nil then - return nil, errmsg - end - setfenv(f, env) - - if rawget(_G, "jit") then - jit.off(f, true) - end - - return f, errmsg - end -end - ---[[ - safe_date is from the mooncontroller mod - licensed under LGPLv3, by OgelGames -]] --- Wraps os.date to only replace valid formats, --- ignoring invalid ones that would cause a hard crash. -local TIME_MAX = 32535244800 -- 01/01/3001 --- todo: change on 01/01/3001 -local function safe_date(str, time) - if type(time) ~= "number" then - time = os.time() - elseif time < 0 or time >= TIME_MAX then - return nil - end - - if type(str) ~= "string" then - return os.date("%c", time) - end - if str == "*t" then - return os.date("*t", time) - end - str = string.gsub(str, "%%[aAbBcdHImMpSwxXyY]", function(s) - return os.date(s, time) - end) - return str -end - -local function datetable() - return os.date("*t") -end - -function libox.create_basic_environment() - --[[ - get the safest, least strict lua environment - *for the "normal" sandbox, when using the "coroutine" sandbox you will need to add coroutine.yield - and edit pcall/xpcall to run coroutine.yield instead of erroring - - ]] - - -- INCLUDES: basic lib (minus coroutine, add that yourself if you need to), string, table, math, bit, os, a bit of minetest, some minetest classes - -- is meant to be added on top of - local env = { - assert = assert, - error = error, - collectgarbage = function(arg) - if arg ~= "count" then error("The only valid mode to collectgarbage is count") end - return collectgarbage("count") - end, - ipairs = ipairs, - pairs = pairs, - next = next, - pcall = libox.safe.pcall, - xpcall = libox.safe.xpcall, - select = select, - unpack = function(t, a, b) -- from mooncontroller - assert(not b or b < 2 ^ 30) - return unpack(t, a, b) - end, - - tonumber = tonumber, - tostring = tostring, - type = type, - - has_autohook = libox.has_autohook, - } - env.loadstring = libox.safe.get_loadstring(env) - env._G = env - - env.string = { - byte = string.byte, - char = string.char, - dump = string.dump, - find = function(s, pattern, init, plain) - if not plain then - error( - "string.find: the fourth parameter (plain) must be true, if you need patterns, use pat.find instead", - 2) - end - return string.find(s, pattern, init, true) - end, - format = string.format, - len = string.len, - lower = string.lower, - rep = libox.safe.rep, - reverse = string.reverse, - sub = string.sub, - upper = string.upper, - -- minetest helpers - trim = string.trim, - split = function(str, delim, include_empty, max_splits, sep_is_pattern) - if sep_is_pattern == true then - error("The fourth argument (sep_is_pattern) must be false", 2) - end - return string.split(str, delim, include_empty, max_splits, false) - end, - } - - env.table = { - insert = table.insert, - maxn = table.maxn, - remove = table.remove, - sort = table.sort, - concat = table.concat, - -- minetest only - indexof = table.indexof, - copy = table.copy, - insert_all = table.insert_all, - key_value_swap = table.key_value_swap, - shuffle = table.shuffle, - - -- luajit only - move = table.move, - } - - - env.math = {} - for _, v in ipairs({ - "abs", "acos", "asin", "atan", "atan2", "ceil", "cos", "cosh", "deg", "exp", "floor", - "fmod", "frexp", "huge", "ldexp", "log", "log10", "max", "min", "modf", "pi", "pow", - "rad", "random", "sin", "sinh", "sqrt", "tan", "tanh", - - -- minetest helpers - "hypot", "sign", "factorial", "round" - }) do - env.math[v] = math[v] - end - - env.bit = table.copy(bit) - - env.vector = table.copy(vector) - env.vector.metatable = nil -- it's useless to add it, and it's undocumented - env.os = { - clock = os.clock, - datetable = datetable, - difftime = os.difftime, - time = os.time, - date = safe_date, - } - - env.minetest = { - hash_node_position = minetest.hash_node_position, - get_position_from_hash = minetest.get_position_from_hash, - formspec_escape = libox.sandbox_lib_f(minetest.formspec_escape), - explode_table_event = libox.sandbox_lib_f(minetest.explode_table_event), - explode_textlist_event = libox.sandbox_lib_f(minetest.explode_textlist_event), - explode_scrollbar_event = libox.sandbox_lib_f(minetest.explode_scrollbar_event), - inventorycube = libox.sandbox_lib_f(minetest.inventorycube), - urlencode = libox.sandbox_lib_f(minetest.urlencode), - rgba = libox.sandbox_lib_f(minetest.rgba), - encode_base64 = libox.sandbox_lib_f(minetest.encode_base64), - decode_base64 = libox.sandbox_lib_f(minetest.decode_base64), - get_us_time = libox.sandbox_lib_f(minetest.get_us_time), - } -- safe minetest functions - env.core = env.minetest - - -- extra global environment stuff - for _, v in ipairs({ - "dump", "dump2" - }) do - env[v] = libox.sandbox_lib_f(_G[v]) - end - - -- oh yeah who could forget... - -- some random minetest stuffs - env.PcgRandom = libox.sandbox_lib_f(libox.safe.PcgRandom) - env.PerlinNoise = libox.sandbox_lib_f(libox.safe.PerlinNoise) - - env.traceback = libox.traceback - env.pat = { - find = libox.pat.find, - match = libox.pat.match, - gmatch = libox.pat.gmatch, - } - - libox.supply_additional_environment(env) -- for mods to use - return env -end diff --git a/mods/libox/env_docs.md b/mods/libox/env_docs.md deleted file mode 100644 index 24c1427f..00000000 --- a/mods/libox/env_docs.md +++ /dev/null @@ -1,99 +0,0 @@ -# The libox environment -- mods *will* extend this, there is nothing really useful that you can do with this if not extended - -# Globals (*) -- assert = unchanged -- error = unchanged -- collectgarbage(arg) = the only valid arg is `count`, may be changed idk -- ipairs = unchanged -- pairs = unchanged -- next = unchanged -- select = unchanged -- unpack = basically unchanged... -- pcall = libox.safe.pcall => pcall doesnt catch timeout errors -- xpcall = libox.safe.xpcall => xpcall doesnt catch timeout errors -- tonumber = unchanged -- tostring = unchanged -- type = unchanged -- loadstring(code) = libox.safe.get_loadstring(env) => does the lame sandboxing stuff like limiting environment, turning off JIT optimizations for the function, also you can't provide a chunkname -- _G = points back to the sandbox environment -- traceback = libox.traceback -- has_autohook = libox.has_autohook - -# String library (string.* or (""):* ) - -- byte = unchanged -- char = unchanged -- dump = unchanged -- find = forced to not match patterns -- format = unchanged, -- len = unchanged, -- lower = unchanged, -- rep = changed to not allow creating GIGANTIC strings, -- reverse = unchanged, -- sub = unchanged, -- upper = unchanged, -- trim = unchanged, from luanti -- split = forced to not match patterns, from luanti - -# Table library (table.*) - -- insert = unchanged -- maxn = unchanged -- remove = unchanged -- sort = unchanged -- indexof = unchanged, from luanti -- copy = unchanged, from luanti -- insert_all = unchanged, from luanti -- key_value_swap = unchanged, from luanti -- shuffle = unchanged, from luanti -- move = unchanged, LUAJIT ONLY -- concat = unchanged - -# Math library (math.*) - -- `abs`, `acos`, `asin`, `atan`, `atan2`, `ceil`, `cos`, `cosh`, `deg`, `exp`, `floor`, -- `fmod`, `frexp`, `huge`, `ldexp`, `log`, `log10`, `max`, `min`, `modf`, `pi`, `pow`, -- `rad`, `random`, `sin`, `sinh`, `sqrt`, `tan`, `tanh`, - -- `hypot`, `sign`, `factorial`, `round` - from luanti - -# Bit library (bit.*) -- Copied, unchanged - -# Vector library (vector.*) -- Copied, removed `vector.metatable` - -# os library (os.*) - -- clock = unchanged, -- datetable = from luacontroller, a date table..., -- difftime = uncahnged, -- time = unchanged, -- date = mooncontroller's safe_date, made to prevent segfaults, - - -# luanti library (core.* or minetest.*) - -- formspec_escape = unchanged*, -- explode_table_event = unchanged*, -- explode_textlist_event = unchanged*, -- explode_scrollbar_event = unchanged*, -- inventorycube = unchanged*, -- urlencode = unchanged*, -- rgba = unchanged*, -- encode_base64 = unchanged*, -- decode_base64 = unchanged*, -- get_us_time = unchanged*, - -\* All of theese functions fail when you give them gigantic string inputs - -# pattern library (pat.*) -- Pure lua implementations of functions `find`, `match`, `gmatch`, and they support patterns -# extra environment stuffs (*) mostly from luanti -- `dump` `dump2` = unchanged -- `PcgRandom` = you are given an interface, where `rand_normal_dist` has limited amount of tries and you call the functions by doing `my_random.func` not `my_random:func` -- `PerlinNoise` = Changed to give an interface, call it like `my_perlin.func` not `my_perlin:func`, also the types in the noiseparams are strict, if it detects a type mismatch it will give you 2 values: `false` and a string, that string being the faulty element (its shallow) - -# notes to mod devs -- Don't be afraid to use userdata, but be afraid where it can get to, it should not be serialized, never. \ No newline at end of file diff --git a/mods/libox/init.lua b/mods/libox/init.lua deleted file mode 100644 index 7dac51b3..00000000 --- a/mods/libox/init.lua +++ /dev/null @@ -1,82 +0,0 @@ -local ie = minetest.request_insecure_environment() -if ie == nil and (debug.getupvalue == nil and debug.getlocal == nil) then - minetest.log("warning", [[ -====Hello, this message is for server owners==== -Libox needs to be a trusted mod for weighing of coroutine sandboxes to work properly. -If it isn't, coroutine sandboxes could fill up your server's memory with local variables and upvalues. - -Libox can re-use debug.getlocal and debug.getupvalue if it is already avaliable in the environment -When adding libox to secure.trusted_mods, be aware that it will expose debug.getlocal and debug.getupvalue -================================================ -]]) -elseif debug.getlocal == nil or debug.getupvalue == nil and ie ~= nil then - -- luacheck:ignore - debug.getlocal = ie.debug.getlocal - debug.getupvalue = ie.debug.getupvalue -end - -if ie and jit then - local MP = core.get_modpath("libox") - local lib - if jit.os == 'Windows' then - lib = MP .. "/autohook/libautohook.dll" - else -- Linux/Unix-like - lib = MP .. "/autohook/libautohook.so" - end - -- Use package.loadlib() instad of require() to prevent using - -- system/other apps' libraries with the same name - local errmsg - libox_autohook_module, errmsg = ie.package.loadlib(lib, 'luaopen_autohook')() - while true do - if not libox_autohook_module or errmsg then - core.log("error", ('[libox] Autohook feature NOT available. Failed loading autohook C module %s:\n%s'):format(lib, errmsg)) - libox_autohook_module = nil - break - end - - local version_file = io.open(MP .. "/autohook/module-version.txt") - local module_version = libox_autohook_module.version - if not version_file or not module_version then - core.log("error", '[libox] Autohook feature NOT available, could not verify its C module compatibility') - libox_autohook_module = nil - break - end - local current_version = version_file:read("*l") - version_file:close() - - local module_version, jit_version = module_version() - if current_version ~= module_version then - core.log("error", '[libox] Autohook feature NOT available, its C module version is incompatible\n' - ..('current: %s | available: %s'):format(current_version, module_version)) - libox_autohook_module = nil - break - end - - if jit_version ~= jit.version then - core.log("error", '[libox] Autohook feature NOT available, its compiled against a different LuaJIT version than Luanti\n' - ..('Luanti: %s | autohook: %s'):format(jit.version, jit_version)) - libox_autohook_module = nil - end - - core.log("info", '[libox] Autohook feature available') - break - end -else - core.log("info", '[libox] Autohook feature NOT available') -end - -local MP = minetest.get_modpath(minetest.get_current_modname()) -dofile(MP .. "/main.lua") - --- Files that are executed sync only, coroutine.lua and *.test.lua -dofile(MP .. "/coroutine.lua") - -libox_autohook_module = nil - --- async files -minetest.register_async_dofile(MP .. "/main.lua") - -local test = MP .. "/test" -dofile(test .. "/basic_testing.lua") -dofile(test .. "/coroutine.test.lua") -dofile(test .. "/normal.test.lua") \ No newline at end of file diff --git a/mods/libox/main.lua b/mods/libox/main.lua deleted file mode 100644 index 36d4ed30..00000000 --- a/mods/libox/main.lua +++ /dev/null @@ -1,18 +0,0 @@ -libox = { - safe = {}, - supply_additional_environment = function(...) return ... end, -- for other mods to do their stuff - default_hook_time = 20, - default_time_limit = 3000, -- 3ms - disabled = false, - in_sandbox = false, -} - -if libox_autohook_module then - libox.has_autohook = true -end - -local MP = minetest.get_modpath("libox") -dofile(MP .. "/env.lua") -dofile(MP .. "/utils.lua") -dofile(MP .. "/normal.lua") -libox.pat = loadfile(MP .. "/pat.lua")() diff --git a/mods/libox/mod.conf b/mods/libox/mod.conf deleted file mode 100644 index bfb6c237..00000000 --- a/mods/libox/mod.conf +++ /dev/null @@ -1,6 +0,0 @@ -title = Libox -name = libox -description = A sandboxing library -optional_depends = dbg -min_minetest_version = 5.8 -supported_games = * \ No newline at end of file diff --git a/mods/libox/normal.lua b/mods/libox/normal.lua deleted file mode 100644 index 7f9ec048..00000000 --- a/mods/libox/normal.lua +++ /dev/null @@ -1,51 +0,0 @@ -local BYTECODE_CHAR = 27 - - -function libox.normal_sandbox(def) - if libox.disabled then - return false, "Libox is disabled. Please wait until the server admins re-enable it." - end - - local code = def.code - local env = def.env - local error_handler = def.error_handler or libox.unsafe_traceback - local in_hook = def.in_hook or libox.get_default_hook(def.max_time) - local function_wrap = def.function_wrap or function(f) return f end - - if code:byte(1) == BYTECODE_CHAR then - return false, "Bytecode is not allowed." -- mod security prevents it anyway, just making sure - end - - local f, msg = loadstring(code, "(libox sandbox: normal)") - if not f then return nil, msg end - setfenv(f, env) - - - if rawget(_G, "jit") then - jit.off(f, true) -- turn jit off for that function and yes this is needed or the user can `repeat until false`, sorry - end - - f = function_wrap(f) - - --local old_hook = { debug.gethook() } - - local ok, ret = false, "Something wrong happened" - - pcall(function() -- this is cursed because of a cursed bug - debug.sethook(in_hook, "", def.hook_time or libox.default_hook_time) - getmetatable("").__index = env.string - ok, ret = xpcall(f, function(...) - debug.sethook() -- try to fix a potential bug where someone can trigger a debug hook at just the right time for luanti to crash - return error_handler(...) - end) - debug.sethook() - getmetatable("").__index = string - end) - debug.sethook() - getmetatable("").__index = string -- OK HOPEFULLY FIX THAT BUG - if not ok then - return false, ret - else - return true, ret - end -end diff --git a/mods/libox/pat.lua b/mods/libox/pat.lua deleted file mode 100644 index a5661bda..00000000 --- a/mods/libox/pat.lua +++ /dev/null @@ -1,484 +0,0 @@ ---[========================================================================[-- - - Lua pattern matching library (minus string.gsub) ported to Lua. - - Copyright © 1994–2018 Lua.org, PUC-Rio. - Copyright © 2019 Pedro Gimeno Fortea. - - 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 LUA_MAXCAPTURES = 32 - -local CAP_UNFINISHED = -1 -local CAP_POSITION = -2 - - -local L_ESC = 37 -- 37='%' --- only used for string.find(x, y, z, true) --- local SPECIALS = '^$*+?.([%-' - -local function LUA_QL(x) - return "'" .. x .. "'" -end - -local function check_capture(ms, l) - l = l - 48 -- 48='0' - if l < 1 or l > ms.level or ms.capture[l].len == CAP_UNFINISHED then - return error("invalid capture index") - end - return l -end - -local function capture_to_close(ms) - local level = ms.level - while level > 0 do - if ms.capture[level].len == CAP_UNFINISHED then - return level - end - level = level - 1 - end - return error("invalid pattern capture") -end - -local function classend(pat, p) - local cc = pat:byte(p) - p = p + 1 - if cc == L_ESC then - if (pat:byte(p) or 0) == 0 then - return error("malformed pattern (ends with " .. LUA_QL('%') .. ")") - end - return p + 1 - end - if cc == 91 then -- 91='[' - if pat:byte(p) == 94 then -- 94='^' - p = p + 1 - end - repeat -- look for a `]' - cc = pat:byte(p) or 0 - p = p + 1 - if cc == 0 then - return error("malformed pattern (missing " .. LUA_QL(']') .. ")") - end - if cc == L_ESC then - if (pat:byte(p) or 0) ~= 0 then - p = p + 1 - end - end - until pat:byte(p) == 93 -- 93=']' - return p + 1 - end - return p -end - -local function match_class(c, cl) - local u = cl - cl % 64 + cl % 32 -- upper case - local negate = cl == u -- true if uppercase - local res - if u == 65 then -- 65='A' - res = c >= 65 and c <= 90 or c >= 97 and c <= 122 -- 65='A', 90='Z', 97='a', 122='z' - elseif u == 67 then -- 67='C' - res = c < 32 or c == 127 - elseif u == 68 then -- 68='D' - res = c >= 48 and c <= 57 -- 48='0', 57='9' - elseif u == 76 then -- 76='L' - res = c >= 97 and c <= 122 -- 97='a', 122='z' - elseif u == 80 then -- 80='P' - res = c >= 33 and c <= 47 or c >= 58 and c <= 64 - or c >= 91 and c <= 96 or c >= 123 and c <= 126 - elseif u == 83 then -- 83='S' - res = c == 9 or c >= 10 and c <= 13 or c == 32 -- 9=HT, 10=LF, 13=CR, 32=' ' - elseif u == 85 then -- 85='U' - res = c >= 65 and c <= 90 - elseif u == 87 then -- 87='W' - res = c >= 65 and c <= 90 or c >= 97 and c <= 122 -- 65='A', 90='Z', 97='a', 122='z' - or c >= 48 and c <= 57 -- 48='0', 57='9' - elseif u == 88 then -- 88='X' - res = c >= 65 and c <= 70 or c >= 97 and c <= 102 -- 65='A', 70='F', 97='a', 102='f' - or c >= 48 and c <= 57 -- 48='0', 57='9' - elseif u == 90 then - res = c == 0 - else - return c == cl - end - return negate ~= res -end - -local function matchbracketclass(c, pat, p, ec) - local sig = true - p = p + 1 - if pat:byte(p) == 94 then -- 94='^' - sig = false - p = p + 1 - end - while p < ec do - local cc = pat:byte(p) - if cc == L_ESC then - p = p + 1 - if match_class(c, pat:byte(p)) then - return sig - end - elseif pat:byte(p + 1) == 45 and p + 2 < ec then -- 45='-' - p = p + 2 - if cc <= c and c <= pat:byte(p) then - return sig - end - elseif cc == c then - return sig - end - p = p + 1 - end - return not sig -end - -local function singlematch(c, pat, p, ep) - local cc = pat:byte(p) - if cc == 46 then -- 46='.' - return true - end - if cc == L_ESC then - return match_class(c, pat:byte(p + 1)) - end - if cc == 91 then -- 91='[' - return matchbracketclass(c, pat, p, ep - 1) - end - return cc == c -end - -local match - -local function matchbalance(ms, str, s, pat, p) - local b = pat:byte(p) - local e = pat:byte(p + 1) - if (b or 0) == 0 or (e or 0) == 0 then - return error("unbalanced pattern") - end - if str:byte(s) ~= b then - return false - end - local cont = 1 - s = s + 1 - while s < ms.src_end do - local cc = str:byte(s) - if cc == e then - cont = cont - 1 - if cont == 0 then - return s + 1 - end - elseif cc == b then - cont = cont + 1 - end - s = s + 1 - end - return false -end - -local function max_expand(ms, str, s, pat, p, ep) - local i = 0 -- counts maximum expand for item - while s + i < ms.src_end and singlematch(str:byte(s + i), pat, p, ep) do - i = i + 1 - end - while i >= 0 do - local res = match(ms, str, s + i, pat, ep + 1) - if res then return res end - i = i - 1 -- else it didn't match; reduce 1 repetition to try again - end - return false -end - -local function min_expand(ms, str, s, pat, p, ep) - repeat - local res = match(ms, str, s, pat, ep + 1) - if res then - return res - end - if s >= ms.src_end or not singlematch(str:byte(s), pat, p, ep) then - return false - end - s = s + 1 - until false -end - -local function start_capture(ms, str, s, pat, p, what) - local level = ms.level + 1 - if level > LUA_MAXCAPTURES then - return error("too many captures") - end - if not ms.capture[level] then - ms.capture[level] = {} - end - ms.capture[level].init = s - ms.capture[level].len = what - ms.level = level - local res = match(ms, str, s, pat, p) - if not res then - ms.level = ms.level - 1 - end - return res -end - -local function end_capture(ms, str, s, pat, p) - local l = capture_to_close(ms) - ms.capture[l].len = s - ms.capture[l].init - local res = match(ms, str, s, pat, p) - if not res then - ms.capture[l].len = CAP_UNFINISHED - end - return res -end - -local function substrcomp(str, start1, start2, len) - for i = start1, start1 + len - 1 do - if str:byte(i) ~= str:byte(i + (start2 - start1)) then - return false - end - end - return true -end - -local function match_capture(ms, str, s, l) - l = check_capture(ms, l) - local len = ms.capture[l].len - if ms.src_end - s >= len and substrcomp(str, ms.capture[l].init, s, len) then - return s + len - end - return false -end - --- this is local already, don't add 'local' or it will fail -match = function(ms, str, s, pat, p) - local cc = pat:byte(p) or 0 - if cc == 40 then -- 40='(' - -- start capture - if pat:byte(p + 1) == 41 then -- 41=')' - -- position capture - return start_capture(ms, str, s, pat, p + 2, CAP_POSITION) - end - return start_capture(ms, str, s, pat, p + 1, CAP_UNFINISHED) - end - if cc == 41 then -- 41=')' - -- end capture - return end_capture(ms, str, s, pat, p + 1) - end - if cc == L_ESC then - cc = pat:byte(p + 1) - if cc == 98 then -- 98='b' - -- balanced string - s = matchbalance(ms, str, s, pat, p + 2) - if not s then - return false - end - return match(ms, str, s, pat, p + 4) - end - if cc == 102 then -- 102='f' - -- frontier - p = p + 2 - if pat:byte(p) ~= 91 then -- 91='[' - return error("missing " .. LUA_QL('[') .. " after " - .. LUA_QL('%f') .. " in pattern") - end - local ep = classend(pat, p) - local previous = str:byte(s - 1) or 0 - if matchbracketclass(previous, pat, p, ep - 1) - or not matchbracketclass(str:byte(s) or 0, pat, p, ep - 1) - then - return false - end - return match(ms, str, s, pat, ep) - end - if cc >= 48 and cc <= 57 then -- 48='0', 57='9' - -- capture results (%0-%9)? - s = match_capture(ms, str, s, cc) - if not s then - return false - end - return match(ms, str, s, pat, p + 2) - end - cc = -1 -- don't match anything else until default - end - if cc == 0 then -- end of pattern - return s - end - if cc == 36 then -- 36='$' - if (pat:byte(p + 1) or 0) == 0 then -- is the `$' the last char in pattern? - return s == ms.src_end and s -- check end of string - end - -- else fall through to default - end - - -- default - local ep = classend(pat, p) - local m = s < ms.src_end and singlematch(str:byte(s), pat, p, ep) - cc = pat:byte(ep) or 0 - if cc == 63 then - if m then - local res = match(ms, str, s + 1, pat, ep + 1) - if res then - return res - end - end - return match(ms, str, s, pat, ep + 1) - end - if cc == 42 then -- 42='*' - -- 0 or more repetitions - return max_expand(ms, str, s, pat, p, ep) - end - if cc == 43 then -- 43='+' - -- 1 or more repetitions - return m and max_expand(ms, str, s + 1, pat, p, ep) - end - if cc == 45 then -- 45='-' - -- 0 or more repetitions (minimum) - return min_expand(ms, str, s, pat, p, ep) - end - return m and match(ms, str, s + 1, pat, ep) -end - --- lmemfind not implemented - only used for string.find(x, y, z, true) - -local function push_onecapture(ms, i, str, s, e) - if i > ms.level then - if i ~= 1 then - return error("invalid capture index") - end - ms.captures[#ms.captures + 1] = str:sub(s, e - 1) - else - local l = ms.capture[i].len - if l == CAP_UNFINISHED then - return error("unfinished capture") - end - if l == CAP_POSITION then - ms.captures[#ms.captures + 1] = ms.capture[i].init - else - ms.captures[#ms.captures + 1] = str:sub(ms.capture[i].init, ms.capture[i].init + l - 1) - end - end -end - -local function push_captures(ms, str, s, e) - local nlevels = ms.level - if nlevels == 0 and s then - nlevels = 1 - end - for i = 1, nlevels do - push_onecapture(ms, i, str, s, e) - end -end - -local function posrelat(pos, len) - if pos < 0 then pos = pos + len + 1 end - return pos >= 1 and pos or 1 -end - -local string_find = string.find - -local SPECIALS = { - [("^"):byte(1)] = true, - [("$"):byte(1)] = true, - [("*"):byte(1)] = true, - [("+"):byte(1)] = true, - [("?"):byte(1)] = true, - [("."):byte(1)] = true, - [("("):byte(1)] = true, - [("["):byte(1)] = true, - [("%"):byte(1)] = true, - [("-"):byte(1)] = true, - [0] = true -} - -local function specials_free(s) - for i = 1, #s do - if SPECIALS[s:byte(i)] then - if s:byte(i) == 0 then - return true -- stop at first NUL - end - return false - end - end - return true -end - -local function str_find_aux(find, str, pat, init, explicit) - local l1 = #str - init = posrelat(init or 1, l1) - if init < 1 then - init = 1 - elseif init > l1 + 1 then - init = l1 + 1 - end - if find and (explicit or specials_free(pat)) then -- explicit request? - -- do a plain search - return string_find(str, pat, init, true) - end - local p = 1 - local anchor = false - if pat:byte(1) == 94 then -- 94='^' - p = p + 1 - anchor = true - end - local s1 = init - local ms = { captures = {}, capture = {}, src_end = l1 + 1 } - repeat - ms.level = 0 - local res = match(ms, str, s1, pat, p) - if res then - if find then - push_captures(ms, str, false, 0) - return s1, res - 1, unpack(ms.captures) - end - push_captures(ms, str, s1, res) - return unpack(ms.captures) - end - s1 = s1 + 1 - until anchor or s1 > ms.src_end - return nil -end - -local function str_find(str, pat, init, explicit) - return str_find_aux(true, str, pat, init, explicit) -end - -local function str_match(str, pat, init) - return str_find_aux(false, str, pat, init) -end - -local function gmatch(str, pat) - local init = 1 - local ms = { captures = {}, capture = {}, src_init = str, src_end = #str + 1 } - local function gmatch_aux() - for i = 1, #ms.captures do ms.captures[i] = nil end - for src = init, ms.src_end do - ms.level = 0 - local e = match(ms, str, src, pat, 1) - if e then - local newstart = e - if e == src then newstart = newstart + 1 end -- empty match? go at least one position - init = newstart - push_captures(ms, str, src, e) - return unpack(ms.captures) - end - end - end - return gmatch_aux -end - - -return { find = str_find, match = str_match, gmatch = gmatch } diff --git a/mods/libox/settingtypes.txt b/mods/libox/settingtypes.txt deleted file mode 100644 index df47521a..00000000 --- a/mods/libox/settingtypes.txt +++ /dev/null @@ -1,24 +0,0 @@ -# Enables automatic coroutine sandbox garbage -# collection, this is only nessesary when: -# 1) You have a mod that does not clean up sandboxes after itself -# - Also, unloaded areas may be a huge issue -# 2) You have way too many sandboxes running -# is experimental -libox.gc.auto (Enable automatic garbage collection) bool false - - -# (In seconds) If a coroutine sandbox has been untouched -# for this long, garbage collection may remove it -libox.gc.time_treshold (Garbage collection time treshold) float 600 - - -# Garbage collection will start to -# actually do stuff when there are this -# many coroutine sandboxes -libox.gc.number_of_sandboxes (Garbage collection "number of sandboxes" treshold) int 60 - -# In seconds -# "How often should the gc be executed" -# Only works when Automatic gc is enabled -# (gc = garbage collection) -libox.gc.interval (Garbage collection interval) int 60 \ No newline at end of file diff --git a/mods/libox/test/basic_testing.lua b/mods/libox/test/basic_testing.lua deleted file mode 100644 index e3755e0c..00000000 --- a/mods/libox/test/basic_testing.lua +++ /dev/null @@ -1,81 +0,0 @@ --- this is a very crappy testing framework i came up with --- combine the best of mtt and mineunit i guess (mtt is able to test weird async easily, i love it) --- with some terrible code of course -local api = {} -local tests = {} - - - -local function core(test) - local function get_success(name) - return function() minetest.log(name .. " : success") end - end - local function get_failure(name) - return function() minetest.log(name .. " : failure") end - end - local function get_custom(name) - return function(str) minetest.log(name .. " : " .. str) end - end - - local function get_assert(name) - return function(cond) - if cond then - get_success(name)() - else - get_failure(name)() - end - end - end - - test[2](get_assert(test[1]), get_success(test[1]), get_failure(test[1]), get_custom(test[1])) -end - -function api.run_known_test(test) - if not test.ignore_async then - minetest.handle_async(core, function() end, test) - end - core(test) -end - -function api.run_test(name, name2) - local category = tests[name] - - local test - for _, v in ipairs(category) do - if v[1] == name2 then - test = name2 - break - end - end - assert(test, "Test not found") - api.run_known_test(test) -end - -function api.run_category(name) - local category = tests[name] - - assert(category, "Category not found") - for _, v in ipairs(category) do - api.run_known_test(v) - end -end - -function api.run_tests() - for k, _ in pairs(tests) do - minetest.log("========" .. k .. "========") - api.run_category(k) - end -end - -function api.get_it(name, ignore_async) -- create test - return function(name2, f) - tests[name][#tests[name] + 1] = { name2, f, ignore_async = ignore_async } -- preserve order - end -end - -function api.describe(name, f, ignore_async) -- create category - tests[name] = {} - f(api.get_it(name, ignore_async)) -end - -libox.test = api diff --git a/mods/libox/test/coroutine.test.lua b/mods/libox/test/coroutine.test.lua deleted file mode 100644 index 78b568c0..00000000 --- a/mods/libox/test/coroutine.test.lua +++ /dev/null @@ -1,273 +0,0 @@ -libox.test.describe("coroutine sandbox", function(it) - it("Can yield", function(assert) - local sandbox = libox.coroutine.create_sandbox({ - code = [[ -local count = 0 -repeat - count = count+1 - coroutine.yield(count) -until false -]], - env = { - coroutine = { - yield = coroutine.yield - } - }, - }) - - local values = { - select(2, libox.coroutine.run_sandbox(sandbox)), -- 1 - select(2, libox.coroutine.run_sandbox(sandbox)), -- 2 - select(2, libox.coroutine.run_sandbox(sandbox)), -- 3 - select(2, libox.coroutine.run_sandbox(sandbox)), -- 4 - } - - local succ = (values[1] == 1) and (values[2] == 2) - and (values[3] == 3) and (values[4] == 4) - if not succ then - minetest.debug(dump(values)) - end - assert(succ) - end) - - it("Limits time", function(assert) - local sandbox = libox.coroutine.create_sandbox({ - code = "repeat until false", - env = {}, - }) - local ok = libox.coroutine.run_sandbox(sandbox) - assert(not ok) - end) - - it("Limits environment size", function(assert) - local sandbox = libox.coroutine.create_sandbox({ - code = "a = string.rep('a',1000); coroutine.yield()", - env = { - string = { - rep = string.rep, - -- Never let the user get arbitrary string.rep, or the user can create terabytes of strings... - -- we are giving it to the user here for testing - }, - }, - size_limit = 1000 - - }) - local _, errmsg = libox.coroutine.run_sandbox(sandbox) - assert(errmsg == "Out of memory!") - end) - - it("Limits circular references", function(_, success) - local env = {} - env._G = env - env.f = function() - --local a = env._G - return env._G - end - local sandbox = libox.coroutine.create_sandbox({ - code = [[ - local e = _G -- Hehe i am an unsuspecting user and i am sure this won't be a mistake - coroutine.yield() - ]], - -- When having _G as the environment - -- it simply stack overflows? this is like... bad... yeah - -- old comment, i fixed that actually, see down - env = env, - size_limit = 1000, - time_limit = 1000000 -- 1 million microseconds, can you imagine that (that's definitely not 1 second) - - }) - - libox.coroutine.run_sandbox(sandbox) - success() - end) - - it("Limits local variables", function(assert) - --[[ - IMPORTANT: This fails when there is no access to debug.getlocal - ]] - - local sandbox = libox.coroutine.create_sandbox({ - code = "local a = string.rep('a',1000); coroutine.yield(); coroutine.yield()", - env = { - string = { - rep = string.rep, - }, - coroutine = { - yield = coroutine.yield - }, - }, - size_limit = 1000, - time_limit = 1000000, - - }) - local _, errmsg = libox.coroutine.run_sandbox(sandbox) - assert(errmsg == "Out of memory!") - end) - - it("Really limits local variables...", function(assert) - --[[ - This fails when there is no access to debug.getlocal - ]] - - local sandbox = libox.coroutine.create_sandbox({ - code = [[ - function evil() - local a = string.rep('a',1000) - coroutine.yield(); - end - evil(); - coroutine.yield(); - coroutine.yield() - ]], - env = { - string = { - rep = string.rep, - }, - coroutine = { - yield = coroutine.yield - }, - }, - size_limit = 1000, - time_limit = 1000000 - - }) - local _, errmsg = libox.coroutine.run_sandbox(sandbox) - assert(errmsg == "Out of memory!") - end) - - it("Limits upvalues", function(assert) - --[[ - this fails when we cant look up upvalues - ]] - local sandbox = libox.coroutine.create_sandbox({ - code = [[ - function get_evil() - local evil = string.rep('a', 60000000) - return function() - return evil - end - end - local evil = get_evil() - coroutine.yield() - ]], - env = { - string = { - rep = string.rep, - }, - coroutine = { - yield = coroutine.yield - }, - }, - size_limit = 1000, - time_limit = 1000000 - - }) - local _, errmsg = libox.coroutine.run_sandbox(sandbox) - assert(errmsg == "Out of memory!") - end) - - it( - "Weighing _G", - function(_, _, _, custom) - local env = libox.create_basic_environment() - libox.coroutine.get_size(env, {}, coroutine.create(function() end)) - -- JIT it up a little, idk man - - local sandbox = libox.coroutine.create_sandbox({ - code = [[ - local e = _G - coroutine.yield() - ]], - -- yeah, it used to stack overflow but now with a minor rewrite it doesn't - env = _G, - size_limit = 1000, - time_limit = 1000000 - }) - - local t1 = minetest.get_us_time() - libox.coroutine.run_sandbox(sandbox) - local sandboxd = libox.coroutine.active_sandboxes[sandbox] - custom("time:" .. - (minetest.get_us_time() - t1) / 1000 .. "ms" .. - " size:" .. libox.coroutine.get_size(sandboxd.env, {}, sandboxd.thread) - .. - " digiline sanitize thinks:" .. - ({ libox.digiline_sanitize(env, true) })[2] .. " lua gc thinks: " .. collectgarbage("count") * 1024 - ) - end) - it("Can detect if sandbox is dead", function(assert) - local sandbox = libox.coroutine.create_sandbox({ - code = "return", - env = {}, - size_limit = 1000, - time_limit = 1000 - }) - libox.coroutine.run_sandbox(sandbox) - assert(libox.coroutine.is_sandbox_dead(sandbox)) - end) - it("Can collect garbage", function(_, _, _, custom) - local sandboxes = {} - local num = 50 - local activation_treshold = 10 - local env = libox.create_basic_environment() - local fake_time_treshold = 50 - - local response = "\n" - - response = response .. - "Size of environment: " - .. libox.coroutine.get_size(env, {}, coroutine.create(function() end), false) .. "\n" - response = response .. "Number of sandboxes that will get created:" .. num .. "\n" - response = response .. "Activation treshold (number of sandboxes):" .. activation_treshold .. "\n" - response = response .. "Activation treshold (time, faked):" .. fake_time_treshold .. "s \n" - - local active = libox.coroutine.active_sandboxes - - local function map_bool(n) - if n == 1 then return true else return false end - end - local function funny_if(c, t, f) - if c then return t else return f end - end - - for i = 1, num do - sandboxes[i] = libox.coroutine.create_sandbox({ - code = "coroutine.yield()", - env = env, - size_limit = 10000, - time_limit = 10000, - is_garbage_collected = map_bool(math.random(0, 1)) - }) - - local actual_sandbox = active[sandboxes[i]] - actual_sandbox.last_ran = funny_if(math.random() < 0.5, 0, os.clock()) - end - - - local function dumbcount(t) - local count = 0 - for _ in pairs(t) do count = count + 1 end - return count - end - - response = response .. "number of sandboxes currently: " .. dumbcount(active) .. "\n" - - local original_settings = table.copy(libox.coroutine.settings) - - libox.coroutine.settings.gc.time_treshold = fake_time_treshold - libox.coroutine.settings.gc.number_of_sandboxes = activation_treshold - - libox.coroutine.garbage_collect() - - libox.coroutine.settings = original_settings - - response = response .. - "number of sandboxes after collection (it should remain high because their 'state' is random): " .. - dumbcount(active) .. "\n" - - - libox.coroutine.active_sandboxes = {} - response = response .. "Cleared the mess" - custom(response) - end) -end, true) diff --git a/mods/libox/test/normal.test.lua b/mods/libox/test/normal.test.lua deleted file mode 100644 index 4bbe2d09..00000000 --- a/mods/libox/test/normal.test.lua +++ /dev/null @@ -1,227 +0,0 @@ -libox.test.describe("Normal sandbox (tests the environment, mostly)", function(it) - it("Doesn't do bytecode", function(assert) - -- mod security prevents it anyway - assert(not libox.normal_sandbox({ - code = string.dump(assert), - env = {}, - in_hook = function() end, - })) - end) - it("Limits time", function(assert) - assert(not libox.normal_sandbox({ - code = "repeat until false ", - env = {}, - max_time = 1000 - })) - end) - it("Handles pcall correctly", function(assert) - assert(not libox.normal_sandbox({ - code = "pcall(function() repeat until false end)", - env = libox.create_basic_environment(), - max_time = 1000 - })) - end) - it("Handles xpcall correctly", function(assert) - assert(not libox.normal_sandbox({ - code = "xpcall(function() error('yeh') end,function() repeat until false end)", - env = libox.create_basic_environment(), - max_time = 1000 - })) - end) - it("Isn't vurnable to severe trollery", function(_, _, bad, custom) - local t1 = minetest.get_us_time() - local ok, err = libox.normal_sandbox({ - code = [[ - local x = "." - repeat - x = x .. x - until false - ]], - env = {}, - max_time = 10000, -- 10 milis for this - }) - local t2 = minetest.get_us_time() - if ok then - bad() - else - custom("took " .. (t2 - t1) .. "us, sandbox was given 10 000 us, for debug: the error was: " .. dump(err)) - end - end) - it("Can loadstring", function(assert) - assert(libox.normal_sandbox({ - code = [[ - assert( - loadstring( - "return 'hi'" - ) - ) - ]], - env = libox.create_basic_environment(), - max_time = 1000, - })) - end) - it("Can loadstring securely", function(assert) - assert(not libox.normal_sandbox({ - code = [[ - loadstring('assert(debug)')() - -- we don't use minetest as an example - -- because libox.create_basic_environment already creates a global with that name - ]], - env = libox.create_basic_environment(), - max_time = 1000, - })) - end) - it("Can handle weird recursive shenanigans (that mostly exploit traceback)", function(_, _, bad, custom) - --[[ - This attempts to abuse libox.traceback to create a gigantic - error message and force several executions of debug.getinfo - - (Now fixed, the limit is 20 debug.getinfo's before just stopping) - ]] - local code = [[ - pcall(loadstring(code)()) - ]] - local env = libox.create_basic_environment() - env.code = code - - local t1 = minetest.get_us_time() - local ok, _ = libox.normal_sandbox({ - code = code, - env = env, - max_time = 10000 - }) - local t2 = minetest.get_us_time() - if ok then - bad() - else - custom("took: " .. (t2 - t1) .. "us, sandbox was given 10 000 us") - end - end) - it("Can't abuse string.rep", function(assert, _, _, _) - assert(not libox.normal_sandbox({ - code = "string.rep('a',9999999)", - env = libox.create_basic_environment(), - max_time = 10000, - })) - end) - it("Can limit string length on functions that probably need it", function(assert) - assert(not libox.normal_sandbox({ - code = [[ - local str = string.rep(":",64000) - str = str .. str - minetest.urlencode(str) - ]], - max_time = 10000, - env = libox.create_basic_environment() - })) - end) - - it("Can check types (basic)", function(assert) - local type_string = function(x) return type(x) == "string" end - local result1 = libox.type_check({ - a = "lol", - b = { - c = "lol" - } - }, { - a = type_string, - b = { - c = type_string - } - }) == true - - local result2 = libox.type_check({ - a = "lol", - b = { - c = "lol", - d = "funny (i am not supposed to be here)", - } - }, { - a = type_string, - b = { - c = type_string - } - }) == false - - local result3 = libox.type_check({ - a = "fine", - b = "fine also", - c = ItemStack(""), -- not fine - d = {} - }, { - a = type_string, - b = type_string, - c = type_string, - d = type_string, - }) == false - - local result4 = libox.type_check("moo", type_string) == true - local result5 = libox.type_check("b", { - a = type_string - }) == false - - local result7 = not libox.type_check({ - a = "b", - }, { - a = type_string, - b = type_string, - c = { - a = type_string, - b = type_string, - } - }) - - local result6 = libox.type_check({ - a = ItemStack("") - }, { - a = type_string, - }) == false - - assert(result1 and result2 and result3 and result4 and result5 and result6 and result7) - end) - it("Can check types (recursive)", function(assert) - local table = { - f = function() end - } - table["k"] = table - assert(not libox.type_check(table, { - f = function(x) return type(x) == "function" end, - k = { - x = function(_) return "lol" end - } - })) - end) - - it("Userdata propertly type checked - PerlinNoise", function(assert) - local perlin = libox.safe.PerlinNoise - debug.sethook(function() end, "", 1000) -- make it so sandbox_lib_f wont get mad - local result1 = perlin({ - offset = 0, - scale = 1, - spread = { x = 384, y = 192, z = 384 }, - seed = 5900033, - octaves = 5, - persist = 0.63, - lacunarity = 2.0, - --flags = "" - }) ~= false - local result2 = perlin({}) == false - local result3 = perlin({ - offset = 0, - scale = 1, - spread = { x = 384, y = 192, z = 384 }, - seed = 5900033, - octaves = 50, - persist = 0.63, - lacunarity = 50.0, - --flags = "" - }) ~= false - --[[ - So, about octaves/lacunarity - when i make those values huge, nothing really seems to happen other than timeout - i think its fine tbh - ]] - debug.sethook() - assert(result1 and result2 and result3) - end) -end) diff --git a/mods/libox/utils.lua b/mods/libox/utils.lua deleted file mode 100644 index fae1ba20..00000000 --- a/mods/libox/utils.lua +++ /dev/null @@ -1,282 +0,0 @@ -function libox.get_default_hook(max_time) - local time = minetest.get_us_time - - local start_time = time() - return function() - if time() - start_time > max_time then - debug.sethook() - - error("Code timed out! Reason: Time limit exceeded, the limit:" .. - tostring(max_time / 1000) .. "ms, the program took:" .. ((time() - start_time) / 1000), 2) - end - end -end - --- luacheck: push ignore - ---[[ - PATH SHORTENING: from dbg - Path shortening is licensed under the MIT license: - - Copyright 2022 Lars Müller - - 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. -]] - --- luacheck: pop ignore - -local modpath_trie = {} -for _, modname in pairs(minetest.get_modnames()) do - local path = minetest.get_modpath(modname) - local subtrie = modpath_trie - for char in path:gmatch "." do - subtrie[char] = subtrie[char] or {} - subtrie = subtrie[char] - end - subtrie["\\"] = modname - subtrie["/"] = modname -end - -function libox.shorten_path(path) - -- Search for a prefix (paths have at most one prefix) - local subtrie = modpath_trie - for i = 1, #path do - if type(subtrie) == "string" then - return subtrie .. ":" .. path:sub(i) - end - subtrie = subtrie[path:sub(i, i)] - if not subtrie then return path end - end - return path -end - --- PATH SHORTENING END, rest is licensed as usual - -if minetest.global_exists("dbg") then - libox.shorten_path = dbg.shorten_path -end - -local TRACEBACK_LIMIT = 20 - -function libox.traceback(errmsg) - errmsg = tostring(errmsg) or "" - - local traceback = "Traceback: " .. "\n" - local level = 1 - - while level < TRACEBACK_LIMIT do - local info = debug.getinfo(level, "nlS") -- can be quite slow actually, thats why TRACEBACK_LIMIT is in place - if not info then break end - local name = info.name - local text - if name ~= nil then - text = "In function " .. name - else - text = "In " .. info.what - end - if info.source == "=(load)" then - traceback = traceback .. text .. " at line " .. info.currentline .. "\n" - end - level = level + 1 - end - - if level == TRACEBACK_LIMIT then traceback = traceback .. "\n... and more" end - return libox.shorten_path(errmsg) .. "\n" .. traceback -end - --- dont rely on this to sethook and -function libox.unsafe_traceback(errmsg) - debug.sethook() - getmetatable("").__index = string - return libox.traceback(errmsg) -end - -function libox.digiline_sanitize(input, allow_functions, wrap) - --[[ - Parameters: - 1) input: the thing - 2) allow_functions: true/false, explains itself - 3) wrap: function, the function that wraps around the functions in this table - ]] - - wrap = wrap or function(f) return f end - local function clean_and_weigh_digiline_message(msg, back_references) - local t = type(msg) - if t == "string" then - -- Strings are immutable so can be passed by reference, and cost their - -- length plus the size of the Lua object header (24 bytes on a 64-bit - -- platform) plus one byte for the NUL terminator. - return msg, #msg + 25 - elseif t == "number" then - -- Numbers are passed by value so need not be touched, and cost 8 bytes - -- as all numbers in Lua are doubles. NaN values are removed. - if msg ~= msg then - return nil, 0 - end - return msg, 8 - elseif t == "boolean" then - -- Booleans are passed by value so need not be touched, and cost 1 - -- byte. - return msg, 1 - elseif t == "table" then - -- Tables are duplicated. Check if this table has been seen before - -- (self-referential or shared table); if so, reuse the cleaned value - -- of the previous occurrence, maintaining table topology and avoiding - -- infinite recursion, and charge zero bytes for this as the object has - -- already been counted. - back_references = back_references or {} - local bref = back_references[msg] - if bref then - return bref, 0 - end - -- Construct a new table by cleaning all the keys and values and adding - -- up their costs, plus 8 bytes as a rough estimate of table overhead. - local cost = 8 - local ret = {} - back_references[msg] = ret - for k, v in pairs(msg) do - local k_cost, v_cost - k, k_cost = clean_and_weigh_digiline_message(k, back_references) - v, v_cost = clean_and_weigh_digiline_message(v, back_references) - if k ~= nil and v ~= nil then - -- Only include an element if its key and value are of legal - -- types. - ret[k] = v - end - -- If we only counted the cost of a table element when we actually - -- used it, we would be vulnerable to the following attack: - -- 1. Construct a huge table (too large to pass the cost limit). - -- 2. Insert it somewhere in a table, with a function as a key. - -- 3. Insert it somewhere in another table, with a number as a key. - -- 4. The first occurrence doesn’t pay the cost because functions - -- are stripped and therefore the element is dropped. - -- 5. The second occurrence doesn’t pay the cost because it’s in - -- back_references. - -- By counting the costs regardless of whether the objects will be - -- included, we avoid this attack; it may overestimate the cost of - -- some messages, but only those that won’t be delivered intact - -- anyway because they contain illegal object types. - cost = cost + k_cost + v_cost - end - return ret, cost - elseif t == "function" and allow_functions then - local success, bytecode = pcall(function() - return string.dump(msg) - end) - if not success then - return nil, 0 - else - return wrap(msg), #bytecode + 25 - end - else - return nil, 0 - end - end - - - local msg, cost = clean_and_weigh_digiline_message(input) - if not msg then - return nil, 0 - else - return msg, cost - end -end - -function libox.sandbox_lib_f(f, opt_str_limit) - --[[ - Sandbox external functions, call this on functions that - - don't run user code - - use "":sub(1, 2, whatever) syntax and that syntax is critical or use pcall or xpcall - - get laggy when supplied with gigantic sting inputs - - ]] - return function(...) - local args = { ... } - for _, v in pairs(args) do - if type(v) == "string" and #v > (opt_str_limit or 64000) then error("String too large", 2) end - end - - local string_meta = getmetatable("") - local sandbox = string_meta.__index - - string_meta.__index = string - local retvalue = { f(...) } - string_meta.__index = sandbox - - if not debug.gethook() then - error("Code timed out! (Reason: external function erased the debug hook)", 2) - end - return unpack(retvalue) - end -end - -libox.safe_traceback = libox.sandbox_lib_f(libox.safe_traceback) -- make it work - - --- strict type checking ---[[ - thing: any - type_check: { - key = function | table - } | function - note: recursive - returns: boolean - -]] -function libox.type_check(initial_thing, initial_check) - local function internal(thing, check, seen) - if seen[thing] == true then return true end - if type(check) == "function" then - seen[thing] = true - return check(thing) - end - - for k, v in pairs(check) do - if thing[k] == nil then - if type(v) == "function" then - if v(nil) == false then - return false, k - end - else - return false - end - elseif type(v) == "table" then - if (internal(thing[k], v, seen)) == false then return false, k end - seen[thing[k]] = true - elseif type(v) == "function" then - if v(thing[k]) == false then return false, k end - seen[thing[k]] = true - else -- bad, just return false - return false, "invalid params to initial_check probably" - end - end - for k, _ in pairs(thing) do - if check[k] == nil then return false, "un-needed: " .. k end - end - return true - end - return internal(initial_thing, initial_check, {}) -end - -function libox.type(x) - return function(something) - return type(something) == x - end -end - -function libox.type_vector(vec) - if type(vec) ~= "table" then return false end - - if type(vec.x) ~= "number" then return false end - if type(vec.y) ~= "number" then return false end - if type(vec.z) ~= "number" then return false end - return true -end diff --git a/mods/player_api b/mods/player_api new file mode 160000 index 00000000..64da3ede --- /dev/null +++ b/mods/player_api @@ -0,0 +1 @@ +Subproject commit 64da3edef46ad77907dbef0410556410fe77e7be diff --git a/mods/player_api/README.txt b/mods/player_api/README.txt deleted file mode 100644 index 37afadfa..00000000 --- a/mods/player_api/README.txt +++ /dev/null @@ -1,27 +0,0 @@ -Minetest Game mod: player_api -============================= -See license.txt for license information. - -Provides an API to allow multiple mods to set player models and textures. -Also sets the default model, texture, and player flags. -This mod is only for content related to the Player API and the player object. - -Authors of source code ----------------------- -Originally by celeron55, Perttu Ahola (LGPLv2.1+) -Various Minetest developers and contributors (LGPLv2.1+) - -Authors of media (textures, models and sounds) ----------------------------------------------- -Original model by MirceaKitsune (CC BY-SA 3.0). -Various alterations and fixes by kilbith, sofar, xunto, Rogier-5, TeTpaAka, Desour, -stujones11, An0n3m0us (CC BY-SA 3.0): - character.b3d - character.blend - -Jordach (CC BY-SA 3.0): - character.png - -celeron55, Perttu Ahola (CC BY-SA 3.0): - player.png - player_back.png diff --git a/mods/player_api/api.lua b/mods/player_api/api.lua deleted file mode 100644 index 6a572f55..00000000 --- a/mods/player_api/api.lua +++ /dev/null @@ -1,239 +0,0 @@ -player_api = {} - --- Player animation blending --- Note: This is currently broken due to a bug in Irrlicht, leave at 0 -local animation_blend = 0 - -player_api.registered_models = {} - --- Local for speed. -local models = player_api.registered_models - -local function collisionbox_equals(collisionbox, other_collisionbox) - if collisionbox == other_collisionbox then - return true - end - for index = 1, 6 do - if collisionbox[index] ~= other_collisionbox[index] then - return false - end - end - return true -end - -function player_api.register_model(name, def) - models[name] = def - def.visual_size = def.visual_size or {x = 1, y = 1} - def.collisionbox = def.collisionbox or {-0.3, 0.0, -0.3, 0.3, 1.7, 0.3} - def.stepheight = def.stepheight or 0.6 - def.eye_height = def.eye_height or 1.47 - - -- Sort animations into property classes: - -- Animations with same properties have the same _equals value - for animation_name, animation in pairs(def.animations) do - animation.eye_height = animation.eye_height or def.eye_height - animation.collisionbox = animation.collisionbox or def.collisionbox - animation.override_local = animation.override_local or false - - for _, other_animation in pairs(def.animations) do - if other_animation._equals then - if collisionbox_equals(animation.collisionbox, other_animation.collisionbox) - and animation.eye_height == other_animation.eye_height then - animation._equals = other_animation._equals - break - end - end - end - animation._equals = animation._equals or animation_name - end -end - --- Player stats and animations --- model, textures, animation -local players = {} -player_api.player_attached = {} - -local function get_player_data(player) - return assert(players[player:get_player_name()]) -end - -function player_api.get_animation(player) - return get_player_data(player) -end - --- Called when a player's appearance needs to be updated -function player_api.set_model(player, model_name) - local player_data = get_player_data(player) - if player_data.model == model_name then - return - end - -- Update data - player_data.model = model_name - -- Clear animation data as the model has changed - -- (required for setting the `stand` animation not to be a no-op) - player_data.animation, player_data.animation_speed, player_data.animation_loop = nil, nil, nil - - local model = models[model_name] - if model then - player:set_properties({ - mesh = model_name, - textures = player_data.textures or model.textures, - visual = "mesh", - visual_size = model.visual_size, - stepheight = model.stepheight - }) - -- sets local_animation, collisionbox & eye_height - player_api.set_animation(player, "stand") - else - player:set_properties({ - textures = {"player.png", "player_back.png"}, - visual = "upright_sprite", - visual_size = {x = 1, y = 2}, - collisionbox = {-0.3, 0.0, -0.3, 0.3, 1.75, 0.3}, - stepheight = 0.6, - eye_height = 1.625, - }) - end -end - -function player_api.get_textures(player) - local player_data = get_player_data(player) - local model = models[player_data.model] - return assert(player_data.textures or (model and model.textures)) -end - -function player_api.set_textures(player, textures) - local player_data = get_player_data(player) - local model = models[player_data.model] - local new_textures = assert(textures or (model and model.textures)) - player_data.textures = new_textures - player:set_properties({textures = new_textures}) -end - -function player_api.set_texture(player, index, texture) - local textures = table.copy(player_api.get_textures(player)) - textures[index] = texture - player_api.set_textures(player, textures) -end - -function player_api.set_animation(player, anim_name, speed, loop) - local player_data = get_player_data(player) - local model = models[player_data.model] - if not (model and model.animations[anim_name]) then - return - end - speed = speed or model.animation_speed - if loop == nil then - loop = true - end - if player_data.animation == anim_name - and player_data.animation_speed == speed - and player_data.animation_loop == loop - then - return - end - local previous_anim = model.animations[player_data.animation] or {} - local anim = model.animations[anim_name] - player_data.animation = anim_name - player_data.animation_speed = speed - player_data.animation_loop = loop - -- If necessary change the local animation (only seen by the client of *that* player) - -- `override_local` <=> suspend local animations while this one is active - -- (this is basically a hack, proper engine feature needed...) - if anim.override_local ~= previous_anim.override_local then - if anim.override_local then - local none = {x=0, y=0} - player:set_local_animation(none, none, none, none, 1) - else - local a = model.animations -- (not specific to the animation being set) - player:set_local_animation( - a.stand, a.walk, a.mine, a.walk_mine, - model.animation_speed or 30 - ) - end - end - -- Set the animation seen by everyone else - player:set_animation(anim, speed, animation_blend, loop) - -- Update related properties if they changed - if anim._equals ~= previous_anim._equals then - player:set_properties({ - collisionbox = anim.collisionbox, - eye_height = anim.eye_height - }) - end -end - -minetest.register_on_joinplayer(function(player) - local name = player:get_player_name() - players[name] = {} - player_api.player_attached[name] = false -end) - -minetest.register_on_leaveplayer(function(player) - local name = player:get_player_name() - players[name] = nil - player_api.player_attached[name] = nil -end) - --- Localize for better performance. -local player_set_animation = player_api.set_animation -local player_attached = player_api.player_attached - --- Prevent knockback for attached players -local old_calculate_knockback = minetest.calculate_knockback -function minetest.calculate_knockback(player, ...) - if player_attached[player:get_player_name()] then - return 0 - end - return old_calculate_knockback(player, ...) -end - --- Check each player and apply animations -function player_api.globalstep() - for _, player in ipairs(minetest.get_connected_players()) do - local name = player:get_player_name() - local player_data = players[name] - local model = player_data and models[player_data.model] - if model and not player_attached[name] then - local controls = player:get_player_control() - local animation_speed_mod = model.animation_speed or 30 - - -- Determine if the player is sneaking, and reduce animation speed if so - if controls.sneak then - animation_speed_mod = animation_speed_mod / 2 - end - - -- Apply animations based on what the player is doing - if player:get_hp() == 0 then - player_set_animation(player, "lay") - elseif controls.up or controls.down or controls.left or controls.right then - if controls.LMB or controls.RMB then - player_set_animation(player, "walk_mine", animation_speed_mod) - else - player_set_animation(player, "walk", animation_speed_mod) - end - elseif controls.LMB or controls.RMB then - player_set_animation(player, "mine", animation_speed_mod) - else - player_set_animation(player, "stand", animation_speed_mod) - end - end - end -end - --- Mods can modify the globalstep by overriding player_api.globalstep -minetest.register_globalstep(function(...) - player_api.globalstep(...) -end) - -for _, api_function in pairs({"get_animation", "set_animation", "set_model", "set_textures"}) do - local original_function = player_api[api_function] - player_api[api_function] = function(player, ...) - if not players[player:get_player_name()] then - -- HACK for keeping backwards compatibility - minetest.log("warning", api_function .. " called on offline player") - return - end - return original_function(player, ...) - end -end diff --git a/mods/player_api/init.lua b/mods/player_api/init.lua deleted file mode 100644 index f258aea7..00000000 --- a/mods/player_api/init.lua +++ /dev/null @@ -1,26 +0,0 @@ -dofile(minetest.get_modpath("player_api") .. "/api.lua") - --- Default player appearance -player_api.register_model("character.b3d", { - animation_speed = 30, - textures = {"character.png"}, - animations = { - -- Standard animations. - stand = {x = 0, y = 79}, - lay = {x = 162, y = 166, eye_height = 0.3, override_local = true, - collisionbox = {-0.6, 0.0, -0.6, 0.6, 0.3, 0.6}}, - walk = {x = 168, y = 187}, - mine = {x = 189, y = 198}, - walk_mine = {x = 200, y = 219}, - sit = {x = 81, y = 160, eye_height = 0.8, override_local = true, - collisionbox = {-0.3, 0.0, -0.3, 0.3, 1.0, 0.3}} - }, - collisionbox = {-0.3, 0.0, -0.3, 0.3, 1.7, 0.3}, - stepheight = 0.6, - eye_height = 1.47, -}) - --- Update appearance when the player joins -minetest.register_on_joinplayer(function(player) - player_api.set_model(player, "character.b3d") -end) diff --git a/mods/player_api/license.txt b/mods/player_api/license.txt deleted file mode 100644 index bdc43154..00000000 --- a/mods/player_api/license.txt +++ /dev/null @@ -1,60 +0,0 @@ -License of source code ----------------------- - -GNU Lesser General Public License, version 2.1 -Copyright (C) 2011 celeron55, Perttu Ahola -Copyright (C) 2011 Various Minetest developers and contributors - -This program is free software; you can redistribute it and/or modify it under the terms -of the GNU Lesser General Public License as published by the Free Software Foundation; -either version 2.1 of the License, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; -without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -See the GNU Lesser General Public License for more details: -https://www.gnu.org/licenses/old-licenses/lgpl-2.1.html - - -Licenses of media (textures, models and sounds) ------------------------------------------------ - -Attribution-ShareAlike 3.0 Unported (CC BY-SA 3.0) -Copyright (C) 2011 celeron55, Perttu Ahola -Copyright (C) 2012 MirceaKitsune -Copyright (C) 2012 Jordach -Copyright (C) 2015 kilbith -Copyright (C) 2016 sofar -Copyright (C) 2016 xunto -Copyright (C) 2016 Rogier-5 -Copyright (C) 2017 TeTpaAka -Copyright (C) 2017 Desour -Copyright (C) 2018 stujones11 -Copyright (C) 2019 An0n3m0us - -You are free to: -Share — copy and redistribute the material in any medium or format. -Adapt — remix, transform, and build upon the material for any purpose, even commercially. -The licensor cannot revoke these freedoms as long as you follow the license terms. - -Under the following terms: - -Attribution — You must give appropriate credit, provide a link to the license, and -indicate if changes were made. You may do so in any reasonable manner, but not in any way -that suggests the licensor endorses you or your use. - -ShareAlike — If you remix, transform, or build upon the material, you must distribute -your contributions under the same license as the original. - -No additional restrictions — You may not apply legal terms or technological measures that -legally restrict others from doing anything the license permits. - -Notices: - -You do not have to comply with the license for elements of the material in the public -domain or where your use is permitted by an applicable exception or limitation. -No warranties are given. The license may not give you all of the permissions necessary -for your intended use. For example, other rights such as publicity, privacy, or moral -rights may limit how you use the material. - -For more details: -http://creativecommons.org/licenses/by-sa/3.0/ diff --git a/mods/player_api/mod.conf b/mods/player_api/mod.conf deleted file mode 100644 index bf62327b..00000000 --- a/mods/player_api/mod.conf +++ /dev/null @@ -1,2 +0,0 @@ -name = player_api -description = Minetest Game mod: Manages player visuals diff --git a/mods/player_api/models/character.b3d b/mods/player_api/models/character.b3d deleted file mode 100644 index 3e0827e40b5608d36019d0cfef98994d2fb9584c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 73433 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 diff --git a/mods/player_api/models/character.blend b/mods/player_api/models/character.blend deleted file mode 100644 index a32c3438b4e75d9db1ee045a7a8e607ba90c0235..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 632100 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%0D|Zb)lvBSlS&< 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 Kl}Pl|-~R!(^E^oa diff --git a/mods/player_api/models/character.png b/mods/player_api/models/character.png deleted file mode 100644 index 05021781e03fbb71cb309d5ac233c6c90f332fda..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2754 zcmV;z3O)6SP)2uX*6~`Is8-X;*&E0SAO>&cvke%!y3xOmA1X`so?O2^U+G=e9kx~mtSV|M1>{}P0 z6tr}4X|WZxTJ;a`g>NiW*4CH)5y$g6w}*Qt8RupuDVh1s@A;i`o`-wBXM29k$@kY+ zT_PRjMY1?qD2r2t(os7`&f#QNIw0MOPIVqq za1wcI%A7}z-ffUgi-4)m>>tkJ+(1o8hIKux4lh^d-C3N67}m(qk7R9TP5{mkNiv~d zqu^LlRbo!w{QYUUaruZ`d*=oD_|4t&@ugjc>z5D9tv|jpV*+rFNRkO(X-VA0Xj9Cb zobyHh5q%uR>B%7djez%$$@O;+$kjK;4FCS^e!20xqjKvHFVFY~lKMD`)045HF?J6K zNKGZ6SEEk`7y(yKYqXCz0UG_E%fH^(i3|c}+5^adDFm!+ipywY?A{PSjkhas7RPx) z2v7P08F1}a6Y|NgC*<1Od*$j|d$b((%FXwWPbq=?r7-nxpvGz)XGwdW5WqL3Lz+Iy@oQ-#Y|IeJz25a`o-;Ss@^&$$6t=63`cDj9)wfbbbf`IGhV6 z!KWXcmm43PG~E2)6d?5tw`YL>IzI&9EMz!%Up5|8p&r+nY%QSVVXk@g+{SR+G+4YurIFK2KT?|wGG)(K$ka%!BY*pKbXLnPL4Qb7otX5P%H$yXk0hev9LF=aJ?@LzHoDq#@hw zeG(u;hYhx#8JxjcoS8WrLJUrTznjkHJfNw4`j_)^`%h;)JxOtXD0S`xIFO;k#_ie5 z8JxwL4$lrR70)tsM9h$TZT0lz^1~1Pf8~n~8@G2kXZg7}=}px82Ww>Lyvv&d|9tl( zPUJeQmz)#AUuWlkUB(&_x?DooYiD@Pdv@`Js2sSC6!w~&wT|vJ&)J>{5S0sLMgY<9 zruErhU!M|foV@erv;OWthHgq$aE3Qk?+KKMmyQD&xuKnY>R&;7gnd5ncjJ1dl#zF9DzH{McEY z>72>g{uRkY@aVHfW(4@BEjK!!-`P3-Do>5HkwC-&Yh<}Lx!^22le0DebBk|y#H@USFm zzT=Sx)5?JMT`{6fLsVE(g$T=vt``#0_;lFTJ$sVUH<6P5{TX!ZNU$&O`H;9&NgI8= zN`_CT-Fbh`oPcQMH*nrah*v)%!C;WcTLzSrl;r&fM$T4B{gWZmpYHA+ zo5NE3eZ6!&6OsBKXXJHCM(@59WnuC~PXu`yNiACw1eucyG+2 zT=}q$zim-<{1{-33>`Muvd8xJ9!;8j;8dA(?ADv#p;GDDr#M(DUC$?^=fzTK*rZPH z(DTQXz}-=Mb{|mUp3R)oxH%+?$0E|YJu1CNN`*eexq~Mw@)JN57X%tI&X<49(!aF! zyEH)00waLlkXZO_D~-(hQOL0<)cznSjXw$5vteV1Xqyww>mz_QGIY7N>?NXF|8a}l zfYx{SZgu{JQp$t~T4ZY;4_JnD?o3z-4V_9;LY4_Nj|HUesi4&TFl5uAWph;e52Q@L z@?3R(0*I!kH<5P&a1?SNg=i;g9z||8j7l0Lqq60>s71A7Ph3XMr=?k=OEjA|M1_tG zSR+G+4YurIFA<|T4!&Gw5nFMwQhIf~^&L-|UFUe52;2VEmln!HSL$W$TeY(MOa&3Q z3~1AoA3B$ofulMaPo!)_uKi67cKHb)jd2tQW7_oM8fBcrQOJP+);JF!3VYTNK>g9Z zd!AQE#uBpV$r9?4PED5wtdXI^23z*9*W_*6tvPDVCv6(^?9J#~l^`;u{^<~7)FQh4 zSehq#GKmZzGZ?4Ht+(_}B;9U01gs&YamYc0y~h1Qp+cnCRqlh=JO`#!CUPc8vOpD05N8Niy+=z5$-?zctinwd`2h%QlW z-4gX^0oKUSVS_Du*vpNOu5FpJ;!LGQa`_3nP0}N{a&!H*i|t-m zcubb;FLk@D{pm7UyfupRQ@%*~;KD(lGF-HB3BYmmpZ)FPGzdsRK(@wXmFooryr^G;Xx0dc=tuvz%!14p<{Y=NZ8s_FBqz?n=1apWGL)C)xm~Cx3b) z=Z?WuJC^`H$^AV)0VV2WFuBs4b`%s8$btn6jDV8Fu-*;UxK7vf1tqOQvmmw7qB!(g z+M{Rn+&Q5WL7nCuuttW?Bg`K5c9H@6repva!~MZ;lamQhCoib(q<_WUmEXGZ5})PM zCx8!~qM{L|M~~n6 z0Wt`19Wt_lHDJx&CGq>DKQUJZllRF;`In?OK37^pbEPXfS3WtM0IZRr!vFxgk;~+!m1FZS~2?+7e@Vo^44=MhLa!}-9{{8ab z&TEibqWl!w& rU}f~-R;g-O%k1_*>%@MOhihZx0?vo`Z!=Z~TEO7x>gTe~DWM4fSl%(n diff --git a/mods/player_api/textures/player_back.png b/mods/player_api/textures/player_back.png deleted file mode 100644 index 5e9ef05420e51ddd7ad33c13a58e21b1bb86a60a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 140 zcmeAS@N?(olHy`uVBq!ia0vp^0zj<5$P6SE-Lv|E6kC8#h%1n0XkeK4M6m_PU@Qsp z3ubV5b|VeQG4XV94B@z*%)oSvjqMmS&l!G+8} - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - - This version of the GNU Lesser General Public License incorporates -the terms and conditions of version 3 of the GNU General Public -License, supplemented by the additional permissions listed below. - - 0. Additional Definitions. - - As used herein, "this License" refers to version 3 of the GNU Lesser -General Public License, and the "GNU GPL" refers to version 3 of the GNU -General Public License. - - "The Library" refers to a covered work governed by this License, -other than an Application or a Combined Work as defined below. - - An "Application" is any work that makes use of an interface provided -by the Library, but which is not otherwise based on the Library. -Defining a subclass of a class defined by the Library is deemed a mode -of using an interface provided by the Library. - - A "Combined Work" is a work produced by combining or linking an -Application with the Library. The particular version of the Library -with which the Combined Work was made is also called the "Linked -Version". - - The "Minimal Corresponding Source" for a Combined Work means the -Corresponding Source for the Combined Work, excluding any source code -for portions of the Combined Work that, considered in isolation, are -based on the Application, and not on the Linked Version. - - The "Corresponding Application Code" for a Combined Work means the -object code and/or source code for the Application, including any data -and utility programs needed for reproducing the Combined Work from the -Application, but excluding the System Libraries of the Combined Work. - - 1. Exception to Section 3 of the GNU GPL. - - You may convey a covered work under sections 3 and 4 of this License -without being bound by section 3 of the GNU GPL. - - 2. Conveying Modified Versions. - - If you modify a copy of the Library, and, in your modifications, a -facility refers to a function or data to be supplied by an Application -that uses the facility (other than as an argument passed when the -facility is invoked), then you may convey a copy of the modified -version: - - a) under this License, provided that you make a good faith effort to - ensure that, in the event an Application does not supply the - function or data, the facility still operates, and performs - whatever part of its purpose remains meaningful, or - - b) under the GNU GPL, with none of the additional permissions of - this License applicable to that copy. - - 3. Object Code Incorporating Material from Library Header Files. - - The object code form of an Application may incorporate material from -a header file that is part of the Library. You may convey such object -code under terms of your choice, provided that, if the incorporated -material is not limited to numerical parameters, data structure -layouts and accessors, or small macros, inline functions and templates -(ten or fewer lines in length), you do both of the following: - - a) Give prominent notice with each copy of the object code that the - Library is used in it and that the Library and its use are - covered by this License. - - b) Accompany the object code with a copy of the GNU GPL and this license - document. - - 4. Combined Works. - - You may convey a Combined Work under terms of your choice that, -taken together, effectively do not restrict modification of the -portions of the Library contained in the Combined Work and reverse -engineering for debugging such modifications, if you also do each of -the following: - - a) Give prominent notice with each copy of the Combined Work that - the Library is used in it and that the Library and its use are - covered by this License. - - b) Accompany the Combined Work with a copy of the GNU GPL and this license - document. - - c) For a Combined Work that displays copyright notices during - execution, include the copyright notice for the Library among - these notices, as well as a reference directing the user to the - copies of the GNU GPL and this license document. - - d) Do one of the following: - - 0) Convey the Minimal Corresponding Source under the terms of this - License, and the Corresponding Application Code in a form - suitable for, and under terms that permit, the user to - recombine or relink the Application with a modified version of - the Linked Version to produce a modified Combined Work, in the - manner specified by section 6 of the GNU GPL for conveying - Corresponding Source. - - 1) Use a suitable shared library mechanism for linking with the - Library. A suitable mechanism is one that (a) uses at run time - a copy of the Library already present on the user's computer - system, and (b) will operate properly with a modified version - of the Library that is interface-compatible with the Linked - Version. - - e) Provide Installation Information, but only if you would otherwise - be required to provide such information under section 6 of the - GNU GPL, and only to the extent that such information is - necessary to install and execute a modified version of the - Combined Work produced by recombining or relinking the - Application with a modified version of the Linked Version. (If - you use option 4d0, the Installation Information must accompany - the Minimal Corresponding Source and Corresponding Application - Code. If you use option 4d1, you must provide the Installation - Information in the manner specified by section 6 of the GNU GPL - for conveying Corresponding Source.) - - 5. Combined Libraries. - - You may place library facilities that are a work based on the -Library side by side in a single library together with other library -facilities that are not Applications and are not covered by this -License, and convey such a combined library under terms of your -choice, if you do both of the following: - - a) Accompany the combined library with a copy of the same work based - on the Library, uncombined with any other library facilities, - conveyed under the terms of this License. - - b) Give prominent notice with the combined library that part of it - is a work based on the Library, and explaining where to find the - accompanying uncombined form of the same work. - - 6. Revised Versions of the GNU Lesser General Public License. - - The Free Software Foundation may publish revised and/or new versions -of the GNU Lesser General Public License from time to time. Such new -versions will be similar in spirit to the present version, but may -differ in detail to address new problems or concerns. - - Each version is given a distinguishing version number. If the -Library as you received it specifies that a certain numbered version -of the GNU Lesser General Public License "or any later version" -applies to it, you have the option of following the terms and -conditions either of that published version or of any later version -published by the Free Software Foundation. If the Library as you -received it does not specify a version number of the GNU Lesser -General Public License, you may choose any version of the GNU Lesser -General Public License ever published by the Free Software Foundation. - - If the Library as you received it specifies that a proxy can decide -whether future versions of the GNU Lesser General Public License shall -apply, that proxy's public statement of acceptance of any version is -permanent authorization for you to choose that version for the -Library. diff --git a/mods/unified_inventory_plus/MEDIA_LICENSE.txt b/mods/unified_inventory_plus/MEDIA_LICENSE.txt deleted file mode 100644 index 0e259d42..00000000 --- a/mods/unified_inventory_plus/MEDIA_LICENSE.txt +++ /dev/null @@ -1,121 +0,0 @@ -Creative Commons Legal Code - -CC0 1.0 Universal - - CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE - LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN - ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS - INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES - REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS - PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM - THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED - HEREUNDER. - -Statement of Purpose - -The laws of most jurisdictions throughout the world automatically confer -exclusive Copyright and Related Rights (defined below) upon the creator -and subsequent owner(s) (each and all, an "owner") of an original work of -authorship and/or a database (each, a "Work"). - -Certain owners wish to permanently relinquish those rights to a Work for -the purpose of contributing to a commons of creative, cultural and -scientific works ("Commons") that the public can reliably and without fear -of later claims of infringement build upon, modify, incorporate in other -works, reuse and redistribute as freely as possible in any form whatsoever -and for any purposes, including without limitation commercial purposes. -These owners may contribute to the Commons to promote the ideal of a free -culture and the further production of creative, cultural and scientific -works, or to gain reputation or greater distribution for their Work in -part through the use and efforts of others. - -For these and/or other purposes and motivations, and without any -expectation of additional consideration or compensation, the person -associating CC0 with a Work (the "Affirmer"), to the extent that he or she -is an owner of Copyright and Related Rights in the Work, voluntarily -elects to apply CC0 to the Work and publicly distribute the Work under its -terms, with knowledge of his or her Copyright and Related Rights in the -Work and the meaning and intended legal effect of CC0 on those rights. - -1. Copyright and Related Rights. A Work made available under CC0 may be -protected by copyright and related or neighboring rights ("Copyright and -Related Rights"). Copyright and Related Rights include, but are not -limited to, the following: - - i. the right to reproduce, adapt, distribute, perform, display, - communicate, and translate a Work; - ii. moral rights retained by the original author(s) and/or performer(s); -iii. publicity and privacy rights pertaining to a person's image or - likeness depicted in a Work; - iv. rights protecting against unfair competition in regards to a Work, - subject to the limitations in paragraph 4(a), below; - v. rights protecting the extraction, dissemination, use and reuse of data - in a Work; - vi. database rights (such as those arising under Directive 96/9/EC of the - European Parliament and of the Council of 11 March 1996 on the legal - protection of databases, and under any national implementation - thereof, including any amended or successor version of such - directive); and -vii. other similar, equivalent or corresponding rights throughout the - world based on applicable law or treaty, and any national - implementations thereof. - -2. Waiver. To the greatest extent permitted by, but not in contravention -of, applicable law, Affirmer hereby overtly, fully, permanently, -irrevocably and unconditionally waives, abandons, and surrenders all of -Affirmer's Copyright and Related Rights and associated claims and causes -of action, whether now known or unknown (including existing as well as -future claims and causes of action), in the Work (i) in all territories -worldwide, (ii) for the maximum duration provided by applicable law or -treaty (including future time extensions), (iii) in any current or future -medium and for any number of copies, and (iv) for any purpose whatsoever, -including without limitation commercial, advertising or promotional -purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each -member of the public at large and to the detriment of Affirmer's heirs and -successors, fully intending that such Waiver shall not be subject to -revocation, rescission, cancellation, termination, or any other legal or -equitable action to disrupt the quiet enjoyment of the Work by the public -as contemplated by Affirmer's express Statement of Purpose. - -3. Public License Fallback. Should any part of the Waiver for any reason -be judged legally invalid or ineffective under applicable law, then the -Waiver shall be preserved to the maximum extent permitted taking into -account Affirmer's express Statement of Purpose. In addition, to the -extent the Waiver is so judged Affirmer hereby grants to each affected -person a royalty-free, non transferable, non sublicensable, non exclusive, -irrevocable and unconditional license to exercise Affirmer's Copyright and -Related Rights in the Work (i) in all territories worldwide, (ii) for the -maximum duration provided by applicable law or treaty (including future -time extensions), (iii) in any current or future medium and for any number -of copies, and (iv) for any purpose whatsoever, including without -limitation commercial, advertising or promotional purposes (the -"License"). The License shall be deemed effective as of the date CC0 was -applied by Affirmer to the Work. Should any part of the License for any -reason be judged legally invalid or ineffective under applicable law, such -partial invalidity or ineffectiveness shall not invalidate the remainder -of the License, and in such case Affirmer hereby affirms that he or she -will not (i) exercise any of his or her remaining Copyright and Related -Rights in the Work or (ii) assert any associated claims and causes of -action with respect to the Work, in either case contrary to Affirmer's -express Statement of Purpose. - -4. Limitations and Disclaimers. - - a. No trademark or patent rights held by Affirmer are waived, abandoned, - surrendered, licensed or otherwise affected by this document. - b. Affirmer offers the Work as-is and makes no representations or - warranties of any kind concerning the Work, express, implied, - statutory or otherwise, including without limitation warranties of - title, merchantability, fitness for a particular purpose, non - infringement, or the absence of latent or other defects, accuracy, or - the present or absence of errors, whether or not discoverable, all to - the greatest extent permissible under applicable law. - c. Affirmer disclaims responsibility for clearing rights of other persons - that may apply to the Work or any use thereof, including without - limitation any person's Copyright and Related Rights in the Work. - Further, Affirmer disclaims responsibility for obtaining any necessary - consents, permissions or other rights required for any use of the - Work. - d. Affirmer understands and acknowledges that Creative Commons is not a - party to this document and has no duty or obligation with respect to - this CC0 or use of the Work. diff --git a/mods/unified_inventory_plus/README.md b/mods/unified_inventory_plus/README.md deleted file mode 100644 index 0f067b55..00000000 --- a/mods/unified_inventory_plus/README.md +++ /dev/null @@ -1,45 +0,0 @@ -# Unified Inventory Plus -Unified Inventory Plus extends Unified Inventory. -It adds 3 button types to the craft page: -- Craft All: crafting a stack and putting the result in the inventory -- Patterns buttons: reorganizing items in the craft inventory following usual patterns -- Rotation button: rotating the craft inventory content -- Clear button: clear the craft inventory content - -In `init.lua`, you can easily: -Disable the functionalities you don't want -Disable and reorder patterns - -Fully compatible with Skyblock - -## Settings -Features can be toggled with the following settings (true per default): -* `unified_inventory_plus.enable_craft_all` -* `unified_inventory_plus.enable_craft_organize` -* `unified_inventory_plus.enable_craft_rotate` -* `unified_inventory_plus.enable_craft_clear` - -## Dependencies -- [unified_inventory](https://github.com/minetest-mods/unified_inventory) -- [fakelib](https://content.minetest.net/packages/OgelGames/fakelib/) -#### Optional dependencies -- [stamina](https://github.com/minetest-mods/stamina) - - -## License -Refer to Unified Inventory for original medias copyright. - -Copyright (C) 2017 Bousket -Unified Inventory Plus code is licensed under the CC0 -https://creativecommons.org/publicdomain/zero/1.0/ - -Copyright (C) 2022 fluxionary -Code: LGPL -Media: CC0 - -## Authors -Bousket - Main mod. -shivajiva101 - Skyblock Integration. -fluxionary - Stamina mod integration, rewrite. -NatureFreshMilk. -Panquesito7. diff --git a/mods/unified_inventory_plus/craft_all.lua b/mods/unified_inventory_plus/craft_all.lua deleted file mode 100644 index 7a3beb63..00000000 --- a/mods/unified_inventory_plus/craft_all.lua +++ /dev/null @@ -1,150 +0,0 @@ -local ui = unified_inventory -local uip = unified_inventory_plus -local has = uip.has -local settings = uip.settings -local S = uip.S -local F = minetest.formspec_escape - --- Backup to inject code -uip.craft_all = ui.pages["craft"].get_formspec - -ui.pages["craft"] = { - get_formspec = function(player, perplayer_formspec) - local formspec = uip.craft_all(player, perplayer_formspec).formspec - formspec = formspec .. - ("image[%f,%f;%f,%f;ui_crafting_long_arrow.png]"):format( - perplayer_formspec.craft_arrow_x, - perplayer_formspec.craft_y, - ui.imgscale, - ui.imgscale * 3) .. - ("button[%f,%f;%f,%f;craft_craftall;%s]"):format( - perplayer_formspec.craft_arrow_x + 0.23, - perplayer_formspec.craft_y + 1.50, - perplayer_formspec.btn_size, - perplayer_formspec.btn_size, - F(S("All")) - ) - return { formspec = formspec } - end, -} - --- make sure the width is right -local function infer_width(list, expected) - if not expected or expected:is_empty() then - return - end - local width - for i = 1, 3 do - local output, _ = minetest.get_craft_result({ method = "normal", width = i, items = list }) - if output.item:to_string() == expected:to_string() then - width = i - break - end - end - if not width then - uip.log("warning", "Can't infer recipe width for %s", expected:to_string()) - end - return width -end - --- Craft max possible items and put the result in the main inventory -local function craft_craftall(player) - local player_name = player:get_player_name() - local player_inv = player:get_inventory() - local craft_list = player_inv:get_list("craft") - local expected_result = player_inv:get_stack("craftpreview", 1) - local craft_width = infer_width(craft_list, expected_result) - if not craft_width then - return - end - - local num_crafted = 0 - -- don't modify player's inventory until we're done, in case something goes wrong (e.g. crash) - -- use a fake inventory instead of a detached inventory, because detached inventory actions all result in packets - -- sent to the player. - local tmp_inv = fakelib.create_inventory() - tmp_inv:set_list("main", player_inv:get_list("main")) - tmp_inv:set_list("craft", craft_list) - - while true do - if ( - has.stamina and - stamina.get_saturation and - stamina.get_saturation(player) <= settings.craft_all_min_saturation - ) then - minetest.chat_send_player(player_name, S("You are too hungry to use Craft All at this time.")) - break - end - - -- note that get_craft_result can be *very* slow, until minetest 5.7.0 is released. - -- see https://github.com/minetest/minetest/issues/13231 - local output, decremented_input = minetest.get_craft_result({ - method = "normal", - width = craft_width, - items = craft_list, - }) - - if output.item:get_name() ~= expected_result:get_name() then - -- the recipe changed, so we've run out of something. stop processing. - break - end - - -- minetest.on_craft expects to see the decremented input list. - tmp_inv:set_list("craft", decremented_input.items) - - -- invoke callbacks, for compatibility w/ stamina, skyblock, moretrees, etc. - -- note that this is an *undocumented* handler of the minetest lua API, and possibly is subject to change - -- in the future. - output.item = minetest.on_craft(output.item, player, craft_list, tmp_inv) - - -- track items added to the inventory, in case we need to remove them later - local added = {} - - if tmp_inv:room_for_item("main", output.item) then - tmp_inv:add_item("main", output.item) -- should be no remainder, ignore it - table.insert(added, output.item) - else - -- no room for the output item, stop - break - end - - -- we now try to add all replacements. - local all_added = true - for _, replacement_stk in ipairs(output.replacements) do - if tmp_inv:room_for_item("main", replacement_stk) then - tmp_inv:add_item("main", replacement_stk) -- should be no remainder, ignore it - table.insert(added, replacement_stk) - else - all_added = false - break - end - end - - if not all_added then - -- if we failed to add all the replacements, remove what we've added, and abort - for _, stk in ipairs(added) do - tmp_inv:remove_item("main", stk) -- should be no remainder, ignore it - end - break - end - - -- the craft list can be modified by the callbacks, so re-load it - craft_list = tmp_inv:get_list("craft") - - num_crafted = num_crafted + 1 - end - - player_inv:set_list("craft", craft_list) - player_inv:set_list("main", tmp_inv:get_list("main")) - - uip.log("action", "player %s crafts %s %i", player_name, expected_result:to_string(), num_crafted) -end - -minetest.register_on_player_receive_fields(function(player, formname, fields) - for k, _ in pairs(fields) do - if k:match("craft_craftall") then - craft_craftall(player) - return - end - end -end) diff --git a/mods/unified_inventory_plus/craft_clear.lua b/mods/unified_inventory_plus/craft_clear.lua deleted file mode 100644 index 572343c2..00000000 --- a/mods/unified_inventory_plus/craft_clear.lua +++ /dev/null @@ -1,43 +0,0 @@ --- Clear items in the craft inventory -local ui = unified_inventory -local uip = unified_inventory_plus - --- Backup to inject code -uip.craft_clear = ui.pages["craft"].get_formspec - -ui.pages["craft"] = { - get_formspec = function(player, perplayer_formspec) - local formspec = uip.craft_clear(player, perplayer_formspec).formspec - formspec = formspec .. - ("image_button[%f,%f;%f,%f;pattern_clear.png;craft_clear;]"):format( - perplayer_formspec.craft_x - perplayer_formspec.btn_spc, - perplayer_formspec.craft_y + ui.imgscale, - perplayer_formspec.btn_size, - perplayer_formspec.btn_size - ) - return { formspec = formspec } - end, -} - --- Return items from the craft inventory to the player's inventory -local function craft_clear(player) - local player_inv = player:get_inventory() - local craft_list = player_inv:get_list("craft") - - for i, stk in ipairs(craft_list) do - if player_inv:room_for_item("main", stk) then - player_inv:add_item("main", stk) - craft_list[i]:clear() - end - end - - player_inv:set_list("craft", craft_list) -end - -minetest.register_on_player_receive_fields(function(player, formname, fields) - for k, _ in pairs(fields) do - if k:match("craft_clear") then - craft_clear(player) - end - end -end) diff --git a/mods/unified_inventory_plus/craft_organize.lua b/mods/unified_inventory_plus/craft_organize.lua deleted file mode 100644 index 40bf7753..00000000 --- a/mods/unified_inventory_plus/craft_organize.lua +++ /dev/null @@ -1,170 +0,0 @@ --- Organize items in the craft inventory following a pattern: -local ui = unified_inventory -local uip = unified_inventory_plus - -local default_stack_max = tonumber(minetest.settings:get("default_stack_max")) or 99 - --- Backup to inject code -uip.craft_organize = ui.pages["craft"].get_formspec - -ui.pages["craft"] = { - get_formspec = function(player, perplayer_formspec) - local formspec = uip.craft_organize(player, perplayer_formspec).formspec - local btnsz = ui.imgscale / 3 - local btnspc = ui.imgscale / 2 - - if perplayer_formspec.pagecols == 4 then - -- UI is in lite mode. - for i, v in ipairs(uip.craft_patterns) do - formspec = formspec .. - ("image_button[%f,%f;%f,%f;%s;craft_organize_%i;]"):format( - perplayer_formspec.craft_x + btnspc * (i - 1), - perplayer_formspec.craft_y + 0.1 - btnspc, - btnsz, - btnsz, - v.ico, - i - ) - end - else - for i, v in ipairs(uip.craft_patterns) do - formspec = formspec .. - ("image_button[%f,%f;%f,%f;%s;craft_organize_%i;]"):format( - perplayer_formspec.craft_x + btnspc * ((i - 1) % 6) + 0.1, - perplayer_formspec.craft_y + 0.22 - (math.ceil(i / 6)) * btnspc, - btnsz, - btnsz, - v.ico, - i - ) - end - end - return { formspec = formspec } - end, -} - -local function get_pattern_id(fields) - for k, _ in pairs(fields) do - local pattern_id = tonumber(k:match("craft_organize_(.*)")) - if pattern_id then - return pattern_id - end - end -end - -local function get_single_item(craft_list) - for _, stk in ipairs(craft_list) do - if not stk:is_empty() then - local item = ItemStack(stk) - item:set_count(1) - return item - end - end -end - -local function all_identical(craft_list) - local single_strings = {} - for _, stk in ipairs(craft_list) do - if not stk:is_empty() then - local item = ItemStack(stk) - item:set_count(1) - table.insert(single_strings, item:to_string()) - end - end - if #single_strings == 0 then return false end - local first = single_strings[1] - for i = 2, #single_strings do - if first ~= single_strings[i] then - return false - end - end - return true -end - -local function count_items(craft_list) - local count = 0 - for _, stk in ipairs(craft_list) do - count = count + stk:get_count() - end - return count -end - --- Organize items in the craft inventory following a pattern -local function craft_organize(player, fields) - local player_name = player:get_player_name() - - local pattern_id = get_pattern_id(fields) - if not pattern_id or not uip.craft_patterns[pattern_id] then - minetest.chat_send_player(player_name, "Unexpected pattern!?") - return - end - local pattern = uip.craft_patterns[pattern_id].pattern - local pattern_size = #pattern - - local player_inv = player:get_inventory() - local craft_list = player_inv:get_list("craft") - - local single_item = get_single_item(craft_list) - if not single_item then - -- craft inv is empty - minetest.chat_send_player(player_name, "Inventory empty.") - return - end - - if not all_identical(craft_list) then - minetest.chat_send_player(player_name, "You can only organize one type of item.") - return - end - - local itemname = single_item:get_name() - local def = minetest.registered_items[itemname] - if not def then - minetest.chat_send_player(player_name, "You can't organize an unknown item.") - return - end - - local stacksize = def.stack_max or default_stack_max - local num_items = count_items(craft_list) - - if num_items > stacksize * pattern_size then - minetest.chat_send_player(player_name, "Too many items to stack in that pattern.") - return - end - - if num_items < pattern_size then - minetest.chat_send_player(player_name, "Not enough items.") - return - end - - local new_stack_size = math.floor(num_items / pattern_size) - local remainder = num_items % pattern_size - - local new_craft_list = { - ItemStack(), ItemStack(), ItemStack(), - ItemStack(), ItemStack(), ItemStack(), - ItemStack(), ItemStack(), ItemStack(), - } - - -- because remainder is strictly less than pattern_size, this should always finish w/ remainder = 0 - for _, index in ipairs(pattern) do - local new_item = ItemStack(single_item) - if remainder > 0 then - new_item:set_count(new_stack_size + 1) - remainder = remainder - 1 - else - new_item:set_count(new_stack_size) - end - new_craft_list[index] = new_item - end - - player_inv:set_list("craft", new_craft_list) -end - -minetest.register_on_player_receive_fields(function(player, formname, fields) - for k, _ in pairs(fields) do - if k:match("craft_organize_") then - craft_organize(player, fields) - return - end - end -end) diff --git a/mods/unified_inventory_plus/craft_rotate.lua b/mods/unified_inventory_plus/craft_rotate.lua deleted file mode 100644 index de75bf91..00000000 --- a/mods/unified_inventory_plus/craft_rotate.lua +++ /dev/null @@ -1,52 +0,0 @@ --- Rotate items in the craft inventory -local ui = unified_inventory -local uip = unified_inventory_plus - --- Backup to inject code -uip.craft_rotate = ui.pages["craft"].get_formspec - -ui.pages["craft"] = { - get_formspec = function(player, perplayer_formspec) - local formspec = uip.craft_rotate(player, perplayer_formspec).formspec - formspec = formspec .. - ("image_button[%f,%f;%f,%f;pattern_rotate.png;craft_rotate;]"):format( - perplayer_formspec.craft_x - perplayer_formspec.btn_spc, - perplayer_formspec.craft_y, - perplayer_formspec.btn_size, - perplayer_formspec.btn_size - ) - return { formspec = formspec } - end, -} - - --- Rotate items in the craft inventory -local function craft_rotate_cw(player) - local player_inv = player:get_inventory() - local craft_list = player_inv:get_list("craft") - - -- Rotate corners - local stack = craft_list[1] - craft_list[1] = craft_list[7] - craft_list[7] = craft_list[9] - craft_list[9] = craft_list[3] - craft_list[3] = stack - - -- Rotate middle ones - stack = craft_list[2] - craft_list[2] = craft_list[4] - craft_list[4] = craft_list[8] - craft_list[8] = craft_list[6] - craft_list[6] = stack - - player_inv:set_list("craft", craft_list) -end - -minetest.register_on_player_receive_fields(function(player, formname, fields) - --if not formname:match("craft") then return end - for k, _ in pairs(fields) do - if k:match("craft_rotate") then - craft_rotate_cw(player) - end - end -end) diff --git a/mods/unified_inventory_plus/init.lua b/mods/unified_inventory_plus/init.lua deleted file mode 100644 index 409250bd..00000000 --- a/mods/unified_inventory_plus/init.lua +++ /dev/null @@ -1,57 +0,0 @@ --- Unified Inventory Plus for Minetest -local modname = minetest.get_current_modname() -local modpath = minetest.get_modpath(modname) - -unified_inventory_plus = { - -- Patterns: (Comment unwanted ones & reorder as you wish: buttons are then placed left to right, - -- then up, 6 on a row) pattern field contains indexes to fill in the craft inventory according - -- to the scheme: (then others for non creatives) - -- - -- 1 2 3 - -- 4 5 6 - -- 7 8 9 - craft_patterns = { - { ico = "pattern_1.png", pattern = { 1 } }, - { ico = "pattern_4.png", pattern = { 1, 2, 4, 5 } }, - { ico = "pattern_9.png", pattern = { 1, 2, 3, 4, 5, 6, 7, 8, 9 } }, - { ico = "pattern_3.png", pattern = { 1, 2, 3 } }, - { ico = "pattern_3b.png", pattern = { 1, 4, 7 } }, - { ico = "pattern_5.png", pattern = { 1, 3, 5, 7, 9 } }, - { ico = "pattern_6.png", pattern = { 1, 4, 5, 7, 8, 9 } }, - { ico = "pattern_6b.png", pattern = { 1, 2, 3, 4, 5, 6 } }, - { ico = "pattern_6c.png", pattern = { 1, 3, 4, 6, 7, 9 } }, - { ico = "pattern_7.png", pattern = { 1, 2, 3, 4, 5, 6, 8 } }, - { ico = "pattern_8.png", pattern = { 1, 2, 3, 4, 6, 7, 8, 9 } }, - }, - - has = { - stamina = minetest.global_exists("stamina"), - }, - - log = function(level, message_fmt, ...) - minetest.log(level, "[unified_inventory_plus] " .. message_fmt:format(...)) - end, - - S = minetest.get_translator("unified_inventory"), -} - -local uip = unified_inventory_plus - -dofile(modpath .. "/settings.lua") - --- Functionalities are independants. -if uip.settings.enable_craft_all then - dofile(modpath .. "/craft_all.lua") -end - -if uip.settings.enable_craft_organize then - dofile(modpath .. "/craft_organize.lua") -end - -if uip.settings.enable_craft_rotate then - dofile(modpath .. "/craft_rotate.lua") -end - -if uip.settings.enable_craft_clear then - dofile(modpath .. "/craft_clear.lua") -end diff --git a/mods/unified_inventory_plus/mod.conf b/mods/unified_inventory_plus/mod.conf deleted file mode 100644 index 843b02fe..00000000 --- a/mods/unified_inventory_plus/mod.conf +++ /dev/null @@ -1,4 +0,0 @@ -name = unified_inventory_plus -depends = unified_inventory, fakelib -optional_depends = stamina -min_minetest_version = 5.4.0 diff --git a/mods/unified_inventory_plus/settings.lua b/mods/unified_inventory_plus/settings.lua deleted file mode 100644 index 1350c51e..00000000 --- a/mods/unified_inventory_plus/settings.lua +++ /dev/null @@ -1,11 +0,0 @@ -local uip = unified_inventory_plus -local settings = minetest.settings - -uip.settings = { - enable_craft_all = settings:get_bool("unified_inventory_plus.enable_craft_all", true), - enable_craft_organize = settings:get_bool("unified_inventory_plus.enable_craft_organize", true), - enable_craft_rotate = settings:get_bool("unified_inventory_plus.enable_craft_rotate", true), - enable_craft_clear = settings:get_bool("unified_inventory_plus.enable_craft_clear", true), - - craft_all_min_saturation = tonumber(settings:get("unified_inventory_plus.craft_all_min_saturation")) or 1, -} diff --git a/mods/unified_inventory_plus/settingtypes.txt b/mods/unified_inventory_plus/settingtypes.txt deleted file mode 100644 index 29eae3f3..00000000 --- a/mods/unified_inventory_plus/settingtypes.txt +++ /dev/null @@ -1,8 +0,0 @@ -unified_inventory_plus.enable_craft_all (enable "all" button) bool true -unified_inventory_plus.enable_craft_organize (enable template buttons) bool true -unified_inventory_plus.enable_craft_rotate (enable rotate buttons) bool true -unified_inventory_plus.enable_craft_clear (enable "clear" button) bool true - -# Disable the "craft all" feature if saturation (from the stamina mod) is below a given value. -# Set to -1 always allow "craft all". -unified_inventory_plus.craft_all_min_saturation (Minimum saturation for "craft all") int 1 -1 20 diff --git a/mods/unified_inventory_plus/textures/pattern_1.png b/mods/unified_inventory_plus/textures/pattern_1.png deleted file mode 100644 index 437d940e71484ac75c6b2ea291ea1db0b5e824a9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 116 zcmeAS@N?(olHy`uVBq!ia0vp@Ak4uAB#T}@sR2^fo-U3d8t0P}6vXFP7C*D+Y5sBb z>ec@f4Y=wVOcI&H!mcIs2rroJ(sAD5gr&t?_i4T#r7d`wTRO N!PC{xWt~$(698ZiB{2X1 diff --git a/mods/unified_inventory_plus/textures/pattern_3.png b/mods/unified_inventory_plus/textures/pattern_3.png deleted file mode 100644 index efa5ebd3944bca686f6906a775690688009c340b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 117 zcmeAS@N?(olHy`uVBq!ia0vp@Ak4uAB#T}@sR2?po-U3d8WWQf6vXFP7C*D+S^RnR z>eYr%UasMk-mqyCTk;%+j9c{*YHj@sIiJYX)SSvu;tqJDek)5!l!4*a+UHA`ybg*6 Pn#17f>gTe~DWM4fs}&~$ diff --git a/mods/unified_inventory_plus/textures/pattern_3b.png b/mods/unified_inventory_plus/textures/pattern_3b.png deleted file mode 100644 index 4eda188afe451325fc59ed195e0bed5825854db8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 116 zcmeAS@N?(olHy`uVBq!ia0vp@Ak4uAB#T}@sR2^fo-U3d8WWQf6vXFP7C*D+Y5sBb z>ec@f4Y=wVOcI&H!mcIwOq;*qqoK({>vkRchg&*z95&9+Slt=Iz+mO`eCdIC9(F)u O7(8A5T-G@yGywo|J|++V diff --git a/mods/unified_inventory_plus/textures/pattern_4.png b/mods/unified_inventory_plus/textures/pattern_4.png deleted file mode 100644 index 3b218d028eda120697b9f5c76a11573d507c6a97..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 118 zcmeAS@N?(olHy`uVBq!ia0vp@Ak4uAB#T}@sR2^9o-U3d8WWQf6vXFP7C*D+S^RnR z>eZ4BKkRw<8`N?RoH`}dbMljLhyR62h35fp)aRH@WWC_4bY%HvwID`@n0X%zzB+Dw Q05pif)78&qol`;+0OuJfNdN!< diff --git a/mods/unified_inventory_plus/textures/pattern_5.png b/mods/unified_inventory_plus/textures/pattern_5.png deleted file mode 100644 index 3d706496cfbbbc6d9d181e666a57c7da5b8da516..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 120 zcmeAS@N?(olHy`uVBq!ia0vp@Ak4uAB#T}@sR2^ec@f4cctxnkF)bgP^+2R}0ub%U%#L Sz19FUiow&>&t;ucLK6UJeJTk6 diff --git a/mods/unified_inventory_plus/textures/pattern_6.png b/mods/unified_inventory_plus/textures/pattern_6.png deleted file mode 100644 index 63d612a9552eb5d8cfb37cc89b677789cc7fb123..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 119 zcmeAS@N?(olHy`uVBq!ia0vp@Ak4uAB#T}@sR2@Uo-U3d8t0P}6vXFP7C*D+Y5sBb z>ec@f4Y=wVOcI&H!mcIwY?=SzW>2W_3CkBXi~hJw@eS!zcdD_FVdQ&MBb@0PTDwVE_OC diff --git a/mods/unified_inventory_plus/textures/pattern_6b.png b/mods/unified_inventory_plus/textures/pattern_6b.png deleted file mode 100644 index 1d2410deacba27cd70f4438091c2e885bb216a8d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 117 zcmeAS@N?(olHy`uVBq!ia0vp@Ak4uAB#T}@sR2?po-U3d8t0P}6vXFP7C*D+S^RnR z>eYr%UasMk-mqyCTk@tqExqR*PFSY=A-(ds88mnw2Q3i&z&5WULTYjVg P&0+9#^>bP0l+XkK-P9)G diff --git a/mods/unified_inventory_plus/textures/pattern_6c.png b/mods/unified_inventory_plus/textures/pattern_6c.png deleted file mode 100644 index a3765dfffc03c51f09159e4fc51bfbe555c0c7d2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 116 zcmeAS@N?(olHy`uVBq!ia0vp@Ak4uAB#T}@sR2^fo-U3d8WWQf6vXFP7C*D+Y5sBb z>ec@f4cctxnkF)bgaeYr%UasMk-mqyCTk@tqExqR*PFSY=A-(dr@$rqo#T+eYr%UasMk-mqyCTk@j6EGB>Ld6FlmA9yB{;_LFeQ)BiDIe(X*o!e%4urin^3uW*1 S&yofj#o+1c=d#Wzp$Py@?kBkb diff --git a/mods/unified_inventory_plus/textures/pattern_9.png b/mods/unified_inventory_plus/textures/pattern_9.png deleted file mode 100644 index ecf11a76ffd900f11374fd0d6bc458ed21c966ca..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 113 zcmeAS@N?(olHy`uVBq!ia0vp@Ak4uAB#T}@sR2?Jo-U3d8WWQf6vXFP7C*D+S^RnR z>eYr%UasMk-mqyCTk@tqExr8gTe~DWM4fN*^Z+ diff --git a/mods/unified_inventory_plus/textures/pattern_clear.png b/mods/unified_inventory_plus/textures/pattern_clear.png deleted file mode 100644 index a54c47a7253dbecd894c45037d670d23446ed87a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 391 zcmV;20eJq2P)LP%~qB{G`Y1l_?S~Eg;#9_`3OiOOvA}N$KuB zN7ChpjimH2UlB}&p9ZV1cXy|(?u=O2Eiwvk-98qmm`u zt^yb(*r7t`CDd-Uij{>`#}Q10_b)u}R9c70Bl~$&!D&II2Ll%n)RBWq3Q%bqN?4(O zeV~3$p~?rS0uQPLhiZ~QwXvWYjZm#%sAfIfa|+yp7u=I1|T9jM*$gO9lw2h0Ef002ovPDHLkV1g*TutNX< diff --git a/mods/unified_inventory_plus/textures/pattern_rotate.png b/mods/unified_inventory_plus/textures/pattern_rotate.png deleted file mode 100644 index e398378a632de4101061444da26c82d5428c9c5a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 900 zcmV-~1AF|5P)T0lN&cmokE?_ zIXdTzIbYP?s72iPh`8_>&hGlZ^&U-QKAv|zoEgnizh?IA%=^s$ectzZpLr)1i!8Fp zB8yDWs@1CJZRT>hKj*5d{+ox-X0uc9_gt_9>;V0xQt1Yc*BN+_E9^J05-bF>fn?PY z+TV)B;x4o&`_gIJ264Us94nX0X&hgIaRQ&gBXAXL0pht-ytiKYEXEQk1yqNf1%@m^Jlr}q(EtAPK z#B>Kp3}XniIEs>@D9ds4n}7*=0H!+0YSY1ew__eW$N3iz1-%9{og{(14xGIMcd$ln zO{G$;25m0_hrlzw{s;@g0?rb{ETL+F^#G^~IQj)Hf~DGa(&@C7j{&Em^nPrMKwf`Q z8~+A2*wtkQBVdn<3Zs`C9a)y=@gAo}W(B2S)GY%&F6YrTk-3uuqr`^0M5|w1yW4}r z@Q~_kvOsBbfhtCqXk6ETNDOt7Z(J~+SH51s`>ZpAGJrBoZs zPFz@$zx?IEWAKDk()>M%BnbDfqBz|`XpCj1?ILr>ChM^Uyd5OKTK=|s6r2YcCK!wJ zCxcLxkdp(Aob+5FfWmiXgjPnji@pBqoKb)HJZ#y_{6D;MAgLu%RBooDq3cceuQBZ>Tc6lW5^N4RWvdST4^OazKqsj( diff --git a/mods/unified_inventory_plus/textures/pattern_rotate2.png b/mods/unified_inventory_plus/textures/pattern_rotate2.png deleted file mode 100644 index 83419309a915905fa1d22d5bbce8d41d7b901bf1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 343 zcmV-d0jU0oP)W#)`&d{BDujUdt`NswlAFKIN0|-DzM~7)3;=@_*wQXmbgEJ)g^r(ifBkL$j@Ayo&o?f-7V z*iH)EqUi0cE1b7(Sp(lp81m<#y$wQ7&ma3+7f> pwRI$_j+ukFJ)mdn)X~wQi!WjPN*G&wP`UsB002ovPDHLkV1gYvjk5p% diff --git a/mods/unified_inventory_plus/textures/ui_crafting_long_arrow.png b/mods/unified_inventory_plus/textures/ui_crafting_long_arrow.png deleted file mode 100644 index 29f7e26af1f50f92986d8098c2e202ab9f5058f0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1419 zcmdT?>sQhT0R16kh?TEMqm)^hX(o20hb1Pd8OKLhavU}kn>+a2Fw&-DKsL{`d`;bO z1!#&hLz9`FwvJP?Qd=f%PH>n4Y5jbJ2tPHt0AM^MV$I1y8;k(3?ldW!82`Ca`==^Om0wwQ=;2L0{}qQv7dt@jP?W_WDUvic9Cc2OB+Ix;1dlpu5KT zb-tOJBh^nqQb6_kH@wLdL+UfVZ>2*11T8oybD`@ybuq> zhgWXmp^(4ZkPi|I0J(F`(y>N7Y(~JE3Ic;?IqU5L=BGva2-OlTIgbf6hG>G4Ap#EV z7D|Oi;pA7Voj?uYm^*+T=I6a-4na+M73S)pk*^|AoS$7nwrJj=NBD*i-Bl;yXTcOl zdOzb!&yKfyML3$Fy=S@zIT9nwA18SD0n91x`1_-UZ+F(>Xv_Olt~@)aLT08g>4OEwzYV9ltDQapIo_Hf&!m(_7~E5;rrrQNm4xcRxaISDj= zFOu&jQ1N}O=YRESPI0Hy-K#oeRUyuHQBQq~3}|hfr|^|khq;9N2eajYUa(g7@#|n5Ae`Cff8#%l%~Srxwj!2-)2J?7bNJiO4@B{#_E!IVb^{L21-Rzy)#bZ(1n1 z>9xJ#WC=#Q2cu?b&q$JDpRh@{C}koXhVGXQd9|GAihvuNK@E4wXU`UO8-9du&UF0G zEK_CA3{K?*it;WF0nLKtsJV4%{y@NdoX%7(hHq!yJv#Y1fd&dC%~NHIen2I}TP{${ zgJTx-Aq$N=6P4t#X-vG=;DbHxKYS;3S-JF}MC)fq??`498KC)bXFSgm-3FOFjfa(gxuHdz#G++#@5gQ+#Eem!wg5K}w z!`@*6Zk_rJ*ZtKhy3i-tF1KfwyV130+ajB^;``cCwb{(xvEvHS3OLxFpEL|JO@D7f Miii!reVktS7ZklIod5s; From 3397d8ff0101f4d95cd8b2957c6a6589cc0268fd Mon Sep 17 00:00:00 2001 From: TheEt1234 Date: Fri, 3 Oct 2025 20:26:44 +0200 Subject: [PATCH 11/28] ... --- .gitmodules | 3 + mods/moblib/Readme.md | 51 - mods/moblib/init.lua | 1 - mods/moblib/main.lua | 326 ------ mods/moblib/mod.conf | 4 - mods/modlib | 1 + mods/modlib/License.txt | 7 - mods/modlib/Readme.md | 37 - mods/modlib/b3d.lua | 1147 ------------------- mods/modlib/base64.lua | 132 --- mods/modlib/binary.lua | 236 ---- mods/modlib/bluon.lua | 333 ------ mods/modlib/build/html_entities.lua | 19 - mods/modlib/doc/b3d.md | 79 -- mods/modlib/doc/b3d_specification.txt | 260 ----- mods/modlib/doc/bluon.md | 132 --- mods/modlib/doc/irr_obj_spec.md | 76 -- mods/modlib/doc/json.md | 9 - mods/modlib/doc/minetest/conf.md | 31 - mods/modlib/doc/minetest/schematic.md | 79 -- mods/modlib/doc/minetest/texmod.md | 39 - mods/modlib/doc/persistence/lua_log_file.md | 23 - mods/modlib/doc/persistence/sqlite3.md | 41 - mods/modlib/doc/schema.md | 47 - mods/modlib/file.lua | 164 --- mods/modlib/func.lua | 126 -- mods/modlib/hashheap.lua | 117 -- mods/modlib/hashlist.lua | 93 -- mods/modlib/heap.lua | 60 - mods/modlib/init.lua | 147 --- mods/modlib/iterator.lua | 311 ----- mods/modlib/json.lua | 402 ------- mods/modlib/kdtree.lua | 64 -- mods/modlib/less_than.lua | 53 - mods/modlib/logo.svg | 38 - mods/modlib/luon.lua | 207 ---- mods/modlib/math.lua | 182 --- mods/modlib/matrix4.lua | 180 --- mods/modlib/minetest.lua | 90 -- mods/modlib/minetest/boxes.lua | 166 --- mods/modlib/minetest/colorspec.lua | 325 ------ mods/modlib/minetest/gametime.lua | 16 - mods/modlib/minetest/liquid.lua | 122 -- mods/modlib/minetest/luon.lua | 29 - mods/modlib/minetest/media.lua | 61 - mods/modlib/minetest/misc.lua | 328 ------ mods/modlib/minetest/mod.lua | 184 --- mods/modlib/minetest/obj.lua | 190 --- mods/modlib/minetest/png.lua | 483 -------- mods/modlib/minetest/raycast.lua | 137 --- mods/modlib/minetest/schematic.lua | 193 ---- mods/modlib/minetest/texmod.lua | 30 - mods/modlib/minetest/texmod/calc_dims.lua | 97 -- mods/modlib/minetest/texmod/dsl.lua | 422 ------- mods/modlib/minetest/texmod/gen_tex.lua | 190 --- mods/modlib/minetest/texmod/read.lua | 429 ------- mods/modlib/minetest/texmod/write.lua | 181 --- mods/modlib/minetest/wielditem_change.lua | 66 -- mods/modlib/mod.conf | 5 - mods/modlib/persistence.lua | 23 - mods/modlib/persistence/lua_log_file.lua | 194 ---- mods/modlib/persistence/sqlite3.lua | 318 ----- mods/modlib/quaternion.lua | 165 --- mods/modlib/schema.lua | 331 ------ mods/modlib/table.lua | 889 -------------- mods/modlib/tex.lua | 386 ------- mods/modlib/text.lua | 189 --- mods/modlib/trie.lua | 133 --- mods/modlib/utf8.lua | 102 -- mods/modlib/vararg.lua | 64 -- mods/modlib/vector.lua | 274 ----- mods/modlib/web.lua | 7 - mods/modlib/web/html.lua | 27 - mods/modlib/web/html/entities.lua | 3 - mods/modlib/web/uri.lua | 42 - 75 files changed, 4 insertions(+), 12144 deletions(-) delete mode 100644 mods/moblib/Readme.md delete mode 100644 mods/moblib/init.lua delete mode 100644 mods/moblib/main.lua delete mode 100644 mods/moblib/mod.conf create mode 160000 mods/modlib delete mode 100644 mods/modlib/License.txt delete mode 100644 mods/modlib/Readme.md delete mode 100644 mods/modlib/b3d.lua delete mode 100644 mods/modlib/base64.lua delete mode 100644 mods/modlib/binary.lua delete mode 100644 mods/modlib/bluon.lua delete mode 100644 mods/modlib/build/html_entities.lua delete mode 100644 mods/modlib/doc/b3d.md delete mode 100644 mods/modlib/doc/b3d_specification.txt delete mode 100644 mods/modlib/doc/bluon.md delete mode 100644 mods/modlib/doc/irr_obj_spec.md delete mode 100644 mods/modlib/doc/json.md delete mode 100644 mods/modlib/doc/minetest/conf.md delete mode 100644 mods/modlib/doc/minetest/schematic.md delete mode 100644 mods/modlib/doc/minetest/texmod.md delete mode 100644 mods/modlib/doc/persistence/lua_log_file.md delete mode 100644 mods/modlib/doc/persistence/sqlite3.md delete mode 100644 mods/modlib/doc/schema.md delete mode 100644 mods/modlib/file.lua delete mode 100644 mods/modlib/func.lua delete mode 100644 mods/modlib/hashheap.lua delete mode 100644 mods/modlib/hashlist.lua delete mode 100644 mods/modlib/heap.lua delete mode 100644 mods/modlib/init.lua delete mode 100644 mods/modlib/iterator.lua delete mode 100644 mods/modlib/json.lua delete mode 100644 mods/modlib/kdtree.lua delete mode 100644 mods/modlib/less_than.lua delete mode 100644 mods/modlib/logo.svg delete mode 100644 mods/modlib/luon.lua delete mode 100644 mods/modlib/math.lua delete mode 100644 mods/modlib/matrix4.lua delete mode 100644 mods/modlib/minetest.lua delete mode 100644 mods/modlib/minetest/boxes.lua delete mode 100644 mods/modlib/minetest/colorspec.lua delete mode 100644 mods/modlib/minetest/gametime.lua delete mode 100644 mods/modlib/minetest/liquid.lua delete mode 100644 mods/modlib/minetest/luon.lua delete mode 100644 mods/modlib/minetest/media.lua delete mode 100644 mods/modlib/minetest/misc.lua delete mode 100644 mods/modlib/minetest/mod.lua delete mode 100644 mods/modlib/minetest/obj.lua delete mode 100644 mods/modlib/minetest/png.lua delete mode 100644 mods/modlib/minetest/raycast.lua delete mode 100644 mods/modlib/minetest/schematic.lua delete mode 100644 mods/modlib/minetest/texmod.lua delete mode 100644 mods/modlib/minetest/texmod/calc_dims.lua delete mode 100644 mods/modlib/minetest/texmod/dsl.lua delete mode 100644 mods/modlib/minetest/texmod/gen_tex.lua delete mode 100644 mods/modlib/minetest/texmod/read.lua delete mode 100644 mods/modlib/minetest/texmod/write.lua delete mode 100644 mods/modlib/minetest/wielditem_change.lua delete mode 100644 mods/modlib/mod.conf delete mode 100644 mods/modlib/persistence.lua delete mode 100644 mods/modlib/persistence/lua_log_file.lua delete mode 100644 mods/modlib/persistence/sqlite3.lua delete mode 100644 mods/modlib/quaternion.lua delete mode 100644 mods/modlib/schema.lua delete mode 100644 mods/modlib/table.lua delete mode 100644 mods/modlib/tex.lua delete mode 100644 mods/modlib/text.lua delete mode 100644 mods/modlib/trie.lua delete mode 100644 mods/modlib/utf8.lua delete mode 100644 mods/modlib/vararg.lua delete mode 100644 mods/modlib/vector.lua delete mode 100644 mods/modlib/web.lua delete mode 100644 mods/modlib/web/html.lua delete mode 100644 mods/modlib/web/html/entities.lua delete mode 100644 mods/modlib/web/uri.lua diff --git a/.gitmodules b/.gitmodules index 2d3bc13b..aff2b473 100644 --- a/.gitmodules +++ b/.gitmodules @@ -19,3 +19,6 @@ [submodule "mods/sethome"] path = mods/sethome url = https://github.com/minetest-game/sethome +[submodule "mods/modlib"] + path = mods/modlib + url = https://github.com/appgurueu/modlib diff --git a/mods/moblib/Readme.md b/mods/moblib/Readme.md deleted file mode 100644 index 84325757..00000000 --- a/mods/moblib/Readme.md +++ /dev/null @@ -1,51 +0,0 @@ -# Entity Library (`moblib`) - -Low-level high-performance entity library - -## About - -Depends on [`modlib`](https://github.com/appgurueu/modlib). Licensed under the MIT License. Written by Lars Mueller aka LMD or appguru(eu). - -## Links - -* [GitHub](https://github.com/appgurueu/moblib) - sources, issue tracking, contributing -* [Discord](https://discordapp.com/invite/ysP74by) - discussion, chatting -* [Minetest Forum](https://forum.minetest.net/viewtopic.php?t=24671) - (more organized) discussion -* [ContentDB](https://content.minetest.net/packages/LMD/moblib) - releases (cloning from GitHub is recommended) - -## API - -Mostly self-documenting code. Mod namespace is `moblib`, containing all variables & functions. - -### `vector get_rotation(vector direction)` - -Returns rotation required to rotate a z-facing model in direction. - -### `vector get_wield_rotation(vector direction)` - -Same as `get_rotation` but for wield_images. - -### `vector get_direction(vector rotation)` - -Inverse of `get_rotation`. - -### `register_entity(name, def)` - -### `register_entity(text name, table def)` - -```lua -moblib.register_entity(name, { - initial_properties = {...}, - lua_properties = { - moveresult = { - collisions = nil, - axes = nil, - old_velocity = nil, - acceleration_dependent = nil - }, - staticdata = "json" or "lua" - }, - on_step = ..., - ... -}) -``` \ No newline at end of file diff --git a/mods/moblib/init.lua b/mods/moblib/init.lua deleted file mode 100644 index 6758f808..00000000 --- a/mods/moblib/init.lua +++ /dev/null @@ -1 +0,0 @@ -modlib.mod.init() \ No newline at end of file diff --git a/mods/moblib/main.lua b/mods/moblib/main.lua deleted file mode 100644 index c7403899..00000000 --- a/mods/moblib/main.lua +++ /dev/null @@ -1,326 +0,0 @@ -storage = minetest.get_mod_storage() -entities_by_id = setmetatable({}, {__mode = "v"}) -objects_by_id = setmetatable({}, { - __index = function(_, id) - local entity = entities_by_id[id] - return entity and entity.object - end, - __newindex = function(self, id, object) - local luaentity = object:get_luaentity() - if luaentity then - entities_by_id[id] = luaentity - else - self[id] = object - end - end, - __mode = "v" -}) - -local highest_id = storage:get_int("highest_id") - -minetest.register_on_joinplayer(function(player) - -- INFO no need to check whether it's an entity - rawset(objects_by_id, player:get_player_name(), player) -end) - -minetest.register_on_leaveplayer(function(player) - objects_by_id[player:get_player_name()] = nil -end) - -function get_id(object) - if object:is_player() then - return object:get_player_name() - end - local luaentity = object:get_luaentity() - if luaentity and luaentity._ then - return luaentity._.id - end -end - -function get_object(id) - return objects_by_id[id] -end - -function get_entity(id) - return entities_by_id[id] -end - --- x/z-rotation -local function horizontal_rotation(direction) - return math.atan2(direction.y, math.sqrt(direction.x*direction.x + direction.z*direction.z)) -end - --- y-rotation -local function vertical_rotation(direction) - return -math.atan2(direction.x, direction.z) -end - --- gets rotation in radians for a z-facing object -function get_rotation(direction) - return { - x = horizontal_rotation(direction), - y = vertical_rotation(direction), - z = 0 - } -end - --- converts a rotation from -pi to pi to 2pi to 0 -function convert_rotation(rotation) - return vector.apply(rotation, function(c) - if c < 0 then - return 2*math.pi + c - end - return c - end) -end - --- shorthand -function get_converted_rotation(direction) - return convert_rotation(get_rotation(direction)) -end - --- normalizes a rotation -function normalize_rotation(rotation) - return vector.apply(rotation, function(c) - local nc = c % (2*math.pi) - if c < 0 then - return 2*math.pi + nc - end - return nc - end) -end - -function get_minimum_converted_rotation_difference(rotation, other_rotation) - return vector.apply(vector.subtract(rotation, other_rotation), function(c) - if c > math.pi then - return -2*math.pi + c - end - if c < -math.pi then - return 2*math.pi + c - end - return c - end) -end - --- gets rotation in radians for a wielditem (such as a sword) -function get_wield_rotation(direction) - return { - x = 0, - y = 1.5*math.pi+vertical_rotation(direction), - z = 1.25*math.pi+horizontal_rotation(direction) - } -end - --- gets the direction for a rotated vector (0, 0, 1), inverse of get_rotation -function get_direction(rotation) - local rx, ry = rotation.x, rotation.y - local direction = {} - -- x rotation - direction.y = math.sin(rx) - local z = math.cos(rx) - -- y rotation - direction.x = -(z * math.sin(ry)) - direction.z = z * math.cos(ry) - return direction -end - -function set_look_dir(player, direction) - local rotation = get_rotation(direction) - player:set_look_vertical(-rotation.x) - player:set_look_horizontal(rotation.y) -end - -function get_eye_pos(object) - local eye_pos = object:get_pos() - if object:is_player() then - eye_pos.y = eye_pos.y + object:get_properties().eye_height - end - return eye_pos -end - -function get_center(object) - local collisionbox = object:get_properties().collisionbox - return vector.add(object:get_pos(), vector.divide(vector.add(vector.new(collisionbox[1], collisionbox[2], collisionbox[3]), vector.new(unpack(collisionbox, 4))), 2)) -end - -function get_mass(object) - local entity = object:get_luaentity() - if entity and entity._mass then - return entity._mass - end - local collisionbox = object:get_properties().collisionbox - local mass = (collisionbox[4] - collisionbox[1]) * (collisionbox[5] - collisionbox[2]) * (collisionbox[6] - collisionbox[3]) - assert(mass > 0) - return mass -end - -function calculate_damage(object, time_since_last_punch, caps) - local damage = 0 - local armor_groups = assert(object:get_armor_groups()) -- object has to be alive - for group, group_damage in pairs(caps.damage_groups) do - damage = damage + group_damage * (armor_groups[group] or 0) / 100 - end - return damage * math.min(1, math.max(0, time_since_last_punch / caps.full_punch_interval)) -end - --- TODO implement physics such as air resistance -local engine_has_moveresult = minetest.has_feature("object_step_has_moveresult") -local sensitivity = 0.01 -function register_entity(name, def) - local props = def.lua_properties - def.lua_properties = nil - local on_activate = def.on_activate or function() end - local on_step = def.on_step or function() end - local terminal_speed = props.terminal_speed - if terminal_speed then - local old_on_step = on_step - function on_step(self, dtime, ...) - old_on_step(self, dtime, ...) - local obj = self.object - local vel = obj:get_velocity() - if not vel then return end -- object has been deleted - local len = vector.length(obj:get_velocity()) - if len > terminal_speed then - obj:set_velocity(vector.multiply(vector.divide(vel, len))) - end - end - end - local props_staticdata = props.staticdata - local props_id = props.id - if props_id then - assert(props_staticdata) - end - if props_staticdata then - local implementation - if type(props_staticdata) == "table" then - implementation = props_staticdata - else - implementation = ({ - json = { - serializer = minetest.write_json, - deserializer = minetest.parse_json - }, - lua = { - serializer = minetest.serialize, - deserializer = minetest.deserialize - } - })[props_staticdata] - end - local serializer = implementation.serializer - local deserializer = implementation.deserializer - local old_on_activate = on_activate - function on_activate(self, staticdata, dtime) - self._ = (staticdata ~= "" and deserializer(staticdata)) or {} - if props_id then - if not self._.id then - highest_id = highest_id + 1 - self._.id = highest_id - storage:set_int("highest_id", highest_id) - end - entities_by_id[self._.id] = self - end - old_on_activate(self, staticdata, dtime) - end - function def.get_staticdata(self) - return serializer(self._) - end - end - -- TODO consider HACK for #10158 - if props.moveresult then - -- localizing variables for performance reasons - local mr = props.moveresult - local mr_collisions = mr.collisions - local mr_axes = mr.axes - local mr_old_velocity = mr.old_velocity - local mr_acc_dependent = mr.acceleration_dependent - local mr_speed_diff = mr.speed_difference - local mr_moblib = mr.moblib - local old_on_activate = on_activate - function on_activate(self, staticdata, dtime) - old_on_activate(self, staticdata, dtime) - self._last_velocity = self.object:get_velocity() - end - local old_on_step = on_step - function on_step(self, dtime, moveresult) - local obj = self.object - if engine_has_moveresult and not mr_acc_dependent and not mr_moblib then - if moveresult.collides then - if mr_axes then - local axes = {} - for _, collision in ipairs(moveresult.collisions) do - axes[collision.axis] = true - end - moveresult.axes = axes - end - if mr_old_velocity then - if not moveresult.collisions[1] then - moveresult.old_velocity = self._last_velocity - else - moveresult.old_velocity = moveresult.collisions[1].old_velocity - end - end - if mr_speed_diff then - local expected_vel = vector.add(self._last_velocity, vector.multiply(obj:get_acceleration(), dtime)) - moveresult.speed_difference = vector.length(vector.subtract(expected_vel, obj:get_velocity())) - end - end - else - moveresult = {collides = false} - if self._last_velocity then - local expected_vel = vector.add(self._last_velocity, vector.multiply(obj:get_acceleration(), dtime)) - local velocity = obj:get_velocity() - local diff = vector.subtract(expected_vel, velocity) - local speed_difference = vector.length(diff) - local collides = speed_difference >= sensitivity - moveresult.collides = collides - if collides then - if mr_speed_diff then - moveresult.speed_difference = speed_difference - end - if mr_collisions then - local collisions = {} - diff = vector.apply(diff, math.abs) - local new_velocity = self._last_velocity - for axis, component_diff in pairs(diff) do - if component_diff > sensitivity then - new_velocity[axis] = velocity[axis] - table.insert(collisions, { - axis = axis, - old_velocity = self._last_velocity, - new_velocity = new_velocity - }) - end - end - moveresult.collisions = collisions - end - if mr_axes then - local axes = {} - diff = vector.apply(diff, math.abs) - for axis, component_diff in pairs(diff) do - if component_diff > sensitivity then - axes[axis] = true - end - end - moveresult.axes = axes - end - if mr_old_velocity then - moveresult.old_velocity = self._last_velocity - end - if mr_acc_dependent then - moveresult.acceleration_dependent = vector.length(vector.subtract(self._last_velocity, velocity)) < sensitivity - end - end - end - end - old_on_step(self, dtime, moveresult) - self._last_velocity = obj:get_velocity() - end - function def._set_velocity(self, velocity) - self.object:set_velocity(velocity) - self._last_velocity = velocity - end - end - def.on_activate = on_activate - def.on_step = on_step - minetest.register_entity(name, def) -end \ No newline at end of file diff --git a/mods/moblib/mod.conf b/mods/moblib/mod.conf deleted file mode 100644 index 11d78887..00000000 --- a/mods/moblib/mod.conf +++ /dev/null @@ -1,4 +0,0 @@ -name=moblib -description=Low-level high-performance entity library -author=LMD aka appguru(eu) -depends=modlib \ No newline at end of file diff --git a/mods/modlib b/mods/modlib new file mode 160000 index 00000000..59ed71df --- /dev/null +++ b/mods/modlib @@ -0,0 +1 @@ +Subproject commit 59ed71df15e4e01e0bb096e7b1d709ea9fdb25cb diff --git a/mods/modlib/License.txt b/mods/modlib/License.txt deleted file mode 100644 index 8532a897..00000000 --- a/mods/modlib/License.txt +++ /dev/null @@ -1,7 +0,0 @@ -Copyright 2019 - 2021 Lars Mueller alias LMD or appguru(eu) - -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. diff --git a/mods/modlib/Readme.md b/mods/modlib/Readme.md deleted file mode 100644 index e8a92286..00000000 --- a/mods/modlib/Readme.md +++ /dev/null @@ -1,37 +0,0 @@ -# ![Logo](logo.svg) Modding Library (`modlib`) -Was taken from https://github.com/appgurueu/modlib, readme.md modified - -Multipurpose Minetest Modding Library - -## At a glance - -No dependencies. Licensed under the MIT License. Written by Lars Mueller aka LMD or appguru(eu). Requires Lua 5.1 / LuaJIT. - -### Acknowledgement - -* [luk3yx](https://github.com/luk3yx): Various suggestions, bug reports and fixes -* [grorp](https://github.com/grorp) (Gregor Parzefall): [Bug reports & proposed fixes for node box code](https://github.com/appgurueu/modlib/pull/8) -* [NobWow](https://github.com/NobWow/): [Another bugfix](https://github.com/appgurueu/modlib/pull/7) - -### Principles - -* Game-agnostic: Modlib aims to provide nothing game-specific; -* Minimal invasiveness: Modlib should not disrupt other mods; - even at the expense of syntactic sugar, changes to the global - environment - apart from the addition of the modlib scope - are forbidden -* Architecture: Modlib is organized hierarchically -* Performance: Modlib tries to not compromise performance for convenience; modlib loads lazily - -## Tests - -The tests are located in a different repo, [`modlib_test`](https://github.com/appgurueu/modlib_test), as they are quite heavy due to testing the PNG reader using PngSuite. Reading the tests for examples of API usage is recommended. - -## API - -(Incomplete) documentation resides in the `doc` folder; you'll have to dive into the code for everything else. - -The mod namespace is `modlib`, containing all modules which in turn contain variables & functions. - -Modules are lazily loaded by indexing the `modlib` table. Do `_ = modlib.` to avoid file load spikes at run time. - -Localizing modules (`local = modlib.`) is recommended. diff --git a/mods/modlib/b3d.lua b/mods/modlib/b3d.lua deleted file mode 100644 index 5b15a72c..00000000 --- a/mods/modlib/b3d.lua +++ /dev/null @@ -1,1147 +0,0 @@ --- Localize globals -local assert, error, math, modlib, next, ipairs, pairs, setmetatable, string_char, table - = assert, error, math, modlib, next, ipairs, pairs, setmetatable, string.char, table - -local mat4 = modlib.matrix4 - -local read_int, read_single = modlib.binary.read_int, modlib.binary.read_single - -local write_int, write_uint, write_single = modlib.binary.write_int, modlib.binary.write_uint, modlib.binary.write_single - -local fround = modlib.math.fround - --- Set environment -local _ENV = {} -setfenv(1, _ENV) - -local metatable = {__index = _ENV} - ---+ Reads a single BB3D chunk from a stream ---+ Doing `assert(stream:read(1) == nil)` afterwards is recommended ---+ See `b3d_specification.txt` as well as https://github.com/blitz-research/blitz3d/blob/master/blitz3d/loader_b3d.cpp ---> B3D model -function read(stream) - local left = 8 - - local function byte() - left = left - 1 - return assert(stream:read(1):byte()) - end - - local function int() - return read_int(byte, 4) - end - - local function id() - return int() + 1 - end - - local function optional_id() - local id = int() - if id == -1 then - return - end - return id + 1 - end - - local function string() - local rope = {} - while true do - left = left - 1 - local char = assert(stream:read(1)) - if char == "\0" then - return table.concat(rope) - end - table.insert(rope, char) - end - end - - local function float() - return read_single(byte) - end - - local function float_array(length) - local list = {} - for index = 1, length do - list[index] = float() - end - return list - end - - local function color() - local ret = {} - ret.r = float() - ret.g = float() - ret.b = float() - ret.a = float() - return ret - end - - local function vector3() - return float_array(3) - end - - local function quaternion() - local w = float() - local x = float() - local y = float() - local z = float() - return {x, y, z, w} - end - - local function content() - if left < 0 then - error(("unexpected EOF at position %d"):format(stream:seek())) - end - return left ~= 0 - end - - local chunk - local chunks = { - TEXS = function() - local textures = {} - while content() do - local tex = {} - tex.file = string() - tex.flags = int() - tex.blend = int() - tex.pos = float_array(2) - tex.scale = float_array(2) - tex.rotation = float() - table.insert(textures, tex) - end - return textures - end, - BRUS = function() - local brushes = {} - local n_texs = int() - assert(n_texs <= 8) - while content() do - local brush = {} - brush.name = string() - brush.color = color() - brush.shininess = float() - brush.blend = int() - brush.fx = int() - brush.texture_id = {} - for index = 1, n_texs do - brush.texture_id[index] = optional_id() - end - table.insert(brushes, brush) - end - return brushes - end, - VRTS = function() - local vertices = {} - vertices.flags = int() - vertices.tex_coord_sets = int() - vertices.tex_coord_set_size = int() - assert(vertices.tex_coord_sets <= 8 and vertices.tex_coord_set_size <= 4) - local has_normal = (vertices.flags % 2 == 1) or nil - local has_color = (math.floor(vertices.flags / 2) % 2 == 1) or nil - while content() do - local vertex = {} - vertex.pos = vector3() - vertex.normal = has_normal and vector3() - vertex.color = has_color and color() - vertex.tex_coords = {} - for tex_coord_set = 1, vertices.tex_coord_sets do - local tex_coords = {} - for tex_coord = 1, vertices.tex_coord_set_size do - tex_coords[tex_coord] = float() - end - vertex.tex_coords[tex_coord_set] = tex_coords - end - table.insert(vertices, vertex) - end - return vertices - end, - TRIS = function() - local tris = {} - tris.brush_id = id() - tris.vertex_ids = {} - while content() do - local i = id() - local j = id() - local k = id() - table.insert(tris.vertex_ids, {i, j, k}) - end - return tris - end, - MESH = function() - local mesh = {} - mesh.brush_id = optional_id() - mesh.vertices = chunk{VRTS = true} - mesh.triangle_sets = {} - repeat - local tris = chunk{TRIS = true} - table.insert(mesh.triangle_sets, tris) - until not content() - return mesh - end, - BONE = function() - local bone = {} - while content() do - local vertex_id = id() - assert(not bone[vertex_id], "duplicate vertex weight") - local weight = float() - if weight > 0 then - -- Many exporters include unneeded zero weights - bone[vertex_id] = weight - end - end - return bone - end, - KEYS = function() - local flags = int() - local _flags = flags % 8 - local rotation, scale, position - if _flags >= 4 then - rotation = true - _flags = _flags - 4 - end - if _flags >= 2 then - scale = true - _flags = _flags - 2 - end - position = _flags >= 1 - local bone = { - flags = flags - } - while content() do - local frame = {} - frame.frame = int() - if position then - frame.position = vector3() - end - if scale then - frame.scale = vector3() - end - if rotation then - frame.rotation = quaternion() - end - table.insert(bone, frame) - end - return bone - end, - ANIM = function() - local ret = {} - ret.flags = int() -- flags are unused - ret.frames = int() - ret.fps = float() - return ret - end, - NODE = function() - local node = {} - node.name = string() - node.position = vector3() - node.scale = vector3() - node.keys = {} - node.rotation = quaternion() - node.children = {} - local node_type - -- See https://github.com/blitz-research/blitz3d/blob/master/blitz3d/loader_b3d.cpp#L263 - -- Order is not validated; double occurrences of mutually exclusive node def are - while content() do - local elem, type = chunk() - if type == "MESH" then - assert(not node_type) - node_type = "mesh" - node.mesh = elem - elseif type == "BONE" then - assert(not node_type) - node_type = "bone" - node.bone = elem - elseif type == "KEYS" then - modlib.table.append(node.keys, elem) - elseif type == "NODE" then - table.insert(node.children, elem) - elseif type == "ANIM" then - node.animation = elem - else - assert(not node_type) - node_type = "pivot" - end - end - -- Ensure frames are sorted ascendingly - table.sort(node.keys, function(a, b) - assert(a.frame ~= b.frame, "duplicate frame") - return a.frame < b.frame - end) - return node - end, - BB3D = function() - local version = int() - local self = { - version = { - major = math.floor(version / 100), - minor = version % 100, - }, - textures = {}, - brushes = {} - } - assert(self.version.major <= 2, "unsupported version: " .. self.version.major) - while content() do - local field, type = chunk{TEXS = true, BRUS = true, NODE = true} - if type == "TEXS" then - modlib.table.append(self.textures, field) - elseif type == "BRUS" then - modlib.table.append(self.brushes, field) - else - self.node = field - end - end - return self - end - } - - local function chunk_header() - left = left - 4 - return stream:read(4), int() - end - - function chunk(possible_chunks) - local type, new_left = chunk_header() - local parent_left - left, parent_left = new_left, left - if possible_chunks and not possible_chunks[type] then - error("expected one of " .. table.concat(modlib.table.keys(possible_chunks), ", ") .. ", found " .. type) - end - local res = assert(chunks[type])() - assert(left == 0) - left = parent_left - new_left - return res, type - end - - local self = chunk{BB3D = true} - return setmetatable(self, metatable) -end - --- Writer - -local function write_rope(self) - local rope = {} - - local written_len = 0 - local function write(str) - written_len = written_len + #str - table.insert(rope, str) - end - - local function byte(val) - write(string_char(val)) - end - - local function int(val) - write_int(byte, val, 4) - end - - local function id(val) - int(val - 1) - end - - local function optional_id(val) - int(val and (val - 1) or -1) - end - - local function string(val) - write(val) - write"\0" - end - - local function float(val) - write_single(byte, fround(val)) - end - - local function float_array(arr, len) - assert(#arr == len) - for i = 1, len do - float(arr[i]) - end - end - - local function color(val) - float(val.r) - float(val.g) - float(val.b) - float(val.a) - end - - local function vector3(val) - float_array(val, 3) - end - - local function quaternion(quat) - float(quat[4]) - float(quat[1]) - float(quat[2]) - float(quat[3]) - end - - local function chunk(name, write_func) - write(name) - - -- Insert placeholder for the 4-bit len - table.insert(rope, false) - written_len = written_len + 4 - local len_idx = #rope -- save index of placeholder - - local prev_written_len = written_len - write_func() - - -- Write the length of this chunk - local chunk_len = written_len - prev_written_len - local len_binary = {} - write_int(function(byte) - table.insert(len_binary, string_char(byte)) - end, chunk_len, 4) - rope[len_idx] = table.concat(len_binary) - end - - local function NODE(node) - chunk("NODE", function() - string(node.name) - vector3(node.position) - vector3(node.scale) - quaternion(node.rotation) - local mesh = node.mesh - if mesh then - chunk("MESH", function() - optional_id(mesh.brush_id) - local vertices = mesh.vertices - chunk("VRTS", function() - int(vertices.flags) - int(vertices.tex_coord_sets) - int(vertices.tex_coord_set_size) - for _, vertex in ipairs(vertices) do - vector3(vertex.pos) - if vertex.normal then vector3(vertex.normal) end - if vertex.color then color(vertex.color) end - for tex_coord_set = 1, vertices.tex_coord_sets do - local tex_coords = vertex.tex_coords[tex_coord_set] - for tex_coord = 1, vertices.tex_coord_set_size do - float(tex_coords[tex_coord]) - end - end - end - end) - for _, triangle_set in ipairs(mesh.triangle_sets) do - chunk("TRIS", function() - id(triangle_set.brush_id) - for _, tri in ipairs(triangle_set.vertex_ids) do - id(tri[1]) - id(tri[2]) - id(tri[3]) - end - end) - end - end) - end - if node.bone then - chunk("BONE", function() - for vertex_id, weight in pairs(node.bone) do - id(vertex_id) - float(weight) - end - end) - end - if node.keys then - local keys_by_flags = {} - for _, key in ipairs(node.keys) do - local flags = 0 - flags = flags - + (key.position and 1 or 0) - + (key.scale and 2 or 0) - + (key.rotation and 4 or 0) - keys_by_flags[flags] = keys_by_flags[flags] or {} - table.insert(keys_by_flags[flags], key) - end - for flags, keys in pairs(keys_by_flags) do - chunk("KEYS", function() - int(flags) - for _, frame in ipairs(keys) do - int(frame.frame) - if frame.position then vector3(frame.position) end - if frame.scale then vector3(frame.scale) end - if frame.rotation then quaternion(frame.rotation) end - end - end) - end - end - local anim = node.animation - if anim then - chunk("ANIM", function() - int(anim.flags) - int(anim.frames) - float(anim.fps) - end) - end - for _, child in ipairs(node.children) do - NODE(child) - end - end) - end - - chunk("BB3D", function() - int(self.version.major * 100 + self.version.minor) - if self.textures[1] then - chunk("TEXS", function() - for _, tex in ipairs(self.textures) do - string(tex.file) - int(tex.flags) - int(tex.blend) - float_array(tex.pos, 2) - float_array(tex.scale, 2) - float(tex.rotation) - end - end) - end - if self.brushes[1] then - local max_n_texs = 0 - for _, brush in ipairs(self.brushes) do - for n in pairs(brush.texture_id) do - if n > max_n_texs then - max_n_texs = n - end - end - end - chunk("BRUS", function() - int(max_n_texs) - for _, brush in ipairs(self.brushes) do - string(brush.name) - color(brush.color) - float(brush.shininess) - int(brush.blend) - int(brush.fx) - for index = 1, max_n_texs do - optional_id(brush.texture_id[index]) - end - end - end) - end - if self.node then - NODE(self.node) - end - end) - return rope -end - -function write_string(self) - return table.concat(write_rope(self)) -end - -function write(self, stream) - for _, str in ipairs(write_rope(self)) do - stream:write(str) - end -end - --- B3D to glTF converter --- See https://registry.khronos.org/glTF/specs/2.0/glTF-2.0.html ---! Highly experimental; expect bugs! -do - -- glTF constants - local array_buffer = 34962 -- "Buffer containing vertex attributes, such as vertices, texcoords or colors." - local element_array_buffer = 34963 -- "Buffer used for element indices." - local component_type = { - signed_byte = 5120, - unsigned_byte = 5121, - signed_short = 5122, - unsigned_short = 5123, - unsigned_int = 5125, - float = 5126, - } - - -- Coordinate system conversions: - -- "Blitz 3D uses a left-handed system: X+ is to the right. Y+ is up. Z+ is forward." - -- "glTF uses a right-handed coordinate system. glTF defines +Y as up, +Z as forward, and -X as right; - -- the front of a glTF asset faces +Z." - - local function translation_to_gltf(vec) - return {-vec[1], vec[2], vec[3]} -- invert the X-axis - end - - local function quaternion_to_gltf(quat) - -- TODO (!) is this correct? - return {-quat[1], quat[2], quat[3], quat[4]} -- invert the X-axis - end - - -- Convert a color from table format to glTF RGBA list format - local function color_to_gltf(col) - return {col.r, col.g, col.b, col.a} - end - - -- Basic helpers for writing to the buffer, all parameterized in terms of `write_byte` - - local function write_index(write_byte, index) - write_uint(write_byte, index - 1 --[[1-based to 0-based]], 4) - end - - local function write_float(write_byte, float) - assert(-math.huge < float and float < math.huge) - assert(-math.huge < fround(float) and fround(float) < math.huge, ("%.18g got %.18g"):format(float, fround(float))) - write_single(write_byte, fround(float)) - end - - local function write_floats(write_byte, floats, expected_len) - assert(#floats == expected_len) - for i = 1, expected_len do - write_float(write_byte, floats[i]) - end - end - - local function write_vector(write_byte, vec) - return write_floats(write_byte, vec, 3) - end - - local function write_translation(write_byte, vec) - return write_vector(write_byte, translation_to_gltf(vec)) - end - - local function write_quaternion(write_byte, quat) - -- XYZW order is already correct, but we still need to convert left-handed to right-handed - return write_floats(write_byte, quaternion_to_gltf(quat), 4) - end - - function to_gltf(self) - -- Accessor helper: Stores arrays of raw data in a buffer, produces views & accessors. - -- Everything is dumped in the same large buffer. - local buffer_rope = {} -- buffer content (table of strings) - local buffer_views = {} -- glTF buffer views - local accessors = {} -- glTF accessors - local offset = 0 -- current byte offset - local function add_accessor( - type, -- name of the composite type (e.g. SCALAR, VEC3, VEC4, MAT4, ...) - comp_type, -- name of the component type (e.g. float, unsigned_int, ...) - index, -- true / false / nil: whether this is an index (true) or vertex data (false) or neither (nil) - func -- `function(write_byte) ... return count, min, max end` to be called to write to the buffer view; - -- the count of elements written must be returned; min and max may be returned - ) - -- Always add padding to obtain a multiple of 4 - -- TODO (?) don't add padding if it isn't required - table.insert(buffer_rope, ("\0"):rep(offset % 4)) - offset = math.ceil(offset / 4) * 4 - local bytes_written = 0 - local count, min, max = func(function(byte) - table.insert(buffer_rope, string_char(byte)) - bytes_written = bytes_written + 1 - end) - assert(count) - - -- Add buffer view - table.insert(buffer_views, { - buffer = 0, -- 0-based - there only is one buffer - byteOffset = offset, - byteLength = bytes_written, - target = ((index == true) and element_array_buffer) -- index data - or ((index == false) and array_buffer) -- vertex data - or nil, -- no target hint - }) - table.insert(accessors, { - bufferView = #buffer_views - 1, -- 0-based - byteOffset = 0, -- view has correct offset - componentType = assert(component_type[comp_type]), - type = type, - count = count, - min = min, - max = max, - }) - - offset = offset + bytes_written - return #accessors - 1 -- 0-based index of the accessor - end - - local textures = {} -- glTF textures - local function add_texture(name) - -- TODO (?) add an appropriate sampler - table.insert(textures, {name = name}) - return #textures - 1 -- 0-based texture index - end - for _, tex in ipairs(self.textures) do - -- Assert that all values we don't map properly yet are defaults - -- TODO dig into Blitz3D sources to figure out the meaning of flags & blend - -- TODO (...) deal with flag value of 65536: - -- "The flags field value can conditional an additional flag value of '65536'. - -- This is used to indicate that the texture uses secondary UV values, ala the TextureCoords command." - assert(tex.flags == 1) -- TODO (?) see https://github.com/blitz-research/blitz3d/blob/master/gxruntime/gxcanvas.h#L59 - assert(tex.blend == 2) - -- Assert that the texture isn't transformed - assert(tex.rotation == 0) - assert(tex.pos[1] == 0 and tex.pos[2] == 0) - assert(tex.scale[1] == 1 and tex.scale[2] == 1) - add_texture(tex.file) - end - - -- Map brushes to materials (& textures) - local materials = {} - for i, brush in ipairs(self.brushes) do - -- Assert defaults - -- See https://github.com/blitz-research/blitz3d/blob/6beb288cb5962393684a59a4a44ac11524894939/blitz3d/brush.cpp#L164-L167: - -- 0 = default/replace, 1 = alpha, 2 = multiply, 3 = add - assert(brush.blend == 1) -- (alpha) - -- TODO (...) figure out what these "effects" are and if/how to map them to glTF - assert(brush.fx == 0) - assert(#brush.texture_id <= 1) -- TODO (...) this supports only a single texture per brush for now - local index - if brush.texture_id[1] then - index = brush.texture_id[1] -- 0-based - else - -- Implementations seem to implicitly assume textures for brushes - index = add_texture(brush.name) - end - materials[i] = { - name = brush.name, - alphaMode = "BLEND", - pbrMetallicRoughness = { - baseColorFactor = color_to_gltf(brush.color), - metallicFactor = brush.shininess, -- TODO (?) are these really equivalent? - -- Add texture if there is none - baseColorTexture = { - index = index, - -- `texCoord = 0` is the default already, no need to set it - }, - }, - } - end - - local meshes = {} - local function add_mesh(mesh, weights, add_neutral_bone) - local attributes = {} - - local vertices = mesh.vertices - attributes.POSITION = add_accessor("VEC3", "float", false, function(write_byte) - local inf = math.huge - local min_pos, max_pos = {inf, inf, inf}, {-inf, -inf, -inf} - for _, vertex in ipairs(mesh.vertices) do - local pos = translation_to_gltf(vertex.pos) - write_vector(write_byte, pos) - min_pos = modlib.vector.combine(min_pos, pos, math.min) - max_pos = modlib.vector.combine(max_pos, pos, math.max) - end - return #mesh.vertices, min_pos, max_pos -- vertex accessors MUST provide min & max - end) - - local has_normals = vertices.flags % 2 == 1 -- lowest bit set? - if has_normals then - attributes.NORMAL = add_accessor("VEC3", "float", false, function(write_byte) - for _, vertex in ipairs(mesh.vertices) do - -- Some B3D models don't seem to have their normals normalized. - -- TODO (?) raise a warning when handling this gracefully - write_translation(write_byte, modlib.vector.normalize(vertex.normal)) - end - return #mesh.vertices - end) - end - - local has_colors = vertices.flags % 4 >= 2 -- second lowest bit set? - if has_colors then - attributes.COLOR_0 = add_accessor("VEC4", "float", false, function(write_byte) - for _, vertex in ipairs(mesh.vertices) do - write_floats(write_byte, color_to_gltf(vertex.color), 4) - end - return #mesh.vertices - end) - end - - if vertices.tex_coord_sets >= 1 then - assert(vertices.tex_coord_set_size == 2) - for tex_coord_set = 1, vertices.tex_coord_sets do - local tcs_id = tex_coord_set - 1 -- 0-based - attributes[("TEXCOORD_%d"):format(tcs_id)] = add_accessor("VEC2", "float", false, function(write_byte) - for _, vertex in ipairs(mesh.vertices) do - write_floats(write_byte, vertex.tex_coords[tex_coord_set], 2) - end - return #mesh.vertices - end) - end - end - - if next(weights) ~= nil then - -- Count (& pack into list) joints influencing vertices, normalize weights - local max_count = 0 - local joint_ids = {} - local normalized_weights = {} - -- Handle (supposedly) animated/dynamic vertices (can still be static by having zero weights) - for vertex_id, joint_weights in pairs(weights) do - local total_weight = 0 - local count = 0 - for _, weight in pairs(joint_weights) do - total_weight = total_weight + weight - count = count + 1 - end - if total_weight > 0 then -- animated? - joint_ids[vertex_id] = {} - normalized_weights[vertex_id] = {} - for joint, weight in pairs(joint_weights) do - table.insert(joint_ids[vertex_id], joint) - table.insert(normalized_weights[vertex_id], weight / total_weight) - end - max_count = math.max(max_count, count) - end - end - -- Now search for static vertices - for vertex_id in ipairs(mesh.vertices) do - if not joint_ids[vertex_id] then - -- Vertex isn't influenced by any bones => Add a dummy neutral bone to influence this vertex - -- See https://github.com/KhronosGroup/glTF/issues/2269 - -- and https://github.com/KhronosGroup/glTF-Blender-IO/pull/1552/ - joint_ids[vertex_id] = {add_neutral_bone()} - normalized_weights[vertex_id] = {1} - max_count = math.max(max_count, 1) -- it is (theoretically) possible that all vertices are static - end - end - assert(max_count > 0) -- TODO (?) warning for max_count > 4 - for set_start = 1, max_count, 4 do -- Iterate sets of 4 bones - local set_id = math.floor(set_start / 4) -- 0-based => floor rather than ceil - -- Write the joint IDs - attributes[("JOINTS_%d"):format(set_id)] = add_accessor("VEC4", "unsigned_short", false, function(write_byte) - for vertex_id in ipairs(mesh.vertices) do - for i = set_start, set_start + 3 do - local vrt_joint_ids, vrt_norm_weights = assert(joint_ids[vertex_id]), assert(normalized_weights[vertex_id]) - assert(#vrt_joint_ids == #vrt_norm_weights) - local id = vrt_joint_ids[i] or 0 - local weight = vrt_norm_weights[i] or 0 - if weight == 0 then - id = 0 -- required by the glTF spec - end - write_uint(write_byte, id, 2) - end - end - return #mesh.vertices - end) - -- Write the corresponding weights - attributes[("WEIGHTS_%d"):format(set_id)] = add_accessor("VEC4", "float", false, function(write_byte) - for vertex_id in ipairs(mesh.vertices) do - for i = set_start, set_start + 3 do - local weight = (normalized_weights[vertex_id] or {})[i] or 0 - write_float(write_byte, weight) - end - end - return #mesh.vertices - end) - end - end - - -- Write the indices per triangle set - local primitives = {} - for i, triangle_set in ipairs(mesh.triangle_sets) do - local index_accessor = add_accessor("SCALAR", "unsigned_int", true, function(write_byte) - for _, tri in ipairs(triangle_set.vertex_ids) do - -- Flip winding order due to the coordinate system transformation - -- TODO (!) is this correct? - for j = 3, 1, -1 do - write_index(write_byte, tri[j]) - end - end - return 3 * #triangle_set.vertex_ids - end) - -- Each triangle set is equivalent to one glTF "primitive" - local brush_id = triangle_set.brush_id or mesh.brush_id - if brush_id == 0 then -- default brush - brush_id = nil -- TODO (?) add default material if there are UVs - else - brush_id = brush_id - 1 -- 0-based - end - primitives[i] = { - attributes = attributes, - indices = index_accessor, - material = brush_id, - -- `mode = 4` (triangles) is the default already, no need to set it - } - end - - table.insert(meshes, {primitives = primitives}) - return #meshes - 1 -- 0-based - end - - -- glTF lists - local nodes = {} - local skins = {} - local samplers = {} - local channels = {} - local function add_node( - node, -- b3d node to add - bind_mat, -- bind matrix of the parent bone (may be `nil` if none) - fps, -- fps of the parent bone (may be `nil` if none) - anim -- shared animation of the parent mesh - ) - table.insert(nodes, false) -- HACK first insert a placeholder to get a fixed ID - local node_id = #nodes - 1 -- 0-indexed <=> before `table.insert`! - - -- Animation (speed)? - fps = node.animation and node.animation.fps or fps - - -- Keyframes? - if node.keys then - -- Convert from a list of keyframes of three overrides to three lists of channels - local targets = { - translation = {output_type = "VEC3", b3d_field = "position", write_value = write_translation}, - scale = {output_type = "VEC3", b3d_field = "scale", write_value = write_vector}, - rotation = {output_type = "VEC4", b3d_field = "rotation", write_value = write_quaternion} - } - for _, keyframe in ipairs(node.keys) do - local frame = keyframe.frame - for _, target in pairs(targets) do - local value = keyframe[target.b3d_field] - if value then - table.insert(target, {frame = frame, value = value}) - end - end - end - for target, keyframes in pairs(targets) do - if #keyframes > 0 then - -- Write input (timestamps) - local input = add_accessor("SCALAR", "float", nil, function(write_byte) - local min, max = math.huge, -math.huge - for _, keyframe in ipairs(keyframes) do - local sec = keyframe.frame / (fps or 60) -- convert frames to seconds; default FPS is 60 - write_float(write_byte, sec) - min, max = math.min(min, sec), math.max(max, sec) - end - return #keyframes, {min}, {max} -- min and max are mandatory - end) - - -- Write output (overrides) - local output = add_accessor(keyframes.output_type, "float", nil, function(write_byte) - for _, keyframe in ipairs(keyframes) do - keyframes.write_value(write_byte, keyframe.value) - end - return #keyframes - end) - - table.insert(samplers, { - input = input, - output = output, - -- interpolation default is already linear, matching b3d - }) - - table.insert(channels, { - sampler = #samplers - 1, -- 0-based - target = { - node = node_id, - path = target, - } - }) - end - end - end - - if node.mesh then - -- Initialize skeletal animation - assert(not anim) - anim = { - weights = {}, - joints = {}, - inv_bind_mats = {}, - } - end - - if node.bone then - local joint_id = #anim.joints - table.insert(anim.joints, node_id) - - -- "To compose the local transformation matrix, TRS properties MUST be converted to matrices and postmultiplied in - -- the T * R * S order; first the scale is applied to the vertices, then the rotation, and then the translation." - local translation = translation_to_gltf(node.position) - local rotation = modlib.quaternion.normalize(quaternion_to_gltf(node.rotation)) - local scale = node.scale - local loc_trans_mat = mat4.scale(scale) - :compose(mat4.rotation(rotation)) - :compose(mat4.translation(translation)) - - -- Compute a proper inverse bind matrix as the inverse of the product of the transformation matrices - -- along the path from the root (the mesh) to the current node (the bone). - -- See e.g. https://stackoverflow.com/questions/17127994/opengl-bone-animation-why-do-i-need-inverse-of-bind-pose-when-working-with-gp - -- https://computergraphics.stackexchange.com/questions/7603/confusion-about-how-inverse-bind-pose-is-actually-calculated-and-used - bind_mat = bind_mat and bind_mat:multiply(loc_trans_mat) or loc_trans_mat - table.insert(anim.inv_bind_mats, bind_mat:inverse()) - - -- Insert into reverse lookup `anim.weights[vertex_id][joint_id] = weight` - -- such that writing the mesh can then write the weights per vertex - for vertex_id, weight in pairs(node.bone) do - if weight > 0 then - anim.weights[vertex_id] = anim.weights[vertex_id] or {} - anim.weights[vertex_id][joint_id] = weight - end - end - end - - local children = {} - for _, child in ipairs(node.children) do - table.insert(children, add_node(child, bind_mat, fps, anim)) - end - local mesh, skin_id, neutral_node_id - if node.mesh then - local neutral_joint_id - -- Lazily adds a placeholder for the neutral joint, returns joint ID - local function add_neutral_joint() - if neutral_joint_id then - return neutral_joint_id - end - neutral_node_id = #nodes -- 0-based - table.insert(nodes, { - name = "neutral_bone", - -- We need to flip the hierarchy: The neutral bone must be a parent of the mesh root; - -- if it were a sibling, there would be no common skeleton root (accepted by Blender but not by glTF validator); - -- if it were a child, transformations of the mesh root would affect it and it wouldn't be a neutral bone anymore. - children = {node_id}, - -- translation, scale, rotation all default to identity - }) - neutral_joint_id = #anim.joints -- 0-based - table.insert(anim.joints, neutral_node_id) - return neutral_joint_id -- 0-based - end - mesh = add_mesh(node.mesh, anim.weights, add_neutral_joint) - if anim.joints and anim.joints[1] then - if neutral_joint_id then - -- Duplicate the inverse bind matrix of the parent (which the neutral bone will be a child of) - table.insert(anim.inv_bind_mats, bind_mat or mat4.identity()) - end - table.insert(skins, { - inverseBindMatrices = add_accessor("MAT4", "float", nil, function(write_byte) - for _, inv_bind_mat in ipairs(anim.inv_bind_mats) do - assert(#inv_bind_mat == 4) - -- glTF uses column-major order (we use row-major order) - for i = 1, 4 do - for j = 1, 4 do - write_float(write_byte, inv_bind_mat[j][i]) - end - end - end - return #anim.inv_bind_mats - end), - joints = anim.joints, - skeleton = neutral_node_id, -- make the neutral bone the skeleton root - }) - skin_id = #skins - 1 -- 0-based - end - end - -- Now replace the placeholder - nodes[node_id + 1 --[[0-based to 1-based]]] = { - name = node.name, - mesh = mesh, - skin = skin_id, - children = children[1] and children, -- glTF does not allow empty lists - translation = translation_to_gltf(node.position), - scale = node.scale, - rotation = quaternion_to_gltf(node.rotation), - } - -- If a neutral bone exists, return the neutral bone (which has the node as a child) instead of the node - return neutral_node_id or node_id -- 0-based - end - - local scene, scenes - if self.node then - scene, scenes = 0, {{nodes = {add_node(self.node)}}} - end - - local buffer_string = table.concat(buffer_rope) - return { - asset = { - generator = "modlib b3d:to_gltf", - version = "2.0" - }, - -- Textures - textures = textures[1] and textures, -- glTF does not allow empty lists - materials = materials[1] and materials, - -- Accessors, buffer views & buffers - accessors = accessors, - bufferViews = buffer_views, - buffers = { - { - byteLength = #buffer_string, - uri = "data:application/octet-stream;base64," - .. modlib.base64.encode(buffer_string) -- Note: Blender requires base64 padding - }, - }, - -- Meshes & nodes - meshes = meshes, - nodes = nodes, - -- A scene is not strictly needed but is useful for getting rid of validator warnings & having a proper root defined - scene = scene, - scenes = scenes, - -- Animation - skins = skins, - -- B3D only contains (up to) a single animation - animations = channels[1] and { - { - channels = channels, - samplers = samplers, - }, - }, - } - end -end - -function write_gltf(self, file) - modlib.json:write_file(self:to_gltf(), file) -end - -local binary_search_frame = modlib.table.binary_search_comparator(function(a, b) - return modlib.table.default_comparator(a, b.frame) -end) - ---> list of { bone_name = string, parent_bone_name = string, position = vector, rotation = quaternion, scale = vector } -function get_animated_bone_properties(self, keyframe, interpolate) - local function get_frame_values(keys) - local values = keys[keyframe] - if values and values.frame == keyframe then - return { - position = values.position, - rotation = values.rotation, - scale = values.scale - } - end - local index = binary_search_frame(keys, keyframe) - if index > 0 then - return keys[index] - end - index = -index - assert(index > 1 and index <= #keys) - local a, b = keys[index - 1], keys[index] - if not interpolate then - return a - end - local ratio = (keyframe - a.frame) / (b.frame - a.frame) - return { - position = (a.position and b.position and modlib.vector.interpolate(a.position, b.position, ratio)) or a.position or b.position, - rotation = (a.rotation and b.rotation and modlib.quaternion.slerp(a.rotation, b.rotation, ratio)) or a.rotation or b.rotation, - scale = (a.scale and b.scale and modlib.vector.interpolate(a.scale, b.scale, ratio)) or a.scale or b.scale, - } - end - local bone_properties = {} - local function get_props(node, parent_bone_name) - local properties = {parent_bone_name = parent_bone_name} - - if keyframe > 0 and node.keys and next(node.keys) ~= nil then - modlib.table.add_all(properties, get_frame_values(node.keys)) - end - - if not properties.position then -- animation not present, fall back to node position - properties.position = modlib.table.copy(node.position) - end - - if properties.rotation then -- animation is relative to node rotation - properties.rotation = modlib.quaternion.compose(node.rotation, properties.rotation) - else - properties.rotation = modlib.table.copy(node.rotation) - end - - if not properties.scale then -- animation not present, fall back to node scale - properties.scale = modlib.table.copy(node.scale) - end - - if node.bone then - properties.bone_name = node.name - table.insert(bone_properties, properties) - end - for _, child in pairs(node.children or {}) do - get_props(child, properties.bone_name) - end - end - get_props(self.node) - return bone_properties -end - --- Export environment -return _ENV diff --git a/mods/modlib/base64.lua b/mods/modlib/base64.lua deleted file mode 100644 index b1f2a2a8..00000000 --- a/mods/modlib/base64.lua +++ /dev/null @@ -1,132 +0,0 @@ -local assert, floor, char, insert, concat = assert, math.floor, string.char, table.insert, table.concat - -local base64 = {} - -local alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/" - ---! This is currently 5 - 10x slower than a C(++) implementation like Minetest's `minetest.encode_base64` -function base64.encode( - str, -- byte string to encode - padding -- whether to add padding, defaults to `true` -) - local res = {} - for i = 1, #str - 2, 3 do - -- Convert 3 bytes to 4 sextets - local b1, b2, b3 = str:byte(i, i + 2) - insert(res, char( - alphabet:byte(floor(b1 / 4) + 1), -- high 6 bits of first byte - alphabet:byte(16 * (b1 % 4) + floor(b2 / 16) + 1), -- low 2 bits of first byte & high 4 bits of second byte - alphabet:byte(4 * (b2 % 16) + floor(b3 / 64) + 1), -- low 4 bits of second byte & high 2 bits of third byte - alphabet:byte((b3 % 64) + 1) -- low 6 bits of third byte - )) - end - -- Handle remaining 1 or 2 bytes: - -- Treat "missing" bytes to a multiple of 3 as "0" bytes, add appropriate padding. - local bytes_left = #str % 3 - if bytes_left == 1 then - local b = str:byte(#str) -- b2 and b3 are missing ("= 0") - insert(res, char( - alphabet:byte(floor(b / 4) + 1), - alphabet:byte(16 * (b % 4) + 1) - )) - -- Last two sextets depend only on missing bytes => padding - if padding ~= false then - insert(res, "==") - end - elseif bytes_left == 2 then - local b1, b2 = str:byte(#str - 1, #str) -- b3 is missing ("= 0") - insert(res, char( - alphabet:byte(floor(b1 / 4) + 1), - alphabet:byte(16 * (b1 % 4) + floor(b2 / 16) + 1), - alphabet:byte(4 * (b2 % 16) + 1) - )) - -- Last sextet depends only on missing byte => padding - if padding ~= false then - insert(res, "=") - end - end - - return concat(res) -end - --- Build reverse lookup table -local values = {} -for i = 1, #alphabet do - values[alphabet:byte(i)] = i - 1 -end - -local function decode_sextets_2(b1, b2) - local v1, v2 = values[b1], values[b2] - assert(v1 and v2) - assert(v2 % 16 == 0) -- 4 low bits from second sextet must be 0 - return char(4 * v1 + floor(v2 / 16)) -- first sextet + 2 high bits from second sextet -end - -local function decode_sextets_3(b1, b2, b3) - local v1, v2, v3 = values[b1], values[b2], values[b3] - assert(v1 and v2 and v3) - assert(v3 % 4 == 0) -- 2 low bits from third sextet must be 0 - return char( - 4 * v1 + floor(v2 / 16), -- first sextet + 2 high bits from second sextet - 16 * (v2 % 16) + floor(v3 / 4) -- 4 low bits from second sextet + 4 high bits from third sextet - ) -end - -local function decode_sextets_4(b1, b2, b3, b4) - local v1, v2, v3, v4 = values[b1], values[b2], values[b3], values[b4] - assert(v1 and v2 and v3 and v4) - return char( - 4 * v1 + floor(v2 / 16), -- first sextet + 2 high bits from second sextet - 16 * (v2 % 16) + floor(v3 / 4), -- 4 low bits from second sextet + 4 high bits from third sextet - 64 * (v3 % 4) + v4 -- 2 low bits from third sextet + fourth sextet - ) -end - ---! This is also about 10x slower than a C(++) implementation like Minetest's `minetest.decode_base64` -function base64.decode( - -- base64-encoded string to decode - str, - -- Whether to expect padding: - -- * `nil` (default) - may (or may not) be padded, - -- * `false` - must not be padded, - -- * `true` - must be padded - padding -) - -- Handle the empty string - the below code expects a nonempty string - if str == "" then return "" end - - local res = {} - -- Note: the last (up to) 4 sextets are deliberately excluded, since they may contain padding - for i = 1, #str - 4, 4 do - -- Convert 4 sextets to 3 bytes - insert(res, decode_sextets_4(str:byte(i, i + 3))) - end - local sextets_left = #str % 4 - if sextets_left == 0 then -- possibly padded - -- Convert 4 sextets to 3 bytes, taking padding into account - local b3, b4 = str:byte(#str - 1, #str) - if b3 == ("="):byte() then - assert(b4 == ("="):byte()) - assert(padding ~= false, "got padding") - insert(res, decode_sextets_2(str:byte(#str - 3, #str - 2))) - elseif b4 == ("="):byte() then - assert(padding ~= false, "got padding") - insert(res, decode_sextets_3(str:byte(#str - 3, #str - 1))) - else -- no padding necessary - assert(#str >= 4) - assert(#({str:byte(#str - 3, #str)}) == 4) - insert(res, decode_sextets_4(str:byte(#str - 3, #str))) - end - else -- no padding and length not divisible by 4 - assert(padding ~= true, "missing/invalid padding") - assert(sextets_left ~= 1) - if sextets_left == 2 then - insert(res, decode_sextets_2(str:byte(#str - 1, #str))) - elseif sextets_left == 3 then - insert(res, decode_sextets_3(str:byte(#str - 2, #str))) - end - end - return concat(res) -end - -return base64 \ No newline at end of file diff --git a/mods/modlib/binary.lua b/mods/modlib/binary.lua deleted file mode 100644 index c4f7d81d..00000000 --- a/mods/modlib/binary.lua +++ /dev/null @@ -1,236 +0,0 @@ --- Localize globals -local assert, math_huge, math_frexp, math_floor - = assert, math.huge, math.frexp, math.floor - -local positive_nan, negative_nan = modlib.math.positive_nan, modlib.math.negative_nan - --- Set environment -local _ENV = {} -setfenv(1, _ENV) - --- All little endian - ---+ Reads an IEEE 754 single-precision floating point number (f32) -function read_single(read_byte) - -- First read the mantissa - local mantissa = read_byte() / 0x100 - mantissa = (mantissa + read_byte()) / 0x100 - - -- Second and first byte in big endian: last bit of exponent + 7 bits of mantissa, sign bit + 7 bits of exponent - local exponent_byte = read_byte() - local sign_byte = read_byte() - local sign = 1 - if sign_byte >= 0x80 then - sign = -1 - sign_byte = sign_byte - 0x80 - end - local exponent = sign_byte * 2 - if exponent_byte >= 0x80 then - exponent = exponent + 1 - exponent_byte = exponent_byte - 0x80 - end - mantissa = (mantissa + exponent_byte) / 0x80 - if exponent == 0xFF then - if mantissa == 0 then - return sign * math_huge - end - -- Differentiating quiet and signalling nan is not possible in Lua, hence we don't have to do it - return sign == 1 and positive_nan or negative_nan - end - assert(mantissa < 1) - if exponent == 0 then - -- subnormal value - return sign * 2^-126 * mantissa - end - return sign * 2 ^ (exponent - 127) * (1 + mantissa) -end - ---+ Reads an IEEE 754 double-precision floating point number (f64) -function read_double(read_byte) - -- First read the mantissa - local mantissa = 0 - for _ = 1, 6 do - mantissa = (mantissa + read_byte()) / 0x100 - end - -- Second and first byte in big endian: last 4 bits of exponent + 4 bits of mantissa; sign bit + 7 bits of exponent - local exponent_byte = read_byte() - local sign_byte = read_byte() - local sign = 1 - if sign_byte >= 0x80 then - sign = -1 - sign_byte = sign_byte - 0x80 - end - local exponent = sign_byte * 0x10 - local mantissa_bits = exponent_byte % 0x10 - exponent = exponent + (exponent_byte - mantissa_bits) / 0x10 - mantissa = (mantissa + mantissa_bits) / 0x10 - if exponent == 0x7FF then - if mantissa == 0 then - return sign * math_huge - end - -- Differentiating quiet and signalling nan is not possible in Lua, hence we don't have to do it - return sign == 1 and positive_nan or negative_nan - end - assert(mantissa < 1) - if exponent == 0 then - -- subnormal value - return sign * 2^-1022 * mantissa - end - return sign * 2 ^ (exponent - 1023) * (1 + mantissa) -end - ---+ Reads doubles (f64) or floats (f32) ---: double reads an f64 if true, f32 otherwise -function read_float(read_byte, double) - return (double and read_double or read_single)(read_byte) -end - -function read_uint(read_byte, bytes) - local factor = 1 - local uint = 0 - for _ = 1, bytes do - uint = uint + read_byte() * factor - factor = factor * 0x100 - end - return uint -end - -function read_int(read_byte, bytes) - local uint = read_uint(read_byte, bytes) - local max = 0x100 ^ bytes - if uint >= max / 2 then - return uint - max - end - return uint -end - -function write_uint(write_byte, uint, bytes) - for _ = 1, bytes do - write_byte(uint % 0x100) - uint = math_floor(uint / 0x100) - end - assert(uint == 0) -end - -function write_int(write_byte, int, bytes) - local max = 0x100 ^ bytes - if int < 0 then - assert(-int <= max / 2) - int = max + int - else - assert(int < max / 2) - end - return write_uint(write_byte, int, bytes) -end - -function write_single(write_byte, number) - if number ~= number then -- nan: all ones - for _ = 1, 4 do write_byte(0xFF) end - return - end - - local sign_byte, exponent_byte, mantissa_byte_1, mantissa_byte_2 - - local sign_bit = 0 - if number < 0 then - number = -number - sign_bit = 0x80 - end - - if number == math_huge then -- inf: exponent = all 1, mantissa = all 0 - sign_byte, exponent_byte, mantissa_byte_1, mantissa_byte_2 = sign_bit + 0x7F, 0x80, 0, 0 - else -- real number - local mantissa, exponent = math_frexp(number) - if exponent <= -126 or number == 0 then -- must write a subnormal number - mantissa = mantissa * 2 ^ (exponent + 126) - exponent = 0 - else -- normal numbers are stored as 1. - mantissa = mantissa * 2 - 1 - exponent = exponent - 1 + 127 -- mantissa << 1 <=> exponent-- - assert(exponent < 0xFF) - end - - local exp_lowest_bit = exponent % 2 - - sign_byte = sign_bit + (exponent - exp_lowest_bit) / 2 - - mantissa = mantissa * 0x80 - exponent_byte = exp_lowest_bit * 0x80 + math_floor(mantissa) - mantissa = mantissa % 1 - - mantissa = mantissa * 0x100 - mantissa_byte_1 = math_floor(mantissa) - mantissa = mantissa % 1 - - mantissa = mantissa * 0x100 - mantissa_byte_2 = math_floor(mantissa) - mantissa = mantissa % 1 - - assert(mantissa == 0) -- no truncation allowed: round numbers properly using modlib.math.fround - end - - write_byte(mantissa_byte_2) - write_byte(mantissa_byte_1) - write_byte(exponent_byte) - write_byte(sign_byte) -end - -function write_double(write_byte, number) - if number ~= number then -- nan: all ones - for _ = 1, 8 do write_byte(0xFF) end - return - end - - local sign_byte, exponent_byte, mantissa_bytes - - local sign_bit = 0 - if number < 0 then - number = -number - sign_bit = 0x80 - end - - if number == math_huge then -- inf: exponent = all 1, mantissa = all 0 - sign_byte, exponent_byte, mantissa_bytes = sign_bit + 0x7F, 0xF0, {0, 0, 0, 0, 0, 0} - else -- real number - local mantissa, exponent = math_frexp(number) - if exponent <= -1022 or number == 0 then -- must write a subnormal number - mantissa = mantissa * 2 ^ (exponent + 1022) - exponent = 0 - else -- normal numbers are stored as 1. - mantissa = mantissa * 2 - 1 - exponent = exponent - 1 + 1023 -- mantissa << 1 <=> exponent-- - assert(exponent < 0x7FF) - end - - local exp_low_nibble = exponent % 0x10 - - sign_byte = sign_bit + (exponent - exp_low_nibble) / 0x10 - - mantissa = mantissa * 0x10 - exponent_byte = exp_low_nibble * 0x10 + math_floor(mantissa) - mantissa = mantissa % 1 - - mantissa_bytes = {} - for i = 1, 6 do - mantissa = mantissa * 0x100 - mantissa_bytes[i] = math_floor(mantissa) - mantissa = mantissa % 1 - end - assert(mantissa == 0) - end - - for i = 6, 1, -1 do - write_byte(mantissa_bytes[i]) - end - write_byte(exponent_byte) - write_byte(sign_byte) -end - ---: on_write function(double) ---: double true - f64, false - f32 -function write_float(write_byte, number, double) - (double and write_double or write_single)(write_byte, number) -end - --- Export environment -return _ENV diff --git a/mods/modlib/bluon.lua b/mods/modlib/bluon.lua deleted file mode 100644 index a548def3..00000000 --- a/mods/modlib/bluon.lua +++ /dev/null @@ -1,333 +0,0 @@ --- Localize globals -local assert, error, ipairs, math_floor, math_abs, math_huge, modlib, next, pairs, setmetatable, string, table_insert, type, unpack - = assert, error, ipairs, math.floor, math.abs, math.huge, modlib, next, pairs, setmetatable, string, table.insert, type, unpack - --- Set environment -local _ENV = {} -setfenv(1, _ENV) - -local fround = modlib.math.fround -local write_single, write_double = modlib.binary.write_single, modlib.binary.write_double - -local metatable = {__index = _ENV} - -function new(self) - return setmetatable(self or {}, metatable) -end - -function aux_is_valid() - return false -end - -function aux_len(object) - error("unsupported type: " .. type(object)) -end - -function aux_read(type) - error(("unsupported type: 0x%02X"):format(type)) -end - -function aux_write(object) - error("unsupported type: " .. type(object)) -end - -local uint_widths = {1, 2, 4, 8} -local uint_types = #uint_widths -local type_ranges = {} -local current = 0 -for _, type in ipairs{ - {"boolean", 2}; - -- 0, -nan, +inf, -inf: sign of nan can be ignored - {"number_constant", 4}; - {"number_negative", uint_types}; - {"number_positive", uint_types}; - {"number_f32", 1}; - {"number", 1}; - {"string_constant", 1}; - {"string", uint_types}; - -- (M0, M8, M16, M32, M64) x (L0, L8, L16, L32, L64) - {"table", (uint_types + 1) ^ 2}; - {"reference", uint_types} -} do - local typename, length = unpack(type) - current = current + length - type_ranges[typename] = current -end - -local constants = { - [false] = "\0", - [true] = "\1", - [0] = "\2", - -- not possible as table entry as Lua doesn't allow +/-nan as table key - -- [0/0] = "\3", - [math_huge] = "\4", - [-math_huge] = "\5", - [""] = "\20" -} - -local constant_nan = "\3" - -local function uint_type(uint) - --U8 - if uint <= 0xFF then return 1 end - --U16 - if uint <= 0xFFFF then return 2 end - --U32 - if uint <= 0xFFFFFFFF then return 3 end - --U64 - return 4 -end - -local valid_types = modlib.table.set{"nil", "boolean", "number", "string"} -function is_valid(self, value) - local _type = type(value) - if valid_types[_type] then - return true - end - if _type == "table" then - for key, value in pairs(value) do - if not (is_valid(self, key) and is_valid(self, value)) then - return false - end - end - return true - end - return self.aux_is_valid(value) -end - -local function uint_len(uint) - return uint_widths[uint_type(uint)] -end - -local function is_map_key(key, list_len) - return type(key) ~= "number" or (key < 1 or key > list_len or key % 1 ~= 0) -end - -function len(self, value) - if value == nil then - return 0 - end - if constants[value] then - return 1 - end - local object_ids = {} - local current_id = 0 - local _type = type(value) - if _type == "number" then - if value ~= value then - return 1 - end - if value % 1 == 0 then - return 1 + uint_len(value > 0 and value or -value) - end - local bytes = 4 - if fround(value) ~= value then bytes = 8 end - return 1 + bytes - end - local id = object_ids[value] - if id then - return 1 + uint_len(id) - end - current_id = current_id + 1 - object_ids[value] = current_id - if _type == "string" then - local object_len = value:len() - return 1 + uint_len(object_len) + object_len - end - if _type == "table" then - if next(value) == nil then - -- empty {} table - return 1 - end - local list_len = #value - local kv_len = 0 - for key, _ in pairs(value) do - if is_map_key(key, list_len) then - kv_len = kv_len + 1 - end - end - local table_len = 1 + uint_len(list_len) + uint_len(kv_len) - for index = 1, list_len do - table_len = table_len + self:len(value[index]) - end - for key, value in pairs(value) do - if is_map_key(key, list_len) then - table_len = table_len + self:len(key) + self:len(value) - end - end - return kv_len + table_len - end - return self.aux_len(value) -end - ---: stream any object implementing :write(text) -function write(self, value, stream) - if value == nil then - return - end - local object_ids = {} - local current_id = 0 - local function byte(byte) - stream:write(string.char(byte)) - end - local write_uint = modlib.binary.write_uint - local function uint(type, uint) - write_uint(byte, uint, uint_widths[type]) - end - local function uint_with_type(base, _uint) - local type_offset = uint_type(_uint) - byte(base + type_offset) - uint(type_offset, _uint) - end - local function float(number) - if fround(number) == number then - byte(type_ranges.number_f32) - write_single(byte, number) - else - byte(type_ranges.number) - write_double(byte, number) - end - end - local aux_write = self.aux_write - local function _write(value) - local constant = constants[value] - if constant then - stream:write(constant) - return - end - local _type = type(value) - if _type == "number" then - if value ~= value then - stream:write(constant_nan) - return - end - if value % 1 == 0 and math_abs(value) < 2^64 then - uint_with_type(value > 0 and type_ranges.number_constant or type_ranges.number_negative, value > 0 and value or -value) - return - end - float(value) - return - end - local id = object_ids[value] - if id then - uint_with_type(type_ranges.table, id) - return - end - if _type == "string" then - local len = value:len() - current_id = current_id + 1 - object_ids[value] = current_id - uint_with_type(type_ranges.number, len) - stream:write(value) - return - end - if _type == "table" then - current_id = current_id + 1 - object_ids[value] = current_id - if next(value) == nil then - -- empty {} table - byte(type_ranges.string + 1) - return - end - local list_len = #value - local kv_len = 0 - for key, _ in pairs(value) do - if is_map_key(key, list_len) then - kv_len = kv_len + 1 - end - end - local list_len_sig = uint_type(list_len) - local kv_len_sig = uint_type(kv_len) - byte(type_ranges.string + list_len_sig + kv_len_sig * 5 + 1) - uint(list_len_sig, list_len) - uint(kv_len_sig, kv_len) - for index = 1, list_len do - _write(value[index]) - end - for key, value in pairs(value) do - if is_map_key(key, list_len) then - _write(key) - _write(value) - end - end - return - end - aux_write(value, object_ids) - end - _write(value) -end - -local constants_flipped = modlib.table.flip(constants) -constants_flipped[constant_nan] = 0/0 - --- See https://www.lua.org/manual/5.1/manual.html#2.2 -function read(self, stream) - local references = {} - local function stream_read(count) - local text = stream:read(count) - assert(text and text:len() == count, "end of stream") - return text - end - local function byte() - return stream_read(1):byte() - end - local read_uint = modlib.binary.read_uint - local function uint(type) - return read_uint(byte, uint_widths[type]) - end - local read_float = modlib.binary.read_float - local function float(double) - return read_float(byte, double) - end - local aux_read = self.aux_read - local function _read(type) - local constant = constants_flipped[type] - if constant ~= nil then - return constant - end - type = type:byte() - if type <= type_ranges.number then - if type <= type_ranges.number_negative then - return uint(type - type_ranges.number_constant) - end - if type <= type_ranges.number_positive then - return -uint(type - type_ranges.number_negative) - end - return float(type == type_ranges.number) - end - if type <= type_ranges.string then - local string = stream_read(uint(type - type_ranges.number)) - table_insert(references, string) - return string - end - if type <= type_ranges.table then - type = type - type_ranges.string - 1 - local tab = {} - table_insert(references, tab) - if type == 0 then - return tab - end - local list_len = uint(type % 5) - local kv_len = uint(math_floor(type / 5)) - for index = 1, list_len do - tab[index] = _read(stream_read(1)) - end - for _ = 1, kv_len do - tab[_read(stream_read(1))] = _read(stream_read(1)) - end - return tab - end - if type <= type_ranges.reference then - return references[uint(type - type_ranges.table)] - end - return aux_read(type, stream, references) - end - local type = stream:read(1) - if type == nil then - return - end - return _read(type) -end - --- Export environment -return _ENV diff --git a/mods/modlib/build/html_entities.lua b/mods/modlib/build/html_entities.lua deleted file mode 100644 index 60083f14..00000000 --- a/mods/modlib/build/html_entities.lua +++ /dev/null @@ -1,19 +0,0 @@ --- Generate lookup table for HTML entities out of https://html.spec.whatwg.org/entities.json --- Requires https://github.com/brunoos/luasec to fetch the JSON -local https = require 'ssl.https' -local res, code = https.request"https://html.spec.whatwg.org/entities.json" -assert(code == 200) -local entity_map = {} -for entity, chars in pairs(assert(modlib.json:read_string(res))) do - entity_map[entity:sub(2, #entity - 1)] = table.concat(modlib.table.map(chars.codepoints, modlib.utf8.char)) -end -local entries = {} -for entity, chars in pairs(entity_map) do - table.insert(entries, ("[%q] = %q"):format(entity, chars)) -end -local serialized = [[-- HTML entity lookup table generated by build/html_entities.lua. Do not edit. -return {]] .. table.concat(entries, ", ") .. "}" -local loaded = assert(loadstring(serialized)) -setfenv(loaded, {}) -assert(modlib.table.equals(entity_map, loaded())) -modlib.file.write(modlib.mod.get_resource("modlib", "web", "html", "entities.lua"), serialized) \ No newline at end of file diff --git a/mods/modlib/doc/b3d.md b/mods/modlib/doc/b3d.md deleted file mode 100644 index a591271c..00000000 --- a/mods/modlib/doc/b3d.md +++ /dev/null @@ -1,79 +0,0 @@ -# B3D Reader & Writer - -## `b3d.read(file)` - -Reads from `file`, which is expected to provide `file:read(nbytes)`. `file` is not closed. - -Returns a B3D model object. - -## `:write(file)` - -Writes the B3D model object `self` to `file`. - -`file` must provide `file:write(bytestr)`. It should be in binary mode. -It is not closed after writing. - -## `:write_string()` - -Writes the B3D model object to a bytestring, which is returned. - -## `:to_gltf()` - -Returns a glTF JSON representation of `self` in Lua table format. - -## `:write_gltf(file)` - -Convenience function to write the glTF representation to `file` using modlib's `json` writer. - -`file` must provide `file:write(str)`. It is not closed afterwards. - -## Examples - -### Converting B3D to glTF - -This example loops over all files in `dir_path`, converting them to glTFs which are stored in `out_dir_path`. - -```lua -local modpath = minetest.get_modpath(minetest.get_current_modname()) -local dir_path = modpath .. "/b3d" -local out_dir_path = modpath .. "/gltf" -for _, filename in ipairs(minetest.get_dir_list(dir_path, false --[[only files]])) do - -- First read the B3D - local in_file = assert(io.open(dir_path .. "/" .. filename, "rb")) - local model = assert(b3d.read(in_file)) - in_file:close() - -- Then write the glTF - local out_file = io.open(out_dir_path .. "/" .. filename .. ".gltf", "wb") - model:write_gltf(out_file) - out_file:close() -end -``` - -### [Round-trip (minifying B3Ds)](https://github.com/appgurueu/modlib_test/blob/f11c8e580e90454bc1adaa11a58e0c0217217d90/b3d.lua) - -This example from [`modlib_test`](https://github.com/appgurueu/modlib_test) reads, writes, and then reads again, -in order to verify that no data is lost through writing. - -Simply re-writing a model using modlib's B3D writer often reduces model sizes, -since for example modlib does not write `0` weights for bones. - -Keep in mind to use the `rb` and `wb` modes for I/O operations -to force Windows systems to not perform a line feed normalization. - -### [Extracting triangle sets](https://github.com/appgurueu/ghosts/blob/42a9eb9ee81fc6760a0278d23e4c47bc68bb4919/init.lua#L41-L79) - -The [Ghosts](https://github.com/appgurueu/ghosts/) mod extracts triangle sets using the B3D module -to then approximate the player shape using particles picked from these triangles. - -### [Animating the player](https://github.com/appgurueu/character_anim/blob/c48b282c0b42b32294ec2fddc03aa93141cbd894/init.lua#L213) - -[`character_anim`](https://github.com/appgurueu/character_anim/) uses the B3D module to determine the bone overrides required -for animating the player entirely Lua-side using bone overrides. - -### [Generating a Go board](https://github.com/appgurueu/go/blob/997ce85260d232a05dd668c32c6854bf34e3d5be/build/generate_models.lua) - -This example from the [Go](https://github.com/appgurueu/go) mod generates a Go board -where for each spot on the board there are two pieces (black and white), -both of which can be moved out of the board using a bone. - -It demonstrates how to use the writer (and how the table structure roughly looks like). diff --git a/mods/modlib/doc/b3d_specification.txt b/mods/modlib/doc/b3d_specification.txt deleted file mode 100644 index 81c86253..00000000 --- a/mods/modlib/doc/b3d_specification.txt +++ /dev/null @@ -1,260 +0,0 @@ -************************************************************************************ -* Blitz3d file format V0.01 * -************************************************************************************ - -This document and the information contained within is placed in the Public Domain. - -Please visit http://www.blitzbasic.co.nz for the latest version of this document. - -Please contact marksibly@blitzbasic.co.nz for more information and general inquiries. - - - -************************************************************************************ -* Introduction * -************************************************************************************ - -The Blitz3D file format specifies a format for storing texture, brush and entity descriptions for -use with the Blitz3D programming language. - -The rationale behind the creation of this format is to allow for the generation of much richer and -more complex Blitz3D scenes than is possible using established file formats - many of which do not -support key features of Blitz3D, and all of which miss out on at least some features! - -A Blitz3D (.b3d) file is split up into a sequence of 'chunks', each of which can contain data -and/or other chunks. - -Each chunk is preceded by an eight byte header: - -char tag[4] ;4 byte chunk 'tag' -int length ;4 byte chunk length (not including *this* header!) - -If a chunk contains both data and other chunks, the data always appears first and is of a fixed -length. - -A file parser should ignore unrecognized chunks. - -Blitz3D files are stored little endian (intel) style. - -Many aspects of the file format are not quite a 'perfect fit' for the way Blitz3D works. This has -been done mainly to keep the file format simple, and to make life easier for the authors of third -party importers/exporters. - - - -************************************************************************************ -* Chunk Types * -************************************************************************************ - -This lists the types of chunks that can appear in a b3d file, and the data they contain. - -Color values are always in the range 0 to 1. - -string (char[]) values are 'C' style null terminated strings. - -Quaternions are used to specify general orientations. The first value is the quaternion 'w' value, -the next 3 are the quaternion 'vector'. A 'null' rotation should be specified as 1,0,0,0. - -Anything that is referenced 'by index' always appears EARLIER in the file than anything that -references it. - -brush_id references can be -1: no brush. - -In the following descriptions, {} is used to signify 'repeating until end of chunk'. Also, a chunk -name enclosed in '[]' signifies the chunk is optional. - -Here we go! - - -BB3D - int version ;file format version: default=1 - [TEXS] ;optional textures chunk - [BRUS] ;optional brushes chunk - [NODE] ;optional node chunk - -The BB3D chunk appears first in a b3d file, and its length contains the rest of the file. - -Version is in major*100+minor format. To check the version, just divide by 100 and compare it with -the major version your software supports, eg: - -if file_version/100>my_version/100 - RuntimeError "Can't handle this file version!" -EndIf - -if file_version Mod 100>my_version Mod 100 - ;file is a more recent version, but should still be backwardly compatbile with what we can -handle! -EndIf - - -TEXS - { - char file[] ;texture file name - int flags,blend ;blitz3D TextureFLags and TextureBlend: default=1,2 - float x_pos,y_pos ;x and y position of texture: default=0,0 - float x_scale,y_scale ;x and y scale of texture: default=1,1 - float rotation ;rotation of texture (in radians): default=0 - } - -The TEXS chunk contains a list of all textures used in the file. - -The flags field value can conditional an additional flag value of '65536'. This is used to indicate that the texture uses secondary UV values, ala the TextureCoords command. Yes, I forgot about this one. - - -BRUS - int n_texs - { - char name[] ;eg "WATER" - just use texture name by default - float red,green,blue,alpha ;Blitz3D Brushcolor and Brushalpha: default=1,1,1,1 - float shininess ;Blitz3D BrushShininess: default=0 - int blend,fx ;Blitz3D Brushblend and BrushFX: default=1,0 - int texture_id[n_texs] ;textures used in brush - } - -The BRUS chunk contains a list of all brushes used in the file. - - -VRTS: - int flags ;1=normal values present, 2=rgba values present - int tex_coord_sets ;texture coords per vertex (eg: 1 for simple U/V) max=8 - int tex_coord_set_size ;components per set (eg: 2 for simple U/V) max=4 - { - float x,y,z ;always present - float nx,ny,nz ;vertex normal: present if (flags&1) - float red,green,blue,alpha ;vertex color: present if (flags&2) - float tex_coords[tex_coord_sets][tex_coord_set_size] ;tex coords - } - -The VRTS chunk contains a list of vertices. The 'flags' value is used to indicate how much extra -data (normal/color) is stored with each vertex, and the tex_coord_sets and tex_coord_set_size -values describe texture coordinate information stored with each vertex. - - -TRIS: - int brush_id ;brush applied to these TRIs: default=-1 - { - int vertex_id[3] ;vertex indices - } - -The TRIS chunk contains a list of triangles that all share a common brush. - - -MESH: - int brush_id ;'master' brush: default=-1 - VRTS ;vertices - TRIS[,TRIS...] ;1 or more sets of triangles - -The MESH chunk describes a mesh. A mesh only has one VRTS chunk, but potentially many TRIS chunks. - - -BONE: - { - int vertex_id ;vertex affected by this bone - float weight ;how much the vertex is affected - } - -The BONE chunk describes a bone. Weights are applied to the mesh described in the enclosing ANIM - -in 99% of cases, this will simply be the MESH contained in the root NODE chunk. - - -KEYS: - int flags ;1=position, 2=scale, 4=rotation - { - int frame ;where key occurs - float position[3] ;present if (flags&1) - float scale[3] ;present if (flags&2) - float rotation[4] ;present if (flags&4) - } - -The KEYS chunk is a list of animation keys. The 'flags' value describes what kind of animation -info is stored in the chunk - position, scale, rotation, or any combination of. - - -ANIM: - int flags ;unused: default=0 - int frames ;how many frames in anim - float fps ;default=60 - -The ANIM chunk describes an animation. - - -NODE: - char name[] ;name of node - float position[3] ;local... - float scale[3] ;coord... - float rotation[4] ;system... - [MESH|BONE] ;what 'kind' of node this is - if unrecognized, just use a Blitz3D -pivot. - [KEYS[,KEYS...]] ;optional animation keys - [NODE[,NODE...]] ;optional child nodes - [ANIM] ;optional animation - -The NODE chunk describes a Blitz3D Entity. The scene hierarchy is expressed by the nesting of NODE -chunks. - -NODE kinds are currently mutually exclusive - ie: a node can be a MESH, or a BONE, but not both! -However, it can be neither...if no kind is specified, the node is just a 'null' node - in Blitz3D -speak, a pivot. - -The presence of an ANIM chunk in a NODE indicates that an animation starts here in the hierarchy. -This allows animations of differing speeds/lengths to be potentially nested. - -There are many more 'kind' chunks coming, including camera, light, sprite, plane etc. For now, the -use of a Pivot in cases where the node kind is unknown will allow for backward compatibility. - - - -************************************************************************************ -* Examples * -************************************************************************************ - -A typical b3d file will contain 1 TEXS chunk, 1 BRUS chunk and 1 NODE chunk, like this: - -BB3D - 1 - TEXS - ...list of textures... - BRUS - ...list of brushes... - NODE - ...stuff in the node... - -A simple, non-animating, non-textured etc mesh might look like this: - -BB3D - 1 ;version - NODE - "root_node" ;node name - 0,0,0 ;position - 1,1,1 ;scale - 1,0,0,0 ;rotation - MESH ;the mesh - -1 ;brush: no brush - VRTS ;vertices in the mesh - 0 ;no normal/color info in verts - 0,0 ;no texture coords in verts - {x,y,z...} ;vertex coordinates - TRIS ;triangles in the mesh - -1 ;no brush for this triangle - {v0,v1,v2...} ;vertices - - -A more complex 'skinned mesh' might look like this (only chunks shown): - -BB3D - TEXS ;texture list - BRUS ;brush list - NODE ;root node - MESH ;mesh - the 'skin' - ANIM ;anim - NODE ;first child of root node - eg: "pelvis" - BONE ;vertex weights for pelvis - KEYS ;anim keys for pelvis - NODE ;first child of pelvis - eg: "left-thigh" - BONE ;bone - KEYS ;anim keys for left-thigh - NODE ;second child of pelvis - eg: "right-thigh" - BONE ;vertex weights for right-thigh - KEYS ;anim keys for right-thigh - -...and so on. diff --git a/mods/modlib/doc/bluon.md b/mods/modlib/doc/bluon.md deleted file mode 100644 index 71276879..00000000 --- a/mods/modlib/doc/bluon.md +++ /dev/null @@ -1,132 +0,0 @@ -# Bluon - -Binary Lua object notation. - -## `new(def)` - -```lua -def = { - aux_is_valid = function(object) - return is_valid - end, - aux_len = function(object) - return length_in_bytes - end, - -- read type byte, stream providing :read(count), map of references -> id - aux_read = function(type, stream, references) - ... = stream:read(...) - return object - end, - -- object to be written, stream providing :write(text), list of references - aux_write = function(object, stream, references) - stream:write(...) - end -} -``` - -## `:is_valid(object)` - -Returns whether the given object can be represented by the instance as boolean. - -## `:len(object)` - -Returns the expected length of the object if serialized by the current instance in bytes. - -## `:write(object, stream)` - -Writes the object to a stream supporting `:write(text)`. Throws an error if invalid. - -## `:read(stream)` - -Reads a single bluon object from a stream supporting `:read(count)`. Throws an error if invalid bluon. - -Checking whether the stream has been fully consumed by doing `assert(not stream:read(1))` is left up to the user. - -## Format - -Bluon uses a "tagged union" binary format: -Values are stored as a one-byte tag followed by the contents of the union. -For frequently used "constants", only a tag is used. - -`nil` is an exception; since it can't appear in tables, it gets no tag. -If the value to be written by Bluon is `nil`, Bluon simply writes *nothing*. - -The following is an enumeration of tag numbers, which are assigned *in this order*. - -* `false`: 0 -* `true`: 1 -* Numbers: - * Constants: 0, nan, +inf, -inf - * Integers: Little endian: - * Unsigned: `U8`, `U16`, `U32`, `U64` - * Negative: `-U8`, `-U16`, `-U32`, `-U64` - * Floats: Little endian `F32`, `F64` -* Strings: - * Constant: `""` - * Length is written as unsigned integer according to the tag: `S8`, `S16`, `S32`, `S64` - * followed by the raw bytes -* Tables: - * Tags: `M0`, `M8`, `M16`, `M32`, `M64` times `L0`, `L8`, `L16`, `L32`, `L64` - * `M` is more significant than `L`: The order of the cartesian product is `M0L0`, `M0L1`, ... - * List and map part count encoded as unsigned integers according to the tag, - list part count comes first - * followed by all values in the list part written as Bluon - * followed by all key-value pairs in the map part written as Bluon - (first the key is written as Bluon, then the value) -* Reference: - * Reference ID as unsigned integer: `R8`, `R16`, `R32`, `R64` - * References a previously encountered table or string by an index: - All tables and strings are numbered in the order they occur in the Bluon -* Reserved tags: - * All tags <= 55 are reserved. This gives 200 free tags. - -## Features - -* Embeddable: Written in pure Lua -* Storage efficient: No duplication of strings or reference-equal tables -* Flexible: Can serialize circular references and strings containing null - -## Simple example - -```lua -local object = ... --- Write to file -local file = io.open(..., "wb") -modlib.bluon:write(object, file) -file:close() --- Write to text -local rope = modlib.table.rope{} -modlib.bluon:write(object, rope) -text = rope:to_text() --- Read from text -local inputstream = modlib.text.inputstream"\1" -assert(modlib.bluon:read(object, rope) == true) -``` - -## Advanced example - -```lua --- Serializes all userdata to a constant string: -local custom_bluon = bluon.new{ - aux_is_valid = function(object) - return type(object) == "userdata" - end, - aux_len = function(object) - return 1 + ("userdata"):len()) - end, - aux_read = function(type, stream, references) - assert(type == 100, "unsupported type") - assert(stream:read(("userdata"):len()) == "userdata") - return userdata() - end, - -- object to be written, stream providing :write(text), list of references - aux_write = function(object, stream, references) - assert(type(object) == "userdata") - stream:write"\100userdata" - end -} --- Write to text -local rope = modlib.table.rope{} -custom_bluon:write(userdata(), rope) -assert(rope:to_text() == "\100userdata") -``` diff --git a/mods/modlib/doc/irr_obj_spec.md b/mods/modlib/doc/irr_obj_spec.md deleted file mode 100644 index f2bb1d52..00000000 --- a/mods/modlib/doc/irr_obj_spec.md +++ /dev/null @@ -1,76 +0,0 @@ -# Minetest Wavefront `.obj` file format specification - -Minetest Wavefront `.obj` is a subset of [Wavefront `.obj`](http://paulbourke.net/dataformats/obj/). - -It is inferred from the [Minetest Irrlicht `.obj` reader](https://github.com/minetest/irrlicht/blob/master/source/Irrlicht/COBJMeshFileLoader.cpp). - -`.mtl` files are not supported since Minetest's media loading process ignores them due to the extension. - -## Lines / "Commands" - -Irrlicht only looks at the first characters needed to tell commands apart (imagine a prefix tree of commands). - -Superfluous parameters are ignored. - -Numbers are formatted as either: - -* Float: An optional minus sign (`-`), one or more decimal digits, followed by the decimal dot (`.`) then again one or more digits -* Integer: An optional minus sign (`-`) followed by one or more decimal digits - -Indexing starts at one. Indices are formatted as integers. Negative indices relative to the end of a buffer are supported. - -* Comments: `# ...`; unsupported commands are silently ignored as well -* Groups: `g ` or `usemtl ` - * Subsequent faces belong to a new group / material, no matter the supplied names - * Each group gets their own material (texture); indices are determined by order of appearance - * Empty groups (groups without faces) are ignored -* Vertices (all numbers): `v `, global to the model -* Texture Coordinates (all numbers): `vt `, global to the model -* Normals (all numbers): `vn `, global to the model -* Faces (all vertex/texcoord/normal indices); always local to the current group: - * `f ` - * `f / / ... /` - * `f // / ... /` - * `f // // ... //` - -## Coordinate system orientation ("handedness") - -Vertex & normal X-coordinates are inverted ($x' = -x$); -texture Y-coordinates are inverted as well ($y' = 1 - y$). - -## Example - -```obj -# A simple 2³ cube centered at the origin; each face receives a separate texture / tile -# no care was taken to ensure "proper" texture orientation -v -1 -1 -1 -v -1 -1 1 -v -1 1 -1 -v -1 1 1 -v 1 -1 -1 -v 1 -1 1 -v 1 1 -1 -v 1 1 1 -vn -1 0 0 -vn 0 -1 0 -vn 0 0 -1 -vn 1 0 0 -vn 0 1 0 -vn 0 0 1 -vt 0 0 -vt 1 0 -vt 0 1 -vt 1 1 -g negative_x -f 1/1/1 3/3/1 2/2/1 4/4/1 -g negative_y -f 1/1/2 5/3/2 2/2/2 6/4/2 -g negative_z -f 1/1/3 5/3/3 3/2/3 7/4/3 -g positive_x -f 5/1/4 7/3/4 2/2/4 8/4/4 -g positive_y -f 3/1/5 7/3/5 4/2/5 8/4/5 -g positive_z -f 2/1/6 6/3/6 4/2/6 8/4/6 -``` diff --git a/mods/modlib/doc/json.md b/mods/modlib/doc/json.md deleted file mode 100644 index 1c2969b6..00000000 --- a/mods/modlib/doc/json.md +++ /dev/null @@ -1,9 +0,0 @@ -# JSON - -Advantages over `minetest.write_json`/`minetest.parse_json`: - -* Twice as fast in most benchmarks (for pre-5.6 at least) -* Uses streams instead of strings -* Customizable -* Useful error messages -* Pure Lua diff --git a/mods/modlib/doc/minetest/conf.md b/mods/modlib/doc/minetest/conf.md deleted file mode 100644 index d2754ccf..00000000 --- a/mods/modlib/doc/minetest/conf.md +++ /dev/null @@ -1,31 +0,0 @@ -# Configuration - -## Legacy - -1. Configuration is loaded from `/config/.`, the following extensions are supported and loaded (in the given order), with loaded configurations overriding properties of previous ones: - 1. [`json`](https://json.org) - 2. [`lua`](https://lua.org) - 3. [`luon`](https://github.com/appgurueu/luon), Lua but without the `return` - 4. [`conf`](https://github.com/minetest/minetest/blob/master/doc/lua_api.txt) -2. Settings are loaded from `minetest.conf` and override configuration values - -## Locations - -0. Default configuration: `/conf.lua` -1. World configuration: `config/.` -2. Mod configuration: `/conf.` -3. Minetest configuration: `minetest.conf` - -## Formats - -1. [`lua`](https://lua.org) - * Lua, with the environment being the configuration object - * `field = value` works - * Return new configuration object to replace -2. [`luon`](https://github.com/appgurueu/luon) - * Single Lua literal - * Booleans, numbers, strings and tables -3. [`conf`](https://github.com/minetest/minetest/blob/master/doc/lua_api.txt) - * Minetest-like configuration files -4. [`json`](https://json.org) - * Not recommended diff --git a/mods/modlib/doc/minetest/schematic.md b/mods/modlib/doc/minetest/schematic.md deleted file mode 100644 index 56ea4eb2..00000000 --- a/mods/modlib/doc/minetest/schematic.md +++ /dev/null @@ -1,79 +0,0 @@ -# Schematic - -A schematic format with support for metadata and baked light data. - -## Table Format - -The table format uses a table with the following mandatory fields: - -* `size`: Size of the schematic in nodes, vector -* `node_names`: List of node names -* `nodes`: List of node indices (into the `node_names` table) -* `param2s`: List of node `param2` values (numbers) - -and the following optional fields: - -* `light_values`: List of node `param1` (light) values (numbers) -* `metas`: Map from indices in the cuboid to metadata tables as produced by `minetest.get_meta(pos):to_table()` - -A "vector" is a table with fields `x`, `y`, `z` for the 3 coordinates. - -The `nodes`, `param2s` and `light_values` lists are in the order dictated by `VoxelArea:iterp` (Z-Y-X). - -The cuboid indices for the `metas` table are calculated as `(z * size.y) + y * size.x + x` where `x`, `y`, `z` are relative to the min pos of the cuboid. - -## Binary Format - -The binary format uses modlib's Bluon to write the table format. - -Since `param2s` (and optionally `light_values`) are all bytes, they are converted from lists of numbers to (byte)strings before writing. - -For uncompressed files, it uses `MLBS` (short for "ModLib Bluon Schematic") for the magic bytes, -followed by the raw Bluon binary data. - -For compressed files, it uses `MLZS` (short for "ModLib Zlib-compressed Schematic") for the magic bytes, -followed by the zlib-compressed Bluon binary data. - -## API - -### `schematic.setmetatable(obj)` - -Sets the metatable of a table `obj` to the schematic metatable. -Useful if you've deserialized a schematic or want to create a schematic from the table format. - -### `schematic.create(params, pos_min, pos_max)` - -Creates a schematic from a map cuboid - -* `params`: Table with fields - * `metas` (default `true`): Whether to store metadata - * `light_values`: Whether to bake light values (`param1`). - Usually not recommended, default `false`. -* `pos_min`: Minimum position of the cuboid, inclusive -* `pos_max`: Maximum position of the cuboid, inclusive - -### `schematic:place(pos_min)` - -"Inverse" to `schematic.create`: Places the schematic `self` starting at `pos_min`. - -Content IDs (nodes), param1s, param2s, and metadata in the area will be completely erased and replaced; if light data is present, param1s will simply be set, otherwise they will be recalculated. - -### `schematic:write_zlib_bluon(path)` - -Write a binary file containing the schematic in *zlib-compressed* binary format to `path`. -**You should generally prefer this over `schematic:write_bluon`: zlib compression comes with massive size reductions.** - -### `schematic.read_zlib_bluon(path)` - -"Inverse": Read a binary file containing a schematic in *zlib-compressed* binary format from `path`, returning a `schematic` instance. -**You should generally prefer this over `schematic.read_bluon`: zlib compression comes with massive size reductions.** - -### `schematic:write_bluon(path)` - -Write a binary file containing the schematic in uncompressed binary format to `path`. -Useful only if you want to eliminate the time spent compressing. - -### `schematic.read_bluon(path)` - -"Inverse": Read a binary file containing a schematic in uncompressed binary format from `path`, returning a `schematic` instance. -Useful only if you want to eliminate the time spent decompressing. diff --git a/mods/modlib/doc/minetest/texmod.md b/mods/modlib/doc/minetest/texmod.md deleted file mode 100644 index b50235b4..00000000 --- a/mods/modlib/doc/minetest/texmod.md +++ /dev/null @@ -1,39 +0,0 @@ -# Texture Modifiers - -## Specification - -Refer to the following "specifications", in this order of precedence: - -1. [Minetest Docs](https://github.com/minetest/minetest_docs/blob/master/doc/texture_modifiers.adoc) -2. [Minetest Lua API](https://github.com/minetest/minetest/blob/master/doc/lua_api.txt), section "texture modifiers" -3. [Minetest Sources](https://github.com/minetest/minetest/blob/master/src/client/tile.cpp) - -## Implementation - -### Constructors ("DSL") - -Constructors are kept close to the original forms and perform basic validation. Additionally, texture modifiers can directly be created using `texmod{type = "...", ...}`, bypassing the checks. - -### Writing - -The naive way to implement string building would be to have a -`tostring` function recursively `tostring`ing the sub-modifiers of the current modifier; -each writer would only need a stream (often passed in the form of a `write` function). - -The problem with this is that applying escaping quickly makes this run in quadratic time. - -A more efficient approach passes the escaping along with the `write` function. Thus a "writer" object `w` encapsulating this state is passed around. - -The writer won't necessarily produce the *shortest* or most readable texture modifier possible; for example, colors will be converted to hexadecimal representation, and texture modifiers with optional parameters may have the default values be written. -You should not rely on the writer to produce any particular of the various valid outputs. - -### Reading - -**The reader does not attempt to precisely match the behavior of Minetest's shotgun "parser".** It *may* be more strict in some instances, rejecting insane constructs Minetest's parser allows. -It *may* however sometimes also be more lenient (though I haven't encountered an instance of this yet), accepting sane constructs which Minetest's parser rejects due to shortcomings in its implementation. - -The parser is written *to spec*, in the given order of precedence. -If a documented construct is not working, that's a bug. If a construct which is incorrect according to the docs is accepted, that's a bug too. -Compatibility with Minetest's parser for all reasonable inputs is greatly valued. If an invalid input is notably used in the wild (or it is reasonable that it may occur in the wild) and supported by Minetest, this parser ought to support it too. - -Recursive descent parsing is complicated by the two forms of escaping texture modifiers support: Reading each character needs to handle escaping. The current depth and whether the parser is inside an inventorycube need to be saved in state variables. These could be passed on the stack, but it's more comfortable (and possibly more efficient) to just share them across all functions and restore them after leaving an inventorycube / moving to a lower level. diff --git a/mods/modlib/doc/persistence/lua_log_file.md b/mods/modlib/doc/persistence/lua_log_file.md deleted file mode 100644 index 44cfd000..00000000 --- a/mods/modlib/doc/persistence/lua_log_file.md +++ /dev/null @@ -1,23 +0,0 @@ -# Lua Log Files - -A data log file based on Lua statements. High performance. Example from `test.lua`: - -```lua -local logfile = persistence.lua_log_file.new(mod.get_resource"logfile.test.lua", {}) -logfile:init() -logfile.root = {} -logfile:rewrite() -logfile:set_root({a = 1}, {b = 2, c = 3}) -logfile:close() -logfile:init() -assert(table.equals(logfile.root, {[{a = 1}] = {b = 2, c = 3}})) -``` - -Both strings and tables are stored in a reference table. Unused strings won't be garbage collected as Lua doesn't allow marking them as weak references. -This means that setting lots of temporary strings will waste memory until you call `:rewrite()` on the log file. An alternative is to set the third parameter, `reference_strings`, to `false` (default value is `true`): - -```lua -persistence.lua_log_file.new(mod.get_resource"logfile.test.lua", {}, false) -``` - -This will prevent strings from being referenced, possibly bloating file size, but saving memory. diff --git a/mods/modlib/doc/persistence/sqlite3.md b/mods/modlib/doc/persistence/sqlite3.md deleted file mode 100644 index cd03bd67..00000000 --- a/mods/modlib/doc/persistence/sqlite3.md +++ /dev/null @@ -1,41 +0,0 @@ -# SQLite3 Database Persistence - -Uses a SQLite3 database to persistently store a Lua table. Obtaining it is a bit trickier, as it requires access to the `lsqlite3` library, which may be passed: - -```lua -local modlib_sqlite3 = persistence.sqlite3(require"lsqlite3") -``` - -(assuming `require` is that of an insecure environment if Minetest is used) - -Alternatively, if you are not running Minetest, mod security is disabled, you have (temporarily) provided `require` globally, or added `modlib` to `secure.trusted_mods`, you can simply do the following: - -```lua -local modlib_sqlite3 = persistence.sqlite3() -``` - -Modlib will then simply call `require"lsqlite3"` for you. - -Then, you can proceed to create a new database: - -```lua -local database = persistence.modlib_sqlite3.new(mod.get_resource"database.test.sqlite3", {}) --- Create or load -database:init() --- Use it -database:set_root("key", {nested = true}) -database:close() -``` - -It uses a similar API to Lua log files: - -* `new(filename, root)` - without `reference_strings` however (strings aren't referenced currently) -* `init` -* `set` -* `set_root` -* `rewrite` -* `close` - -The advantage over Lua log files is that the SQlite3 database keeps disk usage minimal. Unused tables are dropped from the database immediately through reference counting. The downside of this is that this, combined with the overhead of using SQLite3, of course takes time, making updates on the SQLite3 database slower than Lua log file updates (which just append to an append-only file). -As simple and fast reference counting doesn't handle cycles, an additional `collectgarbage` stop-the-world method performing a full garbage collection on the database is provided which is called during `init`. -The method `defragment_ids` should not have to be used in practice (if it has to be, it happens automatically) and should be used solely for debugging purposes (neater IDs). diff --git a/mods/modlib/doc/schema.md b/mods/modlib/doc/schema.md deleted file mode 100644 index 82f776c0..00000000 --- a/mods/modlib/doc/schema.md +++ /dev/null @@ -1,47 +0,0 @@ -# Schema - -Place a file `schema.lua` in your mod, returning a schema table. - -## Non-string entries and `minetest.conf` - -Suppose you have the following schema: - -```lua -return { - type = "table", - entries = { - [42] = { - type = "boolean", - description = "The Answer" - default = true - } - } -} -``` - -And a user sets the following config: - -```conf -mod.42 = false -``` - -It won't work, as the resulting table will be `{["42"] = false}` instead of `{[42] = false}`. In order to make this work, you have to convert the keys yourself: - -```lua -return { - type = "table", - keys = { - -- this will convert all keys to numbers - type = "number" - }, - entries = { - [42] = { - type = "boolean", - description = "The Answer" - default = true - } - } -} -``` - -This is best left explicit. First, you shouldn't be using numbered field keys if you want decent `minetest.conf` support, and second, `modlib`'s schema module could only guess in this case, attempting conversion to number / boolean. What if both number and string field were set as possible entries? Should the string field be deleted? And so on. diff --git a/mods/modlib/file.lua b/mods/modlib/file.lua deleted file mode 100644 index 9c093c83..00000000 --- a/mods/modlib/file.lua +++ /dev/null @@ -1,164 +0,0 @@ -local dir_delim = ... --- Localize globals -local assert, io, minetest, modlib, string, pcall = assert, io, minetest, modlib, string, pcall - --- Set environment -local _ENV = {} -setfenv(1, _ENV) - -_ENV.dir_delim = dir_delim - -function get_name(filepath) - return filepath:match("([^%" .. dir_delim .. "]+)$") or filepath -end - -function split_extension(filename) - return filename:match"^(.*)%.(.*)$" -end ---! deprecated -get_extension = split_extension - -function split_path(filepath) - return modlib.text.split_unlimited(filepath, dir_delim, true) -end - --- concat_path is set by init.lua to avoid code duplication - --- Lua 5.4 has `` for this, but we're restricted to 5.1, --- so we need to roll our own `try f = io.open(...); return func(f) finally f:close() end`. -function with_open(filename, mode, func --[[function(file), called with `file = io.open(filename, mode)`]]) - local file = assert(io.open(filename, mode or "r")) - -- Throw away the stacktrace. The alternative would be to use `xpcall` - -- to bake the stack trace into the error string using `debug.traceback`. - -- Lua will have prepended `::` already however. - return (function(status, ...) - file:close() - assert(status, ...) - return ... - end)(pcall(func, file)) -end - -function read(filename) - local file, err = io.open(filename, "r") - if file == nil then return nil, err end - local content = file:read"*a" - file:close() - return content -end - -function read_binary(filename) - local file, err = io.open(filename, "rb") - if file == nil then return nil, err end - local content = file:read"*a" - file:close() - return content -end - -function write_unsafe(filename, new_content) - local file, err = io.open(filename, "w") - if file == nil then return false, err end - file:write(new_content) - file:close() - return true -end - -write = minetest and minetest.safe_file_write or write_unsafe - -function write_binary_unsafe(filename, new_content) - local file, err = io.open(filename, "wb") - if file == nil then return false, err end - file:write(new_content) - file:close() - return true -end - -write_binary = minetest and minetest.safe_file_write or write_binary_unsafe - -function ensure_content(filename, ensured_content) - local content = read(filename) - if content ~= ensured_content then - return write(filename, ensured_content) - end - return true -end - -function append(filename, new_content) - local file, err = io.open(filename, "a") - if file == nil then return false, err end - file:write(new_content) - file:close() - return true -end - -function exists(filename) - local file, err = io.open(filename, "r") - if file == nil then return false, err end - file:close() - return true -end - -function create_if_not_exists(filename, content) - if not exists(filename) then - return write(filename, content or "") - end - return false -end - -function create_if_not_exists_from_file(filename, src_filename) return create_if_not_exists(filename, read(src_filename)) end - -if not minetest then return end - --- Process Bridge Helpers -process_bridges = {} - -function process_bridge_build(name, input, output, logs) - if not input or not output or not logs then - minetest.mkdir(minetest.get_worldpath() .. "/bridges/" .. name) - end - input = input or minetest.get_worldpath() .. "/bridges/" .. name .. "/input.txt" - output = output or minetest.get_worldpath() .. "/bridges/" .. name .. "/output.txt" - logs = logs or minetest.get_worldpath() .. "/bridges/" .. name .. "/logs.txt" - -- Clear input - write(input, "") - -- Clear output - write(output, "") - -- Create logs if not exists - create_if_not_exists(logs, "") - process_bridges[name] = { - input = input, - output = output, - logs = logs, - output_file = io.open(output, "a") - } -end - -function process_bridge_listen(name, line_consumer, step) - local bridge = process_bridges[name] - modlib.minetest.register_globalstep(step or 0.1, function() - for line in io.lines(bridge.input) do - line_consumer(line) - end - write(bridge.input, "") - end) -end - -function process_bridge_serve(name, step) - local bridge = process_bridges[name] - modlib.minetest.register_globalstep(step or 0.1, function() - bridge.output_file:close() - process_bridges[name].output_file = io.open(bridge.output, "a") - end) -end - -function process_bridge_write(name, message) - local bridge = process_bridges[name] - bridge.output_file:write(message .. "\n") -end - -function process_bridge_start(name, command, os_execute) - local bridge = process_bridges[name] - os_execute(string.format(command, bridge.output, bridge.input, bridge.logs)) -end - --- Export environment -return _ENV diff --git a/mods/modlib/func.lua b/mods/modlib/func.lua deleted file mode 100644 index cb01e0b1..00000000 --- a/mods/modlib/func.lua +++ /dev/null @@ -1,126 +0,0 @@ --- Localize globals -local modlib, unpack, select, setmetatable - = modlib, unpack, select, setmetatable - --- Set environment -local _ENV = {} -setfenv(1, _ENV) - -function no_op() end - -function identity(...) return ... end - --- TODO switch all of these to proper vargs - -function curry(func, ...) - local args = { ... } - return function(...) return func(unpack(args), ...) end -end - -function curry_tail(func, ...) - local args = { ... } - return function(...) return func(unpack(modlib.table.concat({...}, args))) end -end - -function curry_full(func, ...) - local args = { ... } - return function() return func(unpack(args)) end -end - -function args(...) - local args = { ... } - return function(func) return func(unpack(args)) end -end - -function value(val) return function() return val end end - -function values(...) - local args = { ... } - return function() return unpack(args) end -end - -function memoize(func) - return setmetatable({}, { - __index = function(self, key) - local value = func(key) - self[key] = value - return value - end, - __call = function(self, arg) - return self[arg] - end, - __mode = "k" - }) -end - -function compose(func, other_func) - return function(...) - return func(other_func(...)) - end -end - -function override_chain(func, override) - return function(...) - func(...) - return override(...) - end -end - ---+ Calls func using the provided arguments, deepcopies all arguments -function call_by_value(func, ...) - return func(unpack(modlib.table.deepcopy{...}, 1, select("#", ...))) -end - --- Functional wrappers for Lua's builtin metatable operators (arithmetic, concatenation, length, comparison, indexing, call) - --- TODO (?) add operator table `["+"] = add, ...` - -function add(a, b) return a + b end - -function sub(a, b) return a - b end - -function mul(a, b) return a * b end - -function div(a, b) return a / b end - -function mod(a, b) return a % b end - -function pow(a, b) return a ^ b end - -function unm(a) return -a end - -function concat(a, b) return a .. b end - -function len(a) return #a end - -function eq(a, b) return a == b end - -function neq(a, b) return a ~= b end - -function lt(a, b) return a < b end - -function gt(a, b) return a > b end - -function le(a, b) return a <= b end - -function ge(a, b) return a >= b end - -function index(object, key) return object[key] end - -function newindex(object, key, value) object[key] = value end - -function call(object, ...) object(...) end - --- Functional wrappers for logical operators, suffixed with _ for syntactical convenience - -function not_(a) return not a end -_ENV["not"] = not_ - -function and_(a, b) return a and b end -_ENV["and"] = and_ - -function or_(a, b) return a or b end -_ENV["or"] = or_ - --- Export environment -return _ENV \ No newline at end of file diff --git a/mods/modlib/hashheap.lua b/mods/modlib/hashheap.lua deleted file mode 100644 index 2b4e346c..00000000 --- a/mods/modlib/hashheap.lua +++ /dev/null @@ -1,117 +0,0 @@ --- Localize globals -local assert, math_floor, setmetatable, table_insert = assert, math.floor, setmetatable, table.insert - --- Set environment --- Min. heap + Lua hash table to allow updating the stored values -local _ENV = {} -setfenv(1, _ENV) - -local metatable = { __index = _ENV } - -function less_than(a, b) - return a < b -end - ---> empty, duplicate-free min heap with priority queue functionality -function new(less_than) - return setmetatable({ less_than = less_than, indices = {} }, metatable) -end - -local function swap(self, child_index, parent_index) - local child_value, parent_value = self[child_index], self[parent_index] - self.indices[parent_value], self.indices[child_value] = child_index, parent_index - self[parent_index], self[child_index] = child_value, parent_value -end - -local function heapify_up(self, index) - if index == 1 then - return - end - local parent_index = math_floor(index / 2) - if self.less_than(self[index], self[parent_index]) then - swap(self, index, parent_index) - heapify_up(self, parent_index) - end -end - -local function heapify_down(self, index) - local left_child = index * 2 - if left_child > #self then - return - end - local smallest_child = left_child + 1 - if smallest_child > #self or self.less_than(self[left_child], self[smallest_child]) then - smallest_child = left_child - end - if self.less_than(self[smallest_child], self[index]) then - swap(self, smallest_child, index) - heapify_down(self, smallest_child) - end -end - -function push(self, value) - table_insert(self, value) - local last = #self - self.indices[value] = last - heapify_up(self, last) -end - -function top(self) - return self[1] -end - --- TODO what if empty? -function pop(self) - local value = self[1] - self.indices[value] = nil - local last = #self - if last == 1 then - self[1] = nil - return value - end - self[1], self[last] = self[last], nil - heapify_down(self, 1) - return value -end - -function find_index(self, element) - return self.indices[element] -end - --- Notify heap that the element has been decreased -function decrease(self, element) - heapify_up(self, assert(self:find_index(element))) -end - --- Notify heap that the element has been increased -function increase(self, element) - heapify_down(self, assert(self:find_index(element))) -end - --- Replaces the specified element - by identity - with the new element -function replace(self, element, new_element) - local index = assert(self:find_index(element)) - assert(self:find_index(new_element) == nil, "no duplicates allowed") - self[index] = new_element - self.indices[element] = nil - self.indices[new_element] = index; - (self.less_than(new_element, element) and heapify_up or heapify_down)(self, index) -end - -function remove(self, element) - local index = assert(self:find_index(element), "element not found") - self.indices[element] = nil - if index == #self then - self[index] = nil - else - local last_index = #self - local last_element = self[last_index] - self[last_index] = nil - self[index] = last_element - self.indices[last_element] = index; - (self.less_than(last_element, element) and heapify_up or heapify_down)(self, index) - end -end - --- Export environment -return _ENV diff --git a/mods/modlib/hashlist.lua b/mods/modlib/hashlist.lua deleted file mode 100644 index 832e4c69..00000000 --- a/mods/modlib/hashlist.lua +++ /dev/null @@ -1,93 +0,0 @@ --- Localize globals -local setmetatable = setmetatable - --- Table based list, can handle at most 2^52 pushes -local list = {} --- TODO use __len for Lua version > 5.1 -local metatable = {__index = list} -list.metatable = metatable - --- Takes a list -function list:new() - self.head = 0 - self.length = #self - return setmetatable(self, metatable) -end - -function list:in_bounds(index) - return index >= 1 and index <= self.length -end - -function list:get(index) - return self[self.head + index] -end - -function list:set(index, value) - assert(value ~= nil) - self[self.head + index] = value -end - -function list:len() - return self.length -end - -function list:ipairs() - local index = 0 - return function() - index = index + 1 - if index > self.length then - return - end - return index, self[self.head + index] - end -end - -function list:rpairs() - local index = self.length + 1 - return function() - index = index - 1 - if index < 1 then - return - end - return index, self[self.head + index] - end -end - -function list:push_tail(value) - assert(value ~= nil) - self.length = self.length + 1 - self[self.head + self.length] = value -end - -function list:get_tail() - return self[self.head + self.length] -end - -function list:pop_tail() - if self.length == 0 then return end - local value = self:get_tail() - self[self.head + self.length] = nil - self.length = self.length - 1 - return value -end - -function list:push_head(value) - self[self.head] = value - self.head = self.head - 1 - self.length = self.length + 1 -end - -function list:get_head() - return self[self.head + 1] -end - -function list:pop_head() - if self.length == 0 then return end - local value = self:get_head() - self.length = self.length - 1 - self.head = self.head + 1 - self[self.head] = nil - return value -end - -return list \ No newline at end of file diff --git a/mods/modlib/heap.lua b/mods/modlib/heap.lua deleted file mode 100644 index 5bdd7c29..00000000 --- a/mods/modlib/heap.lua +++ /dev/null @@ -1,60 +0,0 @@ --- Localize globals -local math_floor, setmetatable, table_insert = math.floor, setmetatable, table.insert - --- Set environment -local _ENV = {} -setfenv(1, _ENV) - -local metatable = {__index = _ENV} - -function less_than(a, b) return a < b end - ---> empty min heap -function new(less_than) - return setmetatable({less_than = less_than}, metatable) -end - -function push(self, value) - table_insert(self, value) - local function heapify(index) - if index == 1 then - return - end - local parent = math_floor(index / 2) - if self.less_than(self[index], self[parent]) then - self[parent], self[index] = self[index], self[parent] - heapify(parent) - end - end - heapify(#self) -end - -function pop(self) - local value = self[1] - local last = #self - if last == 1 then - self[1] = nil - return value - end - self[1], self[last] = self[last], nil - last = last - 1 - local function heapify(index) - local left_child = index * 2 - if left_child > last then - return - end - local smallest_child = left_child + 1 - if smallest_child > last or self.less_than(self[left_child], self[smallest_child]) then - smallest_child = left_child - end - if self.less_than(self[smallest_child], self[index]) then - self[index], self[smallest_child] = self[smallest_child], self[index] - heapify(smallest_child) - end - end - heapify(1) - return value -end - --- Export environment -return _ENV \ No newline at end of file diff --git a/mods/modlib/init.lua b/mods/modlib/init.lua deleted file mode 100644 index de53983a..00000000 --- a/mods/modlib/init.lua +++ /dev/null @@ -1,147 +0,0 @@ -local modules = {} -for _, file in pairs{ - "schema", - "file", - "func", - "less_than", - "iterator", - "math", - "table", - "vararg", - "text", - "utf8", - "vector", - "matrix4", - "quaternion", - "trie", - "kdtree", - "hashlist", - "hashheap", - "heap", - "binary", - "b3d", - "json", - "luon", - "bluon", - "base64", - "persistence", - "debug", - "web", - "tex" -} do - modules[file] = file -end -if minetest then - modules.minetest = "minetest" -end - --- modlib.mod is an alias for modlib.minetest.mod -modules.string = "text" -modules.number = "math" - -local parent_dir -if not minetest then - -- TOFIX - local init_path = arg and arg[0] - parent_dir = init_path and init_path:match"^.[/\\]" or "" -end - -local dir_delim = rawget(_G, "DIR_DELIM") -- Minetest - or (rawget(_G, "package") and package.config and assert(package.config:match("^(.-)[\r\n]"))) or "/" - -local function concat_path(path) - return table.concat(path, dir_delim) -end - --- only used if Minetest is available -local function get_resource(modname, resource, ...) - if not resource then - resource = modname - modname = minetest.get_current_modname() - end - return concat_path{minetest.get_modpath(modname), resource, ...} -end - -local function load_module(self, module_name_or_alias) - local module_name = modules[module_name_or_alias] - if not module_name then - -- no such module - return - end - local environment - if module_name ~= module_name_or_alias then - -- alias handling - environment = self[module_name] - else - environment = dofile(minetest - and get_resource(self.modname, module_name .. ".lua") - or (parent_dir .. module_name .. ".lua")) - end - self[module_name_or_alias] = environment - return environment -end - -local rawget, rawset = rawget, rawset -modlib = setmetatable({}, { __index = load_module }) - --- TODO bump on release -modlib.version = 102 - -if minetest then - modlib.modname = minetest.get_current_modname() -end - --- Raw globals -modlib._RG = setmetatable({}, { - __index = function(_, index) - return rawget(_G, index) - end, - __newindex = function(_, index, value) - return rawset(_G, index, value) - end -}) - --- Globals merged with modlib -modlib.G = setmetatable({}, {__index = function(self, module_name) - local module = load_module(self, module_name) - if module == nil then - return _G[module_name] - end - if _G[module_name] then - setmetatable(module, {__index = _G[module_name]}) - end - return module -end}) - --- "Imports" modlib by changing the environment of the calling function ---! This alters environments at the expense of performance. Use with caution. ---! Prefer localizing modlib library functions or API tables if possible. -function modlib.set_environment() - setfenv(2, setmetatable({}, {__index = modlib.G})) -end - --- Force load file module to pass dir_delim & to set concat_path -modlib.file = assert(loadfile(get_resource"file.lua"))(dir_delim) -modlib.file.concat_path = concat_path - -if minetest then - -- Force-loading of the minetest & mod modules - -- Also sets modlib.mod -> modlib.minetest.mod alias. - local ml_mt = modlib.minetest - ml_mt.mod.get_resource = get_resource - modlib.mod = ml_mt.mod - -- HACK force load minetest/gametime.lua to ensure that the globalstep is registered earlier than globalsteps of mods depending on modlib - dofile(get_resource(modlib.modname, "minetest", "gametime.lua")) - local ie = minetest.request_insecure_environment() - if ie then - -- Force load persistence namespace to pass insecure require - -- TODO currently no need to set _G.require, lsqlite3 loads no dependencies that way - modlib.persistence = assert(loadfile(get_resource"persistence.lua"))(ie.require) - end -end - --- Run build scripts --- dofile(modlib.mod.get_resource("modlib", "build", "html_entities.lua")) - --- TODO verify localizations suffice -return modlib diff --git a/mods/modlib/iterator.lua b/mods/modlib/iterator.lua deleted file mode 100644 index e5ff49f7..00000000 --- a/mods/modlib/iterator.lua +++ /dev/null @@ -1,311 +0,0 @@ ---[[ - Iterators are always the *last* argument(s) to all functions here, - which differs from other modules which take what they operate on as first argument. - This is because iterators consist of three variables - iterator function, state & control variable - - and wrapping them (using a table, a closure or the like) would be rather inconvenient. - Having them as the last argument allows to just pass in the three variables returned by functions such as `[i]pairs`. - Additionally, putting functions first - although syntactically inconvenient - is consistent with Python and Lisp. -]] - -local coroutine_create, coroutine_resume, coroutine_yield, coroutine_status, unpack, select - = coroutine.create, coroutine.resume, coroutine.yield, coroutine.status, unpack, select - -local identity, not_, add = modlib.func.identity, modlib.func.not_, modlib.func.add - ---+ For all functions which aggregate over single values, use modlib.table.ivalues - not ipairs - for lists! ---+ Otherwise they will be applied to the indices. -local iterator = {} - -function iterator.wrap(iterator, state, control_var) - local function update_control_var(...) - control_var = ... - return ... - end - return function() - return update_control_var(iterator(state, control_var)) - end -end -iterator.closure = iterator.wrap -iterator.make_stateful = iterator.wrap - -function iterator.filter(predicate, iterator, state, control_var) - local function _filter(...) - local cvar = ... - if cvar == nil then - return - end - if predicate(...) then - return ... - end - return _filter(iterator(state, cvar)) - end - return function(state, control_var) - return _filter(iterator(state, control_var)) - end, state, control_var -end - -function iterator.truthy(...) - return iterator.filter(identity, ...) -end - -function iterator.falsy(...) - return iterator.filter(not_, ...) -end - -function iterator.map(map_func, iterator, state, control_var) - local function _map(...) - control_var = ... -- update control var - if control_var == nil then return end - return map_func(...) - end - return function() - return _map(iterator(state, control_var)) - end -end - -function iterator.map_values(map_func, iterator, state, control_var) - local function _map_values(cvar, ...) - if cvar == nil then return end - return cvar, map_func(...) - end - return function(state, control_var) - return _map_values(iterator(state, control_var)) - end, state, control_var -end - --- Iterator must be restartable -function iterator.rep(times, iterator, state, control_var) - times = times or 1 - if times == 1 then - return iterator, state, control_var - end - local function _rep(cvar, ...) - if cvar == nil then - times = times - 1 - if times == 0 then return end - return _rep(iterator(state, control_var)) - end - return cvar, ... - end - return function(state, control_var) - return _rep(iterator(state, control_var)) - end, state, control_var -end - --- Equivalent to `for x, y, z in iterator, state, ... do callback(x, y, z) end` -function iterator.foreach(callback, iterator, state, ...) - local function loop(...) - if ... == nil then return end - callback(...) - return loop(iterator(state, ...)) - end - return loop(iterator(state, ...)) -end - -function iterator.for_generator(caller, ...) - local co = coroutine_create(function(...) - return caller(function(...) - return coroutine_yield(...) - end, ...) - end) - local args, n_args = {...}, select("#", ...) - return function() - if coroutine_status(co) == "dead" then - return - end - local function _iterate(status, ...) - if not status then - error((...)) - end - return ... - end - return _iterate(coroutine_resume(co, unpack(args, 1, n_args))) - end -end - -function iterator.range(from, to, step) - if not step then - if not to then - from, to = 1, from - end - step = 1 - end - - return function(_, current) - current = current + step - if current > to then - return - end - return current - end, nil, from - step -end - -function iterator.aggregate(binary_func, total, ...) - for value in ... do - total = binary_func(total, value) - end - return total -end - --- Like `iterator.aggregate`, but does not expect a `total` -function iterator.reduce(binary_func, iterator, state, control_var) - local total = iterator(state, control_var) - if total == nil then - return -- nothing if the iterator is empty - end - for value in iterator, state, total do - total = binary_func(total, value) - end - return total -end -iterator.fold = iterator.reduce - --- TODO iterator.find(predicate, iterator, state, control_var) - -function iterator.any(...) - for val in ... do - if val then return true end - end - return false -end - -function iterator.all(...) - for val in ... do - if not val then return false end - end - return true -end - -function iterator.min(less_than_func, ...) - local min - for value in ... do - if min == nil or less_than_func(value, min) then - min = value - end - end - return min -end - --- TODO iterator.max - -function iterator.empty(iterator, state, control_var) - return iterator(state, control_var) == nil -end - -function iterator.first(iterator, state, control_var) - return iterator(state, control_var) -end - -function iterator.last(iterator, state, control_var) - -- Storing a vararg in a table seems to be necessary: https://stackoverflow.com/questions/73914273/ - -- This could be optimized further for memory by keeping the same table across calls, - -- but that might cause issues with multiple coroutines calling this - local last, last_n = {}, 0 - - local function _last(...) - local cvar = ... - if cvar == nil then - return unpack(last, 1, last_n) - end - - -- Write vararg to table: Avoid the creation of a garbage table every iteration by reusing the same table - last_n = select("#", ...) - for i = 1, last_n do - last[i] = select(i, ...) - end - - return _last(iterator(state, cvar)) - end - - return _last(iterator(state, control_var)) -end - --- Converts a vararg starting with `nil` (end of loop control variable) into nothing -local function nil_to_nothing(...) - if ... == nil then return end - return ... -end - -function iterator.select(n, iterator, state, control_var) - for _ = 1, n - 1 do - control_var = iterator(state, control_var) - if control_var == nil then return end - end - -- Either all values returned by the n-th call iteration - -- or nothing if the iterator holds fewer than `n` values - return nil_to_nothing(iterator(state, control_var)) -end - -function iterator.limit(count, iterator, state, control_var) - return function(state, control_var) - count = count - 1 - if count < 0 then return end - return iterator(state, control_var) - end, state, control_var -end - -function iterator.count(...) - local count = 0 - for _ in ... do - count = count + 1 - end - return count -end - -function iterator.sum(...) - return iterator.aggregate(add, 0, ...) -end - -function iterator.average(...) - local count = 0 - local sum = 0 - for value in ... do - count = count + 1 - sum = sum + value - end - return sum / count -end - ---: ... **restartable** iterator --- A single pass method for calculating the standard deviation exists but is highly inaccurate -function iterator.standard_deviation(...) - local avg = iterator.average(...) - local count = 0 - local sum = 0 - for value in ... do - count = count + 1 - sum = sum + (value - avg)^2 - end - return (sum / count)^.5 -end - --- Comprehensions ("collectors") - --- Shorthand for `for k, v in ... do t[k] = v end` -function iterator.to_table(...) - local t = {} - for k, v in ... do - t[k] = v - end - return t -end - --- Shorthand for `for k in ... do t[#t + 1] = k end` -function iterator.to_list(...) - local t = {} - for k in ... do - t[#t + 1] = k - end - return t -end - --- Shorthand for `for k in ... do t[k] = true end` -function iterator.to_set(...) - local t = {} - for k in ... do - t[k] = true - end - return t -end - -return iterator \ No newline at end of file diff --git a/mods/modlib/json.lua b/mods/modlib/json.lua deleted file mode 100644 index 17950cb2..00000000 --- a/mods/modlib/json.lua +++ /dev/null @@ -1,402 +0,0 @@ -local modlib, setmetatable, pairs, assert, error, table_insert, table_concat, tonumber, tostring, math_huge, string, type, next - = modlib, setmetatable, pairs, assert, error, table.insert, table.concat, tonumber, tostring, math.huge, string, type, next - -local _ENV = {} -setfenv(1, _ENV) - --- See https://tools.ietf.org/id/draft-ietf-json-rfc4627bis-09.html#unichars and https://json.org - --- Null --- TODO consider using userdata (for ex. by using newproxy) -do - local metatable = {} - -- eq is not among the metamethods, len won't work on 5.1 - for _, metamethod in pairs{"add", "sub", "mul", "div", "mod", "pow", "unm", "concat", "len", "lt", "le", "index", "newindex", "call"} do - metatable["__" .. metamethod] = function() return error("attempt to " .. metamethod .. " a null value") end - end - null = setmetatable({}, metatable) -end - -local metatable = {__index = _ENV} -_ENV.metatable = metatable -function new(self) - return setmetatable(self, metatable) -end - -local whitespace = modlib.table.set{"\t", "\r", "\n", " "} -local decoding_escapes = { - ['"'] = '"', - ["\\"] = "\\", - ["/"] = "/", - b = "\b", - f = "\f", - n = "\n", - r = "\r", - t = "\t" - -- TODO is this complete? -} - --- Set up a DFA for number syntax validations -local number_dfa -do -- as a RegEx: (0|(1-9)(0-9)*)[.(0-9)+[(e|E)[+|-](0-9)+]]; does not need to handle the first sign - -- TODO proper DFA utilities - local function set_transitions(state, transitions) - for chars, next_state in pairs(transitions) do - for char in chars:gmatch"." do - state[char] = next_state - end - end - end - local onenine = "123456789" - local digit = "0" .. onenine - local e = "eE" - local exponent = {final = true} - set_transitions(exponent, { - [digit] = exponent - }) - local pre_exponent = {expected = "exponent"} - set_transitions(pre_exponent, { - [digit] = exponent - }) - local exponent_sign = {expected = "exponent"} - set_transitions(exponent_sign, { - [digit] = exponent, - ["+"] = exponent, - ["-"] = exponent - }) - local fraction_final = {final = true} - set_transitions(fraction_final, { - [digit] = fraction_final, - [e] = exponent_sign - }) - local fraction = {expected = "fraction"} - set_transitions(fraction, { - [digit] = fraction_final - }) - local integer = {final = true} - set_transitions(integer, { - [digit] = integer, - [e] = exponent_sign, - ["."] = fraction - }) - local zero = {final = true} - set_transitions(zero, { - ["."] = fraction - }) - number_dfa = {} - set_transitions(number_dfa, { - [onenine] = integer, - ["0"] = zero - }) -end - -local hex_digit_values = {} -for i = 0, 9 do - hex_digit_values[tostring(i)] = i -end -for i = 0, 5 do - hex_digit_values[string.char(("a"):byte() + i)] = 10 + i - hex_digit_values[string.char(("A"):byte() + i)] = 10 + i -end - --- TODO SAX vs DOM -local utf8_char = modlib.utf8.char -function read(self, read_) - local index = 0 - local char - -- TODO support read functions which provide additional debug output (such as row:column) - local function read() - index = index + 1 - char = read_() - return char - end - local function syntax_error(errmsg) - -- TODO ensure the index isn't off - error("syntax error: " .. index .. ": " .. errmsg) - end - local function syntax_assert(value, errmsg) - if not value then - syntax_error(errmsg or "assertion failed!") - end - return value - end - local function skip_whitespace() - while whitespace[char] do - read() - end - end - -- Forward declaration - local value - local function number() - local state = number_dfa - local num = {} - while true do - -- Will work for nil too - local next_state = state[char] - if not next_state then - if not state.final then - if state == number_dfa then - syntax_error"expected a number" - end - syntax_error("invalid number: expected " .. state.expected) - end - return assert(tonumber(table_concat(num))) - end - table_insert(num, char) - state = next_state - read() - end - end - local function utf8_codepoint(codepoint) - return syntax_assert(utf8_char(codepoint), "invalid codepoint") - end - local function string() - local chars = {} - local high_surrogate - while true do - local string_char, next_high_surrogate - if char == '"' then - if high_surrogate then - table_insert(chars, utf8_codepoint(high_surrogate)) - end - return table_concat(chars) - end - if char == "\\" then - read() - if char == "u" then - local codepoint = 0 - for i = 3, 0, -1 do - codepoint = syntax_assert(hex_digit_values[read()], "expected a hex digit") * (16 ^ i) + codepoint - end - if high_surrogate and codepoint >= 0xDC00 and codepoint <= 0xDFFF then - -- TODO strict mode: throw an error for single surrogates - codepoint = 0x10000 + (high_surrogate - 0xD800) * 0x400 + codepoint - 0xDC00 - -- Don't write the high surrogate - high_surrogate = nil - end - if codepoint >= 0xD800 and codepoint <= 0xDBFF then - next_high_surrogate = codepoint - else - string_char = utf8_codepoint(codepoint) - end - else - string_char = syntax_assert(decoding_escapes[char], "invalid escape sequence") - end - else - -- TODO check whether the character is one that must be escaped ("strict" mode) - string_char = syntax_assert(char, "unclosed string") - end - if high_surrogate then - table_insert(chars, utf8_codepoint(high_surrogate)) - end - high_surrogate = next_high_surrogate - if string_char then - table_insert(chars, string_char) - end - read() - end - end - local element - local funcs = { - ['-'] = function() - return -number() - end, - ['"'] = string, - ["{"] = function() - local dict = {} - skip_whitespace() - if char == "}" then return dict end - while true do - syntax_assert(char == '"', "key expected") - read() - local key = string() - read() - skip_whitespace() - syntax_assert(char == ":", "colon expected, got " .. char) - local val = element() - dict[key] = val - if char == "}" then return dict end - syntax_assert(char == ",", "comma expected") - read() - skip_whitespace() - end - end, - ["["] = function() - local list = {} - skip_whitespace() - if char == "]" then return list end - while true do - table_insert(list, value()) - skip_whitespace() - if char == "]" then return list end - syntax_assert(char == ",", "comma expected") - read() - skip_whitespace() - end - end, - } - local function expect_word(word, value) - local msg = word .. " expected" - funcs[word:sub(1, 1)] = function() - syntax_assert(char == word:sub(2, 2), msg) - for i = 3, #word do - read() - syntax_assert(char == word:sub(i, i), msg) - end - return value - end - end - expect_word("true", true) - expect_word("false", false) - expect_word("null", self.null) - function value() - syntax_assert(char, "value expected") - local func = funcs[char] - if func then - -- Advance after first char - read() - local val = func() - -- Advance after last char - read() - return val - end - if char >= "0" and char <= "9" then - return number() - end - syntax_error"value expected" - end - function element() - read() - skip_whitespace() - local val = value() - skip_whitespace() - return val - end - -- TODO consider asserting EOF as read() == nil, perhaps controlled by a parameter - return element() -end - -local encoding_escapes = modlib.table.flip(decoding_escapes) --- Solidus does not need to be escaped -encoding_escapes["/"] = nil --- Control characters. Note: U+0080 to U+009F and U+007F are not considered control characters. -for byte = 0, 0x1F do - encoding_escapes[string.char(byte)] = string.format("u%04X", byte) -end -modlib.table.map(encoding_escapes, function(str) return "\\" .. str end) -local function escape(str) - return str:gsub(".", encoding_escapes) -end -function write(self, value, write) - local null = self.null - local written_strings = self.cache_escaped_strings and setmetatable({}, {__index = function(self, str) - local escaped_str = escape(str) - self[str] = escaped_str - return escaped_str - end}) - local function string(str) - write'"' - write(written_strings and written_strings[str] or escape(str)) - return write'"' - end - local dump - local function write_kv(key, value) - assert(type(key) == "string", "not a dictionary") - string(key) - write":" - dump(value) - end - function dump(value) - if value == null then - -- TODO improve null check (checking for equality doesn't allow using nan as null, for instance) - return write"null" - end - if value == true then - return write"true" - end - if value == false then - return write"false" - end - local type_ = type(value) - if type_ == "number" then - assert(value == value, "unsupported number value: nan") - assert(value ~= math_huge, "unsupported number value: inf") - assert(value ~= -math_huge, "unsupported number value: -inf") - return write(("%.17g"):format(value)) - end - if type_ == "string" then - return string(value) - end - if type_ == "table" then - local table = value - local len = #table - if len == 0 then - local first, value = next(table) - write"{" - if first ~= nil then - write_kv(first, value) - end - for key, value in next, table, first do - write"," - write_kv(key, value) - end - write"}" - else - assert(modlib.table.count(table) == len, "mixed list & hash part") - write"[" - for i = 1, len - 1 do - dump(table[i]) - write"," - end - dump(table[len]) - write"]" - end - return - end - error("unsupported type: " .. type_) - end - dump(value) -end - --- TODO get rid of this paste of write_file and write_string (see modlib.luon) - -function write_file(self, value, file) - return self:write(value, function(text) - file:write(text) - end) -end - -function write_string(self, value) - local rope = {} - self:write(value, function(text) - table_insert(rope, text) - end) - return table_concat(rope) -end - --- TODO read_path (for other serializers too) - -function read_file(self, file) - local value = self:read(function() - return file:read(1) - end) - -- TODO consider file:close() - return value -end - -function read_string(self, string) - -- TODO move the string -> one char read func pattern to modlib.text - local index = 0 - local value = self:read(function() - index = index + 1 - if index > #string then - return - end - return string:sub(index, index) - end) - -- We just expect EOF for strings - assert(index > #string, "EOF expected") - return value -end - -return _ENV \ No newline at end of file diff --git a/mods/modlib/kdtree.lua b/mods/modlib/kdtree.lua deleted file mode 100644 index 5503baef..00000000 --- a/mods/modlib/kdtree.lua +++ /dev/null @@ -1,64 +0,0 @@ --- Localize globals -local assert, math, modlib, setmetatable, table, unpack = assert, math, modlib, setmetatable, table, unpack - --- Set environment -local _ENV = {} -setfenv(1, _ENV) - -local metatable = {__index = _ENV} - -distance = modlib.vector.distance - ---: vectors first vector is used to infer the dimension ---: distance (vector, other_vector) -> number, default: modlib.vector.distance -function new(vectors, distance) - assert(#vectors > 0, "vector list must not be empty") - local dimension = #vectors[1] - local function builder(vectors, axis) - if #vectors == 1 then return { value = vectors[1] } end - table.sort(vectors, function(a, b) return a[axis] > b[axis] end) - local median = math.floor(#vectors / 2) - local next_axis = ((axis + 1) % dimension) + 1 - return setmetatable({ - axis = axis, - pivot = vectors[median], - left = builder({ unpack(vectors, 1, median) }, next_axis), - right = builder({ unpack(vectors, median + 1) }, next_axis) - }, metatable) - end - local self = builder(vectors, 1) - self.distance = distance - return setmetatable(self, metatable) -end - -function get_nearest_neighbor(self, vector) - local min_distance = math.huge - local nearest_neighbor - local distance_func = self.distance - local function visit(tree) - local axis = tree.axis - if tree.value ~= nil then - local distance = distance_func(tree.value, vector) - if distance < min_distance then - min_distance = distance - nearest_neighbor = tree.value - end - return - else - local this_side, other_side = tree.left, tree.right - if vector[axis] < tree.pivot[axis] then this_side, other_side = other_side, this_side end - visit(this_side) - if tree.pivot then - local dist = math.abs(tree.pivot[axis] - vector[axis]) - if dist <= min_distance then visit(other_side) end - end - end - end - visit(self) - return nearest_neighbor, min_distance -end - --- TODO insertion & deletion + rebalancing - --- Export environment -return _ENV \ No newline at end of file diff --git a/mods/modlib/less_than.lua b/mods/modlib/less_than.lua deleted file mode 100644 index 81d7dc6a..00000000 --- a/mods/modlib/less_than.lua +++ /dev/null @@ -1,53 +0,0 @@ --- Comparator utilities for "less than" functions returning whether a < b -local less_than = {} -setfenv(1, less_than) - -default = {} - -function default.less_than(a, b) return a < b end; default.lt = default.less_than -function default.less_or_equal(a, b) return a <= b end; default.leq = default.less_or_equal -function default.greater_than(a, b) return a > b end; default.gt = default.greater_than -function default.greater_or_equal(a, b) return a >= b end; default.geq = default.greater_or_equal - -function less_or_equal(less_than) - return function(a, b) return not less_than(b, a) end -end -leq = less_or_equal - -function greater_or_equal(less_than) - return function(a, b) return not less_than(a, b) end -end -geq = greater_or_equal - -function greater_than(less_than) - return function(a, b) return less_than(b, a) end -end -gt = greater_than - -function equal(less_than) - return function(a, b) - return not (less_than(a, b) or less_than(b, a)) - end -end - -function relation(less_than) - return function(a, b) - if less_than(a, b) then return "<" - elseif less_than(b, a) then return ">" - else return "=" end - end -end - -function by_func(func) - return function(a, b) - return func(a) < func(b) - end -end - -function by_field(key) - return function(a, b) - return a[key] < b[key] - end -end - -return less_than \ No newline at end of file diff --git a/mods/modlib/logo.svg b/mods/modlib/logo.svg deleted file mode 100644 index e129bbc0..00000000 --- a/mods/modlib/logo.svg +++ /dev/null @@ -1,38 +0,0 @@ - - - - - - - image/svg+xml - - - - - - - - - diff --git a/mods/modlib/luon.lua b/mods/modlib/luon.lua deleted file mode 100644 index c9df4ba0..00000000 --- a/mods/modlib/luon.lua +++ /dev/null @@ -1,207 +0,0 @@ --- Lua module to serialize values as Lua code - -local assert, error, rawget, pairs, pcall, type, setfenv, setmetatable, select, loadstring, loadfile - = assert, error, rawget, pairs, pcall, type, setfenv, setmetatable, select, loadstring, loadfile - -local table_concat, string_format, math_huge - = table.concat, string.format, math.huge - -local count_objects = modlib.table.count_objects -local is_identifier = modlib.text.is_identifier - -local function quote(string) - return string_format("%q", string) -end - -local _ENV = {} -setfenv(1, _ENV) -local metatable = {__index = _ENV} -_ENV.metatable = metatable - -function new(self) - return setmetatable(self, metatable) -end - -function aux_write(_self, _object) - -- returns reader, arguments - return -end - -aux_read = {} - -function write(self, value, write) - -- TODO evaluate custom aux. writers *before* writing for circular structs - local reference, refnum = "1", 1 - -- [object] = reference - local references = {} - -- Circular tables that must be filled using `table[key] = value` statements - local to_fill = {} - - -- TODO (?) sort objects by count, give frequently referenced objects shorter references - for object, count in pairs(count_objects(value)) do - local type_ = type(object) - -- Object must appear more than once. If it is a string, the reference has to be shorter than the string. - if count >= 2 and (type_ ~= "string" or #reference + 5 < #object) then - if refnum == 1 then - write"local _={};" -- initialize reference table - end - write"_[" - write(reference) - write"]=" - if type_ == "table" then - write"{}" - elseif type_ == "string" then - write(quote(object)) - end - write";" - references[object] = reference - if type_ == "table" then - to_fill[object] = reference - end - refnum = refnum + 1 - reference = string_format("%d", refnum) - end - end - -- Used to decide whether we should do "key=..." - local function use_short_key(key) - return not references[key] and type(key) == "string" and is_identifier(key) - end - local function dump(value) - -- Primitive types - if value == nil then - return write"nil" - end if value == true then - return write"true" - end if value == false then - return write"false" - end - local type_ = type(value) - if type_ == "number" then - -- Explicit handling of special values for forwards compatibility - if value ~= value then -- nan - return write"0/0" - end if value == math_huge then - return write"1/0" - end if value == -math_huge then - return write"-1/0" - end - return write(string_format("%.17g", value)) - end - -- Reference types: table and string - local ref = references[value] - if ref then - -- Referenced - write"_[" - write(ref) - return write"]" - end if type_ == "string" then - return write(quote(value)) - end if type_ == "table" then - write"{" - -- First write list keys: - -- Don't use the table length #value here as it may horribly fail - -- for tables which use large integers as keys in the hash part; - -- stop at the first "hole" (nil value) instead - local len = 0 - local first = true -- whether this is the first entry, which may not have a leading comma - while true do - local v = rawget(value, len + 1) -- use rawget to avoid metatables like the vector metatable - if v == nil then break end - if first then first = false else write(",") end - dump(v) - len = len + 1 - end - -- Now write map keys ([key] = value) - for k, v in pairs(value) do - -- We have written all non-float keys in [1, len] already - if type(k) ~= "number" or k % 1 ~= 0 or k < 1 or k > len then - if first then first = false else write(",") end - if use_short_key(k) then - write(k) - else - write"[" - dump(k) - write"]" - end - write"=" - dump(v) - end - end - return write"}" - end - -- TODO move aux_write to start, to allow dealing with metatables etc.? - return (function(func, ...) - -- functions are the only way to deal with varargs - if not func then - return error("unsupported type: " .. type_) - end - write(func) - write"(" - local n = select("#", ...) - for i = 1, n - 1 do - dump(select(i, ...)) - write"," - end - if n > 0 then - dump(select(n, ...)) - end - write")" - end)(self:aux_write(value)) - end - -- Write the statements to fill circular tables - for table, ref in pairs(to_fill) do - for k, v in pairs(table) do - write"_[" - write(ref) - write"]" - if use_short_key(k) then - write"." - write(k) - else - write"[" - dump(k) - write"]" - end - write"=" - dump(v) - write";" - end - end - write"return " - dump(value) -end - -function write_file(self, value, file) - return self:write(value, function(text) - file:write(text) - end) -end - -function write_string(self, value) - local rope = {} - self:write(value, function(text) - rope[#rope + 1] = text - end) - return table_concat(rope) -end - -function read(self, ...) - local read = assert(...) - -- math.huge was serialized to inf, 0/0 was serialized to -nan by `%.17g` - setfenv(read, setmetatable({inf = math_huge, nan = 0/0}, {__index = self.aux_read})) - local success, value_or_err = pcall(read) - if success then - return value_or_err - end - return nil, value_or_err -end - -function read_file(self, path) - return self:read(loadfile(path)) -end - -function read_string(self, string) - return self:read(loadstring(string)) -end - -return _ENV \ No newline at end of file diff --git a/mods/modlib/math.lua b/mods/modlib/math.lua deleted file mode 100644 index d7f01dfb..00000000 --- a/mods/modlib/math.lua +++ /dev/null @@ -1,182 +0,0 @@ --- Localize globals -local assert, math, math_floor, minetest, modlib_table_reverse, os, string_char, select, setmetatable, table_insert, table_concat - = assert, math, math.floor, minetest, modlib.table.reverse, os, string.char, select, setmetatable, table.insert, table.concat - -local inf = math.huge - --- Set environment -local _ENV = {} -setfenv(1, _ENV) - --- TODO might be too invasive --- Make random random -math.randomseed(minetest and minetest.get_us_time() or os.time() + os.clock()) -for _ = 1, 100 do math.random() end - -negative_nan = 0/0 -positive_nan = negative_nan ^ 1 - -function sign(number) - if number ~= number then return number end -- nan - if number == 0 then return 0 end - if number < 0 then return -1 end - if number > 0 then return 1 end -end - -function clamp(number, min, max) - return math.min(math.max(number, min), max) -end - --- Random integer from 0 to 2^53 - 1 (inclusive) -local function _randint() - return math.random(0, 2^27 - 1) * 2^26 + math.random(0, 2^26 - 1) -end - --- Random float from 0 to 1 (exclusive) -local function _randfloat() - return _randint() / (2^53) -end - ---+ Increased randomness float random without overflows ---+ `random()`: Random number from `0` to `1` (exclusive) ---+ `random(max)`: Random number from `0` to `max` (exclusive) ---+ `random(min, max)`: Random number from `min` to `max` (exclusive) -function random(...) - local n = select("#", ...) - if n == 0 then - return _randfloat() - end if n == 1 then - local max = ... - return _randfloat() * max - end do assert(n == 2) - local min, max = ... - return min + (max - min) * _randfloat() - end -end - --- Increased randomness integer random ---+ `randint()`: Random integer from `0` to `2^53 - 1` (inclusive) ---+ `randint(max)`: Random integer from `0` to `max` (inclusive) ---+ `randint(min, max)`: Random integer from `min` to `max` (inclusive) -function randint(...) - local n = select("#", ...) - if n == 0 then - return _randint() - end if n == 1 then - local max = ... - return math.floor(_randfloat() * max + 0.5) - end do assert(n == 2) - local min, max = ... - return min + math.floor(_randfloat() * (max - min) + 0.5) - end -end - -log = setmetatable({}, { - __index = function(self, base) - local div = math.log(base) - local function base_log(number) - return math.log(number) / div - end - self[base] = base_log - return base_log - end, - __call = function(_, number, base) - if not base then - return math.log(number) - end - return math.log(number) / math.log(base) - end -}) - --- one-based mod -function onemod(number, modulus) - return ((number - 1) % modulus) + 1 -end - -function round(number, steps) - steps = steps or 1 - return math_floor(number * steps + 0.5) / steps -end - -local c0 = ("0"):byte() -local cA = ("A"):byte() - -function default_digit_function(digit) - if digit <= 9 then return string_char(c0 + digit) end - return string_char(cA + digit - 10) -end - -default_precision = 10 - --- See https://github.com/appgurueu/Luon/blob/master/index.js#L724 -function tostring(number, base, digit_function, precision) - if number ~= number then - return "nan" - end - if number == inf then - return "inf" - end - if number == -inf then - return "-inf" - end - digit_function = digit_function or default_digit_function - precision = precision or default_precision - local out = {} - if number < 0 then - table_insert(out, "-") - number = -number - end - -- Rounding - number = number + base ^ -precision / 2 - local digit - while number >= base do - digit = math_floor(number % base) - table_insert(out, digit_function(digit)) - number = (number - digit) / base - end - digit = math_floor(number) - table_insert(out, digit_function(digit)) - modlib_table_reverse(out) - number = number % 1 - if number ~= 0 and number >= base ^ -precision then - table_insert(out, ".") - while precision >= 0 and number >= base ^ -precision do - number = number * base - digit = math_floor(number % base) - table_insert(out, digit_function(digit)) - number = number - digit - precision = precision - 1 - end - end - return table_concat(out) -end - --- See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/fround#polyfill --- Rounds a 64-bit float to a 32-bit float; --- if the closest 32-bit float is out of bounds, --- the appropriate infinity is returned. -function fround(number) - if number == 0 or number ~= number then - return number - end - local sign = 1 - if number < 0 then - sign = -1 - number = -number - end - local _, exp = math.frexp(number) - exp = exp - 1 -- we want 2^exponent >= number > 2^(exponent-1) - local powexp = 2 ^ math.max(-126, math.min(exp, 127)) - local leading = exp <= -127 and 0 or 1 -- subnormal number? - local mantissa = math.floor((number / powexp - leading) * 0x800000 + 0.5) - if - mantissa > 0x800000 -- doesn't fit in mantissa - or (exp >= 127 and mantissa == 0x800000) -- fits if the exponent can be increased - then - return sign * inf - end - return sign * powexp * (leading + mantissa / 0x800000) -end - --- Export environment -return _ENV diff --git a/mods/modlib/matrix4.lua b/mods/modlib/matrix4.lua deleted file mode 100644 index 4303717e..00000000 --- a/mods/modlib/matrix4.lua +++ /dev/null @@ -1,180 +0,0 @@ --- Simple 4x4 matrix for 3d transformations (translation, rotation, scale); --- provides exactly the methods needed to calculate inverse bind matrices (for b3d -> glTF conversion) -local mat4 = {} -local metatable = {__index = mat4} - -function mat4.new(rows) - assert(#rows == 4) - for i = 1, 4 do - assert(#rows[i] == 4) - end - return setmetatable(rows, metatable) -end - -function mat4.identity() - return mat4.new{ - {1, 0, 0, 0}, - {0, 1, 0, 0}, - {0, 0, 1, 0}, - {0, 0, 0, 1}, - } -end - --- Matrices can't properly represent translation: --- => work with 4d vectors, assume w = 1. -function mat4.translation(vec) - assert(#vec == 3) - local x, y, z = unpack(vec) - return mat4.new{ - {1, 0, 0, x}, - {0, 1, 0, y}, - {0, 0, 1, z}, - {0, 0, 0, 1}, - } -end - --- See https://en.wikipedia.org/wiki/Quaternions_and_spatial_rotation -function mat4.rotation(unit_quat) - assert(#unit_quat == 4) - local x, y, z, w = unpack(unit_quat) -- TODO (?) assert unit quaternion - return mat4.new{ - {1 - 2*(y^2 + z^2), 2*(x*y - z*w), 2*(x*z + y*w), 0}, - {2*(x*y + z*w), 1 - 2*(x^2 + z^2), 2*(y*z - x*w), 0}, - {2*(x*z - y*w), 2*(y*z + x*w), 1 - 2*(x^2 + y^2), 0}, - {0, 0, 0, 1}, - } -end - -function mat4.scale(vec) - assert(#vec == 3) - local x, y, z = unpack(vec) - return mat4.new{ - {x, 0, 0, 0}, - {0, y, 0, 0}, - {0, 0, z, 0}, - {0, 0, 0, 1}, - } -end - --- Apply `self` to a 4d modlib vector `vec` -function mat4:apply(vec) - assert(#vec == 4) - local res = {} - for i = 1, 4 do - local sum = 0 - for j = 1, 4 do - sum = sum + self[i][j] * vec[j] - end - res[i] = sum - end - return vec.new(res) -end - --- Multiplication: First apply other, then self ---> Matrix product `self * other` -function mat4:multiply(other) - local res = {} - for i = 1, 4 do - res[i] = {} - for j = 1, 4 do - local sum = 0 -- dot product of row & col vec - for k = 1, 4 do - sum = sum + self[i][k] * other[k][j] - end - res[i][j] = sum - end - end - return mat4.new(res) -end - --- Composition: First apply self, then other -function mat4:compose(other) - return other:multiply(self) -- equivalent to `other * self` in terms of matrix multiplication -end - --- Matrix inversion using Gauss-Jordan elimination -do - -- Fundamental operations - local function _swap_rows(mat, i, j) - mat[i], mat[j] = mat[j], mat[i] - end - local function _scale_row(mat, factor, row_idx) - for i = 1, 4 do - mat[row_idx][i] = factor * mat[row_idx][i] - end - end - local function _add_row_with_factor(mat, factor, src_row_idx, dst_row_idx) - assert(src_row_idx ~= dst_row_idx) - for i = 1, 4 do - mat[dst_row_idx][i] = mat[dst_row_idx][i] + factor * mat[src_row_idx][i] - end - end - - local epsilon = 1e-6 -- small threshold; values below this are considered zero - function mat4:inverse() - local inv = mat4.identity() -- inverse matrix: all elimination operations will also be applied to this - local copy = {} -- copy of `self` the Gaussian elimination is being executed on - for i = 1, 4 do - copy[i] = {} - for j = 1, 4 do - copy[i][j] = self[i][j] - end - end - - -- All operations must be mirrored to the inverse matrix - local function swap_rows(i, j) - _swap_rows(copy, i, j) - _swap_rows(inv, i, j) - end - local function scale_row(factor, row_idx) - _scale_row(copy, factor, row_idx) - _scale_row(inv, factor, row_idx) - end - local function add_with_factor(factor, src_row_idx, dst_row_idx) - _add_row_with_factor(copy, factor, src_row_idx, dst_row_idx) - _add_row_with_factor(inv, factor, src_row_idx, dst_row_idx) - end - - -- Elimination phase - for col_idx = 1, 4 do - -- Find a pivot row: Choose the row with the largest absolute component - local max_row_idx = col_idx - local max_abs_comp = math.abs(copy[max_row_idx][col_idx]) - for row_idx = col_idx, 4 do - local cand_comp = math.abs(copy[row_idx][col_idx]) - if cand_comp > max_abs_comp then - max_row_idx, max_abs_comp = row_idx, cand_comp - end - end - - -- Assert that there is a row that has this component "nonzero" - assert(max_abs_comp >= epsilon, "matrix not invertible!") - - swap_rows(col_idx, max_row_idx) -- swap row to correct position - -- Eliminate the `col_idx`-th component in all rows *below* the pivot row - local pivot_value = copy[col_idx][col_idx] - for row_idx = col_idx + 1, 4 do - local factor = -copy[row_idx][col_idx] / pivot_value - add_with_factor(factor, col_idx, row_idx) - assert(math.abs(copy[row_idx][col_idx]) < epsilon) -- should be eliminated now - end - end - - -- Resubstitution phase - pretty much the same but in reverse and without swapping - for col_idx = 4, 1, -1 do - local pivot_value = copy[col_idx][col_idx] - -- Eliminate the `col_idx`-th component in all rows *above* the pivot row - for row_idx = col_idx - 1, 1, -1 do - local factor = -copy[row_idx][col_idx] / pivot_value - add_with_factor(factor, col_idx, row_idx) - assert(math.abs(copy[row_idx][col_idx]) < epsilon) -- should be eliminated now - end - scale_row(1/pivot_value, col_idx) -- normalize row - end - - -- Done: `copy` should now be the identity matrix <=> `inv` is the inverse. - return inv - end -end - -return mat4 diff --git a/mods/modlib/minetest.lua b/mods/modlib/minetest.lua deleted file mode 100644 index 629e442b..00000000 --- a/mods/modlib/minetest.lua +++ /dev/null @@ -1,90 +0,0 @@ -local _ENV = {} - -local components = {} -for _, value in pairs{ - "mod", - "luon", - "raycast", - "schematic", - "colorspec", - "media", - "obj", - "texmod", -} do - components[value] = value -end - --- These dirty files have to write to the modlib.minetest environment -local dirty_files = {} -for filename, comps in pairs{ - -- get_gametime is missing from here as it is forceloaded in init.lua - misc = { - "max_wear", - "override", - "after", - "register_globalstep", - "form_listeners", - "register_form_listener", - "texture_modifier_inventorycube", - "get_node_inventory_image", - "check_player_privs", - "decode_base64", - "objects_inside_radius", - "objects_inside_area", - "nodename_matcher", - "playerdata", - "connected_players", - "set_privs", - "register_on_leaveplayer", - "get_mod_info", - "get_mod_load_order" - }, - liquid = { - "liquid_level_max", - "get_liquid_corner_levels", - "flowing_downwards", - "get_liquid_flow_direction" - }, - wielditem_change = { - "players", - "registered_on_wielditem_changes", - "register_on_wielditem_change" - }, - colorspec = { - "named_colors", - "colorspec_to_colorstring" - }, - boxes = { - "get_node_boxes", - "get_node_collisionboxes", - "get_node_selectionboxes", - }, - png = { - "decode_png", - "convert_png_to_argb8", - "encode_png", - } -} do - for _, component in pairs(comps) do - components[component] = filename - end - dirty_files[filename] = true -end - -local modpath, concat_path = minetest.get_modpath(modlib.modname), modlib.file.concat_path - -setmetatable(_ENV, {__index = function(_ENV, name) - local filename = components[name] - if filename then - local loader = assert(loadfile(concat_path{modpath, "minetest", filename .. ".lua"})) - if dirty_files[filename] then - loader(_ENV) - return rawget(_ENV, name) - end - local module = loader() - _ENV[name] = module - return module - end -end}) - -return _ENV \ No newline at end of file diff --git a/mods/modlib/minetest/boxes.lua b/mods/modlib/minetest/boxes.lua deleted file mode 100644 index 4c193a6f..00000000 --- a/mods/modlib/minetest/boxes.lua +++ /dev/null @@ -1,166 +0,0 @@ --- Localize globals -local assert, ipairs, math, minetest, table, type, vector - = assert, ipairs, math, minetest, table, type, vector - --- Set environment -local _ENV = ... -setfenv(1, _ENV) - --- Minetest allows shorthand box = {...} instead of {{...}} -local function get_boxes(box_or_boxes) - return type(box_or_boxes[1]) == "number" and {box_or_boxes} or box_or_boxes -end - -local has_boxes_prop = {collision_box = "walkable", selection_box = "pointable"} - --- Required for raycast box IDs to be accurate -local connect_sides_order = {"top", "bottom", "front", "left", "back", "right"} - -local connect_sides_directions = { - top = vector.new(0, 1, 0), - bottom = vector.new(0, -1, 0), - front = vector.new(0, 0, -1), - left = vector.new(-1, 0, 0), - back = vector.new(0, 0, 1), - right = vector.new(1, 0, 0), -} - ---> list of collisionboxes in Minetest format -local function get_node_boxes(pos, type) - local node = minetest.get_node(pos) - local node_def = minetest.registered_nodes[node.name] - if not node_def or node_def[has_boxes_prop[type]] == false then - return {} - end - local boxes = {{-0.5, -0.5, -0.5, 0.5, 0.5, 0.5}} - local def_node_box = node_def.drawtype == "nodebox" and node_def.node_box - local def_box = node_def[type] or def_node_box -- will evaluate to def_node_box for type = nil - if not def_box then - return boxes -- default to regular box - end - local box_type = def_box.type - if box_type == "regular" then - return boxes - end - local fixed = def_box.fixed - boxes = get_boxes(fixed or {}) - local paramtype2 = node_def.paramtype2 - if box_type == "leveled" then - boxes = table.copy(boxes) - local level = (paramtype2 == "leveled" and node.param2 or node_def.leveled or 0) / 255 - 0.5 - for _, box in ipairs(boxes) do - box[5] = level - end - elseif box_type == "wallmounted" then - local dir = minetest.wallmounted_to_dir((paramtype2 == "colorwallmounted" and node.param2 % 8 or node.param2) or 0) - local box - -- The (undocumented!) node box defaults below are taken from `NodeBox::reset` - if dir.y > 0 then - box = def_box.wall_top or {-0.5, 0.5 - 1/16, -0.5, 0.5, 0.5, 0.5} - elseif dir.y < 0 then - box = def_box.wall_bottom or {-0.5, -0.5, -0.5, 0.5, -0.5 + 1/16, 0.5} - else - box = def_box.wall_side or {-0.5, -0.5, -0.5, -0.5 + 1/16, 0.5, 0.5} - if dir.z > 0 then - box = {box[3], box[2], -box[4], box[6], box[5], -box[1]} - elseif dir.z < 0 then - box = {-box[6], box[2], box[1], -box[3], box[5], box[4]} - elseif dir.x > 0 then - box = {-box[4], box[2], box[3], -box[1], box[5], box[6]} - else - box = {box[1], box[2], -box[6], box[4], box[5], -box[3]} - end - end - return {assert(box, "incomplete wallmounted collisionbox definition of " .. node.name)} - end - if box_type == "connected" then - boxes = table.copy(boxes) - local connect_sides = connect_sides_directions -- (ab)use directions as a "set" of sides - if node_def.connect_sides then -- build set of sides from given list - connect_sides = {} - for _, side in ipairs(node_def.connect_sides) do - connect_sides[side] = true - end - end - local function add_collisionbox(key) - for _, box in ipairs(get_boxes(def_box[key] or {})) do - table.insert(boxes, box) - end - end - local matchers = {} - for i, nodename_or_group in ipairs(node_def.connects_to or {}) do - matchers[i] = nodename_matcher(nodename_or_group) - end - local function connects_to(nodename) - for _, matcher in ipairs(matchers) do - if matcher(nodename) then - return true - end - end - end - local connected, connected_sides - for _, side in ipairs(connect_sides_order) do - if connect_sides[side] then - local direction = connect_sides_directions[side] - local neighbor = minetest.get_node(vector.add(pos, direction)) - local connects = connects_to(neighbor.name) - connected = connected or connects - connected_sides = connected_sides or (side ~= "top" and side ~= "bottom") - add_collisionbox((connects and "connect_" or "disconnected_") .. side) - end - end - if not connected then - add_collisionbox("disconnected") - end - if not connected_sides then - add_collisionbox("disconnected_sides") - end - return boxes - end - if box_type == "fixed" and paramtype2 == "facedir" or paramtype2 == "colorfacedir" then - local param2 = paramtype2 == "colorfacedir" and node.param2 % 32 or node.param2 or 0 - if param2 ~= 0 then - boxes = table.copy(boxes) - local axis = ({5, 6, 3, 4, 1, 2})[math.floor(param2 / 4) + 1] - local other_axis_1, other_axis_2 = (axis % 3) + 1, ((axis + 1) % 3) + 1 - local rotation = (param2 % 4) / 2 * math.pi - local flip = axis > 3 - if flip then axis = axis - 3; rotation = -rotation end - local sin, cos = math.sin(rotation), math.cos(rotation) - if axis == 2 then - sin = -sin - end - for _, box in ipairs(boxes) do - for off = 0, 3, 3 do - local axis_1, axis_2 = other_axis_1 + off, other_axis_2 + off - local value_1, value_2 = box[axis_1], box[axis_2] - box[axis_1] = value_1 * cos - value_2 * sin - box[axis_2] = value_1 * sin + value_2 * cos - end - if not flip then - box[axis], box[axis + 3] = -box[axis + 3], -box[axis] - end - local function fix(coord) - if box[coord] > box[coord + 3] then - box[coord], box[coord + 3] = box[coord + 3], box[coord] - end - end - fix(other_axis_1) - fix(other_axis_2) - end - end - end - return boxes -end - -function _ENV.get_node_boxes(pos) - return get_node_boxes(pos, nil) -end - -function get_node_selectionboxes(pos) - return get_node_boxes(pos, "selection_box") -end - -function get_node_collisionboxes(pos) - return get_node_boxes(pos, "collision_box") -end diff --git a/mods/modlib/minetest/colorspec.lua b/mods/modlib/minetest/colorspec.lua deleted file mode 100644 index 59798df8..00000000 --- a/mods/modlib/minetest/colorspec.lua +++ /dev/null @@ -1,325 +0,0 @@ --- Localize globals -local assert, error, math, minetest, setmetatable, tonumber, type = assert, error, math, minetest, setmetatable, tonumber, type -local floor = math.floor - --- Set environment -local _ENV = ... -setfenv(1, _ENV) - --- As in src/util/string.cpp -named_colors = { - aliceblue = 0xf0f8ff, - antiquewhite = 0xfaebd7, - aqua = 0x00ffff, - aquamarine = 0x7fffd4, - azure = 0xf0ffff, - beige = 0xf5f5dc, - bisque = 0xffe4c4, - black = 0x000000, - blanchedalmond = 0xffebcd, - blue = 0x0000ff, - blueviolet = 0x8a2be2, - brown = 0xa52a2a, - burlywood = 0xdeb887, - cadetblue = 0x5f9ea0, - chartreuse = 0x7fff00, - chocolate = 0xd2691e, - coral = 0xff7f50, - cornflowerblue = 0x6495ed, - cornsilk = 0xfff8dc, - crimson = 0xdc143c, - cyan = 0x00ffff, - darkblue = 0x00008b, - darkcyan = 0x008b8b, - darkgoldenrod = 0xb8860b, - darkgray = 0xa9a9a9, - darkgreen = 0x006400, - darkgrey = 0xa9a9a9, - darkkhaki = 0xbdb76b, - darkmagenta = 0x8b008b, - darkolivegreen = 0x556b2f, - darkorange = 0xff8c00, - darkorchid = 0x9932cc, - darkred = 0x8b0000, - darksalmon = 0xe9967a, - darkseagreen = 0x8fbc8f, - darkslateblue = 0x483d8b, - darkslategray = 0x2f4f4f, - darkslategrey = 0x2f4f4f, - darkturquoise = 0x00ced1, - darkviolet = 0x9400d3, - deeppink = 0xff1493, - deepskyblue = 0x00bfff, - dimgray = 0x696969, - dimgrey = 0x696969, - dodgerblue = 0x1e90ff, - firebrick = 0xb22222, - floralwhite = 0xfffaf0, - forestgreen = 0x228b22, - fuchsia = 0xff00ff, - gainsboro = 0xdcdcdc, - ghostwhite = 0xf8f8ff, - gold = 0xffd700, - goldenrod = 0xdaa520, - gray = 0x808080, - green = 0x008000, - greenyellow = 0xadff2f, - grey = 0x808080, - honeydew = 0xf0fff0, - hotpink = 0xff69b4, - indianred = 0xcd5c5c, - indigo = 0x4b0082, - ivory = 0xfffff0, - khaki = 0xf0e68c, - lavender = 0xe6e6fa, - lavenderblush = 0xfff0f5, - lawngreen = 0x7cfc00, - lemonchiffon = 0xfffacd, - lightblue = 0xadd8e6, - lightcoral = 0xf08080, - lightcyan = 0xe0ffff, - lightgoldenrodyellow = 0xfafad2, - lightgray = 0xd3d3d3, - lightgreen = 0x90ee90, - lightgrey = 0xd3d3d3, - lightpink = 0xffb6c1, - lightsalmon = 0xffa07a, - lightseagreen = 0x20b2aa, - lightskyblue = 0x87cefa, - lightslategray = 0x778899, - lightslategrey = 0x778899, - lightsteelblue = 0xb0c4de, - lightyellow = 0xffffe0, - lime = 0x00ff00, - limegreen = 0x32cd32, - linen = 0xfaf0e6, - magenta = 0xff00ff, - maroon = 0x800000, - mediumaquamarine = 0x66cdaa, - mediumblue = 0x0000cd, - mediumorchid = 0xba55d3, - mediumpurple = 0x9370db, - mediumseagreen = 0x3cb371, - mediumslateblue = 0x7b68ee, - mediumspringgreen = 0x00fa9a, - mediumturquoise = 0x48d1cc, - mediumvioletred = 0xc71585, - midnightblue = 0x191970, - mintcream = 0xf5fffa, - mistyrose = 0xffe4e1, - moccasin = 0xffe4b5, - navajowhite = 0xffdead, - navy = 0x000080, - oldlace = 0xfdf5e6, - olive = 0x808000, - olivedrab = 0x6b8e23, - orange = 0xffa500, - orangered = 0xff4500, - orchid = 0xda70d6, - palegoldenrod = 0xeee8aa, - palegreen = 0x98fb98, - paleturquoise = 0xafeeee, - palevioletred = 0xdb7093, - papayawhip = 0xffefd5, - peachpuff = 0xffdab9, - peru = 0xcd853f, - pink = 0xffc0cb, - plum = 0xdda0dd, - powderblue = 0xb0e0e6, - purple = 0x800080, - rebeccapurple = 0x663399, - red = 0xff0000, - rosybrown = 0xbc8f8f, - royalblue = 0x4169e1, - saddlebrown = 0x8b4513, - salmon = 0xfa8072, - sandybrown = 0xf4a460, - seagreen = 0x2e8b57, - seashell = 0xfff5ee, - sienna = 0xa0522d, - silver = 0xc0c0c0, - skyblue = 0x87ceeb, - slateblue = 0x6a5acd, - slategray = 0x708090, - slategrey = 0x708090, - snow = 0xfffafa, - springgreen = 0x00ff7f, - steelblue = 0x4682b4, - tan = 0xd2b48c, - teal = 0x008080, - thistle = 0xd8bfd8, - tomato = 0xff6347, - turquoise = 0x40e0d0, - violet = 0xee82ee, - wheat = 0xf5deb3, - white = 0xffffff, - whitesmoke = 0xf5f5f5, - yellow = 0xffff00, - yellowgreen = 0x9acd32 -} - -colorspec = {} - -local metatable = {__index = colorspec} -colorspec.metatable = metatable - -function colorspec.new(table) - return setmetatable({ - r = assert(table.r), - g = assert(table.g), - b = assert(table.b), - a = table.a or 255 - }, metatable) -end - -colorspec.from_table = colorspec.new - -local c_comp = { "r", "g", "g", "b", "b", "r" } -local x_comp = { "g", "r", "b", "g", "r", "b" } -function colorspec.from_hsv( - -- 0 (inclusive) to 1 (exclusive) - hue, - -- 0 to 1 (both inclusive) - saturation, - -- 0 to 1 (both inclusive) - value -) - hue = hue * 6 - local chroma = saturation * value - local m = value - chroma - local color = {r = m, g = m, b = m} - local idx = 1 + floor(hue) - color[c_comp[idx]] = color[c_comp[idx]] + chroma - local x = chroma * (1 - math.abs(hue % 2 - 1)) - color[x_comp[idx]] = color[x_comp[idx]] + x - color.r = floor(color.r * 255 + 0.5) - color.g = floor(color.g * 255 + 0.5) - color.b = floor(color.b * 255 + 0.5) - return colorspec.from_table(color) -end - -function colorspec.from_string(string) - string = string:lower() -- names and hex are case-insensitive - local number, alpha = named_colors[string], 0xFF - if not number then - local name, alpha_text = string:match("^([a-z]+)#(%x+)$") - if name then - if alpha_text:len() > 2 then - return - end - number = named_colors[name] - if not number then - return - end - alpha = tonumber(alpha_text, 0x10) - if alpha_text:len() == 1 then - alpha = alpha * 0x11 - end - end - end - if number then - return colorspec.from_number_rgba(number * 0x100 + alpha) - end - local hex_text = string:match("^#(%x+)$") - if not hex_text then - return - end - local len, num = hex_text:len(), tonumber(hex_text, 0x10) - if len == 8 then - return colorspec.from_number_rgba(num) - end - if len == 6 then - return colorspec.from_number_rgba(num * 0x100 + 0xFF) - end - if len == 4 then - return colorspec.from_table{ - a = (num % 0x10) * 0x11, - b = (floor(num / 0x10) % 0x10) * 0x11, - g = (floor(num / (0x100)) % 0x10) * 0x11, - r = (floor(num / (0x1000)) % 0x10) * 0x11 - } - end - if len == 3 then - return colorspec.from_table{ - b = (num % 0x10) * 0x11, - g = (floor(num / 0x10) % 0x10) * 0x11, - r = (floor(num / (0x100)) % 0x10) * 0x11 - } - end -end - -colorspec.from_text = colorspec.from_string - -function colorspec.from_number_rgba(number) - return colorspec.from_table{ - a = number % 0x100, - b = floor(number / 0x100) % 0x100, - g = floor(number / 0x10000) % 0x100, - r = floor(number / 0x1000000) - } -end - -function colorspec.from_number_rgb(number) - return colorspec.from_table{ - a = 0xFF, - b = number % 0x100, - g = floor(number / 0x100) % 0x100, - r = floor(number / 0x10000) - } -end - -function colorspec.from_number(number) - return colorspec.from_table{ - b = number % 0x100, - g = floor(number / 0x100) % 0x100, - r = floor(number / 0x10000) % 0x100, - a = floor(number / 0x1000000) - } -end - -function colorspec.from_any(value) - local type = type(value) - if type == "table" then - return colorspec.from_table(value) - end - if type == "string" then - return colorspec.from_string(value) - end - if type == "number" then - return colorspec.from_number(value) - end - error("Unsupported type " .. type) -end - -function colorspec:to_table() - return self -end - ---> hex string, omits alpha if possible (if opaque) -function colorspec:to_string() - if self.a == 255 then - return ("#%02X%02X%02X"):format(self.r, self.g, self.b) - end - return ("#%02X%02X%02X%02X"):format(self.r, self.g, self.b, self.a) -end -metatable.__tostring = colorspec.to_string - -function colorspec:to_number_rgba() - return self.r * 0x1000000 + self.g * 0x10000 + self.b * 0x100 + self.a -end - -function colorspec:to_number_rgb() - return self.r * 0x10000 + self.g * 0x100 + self.b -end - -function colorspec:to_number() - return self.a * 0x1000000 + self.r * 0x10000 + self.g * 0x100 + self.b -end - -colorspec_to_colorstring = minetest.colorspec_to_colorstring or function(spec) - local color = colorspec.from_any(spec) - if not color then - return nil - end - return color:to_string() -end diff --git a/mods/modlib/minetest/gametime.lua b/mods/modlib/minetest/gametime.lua deleted file mode 100644 index ebe44aa8..00000000 --- a/mods/modlib/minetest/gametime.lua +++ /dev/null @@ -1,16 +0,0 @@ -local gametime -minetest.register_globalstep(function(dtime) - if gametime then - gametime = gametime + dtime - return - end - gametime = assert(minetest.get_gametime()) - function modlib.minetest.get_gametime() - local imprecise_gametime = minetest.get_gametime() - if imprecise_gametime > gametime then - minetest.log("warning", "modlib.minetest.get_gametime(): Called after increment and before first globalstep") - return imprecise_gametime - end - return gametime - end -end) \ No newline at end of file diff --git a/mods/modlib/minetest/liquid.lua b/mods/modlib/minetest/liquid.lua deleted file mode 100644 index 3e956f72..00000000 --- a/mods/modlib/minetest/liquid.lua +++ /dev/null @@ -1,122 +0,0 @@ --- Localize globals -local math, minetest, modlib, pairs = math, minetest, modlib, pairs - --- Set environment -local _ENV = ... -setfenv(1, _ENV) - -liquid_level_max = 8 ---+ Calculates the corner levels of a flowingliquid node ---> 4 corner levels from -0.5 to 0.5 as list of `modlib.vector` -function get_liquid_corner_levels(pos) - local node = minetest.get_node(pos) - local def = minetest.registered_nodes[node.name] - local source, flowing = def.liquid_alternative_source, node.name - local range = def.liquid_range or liquid_level_max - local neighbors = {} - for x = -1, 1 do - neighbors[x] = {} - for z = -1, 1 do - local neighbor_pos = {x = pos.x + x, y = pos.y, z = pos.z + z} - local neighbor_node = minetest.get_node(neighbor_pos) - local level - if neighbor_node.name == source then - level = 1 - elseif neighbor_node.name == flowing then - local neighbor_level = neighbor_node.param2 % 8 - level = (math.max(0, neighbor_level - liquid_level_max + range) + 0.5) / range - end - neighbor_pos.y = neighbor_pos.y + 1 - local node_above = minetest.get_node(neighbor_pos) - neighbors[x][z] = { - air = neighbor_node.name == "air", - level = level, - above_is_same_liquid = node_above.name == flowing or node_above.name == source - } - end - end - local function get_corner_level(x, z) - local air_neighbor - local levels = 0 - local neighbor_count = 0 - for nx = x - 1, x do - for nz = z - 1, z do - local neighbor = neighbors[nx][nz] - if neighbor.above_is_same_liquid then - return 1 - end - local level = neighbor.level - if level then - if level == 1 then - return 1 - end - levels = levels + level - neighbor_count = neighbor_count + 1 - elseif neighbor.air then - if air_neighbor then - return 0.02 - end - air_neighbor = true - end - end - end - if neighbor_count == 0 then - return 0 - end - return levels / neighbor_count - end - local corner_levels = { - {0, nil, 0}, - {1, nil, 0}, - {1, nil, 1}, - {0, nil, 1} - } - for index, corner_level in pairs(corner_levels) do - corner_level[2] = get_corner_level(corner_level[1], corner_level[3]) - corner_levels[index] = modlib.vector.subtract_scalar(modlib.vector.new(corner_level), 0.5) - end - return corner_levels -end - -flowing_downwards = modlib.vector.new{0, -1, 0} ---+ Calculates the flow direction of a flowingliquid node ---> `modlib.minetest.flowing_downwards = modlib.vector.new{0, -1, 0}` if only flowing downwards ---> surface direction as `modlib.vector` else -function get_liquid_flow_direction(pos) - local corner_levels = get_liquid_corner_levels(pos) - local max_level = corner_levels[1][2] - for index = 2, 4 do - local level = corner_levels[index][2] - if level > max_level then - max_level = level - end - end - local dir = modlib.vector.new{0, 0, 0} - local count = 0 - for max_level_index, corner_level in pairs(corner_levels) do - if corner_level[2] == max_level then - for offset = 1, 3 do - local index = (max_level_index + offset - 1) % 4 + 1 - local diff = corner_level - corner_levels[index] - if diff[2] ~= 0 then - diff[1] = diff[1] * diff[2] - diff[3] = diff[3] * diff[2] - if offset == 3 then - diff = modlib.vector.divide_scalar(diff, math.sqrt(2)) - end - dir = dir + diff - count = count + 1 - end - end - end - end - if count ~= 0 then - dir = modlib.vector.divide_scalar(dir, count) - end - if dir == modlib.vector.new{0, 0, 0} then - if minetest.get_node(pos).param2 % 32 > 7 then - return flowing_downwards - end - end - return dir -end \ No newline at end of file diff --git a/mods/modlib/minetest/luon.lua b/mods/modlib/minetest/luon.lua deleted file mode 100644 index c44889f4..00000000 --- a/mods/modlib/minetest/luon.lua +++ /dev/null @@ -1,29 +0,0 @@ --- Localize globals -local getmetatable, AreaStore, ItemStack - = getmetatable, AreaStore, ItemStack - --- Metatable lookup for classes specified in lua_api.txt, section "Class reference" -local AreaStoreMT = getmetatable(AreaStore()) -local ItemStackMT = getmetatable(ItemStack"") -local metatables = { - [AreaStoreMT] = {name = "AreaStore", method = AreaStoreMT.to_string}, - [ItemStackMT] = {name = "ItemStack", method = ItemStackMT.to_table}, - -- TODO expand -} - -return modlib.luon.new{ - aux_write = function(_, value) - local type = metatables[getmetatable(value)] - if type then - return type.name, type.method(value) - end - end, - aux_read = { - AreaStore = function(...) - local store = AreaStore() - store:from_string(...) - return store - end, - ItemStack = ItemStack - } -} \ No newline at end of file diff --git a/mods/modlib/minetest/media.lua b/mods/modlib/minetest/media.lua deleted file mode 100644 index bdca19ab..00000000 --- a/mods/modlib/minetest/media.lua +++ /dev/null @@ -1,61 +0,0 @@ -local minetest, modlib, pairs, ipairs - = minetest, modlib, pairs, ipairs - --- TODO support for server texture packs (and possibly client TPs in singleplayer?) -local media_foldernames = {"textures", "sounds", "media", "models", "locale"} -local media_extensions = modlib.table.set{ - -- Textures - "png", "jpg", "bmp", "tga", "pcx", "ppm", "psd", "wal", "rgb"; - -- Sounds - "ogg"; - -- Models - "x", "b3d", "md2", "obj"; - -- Translations - "tr"; -} - -local function collect_media(modname) - local media = {} - local function traverse(folderpath) - -- Traverse files (collect media) - local filenames = minetest.get_dir_list(folderpath, false) - for _, filename in pairs(filenames) do - local _, ext = modlib.file.get_extension(filename) - if media_extensions[ext] then - media[filename] = modlib.file.concat_path{folderpath, filename} - end - end - -- Traverse subfolders - local foldernames = minetest.get_dir_list(folderpath, true) - for _, foldername in pairs(foldernames) do - if not foldername:match"^[_%.]" then -- ignore hidden subfolders / subfolders starting with `_` - traverse(modlib.file.concat_path{folderpath, foldername}) - end - end - end - for _, foldername in ipairs(media_foldernames) do -- order matters! - traverse(modlib.mod.get_resource(modname, foldername)) - end - return media -end - --- TODO clean this up eventually -local paths = {} -local mods = {} -local overridden_paths = {} -local overridden_mods = {} -for _, mod in ipairs(modlib.minetest.get_mod_load_order()) do - local mod_media = collect_media(mod.name) - for medianame, path in pairs(mod_media) do - if paths[medianame] then - overridden_paths[medianame] = overridden_paths[medianame] or {} - table.insert(overridden_paths[medianame], paths[medianame]) - overridden_mods[medianame] = overridden_mods[medianame] or {} - table.insert(overridden_mods[medianame], mods[medianame]) - end - paths[medianame] = path - mods[medianame] = mod.name - end -end - -return {paths = paths, mods = mods, overridden_paths = overridden_paths, overridden_mods = overridden_mods} diff --git a/mods/modlib/minetest/misc.lua b/mods/modlib/minetest/misc.lua deleted file mode 100644 index 3cd4b579..00000000 --- a/mods/modlib/minetest/misc.lua +++ /dev/null @@ -1,328 +0,0 @@ --- Localize globals -local Settings, assert, minetest, modlib, next, pairs, ipairs, string, setmetatable, select, table, type, unpack - = Settings, assert, minetest, modlib, next, pairs, ipairs, string, setmetatable, select, table, type, unpack - --- Set environment -local _ENV = ... -setfenv(1, _ENV) - -max_wear = 2 ^ 16 - 1 - -function override(function_name, function_builder) - local func = minetest[function_name] - minetest["original_" .. function_name] = func - minetest[function_name] = function_builder(func) -end - -local jobs = modlib.heap.new(function(a, b) - return a.time < b.time -end) -local job_metatable = { - __index = { - -- TODO (...) proper (instant rather than deferred) cancellation: - -- Keep index [job] = index, swap with last element and heapify - cancel = function(self) - self.cancelled = true - end - } -} -local time = 0 -function after(seconds, func, ...) - local job = setmetatable({ - time = time + seconds, - func = func, - ["#"] = select("#", ...), - ... - }, job_metatable) - jobs:push(job) - return job -end -minetest.register_globalstep(function(dtime) - time = time + dtime - local job = jobs[1] - while job and job.time <= time do - if not job.cancelled then - job.func(unpack(job, 1, job["#"])) - end - jobs:pop() - job = jobs[1] - end -end) - -function register_globalstep(interval, callback) - if type(callback) ~= "function" then - return - end - local time = 0 - minetest.register_globalstep(function(dtime) - time = time + dtime - if time >= interval then - callback(time) - -- TODO ensure this breaks nothing - time = time % interval - end - end) -end - -form_listeners = {} - -function register_form_listener(formname, func) - local current_listeners = form_listeners[formname] or {} - table.insert(current_listeners, func) - form_listeners[formname] = current_listeners -end - -local icall = modlib.table.icall -minetest.register_on_player_receive_fields(function(player, formname, fields) - icall(form_listeners[formname] or {}, player, fields) -end) - -function texture_modifier_inventorycube(face_1, face_2, face_3) - return "[inventorycube{" .. string.gsub(face_1, "%^", "&") - .. "{" .. string.gsub(face_2, "%^", "&") - .. "{" .. string.gsub(face_3, "%^", "&") -end -function get_node_inventory_image(nodename) - local n = minetest.registered_nodes[nodename] - if not n then - return - end - local tiles = {} - for l, tile in pairs(n.tiles or {}) do - tiles[l] = (type(tile) == "string" and tile) or tile.name - end - local chosen_tiles = { tiles[1], tiles[3], tiles[5] } - if #chosen_tiles == 0 then - return false - end - if not chosen_tiles[2] then - chosen_tiles[2] = chosen_tiles[1] - end - if not chosen_tiles[3] then - chosen_tiles[3] = chosen_tiles[2] - end - local img = minetest.registered_items[nodename].inventory_image - if string.len(img) == 0 then - img = nil - end - return img or texture_modifier_inventorycube(chosen_tiles[1], chosen_tiles[2], chosen_tiles[3]) -end -function check_player_privs(playername, privtable) - local privs=minetest.get_player_privs(playername) - local missing_privs={} - local to_lose_privs={} - for priv, expected_value in pairs(privtable) do - local actual_value=privs[priv] - if expected_value then - if not actual_value then - table.insert(missing_privs, priv) - end - else - if actual_value then - table.insert(to_lose_privs, priv) - end - end - end - return missing_privs, to_lose_privs -end - ---+ Improved base64 decode removing valid padding -function decode_base64(base64) - local len = base64:len() - local padding_char = base64:sub(len, len) == "=" - if padding_char then - if len % 4 ~= 0 then - return - end - if base64:sub(len-1, len-1) == "=" then - base64 = base64:sub(1, len-2) - else - base64 = base64:sub(1, len-1) - end - end - return minetest.decode_base64(base64) -end - -local object_refs = minetest.object_refs ---+ Objects inside radius iterator. Uses a linear search. -function objects_inside_radius(pos, radius) - radius = radius^2 - local id, object, object_pos - return function() - repeat - id, object = next(object_refs, id) - object_pos = object:get_pos() - until (not object) or ((pos.x-object_pos.x)^2 + (pos.y-object_pos.y)^2 + (pos.z-object_pos.z)^2) <= radius - return object - end -end - ---+ Objects inside area iterator. Uses a linear search. -function objects_inside_area(min, max) - local id, object, object_pos - return function() - repeat - id, object = next(object_refs, id) - object_pos = object:get_pos() - until (not object) or ( - (min.x <= object_pos.x and min.y <= object_pos.y and min.z <= object_pos.z) - and - (max.y >= object_pos.x and max.y >= object_pos.y and max.z >= object_pos.z) - ) - return object - end -end - ---: node_or_groupname "modname:nodename", "group:groupname[,groupname]" ---> function(nodename) -> whether node matches -function nodename_matcher(node_or_groupname) - if modlib.text.starts_with(node_or_groupname, "group:") then - local groups = modlib.text.split(node_or_groupname:sub(("group:"):len() + 1), ",") - return function(nodename) - for _, groupname in pairs(groups) do - if minetest.get_item_group(nodename, groupname) == 0 then - return false - end - end - return true - end - else - return function(nodename) - return nodename == node_or_groupname - end - end -end - -do - local default_create, default_free = function() return {} end, modlib.func.no_op - local metatable = {__index = function(self, player) - if type(player) == "userdata" then - return self[player:get_player_name()] - end - end} - function playerdata(create, free) - create = create or default_create - free = free or default_free - local data = {} - minetest.register_on_joinplayer(function(player) - data[player:get_player_name()] = create(player) - end) - minetest.register_on_leaveplayer(function(player) - data[player:get_player_name()] = free(player) - end) - setmetatable(data, metatable) - return data - end -end - -function connected_players() - -- TODO cache connected players - local connected_players = minetest.get_connected_players() - local index = 0 - return function() - index = index + 1 - return connected_players[index] - end -end - -function set_privs(name, priv_updates) - local privs = minetest.get_player_privs(name) - for priv, grant in pairs(priv_updates) do - if grant then - privs[priv] = true - else - -- May not be set to false; Minetest treats false as truthy in this instance - privs[priv] = nil - end - end - return minetest.set_player_privs(name, privs) -end - -function register_on_leaveplayer(func) - return minetest["register_on_" .. (minetest.is_singleplayer() and "shutdown" or "leaveplayer")](func) -end - -do local mod_info -function get_mod_info() - if mod_info then return mod_info end - mod_info = {} - -- TODO validate modnames - local modnames = minetest.get_modnames() - for _, mod in pairs(modnames) do - local info - local function read_file(filename) - return modlib.file.read(modlib.mod.get_resource(mod, filename)) - end - local mod_conf = Settings(modlib.mod.get_resource(mod, "mod.conf")) - if mod_conf then - info = {} - mod_conf = mod_conf:to_table() - local function read_depends(field) - local depends = {} - for depend in (mod_conf[field] or ""):gmatch"[^,]+" do - depends[modlib.text.trim_spacing(depend)] = true - end - info[field] = depends - end - read_depends"depends" - read_depends"optional_depends" - else - info = { - description = read_file"description.txt", - depends = {}, - optional_depends = {} - } - local depends_txt = read_file"depends.txt" - if depends_txt then - for _, dependency in ipairs(modlib.table.map(modlib.text.split(depends_txt or "", "\n"), modlib.text.trim_spacing)) do - local modname, is_optional = dependency:match"(.+)(%??)" - table.insert(is_optional == "" and info.depends or info.optional_depends, modname) - end - end - end - if info.name == nil then - info.name = mod - end - mod_info[mod] = info - end - return mod_info -end end - -do local mod_load_order -function get_mod_load_order() - if mod_load_order then return mod_load_order end - mod_load_order = {} - local mod_info = get_mod_info() - -- If there are circular soft dependencies, it is possible that a mod is loaded, but not in the right order - -- TODO somehow maximize the number of soft dependencies fulfilled in case of circular soft dependencies - local function load(mod) - if mod.status == "loaded" then - return true - end - if mod.status == "loading" then - return false - end - -- TODO soft/vs hard loading status, reset? - mod.status = "loading" - -- Try hard dependencies first. These must be fulfilled. - for depend in pairs(mod.depends) do - if not load(mod_info[depend]) then - return false - end - end - -- Now, try soft dependencies. - for depend in pairs(mod.optional_depends) do - -- Mod may not exist - if mod_info[depend] then - load(mod_info[depend]) - end - end - mod.status = "loaded" - table.insert(mod_load_order, mod) - return true - end - for _, mod in pairs(mod_info) do - assert(load(mod)) - end - return mod_load_order -end end diff --git a/mods/modlib/minetest/mod.lua b/mods/modlib/minetest/mod.lua deleted file mode 100644 index a321e530..00000000 --- a/mods/modlib/minetest/mod.lua +++ /dev/null @@ -1,184 +0,0 @@ --- Localize globals -local Settings, _G, assert, dofile, error, getmetatable, ipairs, loadfile, loadstring, minetest, modlib, pairs, rawget, rawset, setfenv, setmetatable, tonumber, type, table_concat, unpack - = Settings, _G, assert, dofile, error, getmetatable, ipairs, loadfile, loadstring, minetest, modlib, pairs, rawget, rawset, setfenv, setmetatable, tonumber, type, table.concat, unpack - --- Set environment -local _ENV = {} -setfenv(1, _ENV) - -local loaded = {} -function require(filename) - local modname = minetest.get_current_modname() - loaded[modname] = loaded[modname] or {} - -- Minetest ensures that `/` works even on Windows (path normalization) - loaded[modname][filename] = loaded[modname][filename] -- already loaded? - or dofile(minetest.get_modpath(modname) .. "/" .. filename:gsub("%.", "/") .. ".lua") - return loaded[modname][filename] -end - -function loadfile_exports(filename) - local env = setmetatable({}, {__index = _G}) - local file = assert(loadfile(filename)) - setfenv(file, env) - file() - return env -end - --- get resource + dofile -function include(modname, file) - if not file then - file = modname - modname = minetest.get_current_modname() - end - return dofile(get_resource(modname, file)) -end - -function include_env(file_or_string, env, is_string) - setfenv(assert((is_string and loadstring or loadfile)(file_or_string)), env)() -end - -function create_namespace(namespace_name, parent_namespace) - namespace_name = namespace_name or minetest.get_current_modname() - parent_namespace = parent_namespace or _G - local metatable = {__index = parent_namespace == _G and function(_, key) return rawget(_G, key) end or parent_namespace} - local namespace = {} - namespace = setmetatable(namespace, metatable) - if parent_namespace == _G then - rawset(parent_namespace, namespace_name, namespace) - else - parent_namespace[namespace_name] = namespace - end - return namespace -end - --- formerly extend_mod -function extend(modname, file) - if not file then - file = modname - modname = minetest.get_current_modname() - end - include_env(get_resource(modname, file .. ".lua"), rawget(_G, modname)) -end - --- runs main.lua in table env --- formerly include_mod -function init(modname) - modname = modname or minetest.get_current_modname() - create_namespace(modname) - extend(modname, "main") -end - --- TODO `require` relative to current mod - -local warn_parent_leaf = "modlib: setting %s used both as parent setting and as leaf, ignoring children" -local function build_tree(dict) - local tree = {} - for key, value in pairs(dict) do - local path = modlib.text.split_unlimited(key, ".", true) - local subtree = tree - for i = 1, #path - 1 do - local index = tonumber(path[i]) or path[i] - subtree[index] = subtree[index] or {} - subtree = subtree[index] - if type(subtree) ~= "table" then - minetest.log("warning", warn_parent_leaf:format(table_concat({unpack(path, 1, i)}, "."))) - break - end - end - if type(subtree) == "table" then - if type(subtree[path[#path]]) == "table" then - minetest.log("warning", warn_parent_leaf:format(key)) - end - subtree[path[#path]] = value - end - end - return tree -end - -settings = build_tree(minetest.settings:to_table()) - ---> conf, schema -function configuration(modname) - modname = modname or minetest.get_current_modname() - local schema = modlib.schema.new(assert(include(modname, "schema.lua"))) - schema.name = schema.name or modname - local settingtypes = schema:generate_settingtypes() - assert(schema.type == "table") - local overrides = {} - local conf - local function add(path) - for _, format in ipairs{ - {extension = "lua", read = function(text) - assert(overrides._C == nil) - local additions = setfenv(assert(loadstring(text)), setmetatable(overrides, {__index = {_C = overrides}}))() - setmetatable(overrides, nil) - if additions == nil then - return overrides - end - return additions - end}, - {extension = "luon", read = function(text) - local value = {setfenv(assert(loadstring("return " .. text)), setmetatable(overrides, {}))()} - assert(#value == 1) - value = value[1] - local function check_type(value) - local type = type(value) - if type == "table" then - assert(getmetatable(value) == nil) - for key, value in pairs(value) do - check_type(key) - check_type(value) - end - elseif not (type == "boolean" or type == "number" or type == "string") then - error("disallowed type " .. type) - end - end - check_type(value) - return value - end}, - {extension = "conf", read = function(text) - return build_tree(Settings(text):to_table()) - end, convert_strings = true}, - {extension = "json", read = minetest.parse_json} - } do - local content = modlib.file.read(path .. "." .. format.extension) - if content then - overrides = modlib.table.deep_add_all(overrides, format.read(content)) - conf = schema:load(overrides, {convert_strings = format.convert_strings, error_message = true}) - end - end - end - add(minetest.get_worldpath() .. "/conf/" .. modname) - add(get_resource(modname, "conf")) - local minetest_conf = settings[schema.name] - if minetest_conf then - overrides = modlib.table.deep_add_all(overrides, minetest_conf) - conf = schema:load(overrides, {convert_strings = true, error_message = true}) - end - modlib.file.ensure_content(get_resource(modname, "settingtypes.txt"), settingtypes) - local readme_path = get_resource(modname, "Readme.md") - local readme = modlib.file.read(readme_path) - if readme then - local modified = false - readme = readme:gsub("" .. "(.-)" .. "", function(level, content) - schema._md_level = assert(tonumber(level)) + 1 - -- HACK: Newline between comment and heading (MD implementations don't handle comments properly) - local markdown = "\n" .. schema:generate_markdown() - if content ~= markdown then - modified = true - return "" .. markdown .. "" - end - end, 1) - if modified then - -- FIXME mod security messes with this (disallows it if enabled) - assert(modlib.file.write(readme_path, readme)) - end - end - if conf == nil then - return schema:load({}, {error_message = true}), schema - end - return conf, schema -end - --- Export environment -return _ENV \ No newline at end of file diff --git a/mods/modlib/minetest/obj.lua b/mods/modlib/minetest/obj.lua deleted file mode 100644 index 82665101..00000000 --- a/mods/modlib/minetest/obj.lua +++ /dev/null @@ -1,190 +0,0 @@ -local assert, tonumber, type, setmetatable, ipairs, unpack - = assert, tonumber, type, setmetatable, ipairs, unpack - -local math_floor, table_insert, table_concat - = math.floor, table.insert, table.concat - -local obj = {} - -local metatable = {__index = obj} - -local function read_floats(next_word, n) - if n == 0 then return end - local num = next_word() - assert(num:find"^%-?%d+$" or num:find"^%-?%d+%.%d+$") - return tonumber(num), read_floats(next_word, n - 1) -end - -local function read_index(list, index) - if not index then return end - index = tonumber(index) - if index < 0 then - index = index + #list + 1 - end - assert(list[index]) - return index -end - -local function read_indices(self, next_word) - local word = next_word() - if not word then return end - -- TODO optimize this (ideally using a vararg-ish split by `/`) - local vertex, texcoord, normal - vertex = word:match"^%-?%d+$" - if not vertex then - vertex, texcoord = word:match"^(%-?%d+)/(%-?%d+)$" - if not vertex then - vertex, normal = word:match"^(%-?%d+)//(%-?%d+)$" - if not vertex then - vertex, texcoord, normal = word:match"^(%-?%d+)/(%-?%d+)/(%-?%d+)$" - end - end - end - return { - vertex = read_index(self.vertices, vertex), - texcoord = read_index(self.texcoords, texcoord), - normal = read_index(self.normals, normal) - }, read_indices(self, next_word) -end - -function obj.read_lines( - ... -- line iterator such as `modlib.text.lines"str"` or `io.lines"filename"` -) - local self = { - vertices = {}, - texcoords = {}, - normals = {}, - groups = {} - } - local groups = {} - local active_group = {name = "default"} - groups[1] = active_group - groups.default = active_group - for line in ... do - if line:byte() ~= ("#"):byte() then - local next_word = line:gmatch"%S+" - local command = next_word() - if command == "v" or command == "vn" then - local x, y, z = read_floats(next_word, 3) - x = -x - table_insert(self[command == "v" and "vertices" or "normals"], {x, y, z}) - elseif command == "vt" then - local x, y = read_floats(next_word, 2) - y = 1 - y - table_insert(self.texcoords, {x, y}) - elseif command == "f" then - table_insert(active_group, {read_indices(self, next_word)}) - elseif command == "g" or command == "usemtl" then - -- TODO consider distinguishing between materials & groups - local name = next_word() or "default" - if groups[name] then - active_group = groups[name] - else - active_group = {name = name} - table_insert(groups, active_group) - groups[name] = active_group - end - assert(not next_word(), "only a single group/material name is supported") - end - end - end - -- Keep only nonempty groups - for _, group in ipairs(groups) do - if group[1] ~= nil then - table_insert(self.groups, group) - end - end - return setmetatable(self, metatable) -- obj object -end - --- Does not close a file handle if passed ---> obj object -function obj.read_file(file_or_name) - if type(file_or_name) == "string" then - return obj.read_lines(io.lines(file_or_name)) - end - local handle = file_or_name - -- `handle.read, handle` can be used as a line iterator - return obj.read_lines(assert(handle.read), handle) -end - ---> obj object -function obj.read_string(str) - -- Empty lines can be ignored - return obj.read_lines(str:gmatch"[^\r\n]+") -end - -local function write_float(float) - if math_floor(float) == float then - return ("%d"):format(float) - end - return ("%f"):format(float):match"^(.-)0*$" -- strip trailing zeros -end - -local function write_index(index) - if index.texcoord then - if index.normal then - return("%d/%d/%d"):format(index.vertex, index.texcoord, index.normal) - end - return ("%d/%d"):format(index.vertex, index.texcoord) - end if index.normal then - return ("%d//%d"):format(index.vertex, index.normal) - end - return ("%d"):format(index.vertex) -end - --- Callback/"caller"-style iterator; use `iterator.for_generator` to turn this into a callee-style iterator -function obj:write_lines( - write_line -- function(line: string) to write a line -) - local function write_v3f(type, v3f) - local x, y, z = unpack(v3f) - x = -x - write_line(("%s %s %s %s"):format(type, write_float(x), write_float(y), write_float(z))) - end - for _, vertex in ipairs(self.vertices) do - write_v3f("v", vertex) - end - for _, normal in ipairs(self.normals) do - write_v3f("vn", normal) - end - for _, texcoord in ipairs(self.texcoords) do - local x, y = texcoord[1], texcoord[2] - y = 1 - y - write_line(("vt %s %s"):format(write_float(x), write_float(y))) - end - for _, group in ipairs(self.groups) do - write_line("g " .. group.name) -- this will convert `usemtl` into `g` but that shouldn't matter - for _, face in ipairs(group) do - local command = {"f"} - for i, index in ipairs(face) do - command[i + 1] = write_index(index) - end - write_line(table_concat(command, " ")) - end - end -end - --- Write `self` to a file --- Does not close or flush a file handle if passed -function obj:write_file(file_or_name) - if type(file_or_name) == "string" then - file_or_name = io.open(file_or_name) - end - self:write_lines(function(line) - file_or_name:write(line) - file_or_name:write"\n" - end) -end - --- Write `self` to a string -function obj:write_string() - local rope = {} - self:write_lines(function(line) - table_insert(rope, line) - end) - table_insert(rope, "") -- trailing newline for good measure - return table_concat(rope, "\n") -- string representation of `self` -end - -return obj \ No newline at end of file diff --git a/mods/modlib/minetest/png.lua b/mods/modlib/minetest/png.lua deleted file mode 100644 index bdec662e..00000000 --- a/mods/modlib/minetest/png.lua +++ /dev/null @@ -1,483 +0,0 @@ -local signature = "\137\80\78\71\13\10\26\10" - -local assert, char, ipairs, insert, concat, abs, floor = assert, string.char, ipairs, table.insert, table.concat, math.abs, math.floor - --- TODO move to modlib.bit eventually -local function bit_xor(a, b) - local res = 0 - local bit = 1 - for _ = 1, 32 do - if a % 2 ~= b % 2 then - res = res + bit - end - a = floor(a / 2) - b = floor(b / 2) - bit = bit * 2 - end - return res -end - --- Try to use `bit` library (if available) for a massive speed boost -local bit = rawget(_G, "bit") -if bit then - local bxor = bit.bxor - function bit_xor(a, b) - local res = bxor(a, b) - if res < 0 then -- convert signed to unsigned - return res + 2^32 - end - return res - end -end - -local crc_table = {} -for i = 0, 255 do - local c = i - for _ = 0, 7 do - if c % 2 > 0 then - c = bit_xor(0xEDB88320, floor(c / 2)) - else - c = floor(c / 2) - end - end - crc_table[i] = c -end - -local function update_crc(crc, text) - for i = 1, #text do - crc = bit_xor(crc_table[bit_xor(crc % 0x100, text:byte(i))], floor(crc / 0x100)) - end - return crc -end - - -local color_types = { - [0] = { - color = "grayscale" - }, - [2] = { - color = "truecolor" - }, - [3] = { - color = "palette", - depth = 8 - }, - [4] = { - color = "grayscale", - alpha = true - }, - [6] = { - color = "truecolor", - alpha = true - } -} -local set = modlib.table.set -local allowed_bit_depths = { - [0] = set{1, 2, 4, 8, 16}, - [2] = set{8, 16}, - [3] = set{1, 2, 4, 8}, - [4] = set{8, 16}, - [6] = set{8, 16} -} -local samples = { - grayscale = 1, - palette = 1, - truecolor = 3 -} - -local adam7_passes = { - x_min = { 0, 4, 0, 2, 0, 1, 0 }, - y_min = { 0, 0, 4, 0, 2, 0, 1 }, - x_step = { 8, 8, 4, 4, 2, 2, 1 }, - y_step = { 8, 8, 8, 4, 4, 2, 2 }, -}; - -(...).decode_png = function(stream) - local chunk_crc - local function read(n) - local text = stream:read(n) - assert(#text == n) - if chunk_crc then - chunk_crc = update_crc(chunk_crc, text) - end - return text - end - local function byte() - return read(1):byte() - end - local function _uint() - return 0x1000000 * byte() + 0x10000 * byte() + 0x100 * byte() + byte() - end - local function uint() - local val = _uint() - assert(val < 2^31, "uint out of range") - return val - end - local function check_crc() - local crc = chunk_crc - chunk_crc = nil - if _uint() ~= bit_xor(crc, 0xFFFFFFFF) then - error("CRC mismatch", 2) - end - end - - assert(read(8) == signature, "PNG signature expected") - - local IHDR_len = uint() - assert(IHDR_len == 13, "invalid IHDR length") - chunk_crc = 0xFFFFFFFF - assert(read(4) == "IHDR", "IHDR chunk expected") - local width = uint() - assert(width > 0) - local height = uint() - assert(height > 0) - local bit_depth = byte() - local color_type_number = byte() - local color_type = assert(color_types[color_type_number], "invalid color type") - if color_type.color ~= "palette" then - color_type.depth = bit_depth - end - assert(allowed_bit_depths[color_type_number][bit_depth], "disallowed bit depth for color type") - local compression_method = byte() - assert(compression_method == 0, "unsupported compression method") - local filter_method = byte() - assert(filter_method == 0, "unsupported filter method") - local interlace_method = byte() - assert(interlace_method <= 1, "unsupported interlace method") - local adam7 = interlace_method == 1 - check_crc() -- IHDR CRC - - local palette - local alpha - local source_gamma - local idat_content = {} - local idat_allowed = true - local iend - repeat - local chunk_length = uint() - chunk_crc = 0xFFFFFFFF - local chunk_type = read(4) - if chunk_type == "IDAT" then - assert(idat_allowed, "no chunks inbetween IDAT chunks allowed") - if color_type.color == "palette" then - assert(palette, "PLTE chunk expected") - end - insert(idat_content, read(chunk_length)) - else - if next(idat_content) then - -- Non-IDAT chunk, no IDAT chunks allowed anymore - idat_allowed = false - end - if chunk_type == "PLTE" then - assert(color_type.color ~= "grayscale") - assert(not palette, "double PLTE chunk") - assert(idat_allowed, "PLTE after IDAT chunks") - palette = {} - local entries = chunk_length / 3 - assert(entries % 1 == 0 and entries >= 1 and entries <= 2^bit_depth, "invalid PLTE chunk length") - for i = 1, entries do - palette[i] = 0x10000 * byte() + 0x100 * byte() + byte() -- RGB - end - elseif chunk_type == "tRNS" then - assert(not color_type.alpha, "unexpected tRNS chunk") - color_type.transparency = true - assert(idat_allowed, "tRNS after IDAT chunks") - if color_type.color == "palette" then - assert(palette, "PLTE chunk expected") - alpha = {} - for i = 1, chunk_length do - alpha[i] = byte() - end - elseif color_type.color == "grayscale" then - assert(chunk_length == 2) - alpha = 0x100 * byte() + byte() - else - assert(color_type.color == "truecolor") - assert(chunk_length == 6) - alpha = 0 - -- Read 16-bit RGB (6 bytes) - for _ = 1, 6 do - alpha = alpha * 0x100 + byte() - end - end - elseif chunk_type == "gAMA" then - assert(not palette, "gAMA after PLTE chunk") - assert(idat_allowed, "gAMA after IDAT chunks") - assert(chunk_length == 4) - source_gamma = uint() / 1e5 - elseif chunk_type == "IEND" then - iend = true - else - -- Check whether the fifth bit of the first byte is set (upper vs. lowercase ASCII) - local ancillary = floor(chunk_type:byte(1) % (2^6)) >= 2^5 - if not ancillary then - error(("unsupported critical chunk: %q"):format(chunk_type)) - end - read(chunk_length) - end - end - check_crc() - until iend - assert(next(idat_content), "no IDAT chunk") - idat_content = minetest.decompress(concat(idat_content), "deflate") - --[[ - For memory efficiency, we try to pack everything in a single number: - Grayscale/lightness: AY - Palette: ARGB - Truecolor (8-bit): ARGB - Truecolor (16-bit): RGB + A - (64 bits required, packing non-mantissa bits isn't practical) => separate table with alpha values - ]] - local data = {} - local alpha_data - if color_type.color == "truecolor" and bit_depth == 16 and (color_type.alpha or color_type.transparency) then - alpha_data = {} - end - if adam7 then - -- Allocate space in list part in order to not fill the hash part later - for i = 1, width * height do - data[i] = false - if alpha_data then - alpha_data[i] = false - end - end - end - local bits_per_pixel = (samples[color_type.color] + (color_type.alpha and 1 or 0)) * bit_depth - local bytes_per_pixel = math.ceil(bits_per_pixel / 8) - local previous_scanline - local idat_base_index = 1 - local function read_scanline(x_min, x_step, y) - local scanline_width = math.ceil((width - x_min) / x_step) - local scanline_bytecount = math.ceil(scanline_width * bits_per_pixel / 8) - local filtering = idat_content:byte(idat_base_index) - local scanline = {} - for i = 1, scanline_bytecount do - local val = idat_content:byte(idat_base_index + i) - local left = scanline[i - bytes_per_pixel] or 0 - local up = previous_scanline and previous_scanline[i] or 0 - local left_up = previous_scanline and previous_scanline[i - bytes_per_pixel] or 0 - -- Undo lossless filter - if filtering == 0 then -- None - scanline[i] = val - elseif filtering == 1 then -- Sub - scanline[i] = (left + val) % 0x100 - elseif filtering == 2 then -- Up - scanline[i] = (up + val) % 0x100 - elseif filtering == 3 then -- Average - scanline[i] = (floor((left + up) / 2) + val) % 0x100 - elseif filtering == 4 then -- Paeth - local p = left + up - left_up - local p_left = abs(p - left) - local p_up = abs(p - up) - local p_left_up = abs(p - left_up) - local p_res - if p_left <= p_up and p_left <= p_left_up then - p_res = left - elseif p_up <= p_left_up then - p_res = up - else - p_res = left_up - end - scanline[i] = (p_res + val) % 0x100 - else - error("invalid filtering method: " .. filtering) - end - assert(scanline[i] >= 0 and scanline[i] <= 255 and scanline[i] % 1 == 0) - end - local bit = 0 - local function sample() - local byte_idx = 1 + floor(bit / 8) - bit = bit + bit_depth - local byte = scanline[byte_idx] - if bit_depth == 16 then - return byte * 0x100 + scanline[byte_idx + 1] - end - if bit_depth == 8 then - return byte - end - assert(bit_depth == 1 or bit_depth == 2 or bit_depth == 4) - local low = 2^(-bit % 8) - return floor(byte / low) % (2^bit_depth) - end - for x = x_min, width - 1, x_step do - local data_index = y * width + x + 1 - if color_type.color == "palette" then - local palette_index = sample() - local rgb = assert(palette[palette_index + 1], "palette index out of range") - -- Index alpha table if available - local a = alpha and alpha[palette_index + 1] or 255 - data[data_index] = a * 0x1000000 + rgb - elseif color_type.color == "grayscale" then - local Y = sample() - local a = 2^bit_depth - 1 - if color_type.alpha then - a = sample() - elseif alpha == Y then - a = 0 -- Convert grayscale to transparency - end - data[data_index] = a * (2^bit_depth) + Y - else - assert(color_type.color == "truecolor") - local r, g, b = sample(), sample(), sample() - local rgb16 = r * 0x100000000 + g * 0x10000 + b - local a = 2^bit_depth - 1 - if color_type.alpha then - a = sample() - elseif alpha == rgb16 then - a = 0 -- Convert color to transparency - end - if bit_depth == 8 then - data[data_index] = a * 0x1000000 + r * 0x10000 + g * 0x100 + b - else - assert(bit_depth == 16) - -- Pack only RGB in data, alpha goes in a different table - -- 3 * 16 = 48 bytes can still be held accurately by the double mantissa - data[data_index] = rgb16 - if alpha_data then - alpha_data[data_index] = a - end - end - end - end - -- Each byte of the scanline must have been read from - assert(bit >= #scanline * 8 - 7) - previous_scanline = scanline - idat_base_index = idat_base_index + scanline_bytecount + 1 - end - if adam7 then - for pass = 1, 7 do - local x_min, y_min = adam7_passes.x_min[pass], adam7_passes.y_min[pass] - if x_min < width and y_min < height then -- Non-empty pass - local x_step, y_step = adam7_passes.x_step[pass], adam7_passes.y_step[pass] - previous_scanline = nil -- Filtering doesn't use scanlines of previous passes - for y = y_min, height - 1, y_step do - read_scanline(x_min, x_step, y) - end - end - end - else - for y = 0, height - 1 do - read_scanline(0, 1, y) - end - end - return { - width = width, - height = height, - color_type = color_type, - source_gamma = source_gamma, - data = data, - alpha_data = alpha_data - } -end - -local function rescale_depth(sample, source_depth, target_depth) - if source_depth == target_depth then - return sample - end - return floor((sample * (2^target_depth - 1) / (2^source_depth - 1)) + 0.5) -end --- In-place lossy (if bit depth = 16) conversion to ARGB8 -(...).convert_png_to_argb8 = function(png) - local color, transparency, depth = png.color_type.color, png.color_type.alpha or png.color_type.transparency, png.color_type.depth - if color == "palette" or (color == "truecolor" and depth == 8) then - return - end - for index, value in pairs(png.data) do - if color == "grayscale" then - local a, Y = rescale_depth(floor(value / (2^depth)), depth, 8), rescale_depth(value % (2^depth), depth, 8) - png.data[index] = a * 0x1000000 + Y * 0x10000 + Y * 0x100 + Y -- R = G = B = Y - else - assert(color == "truecolor" and depth == 16) - local r = rescale_depth(floor(value / 0x100000000), depth, 8) - local g = rescale_depth(floor(value / 0x10000) % 0x10000, depth, 8) - local b = rescale_depth(value % 0x10000, depth, 8) - local a = 0xFF - if transparency then - a = rescale_depth(png.alpha_data[index], depth, 8) - end - png.data[index] = a * 0x1000000 + r * 0x10000 + g * 0x100 + b - end - end - png.color_type = color_types[6] - png.bit_depth = 8 - png.alpha_data = nil -end - -local function encode_png(width, height, data, compression, raw_write) - local write = raw_write - local function byte(value) - write(char(value)) - end - local function _uint(value) - local div = 0x1000000 - for _ = 1, 4 do - byte(floor(value / div) % 0x100) - div = div / 0x100 - end - end - local function uint(value) - assert(value < 2^31) - _uint(value) - end - local chunk_content - local function chunk_write(text) - insert(chunk_content, text) - end - local function chunk(type) - chunk_content = {} - write = chunk_write - write(type) - end - local function end_chunk() - write = raw_write - local chunk_len = 0 - for i = 2, #chunk_content do - chunk_len = chunk_len + #chunk_content[i] - end - uint(chunk_len) - write(concat(chunk_content)) - local chunk_crc = 0xFFFFFFFF - for _, text in ipairs(chunk_content) do - chunk_crc = update_crc(chunk_crc, text) - end - _uint(bit_xor(chunk_crc, 0xFFFFFFFF)) - end - -- Signature - write(signature) - chunk"IHDR" - uint(width) - uint(height) - -- Always use bit depth 8 - byte(8) - -- Always use color type "truecolor with alpha" - byte(6) - -- Compression method: deflate - byte(0) - -- Filter method: PNG filters - byte(0) - -- No interlace - byte(0) - end_chunk() - chunk"IDAT" - local data_rope = {} - for y = 0, height - 1 do - local base_index = y * width - insert(data_rope, "\0") - for x = 1, width do - local colorspec = modlib.minetest.colorspec.from_any(data[base_index + x]) - insert(data_rope, char(colorspec.r, colorspec.g, colorspec.b, colorspec.a)) - end - end - write(minetest.compress(type(data) == "string" and data or concat(data_rope), "deflate", compression)) - end_chunk() - chunk"IEND" - end_chunk() -end - -(...).encode_png = minetest.encode_png or function(width, height, data, compression) - local rope = {} - encode_png(width, height, data, compression or 9, function(text) - insert(rope, text) - end) - return concat(rope) -end diff --git a/mods/modlib/minetest/raycast.lua b/mods/modlib/minetest/raycast.lua deleted file mode 100644 index 5c3617c8..00000000 --- a/mods/modlib/minetest/raycast.lua +++ /dev/null @@ -1,137 +0,0 @@ --- Localize globals -local assert, math, minetest, modlib, pairs, setmetatable, vector = assert, math, minetest, modlib, pairs, setmetatable, vector - ---+ Raycast wrapper with proper flowingliquid intersections -return function(_pos1, _pos2, objects, liquids) - local raycast = minetest.raycast(_pos1, _pos2, objects, liquids) - if not liquids then - return raycast - end - local pos1 = modlib.vector.from_minetest(_pos1) - local _direction = vector.direction(_pos1, _pos2) - local direction = modlib.vector.from_minetest(_direction) - local length = vector.distance(_pos1, _pos2) - local function next() - local pointed_thing = raycast:next() - if (not pointed_thing) or pointed_thing.type ~= "node" then - return pointed_thing - end - local _pos = pointed_thing.under - local pos = modlib.vector.from_minetest(_pos) - local node = minetest.get_node(_pos) - local def = minetest.registered_nodes[node.name] - if not (def and def.drawtype == "flowingliquid") then - return pointed_thing - end - local corner_levels = modlib.minetest.get_liquid_corner_levels(_pos) - local full_corner_levels = true - for _, corner_level in pairs(corner_levels) do - if corner_level[2] < 0.5 then - full_corner_levels = false - break - end - end - if full_corner_levels then - return pointed_thing - end - local relative = pos1 - pos - local inside = true - for _, prop in pairs(relative) do - if prop <= -0.5 or prop >= 0.5 then - inside = false - break - end - end - local function level(x, z) - local function distance_squared(corner) - return (x - corner[1]) ^ 2 + (z - corner[3]) ^ 2 - end - local irrelevant_corner, distance = 1, distance_squared(corner_levels[1]) - for index = 2, 4 do - local other_distance = distance_squared(corner_levels[index]) - if other_distance > distance then - irrelevant_corner, distance = index, other_distance - end - end - local function corner(off) - return corner_levels[((irrelevant_corner + off) % 4) + 1] - end - local base = corner(2) - local edge_1, edge_2 = corner(1) - base, corner(3) - base - -- Properly selected edges will have a total length of 2 - assert(math.abs(edge_1[1] + edge_1[3]) + math.abs(edge_2[1] + edge_2[3]) == 2) - if edge_1[1] == 0 then - edge_1, edge_2 = edge_2, edge_1 - end - local level = base[2] + (edge_1[2] * ((x - base[1]) / edge_1[1])) + (edge_2[2] * ((z - base[3]) / edge_2[3])) - assert(level >= -0.5 and level <= 0.5) - return level - end - inside = inside and (relative[2] < level(relative[1], relative[3])) - if inside then - -- pos1 is inside the liquid node - pointed_thing.intersection_point = _pos1 - pointed_thing.intersection_normal = vector.new(0, 0, 0) - return pointed_thing - end - local function intersection_normal(axis, dir) - return {x = 0, y = 0, z = 0, [axis] = dir} - end - local function plane(axis, dir) - local offset = dir * 0.5 - local diff_axis = (relative[axis] - offset) / -direction[axis] - local intersection_point = {} - for plane_axis = 1, 3 do - if plane_axis ~= axis then - local value = direction[plane_axis] * diff_axis + relative[plane_axis] - if value < -0.5 or value > 0.5 then - return - end - intersection_point[plane_axis] = value - end - end - intersection_point[axis] = offset - return intersection_point - end - if direction[2] > 0 then - local intersection_point = plane(2, -1) - if intersection_point then - pointed_thing.intersection_point = (intersection_point + pos):to_minetest() - pointed_thing.intersection_normal = intersection_normal("y", -1) - return pointed_thing - end - end - for coord, other in pairs{[1] = 3, [3] = 1} do - if direction[coord] ~= 0 then - local dir = direction[coord] > 0 and -1 or 1 - local intersection_point = plane(coord, dir) - if intersection_point then - local height = 0 - for _, corner in pairs(corner_levels) do - if corner[coord] == dir * 0.5 then - height = height + (math.abs(intersection_point[other] + corner[other])) * corner[2] - end - end - if intersection_point[2] <= height then - pointed_thing.intersection_point = (intersection_point + pos):to_minetest() - pointed_thing.intersection_normal = intersection_normal(modlib.vector.index_aliases[coord], dir) - return pointed_thing - end - end - end - end - for _, triangle in pairs{ - {corner_levels[3], corner_levels[2], corner_levels[1]}, - {corner_levels[4], corner_levels[3], corner_levels[1]} - } do - local pos_on_ray = modlib.vector.ray_triangle_intersection(relative, direction, triangle) - if pos_on_ray and pos_on_ray <= length then - pointed_thing.intersection_point = (pos1 + modlib.vector.multiply_scalar(direction, pos_on_ray)):to_minetest() - pointed_thing.intersection_normal = modlib.vector.triangle_normal(triangle):to_minetest() - return pointed_thing - end - end - return next() - end - return setmetatable({next = next}, {__call = next}) -end diff --git a/mods/modlib/minetest/schematic.lua b/mods/modlib/minetest/schematic.lua deleted file mode 100644 index eb7815dc..00000000 --- a/mods/modlib/minetest/schematic.lua +++ /dev/null @@ -1,193 +0,0 @@ --- Localize globals -local VoxelArea, ItemStack, assert, error, io, ipairs, math, minetest, modlib, next, pairs, setmetatable, string, table, type, vector - = VoxelArea, ItemStack, assert, error, io, ipairs, math, minetest, modlib, next, pairs, setmetatable, string, table, type, vector - - -local schematic = {} -local metatable = {__index = schematic} - -function schematic.setmetatable(self) - return setmetatable(self, metatable) -end - -function schematic.create(params, pos_min, pos_max) - pos_min, pos_max = vector.sort(pos_min, pos_max) - local size = vector.add(vector.subtract(pos_max, pos_min), 1) - local voxelmanip = minetest.get_voxel_manip(pos_min, pos_max) - local emin, emax = voxelmanip:read_from_map(pos_min, pos_max) - local voxelarea = VoxelArea:new{ MinEdge = emin, MaxEdge = emax } - local nodes, light_values, param2s = {}, params.light_values and {}, {} - local vm_nodes, vm_light_values, vm_param2s = voxelmanip:get_data(), light_values and voxelmanip:get_light_data(), voxelmanip:get_param2_data() - local node_names, node_ids = {}, {} - local i = 0 - for index in voxelarea:iterp(pos_min, pos_max) do - if nodes[index] == minetest.CONTENT_UNKNOWN or nodes[index] == minetest.CONTENT_IGNORE then - error("unknown or ignore node at " .. minetest.pos_to_string(voxelarea:position(index))) - end - local name = minetest.get_name_from_content_id(vm_nodes[index]) - local id = node_ids[name] - if not id then - table.insert(node_names, name) - id = #node_names - node_ids[name] = id - end - i = i + 1 - nodes[i] = id - if params.light_values then - light_values[i] = vm_light_values[index] - end - param2s[i] = vm_param2s[index] - end - local metas - if params.metas or params.metas == nil then - metas = {} - for _, pos in ipairs(minetest.find_nodes_with_meta(pos_min, pos_max)) do - local meta = minetest.get_meta(pos):to_table() - if next(meta.fields) ~= nil or next(meta.inventory) ~= nil then - local relative = vector.subtract(pos, pos_min) - metas[((relative.z * size.y) + relative.y) * size.x + relative.x] = meta - end - end - end - return schematic.setmetatable({ - size = size, - node_names = node_names, - nodes = nodes, - light_values = light_values, - param2s = param2s, - metas = metas, - }) -end - -function schematic:write_to_voxelmanip(voxelmanip, pos_min) - local size = self.size - local pos_max = vector.subtract(vector.add(pos_min, size), 1) -- `pos_max` is inclusive - local emin, emax = voxelmanip:read_from_map(pos_min, pos_max) - local voxelarea = VoxelArea:new{ MinEdge = emin, MaxEdge = emax } - local nodes, light_values, param2s, metas = self.nodes, self.light_values, self.param2s, self.metas - local vm_nodes, vm_lights, vm_param2s = voxelmanip:get_data(), light_values and voxelmanip:get_light_data(), voxelmanip:get_param2_data() - for _, pos in ipairs(minetest.find_nodes_with_meta(pos_min, pos_max)) do - -- Clear all metadata. Due to an engine bug, nodes will actually have empty metadata. - minetest.get_meta(pos):from_table{} - end - local content_ids = {} - for index, name in ipairs(self.node_names) do - content_ids[index] = assert(minetest.get_content_id(name), ("unknown node %q"):format(name)) - end - local i = 0 - for index in voxelarea:iterp(pos_min, pos_max) do - i = i + 1 - vm_nodes[index] = content_ids[nodes[i]] - if light_values then - vm_lights[index] = light_values[i] - end - vm_param2s[index] = param2s[i] - end - voxelmanip:set_data(vm_nodes) - if light_values then - voxelmanip:set_light_data(vm_lights) - end - voxelmanip:set_param2_data(vm_param2s) - if metas then - for index, meta in pairs(metas) do - local floored = math.floor(index / size.x) - local relative = { - x = index % size.x, - y = floored % size.y, - z = math.floor(floored / size.y) - } - minetest.get_meta(vector.add(relative, pos_min)):from_table(meta) - end - end -end - -function schematic:place(pos_min) - local pos_max = vector.subtract(vector.add(pos_min, self.size), 1) -- `pos_max` is inclusive - local voxelmanip = minetest.get_voxel_manip(pos_min, pos_max) - self:write_to_voxelmanip(voxelmanip, pos_min) - voxelmanip:write_to_map(not self.light_values) - return voxelmanip -end - -local function table_to_byte_string(tab) - if not tab then return end - return table.concat(modlib.table.map(tab, string.char)) -end - -local function write_bluon(self, stream) - local metas = modlib.table.copy(self.metas) - for _, meta in pairs(metas) do - for _, list in pairs(meta.inventory) do - for index, stack in pairs(list) do - list[index] = stack:to_string() - end - end - end - modlib.bluon:write({ - size = self.size, - node_names = self.node_names, - nodes = self.nodes, - light_values = table_to_byte_string(self.light_values), - param2s = table_to_byte_string(self.param2s), - metas = metas, - }, stream) -end - -function schematic:write_bluon(path) - local file = io.open(path, "wb") - -- Header, short for "ModLib Bluon Schematic" - file:write"MLBS" - write_bluon(self, file) - file:close() -end - -local function byte_string_to_table(self, field) - local byte_string = self[field] - if not byte_string then return end - local tab = {} - for i = 1, #byte_string do - tab[i] = byte_string:byte(i) - end - self[field] = tab -end - -local function read_bluon(file) - local self = modlib.bluon:read(file) - assert(not file:read(1), "expected EOF") - for _, meta in pairs(self.metas) do - for _, list in pairs(meta.inventory) do - for index, itemstring in pairs(list) do - assert(type(itemstring) == "string") - list[index] = ItemStack(itemstring) - end - end - end - byte_string_to_table(self, "light_values") - byte_string_to_table(self, "param2s") - return self -end - -function schematic.read_bluon(path) - local file = io.open(path, "rb") - assert(file:read(4) == "MLBS", "not a modlib bluon schematic") - return schematic.setmetatable(read_bluon(file)) -end - -function schematic:write_zlib_bluon(path, compression) - local file = io.open(path, "wb") - -- Header, short for "ModLib Zlib-compressed-bluon Schematic" - file:write"MLZS" - local rope = modlib.table.rope{} - write_bluon(self, rope) - local text = rope:to_text() - file:write(minetest.compress(text, "deflate", compression or 9)) - file:close() -end - -function schematic.read_zlib_bluon(path) - local file = io.open(path, "rb") - assert(file:read(4) == "MLZS", "not a modlib zlib compressed bluon schematic") - return schematic.setmetatable(read_bluon(modlib.text.inputstream(minetest.decompress(file:read"*a", "deflate")))) -end - -return schematic diff --git a/mods/modlib/minetest/texmod.lua b/mods/modlib/minetest/texmod.lua deleted file mode 100644 index 6553b6e6..00000000 --- a/mods/modlib/minetest/texmod.lua +++ /dev/null @@ -1,30 +0,0 @@ --- Texture Modifier representation for building, parsing and stringifying texture modifiers according to --- https://github.com/minetest/minetest_docs/blob/master/doc/texture_modifiers.adoc - -local function component(component_name, ...) - return assert(loadfile(modlib.mod.get_resource(modlib.modname, "minetest", "texmod", component_name .. ".lua")))(...) -end - -local texmod, metatable = component"dsl" -local methods = metatable.__index -methods.write = component"write" -texmod.read = component("read", texmod) -methods.calc_dims = component"calc_dims" -methods.gen_tex = component"gen_tex" - -function metatable:__tostring() - local rope = {} - self:write(function(str) rope[#rope+1] = str end) - return table.concat(rope) -end - -function texmod.read_string(str, warn --[[function(warn_str)]]) - local i = 0 - return texmod.read(function() - i = i + 1 - if i > #str then return end - return str:sub(i, i) - end, warn) -end - -return texmod diff --git a/mods/modlib/minetest/texmod/calc_dims.lua b/mods/modlib/minetest/texmod/calc_dims.lua deleted file mode 100644 index 292e937c..00000000 --- a/mods/modlib/minetest/texmod/calc_dims.lua +++ /dev/null @@ -1,97 +0,0 @@ -local cd = {} - -local function calc_dims(self, get_file_dims) - return assert(cd[self.type])(self, get_file_dims) -end - -function cd:file(d) - return d(self.filename) -end - -do - local function base_dim(self, get_dims) return calc_dims(self.base, get_dims) end - cd.opacity = base_dim - cd.invert = base_dim - cd.brighten = base_dim - cd.noalpha = base_dim - cd.makealpha = base_dim - cd.lowpart = base_dim - cd.mask = base_dim - cd.multiply = base_dim - cd.colorize = base_dim - cd.colorizehsl = base_dim - cd.hsl = base_dim - cd.screen = base_dim - cd.contrast = base_dim -end - -do - local function wh(self) return self.w, self.h end - cd.resize = wh - cd.combine = wh -end - -function cd:fill(get_dims) - if self.base then return calc_dims(self.base, get_dims) end - return self.w, self.h -end - -do - local function upscale_to_higher_res(self, get_dims) - local base_w, base_h = calc_dims(self.base, get_dims) - local over_w, over_h = calc_dims(self.over, get_dims) - if base_w * base_h > over_w * over_h then - return base_w, base_h - end - return over_w, over_h - end - cd.blit = upscale_to_higher_res - cd.hardlight = upscale_to_higher_res -end - -function cd:transform(get_dims) - if self.rotation_deg % 180 ~= 0 then - local base_w, base_h = calc_dims(self.base, get_dims) - return base_h, base_w - end - return calc_dims(self.base, get_dims) -end - -do - local math_clamp = modlib.math.clamp - local function next_pow_of_2(x) - -- I don't want to use a naive 2^ceil(log(x)/log(2)) due to possible float precision issues. - local m, e = math.frexp(x) -- x = _*2^e, _ in [0.5, 1) - if m == 0.5 then e = e - 1 end -- x = 2^(e-1) - return math.ldexp(1, e) -- 2^e, premature optimization here we go - end - function cd:inventorycube(get_dims) - local top_w, top_h = calc_dims(self.top, get_dims) - local left_w, left_h = calc_dims(self.left, get_dims) - local right_w, right_h = calc_dims(self.right, get_dims) - local d = math_clamp(next_pow_of_2(math.max(top_w, top_h, left_w, left_h, right_w, right_h)), 2, 64) - return d, d - end -end - -do - local function frame_dims(self, get_dims) - local base_w, base_h = calc_dims(self.base, get_dims) - return base_w, math.floor(base_h / self.framecount) - end - cd.verticalframe = frame_dims - cd.crack = frame_dims - cd.cracko = frame_dims -end - -function cd:sheet(get_dims) - local base_w, base_h = calc_dims(self.base, get_dims) - return math.floor(base_w / self.w), math.floor(base_h / self.h) -end - -function cd:png() - local png = modlib.minetest.decode_png(modlib.text.inputstream(self.data)) - return png.width, png.height -end - -return calc_dims diff --git a/mods/modlib/minetest/texmod/dsl.lua b/mods/modlib/minetest/texmod/dsl.lua deleted file mode 100644 index beee4345..00000000 --- a/mods/modlib/minetest/texmod/dsl.lua +++ /dev/null @@ -1,422 +0,0 @@ -local colorspec = modlib.minetest.colorspec - -local texmod = {} -local mod = {} -local metatable = {__index = mod} - -local function new(self) - return setmetatable(self, metatable) -end - --- `texmod{...}` may be used to create texture modifiers, bypassing the checks -setmetatable(texmod, {__call = new}) - --- Constructors / "generators" - -function texmod.file(filename) - -- See `TEXTURENAME_ALLOWED_CHARS` in Minetest (`src/network/networkprotocol.h`) - assert(not filename:find"[^%w_.-]", "invalid characters in file name") - return new{ - type = "file", - filename = filename - } -end - -function texmod.png(data) - assert(type(data) == "string") - return new{ - type = "png", - data = data - } -end - -function texmod.combine(w, h, blits) - assert(w % 1 == 0 and w > 0) - assert(h % 1 == 0 and h > 0) - for _, blit in ipairs(blits) do - assert(blit.x % 1 == 0) - assert(blit.y % 1 == 0) - assert(blit.texture) - end - return new{ - type = "combine", - w = w, - h = h, - blits = blits - } -end - -function texmod.inventorycube(top, left, right) - return new{ - type = "inventorycube", - top = top, - left = left, - right = right - } -end - --- As a base generator, `fill` ignores `x` and `y`. Leave them as `nil`. -function texmod.fill(w, h, color) - assert(w % 1 == 0 and w > 0) - assert(h % 1 == 0 and h > 0) - return new{ - type = "fill", - w = w, - h = h, - color = colorspec.from_any(color) - } -end - --- Methods / "modifiers" - -local function assert_int_range(num, min, max) - assert(num % 1 == 0 and num >= min and num <= max) -end - --- As a modifier, `fill` takes `x` and `y` -function mod:fill(w, h, x, y, color) - assert(w % 1 == 0 and w > 0) - assert(h % 1 == 0 and h > 0) - assert(x % 1 == 0 and x >= 0) - assert(y % 1 == 0 and y >= 0) - return new{ - type = "fill", - base = self, - w = w, - h = h, - x = x, - y = y, - color = colorspec.from_any(color) - } -end - --- This is the real "overlay", associated with `^`. -function mod:blit(overlay) - return new{ - type = "blit", - base = self, - over = overlay - } -end - -function mod:brighten() - return new{ - type = "brighten", - base = self, - } -end - -function mod:noalpha() - return new{ - type = "noalpha", - base = self - } -end - -function mod:resize(w, h) - assert(w % 1 == 0 and w > 0) - assert(h % 1 == 0 and h > 0) - return new{ - type = "resize", - base = self, - w = w, - h = h, - } -end - -local function assert_uint8(num) - assert_int_range(num, 0, 0xFF) -end - -function mod:makealpha(r, g, b) - assert_uint8(r); assert_uint8(g); assert_uint8(b) - return new{ - type = "makealpha", - base = self, - r = r, g = g, b = b - } -end - -function mod:opacity(ratio) - assert_uint8(ratio) - return new{ - type = "opacity", - base = self, - ratio = ratio - } -end - -local function tobool(val) - return not not val -end - -function mod:invert(channels --[[set with keys "r", "g", "b", "a"]]) - return new{ - type = "invert", - base = self, - r = tobool(channels.r), - g = tobool(channels.g), - b = tobool(channels.b), - a = tobool(channels.a) - } -end - -function mod:flip(flip_axis --[["x" or "y"]]) - return self:transform(assert( - (flip_axis == "x" and "fx") - or (flip_axis == "y" and "fy") - or (not flip_axis and "i"))) -end - -function mod:rotate(deg) - assert(deg % 90 == 0) - deg = deg % 360 - return self:transform(("r%d"):format(deg)) -end - --- D4 group transformations (see https://proofwiki.org/wiki/Definition:Dihedral_Group_D4), --- represented using indices into a table of matrices --- TODO (...) try to come up with a more elegant solution -do - -- Matrix multiplication for composition: First applies a, then b <=> b * a - local function mat_2x2_compose(a, b) - local a_1_1, a_1_2, a_2_1, a_2_2 = unpack(a) - local b_1_1, b_1_2, b_2_1, b_2_2 = unpack(b) - return { - a_1_1 * b_1_1 + a_2_1 * b_1_2, a_1_2 * b_1_1 + a_2_2 * b_1_2; - a_1_1 * b_2_1 + a_2_1 * b_2_2, a_1_2 * b_2_1 + a_2_2 * b_2_2 - } - end - local r90 ={ - 0, -1; - 1, 0 - } - local fx = { - -1, 0; - 0, 1 - } - local fy = { - 1, 0; - 0, -1 - } - local r180 = mat_2x2_compose(r90, r90) - local r270 = mat_2x2_compose(r180, r90) - local fxr90 = mat_2x2_compose(fx, r90) - local fyr90 = mat_2x2_compose(fy, r90) - local transform_mats = {[0] = {1, 0; 0, 1}, r90, r180, r270, fx, fxr90, fy, fyr90} - local transform_idx_by_name = {i = 0, r90 = 1, r180 = 2, r270 = 3, fx = 4, fxr90 = 5, fy = 6, fyr90 = 7} - -- Lookup tables for getting the flipped axis / rotation angle - local flip_by_idx = { - [4] = "x", - [5] = "x", - [6] = "y", - [7] = "y", - } - local rot_by_idx = { - [1] = 90, - [2] = 180, - [3] = 270, - [5] = 90, - [7] = 90, - } - local idx_by_mat_2x2 = {} - local function transform_idx(mat) - -- note: assumes mat[i] in {-1, 0, 1} - return mat[1] + 3*(mat[2] + 3*(mat[3] + 3*mat[4])) - end - for i = 0, 7 do - idx_by_mat_2x2[transform_idx(transform_mats[i])] = i - end - -- Compute a multiplication table - local composition_idx = {} - local function ij_idx(i, j) - return i*8 + j - end - for i = 0, 7 do - for j = 0, 7 do - composition_idx[ij_idx(i, j)] = assert(idx_by_mat_2x2[ - transform_idx(mat_2x2_compose(transform_mats[i], transform_mats[j]))]) - end - end - function mod:transform(...) - if select("#", ...) == 0 then return self end - local idx = ... - if type(idx) == "string" then - idx = assert(transform_idx_by_name[idx:lower()]) - end - local base = self - if self.type == "transform" then - -- Merge with a `^[transform` base image - assert(transform_mats[idx]) - base = self.base - idx = composition_idx[ij_idx(self.idx, idx)] - end - assert(transform_mats[idx]) - if idx == 0 then return base end -- identity - return new{ - type = "transform", - base = base, - idx = idx, - -- Redundantly store this information for convenience. Do not modify! - flip_axis = flip_by_idx[idx], - rotation_deg = rot_by_idx[idx] or 0, - }:transform(select(2, ...)) - end -end - -function mod:verticalframe(framecount, frame) - assert(framecount >= 1) - assert(frame >= 0) - return new{ - type = "verticalframe", - base = self, - framecount = framecount, - frame = frame - } -end - -local function crack(self, name, ...) - local tilecount, framecount, frame - if select("#", ...) == 2 then - tilecount, framecount, frame = 1, ... - else - assert(select("#", ...) == 3, "invalid number of arguments") - tilecount, framecount, frame = ... - end - assert(tilecount >= 1) - assert(framecount >= 1) - assert(frame >= 0) - return new{ - type = name, - base = self, - tilecount = tilecount, - framecount = framecount, - frame = frame - } -end - -function mod:crack(...) - return crack(self, "crack", ...) -end - -function mod:cracko(...) - return crack(self, "cracko", ...) -end -mod.crack_with_opacity = mod.cracko - -function mod:sheet(w, h, x, y) - assert(w % 1 == 0 and w >= 1) - assert(h % 1 == 0 and h >= 1) - assert(x % 1 == 0 and x >= 0) - assert(y % 1 == 0 and y >= 0) - return new{ - type = "sheet", - base = self, - w = w, - h = h, - x = x, - y = y - } -end - -function mod:screen(color) - return new{ - type = "screen", - base = self, - color = colorspec.from_any(color), - } -end - -function mod:multiply(color) - return new{ - type = "multiply", - base = self, - color = colorspec.from_any(color) - } -end - -function mod:colorize(color, ratio) - color = colorspec.from_any(color) - if ratio == "alpha" then - assert(color.alpha or 0xFF == 0xFF) - else - ratio = ratio or color.alpha or 0xFF - assert_uint8(ratio) - if color.alpha == ratio then - ratio = nil - end - end - return new{ - type = "colorize", - base = self, - color = color, - ratio = ratio - } -end - -local function hsl(type, s_def, s_max, l_def) - return function(self, h, s, l) - s, l = s or s_def, l or l_def - assert_int_range(h, -180, 180) - assert_int_range(s, 0, s_max) - assert_int_range(l, -100, 100) - return new{ - type = type, - base = self, - hue = h, - saturation = s, - lightness = l, - } - end -end - -mod.colorizehsl = hsl("colorizehsl", 50, 100, 0) -mod.hsl = hsl("hsl", 0, math.huge, 0) - -function mod:contrast(contrast, brightness) - brightness = brightness or 0 - assert_int_range(contrast, -127, 127) - assert_int_range(brightness, -127, 127) - return new{ - type = "contrast", - base = self, - contrast = contrast, - brightness = brightness, - } -end - -function mod:mask(mask_texmod) - return new{ - type = "mask", - base = self, - _mask = mask_texmod - } -end - -function mod:hardlight(overlay) - return new{ - type = "hardlight", - base = self, - over = overlay - } -end - --- Overlay *blend*. --- This was unfortunately named `[overlay` in Minetest, --- and so is named `:overlay` for consistency. ---! Do not confuse this with the simple `^` used for blitting -function mod:overlay(overlay) - return overlay:hardlight(self) -end - -function mod:lowpart(percent, overlay) - assert(percent % 1 == 0 and percent >= 0 and percent <= 100) - return new{ - type = "lowpart", - base = self, - percent = percent, - over = overlay - } -end - -return texmod, metatable diff --git a/mods/modlib/minetest/texmod/gen_tex.lua b/mods/modlib/minetest/texmod/gen_tex.lua deleted file mode 100644 index acedd0b6..00000000 --- a/mods/modlib/minetest/texmod/gen_tex.lua +++ /dev/null @@ -1,190 +0,0 @@ -local tex = modlib.tex - -local paths = modlib.minetest.media.paths -local function read_png(fname) - if fname == "blank.png" then return tex.new{w=1,h=1,0} end - return tex.read_png(assert(paths[fname])) -end - -local gt = {} - --- TODO colorizehsl, hsl, contrast --- TODO (...) inventorycube; this is nontrivial. - -function gt:file() - return read_png(self.filename) -end - -function gt:opacity() - local t = self.base:gen_tex() - t:opacity(self.ratio / 255) - return t -end - -function gt:invert() - local t = self.base:gen_tex() - t:invert(self.r, self.g, self.b, self.a) - return t -end - -function gt:brighten() - local t = self.base:gen_tex() - t:brighten() - return t -end - -function gt:noalpha() - local t = self.base:gen_tex() - t:noalpha() - return t -end - -function gt:makealpha() - local t = self.base:gen_tex() - t:makealpha(self.r, self.g, self.b) - return t -end - -function gt:multiply() - local c = self.color - local t = self.base:gen_tex() - t:multiply_rgb(c.r, c.g, c.b) - return t -end - -function gt:screen() - local c = self.color - local t = self.base:gen_tex() - t:screen_blend_rgb(c.r, c.g, c.b) - return t -end - -function gt:colorize() - local c = self.color - local t = self.base:gen_tex() - t:colorize(c.r, c.g, c.b, self.ratio) - return t -end - -local function resized_to_larger(a, b) - if a.w * a.h > b.w * b.h then - b = b:resized(a.w, a.h) - else - a = a:resized(b.w, b.h) - end - return a, b -end - -function gt:mask() - local a, b = resized_to_larger(self.base:gen_tex(), self._mask:gen_tex()) - a:band(b) - return a -end - -function gt:lowpart() - local t = self.base:gen_tex() - local over = self.over:gen_tex() - local lowpart_h = math.ceil(self.percent/100 * over.h) -- TODO (?) ceil or floor - if lowpart_h > 0 then - t, over = resized_to_larger(t, over) - local y = over.h - lowpart_h + 1 - over:crop(1, y, over.w, over.h) - t:blit(1, y, over) - end - return t -end - -function gt:resize() - return self.base:gen_tex():resized(self.w, self.h) -end - -function gt:combine() - local t = tex.filled(self.w, self.h, 0) - for _, blt in ipairs(self.blits) do - t:blit(blt.x + 1, blt.y + 1, blt.texture:gen_tex()) - end - return t -end - -function gt:fill() - if self.base then - return self.base:gen_tex():fill(self.w, self.h, self.x, self.y, self.color:to_number()) - end - return tex.filled(self.w, self.h, self.color:to_number()) -end - -function gt:blit() - local t, o = resized_to_larger(self.base:gen_tex(), self.over:gen_tex()) - t:blit(1, 1, o) - return t -end - -function gt:hardlight() - local t, o = resized_to_larger(self.base:gen_tex(), self.over:gen_tex()) - t:hardlight_blend(o) - return t -end - --- TODO (...?) optimize this -function gt:transform() - local t = self.base:gen_tex() - if self.flip_axis == "x" then - t:flip_x() - elseif self.flip_axis == "y" then - t:flip_y() - end - -- TODO implement counterclockwise rotations to get rid of this hack - for _ = 1, 360 - self.rotation_deg / 90 do - t = t:rotated_90() - end - return t -end - -local frame = function(t, frame, framecount) - local fh = math.floor(t.h / framecount) - t:crop(1, frame * fh + 1, t.w, (frame + 1) * fh) -end - -local crack = function(self, o) - local crack = read_png"crack_anylength.png" - frame(crack, self.frame, math.floor(crack.h / crack.w)) - local t = self.base:gen_tex() - local tile_w, tile_h = math.floor(t.w / self.tilecount), math.floor(t.h / self.framecount) - crack = crack:resized(tile_w, tile_h) - for ty = 1, t.h, tile_h do - for tx = 1, t.w, tile_w do - t[o and "blito" or "blit"](t, tx, ty, crack) - end - end - return t -end - -function gt:crack() - return crack(self, false) -end - -function gt:cracko() - return crack(self, true) -end - -function gt:verticalframe() - local t = self.base:gen_tex() - frame(t, self.frame, self.framecount) - return t -end - -function gt:sheet() - local t = self.base:gen_tex() - local tw, th = math.floor(t.w / self.w), math.floor(t.h / self.h) - local x, y = self.x, self.y - t:crop(x * tw + 1, y * th + 1, (x + 1) * tw, (y + 1) * th) - return t -end - -function gt:png() - return tex.read_png_string(self.data) -end - -return function(self) - return assert(gt[self.type])(self) -end diff --git a/mods/modlib/minetest/texmod/read.lua b/mods/modlib/minetest/texmod/read.lua deleted file mode 100644 index b4ceedb4..00000000 --- a/mods/modlib/minetest/texmod/read.lua +++ /dev/null @@ -1,429 +0,0 @@ -local texmod = ... -local colorspec = modlib.minetest.colorspec - --- Generator readers - -local gr = {} - -function gr.png(r) - r:expect":" - local base64 = r:match_str"[a-zA-Z0-9+/=]" - return assert(minetest.decode_base64(base64), "invalid base64") -end - -function gr.inventorycube(r) - local top = r:invcubeside() - local left = r:invcubeside() - local right = r:invcubeside() - return top, left, right -end - -function gr.combine(r) - r:expect":" - local w = r:int() - r:expect"x" - local h = r:int() - local blits = {} - while r:match":" do - if r.eof then break end -- we can just end with `:`, right? - local x = r:int() - r:expect"," - local y = r:int() - r:expect"=" - table.insert(blits, {x = x, y = y, texture = r:subtexp()}) - end - return w, h, blits -end - -function gr.fill(r) - r:expect":" - local w = r:int() - r:expect"x" - local h = r:int() - r:expect":" - -- Be strict(er than Minetest): Do not accept x, y for a base - local color = r:colorspec() - return w, h, color -end - --- Parameter readers - -local pr = {} - -function pr.fill(r) - r:expect":" - local w = r:int() - r:expect"x" - local h = r:int() - r:expect":" - if assert(r:peek(), "unexpected eof"):find"%d" then - local x = r:int() - r:expect"," - local y = r:int() - r:expect":" - local color = r:colorspec() - return w, h, x, y, color - end - local color = r:colorspec() - return w, h, color -end - -function pr.brighten() end - -function pr.noalpha() end - -function pr.resize(r) - r:expect":" - local w = r:int() - r:expect"x" - local h = r:int() - return w, h -end - -function pr.makealpha(r) - r:expect":" - local red = r:int() - r:expect"," - local green = r:int() - r:expect"," - local blue = r:int() - return red, green, blue -end - -function pr.opacity(r) - r:expect":" - local ratio = r:int() - return ratio -end - -function pr.invert(r) - r:expect":" - local channels = {} - while true do - local c = r:match_charset"[rgba]" - if not c then break end - channels[c] = true - end - return channels -end - -do - function pr.transform(r) - if r:match_charset"[iI]" then - return pr.transform(r) - end - local idx = r:match_charset"[0-7]" - if idx then - return tonumber(idx), pr.transform(r) - end - if r:match_charset"[fF]" then - local flip_axis = assert(r:match_charset"[xXyY]", "axis expected") - return "f" .. flip_axis, pr.transform(r) - end - if r:match_charset"[rR]" then - local deg = r:match_str"%d" - -- Be strict here: Minetest won't recognize other ways to write these numbers (or other numbers) - assert(deg == "90" or deg == "180" or deg == "270") - return ("r%d"):format(deg), pr.transform(r) - end - -- return nothing, we're done - end -end - -function pr.verticalframe(r) - r:expect":" - local framecount = r:int() - r:expect":" - local frame = r:int() - return framecount, frame -end - -function pr.crack(r) - r:expect":" - local framecount = r:int() - r:expect":" - local frame = r:int() - if r:match":" then - return framecount, frame, r:int() - end - return framecount, frame -end -pr.cracko = pr.crack - -function pr.sheet(r) - r:expect":" - local w = r:int() - r:expect"x" - local h = r:int() - r:expect":" - local x = r:int() - r:expect"," - local y = r:int() - return w, h, x, y -end - -function pr.multiply(r) - r:expect":" - return r:colorspec() -end -pr.screen = pr.multiply - -function pr.colorize(r) - r:expect":" - local color = r:colorspec() - if not r:match":" then - return color - end - if not r:match"a" then - return color, r:int() - end - for c in ("lpha"):gmatch"." do - r:expect(c) - end - return color, "alpha" -end - -function pr.colorizehsl(r) - r:expect":" - local hue = r:int() - if not r:match":" then - return hue - end - local saturation = r:int() - if not r:match":" then - return hue, saturation - end - local lightness = r:int() - return hue, saturation, lightness -end -pr.hsl = pr.colorizehsl - -function pr.contrast(r) - r:expect":" - local contrast = r:int() - if not r:match":" then - return contrast - end - local brightness = r:int() - return contrast, brightness -end - -function pr.overlay(r) - r:expect":" - return r:subtexp() -end - -function pr.hardlight(r) - r:expect":" - return r:subtexp() -end - -function pr.mask(r) - r:expect":" - return r:subtexp() -end - -function pr.lowpart(r) - r:expect":" - local percent = r:int() - assert(percent) - r:expect":" - return percent, r:subtexp() -end - --- Build a prefix tree of parameter readers to greedily match the longest texture modifier prefix; --- just matching `%a+` and looking it up in a table --- doesn't work since `[transform` may be followed by a lowercase transform name --- TODO (?...) consolidate with `modlib.trie` -local texmod_reader_trie = {} -for _, readers in pairs{pr, gr} do - for type in pairs(readers) do - local subtrie = texmod_reader_trie - for char in type:gmatch"." do - subtrie[char] = subtrie[char] or {} - subtrie = subtrie[char] - end - subtrie.type = type - end -end - --- Reader methods. We use `r` instead of the `self` "sugar" for consistency (and to save us some typing). -local rm = {} - -function rm.peek(r, parenthesized) - if r.eof then return end - local expected_escapes = 0 - if r.level > 0 then - -- Premature optimization my beloved (this is `2^(level-1)`) - expected_escapes = math.ldexp(0.5, r.level) - end - if r.character:match"[&^:]" then -- "special" characters - these need to be escaped - if r.escapes == expected_escapes then - return r.character - elseif parenthesized and r.character == "^" and r.escapes < expected_escapes then - -- Special handling for `^` inside `(...)`: This is undocumented behavior but works in Minetest - r.warn"parenthesized caret (`^`) with too few escapes" - return r.character - end - elseif r.escapes <= expected_escapes then - return r.character - end if r.escapes >= 2*expected_escapes then - return "\\" - end -end -function rm.popchar(r) - assert(not r.eof, "unexpected eof") - r.escapes = 0 - while true do - r.character = r:read_char() - if r.character ~= "\\" then break end - r.escapes = r.escapes + 1 - end - if r.character == nil then - assert(r.escapes == 0, "end of texmod expected") - r.eof = true - end -end -function rm.pop(r) - local expected_escapes = 0 - if r.level > 0 then - -- Premature optimization my beloved (this is `2^(level-1)`) - expected_escapes = math.ldexp(0.5, r.level) - end - if r.escapes > 0 and r.escapes >= 2*expected_escapes then - r.escapes = r.escapes - 2*expected_escapes - return - end - return r:popchar() -end -function rm.match(r, char) - if r:peek() == char then - r:pop() - return true - end -end -function rm.expect(r, char) - if not r:match(char) then - error(("%q expected"):format(char)) - end -end -function rm.hat(r, parenthesized) - if r:peek(parenthesized) == (r.invcube and "&" or "^") then - r:pop() - return true - end -end -function rm.match_charset(r, set) - local char = r:peek() - if char and char:match(set) then - r:pop() - return char - end -end -function rm.match_str(r, set) - local c = r:match_charset(set) - if not c then - error(("character in %s expected"):format(set)) - end - local t = {c} - while true do - c = r:match_charset(set) - if not c then break end - table.insert(t, c) - end - return table.concat(t) -end -function rm.int(r) - local sign = 1 - if r:match"-" then sign = -1 end - return sign * tonumber(r:match_str"%d") -end -function rm.fname(r) - -- This is overly permissive, as is Minetest; - -- we just allow arbitrary characters up until a character which may terminate the name. - -- Inside an inventorycube, `&` also terminates names. - -- Note that the constructor will however - unlike Minetest - perform validation. - -- We could leverage the knowledge of the allowed charset here already, - -- but that might lead to more confusing error messages. - return r:match_str(r.invcube and "[^:^&){]" or "[^:^){]") -end -function rm.subtexp(r) - r.level = r.level + 1 - local res = r:texp() - r.level = r.level - 1 - return res -end -function rm.invcubeside(r) - assert(not r.invcube, "can't nest inventorycube") - r.invcube = true - assert(r:match"{", "'{' expected") - local res = r:texp() - r.invcube = false - return res -end -function rm.basexp(r) - if r:match"(" then - local res = r:texp(true) - r:expect")" - return res - end - if r:match"[" then - local type = r:match_str"%a" - local gen_reader = gr[type] - if not gen_reader then - error("invalid texture modifier: " .. type) - end - return texmod[type](gen_reader(r)) - end - return texmod.file(r:fname()) -end -function rm.colorspec(r) - -- Leave exact validation up to colorspec, only do a rough greedy charset matching - return assert(colorspec.from_string(r:match_str"[#%x%a]")) -end -function rm.texp(r, parenthesized) - local base = r:basexp() -- TODO (?) make optional - warn about omitting the base - while r:hat(parenthesized) do - if r:match"[" then - local reader_subtrie = texmod_reader_trie - while true do - local next_subtrie = reader_subtrie[r:peek()] - if next_subtrie then - reader_subtrie = next_subtrie - r:pop() - else - break - end - end - local type = assert(reader_subtrie.type, "invalid texture modifier") - local param_reader, gen_reader = pr[type], gr[type] - assert(param_reader or gen_reader) - if param_reader then - -- Note: It is important that this takes precedence to properly handle `[fill` - base = base[type](base, param_reader(r)) - elseif gen_reader then - base = base:blit(texmod[type](gen_reader(r))) - end - -- TODO (?...) we could consume leftover parameters here to be as lax as Minetest - else - base = base:blit(r:basexp()) - end - end - return base -end - -local mt = {__index = rm} -return function(read_char, warn --[[function(str)]]) - local r = setmetatable({ - level = 0, - invcube = false, - parenthesized = false, - eof = false, - read_char = read_char, - warn = warn or error, - }, mt) - r:popchar() - local res = r:texp(false) - assert(r.eof, "eof expected") - return res -end diff --git a/mods/modlib/minetest/texmod/write.lua b/mods/modlib/minetest/texmod/write.lua deleted file mode 100644 index c99f56d5..00000000 --- a/mods/modlib/minetest/texmod/write.lua +++ /dev/null @@ -1,181 +0,0 @@ -local pw = {} -- parameter writers: `[type] = func(self, write)` - -function pw:png(w) - w.colon(); w.str(minetest.encode_base64(self.data)) -end - -function pw:combine(w) - w.colon(); w.int(self.w); w.str"x"; w.str(self.h) - for _, blit in ipairs(self.blits) do - w.colon() - w.int(blit.x); w.str","; w.int(blit.y); w.str"=" - w.esctex(blit.texture) - end -end - -function pw:inventorycube(w) - assert(not w.inventorycube, "[inventorycube may not be nested") - local function write_side(side) - w.str"{" - w.inventorycube = true - w.tex(self[side]) - w.inventorycube = false - end - write_side"top" - write_side"left" - write_side"right" -end - --- Handles both the generator & the modifier -function pw:fill(w) - w.colon(); w.int(self.w); w.str"x"; w.int(self.h) - if self.base then - w.colon(); w.int(self.x); w.str","; w.int(self.y) - end - w.colon(); w.str(self.color:to_string()) -end - --- No parameters to write -pw.brighten = modlib.func.no_op -pw.noalpha = modlib.func.no_op - -function pw:resize(w) - w.colon(); w.int(self.w); w.str"x"; w.int(self.h) -end - -function pw:makealpha(w) - w.colon(); w.int(self.r); w.str","; w.int(self.g); w.str","; w.int(self.b) -end - -function pw:opacity(w) - w.colon(); w.int(self.ratio) -end - -function pw:invert(w) - w.colon() - if self.r then w.str"r" end - if self.g then w.str"g" end - if self.b then w.str"b" end - if self.a then w.str"a" end -end - -function pw:transform(w) - w.int(self.idx) -end - -function pw:verticalframe(w) - w.colon(); w.int(self.framecount); w.colon(); w.int(self.frame) -end - -function pw:crack(w) - w.colon(); w.int(self.tilecount); w.colon(); w.int(self.framecount); w.colon(); w.int(self.frame) -end - -pw.cracko = pw.crack - -function pw:sheet(w) - w.colon(); w.int(self.w); w.str"x"; w.int(self.h); w.colon(); w.int(self.x); w.str","; w.int(self.y) -end - -function pw:screen(w) - w.colon() - w.str(self.color:to_string()) -end - -function pw:multiply(w) - w.colon() - w.str(self.color:to_string()) -end - -function pw:colorize(w) - w.colon() - w.str(self.color:to_string()) - if self.ratio then - w.colon() - if self.ratio == "alpha" then - w.str"alpha" - else - w.int(self.ratio) - end - end -end - -function pw:colorizehsl(w) - w.colon(); w.int(self.hue); w.colon(); w.int(self.saturation); w.colon(); w.int(self.lightness) -end -pw.hsl = pw.colorizehsl - -function pw:contrast(w) - w.colon(); w.int(self.contrast); w.colon(); w.int(self.brightness) -end - --- We don't have to handle `[overlay`; the DSL normalizes everything to `[hardlight` -function pw:hardlight(w) - w.colon(); w.esctex(self.over) -end - -function pw:mask(w) - w.colon(); w.esctex(self._mask) -end - -function pw:lowpart(w) - w.colon(); w.int(self.percent); w.colon(); w.esctex(self.over) -end - --- Set of "non-modifiers" which do not modify a base image -local non_modifiers = {file = true, png = true, combine = true, inventorycube = true} - -return function(self, write_str) - -- We could use a metatable here, but it wouldn't really be worth it; - -- it would save us instantiating a handful of closures at the cost of constant `__index` events - -- and having to constantly pass `self`, increasing code complexity - local w = {} - w.inventorycube = false - w.level = 0 - w.str = write_str - function w.esc() - if w.level == 0 then return end - w.str(("\\"):rep(math.ldexp(0.5, w.level))) - end - function w.hat() - -- Note: We technically do not need to escape `&` inside an [inventorycube which is nested inside [combine, - -- but we do it anyways for good practice and since we have to escape `&` inside [combine inside [inventorycube. - w.esc() - w.str(w.inventorycube and "&" or "^") - end - function w.colon() - w.esc(); w.str":" - end - function w.int(int) - w.str(("%d"):format(int)) - end - function w.tex(tex) - if tex.type == "file" then - w.str(tex.filename) - return - end - if tex.base then - w.tex(tex.base) - w.hat() - end - if tex.type == "blit" then -- simply `^` - if non_modifiers[tex.over.type] then - w.tex(tex.over) - else - -- Make sure the modifier is first applied to its base image - -- and only after this overlaid on top of `tex.base` - w.str"("; w.tex(tex.over); w.str")" - end - else - w.str"[" - w.str(tex.type) - pw[tex.type](tex, w) - end - end - function w.esctex(tex) - w.level = w.level + 1 - w.tex(tex) - w.level = w.level - 1 - end - w.tex(self) -end diff --git a/mods/modlib/minetest/wielditem_change.lua b/mods/modlib/minetest/wielditem_change.lua deleted file mode 100644 index 30d57938..00000000 --- a/mods/modlib/minetest/wielditem_change.lua +++ /dev/null @@ -1,66 +0,0 @@ --- Localize globals -local minetest, modlib, pairs, table = minetest, modlib, pairs, table - --- Set environment -local _ENV = ... -setfenv(1, _ENV) - -players = {} - -registered_on_wielditem_changes = {function(...) - local _, previous_item, _, item = ... - if previous_item then - ((previous_item:get_definition()._modlib or {}).un_wield or modlib.func.no_op)(...) - end - if item then - ((item:get_definition()._modlib or {}).on_wield or modlib.func.no_op)(...) - end -end} - ---+ Registers an on_wielditem_change callback: function(player, previous_item, previous_index, item) ---+ Will be called once with player, nil, index, item on join -register_on_wielditem_change = modlib.func.curry(table.insert, registered_on_wielditem_changes) - -local function register_callbacks() - minetest.register_on_joinplayer(function(player) - local item, index = player:get_wielded_item(), player:get_wield_index() - players[player:get_player_name()] = { - wield = { - item = item, - index = index - } - } - modlib.table.icall(registered_on_wielditem_changes, player, nil, index, item) - end) - minetest.register_on_leaveplayer(function(player) - players[player:get_player_name()] = nil - end) -end - --- Other on_joinplayer / on_leaveplayer callbacks should execute first -if minetest.get_current_modname() then - -- Loaded during load time, register callbacks after load time - minetest.register_on_mods_loaded(register_callbacks) -else - -- Loaded after load time, register callbacks immediately - register_callbacks() -end - --- TODO export -local function itemstack_equals(a, b) - return a:get_name() == b:get_name() and a:get_count() == b:get_count() and a:get_wear() == b:get_wear() and a:get_meta():equals(b:get_meta()) -end - -minetest.register_globalstep(function() - for _, player in pairs(minetest.get_connected_players()) do - local item, index = player:get_wielded_item(), player:get_wield_index() - local playerdata = players[player:get_player_name()] - if not playerdata then return end - local previous_item, previous_index = playerdata.wield.item, playerdata.wield.index - if not (itemstack_equals(item, previous_item) and index == previous_index) then - playerdata.wield.item = item - playerdata.wield.index = index - modlib.table.icall(registered_on_wielditem_changes, player, previous_item, previous_index, item) - end - end -end) \ No newline at end of file diff --git a/mods/modlib/mod.conf b/mods/modlib/mod.conf deleted file mode 100644 index 3f6fba1c..00000000 --- a/mods/modlib/mod.conf +++ /dev/null @@ -1,5 +0,0 @@ -name = modlib -title = Modding Library -description = Multipurpose Minetest Modding Library -author = LMD aka appguru(eu) -optional_depends = dbg, strictest diff --git a/mods/modlib/persistence.lua b/mods/modlib/persistence.lua deleted file mode 100644 index e57ebafc..00000000 --- a/mods/modlib/persistence.lua +++ /dev/null @@ -1,23 +0,0 @@ -local require = ... or require --- TODO consider moving serializers in this namespace -local function load(module_name) - return assert(loadfile(modlib.mod.get_resource(modlib.modname, "persistence", module_name .. ".lua"))) -end -return setmetatable({}, {__index = function(self, module_name) - if module_name == "lua_log_file" then - local module = load(module_name)() - self[module_name] = module - return module - end - if module_name == "sqlite3" then - local func = load(module_name) - local module = function(sqlite3) - if sqlite3 then - return func(sqlite3) - end - return func(require"lsqlite3") - end - self[module_name] = module - return module - end -end}) \ No newline at end of file diff --git a/mods/modlib/persistence/lua_log_file.lua b/mods/modlib/persistence/lua_log_file.lua deleted file mode 100644 index 94b740c6..00000000 --- a/mods/modlib/persistence/lua_log_file.lua +++ /dev/null @@ -1,194 +0,0 @@ --- Localize globals -local assert, error, io, loadfile, math, minetest, modlib, pairs, setfenv, setmetatable, type - = assert, error, io, loadfile, math, minetest, modlib, pairs, setfenv, setmetatable, type - --- Set environment -local _ENV = {} -setfenv(1, _ENV) - --- Default value -reference_strings = true - --- Note: keys may not be marked as weak references: garbage collected log files wouldn't close the file: --- The `__gc` metamethod doesn't work for tables in Lua 5.1; a hack using `newproxy` would be needed --- See https://stackoverflow.com/questions/27426704/lua-5-1-workaround-for-gc-metamethod-for-tables) --- Therefore, :close() must be called on log files to remove them from the `files` table -local files = {} -local metatable = {__index = _ENV} -_ENV.metatable = metatable - -function new(file_path, root, reference_strings) - local self = setmetatable({ - file_path = assert(file_path), - root = root, - reference_strings = reference_strings - }, metatable) - if minetest then - files[self] = true - end - return self -end - -local function set_references(self, table) - -- Weak table keys to allow the collection of dead reference tables - -- TODO garbage collect strings in the references table - self.references = setmetatable(table, {__mode = "k"}) -end - -function load(self) - -- Bytecode is blocked by the engine - local read = assert(loadfile(self.file_path)) - -- math.huge is serialized to inf - local env = {inf = math.huge} - setfenv(read, env) - read() - env.R = env.R or {{}} - local reference_count = #env.R - for ref in pairs(env.R) do - if ref > reference_count then - -- Ensure reference count always has the value of the largest reference - -- in case of "holes" (nil values) in the reference list - reference_count = ref - end - end - self.reference_count = reference_count - self.root = env.R[1] - set_references(self, {}) -end - -function open(self) - self.file = io.open(self.file_path, "a+") -end - -function init(self) - if modlib.file.exists(self.file_path) then - self:load() - self:_rewrite() - self:open() - return - end - self:open() - self:_write() -end - -function log(self, statement) - self.file:write(statement) - self.file:write"\n" -end - -function flush(self) - self.file:flush() -end - -function close(self) - self.file:close() - self.file = nil - files[self] = nil -end - -if minetest then - minetest.register_on_shutdown(function() - for self in pairs(files) do - self.file:close() - end - end) -end - -local function _dump(self, value, is_key) - if value == nil then - return "nil" - end - if value == true then - return "true" - end - if value == false then - return "false" - end - if value ~= value then - -- nan - return "0/0" - end - local _type = type(value) - if _type == "number" then - return ("%.17g"):format(value) - end - local reference = self.references[value] - if reference then - return "R[" .. reference .."]" - end - reference = self.reference_count + 1 - local key = "R[" .. reference .."]" - local function create_reference() - self.reference_count = reference - self.references[value] = reference - end - if _type == "string" then - local reference_strings = self.reference_strings - if is_key and ((not reference_strings) or value:len() <= key:len()) and modlib.text.is_identifier(value) then - -- Short key - return value, true - end - local formatted = ("%q"):format(value) - if (not reference_strings) or formatted:len() <= key:len() then - -- Short string - return formatted - end - -- Use reference - create_reference() - self:log(key .. "=" .. formatted) - elseif _type == "table" then - -- Tables always need a reference before they are traversed to prevent infinite recursion - create_reference() - -- TODO traverse tables to determine whether this is actually needed - self:log(key .. "={}") - for k, v in pairs(value) do - local dumped, short = _dump(self, k, true) - self:log(key .. (short and ("." .. dumped) or ("[" .. dumped .. "]")) .. "=" .. _dump(self, v)) - end - else - error("unsupported type: " .. _type) - end - return key -end - -function set(self, table, key, value) - if not self.references[table] then - error"orphan table" - end - if table[key] == value then - -- No change - return - end - table[key] = value - table = _dump(self, table) - local key, short_key = _dump(self, key, true) - self:log(table .. (short_key and ("." .. key) or ("[" .. key .. "]")) .. "=" .. _dump(self, value)) -end - -function set_root(self, key, value) - return self:set(self.root, key, value) -end - -function _write(self) - set_references(self, {}) - self.reference_count = 0 - self:log"R={}" - _dump(self, self.root) -end - -function _rewrite(self) - self.file = io.open(self.file_path, "w+") - self:_write() - self.file:close() -end - -function rewrite(self) - if self.file then - self.file:close() - end - self:_rewrite() - self:open() -end - --- Export environment -return _ENV \ No newline at end of file diff --git a/mods/modlib/persistence/sqlite3.lua b/mods/modlib/persistence/sqlite3.lua deleted file mode 100644 index 60c484e0..00000000 --- a/mods/modlib/persistence/sqlite3.lua +++ /dev/null @@ -1,318 +0,0 @@ -local assert, error, math_huge, modlib, minetest, setmetatable, type, table_insert, table_sort, pairs, ipairs - = assert, error, math.huge, modlib, minetest, setmetatable, type, table.insert, table.sort, pairs, ipairs - -local sqlite3 = ... - ---[[ - Currently uses reference counting to immediately delete tables which aren't reachable from the root table anymore, which has two issues: - 1. Deletion might trigger a large deletion chain - TODO defer deletion, clean up unused tables on startup, delete & iterate tables partially - 2. Reference counting is unable to handle cycles. `:collectgarbage()` implements a tracing "stop-the-world" garbage collector which handles cycles. - TODO take advantage of Lua's garbage collection by keeping a bunch of "twin" objects in a weak structure using proxies (Lua 5.1) or the __gc metamethod (Lua 5.2) - See https://wiki.c2.com/?ReferenceCountingCanHandleCycles, https://www.memorymanagement.org/mmref/recycle.html#mmref-recycle and https://wiki.c2.com/?GenerationalGarbageCollectio - Weak tables are of no use here, as we need to be notified when a reference is dropped -]] - -local ptab = {} -- SQLite3-backed implementation for a persistent Lua table ("ptab") -local metatable = {__index = ptab} -ptab.metatable = metatable - --- Note: keys may not be marked as weak references: wouldn't close the database: see persistence/lua_log_file.lua -local databases = {} - -local types = { - boolean = 1, - number = 2, - string = 3, - table = 4 -} - -local function increment_highest_table_id(self) - self.highest_table_id = self.highest_table_id + 1 - if self.highest_table_id > 2^50 then - -- IDs are approaching double precision limit (52 bits mantissa), defragment them - self:defragment_ids() - end - return self.highest_table_id -end - -function ptab.new(file_path, root) - return setmetatable({ - database = sqlite3.open(file_path), - root = root - }, metatable) -end - -function ptab.setmetatable(self) - assert(self.database and self.root) - return setmetatable(self, metatable) -end - -local set - -local function add_table(self, table) - if type(table) ~= "table" then return end - if self.counts[table] then - self.counts[table] = self.counts[table] + 1 - return - end - self.table_ids[table] = increment_highest_table_id(self) - self.counts[table] = 1 - for k, v in pairs(table) do - set(self, table, k, v) - end -end - -local decrement_reference_count - -local function delete_table(self, table) - local id = assert(self.table_ids[table]) - self.table_ids[table] = nil - self.counts[table] = nil - for k, v in pairs(table) do - decrement_reference_count(self, k) - decrement_reference_count(self, v) - end - local statement = self._prepared.delete_table - statement:bind(1, id) - statement:step() - statement:reset() -end - -function decrement_reference_count(self, table) - if type(table) ~= "table" then return end - local count = self.counts[table] - if not count then return end - count = count - 1 - if count == 0 then return delete_table(self, table) end - self.counts[table] = count -end - -function set(self, table, key, value) - local deletion = value == nil - if not deletion then - add_table(self, key) - add_table(self, value) - end - local previous_value = table[key] - if type(previous_value) == "table" then - decrement_reference_count(self, previous_value) - end - if deletion and type(key) == "table" then - decrement_reference_count(self, key) - end - local statement = self._prepared[deletion and "delete" or "insert"] - local function bind_type_and_content(n, value) - local type_ = type(value) - statement:bind(n, assert(types[type_])) - if type_ == "boolean" then - statement:bind(n + 1, value and 1 or 0) - elseif type_ == "number" then - if value ~= value then - statement:bind(n + 1, "nan") - elseif value == math_huge then - statement:bind(n + 1, "inf") - elseif value == -math_huge then - statement:bind(n + 1, "-inf") - else - statement:bind(n + 1, value) - end - elseif type_ == "string" then - -- Use bind_blob instead of bind as Lua strings are effectively byte strings - statement:bind_blob(n + 1, value) - elseif type_ == "table" then - statement:bind(n + 1, self.table_ids[value]) - end - end - statement:bind(1, assert(self.table_ids[table])) - bind_type_and_content(2, key) - if not deletion then - bind_type_and_content(4, value) - end - statement:step() - statement:reset() -end - -local function exec(self, sql) - if self.database:exec(sql) ~= sqlite3.OK then - error(self.database:errmsg()) - end -end - -function ptab:init() - local database = self.database - local function prepare(sql) - local stmt = database:prepare(sql) - if not stmt then error(database:errmsg()) end - return stmt - end - exec(self, [[ -CREATE TABLE IF NOT EXISTS table_entries ( - table_id INTEGER NOT NULL, - key_type INTEGER NOT NULL, - key BLOB NOT NULL, - value_type INTEGER NOT NULL, - value BLOB NOT NULL, - PRIMARY KEY (table_id, key_type, key) -)]]) - self._prepared = { - insert = prepare"INSERT OR REPLACE INTO table_entries(table_id, key_type, key, value_type, value) VALUES (?, ?, ?, ?, ?)", - delete = prepare"DELETE FROM table_entries WHERE table_id = ? AND key_type = ? AND key = ?", - delete_table = prepare"DELETE FROM table_entries WHERE table_id = ?", - update = { - id = prepare"UPDATE table_entries SET table_id = ? WHERE table_id = ?", - keys = prepare("UPDATE table_entries SET key = ? WHERE key_type = " .. types.table .. " AND key = ?"), - values = prepare("UPDATE table_entries SET value = ? WHERE value_type = " .. types.table .. " AND value = ?") - } - } - -- Default value - self.highest_table_id = 0 - for id in self.database:urows"SELECT MAX(table_id) FROM table_entries" do - -- Gets a single value - self.highest_table_id = id - end - increment_highest_table_id(self) - local tables = {} - local counts = {} - self.counts = counts - local function get_value(type_, content) - if type_ == types.boolean then - if content == 0 then return false end - if content == 1 then return true end - error("invalid boolean value: " .. content) - end - if type_ == types.number then - if content == "nan" then - return 0/0 - end - if content == "inf" then - return math_huge - end - if content == "-inf" then - return -math_huge - end - assert(type(content) == "number") - return content - end - if type_ == types.string then - assert(type(content) == "string") - return content - end - if type_ == types.table then - -- Table reference - tables[content] = tables[content] or {} - counts[content] = counts[content] or 1 - return tables[content] - end - -- Null is unused - error("unsupported type: " .. type_) - end - -- Order by key_content to retrieve list parts in the correct order, making it easier for Lua - for table_id, key_type, key, value_type, value in self.database:urows"SELECT * FROM table_entries ORDER BY table_id, key_type, key" do - local table = tables[table_id] or {} - counts[table] = counts[table] or 1 - table[get_value(key_type, key)] = get_value(value_type, value) - tables[table_id] = table - end - if tables[1] then - self.root = tables[1] - counts[self.root] = counts[self.root] + 1 - self.table_ids = modlib.table.flip(tables) - self:collectgarbage() - else - self.highest_table_id = 0 - self.table_ids = {} - add_table(self, self.root) - end - databases[self] = true -end - -function ptab:rewrite() - exec(self, "BEGIN EXCLUSIVE TRANSACTION") - exec(self, "DELETE FROM table_entries") - self.highest_table_id = 0 - self.table_ids = {} - self.counts = {} - add_table(self, self.root) - exec(self, "COMMIT TRANSACTION") -end - -function ptab:set(table, key, value) - exec(self, "BEGIN EXCLUSIVE TRANSACTION") - local previous_value = table[key] - if previous_value == value then - -- no change - return - end - set(self, table, key, value) - table[key] = value - exec(self, "COMMIT TRANSACTION") -end - -function ptab:set_root(key, value) - return self:set(self.root, key, value) -end - -function ptab:collectgarbage() - local marked = {} - local function mark(table) - if type(table) ~= "table" or marked[table] then return end - marked[table] = true - for k, v in pairs(table) do - mark(k) - mark(v) - end - end - mark(self.root) - for table in pairs(self.table_ids) do - if not marked[table] then - delete_table(self, table) - end - end -end - -function ptab:defragment_ids() - local ids = {} - for _, id in pairs(self.table_ids) do - table_insert(ids, id) - end - table_sort(ids) - local update = self._prepared.update - local tables = modlib.table.flip(self.table_ids) - for new_id, old_id in ipairs(ids) do - for _, stmt in pairs(update) do - stmt:bind_values(new_id, old_id) - stmt:step() - stmt:reset() - end - self.table_ids[tables[old_id]] = new_id - end - self.highest_table_id = #ids -end - -local function finalize_statements(table) - for _, stmt in pairs(table) do - if type(stmt) == "table" then - finalize_statements(stmt) - else - local errcode = stmt:finalize() - assert(errcode == sqlite3.OK, errcode) - end - end -end - -function ptab:close() - finalize_statements(self._prepared) - self.database:close() - databases[self] = nil -end - -if minetest then - minetest.register_on_shutdown(function() - for self in pairs(databases) do - self:close() - end - end) -end - -return ptab \ No newline at end of file diff --git a/mods/modlib/quaternion.lua b/mods/modlib/quaternion.lua deleted file mode 100644 index de28bd7e..00000000 --- a/mods/modlib/quaternion.lua +++ /dev/null @@ -1,165 +0,0 @@ --- Localize globals -local math, modlib, pairs, unpack, vector = math, modlib, pairs, unpack, vector - --- Set environment -local _ENV = {} -setfenv(1, _ENV) - --- TODO OOP, extend vector - -function from_euler_rotation(rotation) - rotation = vector.divide(rotation, 2) - local cos = vector.apply(rotation, math.cos) - local sin = vector.apply(rotation, math.sin) - return { - cos.z * sin.x * cos.y + sin.z * cos.x * sin.y, - cos.z * cos.x * sin.y - sin.z * sin.x * cos.y, - sin.z * cos.x * cos.y - cos.z * sin.x * sin.y, - cos.z * cos.x * cos.y + sin.z * sin.x * sin.y - } -end - -function from_euler_rotation_deg(rotation) - return from_euler_rotation(vector.apply(rotation, math.rad)) -end - -function multiply(self, other) - local X, Y, Z, W = unpack(self) - return normalize{ - (other[4] * X) + (other[1] * W) + (other[2] * Z) - (other[3] * Y); - (other[4] * Y) + (other[2] * W) + (other[3] * X) - (other[1] * Z); - (other[4] * Z) + (other[3] * W) + (other[1] * Y) - (other[2] * X); - (other[4] * W) - (other[1] * X) - (other[2] * Y) - (other[3] * Z); - } -end - -function compose(self, other) - return multiply(other, self) -end - -function len(self) - return (self[1] ^ 2 + self[2] ^ 2 + self[3] ^ 2 + self[4] ^ 2) ^ 0.5 -end - -function normalize(self) - local l = len(self) - local res = {} - for key, value in pairs(self) do - res[key] = value / l - end - return res -end - -function conjugate(self) - return { - -self[1], - -self[2], - -self[3], - self[4] - } -end - -function inverse(self) - -- TODO this is just a fancy normalization *of the conjungate*, - -- which for rotations is the inverse - return modlib.vector.divide_scalar(conjugate(self), self[1] ^ 2 + self[2] ^ 2 + self[3] ^ 2 + self[4] ^ 2) -end - -function negate(self) - for key, value in pairs(self) do - self[key] = -value - end -end - -function dot(self, other) - return self[1] * other[1] + self[2] * other[2] + self[3] * other[3] + self[4] * other[4] -end - ---: self normalized quaternion ---: other normalized quaternion -function slerp(self, other, ratio) - local d = dot(self, other) - if d < 0 then - d = -d - negate(other) - end - -- Threshold beyond which linear interpolation is used - if d > 1 - 1e-10 then - return modlib.vector.interpolate(self, other, ratio) - end - local theta_0 = math.acos(d) - local theta = theta_0 * ratio - local sin_theta = math.sin(theta) - local sin_theta_0 = math.sin(theta_0) - local s_1 = sin_theta / sin_theta_0 - local s_0 = math.cos(theta) - d * s_1 - return modlib.vector.add(modlib.vector.multiply_scalar(self, s_0), modlib.vector.multiply_scalar(other, s_1)) -end - ---> axis, angle -function to_axis_angle(self) - local axis = modlib.vector.new{self[1], self[2], self[3]} - local len = axis:length() - -- HACK invert axis for correct rotation in Minetest - return len == 0 and axis or axis:divide_scalar(-len), 2 * math.atan2(len, self[4]) -end - -function to_euler_rotation_rad(self) - local rotation = {} - - local sinr_cosp = 2 * (self[4] * self[1] + self[2] * self[3]) - local cosr_cosp = 1 - 2 * (self[1] ^ 2 + self[2] ^ 2) - rotation.x = math.atan2(sinr_cosp, cosr_cosp) - - local sinp = 2 * (self[4] * self[2] - self[3] * self[1]) - if sinp <= -1 then - rotation.y = -math.pi/2 - elseif sinp >= 1 then - rotation.y = math.pi/2 - else - rotation.y = math.asin(sinp) - end - - local siny_cosp = 2 * (self[4] * self[3] + self[1] * self[2]) - local cosy_cosp = 1 - 2 * (self[2] ^ 2 + self[3] ^ 2) - rotation.z = math.atan2(siny_cosp, cosy_cosp) - - return rotation -end - --- TODO rename this to to_euler_rotation_deg eventually (breaking change) ---> {x = pitch, y = yaw, z = roll} euler rotation in degrees -function to_euler_rotation(self) - return vector.apply(to_euler_rotation_rad(self), math.deg) -end - --- See https://github.com/zaki/irrlicht/blob/master/include/quaternion.h#L652 -function to_euler_rotation_irrlicht(self) - local x, y, z, w = unpack(self) - local test = 2 * (y * w - x * z) - - local rot - if math.abs(test - 1) <= 1e-6 then - rot = { - z = -2 * math.atan2(x, w), - x = 0, - y = math.pi/2 - } - elseif math.abs(test + 1) <= 1e-6 then - rot = { - z = 2 * math.atan2(x, w), - x = 0, - y = math.pi/-2 - } - else - rot = { - z = math.atan2(2 * (x * y + z * w), x ^ 2 - y ^ 2 - z ^ 2 + w ^ 2), - x = math.atan2(2 * (y * z + x * w), -x ^ 2 - y ^ 2 + z ^ 2 + w ^ 2), - y = math.asin(math.min(math.max(test, -1), 1)) - } - end - return vector.apply(rot, math.deg) -end - --- Export environment -return _ENV diff --git a/mods/modlib/schema.lua b/mods/modlib/schema.lua deleted file mode 100644 index e23ca943..00000000 --- a/mods/modlib/schema.lua +++ /dev/null @@ -1,331 +0,0 @@ --- Localize globals -local assert, error, ipairs, math, minetest, modlib, pairs, setmetatable, table, tonumber, tostring, type = assert, error, ipairs, math, minetest, modlib, pairs, setmetatable, table, tonumber, tostring, type - --- Set environment -local _ENV = {} -setfenv(1, _ENV) - -local metatable = {__index = _ENV} - -function new(def) - -- TODO type inference, sanity checking etc. - return setmetatable(def, metatable) -end - -local function field_name_to_title(name) - local title = modlib.text.split(name, "_") - title[1] = modlib.text.upper_first(title[1]) - return table.concat(title, " ") -end - -function generate_settingtypes(self) - local typ = self.type - local settingtype, type_args - self.title = self.title or field_name_to_title(self.name) - self._level = self._level or 0 - local default = self.default - if typ == "boolean" then - settingtype = "bool" - default = default and "true" or "false" - elseif typ == "string" then - settingtype = "string" - if self.values then - local values = {} - for value in pairs(self.values) do - if value:find"," then - values = nil - break - end - table.insert(values, value) - end - if values then - settingtype = "enum" - type_args = table.concat(values, ",") - end - end - elseif typ == "number" then - settingtype = self.int and "int" or "float" - if self.range and (self.range.min or self.range.max) then - -- TODO handle exclusive min/max - type_args = (self.int and "%d %d" or "%f %f"):format(self.range.min or (2 ^ -30), self.range.max or (2 ^ 30)) - end - elseif typ == "table" then - local settings = {} - if self._level > 0 then - -- HACK: Minetest automatically adds the modname - -- TODO simple names (not modname.field.other_field) - settings = {"[" .. ("*"):rep(self._level - 1) .. self.name .. "]"} - end - local function setting(key, value_scheme) - key = tostring(key) - assert(not key:find("[=%.%s]")) - value_scheme.name = self.name .. "." .. key - value_scheme.title = value_scheme.title or self.title .. " " .. field_name_to_title(key) - value_scheme._level = self._level + 1 - table.insert(settings, generate_settingtypes(value_scheme)) - end - local keys = {} - for key in pairs(self.entries or {}) do - table.insert(keys, key) - end - table.sort(keys, function(key, other_key) - -- Force leaves before subtrees to prevent them from being accidentally graphically treated as part of the subtree - local is_subtree = self.entries[key].type == "table" - local other_is_subtree = self.entries[other_key].type == "table" - if is_subtree ~= other_is_subtree then - return not is_subtree - end - return key < other_key - end) - for _, key in ipairs(keys) do - setting(key, self.entries[key]) - end - return table.concat(settings, "\n\n") - end - if not typ then - return "" - end - local description = self.description - -- TODO extend description by range etc.? - -- TODO enum etc. support - if description then - if type(description) ~= "table" then - description = {description} - end - description = "# " .. table.concat(description, "\n# ") .. "\n" - else - description = "" - end - return description .. self.name .. " (" .. self.title .. ") " .. settingtype .. " " .. (default or "") .. (type_args and (" " .. type_args) or "") -end - -function generate_markdown(self) - -- TODO address redundancies - local function description(lines) - local description = self.description - if description then - if type(description) ~= "table" then - table.insert(lines, description) - else - modlib.table.append(lines, description) - end - end - end - local typ = self.type - self.title = self.title or field_name_to_title(self._md_name) - self._md_level = self._md_level or 1 - if typ == "table" then - local settings = {} - description(settings) - -- TODO generate Markdown for key/value-checks - local function setting(key, value_scheme) - value_scheme._md_name = key - value_scheme.title = value_scheme.title or self.title .. " " .. field_name_to_title(key) - value_scheme._md_level = self._md_level + 1 - table.insert(settings, table.concat(modlib.table.repetition("#", self._md_level)) .. " `" .. key .. "`") - table.insert(settings, "") - table.insert(settings, generate_markdown(value_scheme)) - table.insert(settings, "") - end - local keys = {} - for key in pairs(self.entries or {}) do - table.insert(keys, key) - end - table.sort(keys) - for _, key in ipairs(keys) do - setting(key, self.entries[key]) - end - return table.concat(settings, "\n") - end - if not typ then - return "" - end - local lines = {} - description(lines) - local function line(text) - table.insert(lines, "* " .. text) - end - table.insert(lines, "") - line("Type: " .. self.type) - if self.default ~= nil then - line("Default: `" .. tostring(self.default) .. "`") - end - if self.int then - line"Integer" - elseif self.list then - line"List" - end - if self.infinity then - line"Infinities allowed" - end - if self.nan then - line"Not-a-Number (NaN) allowed" - end - if self.range then - if self.range.min then - line(">= `" .. self.range.min .. "`") - elseif self.range.min_exclusive then - line("> `" .. self.range.min_exclusive .. "`") - end - if self.range.max then - line("<= `" .. self.range.max .. "`") - elseif self.range.max_exclusive then - line("< `" .. self.range.max_exclusive .. "`") - end - end - if self.values then - line("Possible values:") - for value in pairs(self.values) do - table.insert(lines, " * " .. value) - end - end - return table.concat(lines, "\n") -end - -function settingtypes(self) - self.settingtypes = self.settingtypes or generate_settingtypes(self) - return self.settingtypes -end - -function load(self, override, params) - local converted - if params.convert_strings and type(override) == "string" then - converted = true - if self.type == "boolean" then - if override == "true" then - override = true - elseif override == "false" then - override = false - end - elseif self.type == "number" then - override = tonumber(override) - else - converted = false - end - end - if override == nil and not converted then - if self.type == "table" and self.default == nil then - override = {} - else - return self.default - end - end - local _error = error - local function format_error(typ, ...) - if typ == "type" then - return "mismatched type: expected " .. self.type ..", got " .. type(override) .. (converted and " (converted)" or "") - end - if typ == "range" then - local conditions = {} - local function push(condition, bound) - if self.range[bound] then - table.insert(conditions, " " .. condition .. " " .. minetest.write_json(self.range[bound])) - end - end - push(">", "min_exclusive") - push(">=", "min") - push("<", "max_exclusive") - push("<=", "max") - return "out of range: expected value" .. table.concat(conditions, " and") - end - if typ == "int" then - return "expected integer" - end - if typ == "infinity" then - return "expected no infinity" - end - if typ == "nan" then - return "expected no nan" - end - if typ == "required" then - local key = ... - return "required field " .. minetest.write_json(key) .. " missing" - end - if typ == "additional" then - local key = ... - return "superfluous field " .. minetest.write_json(key) - end - if typ == "list" then - return "not a list" - end - if typ == "values" then - return "expected one of " .. minetest.write_json(modlib.table.keys(self.values)) .. ", got " .. minetest.write_json(override) - end - _error("unknown error type") - end - local function error(type, ...) - if params.error_message then - local formatted = format_error(type, ...) - _error("Invalid value: " .. (self.name and (self.name .. ": ") or "") .. formatted) - end - _error{ - type = type, - self = self, - override = override, - converted = converted - } - end - local function assert(value, ...) - if not value then - error(...) - end - return value - end - assert(self.type == type(override), "type") - if self.type == "number" or self.type == "string" then - if self.range then - if self.range.min then - assert(self.range.min <= override, "range") - elseif self.range.min_exclusive then - assert(self.range.min_exclusive < override, "range") - end - if self.range.max then - assert(self.range.max >= override, "range") - elseif self.range.max_exclusive then - assert(self.range.max_exclusive > override, "range") - end - end - if self.type == "number" then - assert((not self.int) or (override % 1 == 0), "int") - assert(self.infinity or math.abs(override) ~= math.huge, "infinity") - assert(self.nan or override == override, "nan") - end - elseif self.type == "table" then - if self.keys then - for key, value in pairs(override) do - override[load(self.keys, key, params)], override[key] = value, nil - end - end - if self.values then - for key, value in pairs(override) do - override[key] = load(self.values, value, params) - end - end - if self.entries then - for key, schema in pairs(self.entries) do - if schema.required and override[key] == nil then - error("required", key) - end - override[key] = load(schema, override[key], params) - end - if self.additional == false then - for key in pairs(override) do - if self.entries[key] == nil then - error("additional", key) - end - end - end - end - assert((not self.list) or modlib.table.count(override) == #override, "list") - end - -- Apply the values check only for primitive types where table indexing is by value; - -- the `values` field has a different meaning for tables (constraint all values must fulfill) - if self.type ~= "table" then - assert((not self.values) or self.values[override], "values") - end - if self.func then self.func(override) end - return override -end - --- Export environment -return _ENV \ No newline at end of file diff --git a/mods/modlib/table.lua b/mods/modlib/table.lua deleted file mode 100644 index 14cc307b..00000000 --- a/mods/modlib/table.lua +++ /dev/null @@ -1,889 +0,0 @@ --- Localize globals -local assert, ipairs, math, next, pairs, rawget, rawset, getmetatable, setmetatable, select, string, table, type - = assert, ipairs, math, next, pairs, rawget, rawset, getmetatable, setmetatable, select, string, table, type - -local lt = modlib.func.lt - --- Set environment -local _ENV = {} -setfenv(1, _ENV) - --- Empty table -empty = {} - --- Table helpers - -function from_iterator(...) - local table = {} - for key, value in ... do - table[key] = value - end - return table -end - -function default(table, value) - return setmetatable(table, { - __index = function() - return value - end, - }) -end - -function map_index(table, func) - local mapping_metatable = { - __index = function(table, key) - return rawget(table, func(key)) - end, - __newindex = function(table, key, value) - rawset(table, func(key), value) - end - } - return setmetatable(table, mapping_metatable) -end - -function set_case_insensitive_index(table) - return map_index(table, string.lower) -end - ---+ nilget(a, "b", "c") == a?.b?.c -function nilget(value, ...) - local n = select("#", ...) - for i = 1, n do - if value == nil then return nil end - value = value[select(i, ...)] - end - return value -end - -deepget = nilget - ---+ `deepset(a, "b", "c", d)` is the same as `a.b = a.b ?? {}; a.b.c = d` -function deepset(table, ...) - local n = select("#", ...) - for i = 1, n - 2 do - local key = select(i, ...) - local parent = table - table = parent[key] - if table == nil then - table = {} - parent[key] = table - end - end - table[select(n - 1, ...)] = select(n, ...) -end - --- Fisher-Yates -function shuffle(table) - for index = 1, #table - 1 do - local index_2 = math.random(index, #table) - table[index], table[index_2] = table[index_2], table[index] - end - return table -end - -local rope_metatable = {__index = { - write = function(self, text) - table.insert(self, text) - end, - to_text = function(self) - return table.concat(self) - end -}} ---> rope with simple metatable (:write(text) and :to_text()) -function rope(table) - return setmetatable(table or {}, rope_metatable) -end - -local rope_len_metatable = {__index = { - write = function(self, text) - self.len = self.len + text:len() - end -}} ---> rope for determining length of text supporting `:write(text)` and `.len` to get the length of written text -function rope_len(len) - return setmetatable({len = len or 0}, rope_len_metatable) -end - -function is_circular(table) - assert(type(table) == "table") - local known = {} - local function _is_circular(value) - if type(value) ~= "table" then - return false - end - if known[value] then - return true - end - known[value] = true - for key, value in pairs(value) do - if _is_circular(key) or _is_circular(value) then - return true - end - end - end - return _is_circular(table) -end - ---+ Simple table equality check. Stack overflow if tables are too deep or circular. ---+ Use `is_circular(table)` to check whether a table is circular. ---> Equality of noncircular tables if `table` and `other_table` are tables ---> `table == other_table` else -function equals_noncircular(table, other_table) - local is_equal = table == other_table - if is_equal or type(table) ~= "table" or type(other_table) ~= "table" then - return is_equal - end - if #table ~= #other_table then - return false - end - local table_keys = {} - for key, value in pairs(table) do - local value_2 = other_table[key] - if not equals_noncircular(value, value_2) then - if type(key) == "table" then - table_keys[key] = value - else - return false - end - end - end - for other_key, other_value in pairs(other_table) do - if type(other_key) == "table" then - local found - for table, value in pairs(table_keys) do - if equals_noncircular(other_key, table) and equals_noncircular(other_value, value) then - table_keys[table] = nil - found = true - break - end - end - if not found then - return false - end - else - if table[other_key] == nil then - return false - end - end - end - return true -end - -equals = equals_noncircular - ---+ Table equality check properly handling circular tables - tables are equal as long as they provide equal key/value-pairs ---> Table content equality if `table` and `other_table` are tables ---> `table == other_table` else -function equals_content(table, other_table) - local equal_tables = {} - local function _equals(table, other_equal_table) - local function set_equal_tables(value) - equal_tables[table] = equal_tables[table] or {} - equal_tables[table][other_equal_table] = value - return value - end - local is_equal = table == other_equal_table - if is_equal or type(table) ~= "table" or type(other_equal_table) ~= "table" then - return is_equal - end - if #table ~= #other_equal_table then - return set_equal_tables(false) - end - local lookup_equal = (equal_tables[table] or {})[other_equal_table] - if lookup_equal ~= nil then - return lookup_equal - end - -- Premise - set_equal_tables(true) - local table_keys = {} - for key, value in pairs(table) do - local other_value = other_equal_table[key] - if not _equals(value, other_value) then - if type(key) == "table" then - table_keys[key] = value - else - return set_equal_tables(false) - end - end - end - for other_key, other_value in pairs(other_equal_table) do - if type(other_key) == "table" then - local found = false - for table_key, value in pairs(table_keys) do - if _equals(table_key, other_key) and _equals(value, other_value) then - table_keys[table_key] = nil - found = true - -- Breaking is fine as per transitivity - break - end - end - if not found then - return set_equal_tables(false) - end - else - if table[other_key] == nil then - return set_equal_tables(false) - end - end - end - return true - end - return _equals(table, other_table) -end - ---+ Table equality check: content has to be equal, relations between tables as well ---+ The only difference may be in the memory addresses ("identities") of the (sub)tables ---+ Performance may suffer if the tables contain table keys ---+ equals(table, copy(table)) is true ---> equality (same tables after table reference substitution) of circular tables if `table` and `other_table` are tables ---> `table == other_table` else -function equals_references(table, other_table) - local function _equals(table, other_table, equal_refs) - if equal_refs[table] then - return equal_refs[table] == other_table - end - local is_equal = table == other_table - -- this check could be omitted if table key equality is being checked - if type(table) ~= "table" or type(other_table) ~= "table" then - return is_equal - end - if is_equal then - equal_refs[table] = other_table - return true - end - -- Premise: table = other table - equal_refs[table] = other_table - local table_keys = {} - for key, value in pairs(table) do - if type(key) == "table" then - table_keys[key] = value - else - local other_value = other_table[key] - if not _equals(value, other_value, equal_refs) then - return false - end - end - end - local other_table_keys = {} - for other_key, other_value in pairs(other_table) do - if type(other_key) == "table" then - other_table_keys[other_key] = other_value - elseif table[other_key] == nil then - return false - end - end - local function _next(current_key, equal_refs, available_keys) - local key, value = next(table_keys, current_key) - if key == nil then - return true - end - for other_key, other_value in pairs(other_table_keys) do - local copy_equal_refs = shallowcopy(equal_refs) - if _equals(key, other_key, copy_equal_refs) and _equals(value, other_value, copy_equal_refs) then - local copy_available_keys = shallowcopy(available_keys) - copy_available_keys[other_key] = nil - if _next(key, copy_equal_refs, copy_available_keys) then - return true - end - end - end - return false - end - return _next(nil, equal_refs, other_table_keys) - end - return _equals(table, other_table, {}) -end - --- Supports circular tables; does not support table keys ---> `true` if a mapping of references exists, `false` otherwise -function same(a, b) - local same = {} - local function is_same(a, b) - if type(a) ~= "table" or type(b) ~= "table" then - return a == b - end - if same[a] or same[b] then - return same[a] == b and same[b] == a - end - if a == b then - return true - end - - same[a], same[b] = b, a - local count = 0 - for k, v in pairs(a) do - count = count + 1 - assert(type(k) ~= "table", "table keys not supported") - if not is_same(v, b[k], same) then - return false - end - end - for _ in pairs(b) do - count = count - 1 - if count < 0 then - return false - end - end - return true - end - return is_same(a, b) -end - -function shallowcopy( - table -- table to copy - , strip_metatables -- whether to strip metatables; falsy by default; metatables are not copied -) - if type(table) ~= "table" then - return table - end - - local copy = {} - if not strip_metatables then - setmetatable(copy, getmetatable(table)) - end - for key, value in pairs(table) do - copy[key] = value - end - return copy -end - -function deepcopy_tree( - table -- table; may not contain circular references; cross references will be copied multiple times - , strip_metatables -- whether to strip metatables; falsy by default; metatables are not copied -) - if type(table) ~= "table" then - return table - end - - local copy = {} - if not strip_metatables then - setmetatable(copy, getmetatable(table)) - end - for key, value in pairs(table) do - copy[deepcopy_tree(key)] = deepcopy_tree(value) - end - return copy -end -deepcopy_noncircular = deepcopy_tree - -function deepcopy( - table -- table to copy; reference equality will be preserved - , strip_metatables -- whether to strip metatables; falsy by default; metatables are not copied -) - local copies = {} - local function _deepcopy(table) - local copy = copies[table] - if copy then - return copy - end - copy = {} - if not strip_metatables then - setmetatable(copy, getmetatable(table)) - end - copies[table] = copy - local function _copy(value) - if type(value) ~= "table" then - return value - end - - if copies[value] then - return copies[value] - end - - return _deepcopy(value) - end - for key, value in pairs(table) do - copy[_copy(key)] = _copy(value) - end - return copy - end - return _deepcopy(table) -end - -copy = deepcopy - -function count(table) - local count = 0 - for _ in pairs(table) do - count = count + 1 - end - return count -end - -function count_equals(table, count) - local k - for _ = 1, count do - k = next(table, k) - if k == nil then return false end -- less than n keys - end - return next(table, k) == nil -- no (n + 1)th entry -end - -function is_empty(table) - return next(table) == nil -end - -function clear(table) - for k in pairs(table) do - table[k] = nil - end -end - -function foreach(table, func) - for k, v in pairs(table) do - func(k, v) - end -end - -function deep_foreach_any(table, func) - local seen = {} - local function visit(value) - func(value) - if type(value) == "table" then - if seen[value] then return end - seen[value] = true - for k, v in pairs(value) do - visit(k) - visit(v) - end - end - end - visit(table) -end - --- Recursively counts occurences of objects (non-primitives including strings) in a table. -function count_objects(value) - local counts = {} - if value == nil then - -- Early return for nil - return counts - end - local function count_values(value) - local type_ = type(value) - if type_ == "boolean" or type_ == "number" then return end - local count = counts[value] - counts[value] = (count or 0) + 1 - if not count and type_ == "table" then - for k, v in pairs(value) do - count_values(k) - count_values(v) - end - end - end - count_values(value) - return counts -end - -function foreach_value(table, func) - for _, v in pairs(table) do - func(v) - end -end - -function call(table, ...) - for _, func in pairs(table) do - func(...) - end -end - -function icall(table, ...) - for _, func in ipairs(table) do - func(...) - end -end - -function foreach_key(table, func) - for key, _ in pairs(table) do - func(key) - end -end - -function map(table, func) - for key, value in pairs(table) do - table[key] = func(value) - end - return table -end - -map_values = map - -function map_keys(table, func) - local new_tab = {} - for key, value in pairs(table) do - new_tab[func(key)] = value - end - return new_tab -end - -function process(tab, func) - local results = {} - for key, value in pairs(tab) do - table.insert(results, func(key, value)) - end - return results -end - -function call(funcs, ...) - for _, func in ipairs(funcs) do - func(...) - end -end - -function find(list, value) - for index, other_value in pairs(list) do - if value == other_value then - return index - end - end -end - -contains = find - -function to_add(table, after_additions) - local additions = {} - for key, value in pairs(after_additions) do - if table[key] ~= value then - additions[key] = value - end - end - return additions -end - -difference = to_add - -function deep_to_add(table, after_additions) - local additions = {} - for key, value in pairs(after_additions) do - if type(table[key]) == "table" and type(value) == "table" then - local sub_additions = deep_to_add(table[key], value) - if next(sub_additions) ~= nil then - additions[key] = sub_additions - end - elseif table[key] ~= value then - additions[key] = value - end - end - return additions -end - -function add_all(table, additions) - for key, value in pairs(additions) do - table[key] = value - end - return table -end - -function deep_add_all(table, additions) - for key, value in pairs(additions) do - if type(table[key]) == "table" and type(value) == "table" then - deep_add_all(table[key], value) - else - table[key] = value - end - end - return table -end - -function complete(table, completions) - for key, value in pairs(completions) do - if table[key] == nil then - table[key] = value - end - end - return table -end - -function deepcomplete(table, completions) - for key, value in pairs(completions) do - if table[key] == nil then - table[key] = value - elseif type(table[key]) == "table" and type(value) == "table" then - deepcomplete(table[key], value) - end - end - return table -end - -function merge(table, other_table, merge_func) - merge_func = merge_func or merge - local res = {} - for key, value in pairs(table) do - local other_value = other_table[key] - if other_value == nil then - res[key] = value - else - res[key] = merge_func(value, other_value) - end - end - for key, value in pairs(other_table) do - if table[key] == nil then - res[key] = value - end - end - return res -end - -function merge_tables(table, other_table) - return add_all(shallowcopy(table), other_table) -end - -union = merge_tables - -function intersection(table, other_table) - local result = {} - for key, value in pairs(table) do - if other_table[key] then - result[key] = value - end - end - return result -end - -function append(table, other_table) - local length = #table - for index, value in ipairs(other_table) do - table[length + index] = value - end - return table -end - -function keys(table) - local keys = {} - for key, _ in pairs(table) do - keys[#keys + 1] = key - end - return keys -end - -function values(table) - local values = {} - for _, value in pairs(table) do - values[#values + 1] = value - end - return values -end - -function flip(table) - local flipped = {} - for key, value in pairs(table) do - flipped[value] = key - end - return flipped -end - -function set(table) - local flipped = {} - for _, value in pairs(table) do - flipped[value] = true - end - return flipped -end - -function unique(table) - return keys(set(table)) -end - -function ivalues(table) - local index = 0 - return function() - index = index + 1 - return table[index] - end -end - -function rpairs(table) - local index = #table - return function() - if index >= 1 then - local value = table[index] - index = index - 1 - if value ~= nil then - return index + 1, value - end - end - end -end - --- Iterates the hash (= non-list) part of the table. The list part may not be modified while iterating. -function hpairs(table) - local len = #table -- length only has to be determined once as hnext is a closure - local function hnext(key) - local value - key, value = next(table, key) - if type(key) == "number" and key % 1 == 0 and key >= 1 and key <= len then -- list entry, skip - return hnext(key) - end - return key, value - end - return hnext -end - -function min_key(table, less_than) - less_than = less_than or lt - local min_key = next(table) - if min_key == nil then - return -- empty table - end - for candidate_key in next, table, min_key do - if less_than(candidate_key, min_key) then - min_key = candidate_key - end - end - return min_key -end - -function min_value(table, less_than) - less_than = less_than or lt - local min_key, min_value = next(table) - if min_key == nil then - return -- empty table - end - for candidate_key, candidate_value in next, table, min_key do - if less_than(candidate_value, min_value) then - min_key, min_value = candidate_key, candidate_value - end - end - return min_value, min_key -end - --- TODO move all of the below functions to modlib.list eventually - ---! deprecated -function default_comparator(value, other_value) - if value == other_value then - return 0 - end - if value > other_value then - return 1 - end - return -1 -end - ---! deprecated, use `binary_search(list, value, less_than)` instead ---> index if element found ---> -index for insertion if not found -function binary_search_comparator(comparator) - return function(list, value) - local min, max = 1, #list - while min <= max do - local pivot = min + math.floor((max - min) / 2) - local element = list[pivot] - local compared = comparator(value, element) - if compared == 0 then - return pivot - elseif compared > 0 then - min = pivot + 1 - else - max = pivot - 1 - end - end - return -min - end -end - -function binary_search( - list -- sorted list - , value -- value to be be searched for - , less_than -- function(a, b) return a < b end -) - less_than = less_than or lt - local min, max = 1, #list - while min <= max do - local mid = math.floor((min + max) / 2) - local element = list[mid] - if less_than(value, element) then - max = mid - 1 - elseif less_than(element, value) then - min = mid + 1 - else -- neither smaller nor larger => must be equal - return mid -- index if found - end - end - return nil, min -- nil, insertion index if not found -end - ---> whether the list is sorted in ascending order -function is_sorted(list, less_than --[[function(a, b) return a < b end]]) - less_than = less_than or function(a, b) return a < b end - for index = 2, #list do - if less_than(list[index], list[index - 1]) then - return false - end - end - return true -end - -function reverse(table) - local len = #table - for index = 1, len / 2 do - local index_from_end = len + 1 - index - table[index_from_end], table[index] = table[index], table[index_from_end] - end - return table -end - -function repetition(value, count) - local table = {} - for index = 1, count do - table[index] = value - end - return table -end - -function slice(list, from, to) - from, to = from or 1, to or #list - local res = {} - for i = from, to do - res[#res + 1] = list[i] - end - return res -end - --- JS-ish array splice -function splice( - list, -- to modify - start, -- index (inclusive) for where to start modifying the array (defaults to after the last element) - delete_count, -- how many elements to remove (defaults to `0`) - ... -- elements to insert after `start` -) - start, delete_count = start or (#list + 1), delete_count or 0 - if start < 0 then - start = start + #list + 1 - end - - local add_count = select("#", ...) - local shift = add_count - delete_count - if shift > 0 then -- shift up - for i = #list, start + delete_count, -1 do - list[i + shift] = list[i] - end - elseif shift < 0 then -- shift down - for i = start, #list do - list[i] = list[i - shift] - end - end - - -- Add elements - for i = 1, add_count do - list[start + i - 1] = select(i, ...) - end - - return list -end - --- Equivalent to to_list[to], ..., to_list[to + count] = from_list[from], ..., from_list[from + count] -function move(from_list, from, to, count, to_list) - from, to, count, to_list = from or 1, to or 1, count or #from_list, to_list or from_list - if to_list ~= from_list or to < from then - for i = 0, count do - to_list[to + i] = from_list[from + i] - end - else -- iterate in reverse order - for i = count, 0, -1 do - to_list[to + i] = from_list[from + i] - end - end -end - --- Export environment -return _ENV \ No newline at end of file diff --git a/mods/modlib/tex.lua b/mods/modlib/tex.lua deleted file mode 100644 index 006cdede..00000000 --- a/mods/modlib/tex.lua +++ /dev/null @@ -1,386 +0,0 @@ ---[[ - This file does not follow the usual conventions; - it duplicates some code for performance reasons. - - In particular, use of `modlib.minetest.colorspec` is avoided. - - Most methods operate *in-place* (imperative method names) - rather than returning a modified copy (past participle method names). - - Outside-facing methods consistently use 1-based indexing; indices are inclusive. -]] - -local min, max, floor, ceil = math.min, math.max, math.floor, math.ceil -local function round(x) return floor(x + 0.5) end -local function clamp(x, mn, mx) return max(min(x, mx), mn) end - --- ARGB handling utilities - -local function unpack_argb(argb) - return floor(argb / 0x1000000), - floor(argb / 0x10000) % 0x100, - floor(argb / 0x100) % 0x100, - argb % 0x100 -end - -local function pack_argb(a, r, g, b) - local argb = (((a * 0x100 + r) * 0x100) + g) * 0x100 + b - return argb -end - -local function round_argb(a, r, g, b) - return round(a), round(r), round(g), round(b) -end - -local function scale_0_1_argb(a, r, g, b) - return a / 255, r / 255, g / 255, b / 255 -end - -local function scale_0_255_argb(a, r, g, b) - return a * 255, r * 255, g * 255, b * 255 -end - -local tex = {} -local metatable = {__index = tex} - -function metatable:__eq(other) - if self.w ~= other.w or self.h ~= other.h then return false end - for i = 1, #self do if self[i] ~= other[i] then return false end end - return true -end - -function tex:new() - return setmetatable(self, metatable) -end - -function tex.filled(w, h, argb) - local self = {w = w, h = h} - for i = 1, w*h do - self[i] = argb - end - return tex.new(self) -end - -function tex:copy() - local copy = {w = self.w, h = self.h} - for i = 1, #self do - copy[i] = self[i] - end - return tex.new(copy) -end - --- Reading & writing - -function tex.read_png_string(str) - local stream = modlib.text.inputstream(str) - local png = modlib.minetest.decode_png(stream) - assert(stream:read(1) == nil, "eof expected") - modlib.minetest.convert_png_to_argb8(png) - png.data.w, png.data.h = png.width, png.height - return tex.new(png.data) -end - -function tex.read_png(path) - local png - modlib.file.with_open(path, "rb", function(f) - png = modlib.minetest.decode_png(f) - assert(f:read(1) == nil, "eof expected") - end) - modlib.minetest.convert_png_to_argb8(png) - png.data.w, png.data.h = png.width, png.height - return tex.new(png.data) -end - -function tex:write_png_string() - return modlib.minetest.encode_png(self.w, self.h, self) -end - -function tex:write_png(path) - modlib.file.write_binary(path, self:write_png_string()) -end - -function tex:fill(sx, sy, argb) - local w, h = self.w, self.h - for y = sy, h do - local i = (y - 1) * w + sx - for _ = sx, w do - self[i] = argb - i = i + 1 - end - end -end - -function tex:in_bounds(x, y) - return x >= 1 and y >= 1 and x <= self.w and y <= self.h -end - -function tex:get_argb_packed(x, y) - return self[(y - 1) * self.w + x] -end - -function tex:get_argb(x, y) - return unpack_argb(self[(y - 1) * self.w + x]) -end - -function tex:set_argb_packed(x, y, argb) - self[(y - 1) * self.w + x] = argb -end - -function tex:set_argb(x, y, a, r, g, b) - self[(y - 1) * self.w + x] = pack_argb(a, r, g, b) -end - -function tex:map_argb(func) - for i = 1, #self do - self[i] = pack_argb(func(unpack_argb(self[i]))) - end -end - -local function blit(s, x, y, t, o) - local sw, sh = s.w, s.h - local tw, th = t.w, t.h - -- Restrict to overlapping region - x, y = clamp(x, 1, sw), clamp(y, 1, sh) - local min_tx, min_ty = max(1, 2 - x), max(1, 2 - y) - local max_tx, max_ty = min(tw, sw - x + 1), min(th, sh - y + 1) - for ty = min_ty, max_ty do - local ti, si = (ty - 1) * tw, (y + ty - 2) * sw + x - 1 - for _ = min_tx, max_tx do - ti, si = ti + 1, si + 1 - local sa, sr, sg, sb = scale_0_1_argb(unpack_argb(s[si])) - if sa == 1 or not o then -- HACK because of dirty `[cracko` - local ta, tr, tg, tb = scale_0_1_argb(unpack_argb(t[ti])) - -- "`t` over `s`" (Porter-Duff-Algorithm) - local sata = sa * (1 - ta) - local ra = ta + sata - assert(ra > 0 or (sa == 0 and ta == 0)) - if ra > 0 then - s[si] = pack_argb(round_argb(scale_0_255_argb( - ra, - (ta * tr + sata * sr) / ra, - (ta * tg + sata * sg) / ra, - (ta * tb + sata * sb) / ra - ))) - end - end - end - end -end - --- Blitting with proper alpha blending. -function tex.blit(s, x, y, t) - return blit(s, x, y, t, false) -end - --- Blit, but only on fully opaque base pixels. Only `[cracko` uses this. -function tex.blito(s, x, y, t) - return blit(s, x, y, t, true) -end - -function tex.combine_argb(s, t, cf) - assert(#s == #t) - for i = 1, #s do - s[i] = cf(s[i], t[i]) - end -end - --- See https://github.com/TheAlgorithms/Lua/blob/162c4c59f5514c6115e0add8a2b4d56afd6d3204/src/bit/uint53/and.lua --- TODO (?) optimize fallback band using caching, move somewhere else -local band = bit and bit.band or function(n, m) - local res = 0 - local bit = 1 - while n * m ~= 0 do -- while both are nonzero - local n_bit, m_bit = n % 2, m % 2 -- extract LSB - res = res + (n_bit * m_bit) * bit -- add AND of LSBs - n, m = (n - n_bit) / 2, (m - m_bit) / 2 -- remove LSB from n & m - bit = bit * 2 -- next bit - end - return res -end - -function tex.band(s, t) - return s:combine_argb(t, band) -end - -function tex.hardlight_blend(s, t) - return s:combine_argb(t, function(sargb, targb) - local sa, sr, sg, sb = scale_0_1_argb(unpack_argb(sargb)) - local _, tr, tg, tb = scale_0_1_argb(unpack_argb(targb)) - return pack_argb(round_argb(scale_0_255_argb( - sa, - sr < 0.5 and 2*sr*tr or 1 - 2*(1-sr)*(1-tr), - sr < 0.5 and 2*sg*tg or 1 - 2*(1-sg)*(1-tg), - sr < 0.5 and 2*sb*tb or 1 - 2*(1-sb)*(1-tb) - ))) - end) -end - -function tex:brighten() - return self:map_argb(function(a, r, g, b) - return round_argb((255 + a) / 2, (255 + r) / 2, (255 + g) / 2, (255 + b) / 2) - end) -end - -function tex:noalpha() - for i = 1, #self do - self[i] = 0xFF000000 + self[i] % 0x1000000 - end -end - -function tex:makealpha(r, g, b) - local mrgb = r * 0x10000 + g * 0x100 + b - for i = 1, #self do - local rgb = self[i] % 0x1000000 - if rgb == mrgb then - self[i] = rgb - end - end -end - -function tex:opacity(factor) - for i = 1, #self do - self[i] = round(floor(self[i] / 0x1000000) * factor) * 0x1000000 + self[i] % 0x1000000 - end -end - -function tex:invert(ir, ig, ib, ia) - return self:map_argb(function(a, r, g, b) - if ia then a = 255 - a end - if ir then r = 255 - r end - if ig then g = 255 - g end - if ib then b = 255 - b end - return a, r, g, b - end) -end - -function tex:multiply_rgb(r, g, b) - return self:map_argb(function(sa, sr, sg, sb) - return round_argb(sa, r * sr, g * sg, b * sb) - end) -end - -function tex:screen_blend_rgb(r, g, b) - return self:map_argb(function(sa, sr, sg, sb) - return round_argb(sa, - 255 - ((255 - sr) * (255 - r)) / 255, - 255 - ((255 - sg) * (255 - g)) / 255, - 255 - ((255 - sb) * (255 - b)) / 255) - end) -end - -function tex:colorize(cr, cg, cb, ratio) - return self:map_argb(function(a, r, g, b) - local rat = ratio == "alpha" and a or ratio - return round_argb( - a, - rat * r + (1 - rat) * cr, - rat * g + (1 - rat) * cg, - rat * b + (1 - rat) * cb - ) - end) -end - -function tex:crop(from_x, from_y, to_x, to_y) - local w = self.w - local i = 1 - for y = from_y, to_y do - local j = (y - 1) * w + from_x - for _ = from_x, to_x do - self[i] = self[j] - i, j = i + 1, j + 1 - end - end - -- Remove remaining pixels - for j = i, #self do self[j] = nil end - self.w, self.h = to_x - from_x + 1, to_y - from_y + 1 -end - -function tex:flip_x() - for y = 1, self.h do - local i = (y - 1) * self.w - local j = i + self.w + 1 - while i < j do - i, j = i + 1, j - 1 - self[i], self[j] = self[j], self[i] - end - end -end - -function tex:flip_y() - for x = 1, self.w do - local i, j = x, (self.h - 1) * self.w + x - while i < j do - i, j = i + self.w, j - self.w - self[i], self[j] = self[j], self[i] - end - end -end - ---> copy of the texture, rotated 90 degrees clockwise -function tex:rotated_90() - local w, h = self.w, self.h - local t = {w = h, h = w} - local i = 0 - for y = 1, w do - for x = 1, h do - i = i + 1 - t[i] = self[(h-x)*w + y] - end - end - t = tex.new(t) - return t -end - --- Uses box sampling. Hard to optimize. --- TODO (...) interpolate box samples; match what Minetest does ---> copy of `self` resized to `w` x `h` -function tex:resized(w, h) - --! This function works with 0-based indices. - local sw, sh = self.w, self.h - local fx, fy = sw / w, sh / h - local t = {w = w, h = h} - local i = 0 - for y = 0, h - 1 do - for x = 0, w - 1 do - -- Sample the area - local vy_from = y * fy - local vy_to = vy_from + fy - local vx_from = x * fx - local vx_to = vx_from + fx - - local a, r, g, b = 0, 0, 0, 0 - local pf_sum = 0 - - local function blend(sx, sy, pf) - if pf <= 0 then return end - local sa, sr, sg, sb = unpack_argb(self[sy * sw + sx + 1]) - pf_sum = pf_sum + pf -- TODO (?) eliminate `pf_sum` - sa = sa * pf - a = a + sa - r, g, b = r + sa * sr, g + sa * sg, b + sa * sb - end - - local function srow(sy, pf) - if pf <= 0 then return end - local sx_from, sx_to = ceil(vx_from), floor(vx_to) - for sx = sx_from, sx_to - 1 do blend(sx, sy, pf) end -- whole pixels - -- Pixels at edges - blend(floor(vx_from), sy, pf * (sx_from - vx_from)) - blend(floor(vx_to), sy, pf * (vx_to - sx_to)) - end - - local sy_from, sy_to = ceil(vy_from), floor(vy_to) - for sy = sy_from, sy_to - 1 do srow(sy, 1) end -- whole pixels - -- Pixels at edges - srow(floor(vy_from), sy_from - vy_from) - srow(floor(vy_to), vy_to - sy_to) - if a > 0 then r, g, b = r / a, g / a, b / a end - assert(pf_sum > 0) - i = i + 1 - t[i] = pack_argb(round_argb(a / pf_sum, r, g, b)) - end - end - return tex.new(t) -end - -return tex diff --git a/mods/modlib/text.lua b/mods/modlib/text.lua deleted file mode 100644 index 3fe6226b..00000000 --- a/mods/modlib/text.lua +++ /dev/null @@ -1,189 +0,0 @@ --- Localize globals -local assert, math, modlib, setmetatable, string, table - = assert, math, modlib, setmetatable, string, table - --- Set environment -local _ENV = {} -setfenv(1, _ENV) - -function upper_first(text) return text:sub(1, 1):upper() .. text:sub(2) end - -function lower_first(text) return text:sub(1, 1):lower() .. text:sub(2) end - -function starts_with(text, prefix) return text:sub(1, #prefix) == prefix end - -function ends_with(text, suffix) return text:sub(-#suffix) == suffix end - -function contains(str, substr, plain) - return not not str:find(substr, 1, plain == nil and true or plain) -end - -function trim_spacing(text) - return text:match"^%s*(.-)%s*$" -end - -local inputstream_metatable = { - __index = { - read = function(self, count) - local cursor = self.cursor + 1 - self.cursor = self.cursor + count - local text = self.text:sub(cursor, self.cursor) - return text ~= "" and text or nil - end, - seek = function(self) return self.cursor end - } -} ---> inputstream "handle"; only allows reading characters (given a count), seeking does not accept any arguments -function inputstream(text) - return setmetatable({text = text, cursor = 0}, inputstream_metatable) -end - -function hexdump(text) - local dump = {} - for index = 1, text:len() do - dump[index] = ("%02X"):format(text:byte(index)) - end - return table.concat(dump) -end - -function spliterator(str, delim, plain) - assert(delim ~= "") - local last_delim_end = 0 - - -- Iterator of possibly empty substrings between two matches of the delimiter - -- To exclude empty strings, filter the iterator or use `:gmatch"[...]+"` instead - return function() - if not last_delim_end then - return - end - - local delim_start, delim_end = str:find(delim, last_delim_end + 1, plain) - local substr - if delim_start then - substr = str:sub(last_delim_end + 1, delim_start - 1) - else - substr = str:sub(last_delim_end + 1) - end - last_delim_end = delim_end - return substr - end -end - -function split(text, delimiter, limit, plain) - limit = limit or math.huge - local parts = {} - local occurences = 1 - local last_index = 1 - local index = string.find(text, delimiter, 1, plain) - while index and occurences < limit do - table.insert(parts, string.sub(text, last_index, index - 1)) - last_index = index + string.len(delimiter) - index = string.find(text, delimiter, index + string.len(delimiter), plain) - occurences = occurences + 1 - end - table.insert(parts, string.sub(text, last_index)) - return parts -end - -function split_without_limit(text, delimiter, plain) - return split(text, delimiter, nil, plain) -end - -split_unlimited = split_without_limit - ---! Does not support Macintosh pre-OSX CR-only line endings ---! Deprecated in favor of the `lines` iterator below -function split_lines(text, limit) - return modlib.text.split(text, "\r?\n", limit, true) -end - --- When reading from a file, directly use `io.lines` instead --- Lines are possibly empty substrings separated by CR, LF or CRLF --- A trailing linefeed is ignored -function lines(str) - local line_start = 1 - -- Line iterator - return function() - if line_start > #str then - return - end - local linefeed_start, _, linefeed = str:find("([\r\n][\r\n]?)", line_start) - local line - if linefeed_start then - line = str:sub(line_start, linefeed_start - 1) - line_start = linefeed_start + (linefeed == "\r\n" and 2 or 1) - else - line = str:sub(line_start) - line_start = #str + 1 - end - return line - end -end - - -local zero = string.byte"0" -local nine = string.byte"9" -local letter_a = string.byte"A" -local letter_f = string.byte"F" - -function is_hexadecimal(byte) - return byte >= zero and byte <= nine or byte >= letter_a and byte <= letter_f -end - -magic_charset = "[" .. ("%^$+-*?.[]()"):gsub(".", "%%%1") .. "]" - -function escape_pattern(text) - return text:gsub(magic_charset, "%%%1") -end - -escape_magic_chars = escape_pattern - -local keywords = modlib.table.set{"and", "break", "do", "else", "elseif", "end", "false", "for", "function", "if", "in", "local", "nil", "not", "or", "repeat", "return", "then", "true", "until", "while"} -keywords["goto"] = true -- Lua 5.2 (LuaJIT) support - -function is_keyword(text) - return keywords[text] -end - -function is_identifier(text) - return (not keywords[text]) and text:match"^[A-Za-z_][A-Za-z%d_]*$" -end - -local function inextchar(text, i) - if i >= #text then return end - i = i + 1 - return i, text:sub(i, i) -end - -function ichars(text, start) - -- Iterator over `index, character` - return inextchar, text, (start or 1) - 1 -end - -local function inextbyte(text, i) - if i >= #text then return end - i = i + 1 - return i, text:byte(i, i) -end - -function ibytes(text, start) - -- Iterator over `index, byte` - return inextbyte, text, (start or 1) - 1 -end - -local function _random_bytes(count) - if count == 0 then return end - return math.random(0, 0xFF), _random_bytes(count - 1) -end - -function random_bytes( - -- number, how many random bytes the string should have, defaults to 1 - -- limited by stack size - count -) - count = count or 1 - return string.char(_random_bytes(count)) -end - --- Export environment -return _ENV diff --git a/mods/modlib/trie.lua b/mods/modlib/trie.lua deleted file mode 100644 index 3399b697..00000000 --- a/mods/modlib/trie.lua +++ /dev/null @@ -1,133 +0,0 @@ --- Localize globals -local math, next, pairs, setmetatable, string, table, unpack = math, next, pairs, setmetatable, string, table, unpack - --- Set environment -local _ENV = {} -setfenv(1, _ENV) - -local metatable = {__index = _ENV} - --- Setting the metatable is fine as it does not contain single-character keys. --- TODO (?) encapsulate in "root" field for better code quality? -function new(table) return setmetatable(table or {}, metatable) end - -function insert(self, word, value, overwrite) - for i = 1, word:len() do - local char = word:sub(i, i) - self[char] = self[char] or {} - self = self[char] - end - local previous_value = self.value - if not previous_value or overwrite then self.value = value or true end - return previous_value -end - -function remove(self, word) - local branch, character = self, word:sub(1, 1) - for i = 1, word:len() - 1 do - local char = word:sub(i, i) - if not self[char] then return end - if self[char].value or next(self, next(self)) then - branch = self - character = char - end - self = self[char] - end - local char = word:sub(word:len()) - if not self[char] then return end - self = self[char] - local previous_value = self.value - self.value = nil - if branch and not next(self) then branch[character] = nil end - return previous_value -end - ---> value if found ---> nil else -function get(self, word) - for i = 1, word:len() do - local char = word:sub(i, i) - self = self[char] - if not self then return end - end - return self.value -end - -function suggestion(self, remainder) - local until_now = {} - local subtries = { [self] = until_now } - local suggestion, value - while next(subtries) do - local new_subtries = {} - local leaves = {} - for trie, word in pairs(subtries) do - if trie.value then table.insert(leaves, { word = word, value = trie.value }) end - end - if #leaves > 0 then - if remainder then - local best_leaves = {} - local best_score = 0 - for _, leaf in pairs(leaves) do - local score = 0 - for i = 1, math.min(#leaf.word, string.len(remainder)) do - -- calculate intersection - if remainder:sub(i, i) == leaf.word[i] then score = score + 1 end - end - if score == best_score then table.insert(best_leaves, leaf) - elseif score > best_score then best_leaves = { leaf } end - end - leaves = best_leaves - end - -- TODO select best instead of random - local leaf = leaves[math.random(1, #leaves)] - suggestion, value = table.concat(leaf.word), leaf.value - break - end - for trie, word in pairs(subtries) do - for char, subtrie in pairs(trie) do - local word = { unpack(word) } - table.insert(word, char) - new_subtries[subtrie] = word - end - end - subtries = new_subtries - end - return suggestion, value -end - ---> value if found ---> nil, suggestion, value of suggestion else -function search(self, word) - for i = 1, word:len() do - local char = word:sub(i, i) - if not self[char] then - local until_now = word:sub(1, i - 1) - local suggestion, value = suggestion(self, word:sub(i)) - return nil, until_now .. suggestion, value - end - self = self[char] - end - local value = self.value - if value then return value end - local until_now = word - local suggestion, value = suggestion(self) - return nil, until_now .. suggestion, value -end - -function find_longest(self, query, query_offset) - local leaf_pos = query_offset - local last_leaf - for i = query_offset, query:len() do - local char = query:sub(i, i) - self = self[char] - if not self then break - elseif self.value then - last_leaf = self.value - leaf_pos = i - end - end - return last_leaf, leaf_pos -end - --- Export environment -return _ENV \ No newline at end of file diff --git a/mods/modlib/utf8.lua b/mods/modlib/utf8.lua deleted file mode 100644 index 5ff0b10b..00000000 --- a/mods/modlib/utf8.lua +++ /dev/null @@ -1,102 +0,0 @@ -local assert, error, select, string_char, table_concat - = assert, error, select, string.char, table.concat - -local utf8 = {} - --- Overly permissive pattern that greedily matches a single UTF-8 codepoint -utf8.charpattern = "[%z-\127\194-\253][\128-\191]*" - -function utf8.is_valid_codepoint(codepoint) - -- Must be in bounds & must not be a surrogate - return codepoint <= 0x10FFFF and (codepoint < 0xD800 or codepoint > 0xDFFF) -end - -local function utf8_bytes(codepoint) - if codepoint <= 0x007F then - return codepoint - end if codepoint <= 0x7FF then - local payload_2 = codepoint % 0x40 - codepoint = (codepoint - payload_2) / 0x40 - return 0xC0 + codepoint, 0x80 + payload_2 - end if codepoint <= 0xFFFF then - local payload_3 = codepoint % 0x40 - codepoint = (codepoint - payload_3) / 0x40 - local payload_2 = codepoint % 0x40 - codepoint = (codepoint - payload_2) / 0x40 - return 0xE0 + codepoint, 0x80 + payload_2, 0x80 + payload_3 - end if codepoint <= 0x10FFFF then - local payload_4 = codepoint % 0x40 - codepoint = (codepoint - payload_4) / 0x40 - local payload_3 = codepoint % 0x40 - codepoint = (codepoint - payload_3) / 0x40 - local payload_2 = codepoint % 0x40 - codepoint = (codepoint - payload_2) / 0x40 - return 0xF0 + codepoint, 0x80 + payload_2, 0x80 + payload_3, 0x80 + payload_4 - end error"codepoint out of range" -end - -function utf8.char(...) - local n_args = select("#", ...) - if n_args == 0 then - return - end if n_args == 1 then - return string_char(utf8_bytes(...)) - end - local chars = {} - for i = 1, n_args do - chars[i] = string_char(utf8_bytes(select(i, ...))) - end - return table_concat(chars) -end - -local function utf8_next_codepoint(str, i) - local first_byte = str:byte(i) - if first_byte < 0x80 then - return i + 1, first_byte - end - - local len, head_bits - if first_byte >= 0xC0 and first_byte <= 0xDF then -- 110_00000 to 110_11111 - len, head_bits = 2, first_byte % 0x20 -- last 5 bits - elseif first_byte >= 0xE0 and first_byte <= 0xEF then -- 1110_0000 to 1110_1111 - len, head_bits = 3, first_byte % 0x10 -- last 4 bits - elseif first_byte >= 0xF0 and first_byte <= 0xF7 then -- 11110_000 to 11110_111 - len, head_bits = 4, first_byte % 0x8 -- last 3 bits - else error"invalid UTF-8" end - - local codepoint = 0 - local pow = 1 - for j = i + len - 1, i + 1, -1 do - local byte = assert(str:byte(j), "invalid UTF-8") - local val_bits = byte % 0x40 -- extract last 6 bits xxxxxx from 10xxxxxx - assert(byte - val_bits == 0x80) -- assert that first two bits are 10 - codepoint = codepoint + val_bits * pow - pow = pow * 0x40 - end - return i + len, codepoint + head_bits * pow -end - -function utf8.codepoint(str, i, j) - i, j = i or 1, j or #str - if i > j then return end - local codepoint - i, codepoint = utf8_next_codepoint(str, i) - assert(i - j <= 1, "invalid UTF-8") - return codepoint, utf8.codepoint(str, i) -end - --- Iterator to loop over the UTF-8 characters as `index, codepoint` -function utf8.codes(text, i) - i = i or 1 - return function() - if i > #text then - return - end - local prev_index = i - local codepoint - i, codepoint = utf8_next_codepoint(text, i) - return prev_index, codepoint - end -end - -return utf8 \ No newline at end of file diff --git a/mods/modlib/vararg.lua b/mods/modlib/vararg.lua deleted file mode 100644 index 86c5a689..00000000 --- a/mods/modlib/vararg.lua +++ /dev/null @@ -1,64 +0,0 @@ -local select, setmetatable, unpack = select, setmetatable, unpack - -local vararg = {} - -function vararg.aggregate(binary_func, initial, ...) - local total = initial - for i = 1, select("#", ...) do - total = binary_func(total, select(i, ...)) - end - return total -end - -local metatable = {__index = {}} - -function vararg.pack(...) - return setmetatable({["#"] = select("#", ...); ...}, metatable) -end - -local va = metatable.__index - -function va:unpack() - return unpack(self, 1, self["#"]) -end - -function va:select(n) - if n > self["#"] then return end - return self[n] -end - -local function inext(self, i) - i = i + 1 - if i > self["#"] then return end - return i, self[i] -end - -function va:ipairs() - return inext, self, 0 -end - -function va:concat(other) - local self_len, other_len = self["#"], other["#"] - local res = {["#"] = self_len + other_len} - for i = 1, self_len do - res[i] = self[i] - end - for i = 1, other_len do - res[self_len + i] = other[i] - end - return setmetatable(res, metatable) -end -metatable.__concat = va.concat - -function va:equals(other) - if self["#"] ~= other["#"] then return false end - for i = 1, self["#"] do if self[i] ~= other[i] then return false end end - return true -end -metatable.__eq = va.equals - -function va:aggregate(binary_func, initial) - return vararg.aggregate(binary_func, initial, self:unpack()) -end - -return vararg \ No newline at end of file diff --git a/mods/modlib/vector.lua b/mods/modlib/vector.lua deleted file mode 100644 index e37368e2..00000000 --- a/mods/modlib/vector.lua +++ /dev/null @@ -1,274 +0,0 @@ --- Localize globals -local assert, math, pairs, rawget, rawset, setmetatable, unpack, vector = assert, math, pairs, rawget, rawset, setmetatable, unpack, vector - --- Set environment -local _ENV = {} -setfenv(1, _ENV) - -local mt_vector = vector - -index_aliases = { - x = 1, - y = 2, - z = 3, - w = 4; - "x", "y", "z", "w"; -} - -metatable = { - __index = function(table, key) - local index = index_aliases[key] - if index ~= nil then - return rawget(table, index) - end - return _ENV[key] - end, - __newindex = function(table, key, value) - -- TODO - local index = index_aliases[key] - if index ~= nil then - return rawset(table, index, value) - end - return rawset(table, key, value) - end -} - -function new(v) - return setmetatable(v, metatable) -end - -function zeros(n) - local v = {} - for i = 1, n do - v[i] = 0 - end - return new(v) -end -function from_xyzw(v) - return new{v.x, v.y, v.z, v.w} -end - -function from_minetest(v) - return new{v.x, v.y, v.z} -end - -function to_xyzw(v) - return {x = v[1], y = v[2], z = v[3], w = v[4]} -end - ---+ not necessarily required, as Minetest respects the metatable -function to_minetest(v) - return mt_vector.new(unpack(v)) -end - -function equals(v, w) - for k, v in pairs(v) do - if v ~= w[k] then return false end - end - return true -end - -metatable.__eq = equals - -function combine(v, w, f) - local new_vector = {} - for key, value in pairs(v) do - new_vector[key] = f(value, w[key]) - end - return new(new_vector) -end - -function apply(v, f, ...) - local new_vector = {} - for key, value in pairs(v) do - new_vector[key] = f(value, ...) - end - return new(new_vector) -end - -function combinator(f) - return function(v, w) - return combine(v, w, f) - end, function(v, ...) - return apply(v, f, ...) - end -end - -function invert(v) - local res = {} - for key, value in pairs(v) do - res[key] = -value - end - return new(res) -end - -add, add_scalar = combinator(function(v, w) return v + w end) -subtract, subtract_scalar = combinator(function(v, w) return v - w end) -multiply, multiply_scalar = combinator(function(v, w) return v * w end) -divide, divide_scalar = combinator(function(v, w) return v / w end) -pow, pow_scalar = combinator(function(v, w) return v ^ w end) - -metatable.__add = add -metatable.__unm = invert -metatable.__sub = subtract -metatable.__mul = multiply -metatable.__div = divide - ---+ linear interpolation ---: ratio number from 0 (all the first vector) to 1 (all the second vector) -function interpolate(v, w, ratio) - return add(multiply_scalar(v, 1 - ratio), multiply_scalar(w, ratio)) -end - -function norm(v) - local sum = 0 - for _, value in pairs(v) do - sum = sum + value ^ 2 - end - return sum -end - -function length(v) - return math.sqrt(norm(v)) -end - --- Minor code duplication for the sake of performance -function distance(v, w) - local sum = 0 - for key, value in pairs(v) do - sum = sum + (value - w[key]) ^ 2 - end - return math.sqrt(sum) -end - -function normalize(v) - return divide_scalar(v, length(v)) -end - -function normalize_zero(v) - local len = length(v) - if len == 0 then - -- Return a zeroed vector with the same keys - local zeroed = {} - for k in pairs(v) do - zeroed[k] = 0 - end - return new(zeroed) - end - return divide_scalar(v, len) -end - -function floor(v) - return apply(v, math.floor) -end - -function ceil(v) - return apply(v, math.ceil) -end - -function clamp(v, min, max) - return apply(apply(v, math.max, min), math.min, max) -end - -function cross3(v, w) - assert(#v == 3 and #w == 3) - return new{ - v[2] * w[3] - v[3] * w[2], - v[3] * w[1] - v[1] * w[3], - v[1] * w[2] - v[2] * w[1] - } -end - -function dot(v, w) - local sum = 0 - for i, c in pairs(v) do - sum = sum + c * w[i] - end - return sum -end - -function reflect(v, normal --[[**normalized** plane normal vector]]) - return subtract(v, multiply_scalar(normal, 2 * dot(v, normal))) -- reflection of v at the plane -end - ---+ Angle between two vectors ---> Signed angle in radians -function angle(v, w) - -- Based on dot(v, w) = |v| * |w| * cos(x) - return math.acos(dot(v, w) / length(v) / length(w)) -end - --- See https://www.euclideanspace.com/maths/geometry/rotations/conversions/eulerToAngle/ -function axis_angle3(euler_rotation) - assert(#euler_rotation == 3) - euler_rotation = divide_scalar(euler_rotation, 2) - local cos = apply(euler_rotation, math.cos) - local sin = apply(euler_rotation, math.sin) - return normalize_zero{ - sin[1] * sin[2] * cos[3] + cos[1] * cos[2] * sin[3], - sin[1] * cos[2] * cos[3] + cos[1] * sin[2] * sin[3], - cos[1] * sin[2] * cos[3] - sin[1] * cos[2] * sin[3], - }, 2 * math.acos(cos[1] * cos[2] * cos[3] - sin[1] * sin[2] * sin[3]) -end - --- Uses Rodrigues' rotation formula --- axis must be normalized -function rotate3(v, axis, angle) - assert(#v == 3 and #axis == 3) - local cos = math.cos(angle) - return multiply_scalar(v, cos) - -- Minetest's coordinate system is *left-handed*, so `v` and `axis` must be swapped here - + multiply_scalar(cross3(v, axis), math.sin(angle)) - + multiply_scalar(axis, dot(axis, v) * (1 - cos)) -end - -function box_box_collision(diff, box, other_box) - for index, diff in pairs(diff) do - if box[index] + diff > other_box[index + 3] or other_box[index] > box[index + 3] + diff then - return false - end - end - return true -end - -local function moeller_trumbore(origin, direction, triangle, is_tri) - local point_1, point_2, point_3 = unpack(triangle) - local edge_1, edge_2 = subtract(point_2, point_1), subtract(point_3, point_1) - local h = cross3(direction, edge_2) - local a = dot(edge_1, h) - if math.abs(a) < 1e-9 then - return - end - local f = 1 / a - local diff = subtract(origin, point_1) - local u = f * dot(diff, h) - if u < 0 or u > 1 then - return - end - local q = cross3(diff, edge_1) - local v = f * dot(direction, q) - if v < 0 or (is_tri and u or 0) + v > 1 then - return - end - local pos_on_line = f * dot(edge_2, q) - if pos_on_line >= 0 then - return pos_on_line, u, v - end -end - -function ray_triangle_intersection(origin, direction, triangle) - return moeller_trumbore(origin, direction, triangle, true) -end - -function ray_parallelogram_intersection(origin, direction, parallelogram) - return moeller_trumbore(origin, direction, parallelogram) -end - -function triangle_normal(triangle) - local point_1, point_2, point_3 = unpack(triangle) - local edge_1, edge_2 = subtract(point_2, point_1), subtract(point_3, point_1) - return normalize(cross3(edge_1, edge_2)) -end - --- Export environment -return _ENV \ No newline at end of file diff --git a/mods/modlib/web.lua b/mods/modlib/web.lua deleted file mode 100644 index 4a1ba972..00000000 --- a/mods/modlib/web.lua +++ /dev/null @@ -1,7 +0,0 @@ -return setmetatable({}, {__index = function(self, module_name) - if module_name == "uri" or module_name == "html" then - local module = assert(loadfile(modlib.mod.get_resource(modlib.modname, "web", module_name .. ".lua")))() - self[module_name] = module - return module - end -end}) \ No newline at end of file diff --git a/mods/modlib/web/html.lua b/mods/modlib/web/html.lua deleted file mode 100644 index 9b141d43..00000000 --- a/mods/modlib/web/html.lua +++ /dev/null @@ -1,27 +0,0 @@ -local html = setmetatable({}, {__index = function(self, key) - if key == "unescape" then - local func = assert(loadfile(modlib.mod.get_resource("modlib", "web", "html", "entities.lua"))) - setfenv(func, {}) - local named_entities = assert(func()) - local function unescape(text) - return text - :gsub("&([A-Za-z]+);", named_entities) -- named - :gsub("&#(%d+);", function(digits) return modlib.utf8.char(tonumber(digits)) end) -- decimal - :gsub("&#x(%x+);", function(digits) return modlib.utf8.char(tonumber(digits, 16)) end) -- hex - end - self.unescape = unescape - return unescape - end -end}) - -function html.escape(text) - return text:gsub(".", { - ["<"] = "<", - [">"] = ">", - ["&"] = "&", - ["'"] = "'", - ['"'] = """, - }) -end - -return html \ No newline at end of file diff --git a/mods/modlib/web/html/entities.lua b/mods/modlib/web/html/entities.lua deleted file mode 100644 index f9c77c2b..00000000 --- a/mods/modlib/web/html/entities.lua +++ /dev/null @@ -1,3 +0,0 @@ --- HTML entity lookup table generated by build/html_entities.lua. Do not edit. -return {["llhard"] = "⥫", ["ugrav"] = "ù", ["gamma"] = "γ", ["copf"] = "𝕔", ["napprox"] = "≉", ["fltns"] = "▱", ["amacr"] = "ā", ["NotGreaterFullEqual"] = "≧̸", ["SquareSuperset"] = "⊐", ["ffllig"] = "ffl", ["Iacut"] = "Í", ["nrarr"] = "↛", ["sup2"] = "²", ["llarr"] = "⇇", ["measuredangle"] = "∡", ["divonx"] = "⋇", ["boxvL"] = "╡", ["range"] = "⦥", ["Jscr"] = "𝒥", ["ncap"] = "⩃", ["ndash"] = "–", ["varpropto"] = "∝", ["yacy"] = "я", ["gEl"] = "⪌", ["div"] = "÷", ["mfr"] = "𝔪", ["sext"] = "✶", ["darr"] = "↓", ["CapitalDifferentialD"] = "ⅅ", ["ufr"] = "𝔲", ["Scirc"] = "Ŝ", ["twixt"] = "≬", ["num"] = "#", ["Zeta"] = "Ζ", ["ruluhar"] = "⥨", ["CHcy"] = "Ч", ["wreath"] = "≀", ["Mfr"] = "𝔐", ["de"] = "°", ["lpar"] = "(", ["isinv"] = "∈", ["HumpEqual"] = "≏", ["frasl"] = "⁄", ["Ufr"] = "𝔘", ["le"] = "≤", ["curlywedge"] = "⋏", ["NotGreaterSlantEqual"] = "⩾̸", ["Egrave"] = "È", ["subsetneqq"] = "⫋", ["nLeftarrow"] = "⇍", ["angst"] = "Å", ["supseteq"] = "⊇", ["ltdot"] = "⋖", ["int"] = "∫", ["permil"] = "‰", ["equest"] = "≟", ["eqcirc"] = "≖", ["ubrcy"] = "ў", ["micro"] = "µ", ["Ecirc"] = "Ê", ["Fouriertrf"] = "ℱ", ["dotplus"] = "∔", ["ycirc"] = "ŷ", ["boxdL"] = "╕", ["LeftDoubleBracket"] = "⟦", ["Yopf"] = "𝕐", ["Int"] = "∬", ["kscr"] = "𝓀", ["GreaterGreater"] = "⪢", ["lsquor"] = "‚", ["mDDot"] = "∺", ["late"] = "⪭", ["boxh"] = "─", ["sqcup"] = "⊔", ["quot"] = "\"", ["LessTilde"] = "≲", ["ldsh"] = "↲", ["lrhard"] = "⥭", ["ropf"] = "𝕣", ["larrtl"] = "↢", ["comma"] = ",", ["DoubleRightArrow"] = "⇒", ["acy"] = "а", ["gnapprox"] = "⪊", ["boxUl"] = "╜", ["plustwo"] = "⨧", ["Rarr"] = "↠", ["icy"] = "и", ["grave"] = "`", ["nwArr"] = "⇖", ["pitchfork"] = "⋔", ["tosa"] = "⤩", ["Leftarrow"] = "⇐", ["Yscr"] = "𝒴", ["hoarr"] = "⇿", ["ycy"] = "ы", ["subne"] = "⊊", ["lescc"] = "⪨", ["bigcap"] = "⋂", ["marker"] = "▮", ["Acy"] = "А", ["auml"] = "ä", ["NotLess"] = "≮", ["nrtrie"] = "⋭", ["zeta"] = "ζ", ["egrave"] = "è", ["Icy"] = "И", ["Oslas"] = "Ø", ["ddagger"] = "‡", ["succ"] = "≻", ["leftarrow"] = "←", ["iprod"] = "⨼", ["eqcolon"] = "≕", ["RightDownTeeVector"] = "⥝", ["Del"] = "∇", ["omacr"] = "ō", ["zigrarr"] = "⇝", ["Ycy"] = "Ы", ["LeftArrowRightArrow"] = "⇆", ["becaus"] = "∵", ["MinusPlus"] = "∓", ["nvinfin"] = "⧞", ["nvle"] = "≤⃒", ["NonBreakingSpace"] = " ", ["CounterClockwiseContourIntegral"] = "∳", ["sharp"] = "♯", ["ugrave"] = "ù", ["boxVR"] = "╠", ["NotLeftTriangleBar"] = "⧏̸", ["rppolint"] = "⨒", ["egsdot"] = "⪘", ["NestedLessLess"] = "≪", ["DoubleVerticalBar"] = "∥", ["Ycirc"] = "Ŷ", ["ogt"] = "⧁", ["smte"] = "⪬", ["Hscr"] = "ℋ", ["sup3"] = "³", ["cudarrl"] = "⤸", ["Copf"] = "ℂ", ["lbarr"] = "⤌", ["igrav"] = "ì", ["xdtri"] = "▽", ["nequiv"] = "≢", ["rangd"] = "⦒", ["vartheta"] = "ϑ", ["ecaron"] = "ě", ["IEcy"] = "Е", ["nearrow"] = "↗", ["Auml"] = "Ä", ["iacut"] = "í", ["subseteq"] = "⊆", ["Dashv"] = "⫤", ["mopf"] = "𝕞", ["NotReverseElement"] = "∌", ["DD"] = "ⅅ", ["udblac"] = "ű", ["cirmid"] = "⫯", ["bigwedge"] = "⋀", ["timesbar"] = "⨱", ["vzigzag"] = "⦚", ["angmsdac"] = "⦪", ["ratio"] = "∶", ["ZHcy"] = "Ж", ["DoubleRightTee"] = "⊨", ["zscr"] = "𝓏", ["subplus"] = "⪿", ["notinvc"] = "⋶", ["acd"] = "∿", ["ggg"] = "⋙", ["rarr"] = "→", ["checkmark"] = "✓", ["NegativeMediumSpace"] = "​", ["fllig"] = "fl", ["npreceq"] = "⪯̸", ["LeftVectorBar"] = "⥒", ["check"] = "✓", ["veeeq"] = "≚", ["ges"] = "⩾", ["Delta"] = "Δ", ["Ugrav"] = "Ù", ["AElig"] = "Æ", ["angzarr"] = "⍼", ["horbar"] = "―", ["fallingdotseq"] = "≒", ["exist"] = "∃", ["curlyeqprec"] = "⋞", ["hbar"] = "ℏ", ["SubsetEqual"] = "⊆", ["Kscr"] = "𝒦", ["intlarhk"] = "⨗", ["GreaterSlantEqual"] = "⩾", ["real"] = "ℜ", ["VerticalBar"] = "∣", ["leftarrowtail"] = "↢", ["ogon"] = "˛", ["squf"] = "▪", ["hercon"] = "⊹", ["supsim"] = "⫈", ["urcrop"] = "⌎", ["REG"] = "®", ["Ropf"] = "ℝ", ["dd"] = "ⅆ", ["boxuR"] = "╘", ["lneq"] = "⪇", ["leftrightarrows"] = "⇆", ["Dopf"] = "𝔻", ["bigstar"] = "★", ["precsim"] = "≾", ["eacute"] = "é", ["block"] = "█", ["NotSucceedsEqual"] = "⪰̸", ["rarrap"] = "⥵", ["nmid"] = "∤", ["chi"] = "χ", ["RightUpVector"] = "↾", ["simplus"] = "⨤", ["shcy"] = "ш", ["nbs"] = " ", ["weierp"] = "℘", ["sh"] = "­", ["yscr"] = "𝓎", ["erDot"] = "≓", ["hscr"] = "𝒽", ["curren"] = "¤", ["RightTeeArrow"] = "↦", ["colon"] = ":", ["mp"] = "∓", ["nsce"] = "⪰̸", ["mho"] = "℧", ["complexes"] = "ℂ", ["Udblac"] = "Ű", ["intprod"] = "⨼", ["lnsim"] = "⋦", ["sbquo"] = "‚", ["prap"] = "⪷", ["ohm"] = "Ω", ["DoubleUpArrow"] = "⇑", ["rmoust"] = "⎱", ["uum"] = "ü", ["rationals"] = "ℚ", ["dfr"] = "𝔡", ["NotLeftTriangle"] = "⋪", ["flat"] = "♭", ["lfr"] = "𝔩", ["eum"] = "ë", ["LessEqualGreater"] = "⋚", ["tfr"] = "𝔱", ["trianglerighteq"] = "⊵", ["varsupsetneqq"] = "⫌︀", ["Aogon"] = "Ą", ["Uum"] = "Ü", ["dlcorn"] = "⌞", ["solb"] = "⧄", ["diamondsuit"] = "♦", ["reg"] = "®", ["Lfr"] = "𝔏", ["Tab"] = "\9", ["frac56"] = "⅚", ["Eum"] = "Ë", ["circleddash"] = "⊝", ["fork"] = "⋔", ["nsup"] = "⊅", ["Tfr"] = "𝔗", ["leftleftarrows"] = "⇇", ["angmsdab"] = "⦩", ["easter"] = "⩮", ["InvisibleTimes"] = "⁢", ["straightphi"] = "ϕ", ["looparrowright"] = "↬", ["triangle"] = "▵", ["xi"] = "ξ", ["eqslantgtr"] = "⪖", ["pi"] = "π", ["Succeeds"] = "≻", ["suphsol"] = "⟉", ["icir"] = "î", ["gtrdot"] = "⋗", ["Icir"] = "Î", ["Xi"] = "Ξ", ["iukcy"] = "і", ["phone"] = "☎", ["alefsym"] = "ℵ", ["succeq"] = "⪰", ["uparrow"] = "↑", ["drcorn"] = "⌟", ["bsolb"] = "⧅", ["lhblk"] = "▄", ["nrightarrow"] = "↛", ["xrarr"] = "⟶", ["timesd"] = "⨰", ["lrm"] = "‎", ["ltcir"] = "⩹", ["blacktriangle"] = "▴", ["boxH"] = "═", ["VerticalTilde"] = "≀", ["olarr"] = "↺", ["nsc"] = "⊁", ["npolint"] = "⨔", ["ccups"] = "⩌", ["succcurlyeq"] = "≽", ["pcy"] = "п", ["NotLeftTriangleEqual"] = "⋬", ["geqslant"] = "⩾", ["NotTilde"] = "≁", ["qint"] = "⨌", ["lbbrk"] = "❲", ["shy"] = "­", ["squ"] = "□", ["timesb"] = "⊠", ["Uparrow"] = "⇑", ["cularrp"] = "⤽", ["SHCHcy"] = "Щ", ["dscy"] = "ѕ", ["PlusMinus"] = "±", ["lopar"] = "⦅", ["nLeftrightarrow"] = "⇎", ["Ncaron"] = "Ň", ["aelig"] = "æ", ["sscr"] = "𝓈", ["Lambda"] = "Λ", ["Rang"] = "⟫", ["xcirc"] = "◯", ["not"] = "¬", ["Lscr"] = "ℒ", ["rarrpl"] = "⥅", ["vdash"] = "⊢", ["copy"] = "©", ["hairsp"] = " ", ["GreaterFullEqual"] = "≧", ["dtdot"] = "⋱", ["LeftDownVectorBar"] = "⥙", ["approxeq"] = "≊", ["Prime"] = "″", ["dblac"] = "˝", ["notni"] = "∌", ["vsubne"] = "⊊︀", ["suplarr"] = "⥻", ["setmn"] = "∖", ["gneqq"] = "≩", ["nles"] = "⩽̸", ["clubsuit"] = "♣", ["tridot"] = "◬", ["nleftrightarrow"] = "↮", ["ncaron"] = "ň", ["lessgtr"] = "≶", ["gbreve"] = "ğ", ["notinva"] = "∉", ["lambda"] = "λ", ["ape"] = "≊", ["imacr"] = "ī", ["thkap"] = "≈", ["multimap"] = "⊸", ["fflig"] = "ff", ["NotLessTilde"] = "≴", ["boxhU"] = "╨", ["supplus"] = "⫀", ["lowbar"] = "_", ["rarrsim"] = "⥴", ["thetasym"] = "ϑ", ["image"] = "ℑ", ["upsi"] = "υ", ["nsmid"] = "∤", ["gtrsim"] = "≳", ["Lmidot"] = "Ŀ", ["nap"] = "≉", ["Oacut"] = "Ó", ["ZeroWidthSpace"] = "​", ["aacut"] = "á", ["boxvl"] = "┤", ["Colon"] = "∷", ["nsupe"] = "⊉", ["bump"] = "≎", ["uacut"] = "ú", ["Wcirc"] = "Ŵ", ["LeftRightVector"] = "⥎", ["rHar"] = "⥤", ["nless"] = "≮", ["DoubleLongRightArrow"] = "⟹", ["capcap"] = "⩋", ["lltri"] = "◺", ["caron"] = "ˇ", ["upsih"] = "ϒ", ["DownLeftRightVector"] = "⥐", ["nVDash"] = "⊯", ["intercal"] = "⊺", ["lesdot"] = "⩿", ["mscr"] = "𝓂", ["acute"] = "´", ["Uacute"] = "Ú", ["nlArr"] = "⇍", ["rpargt"] = "⦔", ["zdot"] = "ż", ["incare"] = "℅", ["epar"] = "⋕", ["mapstoleft"] = "↤", ["nsubseteqq"] = "⫅̸", ["ctdot"] = "⋯", ["leq"] = "≤", ["there4"] = "∴", ["OpenCurlyQuote"] = "‘", ["andslope"] = "⩘", ["eDDot"] = "⩷", ["frac13"] = "⅓", ["Oscr"] = "𝒪", ["Implies"] = "⇒", ["OElig"] = "Œ", ["drcrop"] = "⌌", ["gtrapprox"] = "⪆", ["RightUpTeeVector"] = "⥜", ["oslas"] = "ø", ["empty"] = "∅", ["xopf"] = "𝕩", ["ocir"] = "⊚", ["NotPrecedesSlantEqual"] = "⋠", ["Ocir"] = "Ô", ["blacktriangleleft"] = "◂", ["ordf"] = "ª", ["lacute"] = "ĺ", ["RE"] = "®", ["trianglelefteq"] = "⊴", ["HumpDownHump"] = "≎", ["frac58"] = "⅝", ["NotTildeTilde"] = "≉", ["Nopf"] = "ℕ", ["csupe"] = "⫒", ["Lang"] = "⟪", ["Lleftarrow"] = "⇚", ["rceil"] = "⌉", ["vsubnE"] = "⫋︀", ["Idot"] = "İ", ["DDotrahd"] = "⤑", ["gl"] = "≷", ["tilde"] = "˜", ["Assign"] = "≔", ["utri"] = "▵", ["OverBrace"] = "⏞", ["odsold"] = "⦼", ["robrk"] = "⟧", ["Bscr"] = "ℬ", ["DiacriticalDoubleAcute"] = "˝", ["coloneq"] = "≔", ["blk34"] = "▓", ["Phi"] = "Φ", ["cupcup"] = "⩊", ["sqsubseteq"] = "⊑", ["NotSubset"] = "⊂⃒", ["nsubseteq"] = "⊈", ["larrlp"] = "↫", ["odot"] = "⊙", ["niv"] = "∋", ["therefore"] = "∴", ["nbump"] = "≎̸", ["kfr"] = "𝔨", ["lbrkslu"] = "⦍", ["sfr"] = "𝔰", ["midast"] = "*", ["micr"] = "µ", ["filig"] = "fi", ["wcirc"] = "ŵ", ["esdot"] = "≐", ["Sqrt"] = "√", ["omega"] = "ω", ["lArr"] = "⇐", ["sdotb"] = "⊡", ["approx"] = "≈", ["nsubset"] = "⊂⃒", ["Kfr"] = "𝔎", ["Qopf"] = "ℚ", ["nvrtrie"] = "⊵⃒", ["latail"] = "⤙", ["leqslant"] = "⩽", ["PrecedesEqual"] = "⪯", ["lesg"] = "⋚︀", ["re"] = "®", ["ii"] = "ⅈ", ["plusdo"] = "∔", ["NotHumpEqual"] = "≏̸", ["rbrksld"] = "⦎", ["angmsdad"] = "⦫", ["cscr"] = "𝒸", ["qprime"] = "⁗", ["rsquor"] = "’", ["rarrbfs"] = "⤠", ["bsemi"] = "⁏", ["TSHcy"] = "Ћ", ["complement"] = "∁", ["ulcorn"] = "⌜", ["orarr"] = "↻", ["veebar"] = "⊻", ["boxhu"] = "┴", ["CloseCurlyQuote"] = "’", ["urcorner"] = "⌝", ["lsim"] = "≲", ["COP"] = "©", ["triangleleft"] = "◃", ["nu"] = "ν", ["OverBar"] = "‾", ["Esim"] = "⩳", ["nlE"] = "≦̸", ["nrarrw"] = "↝̸", ["HARDcy"] = "Ъ", ["sstarf"] = "⋆", ["jopf"] = "𝕛", ["smile"] = "⌣", ["urcorn"] = "⌝", ["G"] = ">", ["ngeq"] = "≱", ["rdquo"] = "”", ["udarr"] = "⇅", ["capcup"] = "⩇", ["mdash"] = "—", ["boxbox"] = "⧉", ["tshcy"] = "ћ", ["LessFullEqual"] = "≦", ["DoubleContourIntegral"] = "∯", ["Nu"] = "Ν", ["lang"] = "⟨", ["oline"] = "‾", ["wedge"] = "∧", ["CupCap"] = "≍", ["Kcy"] = "К", ["laquo"] = "«", ["compfn"] = "∘", ["Scy"] = "С", ["simg"] = "⪞", ["gtcir"] = "⩺", ["loplus"] = "⨭", ["nlarr"] = "↚", ["softcy"] = "ь", ["ENG"] = "Ŋ", ["thorn"] = "þ", ["NotSucceedsSlantEqual"] = "⋡", ["pr"] = "≺", ["harrcir"] = "⥈", ["NoBreak"] = "⁠", ["pound"] = "£", ["upsilon"] = "υ", ["Poincareplane"] = "ℌ", ["Product"] = "∏", ["Iogon"] = "Į", ["Congruent"] = "≡", ["rtriltri"] = "⧎", ["xhArr"] = "⟺", ["plusm"] = "±", ["mid"] = "∣", ["TScy"] = "Ц", ["boxuL"] = "╛", ["Pr"] = "⪻", ["triangleright"] = "▹", ["Rsh"] = "↱", ["Bernoullis"] = "ℬ", ["Gcedil"] = "Ģ", ["Upsi"] = "ϒ", ["gneq"] = "⪈", ["radic"] = "√", ["SmallCircle"] = "∘", ["bepsi"] = "϶", ["frac3"] = "¾", ["eta"] = "η", ["operp"] = "⦹", ["g"] = ">", ["cross"] = "✗", ["epsilon"] = "ε", ["sigmav"] = "ς", ["congdot"] = "⩭", ["frac45"] = "⅘", ["target"] = "⌖", ["Vdash"] = "⊩", ["alpha"] = "α", ["shortmid"] = "∣", ["odblac"] = "ő", ["gtreqqless"] = "⪌", ["ntgl"] = "≹", ["gap"] = "⪆", ["Eta"] = "Η", ["Icirc"] = "Î", ["bumpE"] = "⪮", ["Atild"] = "Ã", ["gne"] = "⪈", ["vscr"] = "𝓋", ["boxDl"] = "╖", ["Yuml"] = "Ÿ", ["nesim"] = "≂̸", ["angmsdag"] = "⦮", ["apE"] = "⩰", ["bigcup"] = "⋃", ["atild"] = "ã", ["searhk"] = "⤥", ["eng"] = "ŋ", ["Cscr"] = "𝒞", ["lgE"] = "⪑", ["cong"] = "≅", ["LeftDownVector"] = "⇃", ["Jcirc"] = "Ĵ", ["Lacute"] = "Ĺ", ["InvisibleComma"] = "⁣", ["lesdoto"] = "⪁", ["eqslantless"] = "⪕", ["lesssim"] = "≲", ["kappav"] = "ϰ", ["nshortmid"] = "∤", ["boxhD"] = "╥", ["lstrok"] = "ł", ["acut"] = "´", ["CircleDot"] = "⊙", ["vArr"] = "⇕", ["uogon"] = "ų", ["nisd"] = "⋺", ["curarr"] = "↷", ["Dstrok"] = "Đ", ["gtcc"] = "⪧", ["topf"] = "𝕥", ["rdsh"] = "↳", ["cwconint"] = "∲", ["prime"] = "′", ["ReverseElement"] = "∋", ["lharul"] = "⥪", ["trade"] = "™", ["Jopf"] = "𝕁", ["rfisht"] = "⥽", ["dzigrarr"] = "⟿", ["Odblac"] = "Ő", ["plus"] = "+", ["capand"] = "⩄", ["nis"] = "⋼", ["cacute"] = "ć", ["RightUpDownVector"] = "⥏", ["frac15"] = "⅕", ["geqq"] = "≧", ["iexc"] = "¡", ["cdot"] = "ċ", ["uscr"] = "𝓊", ["vnsub"] = "⊂⃒", ["cop"] = "©", ["ll"] = "≪", ["bbrk"] = "⎵", ["kjcy"] = "ќ", ["dstrok"] = "đ", ["UnionPlus"] = "⊎", ["gtdot"] = "⋗", ["ecolon"] = "≕", ["sqsupe"] = "⊒", ["swArr"] = "⇙", ["quo"] = "\"", ["RightTee"] = "⊢", ["lbrace"] = "{", ["Ll"] = "⋘", ["gsim"] = "≳", ["subsim"] = "⫇", ["aogon"] = "ą", ["lozenge"] = "◊", ["NotNestedGreaterGreater"] = "⪢̸", ["blacklozenge"] = "⧫", ["mapstodown"] = "↧", ["tritime"] = "⨻", ["mumap"] = "⊸", ["propto"] = "∝", ["scirc"] = "ŝ", ["glj"] = "⪤", ["utilde"] = "ũ", ["sum"] = "∑", ["bfr"] = "𝔟", ["SucceedsTilde"] = "≿", ["downdownarrows"] = "⇊", ["updownarrow"] = "↕", ["jfr"] = "𝔧", ["wopf"] = "𝕨", ["vellip"] = "⋮", ["rfr"] = "𝔯", ["bigcirc"] = "◯", ["Zscr"] = "𝒵", ["dHar"] = "⥥", ["nRightarrow"] = "⇏", ["deg"] = "°", ["zfr"] = "𝔷", ["sung"] = "♪", ["Vscr"] = "𝒱", ["Egrav"] = "È", ["leg"] = "⋚", ["Sum"] = "∑", ["Bfr"] = "𝔅", ["gnap"] = "⪊", ["ntrianglelefteq"] = "⋬", ["boxUL"] = "╝", ["simgE"] = "⪠", ["frac25"] = "⅖", ["Rfr"] = "ℜ", ["NotGreaterGreater"] = "≫̸", ["Zfr"] = "ℨ", ["harr"] = "↔", ["varsupsetneq"] = "⊋︀", ["LeftUpDownVector"] = "⥑", ["Utilde"] = "Ũ", ["numsp"] = " ", ["khcy"] = "х", ["nltri"] = "⋪", ["vee"] = "∨", ["lmoustache"] = "⎰", ["trpezium"] = "⏢", ["gscr"] = "ℊ", ["emptyv"] = "∅", ["ShortRightArrow"] = "→", ["phiv"] = "ϕ", ["ensp"] = " ", ["NotSquareSupersetEqual"] = "⋣", ["jukcy"] = "є", ["angmsdaf"] = "⦭", ["prnsim"] = "⋨", ["uml"] = "¨", ["iocy"] = "ё", ["Omicron"] = "Ο", ["Rightarrow"] = "⇒", ["ncedil"] = "ņ", ["Umacr"] = "Ū", ["TRADE"] = "™", ["dotsquare"] = "⊡", ["ccedi"] = "ç", ["ltquest"] = "⩻", ["NewLine"] = "\ -", ["DownLeftVectorBar"] = "⥖", ["plusacir"] = "⨣", ["egrav"] = "è", ["SquareSubset"] = "⊏", ["imagpart"] = "ℑ", ["rightarrow"] = "→", ["lrcorner"] = "⌟", ["ShortUpArrow"] = "↑", ["Qscr"] = "𝒬", ["glE"] = "⪒", ["ltrif"] = "◂", ["rbrkslu"] = "⦐", ["angmsdah"] = "⦯", ["Hcirc"] = "Ĥ", ["boxHu"] = "╧", ["fopf"] = "𝕗", ["jcy"] = "й", ["Topf"] = "𝕋", ["asympeq"] = "≍", ["dash"] = "‐", ["edot"] = "ė", ["rcy"] = "р", ["yen"] = "¥", ["orderof"] = "ℴ", ["dagger"] = "†", ["sup"] = "¹", ["Fopf"] = "𝔽", ["Bcy"] = "Б", ["NotSquareSuperset"] = "⊐̸", ["frac14"] = "¼", ["bull"] = "•", ["cup"] = "∪", ["CloseCurlyDoubleQuote"] = "”", ["iiint"] = "∭", ["Rcy"] = "Р", ["biguplus"] = "⨄", ["verbar"] = "|", ["Zcy"] = "З", ["Dscr"] = "𝒟", ["Sup"] = "⋑", ["zeetrf"] = "ℨ", ["HilbertSpace"] = "ℋ", ["SucceedsEqual"] = "⪰", ["bsolhsub"] = "⟈", ["SupersetEqual"] = "⊇", ["aopf"] = "𝕒", ["NJcy"] = "Њ", ["Cup"] = "⋓", ["TildeFullEqual"] = "≅", ["csube"] = "⫑", ["parsim"] = "⫳", ["Ncedil"] = "Ņ", ["top"] = "⊤", ["oelig"] = "œ", ["bsime"] = "⋍", ["cuwed"] = "⋏", ["ncongdot"] = "⩭̸", ["bigtriangledown"] = "▽", ["varsubsetneq"] = "⊊︀", ["spar"] = "∥", ["CirclePlus"] = "⊕", ["subrarr"] = "⥹", ["LowerRightArrow"] = "↘", ["npar"] = "∦", ["hookrightarrow"] = "↪", ["EmptyVerySmallSquare"] = "▫", ["abreve"] = "ă", ["arin"] = "å", ["utrif"] = "▴", ["xcap"] = "⋂", ["gsiml"] = "⪐", ["TripleDot"] = "⃛", ["cirfnint"] = "⨐", ["larrsim"] = "⥳", ["imof"] = "⊷", ["shortparallel"] = "∥", ["omicron"] = "ο", ["minusd"] = "∸", ["emptyset"] = "∅", ["Wopf"] = "𝕎", ["boxvr"] = "├", ["Uuml"] = "Ü", ["xutri"] = "△", ["EqualTilde"] = "≂", ["nge"] = "≱", ["dtri"] = "▿", ["bigotimes"] = "⨂", ["lap"] = "⪅", ["ssetmn"] = "∖", ["escr"] = "ℯ", ["LeftRightArrow"] = "↔", ["RightDoubleBracket"] = "⟧", ["Equal"] = "⩵", ["rbrke"] = "⦌", ["nsucceq"] = "⪰̸", ["uuml"] = "ü", ["ThinSpace"] = " ", ["doteq"] = "≐", ["NotGreaterTilde"] = "≵", ["bkarow"] = "⤍", ["ocirc"] = "ô", ["Gscr"] = "𝒢", ["LowerLeftArrow"] = "↙", ["SuchThat"] = "∋", ["LeftFloor"] = "⌊", ["GT"] = ">", ["Cacute"] = "Ć", ["swarrow"] = "↙", ["Cross"] = "⨯", ["perp"] = "⊥", ["dzcy"] = "џ", ["lEg"] = "⪋", ["ijlig"] = "ij", ["NotCongruent"] = "≢", ["thickapprox"] = "≈", ["gnE"] = "≩", ["supE"] = "⫆", ["thor"] = "þ", ["lrhar"] = "⇋", ["Ucir"] = "Û", ["Otimes"] = "⨷", ["sigmaf"] = "ς", ["Cedilla"] = "¸", ["odash"] = "⊝", ["gesdoto"] = "⪂", ["AMP"] = "&", ["xuplus"] = "⨄", ["theta"] = "θ", ["Hat"] = "^", ["YUcy"] = "Ю", ["osol"] = "⊘", ["Uring"] = "Ů", ["hookleftarrow"] = "↩", ["zacute"] = "ź", ["lates"] = "⪭︀", ["RightTriangle"] = "⊳", ["toea"] = "⤨", ["UpperRightArrow"] = "↗", ["ufisht"] = "⥾", ["lessapprox"] = "⪅", ["gnsim"] = "⋧", ["dsol"] = "⧶", ["upharpoonright"] = "↾", ["Cayleys"] = "ℭ", ["otimes"] = "⊗", ["Igrav"] = "Ì", ["piv"] = "ϖ", ["notin"] = "∉", ["gdot"] = "ġ", ["LJcy"] = "Љ", ["thinsp"] = " ", ["RuleDelayed"] = "⧴", ["utdot"] = "⋰", ["swarhk"] = "⤦", ["ltrPar"] = "⦖", ["rhard"] = "⇁", ["nLtv"] = "≪̸", ["DoubleDownArrow"] = "⇓", ["DiacriticalDot"] = "˙", ["mcomma"] = "⨩", ["gt"] = ">", ["scsim"] = "≿", ["rcub"] = "}", ["HorizontalLine"] = "─", ["Cconint"] = "∰", ["afr"] = "𝔞", ["rfloor"] = "⌋", ["QUOT"] = "\"", ["nsupE"] = "⫆̸", ["Ocirc"] = "Ô", ["ifr"] = "𝔦", ["szli"] = "ß", ["Iopf"] = "𝕀", ["qfr"] = "𝔮", ["lbrksld"] = "⦏", ["Gt"] = "≫", ["nsqsube"] = "⋢", ["yfr"] = "𝔶", ["SucceedsSlantEqual"] = "≽", ["rarrhk"] = "↪", ["nprec"] = "⊀", ["DiacriticalTilde"] = "˜", ["Afr"] = "𝔄", ["frac16"] = "⅙", ["subsup"] = "⫓", ["Ifr"] = "ℑ", ["equiv"] = "≡", ["Agrave"] = "À", ["Equilibrium"] = "⇌", ["ntilde"] = "ñ", ["emacr"] = "ē", ["imath"] = "ı", ["Yfr"] = "𝔜", ["Eogon"] = "Ę", ["CircleMinus"] = "⊖", ["looparrowleft"] = "↫", ["iquest"] = "¿", ["LeftTeeVector"] = "⥚", ["sopf"] = "𝕤", ["curvearrowright"] = "↷", ["ntild"] = "ñ", ["ecir"] = "ê", ["bopf"] = "𝕓", ["Ecir"] = "Ê", ["MediumSpace"] = " ", ["lesges"] = "⪓", ["cemptyv"] = "⦲", ["isin"] = "∈", ["sec"] = "§", ["TildeEqual"] = "≃", ["mapsto"] = "↦", ["xodot"] = "⨀", ["VerticalSeparator"] = "❘", ["sqsup"] = "⊐", ["oslash"] = "ø", ["setminus"] = "∖", ["ultri"] = "◸", ["bumpe"] = "≏", ["csup"] = "⫐", ["uuarr"] = "⇈", ["gtrless"] = "≷", ["GreaterLess"] = "≷", ["intcal"] = "⊺", ["Igrave"] = "Ì", ["sqsupseteq"] = "⊒", ["Intersection"] = "⋂", ["ecy"] = "э", ["SquareSupersetEqual"] = "⊒", ["Uscr"] = "𝒰", ["TildeTilde"] = "≈", ["notindot"] = "⋵̸", ["mcy"] = "м", ["divid"] = "÷", ["cuesc"] = "⋟", ["Popf"] = "ℙ", ["bNot"] = "⫭", ["ucy"] = "у", ["isinE"] = "⋹", ["cire"] = "≗", ["agrave"] = "à", ["gtquest"] = "⩼", ["DownArrowUpArrow"] = "⇵", ["Ecy"] = "Э", ["nvlArr"] = "⤂", ["imped"] = "Ƶ", ["Mcy"] = "М", ["preccurlyeq"] = "≼", ["succsim"] = "≿", ["lsh"] = "↰", ["GreaterTilde"] = "≳", ["triminus"] = "⨺", ["Ucy"] = "У", ["DoubleLeftArrow"] = "⇐", ["SOFTcy"] = "Ь", ["Proportional"] = "∝", ["ofcir"] = "⦿", ["circ"] = "ˆ", ["subsub"] = "⫕", ["quatint"] = "⨖", ["realpart"] = "ℜ", ["amp"] = "&", ["cupbrcap"] = "⩈", ["Lsh"] = "↰", ["angrtvb"] = "⊾", ["lvnE"] = "≨︀", ["Ograv"] = "Ò", ["Gdot"] = "Ġ", ["half"] = "½", ["blk12"] = "▒", ["Iota"] = "Ι", ["AEli"] = "Æ", ["squarf"] = "▪", ["cirE"] = "⧃", ["NotSubsetEqual"] = "⊈", ["simdot"] = "⩪", ["Map"] = "⤅", ["Bumpeq"] = "≎", ["roplus"] = "⨮", ["langd"] = "⦑", ["Eacut"] = "É", ["isindot"] = "⋵", ["tbrk"] = "⎴", ["xotime"] = "⨂", ["LeftDownTeeVector"] = "⥡", ["lesdotor"] = "⪃", ["ucirc"] = "û", ["breve"] = "˘", ["Sopf"] = "𝕊", ["cylcty"] = "⌭", ["iogon"] = "į", ["sc"] = "≻", ["circledS"] = "Ⓢ", ["sqsube"] = "⊑", ["rpar"] = ")", ["rrarr"] = "⇉", ["thicksim"] = "∼", ["iota"] = "ι", ["orv"] = "⩛", ["frac78"] = "⅞", ["lfisht"] = "⥼", ["Sc"] = "⪼", ["blacksquare"] = "▪", ["ShortLeftArrow"] = "←", ["DownArrow"] = "↓", ["gesles"] = "⪔", ["dfisht"] = "⥿", ["sdote"] = "⩦", ["eqvparsl"] = "⧥", ["roang"] = "⟭", ["ulcorner"] = "⌜", ["jsercy"] = "ј", ["Bopf"] = "𝔹", ["nleqq"] = "≦̸", ["Racute"] = "Ŕ", ["ngE"] = "≧̸", ["LT"] = "<", ["tau"] = "τ", ["bernou"] = "ℬ", ["nvlt"] = "<⃒", ["succnsim"] = "⋩", ["isinsv"] = "⋳", ["lagran"] = "ℒ", ["rharu"] = "⇀", ["lopf"] = "𝕝", ["RBarr"] = "⤐", ["acE"] = "∾̳", ["ast"] = "*", ["supne"] = "⊋", ["Acirc"] = "Â", ["chcy"] = "ч", ["crarr"] = "↵", ["vltri"] = "⊲", ["boxplus"] = "⊞", ["circeq"] = "≗", ["prnE"] = "⪵", ["awconint"] = "∳", ["succnapprox"] = "⪺", ["boxvh"] = "┼", ["curvearrowleft"] = "↶", ["hardcy"] = "ъ", ["semi"] = ";", ["yacute"] = "ý", ["ccaps"] = "⩍", ["Ntild"] = "Ñ", ["barvee"] = "⊽", ["LeftTriangleEqual"] = "⊴", ["npr"] = "⊀", ["jcirc"] = "ĵ", ["sqsub"] = "⊏", ["subedot"] = "⫃", ["Square"] = "□", ["rbrace"] = "}", ["duarr"] = "⇵", ["NotLessGreater"] = "≸", ["disin"] = "⋲", ["rlm"] = "‏", ["lhard"] = "↽", ["map"] = "↦", ["ap"] = "≈", ["Uacut"] = "Ú", ["OpenCurlyDoubleQuote"] = "“", ["rarrb"] = "⇥", ["lrtri"] = "⊿", ["olcross"] = "⦻", ["varphi"] = "ϕ", ["xfr"] = "𝔵", ["nGtv"] = "≫̸", ["supsup"] = "⫖", ["Eopf"] = "𝔼", ["LeftArrowBar"] = "⇤", ["yum"] = "ÿ", ["hellip"] = "…", ["Nscr"] = "𝒩", ["Hfr"] = "ℌ", ["aum"] = "ä", ["mac"] = "¯", ["pfr"] = "𝔭", ["DownArrowBar"] = "⤓", ["ium"] = "ï", ["emsp"] = " ", ["Xfr"] = "𝔛", ["Lt"] = "≪", ["pre"] = "⪯", ["ngeqq"] = "≧̸", ["cudarrr"] = "⤵", ["oopf"] = "𝕠", ["fpartint"] = "⨍", ["yacut"] = "ý", ["FilledVerySmallSquare"] = "▪", ["xscr"] = "𝓍", ["Aum"] = "Ä", ["Otilde"] = "Õ", ["nabla"] = "∇", ["Pfr"] = "𝔓", ["plusdu"] = "⨥", ["Ium"] = "Ï", ["iinfin"] = "⧜", ["eacut"] = "é", ["Agrav"] = "À", ["ye"] = "¥", ["emsp13"] = " ", ["tint"] = "∭", ["Iscr"] = "ℐ", ["divideontimes"] = "⋇", ["NotVerticalBar"] = "∤", ["olcir"] = "⦾", ["pertenk"] = "‱", ["ntrianglerighteq"] = "⋭", ["mnplus"] = "∓", ["nhArr"] = "⇎", ["ImaginaryI"] = "ⅈ", ["tprime"] = "‴", ["rightleftharpoons"] = "⇌", ["Larr"] = "↞", ["sigma"] = "σ", ["mu"] = "μ", ["ngsim"] = "≵", ["Integral"] = "∫", ["asymp"] = "≈", ["rtrie"] = "⊵", ["sqcap"] = "⊓", ["rightsquigarrow"] = "↝", ["vert"] = "|", ["lcedil"] = "ļ", ["scnsim"] = "⋩", ["cen"] = "¢", ["ldquor"] = "„", ["precneqq"] = "⪵", ["Mu"] = "Μ", ["dcy"] = "д", ["xvee"] = "⋁", ["COPY"] = "©", ["natural"] = "♮", ["Vert"] = "‖", ["lcy"] = "л", ["twoheadrightarrow"] = "↠", ["apid"] = "≋", ["tcy"] = "т", ["gescc"] = "⪩", ["Hopf"] = "ℍ", ["elinters"] = "⏧", ["vnsup"] = "⊃⃒", ["oacut"] = "ó", ["Dcy"] = "Д", ["loz"] = "◊", ["Lopf"] = "𝕃", ["daleth"] = "ℸ", ["Lcy"] = "Л", ["scnE"] = "⪶", ["larrfs"] = "⤝", ["Zcaron"] = "Ž", ["ForAll"] = "∀", ["DoubleUpDownArrow"] = "⇕", ["backprime"] = "‵", ["psi"] = "ψ", ["lnap"] = "⪉", ["profline"] = "⌒", ["bot"] = "⊥", ["Therefore"] = "∴", ["frac18"] = "⅛", ["wr"] = "≀", ["prop"] = "∝", ["par"] = "∥", ["bsol"] = "\\", ["nvsim"] = "∼⃒", ["longmapsto"] = "⟼", ["nscr"] = "𝓃", ["hfr"] = "𝔥", ["Rcaron"] = "Ř", ["epsi"] = "ε", ["sect"] = "§", ["nleqslant"] = "⩽̸", ["lthree"] = "⋋", ["blk14"] = "░", ["zcaron"] = "ž", ["Tcedil"] = "Ţ", ["rbbrk"] = "❳", ["lrarr"] = "⇆", ["duhar"] = "⥯", ["notinE"] = "⋹̸", ["precnsim"] = "⋨", ["rAarr"] = "⇛", ["agrav"] = "à", ["DiacriticalAcute"] = "´", ["cwint"] = "∱", ["napos"] = "ʼn", ["Or"] = "⩔", ["nedot"] = "≐̸", ["simlE"] = "⪟", ["trie"] = "≜", ["vDash"] = "⊨", ["LeftTriangle"] = "⊲", ["L"] = "<", ["gg"] = "≫", ["rcaron"] = "ř", ["nparsl"] = "⫽⃥", ["bne"] = "=⃥", ["nsubE"] = "⫅̸", ["RightTeeVector"] = "⥛", ["Oopf"] = "𝕆", ["ETH"] = "Ð", ["kgreen"] = "ĸ", ["scpolint"] = "⨓", ["LessGreater"] = "≶", ["oror"] = "⩖", ["sol"] = "/", ["llcorner"] = "⌞", ["nearhk"] = "⤤", ["Gg"] = "⋙", ["DifferentialD"] = "ⅆ", ["time"] = "×", ["VeryThinSpace"] = " ", ["coprod"] = "∐", ["napid"] = "≋̸", ["RightDownVector"] = "⇂", ["barwed"] = "⌅", ["ldrushar"] = "⥋", ["orslope"] = "⩗", ["iexcl"] = "¡", ["Longleftrightarrow"] = "⟺", ["boxdl"] = "┐", ["Aacute"] = "Á", ["ltri"] = "◃", ["reals"] = "ℝ", ["Beta"] = "Β", ["plusb"] = "⊞", ["ET"] = "Ð", ["Yacut"] = "Ý", ["nesear"] = "⤨", ["Proportion"] = "∷", ["Tilde"] = "∼", ["DJcy"] = "Ђ", ["longleftrightarrow"] = "⟷", ["trisb"] = "⧍", ["OverBracket"] = "⎴", ["varpi"] = "ϖ", ["hopf"] = "𝕙", ["supnE"] = "⫌", ["natur"] = "♮", ["RightTriangleEqual"] = "⊵", ["supsub"] = "⫔", ["capdot"] = "⩀", ["straightepsilon"] = "ϵ", ["PartialD"] = "∂", ["Aring"] = "Å", ["NegativeVeryThinSpace"] = "​", ["subseteqq"] = "⫅", ["tscy"] = "ц", ["l"] = "<", ["NotGreaterLess"] = "≹", ["UnderBar"] = "_", ["UpArrow"] = "↑", ["lscr"] = "𝓁", ["smt"] = "⪪", ["eth"] = "ð", ["forall"] = "∀", ["CenterDot"] = "·", ["lfloor"] = "⌊", ["topbot"] = "⌶", ["leftthreetimes"] = "⋋", ["boxv"] = "│", ["boxdR"] = "╒", ["RightUpVectorBar"] = "⥔", ["supsetneq"] = "⊋", ["rightharpoondown"] = "⇁", ["lsime"] = "⪍", ["rho"] = "ρ", ["gtlPar"] = "⦕", ["NotEqualTilde"] = "≂̸", ["infintie"] = "⧝", ["larrhk"] = "↩", ["prnap"] = "⪹", ["star"] = "☆", ["gfr"] = "𝔤", ["between"] = "≬", ["VDash"] = "⊫", ["ofr"] = "𝔬", ["seArr"] = "⇘", ["preceq"] = "⪯", ["Rho"] = "Ρ", ["NegativeThinSpace"] = "​", ["larr"] = "←", ["kopf"] = "𝕜", ["xsqcup"] = "⨆", ["strns"] = "¯", ["Rscr"] = "ℛ", ["Gfr"] = "𝔊", ["smashp"] = "⨳", ["GJcy"] = "Ѓ", ["lotimes"] = "⨴", ["nrtri"] = "⋫", ["boxVl"] = "╢", ["icirc"] = "î", ["Ofr"] = "𝔒", ["circledR"] = "®", ["Ograve"] = "Ò", ["Wfr"] = "𝔚", ["NotLessLess"] = "≪̸", ["Iukcy"] = "І", ["ne"] = "≠", ["centerdot"] = "·", ["sccue"] = "≽", ["boxul"] = "┘", ["NotSucceeds"] = "⊁", ["lmoust"] = "⎰", ["supedot"] = "⫄", ["downarrow"] = "↓", ["ljcy"] = "љ", ["Lcaron"] = "Ľ", ["Barv"] = "⫧", ["suphsub"] = "⫗", ["loang"] = "⟬", ["ntlg"] = "≸", ["beta"] = "β", ["malt"] = "✠", ["ascr"] = "𝒶", ["Ouml"] = "Ö", ["capbrcup"] = "⩉", ["sub"] = "⊂", ["Ccedil"] = "Ç", ["subset"] = "⊂", ["prec"] = "≺", ["igrave"] = "ì", ["bottom"] = "⊥", ["NotTildeEqual"] = "≄", ["andv"] = "⩚", ["laqu"] = "«", ["nwarr"] = "↖", ["cupor"] = "⩅", ["vsupnE"] = "⫌︀", ["Dagger"] = "‡", ["prE"] = "⪳", ["integers"] = "ℤ", ["iacute"] = "í", ["pm"] = "±", ["cupcap"] = "⩆", ["ldca"] = "⤶", ["cups"] = "∪︀", ["Downarrow"] = "⇓", ["frac23"] = "⅔", ["Iacute"] = "Í", ["starf"] = "★", ["Arin"] = "Å", ["rtri"] = "▹", ["DownRightVectorBar"] = "⥗", ["Updownarrow"] = "⇕", ["mlcp"] = "⫛", ["Barwed"] = "⌆", ["ContourIntegral"] = "∮", ["RightArrow"] = "→", ["prurel"] = "⊰", ["planckh"] = "ℎ", ["rect"] = "▭", ["efDot"] = "≒", ["eplus"] = "⩱", ["topfork"] = "⫚", ["lBarr"] = "⤎", ["ffilig"] = "ffi", ["para"] = "¶", ["diamond"] = "⋄", ["barwedge"] = "⌅", ["supseteqq"] = "⫆", ["bowtie"] = "⋈", ["divide"] = "÷", ["scedil"] = "ş", ["nwnear"] = "⤧", ["origof"] = "⊶", ["rmoustache"] = "⎱", ["Mscr"] = "ℳ", ["backsimeq"] = "⋍", ["Element"] = "∈", ["subE"] = "⫅", ["wedgeq"] = "≙", ["percnt"] = "%", ["gla"] = "⪥", ["nvrArr"] = "⤃", ["boxUr"] = "╙", ["DownLeftVector"] = "↽", ["smeparsl"] = "⧤", ["xmap"] = "⟼", ["nharr"] = "↮", ["otimesas"] = "⨶", ["cupdot"] = "⊍", ["ffr"] = "𝔣", ["nbumpe"] = "≏̸", ["Oacute"] = "Ó", ["ccirc"] = "ĉ", ["lHar"] = "⥢", ["Fcy"] = "Ф", ["ocy"] = "о", ["lessdot"] = "⋖", ["NotCupCap"] = "≭", ["simne"] = "≆", ["nspar"] = "∦", ["Lstrok"] = "Ł", ["euro"] = "€", ["Longrightarrow"] = "⟹", ["NotExists"] = "∄", ["zopf"] = "𝕫", ["NotGreaterEqual"] = "≱", ["boxV"] = "║", ["ograve"] = "ò", ["harrw"] = "↭", ["jmath"] = "ȷ", ["Rarrtl"] = "⤖", ["rarrfs"] = "⤞", ["RightVector"] = "⇀", ["uwangle"] = "⦧", ["RightVectorBar"] = "⥓", ["nparallel"] = "∦", ["DZcy"] = "Џ", ["nltrie"] = "⋬", ["cedil"] = "¸", ["Gcy"] = "Г", ["Precedes"] = "≺", ["sce"] = "⪰", ["angrt"] = "∟", ["UnderParenthesis"] = "⏝", ["ngeqslant"] = "⩾̸", ["nopf"] = "𝕟", ["nleftarrow"] = "↚", ["Ocy"] = "О", ["precnapprox"] = "⪹", ["sube"] = "⊆", ["boxhd"] = "┬", ["bscr"] = "𝒷", ["lg"] = "≶", ["dotminus"] = "∸", ["vartriangleright"] = "⊳", ["leqq"] = "≦", ["Ccaron"] = "Č", ["Mellintrf"] = "ℳ", ["nhpar"] = "⫲", ["boxVh"] = "╫", ["wscr"] = "𝓌", ["rharul"] = "⥬", ["scnap"] = "⪺", ["curlyvee"] = "⋎", ["in"] = "∈", ["ddotseq"] = "⩷", ["esim"] = "≂", ["subsetneq"] = "⊊", ["minusdu"] = "⨪", ["Star"] = "⋆", ["nsub"] = "⊄", ["Because"] = "∵", ["Jfr"] = "𝔍", ["RightTriangleBar"] = "⧐", ["circlearrowright"] = "↻", ["Amacr"] = "Ā", ["rbarr"] = "⤍", ["Jukcy"] = "Є", ["nsqsupe"] = "⋣", ["ShortDownArrow"] = "↓", ["nvgt"] = ">⃒", ["fnof"] = "ƒ", ["aacute"] = "á", ["NotRightTriangle"] = "⋫", ["lsquo"] = "‘", ["scaron"] = "š", ["sqcups"] = "⊔︀", ["backcong"] = "≌", ["rang"] = "⟩", ["hearts"] = "♥", ["larrbfs"] = "⤟", ["omid"] = "⦶", ["iuml"] = "ï", ["pluse"] = "⩲", ["Kappa"] = "Κ", ["rsquo"] = "’", ["bigtriangleup"] = "△", ["YAcy"] = "Я", ["kcedil"] = "ķ", ["iiota"] = "℩", ["vsupne"] = "⊋︀", ["lAtail"] = "⤛", ["RightCeiling"] = "⌉", ["cularr"] = "↶", ["primes"] = "ℙ", ["Aacut"] = "Á", ["bullet"] = "•", ["LeftUpVectorBar"] = "⥘", ["LongLeftRightArrow"] = "⟷", ["backepsilon"] = "϶", ["dscr"] = "𝒹", ["frac1"] = "½", ["epsiv"] = "ϵ", ["male"] = "♂", ["lcaron"] = "ľ", ["nsimeq"] = "≄", ["andand"] = "⩕", ["Kcedil"] = "Ķ", ["lsqb"] = "[", ["Scedil"] = "Ş", ["boxDr"] = "╓", ["hksearow"] = "⤥", ["sqsubset"] = "⊏", ["digamma"] = "ϝ", ["ThickSpace"] = "  ", ["bnot"] = "⌐", ["Pscr"] = "𝒫", ["SquareUnion"] = "⊔", ["Chi"] = "Χ", ["NotDoubleVerticalBar"] = "∦", ["lparlt"] = "⦓", ["Vbar"] = "⫫", ["gjcy"] = "ѓ", ["die"] = "¨", ["oS"] = "Ⓢ", ["because"] = "∵", ["NotEqual"] = "≠", ["gcy"] = "г", ["xoplus"] = "⨁", ["thetav"] = "ϑ", ["bigodot"] = "⨀", ["equals"] = "=", ["parsl"] = "⫽", ["Ccedi"] = "Ç", ["nlt"] = "≮", ["LongRightArrow"] = "⟶", ["uopf"] = "𝕦", ["race"] = "∽̱", ["DoubleLongLeftArrow"] = "⟸", ["solbar"] = "⌿", ["ac"] = "∾", ["angrtvbd"] = "⦝", ["imagline"] = "ℐ", ["ulcrop"] = "⌏", ["vrtri"] = "⊳", ["nprcue"] = "⋠", ["Kopf"] = "𝕂", ["supsetneqq"] = "⫌", ["ic"] = "⁣", ["nsupseteq"] = "⊉", ["Verbar"] = "‖", ["fcy"] = "ф", ["lesseqqgtr"] = "⪋", ["gesl"] = "⋛︀", ["Jsercy"] = "Ј", ["iecy"] = "е", ["leftharpoondown"] = "↽", ["times"] = "×", ["NotGreater"] = "≯", ["prcue"] = "≼", ["cap"] = "∩", ["rtrif"] = "▸", ["Otild"] = "Õ", ["Omega"] = "Ω", ["ntriangleleft"] = "⋪", ["rBarr"] = "⤏", ["frac34"] = "¾", ["szlig"] = "ß", ["pointint"] = "⨕", ["Sacute"] = "Ś", ["Hacek"] = "ˇ", ["Iuml"] = "Ï", ["Hstrok"] = "Ħ", ["af"] = "⁡", ["cedi"] = "¸", ["curlyeqsucc"] = "⋟", ["notinvb"] = "⋷", ["LeftArrow"] = "←", ["Uogon"] = "Ų", ["ApplyFunction"] = "⁡", ["nexists"] = "∄", ["rarrw"] = "↝", ["Uopf"] = "𝕌", ["sqcaps"] = "⊓︀", ["Darr"] = "↡", ["square"] = "□", ["no"] = "¬", ["KJcy"] = "Ќ", ["DoubleLongLeftRightArrow"] = "⟺", ["bigoplus"] = "⨁", ["ang"] = "∠", ["isins"] = "⋴", ["Cap"] = "⋒", ["ldrdhar"] = "⥧", ["minusb"] = "⊟", ["DownBreve"] = "̑", ["hArr"] = "⇔", ["udhar"] = "⥮", ["nrArr"] = "⇏", ["shchcy"] = "щ", ["NotLessEqual"] = "≰", ["SHcy"] = "Ш", ["plankv"] = "ℏ", ["poun"] = "£", ["lvertneqq"] = "≨︀", ["dopf"] = "𝕕", ["varnothing"] = "∅", ["succapprox"] = "⪸", ["caret"] = "⁁", ["nwarrow"] = "↖", ["Exists"] = "∃", ["varsubsetneqq"] = "⫋︀", ["Ccirc"] = "Ĉ", ["lsimg"] = "⪏", ["Yacute"] = "Ý", ["nLl"] = "⋘̸", ["racute"] = "ŕ", ["leftrightsquigarrow"] = "↭", ["xcup"] = "⋃", ["leftrightarrow"] = "↔", ["supmult"] = "⫂", ["LeftUpTeeVector"] = "⥠", ["UnderBrace"] = "⏟", ["varr"] = "↕", ["PrecedesTilde"] = "≾", ["gcirc"] = "ĝ", ["diams"] = "♦", ["geq"] = "≥", ["rhov"] = "ϱ", ["phi"] = "φ", ["Superset"] = "⊃", ["DownLeftTeeVector"] = "⥞", ["Sigma"] = "Σ", ["lsaquo"] = "‹", ["NotHumpDownHump"] = "≎̸", ["triangleq"] = "≜", ["hstrok"] = "ħ", ["gesdot"] = "⪀", ["risingdotseq"] = "≓", ["luruhar"] = "⥦", ["lbrack"] = "[", ["varepsilon"] = "ϵ", ["nrarrc"] = "⤳̸", ["DownTeeArrow"] = "↧", ["nvDash"] = "⊭", ["Euml"] = "Ë", ["it"] = "⁢", ["homtht"] = "∻", ["els"] = "⪕", ["elsdot"] = "⪗", ["nges"] = "⩾̸", ["rarrc"] = "⤳", ["Subset"] = "⋐", ["cirscir"] = "⧂", ["YIcy"] = "Ї", ["Leftrightarrow"] = "⇔", ["Cfr"] = "ℭ", ["rightarrowtail"] = "↣", ["quest"] = "?", ["telrec"] = "⌕", ["Wedge"] = "⋀", ["ouml"] = "ö", ["brvbar"] = "¦", ["Sscr"] = "𝒮", ["planck"] = "ℏ", ["scE"] = "⪴", ["Wscr"] = "𝒲", ["xharr"] = "⟷", ["rlhar"] = "⇌", ["Vvdash"] = "⊪", ["circledast"] = "⊛", ["gvertneqq"] = "≩︀", ["varsigma"] = "ς", ["realine"] = "ℛ", ["ltrie"] = "⊴", ["precapprox"] = "⪷", ["Re"] = "ℜ", ["prod"] = "∏", ["ograv"] = "ò", ["maltese"] = "✠", ["Ffr"] = "𝔉", ["ropar"] = "⦆", ["NegativeThickSpace"] = "​", ["Tscr"] = "𝒯", ["ccedil"] = "ç", ["frown"] = "⌢", ["nlsim"] = "≴", ["midcir"] = "⫰", ["nang"] = "∠⃒", ["excl"] = "!", ["supdsub"] = "⫘", ["dharl"] = "⇃", ["boxHd"] = "╤", ["Zopf"] = "ℤ", ["Longleftarrow"] = "⟸", ["dbkarow"] = "⤏", ["scy"] = "с", ["gE"] = "≧", ["hkswarow"] = "⤦", ["el"] = "⪙", ["copysr"] = "℗", ["Ucirc"] = "Û", ["acirc"] = "â", ["popf"] = "𝕡", ["frac35"] = "⅗", ["npart"] = "∂̸", ["lbrke"] = "⦋", ["Tcaron"] = "Ť", ["aleph"] = "ℵ", ["AM"] = "&", ["THORN"] = "Þ", ["varkappa"] = "ϰ", ["rtimes"] = "⋊", ["gtreqless"] = "⋛", ["yucy"] = "ю", ["lharu"] = "↼", ["leftharpoonup"] = "↼", ["ClockwiseContourIntegral"] = "∲", ["boxUR"] = "╚", ["Xopf"] = "𝕏", ["brvba"] = "¦", ["boxVr"] = "╟", ["wp"] = "℘", ["doteqdot"] = "≑", ["spadesuit"] = "♠", ["ell"] = "ℓ", ["longleftarrow"] = "⟵", ["uarr"] = "↑", ["blacktriangleright"] = "▸", ["Sub"] = "⋐", ["subdot"] = "⪽", ["urtri"] = "◹", ["naturals"] = "ℕ", ["langle"] = "⟨", ["supset"] = "⊃", ["Breve"] = "˘", ["NotSquareSubsetEqual"] = "⋢", ["notnivb"] = "⋾", ["downharpoonright"] = "⇂", ["sime"] = "≃", ["bprime"] = "‵", ["ngtr"] = "≯", ["succneqq"] = "⪶", ["notnivc"] = "⋽", ["phmmat"] = "ℳ", ["eparsl"] = "⧣", ["macr"] = "¯", ["aring"] = "å", ["gesdotol"] = "⪄", ["sdot"] = "⋅", ["RightArrowBar"] = "⇥", ["Pcy"] = "П", ["clubs"] = "♣", ["Vdashl"] = "⫦", ["Ugrave"] = "Ù", ["or"] = "∨", ["nleq"] = "≰", ["curarrm"] = "⤼", ["NestedGreaterGreater"] = "≫", ["mstpos"] = "∾", ["awint"] = "⨑", ["nVdash"] = "⊮", ["NotSquareSubset"] = "⊏̸", ["UnderBracket"] = "⎵", ["rightrightarrows"] = "⇉", ["IOcy"] = "Ё", ["zcy"] = "з", ["lowast"] = "∗", ["nfr"] = "𝔫", ["exponentiale"] = "ⅇ", ["aeli"] = "æ", ["RightArrowLeftArrow"] = "⇄", ["raemptyv"] = "⦳", ["zhcy"] = "ж", ["uHar"] = "⥣", ["spades"] = "♠", ["vfr"] = "𝔳", ["oacute"] = "ó", ["Atilde"] = "Ã", ["sim"] = "∼", ["swnwar"] = "⤪", ["eqsim"] = "≂", ["ExponentialE"] = "ⅇ", ["oum"] = "ö", ["IJlig"] = "IJ", ["questeq"] = "≟", ["Zdot"] = "Ż", ["rsaquo"] = "›", ["rsh"] = "↱", ["yicy"] = "ї", ["gopf"] = "𝕘", ["caps"] = "∩︀", ["lurdshar"] = "⥊", ["ordm"] = "º", ["cir"] = "○", ["nvltrie"] = "⊴⃒", ["lcub"] = "{", ["lt"] = "<", ["circlearrowleft"] = "↺", ["boxDL"] = "╗", ["Nfr"] = "𝔑", ["ge"] = "≥", ["LeftUpVector"] = "↿", ["ord"] = "ª", ["PrecedesSlantEqual"] = "≼", ["Supset"] = "⋑", ["nwarhk"] = "⤣", ["angsph"] = "∢", ["Vfr"] = "𝔙", ["part"] = "∂", ["smallsetminus"] = "∖", ["sqsupset"] = "⊐", ["Gcirc"] = "Ĝ", ["Gopf"] = "𝔾", ["raqu"] = "»", ["Oum"] = "Ö", ["UpTeeArrow"] = "↥", ["ngt"] = "≯", ["boxHD"] = "╦", ["diam"] = "⋄", ["npre"] = "⪯̸", ["ddarr"] = "⇊", ["quaternions"] = "ℍ", ["Union"] = "⋃", ["nexist"] = "∄", ["ccaron"] = "č", ["itilde"] = "ĩ", ["rarrlp"] = "↬", ["subnE"] = "⫋", ["gtrarr"] = "⥸", ["pluscir"] = "⨢", ["apacir"] = "⩯", ["NotElement"] = "∉", ["bemptyv"] = "⦰", ["rbrack"] = "]", ["slarr"] = "←", ["iques"] = "¿", ["Rrightarrow"] = "⇛", ["Omacr"] = "Ō", ["Ascr"] = "𝒜", ["swarr"] = "↙", ["NotSupersetEqual"] = "⊉", ["atilde"] = "ã", ["Emacr"] = "Ē", ["ni"] = "∋", ["am"] = "&", ["nshortparallel"] = "∦", ["Vee"] = "⋁", ["rcedil"] = "ŗ", ["gvnE"] = "≩︀", ["bigvee"] = "⋁", ["female"] = "♀", ["sfrown"] = "⌢", ["um"] = "¨", ["Qfr"] = "𝔔", ["uharr"] = "↾", ["FilledSmallSquare"] = "◼", ["varrho"] = "ϱ", ["dtrif"] = "▾", ["uacute"] = "ú", ["NotPrecedes"] = "⊀", ["upuparrows"] = "⇈", ["KHcy"] = "Х", ["heartsuit"] = "♥", ["seswar"] = "⤩", ["bcy"] = "б", ["acir"] = "â", ["Fscr"] = "ℱ", ["Xscr"] = "𝒳", ["Im"] = "ℑ", ["Ubrcy"] = "Ў", ["amalg"] = "⨿", ["fjlig"] = "fj", ["mapstoup"] = "↥", ["Acir"] = "Â", ["lAarr"] = "⇚", ["loarr"] = "⇽", ["Mopf"] = "𝕄", ["neArr"] = "⇗", ["kappa"] = "κ", ["uhblk"] = "▀", ["LeftCeiling"] = "⌈", ["middo"] = "·", ["ReverseEquilibrium"] = "⇋", ["UpArrowDownArrow"] = "⇅", ["plusmn"] = "±", ["nsim"] = "≁", ["rArr"] = "⇒", ["emsp14"] = " ", ["lozf"] = "⧫", ["nle"] = "≰", ["andd"] = "⩜", ["egs"] = "⪖", ["RoundImplies"] = "⥰", ["rlarr"] = "⇄", ["lobrk"] = "⟦", ["nsube"] = "⊈", ["uharl"] = "↿", ["lmidot"] = "ŀ", ["DotEqual"] = "≐", ["lnapprox"] = "⪉", ["period"] = ".", ["ccupssm"] = "⩐", ["equivDD"] = "⩸", ["boxtimes"] = "⊠", ["vopf"] = "𝕧", ["ncy"] = "н", ["yopf"] = "𝕪", ["boxminus"] = "⊟", ["scap"] = "⪸", ["hybull"] = "⁃", ["profalar"] = "⌮", ["xlArr"] = "⟸", ["ring"] = "˚", ["vcy"] = "в", ["oscr"] = "ℴ", ["bcong"] = "≌", ["tstrok"] = "ŧ", ["downharpoonleft"] = "⇃", ["NotLessSlantEqual"] = "⩽̸", ["oint"] = "∮", ["bdquo"] = "„", ["rAtail"] = "⤜", ["Laplacetrf"] = "ℒ", ["fscr"] = "𝒻", ["Theta"] = "Θ", ["CircleTimes"] = "⊗", ["DoubleLeftTee"] = "⫤", ["rdquor"] = "”", ["gel"] = "⋛", ["prsim"] = "≾", ["dwangle"] = "⦦", ["Imacr"] = "Ī", ["UpTee"] = "⊥", ["Tau"] = "Τ", ["hcirc"] = "ĥ", ["srarr"] = "→", ["jscr"] = "𝒿", ["Ncy"] = "Н", ["opar"] = "⦷", ["Gbreve"] = "Ğ", ["eDot"] = "≑", ["Uarr"] = "↟", ["QUO"] = "\"", ["EmptySmallSquare"] = "◻", ["curre"] = "¤", ["Vcy"] = "В", ["laemptyv"] = "⦴", ["Jcy"] = "Й", ["gsime"] = "⪎", ["apos"] = "'", ["Edot"] = "Ė", ["commat"] = "@", ["yuml"] = "ÿ", ["RightFloor"] = "⌋", ["Coproduct"] = "∐", ["boxdr"] = "┌", ["ssmile"] = "⌣", ["lesseqgtr"] = "⋚", ["hamilt"] = "ℋ", ["notniva"] = "∌", ["rthree"] = "⋌", ["iff"] = "⇔", ["longrightarrow"] = "⟶", ["thksim"] = "∼", ["Diamond"] = "⋄", ["ohbar"] = "⦵", ["searr"] = "↘", ["uplus"] = "⊎", ["otild"] = "õ", ["angmsd"] = "∡", ["oplus"] = "⊕", ["Sfr"] = "𝔖", ["nsime"] = "≄", ["nvdash"] = "⊬", ["UpEquilibrium"] = "⥮", ["middot"] = "·", ["Rcedil"] = "Ŗ", ["eopf"] = "𝕖", ["euml"] = "ë", ["Epsilon"] = "Ε", ["dot"] = "˙", ["boxVH"] = "╬", ["nGg"] = "⋙̸", ["rdca"] = "⤷", ["THOR"] = "Þ", ["nldr"] = "‥", ["rightleftarrows"] = "⇄", ["ltimes"] = "⋉", ["supe"] = "⊇", ["frac38"] = "⅜", ["zwj"] = "‍", ["nsucc"] = "⊁", ["GreaterEqual"] = "≥", ["circledcirc"] = "⊚", ["Scaron"] = "Š", ["Ntilde"] = "Ñ", ["NotRightTriangleBar"] = "⧐̸", ["parallel"] = "∥", ["dcaron"] = "ď", ["nLt"] = "≪⃒", ["VerticalLine"] = "|", ["Ubreve"] = "Ŭ", ["sup1"] = "¹", ["Dcaron"] = "Ď", ["Psi"] = "Ψ", ["ovbar"] = "⌽", ["xwedge"] = "⋀", ["rarrtl"] = "↣", ["ange"] = "⦤", ["LeftVector"] = "↼", ["nsupset"] = "⊃⃒", ["supdot"] = "⪾", ["Dot"] = "¨", ["rdldhar"] = "⥩", ["blank"] = "␣", ["kcy"] = "к", ["numero"] = "№", ["DoubleDot"] = "¨", ["tdot"] = "⃛", ["hyphen"] = "‐", ["roarr"] = "⇾", ["LongLeftArrow"] = "⟵", ["frac12"] = "½", ["NotPrecedesEqual"] = "⪯̸", ["oast"] = "⊛", ["rightthreetimes"] = "⋌", ["leftrightharpoons"] = "⇋", ["Nacute"] = "Ń", ["wfr"] = "𝔴", ["cuepr"] = "⋞", ["Conint"] = "∯", ["boxvR"] = "╞", ["Gamma"] = "Γ", ["nvge"] = "≥⃒", ["UpperLeftArrow"] = "↖", ["wedbar"] = "⩟", ["dharr"] = "⇂", ["plussim"] = "⨦", ["ltcc"] = "⪦", ["Pi"] = "Π", ["angmsdaa"] = "⦨", ["SquareIntersection"] = "⊓", ["Cdot"] = "Ċ", ["beth"] = "ℶ", ["nsupseteqq"] = "⫆̸", ["dArr"] = "⇓", ["LeftTriangleBar"] = "⧏", ["hslash"] = "ℏ", ["delta"] = "δ", ["pscr"] = "𝓅", ["vangrt"] = "⦜", ["gacute"] = "ǵ", ["vBarv"] = "⫩", ["boxDR"] = "╔", ["dlcrop"] = "⌍", ["lceil"] = "⌈", ["ltlarr"] = "⥶", ["upharpoonleft"] = "↿", ["uring"] = "ů", ["gammad"] = "ϝ", ["tscr"] = "𝓉", ["bsim"] = "∽", ["LeftTeeArrow"] = "↤", ["et"] = "ð", ["lne"] = "⪇", ["ubreve"] = "ŭ", ["DotDot"] = "⃜", ["tcaron"] = "ť", ["UpArrowBar"] = "⤒", ["ucir"] = "û", ["nsccue"] = "⋡", ["Aopf"] = "𝔸", ["DownRightVector"] = "⇁", ["cfr"] = "𝔠", ["angle"] = "∠", ["simeq"] = "≃", ["eg"] = "⪚", ["DiacriticalGrave"] = "`", ["Backslash"] = "∖", ["eogon"] = "ę", ["erarr"] = "⥱", ["ee"] = "ⅇ", ["models"] = "⊧", ["csub"] = "⫏", ["inodot"] = "ı", ["NotRightTriangleEqual"] = "⋭", ["dashv"] = "⊣", ["gimel"] = "ℷ", ["nvap"] = "≍⃒", ["ecirc"] = "ê", ["siml"] = "⪝", ["and"] = "∧", ["dollar"] = "$", ["qscr"] = "𝓆", ["submult"] = "⫁", ["cent"] = "¢", ["rnmid"] = "⫮", ["LeftTee"] = "⊣", ["qopf"] = "𝕢", ["rsqb"] = "]", ["bbrktbrk"] = "⎶", ["expectation"] = "ℰ", ["njcy"] = "њ", ["djcy"] = "ђ", ["profsurf"] = "⌓", ["boxHU"] = "╩", ["bumpeq"] = "≏", ["boxvH"] = "╪", ["GreaterEqualLess"] = "⋛", ["lneqq"] = "≨", ["xnis"] = "⋻", ["olt"] = "⧀", ["minus"] = "−", ["les"] = "⩽", ["xlarr"] = "⟵", ["colone"] = "≔", ["larrpl"] = "⤹", ["triangledown"] = "▿", ["lnE"] = "≨", ["simrarr"] = "⥲", ["comp"] = "∁", ["angmsdae"] = "⦬", ["LessLess"] = "⪡", ["And"] = "⩓", ["forkv"] = "⫙", ["NotNestedLessLess"] = "⪡̸", ["ReverseUpEquilibrium"] = "⥯", ["rotimes"] = "⨵", ["RightAngleBracket"] = "⟩", ["nbsp"] = " ", ["smtes"] = "⪬︀", ["Lcedil"] = "Ļ", ["nearr"] = "↗", ["searrow"] = "↘", ["napE"] = "⩰̸", ["drbkarow"] = "⤐", ["iopf"] = "𝕚", ["Not"] = "⫬", ["Upsilon"] = "Υ", ["Ecaron"] = "Ě", ["ncup"] = "⩂", ["zwnj"] = "‌", ["ominus"] = "⊖", ["Tstrok"] = "Ŧ", ["Tcy"] = "Т", ["vprop"] = "∝", ["lat"] = "⪫", ["DoubleLeftRightArrow"] = "⇔", ["OverParenthesis"] = "⏜", ["DScy"] = "Ѕ", ["doublebarwedge"] = "⌆", ["Itilde"] = "Ĩ", ["puncsp"] = " ", ["bigsqcup"] = "⨆", ["nvHarr"] = "⤄", ["Oslash"] = "Ø", ["bnequiv"] = "≡⃥", ["vartriangleleft"] = "⊲", ["rscr"] = "𝓇", ["umacr"] = "ū", ["raquo"] = "»", ["nGt"] = "≫⃒", ["tcedil"] = "ţ", ["demptyv"] = "⦱", ["backsim"] = "∽", ["triplus"] = "⨹", ["mldr"] = "…", ["UpDownArrow"] = "↕", ["rangle"] = "⟩", ["topcir"] = "⫱", ["RightDownVectorBar"] = "⥕", ["ntriangleright"] = "⋫", ["iiiint"] = "⨌", ["smid"] = "∣", ["Dfr"] = "𝔇", ["Eacute"] = "É", ["order"] = "ℴ", ["larrb"] = "⇤", ["NotTildeFullEqual"] = "≇", ["Colone"] = "⩴", ["Abreve"] = "Ă", ["otilde"] = "õ", ["Escr"] = "ℰ", ["Vopf"] = "𝕍", ["twoheadleftarrow"] = "↞", ["cuvee"] = "⋎", ["xrArr"] = "⟹", ["NotSucceedsTilde"] = "≿̸", ["Gammad"] = "Ϝ", ["NotSuperset"] = "⊃⃒", ["LeftAngleBracket"] = "⟨", ["Zacute"] = "Ź", ["Uarrocir"] = "⥉", ["Alpha"] = "Α", ["ratail"] = "⤚", ["nacute"] = "ń", ["DownTee"] = "⊤", ["boxur"] = "└", ["Efr"] = "𝔈", ["conint"] = "∮", ["rightharpoonup"] = "⇀", ["DownRightTeeVector"] = "⥟", ["blacktriangledown"] = "▾", ["boxVL"] = "╣", ["vBar"] = "⫨", ["LessSlantEqual"] = "⩽", ["sacute"] = "ś", ["SquareSubsetEqual"] = "⊑", ["uArr"] = "⇑", ["efr"] = "𝔢", ["odiv"] = "⨸", ["iscr"] = "𝒾", ["rx"] = "℞", ["infin"] = "∞", ["ncong"] = "≇", ["lE"] = "≦", ["ldquo"] = "“"} \ No newline at end of file diff --git a/mods/modlib/web/uri.lua b/mods/modlib/web/uri.lua deleted file mode 100644 index 87e6aca2..00000000 --- a/mods/modlib/web/uri.lua +++ /dev/null @@ -1,42 +0,0 @@ --- URI escaping utilities --- See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/encodeURI - -local uri_unescaped_chars = {} -for char in ("-_.!~*'()"):gmatch(".") do - uri_unescaped_chars[char] = true -end -local function add_unescaped_range(from, to) - for byte = from:byte(), to:byte() do - uri_unescaped_chars[string.char(byte)] = true - end -end -add_unescaped_range("0", "9") -add_unescaped_range("a", "z") -add_unescaped_range("A", "Z") - -local uri_allowed_chars = table.copy(uri_unescaped_chars) -for char in (";,/?:@&=+$#"):gmatch(".") do - -- Reserved characters are allowed - uri_allowed_chars[char] = true -end - -local function encode(text, allowed_chars) - return text:gsub(".", function(char) - if allowed_chars[char] then - return char - end - return ("%%%02X"):format(char:byte()) - end) -end - -local uri = {} - -function uri.encode_component(text) - return encode(text, uri_unescaped_chars) -end - -function uri.encode(text) - return encode(text, uri_allowed_chars) -end - -return uri \ No newline at end of file From adbf298437f486417f85e9d06478e362180517b3 Mon Sep 17 00:00:00 2001 From: TheEt1234 Date: Fri, 3 Oct 2025 20:32:21 +0200 Subject: [PATCH 12/28] Okay, this should be almost everything submoduled --- .gitmodules | 6 + mods/controls | 1 + mods/controls/.github/workflows/luacheck.yml | 10 -- mods/controls/.luacheckrc | 8 - mods/controls/debug.lua | 21 --- mods/controls/init.lua | 67 -------- mods/controls/license | 24 --- mods/controls/mod.conf | 3 - mods/controls/readme.md | 35 ---- mods/controls/settingtypes.txt | 2 - mods/libox | 2 +- mods/visible_wielditem | 1 + mods/visible_wielditem/Readme.md | 55 ------ mods/visible_wielditem/init.lua | 171 ------------------- mods/visible_wielditem/mod.conf | 4 - 15 files changed, 9 insertions(+), 401 deletions(-) create mode 160000 mods/controls delete mode 100644 mods/controls/.github/workflows/luacheck.yml delete mode 100644 mods/controls/.luacheckrc delete mode 100644 mods/controls/debug.lua delete mode 100644 mods/controls/init.lua delete mode 100644 mods/controls/license delete mode 100644 mods/controls/mod.conf delete mode 100644 mods/controls/readme.md delete mode 100644 mods/controls/settingtypes.txt create mode 160000 mods/visible_wielditem delete mode 100644 mods/visible_wielditem/Readme.md delete mode 100644 mods/visible_wielditem/init.lua delete mode 100644 mods/visible_wielditem/mod.conf diff --git a/.gitmodules b/.gitmodules index aff2b473..21e8510b 100644 --- a/.gitmodules +++ b/.gitmodules @@ -22,3 +22,9 @@ [submodule "mods/modlib"] path = mods/modlib url = https://github.com/appgurueu/modlib +[submodule "mods/visible_wielditem"] + path = mods/visible_wielditem + url = https://github.com/appgurueu/visible_wielditem +[submodule "mods/controls"] + path = mods/controls + url = https://github.com/mt-mods/controls diff --git a/mods/controls b/mods/controls new file mode 160000 index 00000000..61376a36 --- /dev/null +++ b/mods/controls @@ -0,0 +1 @@ +Subproject commit 61376a365dbada466c8f5dbca0613d9463f7b276 diff --git a/mods/controls/.github/workflows/luacheck.yml b/mods/controls/.github/workflows/luacheck.yml deleted file mode 100644 index b5016503..00000000 --- a/mods/controls/.github/workflows/luacheck.yml +++ /dev/null @@ -1,10 +0,0 @@ -name: luacheck -on: [push, pull_request] -jobs: - luacheck: - runs-on: ubuntu-latest - steps: - - name: Checkout - uses: actions/checkout@master - - name: Luacheck - uses: lunarmodules/luacheck@master \ No newline at end of file diff --git a/mods/controls/.luacheckrc b/mods/controls/.luacheckrc deleted file mode 100644 index a68b4397..00000000 --- a/mods/controls/.luacheckrc +++ /dev/null @@ -1,8 +0,0 @@ - -globals = { - "controls", -} - -read_globals = { - "minetest", -} diff --git a/mods/controls/debug.lua b/mods/controls/debug.lua deleted file mode 100644 index f9f91cda..00000000 --- a/mods/controls/debug.lua +++ /dev/null @@ -1,21 +0,0 @@ -controls.register_on_press(function(player, key) - local name = player:get_player_name() - minetest.chat_send_player(name, name .. " pressed " .. key) -end) - -controls.register_on_hold(function(player, key, length) - local name = player:get_player_name() - minetest.chat_send_player(name, name .. " held " .. key .. " for " .. length .. " seconds") -end) - -controls.register_on_release(function(player, key, length) - local name = player:get_player_name() - minetest.chat_send_player(name, name .. " released " .. key .. " after " .. length .. " seconds") -end) - -minetest.register_on_joinplayer(function(player) - local name = player:get_player_name() - minetest.chat_send_player(name, #controls.registered_on_press .. " registered_on_press callbacks") - minetest.chat_send_player(name, #controls.registered_on_hold .. " registered_on_hold callbacks") - minetest.chat_send_player(name, #controls.registered_on_release .. " registered_on_release callbacks") -end) diff --git a/mods/controls/init.lua b/mods/controls/init.lua deleted file mode 100644 index 53903a89..00000000 --- a/mods/controls/init.lua +++ /dev/null @@ -1,67 +0,0 @@ -controls = { - registered_on_press = {}, - registered_on_hold = {}, - registered_on_release = {}, - players = {}, -} - -function controls.register_on_press(callback) - table.insert(controls.registered_on_press, callback) -end - -function controls.register_on_hold(callback) - table.insert(controls.registered_on_hold, callback) -end - -function controls.register_on_release(callback) - table.insert(controls.registered_on_release, callback) -end - -minetest.register_on_joinplayer(function(player) - local name = player:get_player_name() - controls.players[name] = {} - for key in pairs(player:get_player_control()) do - controls.players[name][key] = {false} - end -end) - -minetest.register_on_leaveplayer(function(player) - local name = player:get_player_name() - controls.players[name] = nil -end) - -local function update_player_controls(player, player_controls) - local time_now = minetest.get_us_time() - for key, pressed in pairs(player:get_player_control()) do - if player_controls[key] then - if pressed and not player_controls[key][1] then - for _, callback in pairs(controls.registered_on_press) do - callback(player, key) - end - player_controls[key] = {true, time_now} - elseif pressed and player_controls[key][1] then - for _, callback in pairs(controls.registered_on_hold) do - callback(player, key, (time_now - player_controls[key][2]) / 1e6) - end - elseif not pressed and player_controls[key][1] then - for _, callback in pairs(controls.registered_on_release) do - callback(player, key, (time_now - player_controls[key][2]) / 1e6) - end - player_controls[key] = {false} - end - end - end -end - -minetest.register_globalstep(function() - for _, player in pairs(minetest.get_connected_players()) do - local name = player:get_player_name() - if controls.players[name] then - update_player_controls(player, controls.players[name]) - end - end -end) - -if minetest.settings:get_bool("controls_enable_debug", false) then - dofile(minetest.get_modpath("controls") .. "/debug.lua") -end diff --git a/mods/controls/license b/mods/controls/license deleted file mode 100644 index 0f696e49..00000000 --- a/mods/controls/license +++ /dev/null @@ -1,24 +0,0 @@ -License of source code ----------------------- - -The MIT License (MIT) - -Copyright (c) 2023 wsor4035(aka wsor) - -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. \ No newline at end of file diff --git a/mods/controls/mod.conf b/mods/controls/mod.conf deleted file mode 100644 index 2736ee19..00000000 --- a/mods/controls/mod.conf +++ /dev/null @@ -1,3 +0,0 @@ -name = controls -description = Utility library for control press/hold/release events -min_minetest_version = 5.0.0 diff --git a/mods/controls/readme.md b/mods/controls/readme.md deleted file mode 100644 index 6ef607e8..00000000 --- a/mods/controls/readme.md +++ /dev/null @@ -1,35 +0,0 @@ -# Controls [controls] - -[![luacheck](https://github.com/mt-mods/controls/workflows/luacheck/badge.svg)](https://github.com/mt-mods/controls/actions) -[![ContentDB](https://content.minetest.net/packages/mt-mods/controls/shields/downloads/)](https://content.minetest.net/packages/mt-mods/controls/) - -Utility library for control press/hold/release events. - -Rewritten and maintained version of [Arcelmi/minetest-controls](https://github.com/Arcelmi/minetest-controls). - - -## API - -Callbacks are supported for all keys in `player:get_player_control()`. - -```lua -controls.register_on_press(function(player, key) - -- Called when a key is pressed - -- player: player object - -- key: key pressed -end) - -controls.register_on_hold(function(player, key, length) - -- Called every globalstep while a key is held - -- player: player object - -- key: key pressed - -- length: length of time key has been held in seconds -end) - -controls.register_on_release(function(player, key, length) - -- Called when a key is released - -- player: player object - -- key: key pressed - -- length: length of time key was held in seconds -end) -``` diff --git a/mods/controls/settingtypes.txt b/mods/controls/settingtypes.txt deleted file mode 100644 index 34075551..00000000 --- a/mods/controls/settingtypes.txt +++ /dev/null @@ -1,2 +0,0 @@ -# Enable debug mod for player controls. Sends chat messages to the player when callbacks are called. -controls_enable_debug (Enable debug mode) bool false diff --git a/mods/libox b/mods/libox index 4cd98f7b..08d49da4 160000 --- a/mods/libox +++ b/mods/libox @@ -1 +1 @@ -Subproject commit 4cd98f7b262b32d03dba7d59e62fefa65b036b5d +Subproject commit 08d49da483cc56e8852ce9d941a57867e11074d1 diff --git a/mods/visible_wielditem b/mods/visible_wielditem new file mode 160000 index 00000000..7794784f --- /dev/null +++ b/mods/visible_wielditem @@ -0,0 +1 @@ +Subproject commit 7794784f52eb8e2fc7a7b342b14d3a7bc701e152 diff --git a/mods/visible_wielditem/Readme.md b/mods/visible_wielditem/Readme.md deleted file mode 100644 index 7c0f2cbd..00000000 --- a/mods/visible_wielditem/Readme.md +++ /dev/null @@ -1,55 +0,0 @@ -# Visible Wielditem - -Shows wielded items in-world. - -## Features - -Modern alternative to [`wield3d`](https://github.com/stujones11/wield3d): - -* Relies less on deprecated engine APIs, doesn't aim to support older MT versions -* Supports colored items. Works well with [`epidermis`](https://github.com/appgurueu/epidermis). -* Supports glow (for environmental lighting use a wielded light mod) -* Indicates size of stacks -* Provides a proper API for mods to use -* Rotates the model instead of the texture - -## License - -Code written by [appgurueu](https://github.com/appgurueu) and licensed under the MIT license. - -The screenshot (`screenshot.png`) uses [Hugues Ross'](https://content.minetest.net/users/Hugues%20Ross/) [RPG16](https://content.minetest.net/packages/Hugues%20Ross/rpg16/) texture pack, which is licensed under CC-BY-SA-4.0, and is therefore licensed under CC-BY-SA-4.0 as well. - -## Links - -* [GitHub](https://github.com/appgurueu/visible_wielditem) - sources, issue tracking, contributing -* [Discord](https://discord.gg/ysP74by) - discussion, chatting -* [Minetest Forum](https://forum.minetest.net/viewtopic.php?f=9&t=27714) - (more organized) discussion -* [ContentDB](https://content.minetest.net/packages/LMD/visible_wielditem/) - releases (downloading from GitHub is recommended) - -## API - -All within the `visible_wielditem` global variable. - -### `get_attachment(modelname, itemname)` - -Returns a table with fields `bonename`, `position` (unit: metric/nodes), `rotation` (unit: degrees) and `scale` (number, unit: metric/nodes) based on model attachments and item tweaks. - -### `model_attachments` - -Table. Keys are model media (file) names, values are tables with field `bonename`, `position`, `rotation` and `scale`. The special field `default` is used for default attachment settings based on `character.b3d` if no model attachments are specified for a player model or if the specified attachment settings are incomplete. - -### `item_tweaks` - -Table of tweaks applied based on the item. Subtable entries have strings as keys and tweak tables with fields `position`, `rotation` and `scale` as values. `position`s are added up, `rotation`s are properly composed, `scale` is multiplied. - -#### `types` - -Applies tweaks based on item type. Possible keys are `unknown`, `node`, `tool` and `craftitem`. - -#### `groups` - -Tweaks for a key are applied if the item has an item group with that name. - -#### `names` - -Tweaks for a single item, by full item name. diff --git a/mods/visible_wielditem/init.lua b/mods/visible_wielditem/init.lua deleted file mode 100644 index e5ce3314..00000000 --- a/mods/visible_wielditem/init.lua +++ /dev/null @@ -1,171 +0,0 @@ -visible_wielditem = {} - -local entity_name = "visible_wielditem:visible_wielditem" - -local entities = {} - -local function create_entity(player) - local pos = player:get_pos() - if not pos then return end -- HACK deal with player object being invalidated before on_leaveplayer has been called - local ent = minetest.add_entity(pos, entity_name) - if ent then - ent:get_luaentity():_set_player(player) - end -end - -minetest.register_on_joinplayer(create_entity) - -minetest.register_on_leaveplayer(function(player) - entities[player:get_player_name()]:_remove() -end) - -visible_wielditem.model_attachments = { - default = { - bonename = "Arm_Right", - position = vector.new(0, 0.375, 0), - rotation = vector.new(180, 90, 0), - scale = 0.25 - } -} - -visible_wielditem.item_tweaks = { - types = { - unknown = {}, - node = { - position = vector.new(0, 0.2, 0), - rotation = vector.new(0, 0, 180) - }, - tool = { - position = vector.new(0, 0, 0.3), - rotation = vector.new(0, 0, 135) - }, - craft = { - position = vector.new(0, 0, 0.3), - rotation = vector.new(0, 0, 45), - } - }, - groups = {}, - names = {} -} - -local quaternion_from_euler_rot_deg = modlib.quaternion.from_euler_rotation_deg - -local quaternion_to_euler_rot_deg = modlib.quaternion.to_euler_rotation_irrlicht - --- HACK quaternion multiplication should be fixed in modlib eventually -local function quaternion_compose(other, self) - local X, Y, Z, W = unpack(self) - return modlib.quaternion.normalize { - (other[4] * X) + (other[1] * W) + (other[2] * Z) - (other[3] * Y), - (other[4] * Y) + (other[2] * W) + (other[3] * X) - (other[1] * Z), - (other[4] * Z) + (other[3] * W) + (other[1] * Y) - (other[2] * X), - (other[4] * W) - (other[1] * X) - (other[2] * Y) - (other[3] * Z), - } -end - -function visible_wielditem.get_attachment(modelname, itemname) - local model_attachments = visible_wielditem.model_attachments - local attachment = modlib.table.copy(model_attachments[modelname] or model_attachments.default) - local rotation = quaternion_from_euler_rot_deg(attachment.rotation) - local function apply_tweaks(tweaks) - tweaks = tweaks or {} - if tweaks.position then attachment.position = vector.add(attachment.position, tweaks.position) end - if tweaks.rotation then - rotation = quaternion_compose(rotation, quaternion_from_euler_rot_deg(tweaks.rotation)) - end - if tweaks.scale then attachment.scale = attachment.scale * tweaks.scale end - end - local def = minetest.registered_items[itemname] or {} - local item_tweaks = visible_wielditem.item_tweaks - apply_tweaks(item_tweaks.types[def.type or "unknown"]) - for groupname, rating in pairs(def.groups or {}) do - if rating ~= 0 then - apply_tweaks(item_tweaks.groups[groupname]) - end - end - apply_tweaks(item_tweaks.names[itemname]) - attachment.rotation = quaternion_to_euler_rot_deg(rotation) - return attachment -end - -minetest.register_entity(entity_name, { - initial_properties = { - physical = false, - collide_with_objects = false, - pointable = false, - visual = "wielditem", - wield_item = "", - is_visible = false, - backface_culling = false, - use_texture_alpha = true, - glow = 0, - static_save = false, - shaded = true - }, - on_activate = function(self) - local object = self.object - object:set_armor_groups { immortal = 1 } - end, - _force_resend = function(self) -- HACK - self.object:set_pos(self.object:get_pos()) - end, - _update_attachment = function(self) - if not self._item then return end - local object = self.object - local attachment = visible_wielditem.get_attachment(self._player:get_properties().mesh, - self._item:get_name() or "") - -- TODO softcode - local stack_scale = 1 - if self._item:get_definition().type ~= "tool" then - stack_scale = 0.75 + 0.5 * math.min(1, self._item:get_count() / self._item:get_stack_max()) - end - local vsize = attachment.scale * stack_scale - object:set_properties { visual_size = vector.new(vsize, vsize, vsize) } - object:set_attach(self._player, - attachment.bonename, - vector.multiply(vector.offset(attachment.position, 0, vsize / 2, 0), 10), - attachment.rotation) - self:_force_resend() - end, - _set_player = function(self, player) - self._player = player -- HACK this assumes that PlayerRefs don't change - self:_set_item(player:get_wielded_item()) - self:_update_attachment() - entities[player:get_player_name()] = self - end, - on_deactivate = function(self) - create_entity(self._player) - end, - _set_item = function(self, item) - self._item = item - local object = self.object - if item:is_empty() then - object:set_properties { - is_visible = false, - wield_item = "" - } - return - end - object:set_properties { - is_visible = true, - wield_item = item:to_string(), - glow = item:get_definition().light_source or 0 - } - self:_update_attachment() - end, - _remove = function(self) - self.on_deactivate = modlib.func.no_op -- don't recreate entity; it's supposed to be removed - self.object:remove() - entities[self._player:get_player_name()] = nil - end - -- TODO on_step: reattach regularly to work around engine bugs? -}) - -modlib.minetest.register_on_wielditem_change(function(player, _, _, item) - local entity = entities[player:get_player_name()] - if entity.object:get_pos() then - entity:_set_item(item) - else -- recreate entity if necessary - create_entity(player) - end -end) diff --git a/mods/visible_wielditem/mod.conf b/mods/visible_wielditem/mod.conf deleted file mode 100644 index 2214c494..00000000 --- a/mods/visible_wielditem/mod.conf +++ /dev/null @@ -1,4 +0,0 @@ -name = visible_wielditem -description = Shows your wielditem -depends = modlib -min_minetest_version = 5.1 \ No newline at end of file From 3591e4547a88d4216160ff07d6178fa4586561cc Mon Sep 17 00:00:00 2001 From: TheEt1234 Date: Fri, 3 Oct 2025 20:38:41 +0200 Subject: [PATCH 13/28] Submodule fmod and futil, get rid of biomegen --- .gitmodules | 6 + mods/biomegen/LICENSE | 165 ---- mods/biomegen/README.md | 135 ---- mods/biomegen/biomelist.lua | 72 -- mods/biomegen/decorations.lua | 245 ------ mods/biomegen/init.lua | 707 ------------------ mods/biomegen/mod.conf | 3 - mods/fmod/.cdb.json | 11 - mods/fmod/.check_date.sh | 3 - mods/fmod/.editorconfig | 14 - mods/fmod/.github/FUNDING.yml | 1 - mods/fmod/.github/workflows/pre-commit.yml | 34 - mods/fmod/.pre-commit-config.yaml | 41 - mods/fmod/LICENSE.txt | 168 ----- mods/fmod/MEDIA_LICENSE.txt | 427 ----------- mods/fmod/README.md | 81 -- mods/fmod/build_has.lua | 12 - mods/fmod/get_settings.lua | 150 ---- mods/fmod/init.lua | 169 ----- mods/fmod/mod.conf | 10 - mods/fmod/parse_version.lua | 28 - mods/fmod/screenshot.png | Bin 163389 -> 0 bytes mods/futil/.cdb.json | 11 - mods/futil/.check_date.sh | 3 - mods/futil/.editorconfig | 14 - mods/futil/.github/FUNDING.yml | 1 - mods/futil/.github/workflows/pre-commit.yml | 34 - mods/futil/.gitignore | 1 - mods/futil/.pre-commit-config.yaml | 41 - mods/futil/API.md | 469 ------------ mods/futil/LICENSE.txt | 168 ----- mods/futil/MEDIA_LICENSE.txt | 427 ----------- mods/futil/README.md | 5 - mods/futil/data_structures/bitarray.lua | 125 ---- mods/futil/data_structures/default_table.lua | 11 - mods/futil/data_structures/deque.lua | 88 --- mods/futil/data_structures/init.lua | 7 - mods/futil/data_structures/pairing_heap.lua | 156 ---- .../data_structures/point_search_tree.lua | 268 ------- mods/futil/data_structures/set.lua | 267 ------- mods/futil/data_structures/sparse_graph.lua | 32 - mods/futil/init.lua | 11 - mods/futil/minetest/box.lua | 186 ----- mods/futil/minetest/dedupe.lua | 31 - mods/futil/minetest/dump.lua | 111 --- mods/futil/minetest/fake_inventory.lua | 271 ------- mods/futil/minetest/globalstep.lua | 88 --- mods/futil/minetest/group.lua | 61 -- mods/futil/minetest/hud_ephemeral.lua | 100 --- mods/futil/minetest/hud_manager.lua | 172 ----- mods/futil/minetest/image.lua | 171 ----- mods/futil/minetest/init.lua | 23 - mods/futil/minetest/inventory.lua | 40 - mods/futil/minetest/item.lua | 133 ---- mods/futil/minetest/object.lua | 200 ----- mods/futil/minetest/object_properties.lua | 158 ---- mods/futil/minetest/raycast.lua | 30 - mods/futil/minetest/registration.lua | 15 - mods/futil/minetest/serialization.lua | 87 --- mods/futil/minetest/strip_translation.lua | 205 ----- mods/futil/minetest/texture.lua | 9 - mods/futil/minetest/time.lua | 7 - mods/futil/minetest/vector.lua | 402 ---------- mods/futil/mod.conf | 11 - mods/futil/util/bisect.lua | 51 -- mods/futil/util/class.lua | 89 --- mods/futil/util/coalesce.lua | 9 - mods/futil/util/equals.lua | 28 - mods/futil/util/exception.lua | 29 - mods/futil/util/file.lua | 37 - mods/futil/util/functional.lua | 159 ---- mods/futil/util/http.lua | 10 - mods/futil/util/init.lua | 24 - mods/futil/util/iterators.lua | 106 --- mods/futil/util/limiters.lua | 42 -- mods/futil/util/list.lua | 19 - mods/futil/util/math.lua | 162 ---- mods/futil/util/matrix.lua | 30 - mods/futil/util/memoization.lua | 51 -- mods/futil/util/memory.lua | 45 -- mods/futil/util/path.lua | 7 - mods/futil/util/predicates.lua | 43 -- mods/futil/util/random.lua | 84 --- mods/futil/util/regex.lua | 6 - mods/futil/util/selection.lua | 109 --- mods/futil/util/string.lua | 62 -- mods/futil/util/table.lua | 188 ----- mods/futil/util/time.lua | 29 - mods/minetest-fmod | 1 + mods/minetest-futil | 1 + mods/sbz_planets/mod.conf | 2 +- 91 files changed, 9 insertions(+), 8546 deletions(-) delete mode 100644 mods/biomegen/LICENSE delete mode 100644 mods/biomegen/README.md delete mode 100644 mods/biomegen/biomelist.lua delete mode 100644 mods/biomegen/decorations.lua delete mode 100644 mods/biomegen/init.lua delete mode 100644 mods/biomegen/mod.conf delete mode 100644 mods/fmod/.cdb.json delete mode 100755 mods/fmod/.check_date.sh delete mode 100644 mods/fmod/.editorconfig delete mode 100644 mods/fmod/.github/FUNDING.yml delete mode 100644 mods/fmod/.github/workflows/pre-commit.yml delete mode 100644 mods/fmod/.pre-commit-config.yaml delete mode 100644 mods/fmod/LICENSE.txt delete mode 100644 mods/fmod/MEDIA_LICENSE.txt delete mode 100644 mods/fmod/README.md delete mode 100644 mods/fmod/build_has.lua delete mode 100644 mods/fmod/get_settings.lua delete mode 100644 mods/fmod/init.lua delete mode 100644 mods/fmod/mod.conf delete mode 100644 mods/fmod/parse_version.lua delete mode 100644 mods/fmod/screenshot.png delete mode 100644 mods/futil/.cdb.json delete mode 100755 mods/futil/.check_date.sh delete mode 100644 mods/futil/.editorconfig delete mode 100644 mods/futil/.github/FUNDING.yml delete mode 100644 mods/futil/.github/workflows/pre-commit.yml delete mode 100644 mods/futil/.gitignore delete mode 100644 mods/futil/.pre-commit-config.yaml delete mode 100644 mods/futil/API.md delete mode 100644 mods/futil/LICENSE.txt delete mode 100644 mods/futil/MEDIA_LICENSE.txt delete mode 100644 mods/futil/README.md delete mode 100644 mods/futil/data_structures/bitarray.lua delete mode 100644 mods/futil/data_structures/default_table.lua delete mode 100644 mods/futil/data_structures/deque.lua delete mode 100644 mods/futil/data_structures/init.lua delete mode 100644 mods/futil/data_structures/pairing_heap.lua delete mode 100644 mods/futil/data_structures/point_search_tree.lua delete mode 100644 mods/futil/data_structures/set.lua delete mode 100644 mods/futil/data_structures/sparse_graph.lua delete mode 100644 mods/futil/init.lua delete mode 100644 mods/futil/minetest/box.lua delete mode 100644 mods/futil/minetest/dedupe.lua delete mode 100644 mods/futil/minetest/dump.lua delete mode 100644 mods/futil/minetest/fake_inventory.lua delete mode 100644 mods/futil/minetest/globalstep.lua delete mode 100644 mods/futil/minetest/group.lua delete mode 100644 mods/futil/minetest/hud_ephemeral.lua delete mode 100644 mods/futil/minetest/hud_manager.lua delete mode 100644 mods/futil/minetest/image.lua delete mode 100644 mods/futil/minetest/init.lua delete mode 100644 mods/futil/minetest/inventory.lua delete mode 100644 mods/futil/minetest/item.lua delete mode 100644 mods/futil/minetest/object.lua delete mode 100644 mods/futil/minetest/object_properties.lua delete mode 100644 mods/futil/minetest/raycast.lua delete mode 100644 mods/futil/minetest/registration.lua delete mode 100644 mods/futil/minetest/serialization.lua delete mode 100644 mods/futil/minetest/strip_translation.lua delete mode 100644 mods/futil/minetest/texture.lua delete mode 100644 mods/futil/minetest/time.lua delete mode 100644 mods/futil/minetest/vector.lua delete mode 100644 mods/futil/mod.conf delete mode 100644 mods/futil/util/bisect.lua delete mode 100644 mods/futil/util/class.lua delete mode 100644 mods/futil/util/coalesce.lua delete mode 100644 mods/futil/util/equals.lua delete mode 100644 mods/futil/util/exception.lua delete mode 100644 mods/futil/util/file.lua delete mode 100644 mods/futil/util/functional.lua delete mode 100644 mods/futil/util/http.lua delete mode 100644 mods/futil/util/init.lua delete mode 100644 mods/futil/util/iterators.lua delete mode 100644 mods/futil/util/limiters.lua delete mode 100644 mods/futil/util/list.lua delete mode 100644 mods/futil/util/math.lua delete mode 100644 mods/futil/util/matrix.lua delete mode 100644 mods/futil/util/memoization.lua delete mode 100644 mods/futil/util/memory.lua delete mode 100644 mods/futil/util/path.lua delete mode 100644 mods/futil/util/predicates.lua delete mode 100644 mods/futil/util/random.lua delete mode 100644 mods/futil/util/regex.lua delete mode 100644 mods/futil/util/selection.lua delete mode 100644 mods/futil/util/string.lua delete mode 100644 mods/futil/util/table.lua delete mode 100644 mods/futil/util/time.lua create mode 160000 mods/minetest-fmod create mode 160000 mods/minetest-futil diff --git a/.gitmodules b/.gitmodules index 21e8510b..d6598e95 100644 --- a/.gitmodules +++ b/.gitmodules @@ -28,3 +28,9 @@ [submodule "mods/controls"] path = mods/controls url = https://github.com/mt-mods/controls +[submodule "mods/minetest-fmod"] + path = mods/minetest-fmod + url = https://github.com/fluxionary/minetest-fmod +[submodule "mods/minetest-futil"] + path = mods/minetest-futil + url = https://github.com/fluxionary/minetest-futil diff --git a/mods/biomegen/LICENSE b/mods/biomegen/LICENSE deleted file mode 100644 index 6600f1c9..00000000 --- a/mods/biomegen/LICENSE +++ /dev/null @@ -1,165 +0,0 @@ -GNU LESSER GENERAL PUBLIC LICENSE - Version 3, 29 June 2007 - - Copyright (C) 2007 Free Software Foundation, Inc. - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - - This version of the GNU Lesser General Public License incorporates -the terms and conditions of version 3 of the GNU General Public -License, supplemented by the additional permissions listed below. - - 0. Additional Definitions. - - As used herein, "this License" refers to version 3 of the GNU Lesser -General Public License, and the "GNU GPL" refers to version 3 of the GNU -General Public License. - - "The Library" refers to a covered work governed by this License, -other than an Application or a Combined Work as defined below. - - An "Application" is any work that makes use of an interface provided -by the Library, but which is not otherwise based on the Library. -Defining a subclass of a class defined by the Library is deemed a mode -of using an interface provided by the Library. - - A "Combined Work" is a work produced by combining or linking an -Application with the Library. The particular version of the Library -with which the Combined Work was made is also called the "Linked -Version". - - The "Minimal Corresponding Source" for a Combined Work means the -Corresponding Source for the Combined Work, excluding any source code -for portions of the Combined Work that, considered in isolation, are -based on the Application, and not on the Linked Version. - - The "Corresponding Application Code" for a Combined Work means the -object code and/or source code for the Application, including any data -and utility programs needed for reproducing the Combined Work from the -Application, but excluding the System Libraries of the Combined Work. - - 1. Exception to Section 3 of the GNU GPL. - - You may convey a covered work under sections 3 and 4 of this License -without being bound by section 3 of the GNU GPL. - - 2. Conveying Modified Versions. - - If you modify a copy of the Library, and, in your modifications, a -facility refers to a function or data to be supplied by an Application -that uses the facility (other than as an argument passed when the -facility is invoked), then you may convey a copy of the modified -version: - - a) under this License, provided that you make a good faith effort to - ensure that, in the event an Application does not supply the - function or data, the facility still operates, and performs - whatever part of its purpose remains meaningful, or - - b) under the GNU GPL, with none of the additional permissions of - this License applicable to that copy. - - 3. Object Code Incorporating Material from Library Header Files. - - The object code form of an Application may incorporate material from -a header file that is part of the Library. You may convey such object -code under terms of your choice, provided that, if the incorporated -material is not limited to numerical parameters, data structure -layouts and accessors, or small macros, inline functions and templates -(ten or fewer lines in length), you do both of the following: - - a) Give prominent notice with each copy of the object code that the - Library is used in it and that the Library and its use are - covered by this License. - - b) Accompany the object code with a copy of the GNU GPL and this license - document. - - 4. Combined Works. - - You may convey a Combined Work under terms of your choice that, -taken together, effectively do not restrict modification of the -portions of the Library contained in the Combined Work and reverse -engineering for debugging such modifications, if you also do each of -the following: - - a) Give prominent notice with each copy of the Combined Work that - the Library is used in it and that the Library and its use are - covered by this License. - - b) Accompany the Combined Work with a copy of the GNU GPL and this license - document. - - c) For a Combined Work that displays copyright notices during - execution, include the copyright notice for the Library among - these notices, as well as a reference directing the user to the - copies of the GNU GPL and this license document. - - d) Do one of the following: - - 0) Convey the Minimal Corresponding Source under the terms of this - License, and the Corresponding Application Code in a form - suitable for, and under terms that permit, the user to - recombine or relink the Application with a modified version of - the Linked Version to produce a modified Combined Work, in the - manner specified by section 6 of the GNU GPL for conveying - Corresponding Source. - - 1) Use a suitable shared library mechanism for linking with the - Library. A suitable mechanism is one that (a) uses at run time - a copy of the Library already present on the user's computer - system, and (b) will operate properly with a modified version - of the Library that is interface-compatible with the Linked - Version. - - e) Provide Installation Information, but only if you would otherwise - be required to provide such information under section 6 of the - GNU GPL, and only to the extent that such information is - necessary to install and execute a modified version of the - Combined Work produced by recombining or relinking the - Application with a modified version of the Linked Version. (If - you use option 4d0, the Installation Information must accompany - the Minimal Corresponding Source and Corresponding Application - Code. If you use option 4d1, you must provide the Installation - Information in the manner specified by section 6 of the GNU GPL - for conveying Corresponding Source.) - - 5. Combined Libraries. - - You may place library facilities that are a work based on the -Library side by side in a single library together with other library -facilities that are not Applications and are not covered by this -License, and convey such a combined library under terms of your -choice, if you do both of the following: - - a) Accompany the combined library with a copy of the same work based - on the Library, uncombined with any other library facilities, - conveyed under the terms of this License. - - b) Give prominent notice with the combined library that part of it - is a work based on the Library, and explaining where to find the - accompanying uncombined form of the same work. - - 6. Revised Versions of the GNU Lesser General Public License. - - The Free Software Foundation may publish revised and/or new versions -of the GNU Lesser General Public License from time to time. Such new -versions will be similar in spirit to the present version, but may -differ in detail to address new problems or concerns. - - Each version is given a distinguishing version number. If the -Library as you received it specifies that a certain numbered version -of the GNU Lesser General Public License "or any later version" -applies to it, you have the option of following the terms and -conditions either of that published version or of any later version -published by the Free Software Foundation. If the Library as you -received it does not specify a version number of the GNU Lesser -General Public License, you may choose any version of the GNU Lesser -General Public License ever published by the Free Software Foundation. - - If the Library as you received it specifies that a proxy can decide -whether future versions of the GNU Lesser General Public License shall -apply, that proxy's public statement of acceptance of any version is -permanent authorization for you to choose that version for the -Library. diff --git a/mods/biomegen/README.md b/mods/biomegen/README.md deleted file mode 100644 index 3b9ce182..00000000 --- a/mods/biomegen/README.md +++ /dev/null @@ -1,135 +0,0 @@ -# Biomegen - -Biome generator mod for Minetest, reproducing closely the biome generator provided by Minetest's core, but in Lua. Also includes an optional elevation adjustment parameter. - -It allows to use the biome systems on Lua mapgens (that do no allow to use core biome system). Since it reads registered biomes and decorations, it is compatible with all mods adding biomes/decos. - -Created by gaelysam (Gaël de Sailly) in November 2020, licensed under LGPLv3.0. - -Version 2.0 (February 2024) - -# Include it in your mapgen - -`biomegen` should be triggered during mapgen function, after the loop, but before writing to the map. - -Your mapgen should generate only these 4 nodes: -- Stone (`mapgen_stone` / `default:stone`) -- Water (`mapgen_water_source` / `default:water_source`) -- River water (`mapgen_river_water_source` / `default:river_water_source`) -- Air (`air`) - -All other nodes will be ignored, no biome will be placed ontop of them. - -You should add `biomegen` as a dependancy of your mod (optional or mandatory). - -## API -Description of usual function parameters: -- `data`: Data containing the generated mapchunk -- `area`: VoxelArea helper object for data. `area = VoxelArea:new({MinEdge = emin, MaxEdge = emax})` -- `vm`: VoxelManip object -- `minp`: minimal coordinates of the chunk being generated, e.g. `{x=48, y=-32, z=208}` -- `maxp`: maximal coordinates of the chunk being generated, e.g. `{x=127, y=47, z=287}` -- `seed`: world-specific seed - -### `biomegen.generate_all(data, area, vm, minp, maxp, seed)` -All-in-one function to generate *biomes*, *decorations*, *ores* and *dust*. Includes a call to `vm:set_data` so no need to do it again. Using core function `minetest.generate_ores` for ores, so does not support biome-specific ores. - -### `biomegen.generate_biomes(data, area, minp, maxp)` -Generates biomes in `data`, according to biomes that have been registered using `minetest.register_biome`. - -### `biomegen.place_all_decos(data, area, vm, minp, maxp, seed)` -Generates decorations directly in `vm` (but reads `data` to know where to place them), according to decorations that have been registered using `minetest.register_decoration`. - -### `biomegen.dust_top_nodes(data, area, vm, minp, maxp)` -Drops 'dust' (usually snow) on biomes that require it. Like above, generates directly in `vm` but reads from `data`. If you used `place_all_decos` to generate decorations, you should update `data` from the `vm`: - -```lua -vm:get_data(data) -``` - -### `biomegen.gennotify(feature, pos)` -Adds an entry in gen notify in the field `feature` (`dungeon`, `cave_begin`, ..., also `decoration#id`). No effect if the feature is not requested in `minetest.set_gen_notify`. - -### `biomegen.set_elevation_chill(ec)` -Sets elevation chill coefficient. `0` means temperature does not depend on elevation (behaviour of core's biomegen). Usual values `0`-`0.5`. - -### `biomegen.skip_chunk(minp, maxp)` -Does not generate biomes but updates mapgen objects (`biomemap`, `heatmap`, `humiditymap`, `heightmap` and `gennotify`) so that other mods can use them without crashing. Use this function in the mapgen loop when skipping an empty chunk. - -### `minetest.get_mapgen_object(objname)` -The following objects are updated to take into account what Biomegen generates: -- `biomemap` -- `heatmap` -- `humiditymap` -- `heightmap` -- `gennotify` - -The behaviour of the function is otherwise unchanged. - -### `minetest.get_biome_data(pos) -Takes into account elevation if elevation chill coefficient is non-zero. The behaviour of the function is otherwise unchanged. - -## Examples -### Using `biomegen.generate_all` -```lua -local data = {} - -minetest.register_on_generated(function(minp, maxp, seed) - local vm, emin, emax = minetest.get_mapgen_object("voxelmanip") - local area = VoxelArea:new{MinEdge = emin, MaxEdge = emax} - vm:get_data(data) - - ------------------------ - -- [MAPGEN LOOP HERE] -- - ------------------------ - - -- Generate biomes, decorations, ores and dust - biomegen.generate_all(data, area, vm, minp, maxp, seed) - - -- Calculate lighting for what has been created. - vm:calc_lighting() - -- Write what has been created to the world. - vm:write_to_map() - -- Liquid nodes were placed so set them flowing. - vm:update_liquids() -end) -``` - -### Equivalent with all functions -```lua -local data = {} - -minetest.register_on_generated(function(minp, maxp, seed) - local vm, emin, emax = minetest.get_mapgen_object("voxelmanip") - local area = VoxelArea:new{MinEdge = emin, MaxEdge = emax} - vm:get_data(data) - - ------------------------ - -- [MAPGEN LOOP HERE] -- - ------------------------ - - -- Generate biomes in 'data', using biomegen mod - biomegen.generate_biomes(data, area, minp, maxp) - - -- Write content ID data back to the voxelmanip. - vm:set_data(data) - -- Generate ores using core's function - minetest.generate_ores(vm, minp, maxp) - -- Generate decorations in VM (needs 'data' for reading) - biomegen.place_all_decos(data, area, vm, minp, maxp, seed) - -- Update data array to have ores/decorations - vm:get_data(data) - -- Add biome dust in VM (needs 'data' for reading) - biomegen.dust_top_nodes(data, area, vm, minp, maxp) - - -- Calculate lighting for what has been created. - vm:calc_lighting() - -- Write what has been created to the world. - vm:write_to_map() - -- Liquid nodes were placed so set them flowing. - vm:update_liquids() -end) -``` - -### Mapgen example -I have made a [modified version of `lvm_example`](https://github.com/Gael-de-Sailly/lvm_example/tree/biomegen) (mod originally by Paramat) to provide a minimal working example of a mapgen using `biomegen`. Try it! diff --git a/mods/biomegen/biomelist.lua b/mods/biomegen/biomelist.lua deleted file mode 100644 index eac26d8e..00000000 --- a/mods/biomegen/biomelist.lua +++ /dev/null @@ -1,72 +0,0 @@ --- biomelist.lua - -local core_cid = minetest.get_content_id -local function cid(name) - if not name then - return - end - local result - pcall(function() --< try - result = core_cid(name) - end) - if not result then - print("[biomegen] Node " .. name .. " not found!") - end - return result -end - -local function make_biomelist() - local biomes = {} - - for _, a in pairs(minetest.registered_biomes) do - local b = {} - b.name = a.name - biomes[b.name] = b - b.id = minetest.get_biome_id(a.name) - - if a.node_dust then - b.node_dust_name = a.node_dust - b.node_dust = cid(a.node_dust) - end - - b.node_top = cid(a.node_top) or cid("mapgen_stone") - b.depth_top = a.depth_top or 0 - - b.node_filler = cid(a.node_filler) or cid("mapgen_stone") - b.depth_filler = a.depth_filler or 0 - - b.node_stone = cid(a.node_stone) or cid("mapgen_stone") - - b.node_water_top = cid(a.node_water_top) or cid("mapgen_water_source") - b.depth_water_top = a.depth_water_top or 0 - - b.node_water = cid(a.node_water) or cid("mapgen_water_source") - b.node_river_water = cid(a.node_river_water) or cid("mapgen_river_water_source") - - b.node_riverbed = cid(a.node_riverbed) or cid("mapgen_stone") - b.depth_riverbed = a.depth_riverbed or 0 - - -- b.node_cave_liquid = ... - -- b.node_dungeon = ... - -- b.node_dungeon_alt = ... - -- b.node_dungeon_stair = ... - - b.min_pos = a.min_pos or {x=-31000, y=-31000, z=-31000} - if a.y_min then - b.min_pos.y = math.max(b.min_pos.y, a.y_min) - end - b.max_pos = a.max_pos or {x=31000, y=31000, z=31000} - if a.y_max then - b.max_pos.y = math.min(b.max_pos.y, a.y_max) - end - - b.vertical_blend = a.vertical_blend or 0 - - b.heat_point = a.heat_point or 50 - b.humidity_point = a.humidity_point or 50 - end - - return biomes -end - -return make_biomelist diff --git a/mods/biomegen/decorations.lua b/mods/biomegen/decorations.lua deleted file mode 100644 index 3d0ccc0a..00000000 --- a/mods/biomegen/decorations.lua +++ /dev/null @@ -1,245 +0,0 @@ --- decorations.lua - -local emptynodes = { - air = true, - ignore = true, -} - -local core_cid = minetest.get_content_id -local function cid(name) - if not name then - return - end - local result - pcall(function() --< try - result = core_cid(name) - end) - if not result then - print("[biomegen] Node " .. name .. " not found!") - end - return result -end - -local function generate_deco_simple(deco, vm, pr, p, ceiling) - local emin, emax = vm:get_emerged_area() - - local place_offset_y = deco.place_offset_y - if ceiling then - if p.y - place_offset_y - deco.height_max < emin.y then - return 0 - elseif p.y - 1 - place_offset_y > emax.y then - return 0 - end - else - if p.y + place_offset_y + deco.height_max > emax.y then - return 0 - elseif p.y + 1 + place_offset_y < emin.y then - return 0 - end - end - - local decos = deco.decoration - if #decos == 0 then - return 0 - end - local nodename = decos[pr:next(1, #decos)] - local height = deco.vary_height and pr:next(deco.height, deco.height_max) or deco.height - local param2 = deco.vary_param2 and pr:next(deco.param2, deco.param2_max) or deco.param2 - local force_placement = deco.flags.force_placement == true - - local direction = ceiling and -1 or 1 - p = { x = p.x, y = p.y + place_offset_y * direction, z = p.z } -- Deep-copy the table to avoid issues - for i = 1, height do - p.y = p.y + direction - local node = vm:get_node_at(p) - if not force_placement and not emptynodes[node.name] then - break - end - node.name = nodename - node.param2 = param2 - vm:set_node_at(p, node) - end - - return 1 -end - -local function get_schematic_size(schem) - if type(schem) == "table" then - return schem.size - elseif type(schem) == "string" then - local mts = io.open(schem) - if not mts then - return { x = 0, y = 0, z = 0 } - end - mts:seek('set', 6) - local sx1, sx2, sy1, sy2, sz1, sz2 = mts:read(6):byte() - mts:close() - return { x = sx1 * 256 + sx2, y = sy1 * 256 + sy2, z = sz1 * 256 + sz2 } - end - - return { x = 0, y = 0, z = 0 } -end - -local function generate_deco_schematic(deco, vm, pr, p, ceiling) - local force_placement = deco.flags.force_placement == true - local direction = ceiling and -1 or 1 - if not deco.flags.place_center_y then - if ceiling then - local size = get_schematic_size(schem) - p.y = p.y - deco.place_offset_y - size.y + 1 - else - p.y = p.y + deco.place_offset_y - end - end - - minetest.place_schematic_on_vmanip(vm, p, deco.schematic, deco.rotation, deco.replacements, force_placement, - deco.schem_flags) - - return 1 -end - -local function parse_node_list(raw_list) - if not raw_list then - return {} - end - local ilist = {} - if type(raw_list) == "string" then - raw_list = { raw_list } - end - - for i, node in ipairs(raw_list) do - if node:sub(1, 6) == "group:" then - local groupname = node:sub(7, -1) - for name, ndef in pairs(minetest.registered_nodes) do - if ndef.groups and ndef.groups[groupname] and ndef.groups[groupname] > 0 then - local id = cid(name) - if id then - ilist[id] = true - end - end - end - else - local id = cid(node) - if id then - ilist[id] = true - end - end - end - - return ilist -end - -local function make_decolist(gennotify_decolist) - local decos = {} - - local gennotify_decos = {} - for _, v in ipairs(gennotify_decolist) do - gennotify_decos[v] = true - end - - for i, a in pairs(minetest.registered_decorations) do - local b = {} - decos[i] = b - - local id = minetest.get_decoration_id(i) - if id and gennotify_decos[id] then - b.gennotify = "decoration#" .. id - end - - b.name = a.name or "unnamed " .. i - - b.deco_type = a.deco_type or "simple" - - b.place_on = parse_node_list(a.place_on) - - b.sidelen = a.sidelen or 8 - b.fill_ratio = a.fill_ratio or 0.02 - local np = a.noise_params - b.use_noise = false - if np then - b.use_noise = true - b.noise = minetest.get_perlin(np) - end - - b.use_biomes = false - if a.biomes then - local biomes_raw = a.biomes - b.use_biomes = true - if type(biomes_raw) == "table" then - local biomes = {} - b.biomes = biomes - for i, biome in pairs(biomes_raw) do - if type(biome) == "number" then - biome = minetest.get_biome_name(biome) - end - biomes[biome] = true - end - else - if type(biomes_raw) == "number" then - biomes_raw = minetest.get_biome_name(biomes_raw) - end - b.biomes = { [biomes_raw] = true } - end - end - - b.y_min = a.y_min or -31000 - b.y_max = a.y_max or 31000 - - b.spawn_by = parse_node_list(a.spawn_by) - b.num_spawn_by = a.num_spawn_by or 0 - - local flags_raw = a.flags or "" - local flags = {} - b.flags = flags - for i, flag in ipairs(flags_raw:split()) do - flag = flag:trim() - local status = true - if flag:sub(1, 2) == "no" then - flag = flag:sub(3, -1) - status = false - end - flags[flag] = status - end - - if b.deco_type == "simple" then - local a_deco = a.decoration - if type(a_deco) == "string" then - a_deco = { a_deco } - end - local b_deco = {} - for _, deco in ipairs(a_deco) do - if cid(deco) then - table.insert(b_deco, deco) - end - end - b.decoration = b_deco - b.height = a.height or 1 - b.height_max = math.max(a.height_max or b.height, b.height) - b.vary_height = b.height < b.height_max - b.param2 = a.param2 or 0 - b.param2_max = math.max(a.params2_max or b.param2, b.param2) - b.vary_param2 = b.param2 < b.param2_max - b.place_offset_y = a.place_offset_y or 0 - b.generate = generate_deco_simple - elseif b.deco_type == "schematic" then - b.schematic = a.schematic - b.replacements = a.replacements or {} - b.rotation = a.rotation or 0 - b.place_offset_y = a.place_offset_y or 0 - - local schem_flags = {} - for _, flag in ipairs({ 'place_center_x', 'place_center_y', 'place_center_z' }) do - if flags[flag] then - table.insert(schem_flags, flag) - end - end - b.schem_flags = table.concat(schem_flags, ',') - - b.generate = generate_deco_schematic - end - end - - return decos -end - -return make_decolist diff --git a/mods/biomegen/init.lua b/mods/biomegen/init.lua deleted file mode 100644 index 537d36c6..00000000 --- a/mods/biomegen/init.lua +++ /dev/null @@ -1,707 +0,0 @@ --- biomegen/init.lua - -local make_biomelist = dofile(minetest.get_modpath(minetest.get_current_modname()) .. "/biomelist.lua") -local make_decolist = dofile(minetest.get_modpath(minetest.get_current_modname()) .. "/decorations.lua") - -local np_filler_depth = { - offset = 0, - scale = 1.2, - spread = {x=150, y=150, z=150}, - seed = 261, - octaves = 3, - persist = 0.7, - lacunarity = 2.0, -} - -local nobj_filler_depth, nobj_heat, nobj_heat_blend, nobj_humid, nobj_humid_blend -local nvals_filler_depth = {} -local nvals_heat = {} -local nvals_heat_blend = {} -local nvals_humid = {} -local nvals_humid_blend = {} - -local water_level = tonumber(minetest.get_mapgen_setting('water_level')) -local elevation_chill = 0 -local function set_elevation_chill(ec) - elevation_chill = ec -end - -local init_mapgen = false -local init_biomes = false - -local c_ignore -local c_air -local c_stone -local c_water -local c_rwater - -local biomes, decos - -local gennotify_flags = {} - -local function initialize_biome_data() - print("[biomegen] Initializing") - - init_biomes = true - - local gennotify_flagstr, gennotify_decolist = minetest.get_gen_notify() - local notify_decos = false - for _, v in ipairs(gennotify_flagstr:split(',')) do - v = v:trim() - if v == "decoration" then - notify_decos = true - else - gennotify_flags[v] = true - end - end - - if notify_decos then - for _, v in ipairs(gennotify_decolist) do - gennotify_flags["decoration#" .. v] = true - end - end - - biomes = make_biomelist() - decos = make_decolist(notify_decos and gennotify_decolist or {}) -end - -local function initialize_mapgen_data(chulens) - init_mapgen = true - - if not init_biomes then - initialize_biome_data() - end - - local noiseparams = minetest.get_mapgen_setting_noiseparams - - local chulens2d = {x=chulens.x, y=chulens.z, z=1} - local np_heat = noiseparams('mg_biome_np_heat') - np_heat.offset = np_heat.offset + water_level*elevation_chill - nobj_filler_depth = minetest.get_perlin_map(np_filler_depth, chulens2d) - nobj_heat = minetest.get_perlin_map(np_heat, chulens2d) - nobj_heat_blend = minetest.get_perlin_map(noiseparams('mg_biome_np_heat_blend'), chulens2d) - nobj_humid = minetest.get_perlin_map(noiseparams('mg_biome_np_humidity'), chulens2d) - nobj_humid_blend = minetest.get_perlin_map(noiseparams('mg_biome_np_humidity_blend'), chulens2d) - - c_ignore = minetest.get_content_id("ignore") - c_air = minetest.get_content_id("air") - c_stone = minetest.get_content_id("mapgen_stone") - c_water = minetest.get_content_id("mapgen_water_source") - c_rwater = minetest.get_content_id("mapgen_river_water_source") -end - -local biomemap = {} -local heatmap = {} -local humidmap = {} -local heightmap = {} -local gennotify = {} -local imax = 0 - -local function add_gennotify(feature, pos) - if not init_biomes then - initialize_biome_data() - end - - if not gennotify_flags[feature] then - return - end - gennotify[feature] = gennotify[feature] or {} - table.insert(gennotify[feature], pos) -end - -local function calculate_noises(minp) - local minp2d = {x=minp.x, y=minp.z} - nobj_filler_depth:get_2d_map_flat(minp2d, nvals_filler_depth) - - nobj_heat:get_2d_map_flat(minp2d, nvals_heat) - nobj_heat_blend:get_2d_map_flat(minp2d, nvals_heat_blend) - - nobj_humid:get_2d_map_flat(minp2d, nvals_humid) - nobj_humid_blend:get_2d_map_flat(minp2d, nvals_humid_blend) - - for i, heat in ipairs(nvals_heat) do -- use nvals_heat to iterate, could have been another one - heatmap[i] = heat + nvals_heat_blend[i] - humidmap[i] = nvals_humid[i] + nvals_humid_blend[i] - end -end - -local function calc_biome_from_noise(heat, humid, pos) - local biome_closest = nil - local biome_closest_blend = nil - local dist_min = 31000 - local dist_min_blend = 31000 - - for i, biome in pairs(biomes) do - local min_pos, max_pos = biome.min_pos, biome.max_pos - if pos.y >= min_pos.y and pos.y <= max_pos.y+biome.vertical_blend - and pos.x >= min_pos.x and pos.x <= max_pos.x - and pos.z >= min_pos.z and pos.z <= max_pos.z then - local d_heat = heat - biome.heat_point - local d_humid = humid - biome.humidity_point - local dist = d_heat*d_heat + d_humid*d_humid -- Pythagorean distance - - if pos.y <= max_pos.y then -- Within y limits of biome - if dist < dist_min then - dist_min = dist - biome_closest = biome - end - elseif dist < dist_min_blend then -- Blend area above biome - dist_min_blend = dist - biome_closest_blend = biome - end - end - end - - -- Carefully tune pseudorandom seed variation to avoid single node dither - -- and create larger scale blending patterns similar to horizontal biome - -- blend. - local seed = math.floor(pos.y + (heat+humid) * 0.9) - local rng = PseudoRandom(seed) - - if biome_closest_blend and dist_min_blend <= dist_min - and rng:next(0, biome_closest_blend.vertical_blend) >= pos.y - biome_closest_blend.max_pos.y then - return biome_closest_blend - end - - return biome_closest -end - -local function get_biome_at_index(i, pos) - local heat = heatmap[i] - math.max(pos.y, water_level)*elevation_chill - local humid = humidmap[i] - return calc_biome_from_noise(heat, humid, pos) -end - --- Walkable, liquid, and dustable: memoization tables for better performance -local walkable = setmetatable({}, { - __index = function(t, c) - local is_walkable = false - local ndef = minetest.registered_nodes[minetest.get_name_from_content_id(c)] - if ndef and ndef.walkable then - is_walkable = true - end - - t[c] = is_walkable - return is_walkable - end, -}) - -local liquid = setmetatable({}, { - __index = function(t, c) - local is_liquid = false - local ndef = minetest.registered_nodes[minetest.get_name_from_content_id(c)] - if ndef and ndef.liquidtype then - is_liquid = ndef.liquidtype ~= "none" - end - - t[c] = is_liquid - return is_liquid - end, -}) - -local dustable = setmetatable({}, { - __index = function(t, c) - local is_dustable = false - local ndef = minetest.registered_nodes[minetest.get_name_from_content_id(c)] - if ndef and ndef.walkable then - local dtype = ndef.drawtype - if dtype and dtype == "normal" or dtype == "allfaces" or dtype == "allfaces_optional" or dtype == "glasslike" or dtype == "glasslike_framed" or dtype == "glasslike_framed_optional" then - is_dustable = true - end - end - - t[c] = is_dustable - return is_dustable - end, -}) - -local function generate_biomes(data, a, minp, maxp) - if not init_mapgen then - local chulens = {x=maxp.x-minp.x+1, y=maxp.y-minp.y+1, z=maxp.z-minp.z+1} - initialize_mapgen_data(chulens) - end - - calculate_noises(minp) - - local index = 1 - for z=minp.z, maxp.z do - for x=minp.x, maxp.x do - local biome = nil - local water_biome = nil - local biome_stone = c_stone - - local depth_top = 0 - local base_filler = 0 - local depth_water_top = 0 - local depth_riverbed = 0 - - local biome_y_min = -31000 - local y_start = maxp.y - local vi = a:index(x, maxp.y, z) - local ystride = a.ystride - - local c_above = data[vi+ystride] - if c_above == c_ignore then - y_start = y_start - 1 - c_above = data[vi] - vi = vi - ystride - end - local air_above = c_above == c_air - local river_water_above = c_above == c_rwater - local water_above = c_above == c_water or river_water_above - - biomemap[index] = nil - heightmap[index] = -31000 - - local nplaced = (air_above or water_above) and 0 or 31000 - - for y=y_start, minp.y-1, -1 do - local c = data[vi] - if heightmap[index] == -31000 and walkable[c] then - heightmap[index] = y - end - - local is_stone_surface = (c == c_stone) and - (air_above or water_above or not biome or y < biome_y_min) - local is_water_surface = (c == c_water or c == c_rwater) and - (air_above or not biome or y < biome_y_min) - - if is_stone_surface or is_water_surface then - biome = get_biome_at_index(index, {x=x, y=y, z=z}) - biome_stone = biome.node_stone - - if not biomemap[index] and is_stone_surface then - biomemap[index] = biome - end - - if not water_biome and is_water_surface then - water_biome = biome - end - - depth_top = biome.depth_top - base_filler = math.max(depth_top + biome.depth_filler + nvals_filler_depth[index], 0) - depth_water_top = biome.depth_water_top - depth_riverbed = biome.depth_riverbed - biome_y_min = biome.min_pos.y - end - - if c == c_stone or c == biome_stone then - local c_below = data[vi-ystride] - if c_below == c_air or c_below == c_rwater or c_below == c_water then - nplaced = 31000 - end - if river_water_above then - if nplaced < depth_riverbed then - data[vi] = biome.node_riverbed - nplaced = nplaced + 1 - else - nplaced = 31000 - river_water_above = false - end - elseif nplaced < depth_top then - data[vi] = biome.node_top - nplaced = nplaced + 1 - elseif nplaced < base_filler then - data[vi] = biome.node_filler - nplaced = nplaced + 1 - else - data[vi] = biome_stone - nplaced = 31000 - end - - air_above = false - water_above = false - elseif c == c_water then - if y > water_level-depth_water_top then - data[vi] = biome.node_water_top - else - data[vi] = biome.node_water - end - nplaced = 0 - air_above = false - water_above = true - elseif c == c_rwater then - data[vi] = biome.node_river_water - nplaced = 0 - air_above = false - water_above = true - river_water_above = true - elseif c == c_air then - nplaced = 0 - air_above = true - water_above = false - else - nplaced = 31000 - air_above = false - water_above = false - end - - vi = vi - ystride - end - - if not biomemap[index] then - biomemap[index] = water_biome - end - - index = index + 1 - end - end - - imax = index -end - -local function skip_chunk(minp, maxp) - if not init_mapgen then - local chulens = {x=maxp.x-minp.x+1, y=maxp.y-minp.y+1, z=maxp.z-minp.z+1} - initialize_mapgen_data(chulens) - end - - calculate_noises(minp) - - local index = 1 - for z=minp.z, maxp.z do - for x=minp.x, maxp.x do - biomemap[index] = nil - heightmap[index] = -31000 - index = index + 1 - end - end - imax = index -end - -local function can_place_deco(deco, data, vi, pattern) - if not deco.place_on[data[vi]] then - return false - elseif deco.num_spawn_by <= 0 then - return true - end - - local spawn_by = deco.spawn_by - local nneighs = deco.num_spawn_by - for i, incr in ipairs(pattern) do - vi = vi + incr - if spawn_by[data[vi]] then - nneighs = nneighs - 1 - if nneighs < 1 then - return true - end - end - end - - return false -end - -local function place_deco(deco, data, a, vm, minp, maxp, blockseed) - local ps = PcgRandom(blockseed + 53) - local carea_size = maxp.x - minp.x + 1 - - local sidelen = deco.sidelen - if carea_size % sidelen > 0 then - sidelen = carea_size - end - local divlen = carea_size / sidelen - 1 - local area = sidelen*sidelen - local ystride, zstride = a.ystride, a.zstride - local pattern = {1, zstride, -1, -1, -zstride, -zstride, 1, 1, ystride, zstride, zstride, -1, -1, -zstride, -zstride, 1} -- Successive increments to iterate over 16 neighbouring nodes - - local gennotify_list = {} - if deco.gennotify then - gennotify[deco.gennotify] = nil - end - - for z0=0, divlen do - for x0=0, divlen do - local p2d_center = {x=minp.x+sidelen*(x0+0.5), y=minp.z+sidelen*(z0+0.5)} - local p2d_min = {x=minp.x+sidelen*x0, y=minp.z+sidelen*z0} - local p2d_max = {x=minp.x+sidelen*(x0+1)-1, y=minp.z+sidelen*(z0+1)-1} - - local cover = false - local nval = deco.use_noise and deco.noise:get_2d(p2d_center) or deco.fill_ratio - local deco_count = 0 - - if nval >= 10 then - cover = true - deco_count = area - else - local deco_count_f = area * nval - if deco_count_f >= 1 then - deco_count = deco_count_f - elseif deco_count_f > 0 and ps:next(1, 1000) <= deco_count_f * 1000 then - deco_count = 1 - end - end - - local x = p2d_min.x - 1 - local z = p2d_min.y - - for i=1, deco_count do - if not cover then - x = ps:next(p2d_min.x, p2d_max.x) - z = ps:next(p2d_min.y, p2d_max.y) - else - x = x + 1 - if x == p2d_max.x + 1 then - z = z + 1 - x = p2d_min.x - end - end - local mapindex = carea_size * (z - minp.z) + (x - minp.x) + 1 - - if deco.flags.all_floors or deco.flags.all_ceilings then - local biome_ok = true - if deco.use_biomes then - local biome_here = biomemap[mapindex] - if biome_here and not deco.biomes[biome_here.name] then - biome_ok = false - end - end - - if biome_ok then - local size = (maxp.x - minp.x + 1) / 2 - local floors = {} - local ceilings = {} - - local is_walkable = false - local vi = a:index(x, maxp.y, z) - local walkable_above = walkable[data[vi]] - for y = maxp.y-1, minp.y, -1 do - vi = vi - ystride - is_walkable = walkable[data[vi]] - if is_walkable and not walkable_above then - table.insert(floors, y) - elseif walkable_above and not is_walkable then - table.insert(ceilings, y+1) - end - - walkable_above = is_walkable - end - - if deco.flags.all_floors then - for _, y in ipairs(floors) do - if y >= deco.y_min and y <= deco.y_max - and can_place_deco(deco, data, a:index(x,y,z), pattern) then - local pos = {x=x, y=y, z=z} - local gen = deco:generate(vm, ps, pos, false) - if gen > 0 and deco.gennotify then - gennotify_list[#gennotify_list+1] = pos - end - end - end - end - - if deco.flags.all_ceilings then - for _, y in ipairs(ceilings) do - if y >= deco.y_min and y <= deco.y_max - and can_place_deco(deco, data, a:index(x,y,z), pattern) then - local pos = {x=x, y=y, z=z} - local gen = deco:generate(vm, ps, pos, true) - if gen > 0 and deco.gennotify then - gennotify_list[#gennotify_list+1] = pos - end - end - end - end - end - else - local y = -31000 - if deco.flags.liquid_surface then - local vi = a:index(x, maxp.y, z) - for yi=maxp.y, minp.y, -1 do - local c = data[vi] - if walkable[c] then - break - elseif liquid[c] then - y = yi - break - end - vi = vi - ystride - end - else - local vi = a:index(x, maxp.y, z) - for yi=maxp.y, minp.y, -1 do - if walkable[data[vi]] then - y = yi - break - end - vi = vi - ystride - end - end - - if y >= deco.y_min and y <= deco.y_max and y >= minp.y and y <= maxp.y then - local biome_ok = true - if deco.use_biomes then - local biome_here = biomemap[mapindex] - if biome_here and not deco.biomes[biome_here.name] then - biome_ok = false - end - end - - if biome_ok then - local pos = {x=x, y=y, z=z} - if can_place_deco(deco, data, a:index(x,y,z), pattern) then - local gen = deco:generate(vm, ps, pos, false) - if gen > 0 and deco.gennotify then - gennotify_list[#gennotify_list+1] = pos - end - end - end - end - end - end - end - end - - if #gennotify_list > 0 then - gennotify[deco.gennotify] = gennotify_list - end - - return 0 -end - -local function get_blockseed(p, seed) - return seed + p.z * 38134234 + p.y * 42123 + p.x * 23 -end - -local function place_all_decos(data, a, vm, minp, maxp, seed) - local emin = vm:get_emerged_area() - local blockseed = get_blockseed(emin, seed) - - local nplaced = 0 - - for i, deco in pairs(decos) do - nplaced = nplaced + place_deco(deco, data, a, vm, minp, maxp, blockseed) - end - - return nplaced -end - -local function dust_top_nodes(data, a, vm, minp, maxp) - if maxp.y < water_level then - return - end - - local full_maxp = a.MaxEdge - - local index = 1 - local ystride = a.ystride - - for z = minp.z, maxp.z do - for x = minp.x, maxp.x do - local biome = biomemap[index] - - if biome and biome.node_dust then - local vi = a:index(x, full_maxp.y, z) - local c_full_max = data[vi] - local y_start - - if c_full_max == c_air then - y_start = full_maxp.y - 1 - elseif c_full_max == c_ignore then - vi = a:index(x, maxp.y, z) - local c_max = data[vi] - - if c_max == c_air then - y_start = maxp.y - end - end - - if y_start then -- workaround for the 'continue' statement - vi = a:index(x, y_start, z) - local y = y_start - for y0=y_start, minp.y-1, -1 do - if data[vi] ~= c_air then - y = y0 - break - end - vi = vi - ystride - end - local c = data[vi] - if dustable[c] and c ~= biome.node_dust then - local pos = {x=x, y=y+1, z=z} - vm:set_node_at(pos, {name=biome.node_dust_name}) - end - end - end - index = index + 1 - end - end -end - -local orig_get_mapgen_object = minetest.get_mapgen_object -function minetest.get_mapgen_object(objname) - if objname == "biomemap" then - local bmap = {} - for i=1, imax do - bmap[i] = biomemap[i] and biomemap[i].id or 0 - end - return bmap - end - - if objname == "heatmap" then - return table.copy(heatmap) - end - - if objname == "humiditymap" then - return table.copy(humidmap) - end - - if objname == "heightmap" then - return table.copy(heightmap) - end - - if objname == "gennotify" then - return table.copy(gennotify) - end - - return orig_get_mapgen_object(objname) -end - -local orig_get_biome_data = minetest.get_biome_data -function minetest.get_biome_data(pos) - if not init_biomes then - initialize_biome_data() - end - - if elevation_chill == 0 then - return orig_get_biome_data(pos) - end - - local heat = minetest.get_heat(pos) + math.max(water_level - pos.y, 0)*elevation_chill - local humidity = minetest.get_humidity(pos) - local biome = calc_biome_from_noise(heat, humidity, pos) - if biome then - return { - heat = heat, - humidity = humidity, - biome = biome.id, - } - end -end - --- Reset gennotify after mapgen (ensure it is called last) -minetest.register_on_mods_loaded(function() - minetest.register_on_generated(function(minp, maxp, seed) - gennotify = {} - end) -end) - -biomegen = { - set_elevation_chill = set_elevation_chill, - calculate_noises = calculate_noises, - get_biome_at_index = get_biome_at_index, - calc_biome_from_noise = calc_biome_from_noise, - generate_biomes = generate_biomes, - place_all_decos = place_all_decos, - dust_top_nodes = dust_top_nodes, - skip_chunk = skip_chunk, - gennotify = add_gennotify, -} - -function biomegen.generate_all(data, a, vm, minp, maxp, seed) - generate_biomes(data, a, minp, maxp) - vm:set_data(data) - place_all_decos(data, a, vm, minp, maxp, seed) - minetest.generate_ores(vm, minp, maxp) - vm:get_data(data) - dust_top_nodes(data, a, vm, minp, maxp) -end diff --git a/mods/biomegen/mod.conf b/mods/biomegen/mod.conf deleted file mode 100644 index 4b4f57db..00000000 --- a/mods/biomegen/mod.conf +++ /dev/null @@ -1,3 +0,0 @@ -name = biomegen -author = gaelysam -title = BiomeGen diff --git a/mods/fmod/.cdb.json b/mods/fmod/.cdb.json deleted file mode 100644 index 522bceb4..00000000 --- a/mods/fmod/.cdb.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "type": "MOD", - "name": "fmod", - "title": "fmod", - "license": "LGPL-3.0-or-later", - "media_license": "CC-BY-SA-4.0", - "repo": "https://github.com/fluxionary/minetest-fmod.git", - "website": "https://github.com/fluxionary/minetest-fmod", - "issue_tracker": "https://github.com/fluxionary/minetest-fmod/issues", - "short_description": "flux's mod boilerplate" -} diff --git a/mods/fmod/.check_date.sh b/mods/fmod/.check_date.sh deleted file mode 100755 index 831a6ddd..00000000 --- a/mods/fmod/.check_date.sh +++ /dev/null @@ -1,3 +0,0 @@ -#!/usr/bin/env bash -grep $(date -u -I) mod.conf -exit $? diff --git a/mods/fmod/.editorconfig b/mods/fmod/.editorconfig deleted file mode 100644 index 33568faf..00000000 --- a/mods/fmod/.editorconfig +++ /dev/null @@ -1,14 +0,0 @@ -# See https://editorconfig.org/ - -root = true - -[*] -charset = utf-8 -end_of_line = lf -indent_style = space -indent_size = 4 -insert_final_newline = true -trim_trailing_whitespace = true - -[*.{lua,luacheckrc}] -indent_style = tab diff --git a/mods/fmod/.github/FUNDING.yml b/mods/fmod/.github/FUNDING.yml deleted file mode 100644 index c39ac9d9..00000000 --- a/mods/fmod/.github/FUNDING.yml +++ /dev/null @@ -1 +0,0 @@ -github: fluxionary diff --git a/mods/fmod/.github/workflows/pre-commit.yml b/mods/fmod/.github/workflows/pre-commit.yml deleted file mode 100644 index d1faea17..00000000 --- a/mods/fmod/.github/workflows/pre-commit.yml +++ /dev/null @@ -1,34 +0,0 @@ -name: pre-commit -on: [push, pull_request, workflow_dispatch] - -jobs: - check: - runs-on: ubuntu-latest - - steps: - - name: update - run: sudo apt-get update -y - - - uses: actions/checkout@master - - uses: actions/setup-python@master - - - name: install luarocks - run: sudo apt-get install -y luarocks - - - name: add luarocks path - run: echo "$HOME/.luarocks/bin" >> $GITHUB_PATH - - - name: luacheck install - run: luarocks install --local luacheck - - - name: install cargo - run: sudo apt-get install -y cargo - - - name: install stylua - run: cargo install stylua - - - name: Install pre-commit - run: pip3 install pre-commit - - - name: Run pre-commit - run: pre-commit run --all-files diff --git a/mods/fmod/.pre-commit-config.yaml b/mods/fmod/.pre-commit-config.yaml deleted file mode 100644 index 6d4489f9..00000000 --- a/mods/fmod/.pre-commit-config.yaml +++ /dev/null @@ -1,41 +0,0 @@ -repos: - - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v3.3.0 - hooks: - - id: fix-byte-order-marker - - id: end-of-file-fixer - - id: trailing-whitespace - - id: mixed-line-ending - args: [ --fix=lf ] - - - repo: local - hooks: - - id: detect_debug - name: detect debug - language: pygrep - entry: DEBUG - pass_filenames: true - exclude: .pre-commit-config.yaml - fail_fast: true - - id: date_version - name: date version - language: script - entry: .check_date.sh - files: mod.conf - always_run: true - fail_fast: true - - id: stylua - name: stylua - language: system - entry: stylua - pass_filenames: true - types: [ file, lua ] - fail_fast: true - - id: luacheck - name: luacheck - language: system - entry: luacheck - pass_filenames: true - types: [ file, lua ] - args: [ -q ] - fail_fast: true diff --git a/mods/fmod/LICENSE.txt b/mods/fmod/LICENSE.txt deleted file mode 100644 index b6ff27cc..00000000 --- a/mods/fmod/LICENSE.txt +++ /dev/null @@ -1,168 +0,0 @@ -this license is for the code. -any non-code media included in this repository is covered by the contents of MEDIA_LICENSE.txt. - - GNU LESSER GENERAL PUBLIC LICENSE - Version 3, 29 June 2007 - - Copyright (C) 2007 Free Software Foundation, Inc. - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - - This version of the GNU Lesser General Public License incorporates -the terms and conditions of version 3 of the GNU General Public -License, supplemented by the additional permissions listed below. - - 0. Additional Definitions. - - As used herein, "this License" refers to version 3 of the GNU Lesser -General Public License, and the "GNU GPL" refers to version 3 of the GNU -General Public License. - - "The Library" refers to a covered work governed by this License, -other than an Application or a Combined Work as defined below. - - An "Application" is any work that makes use of an interface provided -by the Library, but which is not otherwise based on the Library. -Defining a subclass of a class defined by the Library is deemed a mode -of using an interface provided by the Library. - - A "Combined Work" is a work produced by combining or linking an -Application with the Library. The particular version of the Library -with which the Combined Work was made is also called the "Linked -Version". - - The "Minimal Corresponding Source" for a Combined Work means the -Corresponding Source for the Combined Work, excluding any source code -for portions of the Combined Work that, considered in isolation, are -based on the Application, and not on the Linked Version. - - The "Corresponding Application Code" for a Combined Work means the -object code and/or source code for the Application, including any data -and utility programs needed for reproducing the Combined Work from the -Application, but excluding the System Libraries of the Combined Work. - - 1. Exception to Section 3 of the GNU GPL. - - You may convey a covered work under sections 3 and 4 of this License -without being bound by section 3 of the GNU GPL. - - 2. Conveying Modified Versions. - - If you modify a copy of the Library, and, in your modifications, a -facility refers to a function or data to be supplied by an Application -that uses the facility (other than as an argument passed when the -facility is invoked), then you may convey a copy of the modified -version: - - a) under this License, provided that you make a good faith effort to - ensure that, in the event an Application does not supply the - function or data, the facility still operates, and performs - whatever part of its purpose remains meaningful, or - - b) under the GNU GPL, with none of the additional permissions of - this License applicable to that copy. - - 3. Object Code Incorporating Material from Library Header Files. - - The object code form of an Application may incorporate material from -a header file that is part of the Library. You may convey such object -code under terms of your choice, provided that, if the incorporated -material is not limited to numerical parameters, data structure -layouts and accessors, or small macros, inline functions and templates -(ten or fewer lines in length), you do both of the following: - - a) Give prominent notice with each copy of the object code that the - Library is used in it and that the Library and its use are - covered by this License. - - b) Accompany the object code with a copy of the GNU GPL and this license - document. - - 4. Combined Works. - - You may convey a Combined Work under terms of your choice that, -taken together, effectively do not restrict modification of the -portions of the Library contained in the Combined Work and reverse -engineering for debugging such modifications, if you also do each of -the following: - - a) Give prominent notice with each copy of the Combined Work that - the Library is used in it and that the Library and its use are - covered by this License. - - b) Accompany the Combined Work with a copy of the GNU GPL and this license - document. - - c) For a Combined Work that displays copyright notices during - execution, include the copyright notice for the Library among - these notices, as well as a reference directing the user to the - copies of the GNU GPL and this license document. - - d) Do one of the following: - - 0) Convey the Minimal Corresponding Source under the terms of this - License, and the Corresponding Application Code in a form - suitable for, and under terms that permit, the user to - recombine or relink the Application with a modified version of - the Linked Version to produce a modified Combined Work, in the - manner specified by section 6 of the GNU GPL for conveying - Corresponding Source. - - 1) Use a suitable shared library mechanism for linking with the - Library. A suitable mechanism is one that (a) uses at run time - a copy of the Library already present on the user's computer - system, and (b) will operate properly with a modified version - of the Library that is interface-compatible with the Linked - Version. - - e) Provide Installation Information, but only if you would otherwise - be required to provide such information under section 6 of the - GNU GPL, and only to the extent that such information is - necessary to install and execute a modified version of the - Combined Work produced by recombining or relinking the - Application with a modified version of the Linked Version. (If - you use option 4d0, the Installation Information must accompany - the Minimal Corresponding Source and Corresponding Application - Code. If you use option 4d1, you must provide the Installation - Information in the manner specified by section 6 of the GNU GPL - for conveying Corresponding Source.) - - 5. Combined Libraries. - - You may place library facilities that are a work based on the -Library side by side in a single library together with other library -facilities that are not Applications and are not covered by this -License, and convey such a combined library under terms of your -choice, if you do both of the following: - - a) Accompany the combined library with a copy of the same work based - on the Library, uncombined with any other library facilities, - conveyed under the terms of this License. - - b) Give prominent notice with the combined library that part of it - is a work based on the Library, and explaining where to find the - accompanying uncombined form of the same work. - - 6. Revised Versions of the GNU Lesser General Public License. - - The Free Software Foundation may publish revised and/or new versions -of the GNU Lesser General Public License from time to time. Such new -versions will be similar in spirit to the present version, but may -differ in detail to address new problems or concerns. - - Each version is given a distinguishing version number. If the -Library as you received it specifies that a certain numbered version -of the GNU Lesser General Public License "or any later version" -applies to it, you have the option of following the terms and -conditions either of that published version or of any later version -published by the Free Software Foundation. If the Library as you -received it does not specify a version number of the GNU Lesser -General Public License, you may choose any version of the GNU Lesser -General Public License ever published by the Free Software Foundation. - - If the Library as you received it specifies that a proxy can decide -whether future versions of the GNU Lesser General Public License shall -apply, that proxy's public statement of acceptance of any version is -permanent authorization for you to choose that version for the -Library. diff --git a/mods/fmod/MEDIA_LICENSE.txt b/mods/fmod/MEDIA_LICENSE.txt deleted file mode 100644 index 7d4f96c5..00000000 --- a/mods/fmod/MEDIA_LICENSE.txt +++ /dev/null @@ -1,427 +0,0 @@ -Attribution-ShareAlike 4.0 International - -======================================================================= - -Creative Commons Corporation ("Creative Commons") is not a law firm and -does not provide legal services or legal advice. Distribution of -Creative Commons public licenses does not create a lawyer-client or -other relationship. Creative Commons makes its licenses and related -information available on an "as-is" basis. Creative Commons gives no -warranties regarding its licenses, any material licensed under their -terms and conditions, or any related information. Creative Commons -disclaims all liability for damages resulting from their use to the -fullest extent possible. - -Using Creative Commons Public Licenses - -Creative Commons public licenses provide a standard set of terms and -conditions that creators and other rights holders may use to share -original works of authorship and other material subject to copyright -and certain other rights specified in the public license below. The -following considerations are for informational purposes only, are not -exhaustive, and do not form part of our licenses. - - Considerations for licensors: Our public licenses are - intended for use by those authorized to give the public - permission to use material in ways otherwise restricted by - copyright and certain other rights. Our licenses are - irrevocable. Licensors should read and understand the terms - and conditions of the license they choose before applying it. - Licensors should also secure all rights necessary before - applying our licenses so that the public can reuse the - material as expected. Licensors should clearly mark any - material not subject to the license. This includes other CC- - licensed material, or material used under an exception or - limitation to copyright. More considerations for licensors: - wiki.creativecommons.org/Considerations_for_licensors - - Considerations for the public: By using one of our public - licenses, a licensor grants the public permission to use the - licensed material under specified terms and conditions. If - the licensor's permission is not necessary for any reason--for - example, because of any applicable exception or limitation to - copyright--then that use is not regulated by the license. Our - licenses grant only permissions under copyright and certain - other rights that a licensor has authority to grant. Use of - the licensed material may still be restricted for other - reasons, including because others have copyright or other - rights in the material. A licensor may make special requests, - such as asking that all changes be marked or described. - Although not required by our licenses, you are encouraged to - respect those requests where reasonable. More considerations - for the public: - wiki.creativecommons.org/Considerations_for_licensees - -======================================================================= - -Creative Commons Attribution-ShareAlike 4.0 International Public -License - -By exercising the Licensed Rights (defined below), You accept and agree -to be bound by the terms and conditions of this Creative Commons -Attribution-ShareAlike 4.0 International Public License ("Public -License"). To the extent this Public License may be interpreted as a -contract, You are granted the Licensed Rights in consideration of Your -acceptance of these terms and conditions, and the Licensor grants You -such rights in consideration of benefits the Licensor receives from -making the Licensed Material available under these terms and -conditions. - - -Section 1 -- Definitions. - - a. Adapted Material means material subject to Copyright and Similar - Rights that is derived from or based upon the Licensed Material - and in which the Licensed Material is translated, altered, - arranged, transformed, or otherwise modified in a manner requiring - permission under the Copyright and Similar Rights held by the - Licensor. For purposes of this Public License, where the Licensed - Material is a musical work, performance, or sound recording, - Adapted Material is always produced where the Licensed Material is - synched in timed relation with a moving image. - - b. Adapter's License means the license You apply to Your Copyright - and Similar Rights in Your contributions to Adapted Material in - accordance with the terms and conditions of this Public License. - - c. BY-SA Compatible License means a license listed at - creativecommons.org/compatiblelicenses, approved by Creative - Commons as essentially the equivalent of this Public License. - - d. Copyright and Similar Rights means copyright and/or similar rights - closely related to copyright including, without limitation, - performance, broadcast, sound recording, and Sui Generis Database - Rights, without regard to how the rights are labeled or - categorized. For purposes of this Public License, the rights - specified in Section 2(b)(1)-(2) are not Copyright and Similar - Rights. - - e. Effective Technological Measures means those measures that, in the - absence of proper authority, may not be circumvented under laws - fulfilling obligations under Article 11 of the WIPO Copyright - Treaty adopted on December 20, 1996, and/or similar international - agreements. - - f. Exceptions and Limitations means fair use, fair dealing, and/or - any other exception or limitation to Copyright and Similar Rights - that applies to Your use of the Licensed Material. - - g. License Elements means the license attributes listed in the name - of a Creative Commons Public License. The License Elements of this - Public License are Attribution and ShareAlike. - - h. Licensed Material means the artistic or literary work, database, - or other material to which the Licensor applied this Public - License. - - i. Licensed Rights means the rights granted to You subject to the - terms and conditions of this Public License, which are limited to - all Copyright and Similar Rights that apply to Your use of the - Licensed Material and that the Licensor has authority to license. - - j. Licensor means the individual(s) or entity(ies) granting rights - under this Public License. - - k. Share means to provide material to the public by any means or - process that requires permission under the Licensed Rights, such - as reproduction, public display, public performance, distribution, - dissemination, communication, or importation, and to make material - available to the public including in ways that members of the - public may access the material from a place and at a time - individually chosen by them. - - l. Sui Generis Database Rights means rights other than copyright - resulting from Directive 96/9/EC of the European Parliament and of - the Council of 11 March 1996 on the legal protection of databases, - as amended and/or succeeded, as well as other essentially - equivalent rights anywhere in the world. - - m. You means the individual or entity exercising the Licensed Rights - under this Public License. Your has a corresponding meaning. - - -Section 2 -- Scope. - - a. License grant. - - 1. Subject to the terms and conditions of this Public License, - the Licensor hereby grants You a worldwide, royalty-free, - non-sublicensable, non-exclusive, irrevocable license to - exercise the Licensed Rights in the Licensed Material to: - - a. reproduce and Share the Licensed Material, in whole or - in part; and - - b. produce, reproduce, and Share Adapted Material. - - 2. Exceptions and Limitations. For the avoidance of doubt, where - Exceptions and Limitations apply to Your use, this Public - License does not apply, and You do not need to comply with - its terms and conditions. - - 3. Term. The term of this Public License is specified in Section - 6(a). - - 4. Media and formats; technical modifications allowed. The - Licensor authorizes You to exercise the Licensed Rights in - all media and formats whether now known or hereafter created, - and to make technical modifications necessary to do so. The - Licensor waives and/or agrees not to assert any right or - authority to forbid You from making technical modifications - necessary to exercise the Licensed Rights, including - technical modifications necessary to circumvent Effective - Technological Measures. For purposes of this Public License, - simply making modifications authorized by this Section 2(a) - (4) never produces Adapted Material. - - 5. Downstream recipients. - - a. Offer from the Licensor -- Licensed Material. Every - recipient of the Licensed Material automatically - receives an offer from the Licensor to exercise the - Licensed Rights under the terms and conditions of this - Public License. - - b. Additional offer from the Licensor -- Adapted Material. - Every recipient of Adapted Material from You - automatically receives an offer from the Licensor to - exercise the Licensed Rights in the Adapted Material - under the conditions of the Adapter's License You apply. - - c. No downstream restrictions. You may not offer or impose - any additional or different terms or conditions on, or - apply any Effective Technological Measures to, the - Licensed Material if doing so restricts exercise of the - Licensed Rights by any recipient of the Licensed - Material. - - 6. No endorsement. Nothing in this Public License constitutes or - may be construed as permission to assert or imply that You - are, or that Your use of the Licensed Material is, connected - with, or sponsored, endorsed, or granted official status by, - the Licensor or others designated to receive attribution as - provided in Section 3(a)(1)(A)(i). - - b. Other rights. - - 1. Moral rights, such as the right of integrity, are not - licensed under this Public License, nor are publicity, - privacy, and/or other similar personality rights; however, to - the extent possible, the Licensor waives and/or agrees not to - assert any such rights held by the Licensor to the limited - extent necessary to allow You to exercise the Licensed - Rights, but not otherwise. - - 2. Patent and trademark rights are not licensed under this - Public License. - - 3. To the extent possible, the Licensor waives any right to - collect royalties from You for the exercise of the Licensed - Rights, whether directly or through a collecting society - under any voluntary or waivable statutory or compulsory - licensing scheme. In all other cases the Licensor expressly - reserves any right to collect such royalties. - - -Section 3 -- License Conditions. - -Your exercise of the Licensed Rights is expressly made subject to the -following conditions. - - a. Attribution. - - 1. If You Share the Licensed Material (including in modified - form), You must: - - a. retain the following if it is supplied by the Licensor - with the Licensed Material: - - i. identification of the creator(s) of the Licensed - Material and any others designated to receive - attribution, in any reasonable manner requested by - the Licensor (including by pseudonym if - designated); - - ii. a copyright notice; - - iii. a notice that refers to this Public License; - - iv. a notice that refers to the disclaimer of - warranties; - - v. a URI or hyperlink to the Licensed Material to the - extent reasonably practicable; - - b. indicate if You modified the Licensed Material and - retain an indication of any previous modifications; and - - c. indicate the Licensed Material is licensed under this - Public License, and include the text of, or the URI or - hyperlink to, this Public License. - - 2. You may satisfy the conditions in Section 3(a)(1) in any - reasonable manner based on the medium, means, and context in - which You Share the Licensed Material. For example, it may be - reasonable to satisfy the conditions by providing a URI or - hyperlink to a resource that includes the required - information. - - 3. If requested by the Licensor, You must remove any of the - information required by Section 3(a)(1)(A) to the extent - reasonably practicable. - - b. ShareAlike. - - In addition to the conditions in Section 3(a), if You Share - Adapted Material You produce, the following conditions also apply. - - 1. The Adapter's License You apply must be a Creative Commons - license with the same License Elements, this version or - later, or a BY-SA Compatible License. - - 2. You must include the text of, or the URI or hyperlink to, the - Adapter's License You apply. You may satisfy this condition - in any reasonable manner based on the medium, means, and - context in which You Share Adapted Material. - - 3. You may not offer or impose any additional or different terms - or conditions on, or apply any Effective Technological - Measures to, Adapted Material that restrict exercise of the - rights granted under the Adapter's License You apply. - - -Section 4 -- Sui Generis Database Rights. - -Where the Licensed Rights include Sui Generis Database Rights that -apply to Your use of the Licensed Material: - - a. for the avoidance of doubt, Section 2(a)(1) grants You the right - to extract, reuse, reproduce, and Share all or a substantial - portion of the contents of the database; - - b. if You include all or a substantial portion of the database - contents in a database in which You have Sui Generis Database - Rights, then the database in which You have Sui Generis Database - Rights (but not its individual contents) is Adapted Material, - including for purposes of Section 3(b); and - - c. You must comply with the conditions in Section 3(a) if You Share - all or a substantial portion of the contents of the database. - -For the avoidance of doubt, this Section 4 supplements and does not -replace Your obligations under this Public License where the Licensed -Rights include other Copyright and Similar Rights. - - -Section 5 -- Disclaimer of Warranties and Limitation of Liability. - - a. UNLESS OTHERWISE SEPARATELY UNDERTAKEN BY THE LICENSOR, TO THE - EXTENT POSSIBLE, THE LICENSOR OFFERS THE LICENSED MATERIAL AS-IS - AND AS-AVAILABLE, AND MAKES NO REPRESENTATIONS OR WARRANTIES OF - ANY KIND CONCERNING THE LICENSED MATERIAL, WHETHER EXPRESS, - IMPLIED, STATUTORY, OR OTHER. THIS INCLUDES, WITHOUT LIMITATION, - WARRANTIES OF TITLE, MERCHANTABILITY, FITNESS FOR A PARTICULAR - PURPOSE, NON-INFRINGEMENT, ABSENCE OF LATENT OR OTHER DEFECTS, - ACCURACY, OR THE PRESENCE OR ABSENCE OF ERRORS, WHETHER OR NOT - KNOWN OR DISCOVERABLE. WHERE DISCLAIMERS OF WARRANTIES ARE NOT - ALLOWED IN FULL OR IN PART, THIS DISCLAIMER MAY NOT APPLY TO YOU. - - b. TO THE EXTENT POSSIBLE, IN NO EVENT WILL THE LICENSOR BE LIABLE - TO YOU ON ANY LEGAL THEORY (INCLUDING, WITHOUT LIMITATION, - NEGLIGENCE) OR OTHERWISE FOR ANY DIRECT, SPECIAL, INDIRECT, - INCIDENTAL, CONSEQUENTIAL, PUNITIVE, EXEMPLARY, OR OTHER LOSSES, - COSTS, EXPENSES, OR DAMAGES ARISING OUT OF THIS PUBLIC LICENSE OR - USE OF THE LICENSED MATERIAL, EVEN IF THE LICENSOR HAS BEEN - ADVISED OF THE POSSIBILITY OF SUCH LOSSES, COSTS, EXPENSES, OR - DAMAGES. WHERE A LIMITATION OF LIABILITY IS NOT ALLOWED IN FULL OR - IN PART, THIS LIMITATION MAY NOT APPLY TO YOU. - - c. The disclaimer of warranties and limitation of liability provided - above shall be interpreted in a manner that, to the extent - possible, most closely approximates an absolute disclaimer and - waiver of all liability. - - -Section 6 -- Term and Termination. - - a. This Public License applies for the term of the Copyright and - Similar Rights licensed here. However, if You fail to comply with - this Public License, then Your rights under this Public License - terminate automatically. - - b. Where Your right to use the Licensed Material has terminated under - Section 6(a), it reinstates: - - 1. automatically as of the date the violation is cured, provided - it is cured within 30 days of Your discovery of the - violation; or - - 2. upon express reinstatement by the Licensor. - - For the avoidance of doubt, this Section 6(b) does not affect any - right the Licensor may have to seek remedies for Your violations - of this Public License. - - c. For the avoidance of doubt, the Licensor may also offer the - Licensed Material under separate terms or conditions or stop - distributing the Licensed Material at any time; however, doing so - will not terminate this Public License. - - d. Sections 1, 5, 6, 7, and 8 survive termination of this Public - License. - - -Section 7 -- Other Terms and Conditions. - - a. The Licensor shall not be bound by any additional or different - terms or conditions communicated by You unless expressly agreed. - - b. Any arrangements, understandings, or agreements regarding the - Licensed Material not stated herein are separate from and - independent of the terms and conditions of this Public License. - - -Section 8 -- Interpretation. - - a. For the avoidance of doubt, this Public License does not, and - shall not be interpreted to, reduce, limit, restrict, or impose - conditions on any use of the Licensed Material that could lawfully - be made without permission under this Public License. - - b. To the extent possible, if any provision of this Public License is - deemed unenforceable, it shall be automatically reformed to the - minimum extent necessary to make it enforceable. If the provision - cannot be reformed, it shall be severed from this Public License - without affecting the enforceability of the remaining terms and - conditions. - - c. No term or condition of this Public License will be waived and no - failure to comply consented to unless expressly agreed to by the - Licensor. - - d. Nothing in this Public License constitutes or may be interpreted - as a limitation upon, or waiver of, any privileges and immunities - that apply to the Licensor or You, including from the legal - processes of any jurisdiction or authority. - - -======================================================================= - -Creative Commons is not a party to its public -licenses. Notwithstanding, Creative Commons may elect to apply one of -its public licenses to material it publishes and in those instances -will be considered the “Licensor.” The text of the Creative Commons -public licenses is dedicated to the public domain under the CC0 Public -Domain Dedication. Except for the limited purpose of indicating that -material is shared under a Creative Commons public license or as -otherwise permitted by the Creative Commons policies published at -creativecommons.org/policies, Creative Commons does not authorize the -use of the trademark "Creative Commons" or any other trademark or logo -of Creative Commons without its prior written consent including, -without limitation, in connection with any unauthorized modifications -to any of its public licenses or any other arrangements, -understandings, or agreements concerning use of licensed material. For -the avoidance of doubt, this paragraph does not form part of the -public licenses. - -Creative Commons may be contacted at creativecommons.org. diff --git a/mods/fmod/README.md b/mods/fmod/README.md deleted file mode 100644 index ca3fab52..00000000 --- a/mods/fmod/README.md +++ /dev/null @@ -1,81 +0,0 @@ -# fmod - -flux's mod boilerplate - -## what? - -i use this to create a common basic API that all of my mods share. it grabs a lot of mod metadata from e.g. mod.conf -and settingtypes.txt and automatically makes those values available. - -this mod is primarily for my own use, but i'd be elated if other people find it useful. suggestions are welcome, but -note that my own patterns come first in any suggested changes. the more mods i create which depend on this (there's -over 70 and counting, though only 50 or 60 are released), the harder it will be to change fundamental features. but -if i've made major mistake somehow, please let me know sooner rather than later! - -## public API - -* `modname = fmod.create(fork)` - - creates the boilerplate. - - `fork` is an optional parameter for other people to use if they fork a mod. - -the api which is created looks like this: - -```lua -local f = string.format -local modname = minetest.get_current_modname() -local S = minetest.get_translator(modname) -local modpath = minetest.get_modpath(modname) -local mod_conf = Settings(modpath .. DIR_DELIM .. "settingtypes.txt") - -modname = { - modname = modname, - modpath = modpath, - title = mod_conf:get("title") or modname, - description = mod_conf:get("description"), - author = mod_conf:get("author"), - license = mod_conf:get("license"), - version = mod_conf:get("version"), - fork = fork or "flux", -- fork is the argument to `fmod.create(fork)` - - S = S, - - has = build_has(mod_conf), -- this reads mod.conf and creates a set from optional_depends - settings = get_settings(modname), -- this reads and parses settingtypes.txt, and populates w/ values from - -- minetest.conf, or otherwise the defaults specified in settingtypes.txt - - check_version = function(required) - assert(mod_conf:get("version") >= required, f("%s requires a newer version of %s; please update it", minetest.get_current_modname(), modname)) - end, - - check_minetest_version = function(major, minor, patch, other, reason) - assert(..., "check that the required version of the game engine is present. \"other\" is reserved for " .. - "future use, once i figure out how to deal w/ engine forks." - ) - end, - - log = function(level, messagefmt, ...) - return minetest.log(level, f("[%s] %s", modname, f(messagefmt, ...))) - end, - - chat_send_player = function(player, messagefmt, ...) - minetest.chat_send_player(player, f("[%s] %s", modname, S(messagefmt, ...))) - end, - - chat_send_all = function(message, ...) - minetest.chat_send_all(f("[%s] %s", modname, S(message, ...))) - end, - - dofile = function(...) - return dofile(table.concat({modpath, ...}, DIR_DELIM) .. ".lua") - end, - - async_dofile = function(...) -- load a file into the async environment - return minetest.register_async_dofile(table.concat({ modpath, ... }, DIR_DELIM) .. ".lua") - end, -} -``` - -note that fmod itself is created w/ this same boilerplate; therefore, i can indicate that certain mods require an -up-to-date version of fmod to operate. diff --git a/mods/fmod/build_has.lua b/mods/fmod/build_has.lua deleted file mode 100644 index 691872ee..00000000 --- a/mods/fmod/build_has.lua +++ /dev/null @@ -1,12 +0,0 @@ -return function(mod_conf) - local optional_depends = mod_conf:get("optional_depends") - if not optional_depends then - return {} - end - local has = {} - for _, mod in ipairs(optional_depends:split()) do - mod = mod:trim() - has[mod] = minetest.get_modpath(mod) and true or false - end - return has -end diff --git a/mods/fmod/get_settings.lua b/mods/fmod/get_settings.lua deleted file mode 100644 index 8a0024e6..00000000 --- a/mods/fmod/get_settings.lua +++ /dev/null @@ -1,150 +0,0 @@ --- https://github.com/minetest/minetest/blob/master/builtin/settingtypes.txt --- https://github.com/minetest/minetest/blob/master/builtin/mainmenu/settings/settingtypes.lua - -local f = string.format - -local function get_lines_from_file(filename) - local fh = io.open(filename, "r") - if not fh then - return - end - local lines = fh:read("*all"):split("\n") - fh:close() - return lines -end - -local function strip_readable_name(text) - if text:sub(1, 1) ~= "(" then - error(f("%q %s", text, text)) - end - local depth = 1 - local i = 2 - while depth > 0 do - if text:sub(i, i) == ")" then - depth = depth - 1 - elseif text:sub(i, i) == "(" then - depth = depth + 1 - end - i = i + 1 - end - return text:sub(i):trim() -end - -local function starts_with(s, start) - return s:sub(1, #start) == start -end - -local function parse_line(modname, line) - if line:match("^%s*#") or line:match("^%s*%[") or line:match("^%s*$") then - return - end - line = line:trim() - local full_name, rest = unpack(line:split("%s+", false, 1, true)) - if not (full_name and rest) then - return - end - local secure = false - if starts_with(full_name, "secure.") then - secure = true - full_name = full_name:sub(#"secure." + 1) - end - local modname2, short_name = unpack(full_name:split("[:%.]", false, 1, true)) - assert(modname2 == modname, f("invalid setting name %s", full_name)) - rest = strip_readable_name(rest) - local datatype, default, params - datatype, rest = unpack(rest:split("%s", true, 1, true)) - rest = rest or "" - if datatype == "string" then - if rest:sub(1, 1) == '"' and rest:sub(#rest, #rest) == '"' then - -- this is not actually according to spec settingtypes.txt, but there's no good way to specify that the - -- default value is a single space, so we invent our own syntax - default = rest:sub(2, #rest - 1) - elseif rest:sub(1, 2) == '\\"' then - default = rest:sub(2) - else - default = rest - end - params = "" - else - default, params = unpack(rest:split("%s+", false, 1, true)) - end - - full_name = (secure and "secure." or "") .. full_name - return full_name, short_name, datatype, default, params -end - -local getters = { - -- TODO there's other setting types, but i don't use them and no-one else uses this mod - int = function(full_name, default, params) - return tonumber(minetest.settings:get(full_name)) or tonumber(default) - end, - string = function(full_name, default, params) - return minetest.settings:get(full_name) or default - end, - bool = function(full_name, default, params) - return minetest.settings:get_bool(full_name, minetest.is_yes(default)) - end, - float = function(full_name, default, params) - return tonumber(minetest.settings:get(full_name)) or tonumber(default) - end, - enum = function(full_name, default, params) - return minetest.settings:get(full_name) or default - end, - path = function(full_name, default, params) - return minetest.settings:get(full_name) or default or "" - end, - filepath = function(full_name, default, params) - return minetest.settings:get(full_name) or default or "" - end, - key = function(full_name, default, params) - return minetest.settings:get(full_name) or default - end, - flags = function(full_name, default, params) - return (minetest.settings:get(full_name) or default):split() - end, - v3f = function(full_name, default, params) - return minetest.string_to_pos(minetest.settings:get(full_name) or default) - end, -} - -return function(modname) - local modpath = minetest.get_modpath(modname) - local settingtypes_lines = get_lines_from_file(modpath .. DIR_DELIM .. "settingtypes.txt") - - if not settingtypes_lines then - return - end - - local settings = {} - for _, line in ipairs(settingtypes_lines) do - local full_name, short_name, datatype, default, params = parse_line(modname, line) - if full_name then - local getter = getters[datatype] - if getter then - settings[short_name] = getter(full_name, default, params) - else - error("TODO: implement parsing settings of type " .. datatype) - end - end - end - - local listeners_by_key = {} - - return setmetatable({ - _subscribe_for_modification = function(self, key, func) - local listeners = listeners_by_key[key] or {} - table.insert(listeners, func) - listeners_by_key[key] = listeners - end, - }, { - __index = function(self, key) - return settings[key] - end, - __newindex = function(self, key, value) - settings[key] = value - for _, func in ipairs(listeners_by_key[key] or {}) do - func(value) - end - end, - }) -end diff --git a/mods/fmod/init.lua b/mods/fmod/init.lua deleted file mode 100644 index ba4f05aa..00000000 --- a/mods/fmod/init.lua +++ /dev/null @@ -1,169 +0,0 @@ -local f = string.format - -local get_current_modname = minetest.get_current_modname -local get_modpath = minetest.get_modpath - -local our_modname = get_current_modname() -local our_modpath = get_modpath(our_modname) - -local build_has = dofile(our_modpath .. DIR_DELIM .. "build_has.lua") -local get_settings = dofile(our_modpath .. DIR_DELIM .. "get_settings.lua") -local parse_version = dofile(our_modpath .. DIR_DELIM .. "parse_version.lua") - -local function create(fork, extra_private_state) - local modname = get_current_modname() - local modpath = get_modpath(modname) - local S = minetest.get_translator(modname) - local F = minetest.formspec_escape - - local mod_conf = Settings(modpath .. DIR_DELIM .. "mod.conf") - assert(modname == mod_conf:get("name"), "mod name mismatch") - - local version = parse_version(mod_conf:get("version")) - - local private_state = { - -- minetest.request_insecure_environment() can't be used here - -- minetest.request_http_api() can't be used here - mod_storage = INIT == "game" and minetest.get_mod_storage(), - } - - if extra_private_state then - for k, v in pairs(extra_private_state) do - private_state[k] = v - end - end - - return { - modname = modname, - modpath = modpath, - - title = mod_conf:get("title") or modname, - description = mod_conf:get("description"), - author = mod_conf:get("author"), - license = mod_conf:get("license"), - media_license = mod_conf:get("media_license"), - website = mod_conf:get("website") or mod_conf:get("url"), - version = version, - fork = fork or "flux", - - S = S, - FS = function(...) - return F(S(...)) - end, - - has = build_has(mod_conf), - settings = get_settings(modname), - - check_version = function(required, reason) - if type(required) == "table" then - required = os.time(required) - end - local calling_modname = minetest.get_current_modname() or "UNKNOWN" - if reason then - assert( - version >= required, - f( - "%s requires a newer version of %s because %q; please update it.\n" - .. "go to the main game menu, click the content tab, browse online content, and update all.\n" - .. "(have %s, require %s)", - calling_modname, - modname, - reason, - version, - required - ) - ) - else - assert( - version >= required, - f( - "%s requires a newer version of %s; please update it.\n" - .. "go to the main game menu, click the content tab, browse online content, and update all.\n" - .. "(have %s, require %s)", - calling_modname, - modname, - version, - required - ) - ) - end - end, - - check_minetest_version = function(major, minor, patch, other, reason) - local mt_version = minetest.get_version() - -- TODO: figure out how to allow various "projects" (e.g. Minetest, Multicraft) properly - -- TODO: we perhaps want to allow depending on multiple projects, so this is complicated. - local mt_major, mt_minor, mt_patch = mt_version.string:match("^(%d+)%.(%d+)%.(%d+)") - if not (mt_major and mt_minor and mt_patch) then - error( - f( - "%s is not compatible w/ minetest %s because we don't understand the version", - modname, - mt_version.string - ) - ) - end - mt_major = tonumber(mt_major) - mt_minor = tonumber(mt_minor) - mt_patch = tonumber(mt_patch) - local check = true - if mt_major < major then - check = false - elseif mt_major == major then - if mt_minor < minor then - check = false - elseif mt_minor == minor then - if mt_patch < patch then - check = false - end - end - end - if not check then - if reason then - error( - f("%s requires at least minetest %i.%i.%i because it %q", modname, major, minor, patch, reason) - ) - else - error(f("%s requires at least minetest %i.%i.%i", modname, major, minor, patch)) - end - end - end, - - log = function(level, messagefmt, ...) - return minetest.log(level, f("[%s] %s", modname, f(messagefmt, ...))) - end, - - chat_send_player = INIT == "game" and function(player, messagefmt, ...) - if player.get_player_name then - player = player:get_player_name() - end - - minetest.chat_send_player(player, f("[%s] %s", modname, S(messagefmt, ...))) - end, - - chat_send_all = INIT == "game" and function(message, ...) - minetest.chat_send_all(f("[%s] %s", modname, S(message, ...))) - end, - - dofile = function(...) - assert(modname == get_current_modname(), "attempt to call dofile from external mod") - local filename = table.concat({ modpath, ... }, DIR_DELIM) .. ".lua" - local loader = assert(loadfile(filename)) - return loader(private_state) - end, - - async_dofile = function(...) - assert(modname == get_current_modname(), "attempt to call async_dofile from external mod") - local filename = table.concat({ modpath, ... }, DIR_DELIM) .. ".lua" - return minetest.register_async_dofile(filename) - end, - }, - private_state -end - -fmod = create() -fmod.create = create - -if INIT == "game" then - fmod.async_dofile("init") -end diff --git a/mods/fmod/mod.conf b/mods/fmod/mod.conf deleted file mode 100644 index 1a33e0dd..00000000 --- a/mods/fmod/mod.conf +++ /dev/null @@ -1,10 +0,0 @@ -name = fmod -title = fmod -description = flux's mod boilerplate -website = https://content.minetest.net/packages/rheo/fmod/ -author = flux -license = LGPL-3.0-or-later -media_license = CC-BY-SA-4.0 -version = 2024-04-03 -min_minetest_version = 5.8.0 -supported_games = * diff --git a/mods/fmod/parse_version.lua b/mods/fmod/parse_version.lua deleted file mode 100644 index c1ca253f..00000000 --- a/mods/fmod/parse_version.lua +++ /dev/null @@ -1,28 +0,0 @@ -local f = string.format - -return function(version) - local y, m, d, h, mi, s - y, m, d = version:match("^(%d%d%d%d)-(%d%d)-(%d%d)$") - if y and m and d then - return os.time({ year = tonumber(y), month = tonumber(m), day = tonumber(d) }) - end - - y, m, d, s = version:match("^(%d%d%d%d)-(%d%d)-(%d%d)[%.%s](%d+)$") - if y and m and d and s then - return os.time({ year = tonumber(y), month = tonumber(m), day = tonumber(d), sec = tonumber(s) }) - end - - y, m, d, h, mi, s = version:match("^(%d%d%d%d)-(%d%d)-(%d%d)[T ](%d%d):(%d%d):(%d%d)$") - if y and m and d and h and mi and s then - return os.time({ - year = tonumber(y), - month = tonumber(m), - day = tonumber(d), - hour = tonumber(h), - min = tonumber(mi), - sec = tonumber(s), - }) - end - - error(f("can't parse version %q", version)) -end diff --git a/mods/fmod/screenshot.png b/mods/fmod/screenshot.png deleted file mode 100644 index 77fcc5885b11bb73c9ae194f0e403fe05b4b75f1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 163389 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�e~I$o>Y1JR_|JmB39+o*22rZpK|4A&K}tp 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%0DltVW~<(T)q z@SR|$V4&84#t zlM#4(I6K5&-R+Z6xpeEh$UkFVJf=FmreO!O{HXLWUA2 zM9sSf&h2HaKIz8D9BO}8_NlK}{`s;Vo9Z9pZ^O%eZGEJU6crBin5+K15|KxVlKO^) zGsnb~bywqI)<|NeEoGUOgU;khWN)MDjaT{f*!J6JGczZ4xa~F)mwoyN&Mq#T8IoOy z|K)2RJeG~fY4>Qpc~?PI<;y$Y)cGHgwE-Uu#bLC)D1gep4)Cp%@KLPtZ?Ba(2%h~> zn>%kzir>Y*5c}JH1CA!ZY+8v79QDmY?h1wBF2)<1c_7+ZQeB_r?Ewa`w83Z(?`QXqP>Dx`n3NxyR4Ok4h3d-0+(DN zzX9BSo}08luv-C$uZy~wL_fx9kU&8gl9ne&CauZ4Bduw5M_eq>=R`5XV6igV zONqxr)zSWS&bk#rTL`LsT$&w=HZz=^=cEJqlCOPzxn^Qn4QbgST({qj76k#>o@p7ssfWV+jvrLE&~nd3*|7|i;H8{JI7+(XmHnUj{q zHj2UEbA2<-&a7AeTaMr*bSkU*Wam)LRZVyCVWWX*H-(a!aCmmhb-_3I(5lLLcs&O< z`;SNYW5UbM{t<*_ zc|_clFW$oi!qN)xyg%MktFw*;?imTQF6({!*dAmeZfzLMD*+|B1pC>ghb0SfH&P?^ z#v!@BoJIhT#e+QEh19HjoF!q3>z@w5SW+CYKjJ5;lhPazQE2_p5G6P*85?A6- zZay37J8-S<)ofcp`giG!&rwZ3({1eS=kk`EUBU{RP#f95eUh>RM*Kzpt@o z3@z_Sx?Yoh5wg&YjeQ=R#hGnX8g*{TwIWL;A|y!~@Ad57z1*-`rlGW926-wBfAj8%L}cA;X4tN{3_V;v2o@MTR&(Pwsd@dIvxHZu z55B-tx-i$iU>}G}I%Pe^|M9@BJYD|x%qxc}wB#OxYnfAlpRmhC+eE>n|J88~+bsuj zS0(qbpL(_nj19H2wRcqWQWDz=%d0(4@MXNDSu@N_z7=hJJdYjfCmkm%!bO_38?t@{ za(=>hUh{2QIBdJ(jYh#Vc58D}uAPmDEq1U#sXIFA)Y8g6HTDY}lK1?G3hH@=tb+cd z#7G$g$^*9W5gt3ubp<=T9v4Mh-sS_sche319QfxK5L}@;b+?e|!Y`NAmp-y@)^88( zth3+n#)EaA3u?6mj?VA z%&esBnqET=dX3HcjdRug>G`|eokH2K9%RR`8sCoif8#mBX36hfZV-IzDgbkKKTV%_ zp8om}&@KfAyxa#Lz9-(+AEIi;t=5Z|xA~(Zsi@E3mEY7WB|wS0rg3XbhpPXHsL;ij zN{6m*+x=iN)J;c)XU>w*=R5QC_(TtZ1=>q;&4lj-|(Ezn$46@{!H)SPIox-4RM#bxupc<9;i zA;an0GrpsWhP%D2LCT+>$=&ba1A|jhCmJEeZFN#_z){+MkOMlxAy9$8v}qZniuG0S^`C%}tL_Jv7jlq7nGMDB*BVbzoq*MOB$B z(lSgsz2ZaDFq6B^m-l2O^dC*Nv02v0DhQE0w_0D}^MdCzA7+Xuz(}A5*R7@1Ke;R8 z0kH6`|7jR$AS`)fTdTAOD=QreO(G1GYM%SHlffqFA^Y=kjL9cVgX4zLx(>EOz^KC9 z)+ITgrh3-kq~5TggqDUi-L>bVl=biF8E&(8LS6rVahk$L>WP<&V9!Ncd3fCRkvANSC01uOp;RbGvDFX29MpT;P z??eK=!|>sA`{1%WMP^5&-wKRXJ_5Pzz5g;xu?XZ{{{(8!-fB^TFG!Gn4V&H*za{Ug zQwl#%CFnV}%ppa+vG*qd+>wuJ9@OW@59yqw+}IB{ouEaSQNvcs^<$1}uGHxBh_1%# z0DGM#lZtVpPf{<;XZdChhtj1>SNmf!bIw?y7lD7IH@@!I>}1xI2N=9Li7_Z;+}-p& z>>e$@$xQ8kHp%n4x(?cjK>82mcPU(FM>16*6uH3{9nlx!Mq^oZt=iKnCxwpW*MVC@ zibNvF7w-}eD9q?3V2{Q&)55M}8vTs}lLarHy=~V#46a|yKc3aBxUGcEa=wUV=@tx! zq#IUyI;cfXhKHU$B19jGluge3z&Y?*9K*a-B}0)cyGud6L&?DIS=NRT@Ur|;r=+W! zUiX9jVXtt3#0v~9G)nnmVAVN;=)c#_4An#JO}9m zo5fSt`f=o99wySFKo1vKPkd>vw=k+V!JGKfR9`5*3U}^UcIowPTnmrEhCQ%${HFlp ze`wxC@_HYfk&e!G`Ob9t@Rzj*taKO6UNurb4$E;rxVBhh5SZG%4~-EjtTfcKUd=BB zBc1u6jdeHjWN%j4X7yXsO$0KdHdIxqv@~Y0zlbi_@Ye3q(+?@PDER-8J*0GJp!~g> z9@Nyr=7hYo!6Oo+Sv;o{jnQ)iY{0Fyedyh5Sa<&j$qgqG?tzt3DC7-A7M}xm?XPd_uD;V58Pt0>RH8ZbZY0X` zuAOU-IsQP5@~!-C{$EB859!j0w4D{|5Sk_BMw7^@unfptfGz z5qUHxj)!!hgp*>JP;W6kKKxSqvlS+iAMwv%ycb_42TlHp78-1NfA3PGdbK6&#qneX z;k@b&<@$MQ(G6;O2>VIpsD*ElCGpy>_o|EXkH<;A@2PeO}4tG3H z(jZk7X<~x-h=CeLm(0zkFI-&mHB|U;i!LRNb zGV0u4S{WNzfsd>U>!8q$a62pY?b&gm>BYDX5WmV<6gjwJL@D}Z(slDw6KqQM=)tdS zz0KElb((64o_I;`hdFj@3BcsyN#H>rZgqjo?EJc`df&9}SDeb1E>l!dI<;4QG?_iaYI{qPiR!ZXy*{u(df0`rzBVWE0Wgv9c? zW&n$|nY_xuar8c+mm}0t7hz42kUKnm2R8Qvv*>rY*{5;Mc}1uR2nbqzP|hH}ZQM;s z%oy5ru3~=*9o6zs4h!59Rm%J$px<-a&gB$gm_pMdY{-*vO6BzFOHro3Oy;;*f!USx z0R1>PZ0^V6eOZg|XAGB9ipu-+Dr2eNPfk*?o$e>>b-zXjQSfR&ZCzeuZH)HznX&`| zX#{q3ek{E`RP7}~owVjCqWe7HcWT88e+w5EHF2$WRy08Pte#ins+f7ZPF9Uy6QMJk zivu=TZHC};5@jp|91HzV;iuhMYf^r5Q!kvxucA`PP;SkBuHKt8gw$uP6rJEh^IQyx zG^StfG;4FpCvgzMW=S7O!r%vl!a3r!)Tk}mfgV;m zAU0!Fcz$^HfHY`q^l~!_Bc(!}-F6*3WXQetE5v*S7Q3jy(X#0I885%wpdjyf)syS~ zb==r;!R+oj>%h7JydE8luv#n<2icFCL73!Kd?g>LmZ&6$jm%kA^WR-~`DTX3SC25P zE?M#fpTGH}&pcOE?uM+CHFqn_)5=#!PxlBwI>4tU5i$MZ+ZRM0GiF zVq>&Aj=9-oW@-;TukWd2PhO0-iFz%W{c$B|7u7$A`W#0B}p+i;mt^Dy1m+Jh*DtnDBe2L5uO*v#@~&^oH;9yBSiOe58Ef z{oVwqQ2)^${+pknN&5(_-KU#%1p1{b)F=Xw3&IObpA4BAHSUc{IpCh2&J3=M@I43N z1jxJciyFFA@&$=%`$XWrI|=H<$pEvUHnsVzh&=#T^QZlBq+wX*D>`9rY zvCwVDeir?i{CpL9KUVoomz2*5P3I8L`@sinDcZh-DRaM^pAHuhVKmQW`ll!w=%Up2 z=r9B86)wWSXuJPQ>suKXNQ_8P2*_7iD?1W|urS{BeiHuKG&Dd;^xaHD?0c|rK4T)5 zVg@+7%7o$H!z#OVpAtyT-=$aj7^HSCM}Yjc+-vPEJMhgfR7P|0dp>z=8Q81T(jK3x ztc2U`3C&Fue8y#Y1P<)G>%$`5hCd&ZXKqCe3{a_oktA1}=Yl(CKL`XAz|n}wzFh-; z5zUp*&=6NT)VF4{0LzG`u}PWy{x4JJfxm=6(%mI()?K-cZ}^1hFD4;+cHgULmrk^A77Ui2%+V%y%+FQz-9@mFFYf9EP@lla zuVVR}W_qZF+%JnnGm+DA=_tn)n6SI};-jg#b;OKoUl0Lq@F0{BohePzj)yvNDfAFd zf{Gjk>qSXjME8L;G6cGn5cNo(Jofk~giu;86^G9>eD_Hd1c^EdT^o!cJ@oC%oK7hN z>8fm4XlmHwKTyON3F0VFzlIdQ9E=Hp+vD^JFFhG}7L$S}tumrASZCSBmX;5mdF;k<&`Nfn; z&;vwBsA4KE_1TWBI}S26<##91En=gKHsNxhNMaJv3l#H1@NY*b;tzZ!gUZbkpz1PT zV(vo90*|eQw0p8LHQCuD(H)MouzhE2DMU+jf?KL9yhn0!_Jzg9v*Hv~)~ErK7a%X{ zm*!w`$6DS1CNnJNh6`+E`~joS?W=pz(L|_P@bpS2!24#(?XzPt-P3N+AD#tgb|A8z zB0}v&ju9d8s&VJGel{+9ODb|;#fo2Bhmm%JwR09BsD{bqMq3b8JE%;WQPlhR{cmB_ zd**2Av1aedCjZI4Ly{A$uXCJ9ak`qab|}Xb5S&Z`qZNKwQfo_>au})zH>0Rqxhr+I zU_l5N`i5rgXH7@}5?_KaOW^sf8$j437_Ewv_7*`xlr;%DOja1&Iit)zO!lQ%hjpCa z>HL#Nb_)h2?0M(|p9|6Xgyw7OOz)xbH zN{wd>Kija*Alt=st0RJ{8xxK(zT_P##gFmywe*AU{IBvIWea=D3>Zc34It8Bv_*HD zYfBtwf9)<8;$lUCfnJfvkA#0BkkF(Rf)1tjf-8j0+zx%MCu2dgbX-Y-n79F0Y&s~j z1GQaQe%w`p#8NZZvdNi%7km5Wi{>cM_hEIy~--JBE!LZN%(jfrzE@x>h{)#B)#n{?n`wJ&HN$d|8?P7lko)YFDq&n=ZGG~mBLCzqCN6b> zSUQt4J{yZg38rXQsd+W*$OPrdrIN?#{gD8**T~iMLOP?FUkwL&;%ze$AM@<%-YHb{ zZRo7~EIrFfb{+$fxUC1f`nbj6mEPu6UmO-o64c%n?wO@o$+=f+^D)EZEjP9uM{8^W zZg_L#?k%?$PWK@;KnYRt&B-s%2(P!_UwpQ97lnCLe)FYptxsXEZSEuMnlBEWy9`)C z=c4}SXG#2KM4n@5_(}e8kW$nrgMeoCR^yPgJJ$=<)Gr5+CE~S?&PE*EcY62H$?hO-B+! zl*sNzpwsNd1=Yq`;LngPf;mFrUp!a`e(`Cig4My0xFgIuUOKh!(qBNy%smzXI%|(m z56cXSr(aRGI0$IRLFVF?_!#ra6YT6bUYKnYC**;un7|aJ;+27;U}l@zSm8YLliYO` zR>`^7KAKw`!++XL_t&SUVp#spM>rKq^^9Zgh33xpe0$cKv+r$Twbu64KBYB>w}RTu zUgKiHnw?@@0Cm=^HBo9pZ=0$u90y!Rlv_I+)W=kzt5J|fQlq#`z#jMFl*#Dy&igoP zc$vXxpNu}`$aXX9uB9Y!n#}J>v(?LpMQ|Bd0CE>k)E1ileE9}7CPmRkJdhQY{=7&y z-hsitV0#E#IT#uKp{-BES5qfVON4+oU?Y-`AY@ehBe~!~7?|@oBjDvD8+Q?DAeDo}S_~>ER zIm`e06!nS>m78DOXu_|`ot8i?BzbdSPL~V6CbC+~?&y^MO?mj>m2 zT(90ZnbEY$sAyYtzKI_x(b#GKNuR6N(k(xY#fWc|uBGHrJnYgeUbaNxvw^;McuSkF zlGrJ_t?j3c??X`EKg1jNc`Likoa?Ofhh|iSKQ*VFyM8vVR7$}5Z^M_Y;M2-}C$@0) zMq;jqj{N!Xcb_^wkU#Axl#;rx%>IP~OgRRnX{7!y10*>d9((<^p_iVMv4?74pziC6 z;DhS25G3MDII29w1td+P)!;e!|0Qb*2SREE={ln4K|w(VeKRFK)uiFPXYUg@;&W33 zK?!LG_J4;niG;vRM@mNO|D@*JGj(3TM}#)h?d7v#l)Tb0D3kQYo3mKgLbE*j3qlzMxyP4}*$X`6msBwqOLl=P+O2p< zr|FVZwmxujdTRHlVPDs-u_mw2?)!?6Hb;v`sP4oK6exQ5sAowzi2!yJ1zA7nL2>c| z*+UR);O)dl2MiySR(#}$qyP#qTk0h5&wmW-8yb1(d|uiob`9FQir?(zr9lzty@!+s z!Ocl0qw$}EBT^s;qm{zWw(0+Hm?-W=weNMs(v1%Fv3_JG!Pt0zx?16-+>P&+J+_9q z!!tWXs4nuo{e+}L<9#bFynC>J&pT8e!(u57R~0o~KDIt7m}0%r8SfYrGGCaFj}We+ zo1QUw@201#3so4Up2VKxu^`Hx8Obaqlvcb^w+Nqm@(UA5!(6Msv8&heH{N$ior(o4 zwrHYxWmM?GKG1jb&-dNF|M~`yO?qe!_iBO zLL+5Qt*g@gtc8ZK7D=4nm=f2M2EqS5PfBiqmwArn+`86&w=nUJPNGU#F|=xH@|xrv z-qL$nm~`ONXn(BkYyJffreTYXOp?{>stDqF8bA3Z@vQqz-X zsERCu6bQVTkCs zID73qspbvv=z%9oNASg<5koE08;b5TR@lwW-CP8o${pB;{44nQsNaS~+OO8GC`nQ+ zBK{q)KmfcUOYQ&|T(~_04(W?EX=k`$PmBsZgi^ zqwv!wCi-?;=Eo1uE))On)Q!{7IoH?On(atm9s;Eq5s}9O^ z6f|j4hE5j3do7L)pX1xrGAh(He(Cwi#sdppg{^0aH2PRzC5Gu7JY8>(fQ0W%Q3SPKzG)uV4tXff4xa0sJ`T08A|Tp=Pa-1 zbtp@Eut|;tDL27Z^qpGE@TR2y1Yis2ZnC67ajz$&hTi1^qG$E935m47hyk!iG|j{3 z3q`ag7cJW%s(Q#Vq^C-9B@|O*#O($~yZ=oKZW1{6#SE9XC%E&boj#h0QleBXg?R|X zMfPo{uA`M-H8l?2hic_QRuv%%!(YwmK`=XXI^yF`Ez}HuV!dLf-a7~NgFAj;cisTu z9!+P+DU#Z2bv{f3nBDVvf!HXq8R3~&sj10=eaVaKfME~#GYV=Kr?j9DG|jU>ZUsXu zx3(tfiwaFVeE#TPDm-*!U&c1+a}S9L;rs;3B<$tre{c!2Ba&&rtoEy1hO@47%}4Ba zb4o=GyuVJn>aI*q8E zv4K_Zw$sHLCoR+)|A+W{Fp>hS4oNV~C17O;FzqN#FHbuF))s`t;5+!nVpnc&vM>=F z8RreKN-ng#<`s0;cs0TLjvOVQI@Dxj6LjL}$|f;+)1Ua? z;=4nK?j2hhkcuY3JPr6syf&?VsO^T>2%{an1JCcQjCs`aIDf_X$Bz1AwFUdq@A>`@ z4y}ys$NAsK!uU?|fGb&dMDvY zGV@;Ds_H?tAfpR0NsFG`tW_s@@wx=s*sqj2qis+{X~0Q{x4=y1I;v80?)SdiMqt z2WYkBE(N2fhw9Hq!pjCEb&^lt1&vjTt`uGC5q_6&b$*HrXje9Hx9qWTZ|Ip-sA@ql zOXYf2Lz*6MF-ew0`n5mflB1p=QMHzQIl-i zWBd5_^^WeP3Z3OLU{$mG%oXa#U3LZ3vnNHb|4MreGbZ*{JI$Z%kkyMN?{N^Z1u7$Y>`iB;1VmfY87>Y-=J@_vId!d}nKB?%H9LG0x>)2yAAL*~ z$m4wk$9|}$Y#tZ#4t;Jy8d^JgoV{+KW@dhyqCX$hsb%SxMfgb@5S+D-=u)YAew7*66EP*#1*NQN>) z*USJNS31=A$GJMWxsMSP;3plrI4pKZ%*FZpTyZ%}T@6AB1upx5;#k;3mV;Bvg^gEp ztbT3a&})qaOv@YZGA1?VU>HeJW*-TKZGhUT{88>kJfv5lk(iH}^U>eRX#{q(Nl8FzjoSo~1Wn@mpM0fz6HW^>9TJu!6u`e6Cf(ln=v|4-Kj$8Qp zUn}b_J-Fv|%OyurcB_;Z&cO^KSLC2Pz!iboxx&Qg-~{9uM^a-8iOq|s76}A59YZLL zeueQf_Aw$BeLM-#=P7|S$pi%%O0}|p8KVo^D9=YsRGyZx;N{&@jHV#N%(U*w@iT*h zD}b!I6=d*Jjq9QR8iS$dLHJnA=ix7GkmryR|Kvl@l|UJi1saiOr0A$nSiX-hh&rk% zH+}=hqzCQz?+tW(s|Wxa4=c}h!=<4zc*n||n*z@5`s9X^YwTD0uY9==;#fc|E`62< z?GwL$wb)cKLxcxd%!;5a!0X)Vkj-M)L^pz4mFdVaMUgNOPP^ZbnE#Lwc- z1;v;M?UhnFCGNO8MYBO&MlStm@OA#?NC_2vhr+~9!0d|@raDs<#Ip~9)gS`pwmDSl z)89bETc-c8BngYD zO8z)jt>oxg3XnRXe#g62!6tBT6>cTgK&+3$C|mjKyG4Kv+EIm(?rxvFYZ@>26gj;< zw|Z6YT~n&an*V*Xx?ggku#doM*de>zC4~E_ucLkY?|emKwvedgzAJK9tZffIj^O%N zVAI3(oztNKv$#|Ho;cUUkjvzMB&kS>N@_E(6F8*v%n)}y%?3U=n6~r;$YL$8%905W zS_Kf(XA4jtlQZY2>l3*D7%b#q7Nz^!ZQF6R#`$r)-ZTabU=OA{TW1JO(ZL+Mr(nWY z1pJ6w$?^n+6cH>EhJvU>0lu0`kxo?lZV##rfn9`*Cp-hD*wy={gp4o`5S$SlQB*T*UhLRiZCr8)c9rZp?z-{$TJt_YU8!ZW>LH~f~%nbElk9CW)g%%fHO-*jiXWFTq z2>Zu|0a$PrXUL6t1oN%imv`9BUTf63>4 zM%vum`;LCj7hHruX$w~+rz*%**B2hzWZGEHgYYFv$L&1X6B#3uPzhim z;4Z$mxN$@O#wAkB@B5M+YjU!`3miY@k^$o*GPFaI@<_a^QyyP#_;_!;Urmsmy4{k zih80}VxoI2+6c$D{Cl|mmCvBLyw2z{4BUwZI=0VxW7D>C3tx7T5P9e|+8Z1B5X*puQpb@fGUA&TjKM zDG#(vS`W$;^lcoMZx9?jRD!8No1FXA9k}tleon*eMS_v+?8mBvoxki^5^M}1MlN1o z{mu14n-O3j8Se+DiO-~`k_?@dMD#uDJ(u)YmSi1y7)QK@&$TQM=`Vt!6)-qD;1hYN zV*LeQPVUsuay0XlmNX1x8-mw#hmmx1Pm%KRA7C3@jzT-$eF-~+UGWM|fZpK(z0A2; zCGx+>!3Fi%OBIl-DvK3(w|V`5TK(L~8t1rAx=WSG4Bi^8wByEIV?9}i5%~j<{OQ4m zsZ;d7JSbOz`tfvz+COG%fdHc3DX)G)Wvh=}bMNxxn0KcmCwE3~+;V^x>G z54XHHBF@epO)4HP!y$Qowgl~pB&d9)M*>E4FyU-sB%6N$Z>R|9dKnWDU+{3Thm7E` z+Tofv=l#91S2Bf7E?5t?aVXPJMC%o&F`!*!vu-03IgiUD$Ox@#A5Q-na~Bk6SyoMg zjS{U4#j0g)@b(G?kU9^#+=s>LGRj#|V<$14`O-VK$laEu={ZVbHJy=R+VVCrZm*&A zpn>GC74$Q9muCWZfBeC_HMtMl2xF-*fHs92PdBMNi;=11R*>c0NY;0(ofwRYaEEP- zXiL-CCX9NxettX;v8dN*Ym4AN43!2WM_WP0)GG@>o{9Z1bqG$jp9d3hK*vq>Dk(NA zGU5O?J~w;B3p-ZdpL;(=ml8w~6SiUf2QcBdyO5f-$9jQ?j_o{%XXb=w$H`wBp1v%$YA!YBI4nyqM^Hu}%;)$uH+m%fJbDtm@u#P1NdE4ZkP2~a-Xw~WqKqth zbdJ_OAz|F#o&}u(zV}&I5}n>xs;Du7eml?54ZDf~NK$|8b!hd}MR#z3d-G&@3B3&m zd){N}Rb|!v*P${O@{{FCHiIet&rV#Ocj; zI&_7jJ6q2wA!;xCZqH>`JBA$#>2eCPegA6Of7_nUC^*?Qa(ekJ_`0)6{PlK2Bhxnk zsm+|)!uHY)#_dy4DRJodrg;jML@ap!|9yA>7Fw%J197iRarx!g$K}%q?#^ib2I3fR z2P1&oxoz-tl`FJ)-24F}nB@JpwP~FJUk&Cm#Efn2A9lEENdr+P_YWYL z&QxNTr|N5lb?1c-?Hy3(QrqMN?Ff4Cy+bggZ*F4h)pzzYwu9Sb)j0jt?VnX^rgv1J zX>hD%Y?y#AOruJXxO7yk9Ioo=t@SkPg*%ujZh`GFkzvfevh4`83Ff4j{-wf(JsdE~ zY@so-z05OoW!~xEevTPJqUCYoZ;O3l{onfG&FS-VbRO|6fb7yu>ux5aRKti@1bdO! zdw`n!x10-`#%DJ4@`VemuW@%0XtB3)3TVE^yy+Y-z&2O)U;7U$Mj&1OLkf|;7R7<^ zK!{I0InYC*CS}!5fj6&y54*6^p||Uoc%^ScZRbqSZRWh?O@wV+#H|Zf)sM4s(1(=V z%yXTq`5#$*0a9s(5wOmsAq&qZ@(Uj%U7a;SW5?R`t=1nfZdRH>u01~lx6T*J=PsWo znP&xAE$45i7K|1@<6i@4)F@|Em(kn>RiHTUs-AI=J8p@BvF#^kYNtT!3G?Z z4Gk9-k2y%aN-|5)$A<>NbJIP4w#m;b-N9{^gUP zrrkN2)8YNbdf5MQ%W(w5!Ryb@@&|4 zg!ar;P$h4^(EA~S`Gyh&8WZ*IGE^41?=iqWS?d;2+ZW%1GAWK(+=M_ahQ}HR^?Bq7 zfahz;%lRNfZ%8DmFRE(or4sGYvIzonvaCgI>*JoG3BazgoLw3vNAIuz#o^+&A4Sx# z);q1xKqzqD3-FDd5g5kxj1SLq?nudk01ta{0cjB4N9ks3Ia=-pOWLo`PSMc=$oiRx z$;JRmSpFD1>HaCXc-Px#Xbd#C(+pfc!-5^5u6WW7Q)_U;%V0(?W2)H|#=S1^$g{Jw z2S};&e5)>#6ivMjvWtM!V472_*XPGq{<35SHqp|^7eH|C_9Ib+Se$10d^Qw;`rSa7 z`f5n`9G;|1hfZw=jW^Kku32Xr00UU&2lal%zg#+g(A8YI})ab5?+b(d!cA)NF`QS{&dKAUPDcnTh-d#8*?rMJf zs z@P8wi`o>2r=f3$15(QydK zAC&)qC6%Hyh^f$~z;KjVsWPeHx~9MI#oh50no!x=>x0#}t3-6ZAO*F@ejo@JwIik9 zxf;g_wtjZBKP^4BIRh{je`X-Y8rG=~Ew`&Cbg1yPp$(?5;uI4!-p*&1cnvpOYnu&w zxQc`%(?`8$y9*nGzLqXiO&@))r;E7)vuu>r;w0J zl#Oq~d2qt5Lui_Ly_0Ob7`s>Y0lTbNy-75lCVO>!vNc&hd$Pi(EIplQc*DRJdq8wx z=uC*}XVZ|8gQk*L&KU&(fliClM?O7Q;o*NL!Wy98&cHW^$%BZB-)`om8q0Pa6@+jq z;8A54cVstuqSaIt88F8Ly-g3A*ulM|Rl;MhR<3B+{#IA~enXFxG(elvf!aBOB!0uE z9BV}Syom}Stv}v_E}F+Z-1usms9gkX}SNRCCaz!sijIUxWdPA^*#Pbh-;7xb|9%by>Z9atMpzy;q|g{*cQ|vB z;zYa%A2q4<&&l<7hpfKS)Yq%D&PTh${gODMAMscy2b0l0pW_g$pB{;_sy{WgBP+dq zeX9FHx!v}UxnKK( z#||bHXZsTR@t8t@$z=v%&mP^0usnL^b+JebG8~Ut1i*?3jNF6jS+RBD65T(`TY)xAT-*vrnn;rkP} z@b4dX%9ARfS^wa%+41Pdk8wXGsywpE8=tfucphAcZ`Fkg3j8r<0dUR)X7Mu)=}+Cr z^e(^}-J7c#$3?vw>p*l4fp+d$(XjS(|a(Ly;qVP`>_ zMlK$!N`ZNF@h?pp*W2GsFU{U5V<-(X$bAW+4BZ91pyimcQN9YZnh0D82d$s3{~&vI#Cw|cxP(n&z^CMo8q_+$K7J7hiq?j;h`(9S6s8@gPR9J~{REih~1X8ojJ zUcc2!fu7BsUhepYCB7_;(bfK40dqUmVtDjH-XT9c2Ce&i^HY}5g{QWjwR8eCqg$sc z-Oe#VjhF}SPf~UZ%$jpmlSxmGQqm+6hmJ}7!M4?M+cKk1bmM#to8cVwCNRXZQ)Z}^F4^+HtY_) zU34!J^GI^(uxR3M&cG-?Pd z>uu&Zkf^#L|KwBq1Nk>-X%-|Z5xmoHeZNDEIUos|w|c|q>nx|cQTEkGqoq5tcJHcA zM=Du^uV6%p$vYb2y7lP$BN_Q9-$Co@M#H z6}#fT!~liMV}+tMLq4|`jU=`2$)k=`4xC)rWKwPq3p_KL4{#mZb@}8LF>aMO?l|dI zxkd9S(%oQ>i-U^&OTWDChWppOMed0SeMlBo`yM6lVeO0g)5DW={mLqZzAgDU7xaWyCZO?vMAMho6 zAMF^g=V2}(QZ#)x)~2h50)lLs9yahqh{6}DUhr8iWrVIABf6AY>Frd6w@tS#@fqc# zNR*@94XxXtS=gryy20k7yl5n}lgDJ&`7km3{M*^UGZk$*waD?YE*7F}!S~67;NP7R zcNiHzsX9-X-~PPs^~md-O27Z=&oSO!s(Lv0F4qZs*m_nYhimoW5l{1Y-mOfBuX*sB zwVys}i9(8sz6FlDz&*X)apmcEqw(vosBN0PFWMlEL*b1&L}b!8wL9(mMJyZsP)tS^ zI!%WNMUbG<(pJw0r(N5tQl#|!g-MKC9PH0^?XDuFX% zH__UWI&Js@LvZfi;H%*-=bgfRT{0o2RjHzzjErKzrSE(djt(7SM?NP5zC3?l1+UR{ zcid5^&o4Z?giQkn3R-TEiu?7n;Vy1xiR0u1|IiS zDCCriNOZu0S^COaJP{)Wr&j11tbEz8iqu%IT}{cfFVymB%w=9Z11onQ=&$m2Hu6*w z;6i;R=6Ui{y#GFF{K9ic*L$?q2hJ8#@#eyrYnxPw)MzVC+w}d@Win0O5e-}SJ{L4# zjo~E%W3?e5Bain^WhNq*wRW7V%_7mO#@FLdg%xPiLV<5aK(E|>{SqkyKk%P^ss4$D zHL{vT_?v5=+GrsR&jY0?nuOoX_<{gUUX9^v zlsgL_5E|b%YR4AvG$;NP1T}V{Ldo9pO8V?W0ncZGV^F~4HmG2K17&F;o*;*)R-YFL z0ww8n)*16l#VRiyzu^|tiuxtRYbuo!$|4aCdM6rHzZg5~Nw4_FZKm>X`e?V1>D*Ma zSBXBto%*OI!J2+QZ(~(00$GqtrD&&h`ifsLOdYW=vgrSNXqggir(ZLs15~*owG4$L zLRID4@s{3)p|#a;^$MQb+7D_>RWIJ!^Jz-@z86M9x7S<>e9WJRmZn=y%$p_J=#Odd zVIK{c(y-^TMt(R=DtIJvZb7(fSX=%sFhhQERkKxL zt#U41>jXNg19YNwdBI%4b}0SNTCr?IMLQ>On)1H=6?gZ;ZiF8vD% z)HtfeO{C(F)Jt8aXdA*-rs@s~V_U%Kt95J=oZaD6I7#^bo=Bk_bHa-gu2+yo8 z&#gCZ5|-DS9GSXkAd%bzFUW|_`-}}q&>d6XBc5?Ax@6& z&xYUpx)&ygq;Tj}bMhj-u1j6RGk%GdVqUcf^L$-tqc~)Ns&oOh=MImB5mR{up;H|BQZ|<$kI(cz+}9*Bu2f_ z&xB?vXRp0w*ndTBNa@Af#5<=~1Ne&-%w#1bh@in`G9y#ZW zZ{Cim>IGR=Q)435U}a@9{P(v5vmzrmJfQ8F9<9#DzB%`ZjM@Me=)a5D-$628}RV9MX!1E;T{F=@H)L<-rwDDs&$@y#23eDvt2JbRz3 z(ul~q4e>3B5tph*?`yl7GMmu%c`hC7iLi5QVsrKuP$b~~t3>i925;#a!@cAM)-(8|~%uH4wlgsTIK z*bD5-Va|aIh@liBGAnVEl?0t5okp^sJL$#Jl^8F^Nt8@&?6f!b*%CWCX%K%Ij~6j- zy|y!8K%@pa)3xVENphwYzTaE@7>7uzl~1{V`bgrt3A!mBr8S8FdMUzxH)<<6s>cK)>0x zNL@-76Z9I*Qy5fl)#A_oWv#`cy> zXvuY_pv5|0zqah(61wHM+N$y>_BSo*M1gcsoN>k46*?A@77%3_lS0_k^znZonM+si z0g4ITTb$P8%QqOorcA$3={>yVl0waoe-xR8doa+LqYnJU;QONxCn)(pFn#VB#Kd9Y+|#nS^a4rkKky78=sj6u7X}Z z$`m>Rv#Ew;%bB%6>icS>G$jvzQvBl); zsLvBayi|cpMng>&Q(QC+>EE$kRaLv=E4#}=hU zx_Zr+=8=oo16Z?wCVP<6HQY^Kv0rLD%iT^TUMbN&p+P3|-D#8qBh)D^I&3+O+}rIZL*ABOfPsCv## zX44lfXyqNn2kqj zj;BOP$%k%t?bS?r4=LOyzWn2|h0`x(0yXKmY;kr`U}VLHUcpdfWa{lHf(g0^*hY1; zeH6M>@lV#nyGzui)K6(E-9*kX%6I8t#y5>JiI_9TJb>w#HWSn3*t0kjn&eDByp#i1 zVH2KLKyiQ?n`Ie=PQQ~~OFTve6F1IdJpDKrVgY1^h4}ajZ-hbF`_OTG0>wX#aOqg4&*7EtS2(W!Gwnp zsCKfxz{41YWDcYj=0(;SoTM*Yc-@Gt$MvMyf8RiRDrD9;;N$A+%xr>fhbzb?rmujR zIHOtRJbl%-3aPIbT7$pA@4W9vo`Q7i2i&7^bI3W)A&-| znco3nrWM<%{fbmkBXlJ*zrVZ+I12=LPtF;}JIE1t>Am(B9(DdB_?S`T7-vdMApJ8o zP-yJeQA2dJ7H<&FqjI`}Q|?IZJx>>QG?ICln$d%!JXa8B`7=vvIo&)=n4Odja;ZRm zm1D09LWSz|9|70Pf2eV z4x_&)n6tLXwl6(6Kcu*xRh~fQ!ML|}dbU^&JRBNO3zdDen>FibaLw=9-$WM(A~zVm z2p-FmO{gi5Oj>xSP(qvdKL-ztyjvPv8dOxhag5mUV_ZssVq*OX0^`12`=8%jD9}wk zGCwx?YY#U^$`y_tbciTq_`$1+&qCJPAF4p53Mgc!T!SjEex}>Tu{ih@o%LoC{$D@? z*&t5gdD$KRgO>Fw!Iuyu*fBWN3^~fR>D1$Py&V-o`2TTYJpi;~o8q`#zP+e(0d61$HQ|Hixd8JNkL7y9)WU@oXhdpAN+u-r)40=)&k{|Uqu=pjd)r$lE~ zeVSaauDTwCto()%QKYdOsHav4l-G{twO?X= zAq3FSm55r#9sMsff0)J%Lihm|IT6sI(AEeQ&O3Ilc{W;~7-H?W`VVCtlBAoiQZ`qf zom;kUoaX_~LcVbIVcrKX&Znn%J`uP5-}kteJ+C=`?Bnn;8tpFHl7;ZWNKl{xxuH$t zoj3`{D0p>-Hl$W8ry!tka)kZ z?UrP9Y1r54>GXvY209jJqWkF>mFB8O zCb253#Ok?Jir06$Am`u-NVYnPz~ObcU8>^r^9AU#|G`xVgms-8{=yVcXk{6`EMGm@$g_MtQpWtD zVypYtVFPGxW26wBy?n(j^FFB$P8LIx1$vO&t#JF`JdJ4=!{|c0iNL3ifJ0nsq*lBp zvHsMQ~TXz67pah9A!w`AYQt*SgEe z*|gW9MlE~(<9Dl#Ml=E_HioS`yNqYr`8_Yd=_ zTi`zq|F=w3VZzL;8!5CItA`Xk9-4Ql#D4#hjco)2Vz5U3;qOpxF4UKeTMx;dyBv0V z5-P<#oS2bY^09+H*5LHXZj5p}pQuP>g>!lTPoDg~(9ZO(o(>%be=nv7&K{C|^0L zbNxHXtz#Z-LmqEQ^TsRIoyHf}1>(7uP6BX^9(fIbb1+Qz&q1}rt-RjZN1b_j`XZl1 zldh|Yz`)2uqap3`F?xVa1t1A(&KgDa-$&7p9yUm~tG4Wo8?Y%;H5*(Zu_>yHxIfJZ zOM1>%mTH^^OA>-q&hc7sd&>-@u&~l+V&)h_kqsH<4YUpA%_NqgV!XWF5HKER;+|5Af)>C z(zz3+U_l86Eg$GPMimBlU|_GSWILjQT13k1YsqBV2LTAPR#lLJ3)Rz(0tL zV8g4R+BMW1pFwWSh&Z7HjrE=uSmCc+@@R=)U%#7ZD9e9mtUbwxq|_?49clJ9khMR{ z;48nUjaano8?y}IYf+WQkpDyPCoK@>?MN6PmWLSOV2Fdk-6jeD+Q(zeK4 zGa9{yjPsgGQF6OwzTBVl_v1fIuGRpJb8?wS?P)5GiywAIKh^8TCyZaRWC1wMG&pdH zWO_EJ{EE9gJ=`+dkaYTN=1#Hk69}o6QWs5y#BI|MC0gJg!Ds6dJq^R0CJ6o=`mZQN z5WvKGl~;#GecU(M`tr^B4kfNQUj0*hazaKDbs$L-s>CkhI9B7Usw(`uu;|h!mf`tJ z6)8=AyRzv8;jxve{L-i63R4}H;A^(&1}w0BsqUl>Xd8tdNYva=^f4P)$sg3FNKhD_ zm9dD`q%$^2Omy1veSQDB3~cYsnNy|NU7w@?W_~^&n-JVrmHkp5t0b~_EscQW**bde zJb8%(?J+w-xOYL}(5@PS@E7~PvoA^)a7Sn*{O&44i-BXxAosJZ@y$6aQ#9p0(7>?zxdp zb$M#)w4wMPlF-Ne0;ty@Ut2fR!S9)mIX2D0K*S|-=;)AY=jYh2*r1f{?-qJ)h6a#d zXEDx23*J?B9Cbd>yZq{Wo4UiN00uCT@gveQ?7&8I?=}mJ8`u|FB}IMWZ9b5_;*<0! zLkwGI>sHT@cT2IU_%9d#&Vk0X*{@XvewR0Bd=k*9%zy~i=Q2C za^bfX6+VbrnW6L%ou7sOh4@D|q3-}=-?Jp|bPkvx*t$%6ukv};mOlG;@v2%>Fwud= zhWtFrB8n&;Vo#Z?Wo9PM2dFw2QdS}O4%U;p6KdsCO&iVuUkYDV7LOGRRDl@@q8vdLL?#6*9 zi$0k8g7^dCuL8OWN*xko1`E9&a@~NwIy@fj z_&Sgr*EiCAQ+s3fJUt`0H*ywqdLgcBKC~8TdfyX81zjvZ-HW$5Cj^Vs?~Uv(jPl{ac1H0JNCjqAjwJ%IkQ4j zXW{A|<=@?L4>-Lq9FsIf4;W?P+)sSoUo73Uuy+5T2JF2bZVW1XcB^wC z@o@fy>v*vjI2{}LbBmOSHfk*Rh~$<57FqbK<_W$WUnN;bwu6$n_p;&rwr z_sb;bnmq)B$^PJW1+HGC)%ix~RbGFE1tl2z5;DdK>5S(H6rW9dz2FNjf=c- z!3gmD5HGng8}hU6P8PVUd+h`Wd;*N^g6TUcq<+IDzFcjncRA3m188f2+Ea$&lH;|O zgVq~5iQBtAUjaS0owmg~($>uEkp0(o!m#zxa#Bdv{0Qc5;5r3551*ls-0Y4+y`2m#J)N&F_*rJ^ks>vbq{R1D77gA(!piBw$)>R)>rZ;hB8**tNxi?{G zc9+d7%esyg45j9|87zUTKYM9Ye@WXYivp-=SK~V;{sEZ)sHFD^Zh#qvfi|bW(JmVi zwmaU8fF4S6JK5r3s@J68>(9p4Jy^Re+plgbJf_pyo{Hu-=;p*5&b<9 zpm(tX&yD6B`pW_Wfa{Vu?_xIsFtUKR9vrX8{LF!H>o*eWZ_wlvhSQt2m4`g{xVoOs z0M@ZJTarZPW*EBuyw>b@PRND;!ea1zcmI2IA0Dmww#!tn>98dYz%Wb}J3+2y0Hqdm z6Ap?o@+y7(rE|q~1uGA}F4Xki$YOcti=+SxKgF{t&>;*!j}-e#`Jm4fpgzOVo;k$P zxs{n;hu^@oD4LNH$g`ikI#zxVKY9)5NcIetSLwY#w;^uC&&KAicb^uz1*#Io!uzdM zrc+8JGa@eNAXj5 zrv%9-)u9N?U;sZgn$Xg<-?W+QMb}X8eWVqqu)b1P5Wrtr>ON>6?QJoMTr3gxqHx21 z8dgx+&YH{0$@k{;+#TA?wrM*zJ^iKMkOKBL2&dRIIlcY){$5yCULM6;xebFp8~Ne! zroeaz>VmcLlkL08q6JjDkbwx$kh_PJTD=uurq}0b2uwIlQo!k>jRY9p^?XrK) zJ7(iTSFL%@?MoPZO|D7fNRG9q2Uh&(Sj4X%BX4hkl(z_zmrx9}2F$puS0tkZ*A|HN zsw<)c?Y*oUEU~@bDQ_#n6*L5UUdn2B7=3fjhJu4{fj(B2!{nlnoekAxjoqa%(zo!h z2jpPn(u|ttuDD&Mka+&GmP9-$__@cWXVT|o*!yEQUF)uUG7VMRQEkZcouo1{6atuP zOKf<&ZpbY>U{yG=LU<_Tqe~0MxWNjeDV+5U6I<)1&D@oK`AZAp{J=Qe&2?@-ZiR1o zk!fx*Yhcp!`$kXz84Mk& zN9$72ah}PY&Fl{|>-`zfYl+RjQoT!H#8;9%qXw;Lo4H}@QNoe2L&q#!Yr*p9-11Lj z2j^+j4L6~k&e64%m6covXlCP^j+(Yt%eg$q%og3gAkdigE#|{4JwP5jeX0~{r^_or z(D#;0+$Rnjm5%x}2F}ylN+}tByBqtCb=xxc9Rs9JX})Qou5f*P9-c>$Tg_A_kHZbQ z5#OmdraOx*FN$xmI)$^jx_iZO>?xe?y$KArx%Oo>YLOtU&C(D`kIqgJKQ^-J*68+h0l&GH*j7 zK_gFEVvF>XuJ?d%{YRxopCVKPU-*D>k*3zDraG*sHk%BbzXV)40{1wa7HJjTL#CeM z`k{pzr$E7vW%-7WJo)6CsFD76^aO7*+{cBLcwNr$9iW#XM0zu*IJ_}xV!fQ|E>8)1 z8vRS`8-s3Kh%rCphKlv9^9YSucC-k6Q!^c3iWBw#aLYF@ys4zqwuu)Xr7In*L|bv8 z6PcOZeV|1}pl(+*vYNXOLl-%F#z{_%)#>UMhtIz&{?Q?GgmHOUIxg|Gk_;^uau!bS zET8ULrNRl@fZPtyzSjzX812*2!N?2H7F*)2;Dm1`M^#=T<2w&rV+L@QRSLqt+s-ak z*s)|fVy)eLW;;j7dbcv6gdzcvOGA#3`RB$e0-p$^2Ff3qohNG)TP^`WK?&;QXdCK( z-MxF@qYYW=$))rmc-e?GEX6(?72$g z^h$xi5T`9?)JdQe>Qg9`A4sRU{|<1EjyGw3=;@Go2sR+^NK8?!lJ}v}^GSt?Plbnd zkOtj^3unxK;i^Kh!Hh2)T5r{i^zT`U)Cp$qyV&f3Dv4!9@S}qlNqZs|%>X;zdFdUY zGjoXM(|Ld23PySmDArYxs8|dpg2+K(f6l}n%qF`$UER;j3w+$rz(H&z8)B#xYI zN*$gsfOpoV{v;mZ3_u)&%gM++=lLNAu)abmPrsGC7|BWtLV!EUz$(}AX`E0^rvSB> z3=H$Mj||+Rt#XmY~cU zyo(Zpzcm7r1*t+BkO8MDrb8`|qooX^?p#TffMcjD&4SpaxK`kIz<i}e(UMDSCKOs)*&a;|KIgA3mo!6S7z_GlAi@=1f7f%_H_2*GTANX|w3*6iLgcc0h>pYY zFI_Ww_86VSE_Auwg=j`oZszG~d5~Er^JYkX=>U5cJWa~RTJB#$yv>KU zCH;Zujo*yNjxFP_pmW=^@pkFaoTu7eeuau1Go%b}1E5|72hR|gST8mE@w{XeAa)V8 z9hsIBpSMB$P$x+Nu6lv+w|ZZvjn4EP^{*oA_d|?ZONMS!+gkft@%3(Jo&%}FM#XM} zl*FHc&yeU^A9Mp{0Uf&FAzCo7z#bg2b?O$dF5|LrVCKyS@NSyI{BSh;6fBAB;()Vu ziHY4Bmyf%l?FRnM@^vnN+m1P$KhFT-59$vhFjJnFFK;*Eq(@-KPR1LMlhLebI1^u6 z^E{2ZvlWI`>?a~Xk}DjYBI-9?J@Y25zQTA?E%BU}(F)+cXl<=GWMX<$>l=@rAJdBw zSVm@x^<+ERIotd{uHFJF%AgAvo?SYmLl6n+MpAkeL=*(1krbpsx?@)XDG^XwN+cvC zq#GrbRFsCLL%J4_*zdvjegFSE-*XOdc6nyz&Ye4V?!9y4?w7ShnT5_yKjBT>{4Ct3 z^}6K+U-@hZ?U!{RDMuDX|9d=;d$yG)Zs(nE>6z6FrlUvn)@*xio-l3Bw6>!77{*>p9#QNd8GxN-@m^= z^8k^oVq1p20w@W^W2Ng&nFV5IkJHimPp%|N2K#a|nC3K_XBu(ChtBmv;yx=@3>Npz z)$aLFp%r~1$C;o_<#(YpLU&BuyFOYnCLGLzxss%Rj(y4!iKgaxb{jHN$16_~TxCIE?Gv;CNPEdTel~Y{8l7olEX^ z2Z~V!i|SL+hXZH^fa<}cChnvKO_OqE1MwF#KRZ7=!y4aO5`+8W_Vz;T=dDkG#WUus ze+1BH1J7Itl^&K#CAj$8*4}jq6p_c8^w_jbD(E@2=?xT&6_dS-=@grJS1qOye|DcCO6VzApN6i(3JCE-}d~|Sh z(_r9UFzj$7^3#7b_g8ozR_lCaE2K~i@#l}=Uw69X21e7??e zbU+R7Gwms(@I_>#2(d>=TLX8I-qABXdCd>H#&*>$b>yey5U*(S1tQ;M0s5LJ0|A)& z{9u$6c3Cwr2M3iK<~Y2}u#8<0hiBu0GZN~X(t3Kz27Zd(pnOT4Ihf_&(S-w)TZFZv zPV`P?kBUB6qdr%oSNZ#`;SfB5aKz8AetVV(7fyiCNf?!LinIwV0om8E=9eb^2wp%T zp@1H!#aZCWu|?UDLf0a2(18Pnk}O`Hdp&>j?spXJrE~}xqR2oM=Z?n+)tG{tJQUt> z+eHd+K(~evHta@lz#tfutb`(8F9HA01;W7y4k|JU&wr$_6-f`h4}Ja5V%O{iEZkGS z|Czas3!vlfKUVa#>i{A4Jf}juMG8$w`u}|m85?jw&YOxLXdLKG=xl;;kLUxe$WLaw z!RBbi=o_(gp)df!bJ>Ov`Zr+|I~YpynV*n$+WrkaNsX2oOsg0SKHXzZ$b{vP+Z=x{Ir`MtIOV|2VU^&x#2;jLtgz9jXe zV~GaklrBLbM$;jIcad9>Dl8{YzX>ah52K}5G6Mo8XTCZYB6?2~U0NX9L%>$Ef}vuW zhr)^nE2ND8=ob|K&_s{wqkZ9etn>*ENoAKeyYS2J`!ayjFT?uvrWvej2Mj{qe@p+o zc?fRUVy?0N{~f%b1UR_=X$iH1+%dWi=T|70la($%AfT_HJS?=J|F8pEL@3cPH!v#I z2|E4)jS@EtpEcRveN&Z+Cpk9>TV%<&4m13Yup?rH9NUbDv4aUrPG88O0A!RhROmB4 z?*oTft-Qaa+}oduX1mu?KPgUEOtkQ4kU^Yohx_K;`J2?G}GRNdr1|7DvN8V;8Z zHQ^z?hfLucYv>7YPuwN;bZC8CjRRf(FvILH(F$*G-~`9V{~&;+5IjvzoF+u&@JG0}L{A+6bp{Gl3#GX-(PAt-_0IX7=yxpKOgTu1tmMRn9 z=OuzGgs#Iyj+!{(+0VBBes!l=gYq2%Dq|q2YuGxyC@umMp)oMpzc)|2W>P*Q91eg; zGl)yUqJCbb>HhpMn(kqpa=hiDg)T%8cSunCue8b)H0eM{vFmjuh4}xE3!u&ZZwoY6&Mlx2dK@faP9N)XDmr52w4v z(A693dptzsF%)uA{5bu{YV~Odp~uRXbRZ$&*QYLPA9D zlhdoNi4z0&-omSF0vw*0iIO0eiJ$!bV{f1_#d!X^;M7T8?dBrcmnK?Nq*;YfKs+B_ z#L`89PZ0^uZE%1Q8)!d#eq&_o?WFao#3XO)x0TAB8FgF~3)=$`1_5voTGFNXKt&4% z?O4PMk~X%=9rWVYcpg+w$=R`7!#5KXM1xt(y)DWU@&0mpMglJYS@ ztS~H{5d7|5upRKoo8Qnk3|Kq5NY$i)iAxoxg_k=Qhm5QCODdAIw&< zb%cfmuvJR%>1#IQj~a|)Ns1aQ;#nt9g~L*=a#RFka_)8pORpfU%k0cm9uxdz12^08 z+Rlu3j)UyprE}pO1^vtc4fqHnQdUz+Z9GEA4-p#E9FWqN;2pjJ<>k{soS2Gb9b=rp zx0JjiuTAiEvtWT1FcGJZD1b7eLD@);W^tYGxAuO1C{9V}2y(hj%1ZW3d+%ZF`?Hb+ z&raho)W2__&!LQ5dm)vACNv^A&^mUG_jYI4Y3r$VQ!D=+xo*h1#qw&BrtK>w>ac{6 z;=LIi*kfs_6s*Ev>+XFx&nmO!&4n+Lj-@0V?Zei{PS#xRKT%t9q>DfPExzQ45rto{XbFT6)_UkE7k-ZPED2lN-uqN)LV!pelG@M@{)$fE^qJ_h|!CQ}3O*sz8=Iw5+z;f&RQMxc~}`3mh8Gv|5c5rg=D zrqI1zv?~-a7JtY41nHh0F|cBZpFJ#GvwPmQ;pJoi0?@cwP`>t5Xp33Akvb49vH@4I zSI8EYYP9hp4Dg6cU=iXtuDc|?K92w4*@d`m>x#_73SeekJc5Q<9@DQ5@}*F>h*84< zFI@;{`DmS3mae92D7nS>Uuk>kb>|`=O=Q^2ik6tq4;AG5;qXi(GJBt?#GZPpWIjHb zY^=9hv-lRB7tSd#HCCdVR>cJEYS`@t+ZSoQ|LmVkr@hl$WM6BPK#n9fl&l}LPo zH6Oh^wzFl*XViOv+To1b+Kn1DvuqMoEL=xPTS|OhNC0rxo*v^$_?>_ z?#rWCn-FmtA9F=}>ok8=>C3#aWLnhci~+d1L8HxtUqqGFFDRUw5JuRR_4EE)6kkTQ zIngsSERQPasdW!kR}_=Vfz|xEZol8eboXuWS2M+@MlO)(y`i68pDe6TSnroh5|X9q z5Y`&K@E8Hwrij{dm}|D_Be8kapg%-g=an&Kb{IQgrY?hvUnra6C%8?1{DH~c$w62z zXq#z{F@g^(_qFuctVTvTx%qajE)V@VytZ{@#k+gmTLwq&Iphwi9BaW!9{2GF4V{mA zS2jrzDd1|r!Ltw6rz{e?{`{BEbVKmcFDti_DZ!Q>1BF{8s=)9zORP+E zw^P2L<|1Y>H~vg`=(caxmxue`wABtPWq2Tlf(oStNjC>xU^}gD8oW62#?`*>&`L~d zGI+{|kn=O6(BJGCrT`}__qx0v%k-%2^seBh@xfd%7r%ZDb=DfZeh74HPdqaqLGHiQ zTB6kNvzy6gFflW|&n6TOI3htGe&&D}XHtkE5h=8GZg{hC76He9W(+6P^`F~p(I#xX znI|)g;o^d&Ob3DE^e_rlKun2Jnt*4&UITFBPJ^T^Js>3np-BA^vfV@X8@9mY+Bh6_=5zGNMg+%IHPI{h3u7f%jl?bpg3j7i z3SU-dUJg8-TY2b05B#>t+jss*wJ-?5$)4`r(&a@IDI83xB*JMfgs3)!Pw~F|B}#%L zAUy?bRlUui}oiu>UG%9PyysK{Svb9Qpj<4uPzzCl%_6)w9se31t{qeT7}% z2jZ~R3$6w-#0=+XAz9ekOQXb_eV_*i(-aG>uhu)=X3CU*fV<$*VTADY=IJiGh9pq{ z=n_Erj~#YJmzBwB6o?|t*wV`4B(=v$pY*r8*wnrXaeuQ6(N`xt}x1&=$j z57Vu>mu4AZ1Qz>gSN*h+w}Vz2VnlJWcZK}?9;;>j4{!k**s6SWm3hQ%KpKzN_TCtb zIE~U{yY;}t(x&%Xa(ECKZ`gg;SRNg)jyrdzH?sHFyy=H54kEhv;sO1Ne{6d1c9ana z)hn=9NvbXS+C`FxfAoGu^101%<1fjbJhc2G8QUN}q&r^DgtZ>8Enx9(NIIOxi%)eq zV>9jSdM7Dl?3dp~rhCJM0^cefebFXH{p4Wf?4k?x32Th~ff}m_AL$9ar8`y?q$@^p z&lsdvRmBB-bd_rU_+2Iuc;@j9y<({b>B!qHHW_g}(*-xrvo8S{YrN$cNhQbVaAS1x zmoeKvEgFJB)f;A~SncVFAC3AzinNvO4^$b<>1b1rhi(F|NkUiJhyQW7@7M|@~dXcj}!b9opc#_LAD_l|^lr$NS^=>P$fKmzo#QXr5 zivKy}yltZfXZ>e=NGX6@h(5V=^h4~CfawcIc40E5WLUv%XtzO|4tfcIH%5SzEZk#< zvkZq1V*ZK$wL$#ne+J;HpBa{LY|8_lc zo&ZXJxLgQ2R8xS!bI1S{1H@17X5D{QcXq?di4)i231M3vRrJz!b>yDd?_(LMqrv-^ zycGdn;IV#yL8dZs_>j=+!-qW!*kCsS=RA)gp%H5(Ko<(qH$Da*c7#9?I?(hv%0Wc8 zHX8uSY=C1~krkP_O56Q8uOz$eHX%Zr1o7gDq|IHyE0?sQ>JA%|>Gy|d6a{d_Zt}eL zD&_*;jW9@$GQ(szw1Dcg1_oDrxVuU&ClB5jgWv~Y5afyABR9}C@%EE;ZA|%b1(p&7 zvs3td=FmX1KrVzF>TW-`!R{7MzlX;iHh1osQa0|bQ}s4h9w@CG%B~b$3od-C?f)#v z@WSlW{vHxJthd%=DkYi8UvaRlFw>ouRsHy?LBc)O(WAHPK^uR&$fB*qq_wAA%QX2* zFTT19@Zs47W(3skAB~n}%>?mZPjPC&B#2|r9&PQ4o?x;XCl`F@tX=j35V( zoj}o=3kZCU0E7Bas$&jEMXryDjYd&vVmV~o>Ws0!K$aKj0 zRN%LP?AY_x+E7KI#&-{35fnU3(^R)X=7XC}G!>1x`dj<0xhXCB4j12WF3{!#xNYiX zgIDNLyr+#^4DF_us|}TG&6R)>K!FGiVB%dNXn~Ww^dg&j)6!JN2H2PbI($%oUCvt&KGtOQX8YqiYyPq{a%$*kk^`ZhK}@Sj;F8DKYAQurZ_$RT(CT6zJF+!%Zc|=j5vZIuU?)^yD3g{ zVR&lAN7(#gy^yADc-#Cfrg}xQ-3DAdkvfidg-WZg{S|vgvIV7lM2Hf%z1b{;$SQ{# zwQP3NsvjGLv6j|Wi0kpP$T2v0Lb+qo2h^tw75eZm0+JO8JI;6?I|5bI0Q|7)HC3<1 z-q9jU(w`&e%;-^!k$`7M7BfrpsI#Y+>W4GMs-$$o&3NTm+4`Lo+fUzxz@mR|vE*Q> z{HLFx@ZINs*jVhT@x}_zd-|{G5|@i=&b2IuAIj-Gg zM@FkEt809maS}%hR4`dr1SgG`OdZ%nikb+QaoBCdm15I0$>L58y;XQ<{=6sFa(Ak; z`#aj}5O|)3H=p^oz8<>v-~LXh7=6GkygL>=s?#q4UVY1EfC#4d&1B<06T>$?Fkhhy zkmIns)Jj*(NVv#Xs8y?wtw0EQ1|)f0V}&@j?d9gJ=}A+l=rm z93A+es}4InNR9pbbBSDzGs4oKj1;oc76J7GA(k!4ys2!gVl@~NMaaqb}gLF5y z$S9{PEz*~V$8mP9seJGoHAgmEyVc(riU-7L0YUpnOHUQ zBHLvmrp@p|A#yTLQ~_d;Gl^x3G`m6Y5&W1hwtnXYl3UduU%%zScKEM-Xi8{1!)};5 zs_TwUWU^(F(vElBj7zmlrI7D2jD*>U@9|2$$iaxSCPqnEKGL0VFNXir7oc;vVi{(6 zw+hDZ+{8xVyv|m=Nv}CclUGo1SoNExC|I#7MtUW@D~0Rqc*NR#)GR%d+UjY_PXW6o?Mw>mTTXs`ek^PGtq$c15KsyWa z`J5*K!@n+Lj!;;BAltwR%T73Vs z+;X3pF%4%w`XC-Qlr?oDpXi5Wj&c9@?=ULdM#+e>G7p_VreO@#UtucOvO(B!@yl}A zt7fG}ur}V?4ls&&H@vpC%m?7$tCSoBgSslrA}vo4hZs8Rcb<^9dDd?fXdkg$&w#-# z4sa3oy_Q}$EU|$u`0Tjg*HU$RV)Sli%I>h%v)Yw+OS-|SKro58;evfukxRT7z)&nW2vOwx-o{B$IF4-?gc^C+(DajcrPJ{A zw+3GX2#0ugEPWk!&lCScSL#^C|qn)0tzZ5t1 z3+ortCm+^O{E9A6eZ;C!cctvF682CGv%Da65v1~PCpLPea|O(1Wfda*jbO85jklSJ z1jgIzsA&)H!viNFi)I@x704eGz70WoL5RxE^FIB>8=s#e7hqE*Bg{hxnbe3-vpK}? zmf64)PFl%)9-h2emiQ~J2}|L#?&om7EtiQ*-`@+cTq5_WTe1gF>|oRE>8E_bWUeu+ zRXHr<#cN!awLi^EiK7gteD9)|%KqNPdWm87-UbN2B|ybHWMcId>**=|_Bhbjo@$nj zr?V>%8LICc*_6FkuJTbbf~}q_@cl78{tQ{~P(++SJwNt;uzr@)J{k^wJVk&cF$I)*Il)DU{A3wMyYhL}{M-TR}%|)IOt;T(XG}xY=me(w$6o0$tk0{>VXto6u0QkI{M^B{#idy7z2HdSOu1PDouzOA9N)^7 zTNehOKogNfcE}kHpuHT9y0j%JR z9w?wNt9RhpdTALx2O6i=m5nwFcV&dpT7z`3@6ulHRaA?O%1TI56P4fiU`b9jWlP7<1sgu#Y|2#jc{R z!e*zyN@eer#==?SHwF2zMCd2m}@=g#j&tt{>kgJBU86tRx_W#t*jvkSsT*E?{`_D9F} z-w-Hp^%a!oQt^L1T-Af^D6+qbWQAHo58R@h7oiH3ZG?d@xG1Q92$0JM>Lnbc93~r@ zi5_KppV@edY*|^HiVGx22?fc4D(R z+da9vTj9n5zALp0ind5YtO|;HyKHqiFljOnVMXM>=LL~}6w|}Zba{SZ-}fsVx>UY8 zm6j4DtySJIQM9$XV%ect>P_Zd7un06$sz@3-PL8BKYuzl?mHHpaXA~*zy2;ENudBO zd?0drfr+(I9qYW^A(Jt4T(K10cl8amPS9K`L&)_{9uo@-_W*}N^^oPsvVKwuv98qd zzi9#ZfBK;SFglg%Mgsd1YC{} zZlS$%3)jgAA8Jhjc|U{WT;REnMN$@2_o4&O3nUza{m=W|&1&oXk|N}rsI7m$mzZ>m zWJ+fajo1*onV(l6S@U@Lr}NjlzsW0&*=rP!oVoI_1%GaIT&eyk2_FHLU+<1eD$rdV zzK=HIQ~X&G_&feE)_H|~Z8%N z9xWRr^EA>T6gnk6Ydz>Y+NG7*41& zX(m8fwS5lS`h>?}%+qg4$vvyHY;1#We;Jh&Zk%bNeqTY}lCP+xO@GCT*@)s9$ff{2%o3_u7xj~SrdCG4_q9tPAs9}`FoccC z>BHXiVi(vC9qTMcft>?(3Z3w&7|Kc~EoSrO%(+su^EV+Vg{5xgw{l``_b(RuPFaWX zE*}S8Y&1PLaPny#*y3_~bKL_|=T`y@A3J?H_4gwI50p;u264C_v=1mT@m?YY+OoIi zF%9Mu|KT3Y5`Tq*|H_W^tDOouUgd0~z(XY;a}5xqUKwe;EwqY(jRgUT~S9RL!96c58MiTI{s^J%MRLS4JebdZv2&@*Jpyw^cYq$6>COTq3EB zy$hSDiJkJmyR-h|xS|n0d$Wb8k^s@wT^Hhj-F{cSRI~{c*Iv<_Ylrt98k$Mdv5P*< z7w5705`Ll^$b1j@-b86oGse7qLRL)eN;Z5D)Qgq$W9#~C&@%1U=Z&iZXo|<`y7G(Y znaS)s4zr_w)`?Mq5SBG|e(?3d2C+u+8!OJY`}vw#GMuEiZ9GKa-rvtMwXB4r)IG(e z@VQ!MnTi|xYc~SI1Q$HldMJ;#UVkrPBSB4tjNp{UaX8YRD6Bs#E^-j&!14I?c)Lzz z`Lqh-q^B?xHP^`8Z%|Z1$bDc74`{t^JMfrD1^Y~&*CgLrZjK6EaU>v(ha@I(VvGvbV0NygU3bL*5jr0}2+{ zgevZ@56{-GB?=%%NBZ58kWC5!vVzrxP`VXTRq?b90j=i|FZ1e9wjJB_mA9;Z1xS3B z4an=;8D2R}g6Cdg9QF{+8~h(Wf@5iL5pgPjVt^(2p7}#TJeUX{Jp27j%vvjJ(`|(# z&1aNbiBSa{GShaIdNyOP@5ZKsp2C{zBqR|)#0nmwGBSPd*jQ88CdQV$Beu^#jQER; zc1sryJV-u`m%lc1Xg3RicDWDIU1Km32dtpSHI?|7JZ5F831Ownm(-T%?}aTg)W=(L_4c%``i@%@Ul~7}s5RvP!}NB3!=8 z5g@)QrI(fp0snCt4geYf7^9#3~Z%4v+7m=Z{n_`nM8G!Wyy&nKIMVnKrRd>>}+=v3_foGnM}VAGwu17)u2 z2Iq29@B=|#Omd%vS#=G)cMWCD@XmVNviSMCC!b!>q98K4VlZSHqmt4w_w{)*nr$p* zt)$xapzMk9EH3a+^n@c$P8kG7rq!Dp2Ypn0#JoN!>W-i>4N^mgi;5~bSp;3keZ(Fb z=fmLdtc%4hL3*?bJsQf1^7BFn?Gj@MeBncOscfBKmbaDvSFB-o)Q5P9TJ4=!Fo>^5~f zt0hDTZ*hEocTnZj-aWfVA?ThIAu668tViL^CGCAeer9#fPo)H$w25I)o~Mq-7SF10 zc#z{;kRz0`syT7rGM;5XrCY5eSJIs|S&7&Xo!sAFd?gCeX?Jh+cy%6=NQ+{-f880` zj~>*5dms1xh&M6ZAb)>UD{s3c=OCW!313jOXFZvYLkWP7isyOkjyUqGUY*aLXrjKO z7`vpFq0|4&To7z%)D!$0izhGP7FV~V_N4Ij0Xzl1Skbz?ZL2&x5hUhyC{i;zn1M|_`(`)Oi#jH^ zSKCr#iLk56x|mNx1>Db86wEqLMi~Vla8XYJtxUmj2iC|g6Q+e`(AkD!e5v#WtK{k@ zEXd0qfZV}k{)K%!6g|$L{)T{8_*ySjt85sauP3_rR8DO1d6R?8*p&@9=5uT^H%Q=V zc7|gdp>vFIFiVtECV~p99)Cptb1~Z;BJ~@ffjBfd!6kNT>FYJN$FOqovac`QUbXa; z>oI?uqEy!L;XA^ky zb-!AzP3EvMF3SCgTpB5>{U|lw=m9;^klz6xe?xB0eItpUZ|%|#AU6U$&2vfPVye|w z<pu-Td~#5vbP;b(XPMTwc5bESVkRouR1!8`EROZb&Y8KvR$N`9qa?l? zx@f?z%X$24&`M7G6emL^p;mq_yrrlJN3p|WV}-e+T}V2*ay~Ep>L+ASAgOc}9iLdc zjrm{4?shZsiPoa#ykVZ;nd3yv{Hvy3SG=~4aMgLyhGp)}M_<%LNxVF_sf>V2nZA|H!wb*mFD?L*>^*6TSBy#_x$Q!VUOcp#XR-k|k1={!%jr1JfTy3*y^l4;{m(;jQ93f7W7 z>1t`g(|NM~ledda&zohQ3J)*Ix7-v0_?=h@=nC?e7(Y;CAVQre1CG5SUp|4cR4R=$ zdurQX@V01JebRv0hxr^|T($TwQo6Cs3;s(Joz@82#&=_)*&K3f(y%{=2x&xl+(dAi9w@!tdK89&!#y_dFe){w&K7mg%yI|b&3sXKC zJcOpSjFwRZvcITHHq1HED2DbRnK?~CS(0MXDfP)1jY49)n}C4(JKwrOUFnb2$@k?c zDtlCi$sS)PJiL9L#^@Xc2$eKaB#7N?NC)9k3*r>Yhb06Lltj9>8j&$cT4CnBQGxPRE^q0zD&as#Ey~zA|bmgE5euGhbW!KmcN(cAj@JH<^ z`U~u9DVBnI)3hHM<$207HZlH`7PdkZ5ocHtv{z6U5F&8`a~s})RU5n@RCL}&;r6tQ z{B0*=G0DkQPYdG(!;^&VWs=TbfIYY%Cmv~H@X**l4)WBimo{27$KVQ?n#UE8W zTsg#;n0n>N=N-gCT+kShMq%Hnr+vpJTUGG`N76B_`S0cevu-w<#E1uV%Z2(0QL?`U zMk-;cDhtFJ(O1H?SW4e_nn0p`M{|mG$QTr~TRt@BgwvIJ+g<#f=iuHvRMqlQ1Ym?@ zX$i*70<}gX7zIAuLKzRSb}-OjJy!uCZi7rC*I7YzV{evvi2m_1(p6gz4RgOge|Rx|YcG2xRjt`dH>tuKL)9ybqX)>D zw@9~H{_hckXQ^kircSg2LT$J;CN05^+BtH}r zi0yBiwDu$WkChtcz8EOlE}1i`ZlP!Qwy@tfF9!D&RkyIx=qUIq=dRqXsgP4eR{uFZ z(Sv4Dg%O1SGuzn6*z*JWZHF&H=r<)Jw2eN$f3ubb!_LDuXW!(!&xsP+=-}t zsaV+-(b`?A-6Qnp1`#-9s+jDZi|PQ zuXl}JY7f*Pi@RDyZB8s>4N3R0KRy2OOT=5Ego4})di=zPS&Ucs0lP35>8GZt5|V^+ zfW857jvi61to|CyYrH-M&foc*l6y>o;y<~EH*X9Je7|~Alrxk1; zLntn&c;PhKIw|Dja1Z+x$6^ijH`I4rt$nmPekT61;Q$kA0sTcXcSL_UQgZv=y!OgP zq1PP7s``@`p1ziQ{~Vzmz{Z0Rx3yyCrlB5xl4>MicQui&KWHu29eI6NL%I z=x$ku&b#B7m~Ta-WGN{)a=REds%4%AzlsC`r#C(~6Zc{CcKdaopm*=)Eqhy8_BuRC&icga=h{G6iU|!u%utIZya#*0BL;tnos{U z$NcE%!0aR;E^+zhs+P~{k<(E{*m}zazUPr1lv~;DbfNXTM*{Qj*G0)B#0teFVo3H4 z_Yx}9D-8W!zQ*~cbbkEc+O%J3f(M@Dn)ErcM&sw}>{RQvZ)+yJRG|K<)|b9fLCDb- z`IkT*_@sahUyU1}FTP=;K4k=FsPFCbca_IoAbW}W@XX|0Ub$Gb+@l|kpMKtU&l^08 zaw;Im)`4ucegXuDtA7LRb)r+APsep>v>A2g|FCj&<@V)J>k)6Z%q5R}o&C+oKPdM4 zhwGMKBp#EaUV`KABx$ivqei)&V_Y{Mazyg&h4&P6&2BM^X1Ny`6)hC+4~M?e3e!~v zco}8Q%xl4fu`gT&Kkgg6$B>_J!3tVto@m0`R;B3_%OIJ1>E36=`nTq3%O9x7X>FVbmGL&LY^ zh44VfixN|A&3cvr7pyoD__19pAbCO4sCuF7P;{rOSR&prjs)(tY-afzyLR)(2D|c{ z6!S_Z%%91-dVSF}v^$FFMbkHRfP%fcgBAATfZ^cqWMJ}yh^~?@depYm|BaUjkIX+K z&y0R>^f9f`{qT=O`2LI=CE#%vJNzLvm(Y~Vob`nWOmF;|V0Ww;Af~dQM*XbT!rR|= zQTXh?^n^~WHMDPq#Z$&lXFrqYkpoS=%3<7Oiv{2M>E5p>XP?7eUj8s_1b{SgEG(*P00`DHz3G6vLBpg>O#JD>fOP z9W`!LvtCPyNPpSXGXaIB;1pQT8lKl&le} zM#@*te^Fj3BzVxMVRmJ@h^r#?J4p%}R}&uW`+eh4ghv8QF9>Ke3}H{gs^ov89Xhp0 zu%_$^&^o`uj2;J@#0Kl^L8>u>W{bL_)%9~+)%XJs$*s>Xvq7W{^Z%lgDbF!v z1D~6iPTnR7xiXB2tzHcyK&|E`H^`FTc|uF*F3GxC5pYyX|GAk6oM+rOscU<&D(DI? zH|7F`z94W3ub*4oRrhI7zA9kaBfxmo{@!+!8yj^Z^bvOrxH!T1Z7TQj!;K$2 zcz=D9;o_wXVJ@G76deijOANkjoszxOY{)g2hsct?pC{MPP38PT!@h>Uyl2;UmPg6E zl2o8~x|!`|uk2ZAxi>g;Dre&7*L=VKsBiumlk8`?KM+Aw-f%{^^0=Oj7>Bk}Xz#l9 z^yIzxbVB-BDrDX_WeNA=UZQu5++pymZ#d;FQKzFplqVtg#gA7;+b4U+2o|rf0gmA5i)5D^Ni|w?x;Y@{9BvKc3 z4mvaWpA38v>b(O52F_{m-Gd$~{f+ky6V(2e-Uw1G?oYu!hmu7;$9nYRJbmguCr8I) zrJ-^BtnEy&Ew>s?`sok z1sGgB@A}GQKu8gfucu@r%@zs9_LON^>9oWV@?d;~R8&@F0fs`w-AQA5aLD8l!K*cm zRymggUpw-6bYIfEd6PuYrero0*cWnIashdn=_&lWkQyt>i!Bm=&ET8j7KZTZCs9?$6# zwjKL{k6&g=8XqK_)zKcgq!iqx%%*5Eb>bu$qHm1QWRO~!IFy^- zME3k|q+qVn@eRV7Xo?D{kw7XZg`&V}Q+CZ}7OP!=NFOMR+%pp+5kHQ$z7tzeaX$OB z=Czdg-5RMj3ra~wbfk*?=(kD>&2LR*geWm0)J>GVaDz7B6171WK411_&Xw(zrapTB zl`29#1o%+7GDuL!1ZONq?GvdcP>wh=eq|)H#I}c6^V13gInc&1;6HTcF!lR6Oa>ntJGs@NeCAxGFme>}<(OJhPkpWD*Nk(UVfWnjwJ3&j^&6U>de zJDC_TxzGo5wd>;b1#<3w@+-p=$&+@kxCq*6L|E3PjgqcT$rrfP7BVOf;UEs%J6MI) zvgS_)))|oGC{04GwDpX90z`9g>|sUM{`YC`7+YLFFt(q6P4gYjZ20azNGZ7e8x4DK zK{hEwZq(pJ#kIKe)%elX2quFR@eiX3uP#P=bJO8@8FUxV<*c?WTrocK!gpW_Jp%h~ zy$E5C(09?z$4VxP6qPinI4=Q#^P-a(Kc|liM9qr!0mOmb+c+1Zp6@(w`Ch{{Uf7rV z6R3Lv9d()his|T!jS0*Y%1k?ZF?5)G13f{lr*`QInq*g&n1SJHd77*DJ!j@j+%@;info(XwsyoN6e+qO z1~GkUynJokO|Jd0=VJFR!~xLH{1g9tTNY4Ln?1c|)%N*a2l*)D3M_Iv*HQQW@OAAs z&fbWD35!CK`t!o3awJC{2N(?i1-uF!D1HtMj|$#Ne5iyqT=nMwXAoM#kH_Bo)%wWR zYGZxKu*wXn=Cv^NuiWw@KYeYF679g~st6HmJOnek1s5P!dB#-h%excIy`RX#y>{c|E!`<cYsqn=ObJyXyL6Bj@^>X4d*=2PZ_@51Z$G8Lb&kx8^7-iHz4XC9}2FTRc&SbgaNt8 zIy-AWKRXhez?lz5B%_C0trrdw?WuU=`tQSXqFg}H@~>c{g9SDzkY^Nb)Vz%}#b(sL zxPC{{)+xT~=-TCpY}fL)Pf4&OMkdT1j~;D)>nfS>;WbUO`ZP2CT5F?yRyxmZ6SabZ zczt%lrS5syqX*Smq*#GEzp2(*a|^31?}{p^Z0i$-t4Uc|Pbn;X9D=@DcdFIbBGIdy zo9b}2M>X&6cAf2$=2o5{i|YwqvpBzKVpwP6+rQC&G^cMmckq1`>C@pi`J`LXm(y@H z``)*A^iB7M6lG1CfxNK5W{dv$!%8D0=@r8BFfWP+?xve}*<#3_+M6o*(yHIr(TSnQ zCsu1+zeuYfvHPJ|bBxTt0<19*Z z$PU6ysQeE#N_Z*1Nb{t0Z_dxGhZ^F!+nTtV!$|CX+vq*CYkSwCGEXMD7%!S5bLSYV zlpWr~BT=44>hIG@qP7>!#0$R*PY_f3Jzm^s%V4I*-Lka^2m0Jrj1CdQt3saBEI~In zpKMi8kz$i!)j@~yW>M5w|M0iXAD&F@x)Ra%HLDPm;gQ7GQ!{W3gvYktF>)l}5@w?J z*p7r_Ny~iKND4rvz{~mCkbhI+8=*5DDFfv2$1aR&n3sI3DiN_QoRxDMT3`$j`MU4u z{!rP6(j;ew)Wk!4KAH-A-^ns69mpY9Y!@p!$FE7(5Y*TU|f2O-_G!gP4v=Va^ccy3HZ#^>OtJ1SG1;5~qmL<@H*HHZQ&f8;&nO>*#$;CL3aPeP=>x%3p$S1@~37eHa62tM@Z$=KPPo zKS~SiAt*LkXD>$d3TYD+!9&?_L@-Ii2c8o6tJj`PzmT(k>rnH}X3|I7qIslU$&tQ8 z^YG=CFve`DV^7GX)}J36ni> zQFtTzUb2PX9uX`q?*SkPDjCsTzD0`uNV__9SnNt9nyGHnejV=EOosi`9HXbbckSWP ztE>h@s}ggfiiLMc_xqJ=9{dW z6TEc;Q)=Z(GR1-0@}7&)`$@cM&gvY+#rGQK8YZqAs29iz5dPswPp-3|kMIGiH(uD(NBcS`6XHMWT2 z*><>!{VBdBF8ilNekTmPH)Qa9=HPp1cXD}ddaoR4+cMpzR3Wck_qYmAOS$p>PmAmsU}n$#J1YHp7Y<+T>~?i*WLmlVN`HiV%^YH4&X?fy zNPF5X+gDf^CCYETIiRzYXaDT8^RI@j~?i0%EiqAwgT`S3~K z?>B!WgE$v(=i9w$QNQk%xg8$*)yoe^3f^B_e@pBqAG+youQPdE9oFj7?q25I_If>V zW-R5V?xyXmzM@FXj=C*R$IF4)@gC%59P*;cdPq(6d~WLU&N@M=Y^m6SkNgSGt&dRD z&G!Ia84U6GX;4%=rO93vA`dU2`?A-$`dg_H9d`4N4JD;_J%J=;d|kKFQ? zsdT9pwq`h{#QJ!sJeO(#Rk=cg;^|k%Hnz0$1THG?@^>aFG zBV038c&dnv<3sI__w$Zz+k9^Vk=wVu{r1kCg_+duSDo$`p}7en!TXo&-D{%^FR!0l zqrTmsTV$0+i=7;e`f00Av}kAveK=_xF3EqePH)N$>?v$FOhR_mk_S%RGxu7(7(tDR zO{s61dm$}1QYBkEKZY53dcjSsN4*el&I>MZz7?6Px@b&nsI}wnpe)05&D~B`K%0?t-QBw19yrL{1<<=Hr;?*MVO( zttG3|?gxYep@{BU9No7j^-8??c_4Mq$FYD8AmL$I_1b@<7l^zUd$& zP$+M;qw5A0Ftgej)d39JoMhmzBDL1$Ycm!djH}3CpD>33xT-2nEjYKcNSttxX z65P>+Q^)5b0mg`i^iQk)m3!1gg5AX+;r?hi776}yMN$7L?myT6P9~Ru@}mBf`JXFP z;0Xc2f3E+}$MD|tG|!B%V|5c%IVuF=6Y%2Cdbi0=N) z4M{8(je=FElh%`{zG`q#-YEaC{B$v(gmGAMvPs@RM?=FP6lp3Jx2K;wPxavVvI5ji zDC`5GU1K9RK%9XWMlKSFN~Las8_)NXhj#`3R~F|57a|_zYaE_+BGU?CXW^1Wti9C93+Y2h~GbTVnY5lR8hN0zfRJ z#lk%Lj2#n2{3o9_nSF(ab3ya(p9x&**EbgayAQ9x!}6}=8_#@~Jdqj}>*mo!sU)V` zLRcO1p~0DMvj0mnp7$i^O{5r=uJXk=#3kZHd#_p;1?=qqt@0Wj*7zf-6^|Ea3Oc1a z7W=>77J+4%=oDVN+Q@c7l>gy+MJ!o;_0zWn1bJ_FCc1&QmmGaw#D%&pQa5zW%0BYq zL6R_^vX1;BcuO_RA&7IJ=dShrR&g~FWcn>mula#v6EPBD*5u2DC7Ra z!Ee>s*2PhZd7SS?Sb5vSyk|NmS5}iF-ij_HvY75mUg|i;FnxVsaT>w2dED)i>_Q#~ zi({gJw)LW+owevUB?@KCprRZJ-STHF|MdSRxUZUYy8u9Xy;J_3M_f`LFcUV)4joGIT!_WdJvwZzizr zdg4nH||CIFq{nr5L`J_FBY(pV+BL9^!C}H^S0AD*pv)(bWcQtX?rU+?aim-l3aAITe!q;u>$ zSTop?VWXmp@v(VvN9?%hiLd2&vR=&IxA3DUF;xGzaFGm5c;v{1Dt zg8l}=QDQ{c%;2mP#GGzN%8G*Qblf97I&k+_P}b-7^jL0^`fw*#Z(a8FDv}ukzRDh5{84DlT%JwoKs z(8dH=W+q|&lsn^07$!|i(D>u=0pvnE>Efw9QGr-d+F;6XNCN>JbpdX=&Z8p&&Ws*g zLRw!8vS{H8cT5(k;j7=P6JQs2tC-8G%>&(q1mpc=D{RQDY5$` zmf|*02}tx6B--QI`Ul~5wr_U&AfV2D0)hp`-hre1=)jDdxwV2EF;SWkGzRP!ClB zecklb+$Cha@f39EU<)^hW~kGg37JM?)D`@Q>pPPx%xO-<3W**h!Imw>vH;T;Fpc+9 zNYpC??h(@P(96FTtd*hD8X6Bb!Pg`TBz zt#?R*^{gRKmq=+|q+M|`m z-&qBMrpPLMGi7?z%ZW|RuG6n4FMpO0Nh3l3u4N?pLo{k&v~2hhW37cqovDg2%r9Sp zH0Tfnxse>cq|8M8nqO7}D!ibdruMNe%Ty+W4kp8_!&&oLfCdumn?I%gGz7ytZSUE? zesyV!u$|bw?#yn?$@8ZpK6F44h>g+%>xU{pa^kNdxmOKbT&BeKNmbnT94;i?_h+M^ zfd~MJuo5{oe$qfrCvjcv-mn4yEQ#=k>O>?2we2euAUb zuw31kJW4`@+-JipBOvH9iWK{e63eentiKK7HbTGnZde4I;99^6Jzyvb9ow<{nsVR% za7xH%FiHWoAJ)X^P?!Ql*R45!$wqNB1W{XWMue`oR1BjwM?+StUgjqf zbyAj9p2}vG1(6j;9 z{|qPC4f3GzRCIUb3#{S)> zXr=l;IRwDtD@PJ<=%C~IV1?DiMTKIQXNRZ`l)azh@8-iHV#5kc;Pp;l+ymRO@V*Yf zYylrl4-PwhR-+8EP7q0S&0vK??r|RhjD;9o;6|fi_n;8PCiqkCZwmy$S60Xv_CY39 z+;FE@kvgD0q!(f`M51~K{U^s2zm*6_K4b*i*QOI|;b<~&)>N174wMdA8Vu;ith?9= z|21NdYnIf5*s#_q=0UoJKIrEw&hbI-kq_@sfR{6zKi z2vidm1$gSnu*aV1oA0w|iJ%Bsh-xkKfRu^x{uv1!A43I5W0C0CA5REb)juu@lkJi7 z5B;Z!7eL6^aSAJ9T5u0`G8R~s_oP%WJCx}3i2dX72pf0+8402NE{C(wkx~fAQ!~9f zY(j8ClX|qjVLEXrAwjSvuKxsa36cXzq89tV1P%P@yNzSAc*-9K!S;HBVa6;tw339DjOsqFDe$3d16Q{IfGB zC0qkf2zi$i$Cq#^1RIEHe~Nt!`fY#L?B8}Se%D#|^52UeVH$+|Wwj*ht&3~O6SQi8 z(m_D5>;(RX82JWPpM`Sh*`GFu188^-9b@td{AXJZXo2^?pPyNQ_EASB@Lm5&kHSKQ zK)6IeJVBKU|I;^rRS-`6r;#6F)B97Ipy)_L1)4pY&5W zOydFH5`ENR#4nQqTKMV}BCJG`Eh%=oRFUIbhW0LAUb@27F#1&Y5dN^~n~JDp8(Xzs z%hqi2F+5xH{b$*#b?KoYVXbwUGhr78t0)CtUrdn8Jdv8+9L)MbLCkl83dB~OTLAQR zfjD?7-^L#cf|`QYe}<5evrZE%*}-PJd%}yOwO39X^P?=s(MPfbxePxyuW-bEpUOFq zuZk05y%xc1n}n>;@ZMw~W`aoJJrK~qFjl4=E#1b;4lWZTVW}_O$o-3GV`S!s5UDDp z+rvzNpWyPal@cvxsHZnlI5i1^e9oO-U3-<6G|>J*L9_Y+z7294cG>n4gHrG_9FeZy z%!=9TyLWad%(`_KM;PY9GC1c|9LCr{*L-I(U4cj?fSiZjzhmC}oWXsKx?*j~EOm+! za#bZyCa}>kdW8h*{m`D5KpFm0BIn|>;kT+TahO^OGZ*Qn@27Af?%4BH8x`*{!GyML0&Fb)~Q|w8_{_g6nPP&L^_XN zuTWuSn{6cSi&jG|f~?OV60P#!LH15A=8*{MHpseKSG9vba=_=wewuLFO;>d=Hg+2? zc6y`ZZg}OKac|%=-=C3gZY?^a*2kN>{<}vrKReljGb@f}JKt4}S`&QJzMQhVsz8vb zJ=z)F+QAv@mRlAtM30GKB~sX@oLvPOS-rEuf(u@lAx6J%&422#b8nlmHkRM{^t-3H z>-%s6*+GgW!n!tPrEO7{kKWsDOt#hS_yEzm&^)WW7y5!DV=CnrPOld8+l#NYmXg#@ z_ox6tDGc@GO7`Ju0VAdWGTPaQ`a)(&r;!w^f(z)f#b zVS7DjtUki;?lIZoOLwf{XGZc<@8#qgSU|SqwuhGAhT>d` z<=uGPty94p`^CW}V@8+lMDel{LnW($8=!DSI456|bb_O25a`y`9W6aYVvp?BDk0@7 zRCh{fH|u1Cd|W{gt$-18BGY)6j|Cda<;yad!%u0yTjaW>+n$RiIUFxZ9hg5Da_5}b z?BD?$p{&He8-7_p;0HHejCrrMHtegkfsu<5gcDDa7gO<`Z8Ek>AsnmXg_ex4Hj$#n zhz2jT7w9Zd<{rJqJjErHUG0RKNsZu1y+a4^~*PpIEQ=UPi07gMe?Q;}O?SBix5Ff*o3 z7qJ&c#omLchdzQq{lR9o;<8h8_n_%i-Xr3A$8aAH;)nPssQ2tA^>(tNFTrzU%B5JcWE9~}!4h9}SCKKKy!-}`s!z(SxA zl@$BD@AsFN($J(i{lxo8Ra_K)X~I|%4T7M_QiJ|IV3^pajfK#@Zjxaiw=c)AU|SxF zLdVO@aAB75y`6wLJko?sHTiOS(s4l&;ys&bY_FVLpE#K3`pthtA;7yDD(k(^SL?D| zR_yXbaKp#0z94K%_%RouWW5{eV?PU)81mgwvG7!jVvM;I3_PR-?1#?@F=W^|B4`?P z8o1vE{at3K>T@lCAnejACHByVe})D0NkNeyCDCk?DdECIH+_99Y(TE^^u1kPqZM{h zc*Dmbm=EKEIM8QB`Hwaa~g82Q>a#I|%NqV8qZZLRq`-;CeM(}mch}KY{ z+bFS*Fj4eu9#34gI2LSl@DdK|nnIiDa-L6$Ajq*PPEp7$I{F_M8;O4Pg9kdkj(b=X zp)tE7RD9g5S)nxu8s#OEI@brgt^l4J{S-S7We}ITZ9x2xXV)DsPJm-OoK^6iV?+6t zBp&X|X(X1_Y}DF`n>feaSrSYM*Riq5rB!_j{}bpRpS0&u04;Vwstmc(^LN za9-J~r}m?2jB6!>1y73@nU`v^uJ@jKH~PJdd}3e0#*|(29>b%&&#V(wdcQRcF0GuA zf3X=@c6NpH{Cq|*W_)isQOdIG?OV}HqEF@OGCU@?{6wl3*Y{+)kE%nIl8SY;tnoHh zy?zZ|H6+t_oSc3LxNv~<4L*3pe6MqCB7KXZEZEQa+5W^7LOL}xxkQEiHhaiRQu4B_ z0PY1jkZ90I;;Az4gFK6du#RAsv=8K?hDAp&R{^3{Q zDMU}nBwkVP?z#<=L3$L?&1<&FvkT1_XJSV0H$y2~QwS8%IHI0q0)gdyum_Oj;P|5T zp|p0OM@%)LBTX%PH#O>RbE97; zhfb$XQSPt9NOeslsnATzW@fl;gx=&~djUm9tW$rCZzkzBWKOUkh~mDFxb(pQ8>GKz z4;Z$>uk=ehGdo=Ej$veSGP@C;QwcWhl|p!TNA8=7Jv@1?j!bvIB&2cAhvkDHx|il) zelpo5%Kw}3XEG1nVAgBn_-hokWYBtH0dbQAOlPoiqVym>;Tc)`kT(c=qiIl0(@-bH zP14zy@T5i&_nF-0Mq*{kJP^qr+HU5gsVW@~B|%FV)A4NY&zo>2iKK>l9T01}_-qMp z0MeD5f-inMs`c?Z&$l4B(#tpP;qzY$Qhfc6!>?^UDzRLN7lE8~s89K=gzCpd1RFIq zd}kZ-q-VOY9s~Kk_u|QLl+%4LFAJ>$3_TGTDorNdn3?8O8IqnI!MA%xmrxWKm24>! z?n`^ZQd{BC@?Ou3DaIA|E4$2ulRlrFVomI>45C`3aJzwi?y|H?a=mL9f%0joK2t>8 zx^>Vuf727uR`WT8NLFHKLHo?|k~mKD@=*wF9{nI9m9@L~Z05l`ivw)Y@N6Hg->t8D zPko*lf3_{bM{)p#F1AJ);&+1u)W_-1=i9C1N9qKD+g}kQw_fj3yKmn0(UFE30%rnQ zLa?6kQ*7yiXl9DOz6Isi1m%0c(b`)-8`OuE%||dLBw&tQOQZO1WZk?;{suDiR3NP) zN#aGZSAMC6UqSh>0Y~KFZP$nkO>it5@}_`Rxx{ba*p+u2Zhjy@;i_8Kof24_W?sL* z%Dk=5UH3d?4*aBCF2%J52dJd!QDN<6+Nn7@B;+I?8#e8M{U+g=zS{nt8Q_>M=D|aC&O9pB&ljF7)HT+qa$oaf}q}@c@5(B6juL z3?TSz!Fzc+aXhCyOygNM$xw|cq5S9DBc>Wut{?vmI0)?F3|iQ``(=%2>y&EqPOR|f z%~H zyX&lVD`9OOKL#NXQONVlNCG##_i9p{(a^1^65#Ga!vMFFz|CKBlfJn9jg>5UvS3Y? zlgwz)0qrm2Tb(eeA>)AVk=kA7j)Ndvg`V_&TbcvIvP#63;unY4(mpGvo0qDTb zi!^jI80hdCh+I%dMKwU~@YMw+h-A?8seT)Is)Q-V5%+7GJL#9)Y5B7!@0b#kV*|=l z2(D*Orrl6I`ey4a2W1n#4v;L~C+}h3@`3v+Z*dD@DCm|NTKym$!0ErSJ~*io1uW9Q z&6Y9IqjW{7zv-xxe*k!pBkO;)fLka6e}Nrhjb!LBB^Ppw|TrC88i= zf#h>X^83(DecyS|L5rHkLT~&{FeCvLP{N-w{#{SV0e*9nW0i_6E^0BQjFdzD2Gr29 z$Y)2nuU{eLMr_d8*;P07<{cR)czu*AD*l++%0`2(&%3;dBHxbn+s!tpe5Ve$*g~N` zSh?lL&;^yaK?{z$#;Ci50SpAudwQ=VT*#d9N{09-$Y36O3%_(2AT~u+Vt;jgu;R<- zfV%SgVkX3pRW)Zsg+a&Tcl5@j2 z{nuqDD%{%OfX3tcWNbF6yq8d9ig(>`j8~5S!>`i{)Nh0hsd&KGy`gT-i?sF&5)Orp zmg*!^>=B4-Ms*GXbzJw{{G!>);)D?pmKg`EaR0+Yi0)`+SP$!MpsN6`v-iIJk;~jn z6{N~_x|ubDCB$*?@_lNW2UMfRy1PN7SWd1_aJRe#OwM^uRl2$L+FMZxt-E_Zw#~?h z1^1Bnoh)R%LPFlBez%S@5_pHaVcF7Oe6YG_q>|?r$YHU&0&w&a6xV&^TQR*l$+@CD zPX@&lZVz>GUWCq~PO2*vPP-g=JEX zNhA>f1Z;rWyo7|;w=~pQFvd-{cF(cOfXmPq`~|a>^X}o2P5O5zz);Xk*iArQUU%c674-8*u16RJ!$8|V5}Co82|@s=MwYCkjl*uw7c!9npx2fd9O1pD)?%sj)G zXRv%vsR7~0oke2Gx1+W5R`~8^m-6w+xziTqrFVtaT=ffc9+MkCD6tD_OEhZw7K^ay-3&SE_aSTd zh`6!5k|U>~8R%cKSH=h*pyb44`XQ=29$sr3i}MC8yuWWCA3;V&k`()peZIQ##7ICx z@%GQa%Fx&LyO!J;m~ZL;USCaOs?VMy$mx_zlRoS>lAdNmLmfi3IwoO7=CcL?Oa$Pn za#o}Vk$Mr=dRPt8u6HckHQ%WXeE}+xyc)lr`mmNG{u`{QuF`)FQK$BIpx^-XUlFEh zb$)n0yAg+jD2ewK$8G_m>=84u;vH+@pFzDGb=cNT@g2@TqH!#ysf;$n)4knon|H^jLybc>8&xlNPlNq(J4f^gn$*i_<(m%s^a+i zK_}Oyp2eR3mdU65{=s46d5d?_VHbl*#_Ym;XFpk(Was_pxiPrN?Q%wNa%d7;X%!W+~;S8`xES!>YiK~iWqJM+u8WSvw!r( zunWj!cEZIlCu0#Rkpw+Qmi0y!HrP0M2a4Yr8)L$P9#Sl8z~r9BV5IN!?>I!9^OMsb ziLemxLO)JA(0edat|69^0Uc{j*|+5xkj@mzqy;WDJ*Qg9&nVCxR_h~8Uymsnr4l$J zwiBdT!=uyPE@4}syoU=EU}~oBq|kb@M|)n@d*t#DgS}t39xRmaHt4fv^1P6Dz|zE@ z4JJbCG9PS|-m3KS#n1)J-;*u~(I3nY99{Tc)|61y5#MVNQG(__BrM(K0f$T9Up75H zu5go(2*;)iH?FMd87p;7ZJv*=lirKmsz@l;-jJlj9C+2v4&U#^a*z!UE;rM? zDepzpoDck#y&j%Fo`ADjKJ`<0hSsu>Rj1v@XS~92p^wABlGlgi5iFIxAU4Tyqev9M zwkX)42;%XPoX(gxq<@BB=tHwf4>{HpNh*l~NGu1*+aGmIWLTvm5s~?fg*aNkQr7!~ z8iaf~Y;#oaK2u)h5l4IYJw{J*X9*_@`I{#sZGB zXB2YLow3qQ`YmrAGxCqdEkk2bE14KPCID6@n;T8p;5;8(()b3@Aq8XJFTsNHT0nTUR8 zK$Wi~E3jnuB&bhtG;`98p|niMxLkARt~AFEF#Y5oO+w31kr>d#->&v6Pca9*3L73Y zorO(P!xoSQDcFz2K)Z(<+S3a-x|90vv35U985zq9`9&2^)N+SVf1vpFbBufl=8UrN zPfoH!e%;?N!&(*>x35!1oMYAp?$I&s+8fG*Z)!`o#y>0PV_x}0W&y3DOD z{7>Eq2W8W}=q5YIv$4r<#LKhBp@2RWd~532)!b`y$EspamFbld`!m7Lx#ky$(jP1QFq(a85b5JAImW0fBpYOoYc3+w=%QN<$(tM{7 z9PMiytOWEZm$l~E;EW681D4LB0(=cg9p%ZNJh(lau_rCWdJhKrH0 zm&?z;@&qDk^SZ^$gG6;Cra#6l8B7OFuDZWtK!P3c5GQ@*y-Lt0^Vc{;+p?63$rbFKuXG&`2;&rMZ87`*ckK&P5Ew`Z)*J-8QjIx6SlCb{Et@t+CU0X=M?vH+{)ul49` zxpTh=!qk;*VM(ybq0&C1l)OA{%-* zSMQa+aWjjWmS{KWrznySR5V+-`l3yKGO=0ZL$N&` z&pES`wXTvX19^F`a{l>1>^Ja~GoKQ|an^wqnvETph$Sad!J*mi1>m(T+E(<43dF!& zoxM=9jK{x@g@-W;Db%PYpL4xO51Ge5XCYhu6hcSipmp}89{1$xR+R?|hz@8>@h z?%^j8OC-67I8dP?|9o?2cN$vIIsIb(Dj$>CWi(vCOffS*`6aZADa})v;+O5=4$=cG zG5D!Xp&0!HZ=K!W{$y5e7Z%er*QfTj`(eq932hF=!~BRR*Ua_8jX_q^h2oqkTk8sa z8|}R5k|so?2pJU+pZO@VzwH-QX%bs_kMt}wXOM^});@lDz#SaAeEuk0jz+e3tUS?R zb=XY3{hTU1fXhowLm4a>nk`VdRGzRv1k-)gpML4vgg=>N=DF$0iJ*%|OS*~mMP3O8 zS^{s_;it>15DU$K3QT9y0c!_b-W{Ifmulrv+^HBL1PlTirw1#vAdTp_AV<|3Soo8m zcY((4g`J&J>dAcUWltX}H1v6{QeF;0eGTZgDf0*@4LK`+Sd>yx-C>huE>tLMx}3Z| za-9vyq0N{QtX*^?P9th}ajErX@F&aIL;kwT8XEeph*;;UMWH0ZRZk5Oq^Er`H~O6{ zNcO{YAl{(`sUmIaC9HJ2m7sN}qU;bocPXJnlGJizo{8X~iM>}`m5)N6r^ueOn2P<$ z1cFJd$nG$f0RNd!=|J*;Dg&Rx&@Z6|Exbw|ts1SBEmyg%HfMN0 zaCrQ9DSKJDR^?}h=N}rYU+#4GYv*L7c{Ww;uNZNBn~^mD!Fjs#CA_dm>u^Tia((*f60Ws0n#dAD)am^MO(Z0+8&rdK>L8>#e zgfn`Z1M65N9Y=zK0<-H80B))eIans=2{xC#y9}Zdj}shh7le7b@#+<%l;F~N5Um1A z;HKvLqVY3eD%?dAXq)wf{}#5;1&bsm zTVcm@z4p&j{!Z#FYFEP-!r-}o4mPqH;R#ul zHP<~WhMxi2r256i#BhF|;#cyix2-gaM)(SeX5RDPiV1kAQ<%}nM<1&>gXh!KZh5Hp zI;KkVwMRQuR*4x#t1aSqv}R%4MSg*`JC5bZ^L^vqxb&X0tczV;w`aGf`ZpGUBYd5g zq+Nc}joY6G!wAQC;@q=nn-EJ7KdEhw^MwFil%Bql?QXpQeb}fp{u+8rH<%pS0V>u^ z3(28GkR1Dljf3^bv6Xdx;niE2jjm#qwk){T+QFl~Dxqpj7$v7t-4WFecHoF(bbw#t z`cc|#hM>D!Iq6fm0|bw*4WFT-8QH;^q{NNBSHg&C?=!_C``HmDm11^EtCMa8e4AV* zwp0fj6zETx(hkI_yDrdj7BaOKIqlDzfO$l8G=?uakVsg+a((*Se1ZK90NQA@n@oOg^n#zK_D>%vV^{VXK1y8FBaW78#adt39qOe(U3vm1kzog@?R4M=#75QV^zG zO<+e~9J9$*AcjB@zmT6_65W}M5JsTB;)8NXa(G|{r9N5{exeA|Zdg!7Cb2FHa37yM z8%V1sT{Cn~8{5wziYRQ3*GtT9V#9W1cAx$xZ`hkj5-z3bClh&qqs?@*{6vYCT8Qm@ zLs%61daQFbMe@So1m@g~2hC7>YfT!fannJi)Gpz5jN3Uh2Z4LfqjuT1=-oAb{@o|^ z$%tt@OPFP`Ea!;q{#qFyIX7?L%N7$KPoSJ^+l{SP zn1q3);mPCD=EhwkD!(Zf=x8%QPlu%$TB<{|kEuZW5YA6Ki-Mum3L~A3SI}l%^_&-e z!?~OHG>OqqehZ7f1Vn~P*hWDk%f7@fS>%XdMF=WNH&gecj&k3AZ8(xK%AMr!sZtlCF0#KF3cIcT@v(qs_yV+dVldyR z_}$H6mfiQL>OH!Wqa)}OyAUG&iiC_g1UQz$5d#Z)PZ$jv5LM3>z0n~BD14o~52X~r zN>cvv$X`;U@IUN7Fo|}97IL|B*uAc~nD`!(8^o!(TfX#ovC}J;z8?SJviQz%IfIZA z4JtxF>u$rx&eksiG^minfOYlw=I*P_xS`^q?K2$xB}t-~tIl52Te4yEN84rPCdQ@e z`pfzsIS4Cb?rNN(T;2{hP=r3CNjB`ysVP;{>bGkOn&-!`pkEi@SHhWAMnEUwH~Z(( z$3|P~>k0teroa}HVpWJY?@+V^);zofr~V!KBleD3Hc|EIF<5mA;5Pb&-5MOSP2PHG z3CdcY%2-}6zzJoV79mOXPwJ**Y z1SVsqK9_T7@Ao}!IV>nR{XA9dn3c1geR!1F$=oUsYDKJ) zL##15Gr6To)-H|tN+#XuKjZJSH`5M+PVcXs?Y?H}xd4F*V5g^hE!}QBwR`5h7vHSB zD_7h~y8i50-fGjw(GHqxgKASd=XSLKv_D0R3I4L>c|F_f#apYs7w$R{qi?L<0GP`* zyVFxgzaEI%yW3oQMTyp1IO03DUKzDR4q1Fp_H_=$zwL4y;ygtB+Pf+}mrBcpUH3Z6 zyspdihW&7Z>%m*nOD~ag9Nq3U5+>@zUS+Fps<5~(eXsfu>zFfB_?s~sT0647t0nr3 zC`V^~3lK1lUuf1*;WpjL4ocDW)k*Q7a-@Z1dOu3fo zW-bq`V`kkxKx=7eO&D`en(x|E^vkg^#!#!#4AXl=DBvjq^jywQ*LHT@uGQg%5J*FA z!75pXn;UO`F~b$0Av>#yHqG8mUioyj@UupNHqL~Rc+@n5vbLtIX0^;= zgv;wXT9|1!W*HnsymZCZ^$l_{(oQCJ_|`CR1%DdM*OWKOU8Q5@rGyR;!HfH*%h&9_ z%{?r@9MAba?Z!K;PDb~QnL3lbZ2QAff$1*Ygjxag4VPb{tg%9?9MQ6e=YmZQ zrw8!vv1d%eaOXD5-7E7mEAe!L+@>)wtJ^JfdqTeAb8X;yulK;UhM0$-5pb~N8JO>@ zCmB0?h@92gbTz|&Wx;NC?M2Gvi>khH;8}D&UO{6XdYNc|LG9`SR!(*y1PWFN7frxMX|t8^hl1`t!B&1a*hjvX*qMeqyBQpa`JCr;D1YjO<%BJ>xUm{BNvZv>!c*sQ!a8X?N^L^G1enS z=i|q0bg_c)XnF#)PB4PHx@M$=eUeR?)3gvDlM@x8y|2teecT+_EvduWwdHl;`lZ-g z;t?3HRXNcXCK~)FVeOe}J(jz5dpbkcX{SqaPSZznRqT0R)sxOJilLI$O1f^T+uhLg z!@4R~6k^peR`>ddK)n`f#pkQbu!}sN5`C#cpw#J?Xn`x$qo;F^z*D=Q0XptCc2~qB zGQ)P8)*5p-Yb=nftW{$Z(k=xHE1E1=Q;SAPCv*3NOmdCxs%|Z4JgnQwHT=5V-)_N> z5~-Drx;4QQ*JwbvZWEZ07%v_SSJteQ)6S*%%?9GzbzC zlok*rL|{`XK?J26m6Q@eX?9H%Bo*l}L6Al|W`VTQ(jnbBU~K!{`To@Jzwht+yLLe~2RS=D@c$#%e;;md;v)YxvXMxiC*Xq@20 z7DEP}0cOUV0SlQnKTiE7#;8iIc-xpDNE!M~`vpq$2ZFz!avA%|@)r4{2(wm1z*O8_ zije3-XK2{f3*K(yJme7|Uqd+|M$g*uURK`<5v&?CzZCsG3sZHwwGLwN_Uw1do)#pe zdeuC7{y3N`y;ROUQp8(bkU%ou3QT5<`ec{r*QMEYej#{eP3P%?W-y#}RIIgvF-FZD zch95|lPSc(6`W4`y%kEBvA}|6)luRK5Bc%V+$;R5B<;0X! zKFQ+ALirWXF3|(CkYY0wYQs&!%^qpP)r}17n!#ex;sTU|M4~AZbo;b&e-=lD-&Nk} zV7lEQdtdq}yCDavNBV|M-<@i~h-FS<(IK(#T0R#vYzp$p>XU^pY*pM7cP`o-m6&aESr!*@Tg%DCNi|J9Rw)B|4Py1aj#%e18v2X z4qUqPuU*A`kLsyi+LMdVyj!?QHb(wl*)@c-gsgJ&Apbw#hsU$}`Y~K6&r$tW6T;dj{lb?e`jFFPK!x*69kF~gfdS&vBI~8J= z`)0T^Skdr1et?7ke!mIvlY(LTac}$jjgR40zvpeD4H&3>{&vm`e<*4v|6tMmQ`yLe z>8-zm{d1#g_SL+n2@y7201`m(;Q-a80)o#D;On2C{tv(6r5}yhdEbNIBvHFU)W7A{ zK)A)qD!0r*0zOXrXVg09{Yg;dmLWHhO5CJc`O!H)+bB|v@?K132>pN)O}*b(dVhVAU?qxDa=9Q5%hh`!Xc9l*O1)?m!^pNDlvuzn4dziA5fCM2047`h|D!`{XQS>}T_ zHT)4CTy(dt-wd7z9{s6#fho!%bQQsR5{(9Do_xu;>1Mbv zQliY~;gNwu#-yc&3veAVlWioQPvC|6ci$GpCO%11s+)cOm;vQ$Bb0I;9^&r;@>u|t z(%ExvdU~$EUcA>_Ny70$3q?LsQw>l1cXX2wPtxL-lv-)}ZcH9=Aj(l`gi3Nh@yM7W z9>fo-O{`(mm1DfcP17z0@)Wm@0j*T8c5>RYNQ`GY!hh%lnAbx$@x%SF!1Dvxp(CB5 z2bot9w-_l;im+^-+`3db!4clwj6`@Z|F#Ea|9`<{3R2(U(u%Mm?alZNCx#dUuW+9~r}z%;_D??zAphXk6|>rmdoM(J z1(I=0_nH{&Zrgq%obdshO%ef{L-Kl{`00TK1-QrGRbWNNY#-ddD68xG>wAlc{wH=w zwL1c!&iBb0d~c9-KiKpVL&M7O>;y-c&2vcXpvBMKNf^q%U9lISoBARLAQ@-MiLswt$Qcf;82#nj6%8~;lvCGsHA?|~fcVJaC~@IZ_- z=<8T4{Qc%h-XmFb;{P5(&JKl#s3`f%A#m||c6f-t@&s=DfA^Kzi#p=p?tlMMnSuIW zs+jsmH2nYn3h^;usZy=OLxegy6=8CIDD))L&M8=y|CQ#Tb(|TiEjchE%G+HfB1|*( zKTWe91I@73$QNZsPAFB6zW`EUo=yf1-x?rA6^H-#&rtx?C1uHe{f&0y&YbI7*?*<( z1zun#nkj4aHj+B)U*hFwhuG}eGGcRjz+WDw>W|D3RHoQF56RxY+(Z4v{?Gwz7`K}F z$NzR5VuM;Ud(*@_|F;oTKa1nyp#n$6;op&{BKL*F|Fl|Wpte%@-&XA?be?O-_ksT+ z<0v9~N*G2Id?6tKx)VURFB?1{d{IZA*Q4@;U6CSHfc&KfA8nZ02V4quj{JMspfkr{ z+uzsue;c_n80MX$4)Py0`G5SC+KWmPSn8L*fB!E@?*B`-zf)oV(j%1?|AO6obYyMl zXIp9?vHNnGAM8a*MF{*nnV-K4vn73G9`|NCC-1SRY)Y+2P;GUJ1) zzk1cB|52mHV8V*8itQhjn?UT0xN7O^t@l<7`7=3Mg##K787DG5%3GuFQxiHAR^4k= zFno9Rm*YCVY53Z?zT)|j*8aT@iJy0G+N^vtUUZ?YU0*v@{WZg`rqXl2LPyY-grfO} zgP^@8;E%#K?9)h;eDY^N{AiTnnzll&u14M3u`>$10QYwsA4lyJmaZ52YnRJ7E;h#>+vbXu0y>dR-}(bmvKzdPaSYV}F=c!~lWlsd{E zc??*kFYc|q=b~dfOH)Xka}@p-<-DwT7gO=33YjSs73n1)ZysQj<=l9^sANPf-Vp>6 z9^vFpKlie4saj=$MK#yIsO&h+&)D!}HImj?y-~2hFD;I9Uzt@(U4)P^Enm+r)=_Hs zvx~t)Q76S6XLrfFy@WgmsWX&6%SoY_1}?>o{|w{I5CbQ`@i2DZWKI_R+5P4rY&c5e z3(A0X+7p`{+;%%fEXSu~l6l;z;t=7I#<5d8%?__W%i44?r>{+DeTjUg>84a1?3&|n z&4NwiTy_Mrg68q!n=++bE_!ZCH<$Ae!=_J5l}{I!$GR6gh?%wN|43GNyceOrv$W2# zxG|Lq=bAZl%IEN*Cp)2^yr<7}1PHbVV|QyZI%alNBMu9`m%v8+65=6c9pNDym{;Fy zY|Wyw6nbV6hbj3NY{ciu*&aWU9cH(G(#8+c#bU01+0Wd6g@E5 zpd4uAyTJ%l>WtMwU%l0zJ}ADtace}m<9%gw*UrW2qN(vqBP{XjC!(%(@@GuAQoaUA zHux)_3y{^f`?g{>-PdMTZl=6o{#IXh59j)=0IsnL!5?7%hynCC*{83a`r$)K({&lU z!wx3I2OF&d&%uHGu_CQsdD;u5DF@OgDO*miELhxm1Uj0Mt*n)K?z6bT$T=U1*v9#D z0W8pE@bF@F+zQ(v@91Ho;cbHJS$??goDV`Sp8*uSW!TAwW_MM4qWA4&ieu{ENK_h8 z#SIqzfWj9@`=24XA?F8}45y53ZBM~9ywSm%=*jLj!iqP-u;@Xll4Gi>F#nrJa@r)e zu(T!AY}R0?ERl+iP;rsT?L(h`(q29W`;}z#@5Ed|**gWxceAI8dhUa^ML$*wE=NgO z-pYS8wKFFyB#N(QTmpq>weTwXk4es~;>+eeulR`BnIEpyPScYBr=6iZPDCar<-?@ci@OxZ z{J6%R$y}h1vTHZ(?OxHMAh@MYk=1%$UrGw z3w$$Y15=?*8+{#NRAu!Kwdm5~4}>y+NLpt0Moij)dwnbD!bBvVO&e^A$pZF8gbrNu zk^>wN0gGfgVd~6?)p;i9oZs>lc#unsAdmt7kRQa5$md$lgMvD+YRwt<3@k>?jHNtf zHD^Pt9*+X8-@<_^J1ccL7$7cbaCv_kLD(Y<4Lg?CZ*5$L2Wn*iS+^O$@WJ3*H4}9{ ze+d+HN=izfz@ptSKTI=*k!qj>9-zf7PLCD;EC47_o1=vIZd7rbv8r{w3M*u z#U0zXk0G~{dvTQh8@M-zkpOTYv3KD3?v)oTC_TGyPV~(CkA7)<6uYkABqWqUgYC%o z*v@T7*wa50U~kg|l6<=LrhJ`eK-qllRq<=%*#z+LsZz)MMweO2=kQwNzESQo^yrUg z>G4j!hX6?!ZW)Nc>Sywf+I12Zh_us#rz6Be;RFRR2C(bygV!iC2QM*v#7(9xN#OR& z7fW_wG#ujwSwlIbx(A+qy^m907;Sl;;j}LTI{L#e;-^0KQp)#^jj3;4#Pc>^#9u)| z9uu|F{Da!I>y=@4gjcJ2m8qK@2FQ`2qCQ-n@-73`fd#vh6MTDR$GqSEyX~0+{#s2( zgzHEwwVTK6RSu}}C8ndS2L+kSh^NKqPsw6bkoeN*3vR;WmtuFz+AbW^U<<8=5rx8c z7A}`>U+A91+)^b9DZc&VHR?toq*3AJ1RMgDIqsC?b4rcH!q_WFw1S9~RO403s3c>hu@K?cCX^MkoW6 zh#Z3plo|tmTS~*Zfw~&cP@G1Ss zvQ&tdxc&&q&8<41AZw?=d&<_VE%V7%x zj!`s0p^3;2)Sf}vI*v+#MiN*(eb^1Ut)scQ@F%7G68NElpTJpa{;EoH$q&6BniAOJ z-CEF=9~O_fuBBP!$M6m(VRj7Cc24(SB7fFv`=YJ6N)7En+Ba$TxHOfY!$@QA))jX77S>Ee|$LnLPk9N!p++TI)BV+zT#5*Ya8#9t{JEwpo#5?mZ$Ukh;OZg%rje>3F+IvINv4|gU}0C{pU%Ks+j37AeQ-J??IZOp>`BL% zS~V#p?KDYjux=|WXP^3{)PX*VguDYAb?Tb{011nl~L`-o&$FR+IG~pcNtI3yX?tQ@`r_~r7z^gMh}9;7%ojomy!JwaGP}_| z=i&3I>Bvh1IAXe;axHF)a%&qW&ai?J_rHU|ZXFu8h<`Fe%L*(FPyc0H5-?V)xas4HlqtFrR z{hE$%J@Yv-<*iB8k%!I^?cImBm>T&6m;|-z?z*nsPA*)^r&z9?za*I1+OhPUtosb* zFzqHny0`nv_E-0gsAI5wlx}|bZ)|MfThGwWHru(1T`fVRB&qXSlG?m_%f4|bDP+1b z^V|$BIH5_o>dCHjs4c9(PFrmvvEywaPhh$?1D76xOIBB!&qjZsBV@gJu%{_OECGp)3r6b;BzdNzYO=@ z?N%>1IpX%wM7_zU%B$T%W?LO*$%j|gB6Conw)4c9oprFZALY6J`0}Nhq#HPn1sP(8 zxmePCI(yjg2K@!ZSS&4m_4;(lb^ro}7cM4`lD;K=q*?&qqJevE$8gNo*;@%+nv}9Y zLf*5~6AvnvZ_A>fEmnk_Q^-!u)%Cf^>YIaug9M)J-tY7pW!Q@{<@6U~`=N0!3d^Ie zb62E5wpa4=PFT53IpUL_X`J8i?TZkg4MW{%}sMnRoO>Q;{3MUGZXh8lt=B1#xG9x#F$>R&sP%5 zvU#>yE)c^#%MmFSwf~v_DY9+?Q*b4qYBvSxbMLxPt%v6}n&M_r+vjCdWjgGfWOhRf z)=lS|{gS#Ok~=!7l;1K9KGVa|nDd;OLuj1Qin{Ivq`l$Xt$%6spihzKYBZym< zxDNGe=u2KOca3 z>z^j1GZ~E{1hYVmUt)@D@p~GRAJAx{LdtKYJ1?A(A3~SAHzMBLi^89aoqrsK*SfNM zM%g7^VK2kU_S2&q3?N@e-AV_Aw^!H8;Q1?$SL0B4l;4gQZRMf6!tVPLheS?)DyT!Y}=8> zQ~{Y1r2X67f!98#B?S+>qyOr(ylKt-Q0(@Tr_0U5wKa;%p5nuY6+;L*_I14?f!$G6 zVajVq94#&pJp`k*j|q~s>?YR!l<5jpj>R@~EmZlZ29n8fyCEeGV>>4Y>{K zOYb{lLH1BfQ_Y8&BhF3@Sq=ruaJ){Zy`962mEGgH0Hrq(oaV0N+pzCaA5pZ^8nA{Y9*{m;K$8S)~F~9xQn_%m{ z6K8TV(=~e!Z`t$>ZsmLGy$V0sGZ|J9-6jl{{+t)TUWXD=nm>}0F56t=OU`r(C6SWL zK5y_Pnki=SGh|zQ{iyZPr+I1Ov0p<;_yjvo;|t%u@I!=JGYhlZe?mSa>J7F9sl8jF zSja5*nzcyc}T`yuddWt8RSp0+toAn%LFg|EDSLMgOuB)xW>ugE`9 zSrT#`h(vm08yp3wU^=~+sfeo-E1!39+R9D{qSuW{3_4U+E1e%WtZ0(FEt?4Q{ zi8_1)_k(Y^>0CzWCa4B~=swsM$inq_yQ>cw57!hq@0Rebt90^d`TCE70o$g8S54(f zp(QO-?so#3RPMz1XE|yJ$Q8Ws-!Yj92ol$6{B)-{@2iYirP18`rTm=Fm&uQ(YTTS- z(Ko8^uhD`K`+yADSdF+w8>uDe<)p{~_53Iu3?amK+N7<+%x{a}mLawm5ZNk~VkGZ5 zc(Li`g(U&U?#qsj;Xtl5To_!J9wCgfw(l3%vDQf(#TBZ)BF8y3h0FwI?y;XZD#?HL zxAf1A1Co3XJ71aJ{mPLpQZQE#`j#E|)`ipI=K4BGEiVq7?hJnaqXuL$Z3+{It}@2F z=$-7^DzQex%%fkGhwP!NI;Vi6T_Zo885Kwrxte*U&bxHiJWun{9aUU2KevZn2*Kmt z2L`|fX!#JUJzbYv-xMAWQfH#d1ZfpexV+PQ0oG$Nso?M*1xU0mj)1z9I+k*uW9)9c z<2mr-p_p?+qtt`X6THhmF*q@=VE6!o6eC8?qJ8lBnlRn{7sv+;kY{k>rorVNx~!+q z4nK*lH&T}CwLQXkkqtgJV&0B(I?(p5 ztcJ5$yi&-7MwV~SRA6COlKROXgLCblbNFvpe*I3@wfu^EdhG6fTAGD1?!a8D*)vJxfV81@ku94p+Y%@H)M( zzvea<+H>eoAIf>P+MjpP)2E7vq*$VvB?@bi>Fj!@ zlQG1|Vbn9NSRwObc~YN$O}4>qR(qZ2vp~s--4&sO#!>BNcXR11i(D@}R$eR}GO$Ku zzChfW6#*Our|Jdjo^R~9PFKF{|2NC9L8DG~Kf+)GlNVuVw2~j!LF+P(%)C$)hXuaz z@p*0cfT1v$yz$zFsU9teSvx4Gr+^V)+4yrj*pklJLh$qx;L^bHiFN(Vm(ww<@|JJv zMB)iq@6e2HY%K! zJ>`6^G+=K3Xw|#qY(^&=5@~Pd7p9;n;FD=>8;vM`8hGN$WiV)S)bz2|caiZ+ClAta z_J#aFVF@DV{CkCa1w>WGkXDyxmRdsVu^oNFdzqUNlCj?pw99*0&5I$=tKg)r?sUBw zvhz#SfiAR6RvE7xH~4cZXhS;p^VgQGTvHN3d#_SvHa&j+VS~^prkQcy&_8bfiQ;h` z422Xf`%XIk%FTSnH^f%8=s+@`eR(v`jY zK0mqkPDY+#54AqAE?1cv(_Rz1EA?sGteM4?Dx(gzd8tXOoQB4g$c?xese z8!hG9QJ)L`=P8*?Gd!d(vbCzG;lrZhdCEuq7x!=JIFMTVB6_^KxX3S7%(i6D38fPLAPWlV6DitYCe?_%H9qDVo+Fr(p5e#}$4fl99V5c3 z=v_&R_icp>`aGZQN*q;ZgHPY=j~{?ue61dlz7Ny&0XXXNl`#o3em7y}Y;D&3aCzqq z<>i#neX?06Zq%rtzQpZ04-(P_PUo*laI#K>s!_Q1l)Y+x8KbagL;bb*M7NIkXYUu6 z(qor?De`?>Z9$?ioiX^6!vyu#93vw{t-d5$!efjP;$ z?R*5Ty-8tbhPCD7jeK3P4wtNwd8doZ{GjPjH{*4F9}V2l;pum@8V6f*TQPYIpp8Vw zF_+%=qsB6qJ*3;D?%HSM*Z|3%dB&sEqJQazruF>xUdN>fUyc=vmjk2oJTgxdN4Nvn z(CfF-kEpWZ_gFLugT7*qHJ3-ndFrf1N8c?wWw;`+gvIbqT~gu&iypJ>rMudfx90C8 z9=2m+1JarHhA161%$&Lo0oAco5T${(J&(e3OCd9xkL`8Cr;#Xp?oqI9ZAs~(o+@(7 zfVUUG+uPU|L)LyD0dx+9reOnTka(7%g9Zi!`Ffjk>wo6X0B;d6zvjz=rHUU)!pqF~ zyWb{z;%krAxu!B;-$^=VpY%pyn@qE0Ka|_By*HU!G%_e;z|Pxe4OzV%P{yha&B37w z!8hJWcG0SLwYGI%UV13+p>jE`QeWTI`-mr8_dCLOE!_Q_oWGO;W06LlASEt`0 zMdXhggkqi&7WAv>vFfNWjbHD&Y7hQq#7cJ#4b@N%+_-ZYnWd3fPa4eW<5aj$>5-{? z3cIL!#8mKZRS?VNe-2A@k83h#0=i8O8 z+I!dU`mn$S4Pc~HI)E24SFURh?e~5>1@fa)`rxc(f04mlaKm`YKY^Y;BjIb@C-7wb zeA9)AFh%1JH_>0pA->O;+$YMmoWxB!!G#!uZ)=)rCTK?B3Fc4%hrwNpr&ddRyUfiBj-dMUMaO19SF#T%iMbDK|{PyY(Z{x zYMP7TwF9ikLVJ|`oM(N6m6GC7IHfu*UYc|xmywUrNd#;nbYP#niEYIqu5NXT`jJoX zp)Lndx^czo`G!w#&GMdCChpd|lu-ar+^wi(qg{KqFz2ydj8<_vT*|+-JgD+5GlY zQVd!jXxSRvUYc*&GV(=S4#s_n!}&x*YSv}>UZTvYUaDDS^9diW`QuA8tX)X*E0)|2 z$&{iOpE3#S%lLi|ht{REUl0?6dJwa1L-It35@C|nZT`(?BxPz4)c zk-Pr<1|9yRr^s~j)^TjgvnM`A$;^-kyGl%{bW}jS2>nt-6UR2_w%}T5*-Q6(Nj&XT z_=y?6X%x7s;`PHK)k+2?GJT<9OJJcgK=OEo_Z&PI)W5~JfkLL=Inza*K-d~Eh|@`_lvU-PT-w!P?7A5O%4CkG;> zIG{eLsXp#4L(J0N$r~dW?vnZ|q-(0RuI=a5w1uFa9&Lx+&e#ISo{TRs?tG#@0WM;1?WEK|IKxPI~m0c%#?c zet=7}N8gL@$OaByHW$c#|6)-dl<{q?tGvm7vSr+OEqBs+Kpjjypr6;!E?C#mjLyRp z7SY?|hF{&Y4{)H|qj?$xTA8swL%6<*?y*!%*X5lZxz++)GE|fuoxmR+q^S^eNyu!| zG~Lqmi0vdvs`lyEg?3P33)5RZQU7F3`;}p#o5mP_4J)j|UF_+LE z`Xr2{cXYtzzsVtb1=U^<^7H+HwL3UgZ6_Z6$um3d!2NzH6O&<_(94<8s^jUmZ0#0r z+Xfl!<~_yP;YJwpX4s`afluuo*;rvmMLR zS3)@R05%#Va?By4`VTJm*CAzkR_GY)Bi(zzzk|k9Y*fhUb;dGl z3X=0gVRZQA&#x&71U`A7{yVvM9>w1mEo)8;7T|>xiw103BO)Hnc}y>EW?R$AzE1zN zPLhqZ%=5_@{9TlHLX!^vn;x6H;WI0^g%Orc3(fJ&gPGT9ujl!lJ8HzK+{mua>S{Es z{ChkfxY~1FP+^B$NDnwpftxWQq5cWhUuFA-GDc6=mI|#VKaRJqFtAydXIo%l zV(iW=_kL`YzYpA?NseOKoqsspZmp4vP()dCtcg3p9rO~Gc(H#Ym*h+mH7l5D(tXSHaFpS_t->+|;4?)f#=m z&|025&FZ&F`~1{?{({wa%2E*R$Y4^j`@*MZ+MMBTI~RHb*93OOV;Oe1&OaIr6b z_gIyG8*#4& zqy1b$Dz3v$=#T$MbMl<*jV;Pj5B)IX z*!MWHc}k_mOp(JKh<(JX>>#Ud;l&pIM0fp)I)xS4ZPwZQY=i4AJ<(_LZv@NBB2*^K zk$<+dM$TMkgp>;RsztQbD_&EA<1=SzR@W_#zXJ|6|8M|p5lY;`6d)=TX>^_){_}dZ zd&Q7n_D5yDmMSZuYP(R>`c2zi(*xNQGtS0?mC?1{jmOiiOnONA1}P`bpP>6_@JG;t z@OY$R<9L#K{zTPV|8oQ5`s)|2bPh!mCjta)iK#o$lOOnQRMzoDybFjmZL@3gk1eg? zjZ8Nn?wLn5Mwy$Is`<$H>u!)a)85?OX^r9319 znk@Kq-IvbCdUTP;DfE48(T!*`wJxq`yT%;{Q^8S1I$?9wlHhFfzzjD29zu>A-bTp#AXvAbPo z6W~CED?G2r%B0>3d^Id9&5k%s{PUT(jBEJg3ct*3jR&dwZ!b?hhe>yiZLs*9)Ltau z++7{Wm*n2It_OeKCF8zc@-4MTO#b-1Or-R`;hZIU_%UG5?InBIZH*0jFwI6UoUgVs z=SQyU_~}PxQ|#W53SO$iA^oBtR`enb((u0c$QXyt0keyDM`H0FI@?Ab4fZ_%o+ zK65?4e)JAsE0Q=>@^hJo`w`eD{<5^^7cT{+!Hb0Y!LAx#za_V}7WJy4>EX-U@aCNA!wLcG5@0R6{|-hW;|Y+L zyN{c7Ut>TRM)wNkR=#1Qz9MCXYR09KcSajmWnNx^tGS@n^t{%++|~~xf2#X;g;&Eb zlwhYy@z0##Yqh@?E!=(+nW;ri1~uqIgVDPyPOyI?Jkbm5L-@v3c?t{cLlBFIiLKv5 zvm*pMq!h%mkthfT2fp4(!XVtt@QAZQlzyi~cdI`A2Tu6y@KIXyiAVWJ-&RW4<>;)C z2X=JiB_Sg0k^sMp1%Ock%t`pp)_S(JmH$YhOm!#*s#@J8j?QYpFY>4j#7z+9d$Wv1 z2e6U*Zg!-wQK7AcAjDtL;k&w5fGVl>w!}{n1xwj6v7mnss|)ALOzy28&3jDwBo>&g z3U9)Z)X|R106~M6v81XClaUfg^mQy%y}*~a1j3LDtq(Mq8K@4z)Ru7aci4ya2Q9in znzPwzsRSEt352;`8D_ucN5Ji{@NQ)~{5kj09Dv~b0Q?ohUhckpq&OpSTbnuz zcNQqErxe;Ej3-T15Ht?l(5rCrEmB-_=2FE-s5Jv3oB5Gsj~(Ou1&5=I(7MxRmm>K) z+z(|xLTgVtsl6kM$~=GoKhS`<_ciYL*8%Tb@0xOZB>E*qscDq4t>HQCODa&X!+|&> z!o0j;#cpl>0p`^1`{&F68;D>yv=x?MtTm9Z6&Ca-wLVbQmUr#hqp!7}kq5AEzgX@~ z9(a`8MD30SeJ?@(m>rpLul1iu1jU9glLx099lP?z_tf@^F3~bSUI@!#5(c+->vw~W zzCJ-GOapg>z@OI6lzlJXKv+>*qcXj4{@9>S*^KPQ+U?1GCdiyDR7kqckfY9u{-?S1 z1F)DsJbex>BfnDf-2aorrJncxICBWxOHsJM(0XvpI z`{&X4ctpbMUjko1d;8_~OG~_U**8DCSgVn*X{BS%`oKNmh00_=;eCP*!g)+@b3w&h zubF?ESEzRzIx*nu_KqL)NkoYA!Jz@^kx}7d80&Ddbu2G5Yn-z8_L`{5J9Y5{6Sh^! zaQTxFRG5&4%*ev2_gn=EM**lj0446TM7+*WzW}=X?a0n+jv!wHViW@`8!Xs>d#Av6 zNgyh}jyVhaFL*SZq%sKuexC_TB;MTjnlXi!-~qT4{ox+2k`wWp!CgHEaOHtxaEMpz zKcM-e#_TASTE~F&4?s=suC|=8h1F!V_clXZo!q;YR?A2&R0V@!0|ugdy3_ruAC5 zCsBCE2bRub-;V<=Au#30yIOq;SPFryg>7|U_WHd7JUJTp$bfM?Uo|{& zw!@k0(Pj(F+48#b=CTkJU!3T?j1Lktq#-#3fzZUKTCz2#gT0*^IHCUI`iy^{pppmb zHTg6M55rHJ=_UQ~nmgS{Ux9#Zli7Yfgu-g=#7VG?iY+1xWjdNmGDfa5U~8^5_`{{o z08*|G`E%X7Z8(wvU_FtBre&c%xQfsw`4B0r#c#t$%K1Z9rs4>l^F<7h(yggZci;6d zQIP6wXHYZp)ask-py*gjj{Y%34OJd;M^wl^TS6eo-B7r*C z1eh6x<882D`XW$Whzi{bfUDLRb|Yi%p8Q$Egl*@2p!dswiyDCi$6H2&(<^YTIX>Ld zsRDJERedq4M-L}!5iN8A|F=N`kRD$0^Im8Wg#{`?9G&pyc{iY?3cPew=J6x|2Zg~J zjhP98$3r9*Fk^|+&t=ZT&k3j$2aZdE-*nh-5Cks*d_mO3fbYR~3o~gm-xb3=iKYHG zQ-d~ht8{@$NUcrO9>7zo}r+5-?@axC0 zZjXSoCg<9$N(sO>yJ^R+;Mz(aBZ7U0V9BZkTNP+(FT)(<*za|hrS-EaQ|lRneLEzB zx?#9N=6`h7>a&n(Sb0mlq;&5k;C>DM_nr-`LMc2n*LOSGWKX|m{8vaK6_V31^Nv2| zqh$2%ki_-Hy>hH`eARYvmlNVKK~w~8@py?)d%zl0&yOh3-8*kEi(-y> z1ei@W!xj>Z>GEVZ!@jB=q~(H|4YRM3-esz5tfwLjcg3j4&n%_Q{C)z6mV3f}jBt6c z?GNL1_NuRO*J^jp8x+Dw{f|1^XTZ<*tYjZrjeylJwc{zUlwu$%)(t;~1H2iz<$uxf ztz)5W^llct36CB;K1jwbV&G+O|@rHfMgpK;IDwFT^I@q_u7JYMH=;mQ5 z2Rf__MF}UXQTiRb%MP_*{z@sTH2}Rp{w&9+qHmDu$g7Y6<7e!Hn}|tT4p6j@u_u0K zH4Z_?)H6epfFf`no(1j!i@p!wQm%KsCvt1O$vmqRy6*^t59E?VxB})GoEWjRNVr{L zA}Z7I_jFrJGCYTS0&p!N8&-t&?@!nx2;i6&u`U?S;*tXl;rz_NevJW3G*YTNK2HhW zBF$;RGcX|z&$AHd+UOIwS|fq~#tHa{7QVP6!Ltz48;UeLuVL?SxVp{j`I)%pqP<%` z6ld&yr~z7TC?nst7Je;FB?{P(Eu5<0qx6yI>WE&fjH?bjf6t_XFBG$3y#nIyoMSQs zrJi_67BqG6Ld}Ot8v!jwiN&WNw=7a)aBj9A^%urDJ27i)Z`pT}_48IbB z2CIjHoTJ~#nm*f68acS^!3ON70c#YogQs9G!HZ^<6AiC_`eU$axtG^G_2$EKSw=W( zJD6=5I`h0OM8(Rx2Nya@vsxhqMquOT1P2JrMdA-40G}DqU7_$TNz+4F705AtJotGY zkr~Kn7%hR7OOe1Ph2%yE4e&Imf%;|GK+Qak#4d}Dg{v0I_fL!3yRZWGH%XTolTAFF z!RHZ&+U>1ewNMLmSpH85QNOx$p`aS+&Dm{H%Ro^-~sEh2%??=0tuNO z03I_@w3>5ILu`=Xv>izFmjC&N7TULhaJAGhlb3LVvoZ&V!yi*J42GAJJ%I!B6Hthy z!5SlWRw%@bdf2GXyo1CV7+4t)@@GcP8K3BW_>n8!Ag}E3nL{kMr05gX955(A%+jpLOnrvf# zn2=Pli~n*EgcM{wSjed53sGI0`h@n!Mf_Dlh4wV~?R%SLor#pi_Dsrg1V~1MW785; zlyd{cW#;_)iu}@@#b$fIgnv3DdKLNUVvrO=QDJNOHRL*e_Q z60`f{2QYR$fX-b%U+LSuv;Z;2w&}rmwGU&(9ir+zXUWRHCM@SN019uqYHK%k-p#Us zkt6syz2yU1XLJ;2e{n~tqOL$6K%xhMN3}{7&mF%-%cUA77?~oqz@8gn z?=T0`#P?!{@3)<&)~(HZe-%lqN<74wsYAh2RF-_Hnh5i{2tOhMU67TPmlf2Pzns7N0FJ_@ z!QOUIF1h|YCvx~}Qf<@v?LimOl7f)s_mqV9=Kwm0r z7a=#TUI?v}8xfL{euVLHqK94{0%GbHrv%9XA$EN&Uhg+pkRhQS(Jp|&Sz9lFos!#tfqwh>^U4VF^Ib-~vF}!WY0b{(Z}h)zmkuNe0LwFAvEL$ipF*_C zN6i(8^2iD?+z*0<*-vqB?5;*MiMP%7?#KK}C3~;iBQ$t(?@YVHV+P!^Bp&k1x{SpB zrPf0rj~{HiAKI&*vyR;*V=0vUMNH}YtSpbs=a~e%DimUjufcQ zZ6N*C5rV*0Z&W&1)lzUvhzn$1`>RZhf|qB~9M%w6zusf)2JexEA=lvfdg^b@)f*#L z;r$ycn4rPJ;^q`RG~T|Sg5!9TbarWJ_u{#7{rcl;50TiVAkc7g86iHxAvdiCi(OO``krE~Jxe&n&L+i5kV3t_aL@x=z|HImQ07cm};i9t(2$DeoMUo&vaz^r^ z2q;l<1|>@d$!P@v$sm%WAR>}PGDwn~bIv*EC9~{ZzwiI=xwmeeQ|DHlw+f2gWoLTk z?S8ta-wp#uWbkLTM-|`3<~jY;A#fRpu>*gsR^pkOeoxP63NXh9CavpWwf!tsU?0-) zJYYlb46TRqwSd1iD;VHLho_6W5?F|6y-TpeVwn_`h0w|HfR*5LwZQEgo_-`PUi*!j z+8zY0J&Hj~Bx;xyaEAfzeoC~-2m^`Fu@+*HB{ymS{tXWdE8jw=s-xeHg+%kv{i`3~ zXoN-o{PXMo-yZ;t-T&hE-|wMec;F4hxD)Y@TKQ`|qG7KMJ+PSI-;dG8MKQXeuMiY` zN597*{g1BsYcKxwIiV5quj=`qy+r@l-_QRSzyF=?UqJh3-G68Q|GXsk2KPL@wb1)BSJ$v68r` zB3-0qgoSLzwBC6l{4I9jo{E<)F|<+g_yql%K_YESXN06Q7{RLBr7-EWa6_4(Ai_T-i3YC#6GB*yn5 zdC=&M3IDQJQ$G6)tvcng7Mg_uP9#04a%03X6y2)pZr5T0JV{`qO09w|vs-JI|lpPMJFAwv}R3h7Opmxe}IM^=23AGW~+ z(8lGH!^%sUzuZ1MdbM);C;Lh*&ujJKYI3)=$=hN7E&mL1Nz<_!WzJgxb>P>yetx+! z+7kQ^j0O5vXBwG3J$#1{V%u0|VH5Fm8x&#OJr2ZB^`Sb6lJ{t7GsGlqvFM&$7-4K$`VE4bDxcB4Pm=d( z8_2&lP)1RT%>67L=GWm=7@>N3e&uCtxUXpRL<|x23cFMm+uw5g%lF-cqkxN=?7~ge zoxc>Jx#XG*zLW0osMb~XzhN&)q4LOQDBu86CJxx=N!aGRI8 zTujd62eO7-l}2u58V1Se=##(DVR?iLJIa1PgtfEdRzX3|IzGm#*qL$h7&d9e2AWRt z1Cioax<1UI5V~(r;`#A&rtaB7ThX(t^#-k)iv?zkrp~95(~_)yMdDLGI0YvDLv}ed zy6(Z(ZfA3uNUS<8#<$~R_a^Tm*4z3CSb@Eg8bl6V;x|E0cbcZMb^;gXZM2-iUa9_< z+N0#1G4(2!=Ryray@Q&rd4vDC6<^8V4&Hh^r9KBQqaRGj4C~reDAR&;qbnRT`1Mb5 z-3J6kL`+Mr6nc=4`_|sEt8-%&X;;YJp{0fG)xz#CSvQvXH6xb)S@IArjGt0M`{pD< zop|<0w^UG)i5BT}@m}vD_w`yv1}gdtd@ddc4mh5%+j9Hwka5_$!>)U0VXW~#zS?t! zN=|igDwdL<*#s^79$1;;lu5-L#gfUmbCPP6f=;d$7cb7EG$AauYQObqOKYqCv&uaC z+M4OXGmWFx_m|m)J45^rAaFFZ!G^WKpD#A8s|QP&HRiVOtRy{2?DhkjAGEa#>8BfD z8P|9L*10XcDt)7dzdNRH6pLnN)p=K!%I1BqY$1xz1!-%RY_)f5|3i@v7M*8@Vk_CP zjjyg^@6^CTAKeD3H-5&RW{C#A5>5ucoNd(vOIK5wP?f))L5F#G8-^p69&n9GC?Cmuso42qs`e#FE z<_&r*p*eQt`lz*$9u>&8VMfz8nt<=5k{5X@R$H3AJ|fD6T<#lxcIl;CC=mZZN&eo%XeO zzqfAO?O=vtkUe7}yKqaj=U<^X;8zEvle-vF1E{_r0&G>O1CPT=!2q}BoH>Wxfx-

l;=mmdfM`9H-Wk+%d2IKu1i7=af{>kb^nrKE(C>?w&CTRI znUOPDM2BqA-MR2lzl|PQjM6-`5ynL^y<6vg^YZOCT-fa1A0>mnh7WAljsgE!-uUiL ze{r1AW?ae|?O#v|o&Fa;(t~he?YL0|_jA#r$ZPlR`+Apw|GOljk z9|*;IO*g;tMX{r4k#<_Kc#U^<=2yd&Qb%$Np2Rh-wa*#zQmgU$FnTafbfV|I`}$-?YQfeVfsPl;Kl2K+t3TFE4FlS8+FY)XkR? zB^26r{dvGaeYI)da5X#cBmP-ujTQs#52)&EHbQNk75_fElDs}mI=i+8pb;uW9)a>Z z2r#NY3Z5rS!a`4o*HL3OE1$3z%D%g2NKv?{TeIS}cp!PyMO#mEtc(eMMsw&T(_#*> zE~Ch3iE?}|T^?0&-x%_*`b|nA5n2sB*l?qp8@Fd1=TV;~qYqK|z>0Bd66A@t852o`CgSR%$5C$N)$`uP1^uo$M4 z)Q6h8JKMRx12H8rLy-fN0beL6f4->Zt1Yc9EwwObv}T{|OU*cS%SjvUN#e8UbL&gx z3oiFA6ulo(0~ShS-e1>N5{6om+}&qARQW0wL;pPV6u*_@fxtJXJ7#K?w#Yj_>ez_s z$YrqIchY9j&zK2+&rZ$F-5mFG4K!4ajS1pb*A6z!;xwYqm6vb#r${H{Nt5(gG~Sdv zwfa&}#g+C0?wQY8!J_)rGGpL(c9l9ltY}ir)GeqA3b3gFf{dux)&_Nf_1w?S-qvR0 zmCvX+v`p8#l3is=?#Bfo<<_pZGo#gHEb;PWg>&6vFQt%U z#rLx1VzQ7W&uTrb?N^v;1eb0qsB4?{66UZl4~n30Q{~m&Y4`=Im7;q-%BHB$jt&!U zX==uBNl4wg(T8m=S^Vq0o~&cg1+LF-{imqb&mY+St`G_ja`JCyCT~z=0gXcj%tz@_ zCZRQb4{wVe1jbI~*133(83L7_N({iy8p(SxcH-``-JgjxLf({8aE)n=32JI-X%3)H z_WN$Xr;fxFlHZwPW${0rw-Iy@4fN5vV9fY&1Zgx>71-T1`;@zMG~^hMu+{u~(}=5e z!#^`qtYQ)&uew!jh7t>YM@sxko6N2eymHKkz&(^qHYhirt-T;{ad2|nn|!WpL?iiH z^1~H!hxFLXILth6*zAYT+?5@^n8kCETc_3;81Oe1Muzy{Jaz(8fHjizV$8t3wwz!J zb=sLR+I%@5Rj$3uDUOs?-akLvYhWcW$g#xRLm$)a_Uxm*CmRWhp^sxLO3N$fAux+$ z@8~Midn9xAfUYlYzX~OF+}3^ljCz-+dmd3CQ~X%~hP-k^1SNYGg2c3fbF5U1!n`Dotzn9=3Cg65$&)hA*je7s; z|3R(S^;-&HNpvPfGG_rYqoh3`0$Q8LMC#1VBPT{m<J4szO=@D=qu zsq1u#Xp+aGeFX}M669=-I=seBzkjcZ1mc}K2-R`lk{cFOP@K;i{?x0Xs(?Y#OY6;7 ze;l3eZ_Xd8jS3CB;}~+sjc2{c3Vnu#rL>1KB0*Pyr;W``rzStOP{@otPQeml3&hvpN45xI4*?hfBsUTRxT;8Oo47)y0JOA_+bv z5a`ddW{!k?#c5O;oAV6=@7_(S-<1YaO+G3g&h7(khZ&?n4*VULO249_rRSwE<$8+0 zo%bkZ-M7DRKw!!H2IcJR-+N`!@$@FbhB)Z~EibF6$3r$OFroS73j5hj2Gz*s>=WVS z(IG#Ba*+qseo8{|O0`Oy?E_t67x#6pBRN+qEI+-40^)2!m>2Z}&$v<5N+NWzo`+!Y zQAOg{!@}*uwu**J=F9oG8&go5*PCvT=Eo*I^h2R^BXr zwl*aj*m{mmn!&cVr+p4;mJZ#^WmvdELD~DOOq_i#FtD6<_9C9Gz~RiDXl}S%N3_Cb z&fP;K>+gcRK4y)$DnI~A!p-{+%#*!o_PQr`s$3KMF?Q+Hq@nJ5u06AYg-Obw0IB_n zhwkBeyHaqOr6?UwZDgRQdV$SQkp2TO*85ZT8N3GU=M)p{>j26HX?$`|VQ+X)MOLA9- zx?ZpHcRGula+R7v-HK`riV}T!lnwTlW#ZLWq+ui4wx=V~C$~?kKa(MN_l;%&@2i z)>hT9;@LB^qK3x`lqJ`Z^6Cx%P(W~)V#a+E9zG0kyf79Q3alTYSWmBZ7I{~v>G@rG zErE-1W$L!T7WC&Xhv|u0S;dn2YD-H;T=q6Etymj=cTA(a=WN8_;J5v|wqH}A$4 z#EkKQzgL!A_uxZ}51)V191sM@w~vL!q4Azj5Ewi88}M=9dD(n4uUQ`vhIJKH_wh$# z7}HM=7SgJm z`wfOpI=2;>M02f*IkB zeOlzexI)_xTQs7S$^Qvi)CX$rMn&Ds`j_rBwy8_8^&FFx1i8@C1PHbkL^pA-Ks)1n z6z_?;!xv05Sk)`>A2oxP}N#LJ>Y->f9Hojs~#7~H)hz=hPq0OiEEA-qSUh1zq-by-2KkDMngqNRTm0fUf&a;n4=XmX644YT;2&E-^X%@x*N_MOmZR963VxvcybwXd|f=eIevH~k0>&!wld*NZZ^ubT~pZDz+S4tSDj6YK7oSNy#Wm? zV^ZPS+##u{DOb>PNL2~wwh;q_(M zh7KByDQerd(Wr|cIB@tN$YNqf6$)*H^B@j-eDpRX4pA(i`+*Ox+Q3B zKPZI_1Quw1F5l6`#hvs_-t0)w-9|@{^erzlPteq41|F6r%jGQ<;p%ow`#=CUk>@;B zVbs0kei7e-j*;7@OL|`GBjH8UI?fxnZ8x2%{%~U}lkR^KC2-H;Jj>#`ldaTq%O{u1 zhvvm2(q(4$+($Q_8+ms2a~sq9MN1{JZQV|9R$iYrut0%Z#+#4s-27kwfvDV&=W|*l zznz!z%*d$h*F==bMnW_W_%Wp?1b*HEaEK`8&kN-*#pn>YpTh^bEvk;6@1yybT}4v& z*!J{9MnCHGuICY3_1+(kt1b+t2Z<{;u067t`E&tei?;SJmR=2SVNtSLe8DvRFEbBp zbllriSi8lmXbXr_@h;f<8LDus^M*r|)~36Cv_EWn%fszcUD3>Z-*~Y8S0sJ@CBusr z4G!cLqxm_ML+G87ywA2`qpjzY0sW2Rco~!inJn{0s_8cAJvJAxNSd;d5b-B@pEj&^Ud3E!UbR;iL9 z-<%9hRX;P8eeLlHw{UVOrG9)$If*$c%n2;)so|3lwP6D)lPPaX2cazcV#G^K(AutN z2L-06VmngSTq75j`uIm$L;BPT{z7;I9f*n%H&2)Pt+zG zADva+u}W2qGA7G3Bq@=6ntB|5oAMs3{TBx_@Rtku|8Uii9EQu@QYQU(qlmy_$i_4TV2B>3L`F zG5pN-+ARJqbDhH{5nd7g#Y=zsy-9sU%PR}cpaz6Jagy^~-&Sg&)O<`epX1)_`d)q- zAA!~i`66K{3M;l_Q^F-kQ|ulsa9|$y>*#pv8J39u3BYa+;#mO92}nGc6!WhChp!yI z;c^?pQ$9NnTA6z%-%IA%YQW8h;N_84KE&_5#Z=wU=^p4z1h2)7%y96GytI9&--c-x z+-1O`e;+<(7(E_w&}}X4ax0<*3L5o0j67(Bw<8~mZKtaie?0$rHG}=UYOeC9_j36% ztMu*dG$KI1ZjiPfq|?EJ)NvYq{XPDe@U^f?<9$N5C=PNqwCzD{0|sU(ji@MuqyA-d^fp_U!ukID=L9oj zlEkt!Ct|*|d2;V739Tz>hr^9%JH?RHXij1#*^*$?UTQi=cK~Q`cu1;=)*DAZV=;ac zU;)js+1kdwW~B{uw|FN2Ob<~^o8 zkDdc)e&eFFxlE<_*YMl8_!_@epmzw6tR35z7psC8(?|cJqp;$Ed?;jcNchMxld=AI=g{hZBJ({fie&YwhRb z!MH@bS@%^T@HHr$;~uCIg3Ms04M+jlb1W-#YL-sXrX%8(djAEN0+$iP--zI-hSN8MGRabjtN9a$->QeSUEWsIqpK!HZA&in z;iu?~gMHq8w+iw-Y0Yu_3U@^}w>s5qgbZlNO&0GkrAMm8*hX zXP6JFwMAaw(=z6Ctm9+Yn2YtUop%SjTVKj+wk58<-dUJN`QyOk&YH2GVSvgw6JJwb z&y6}SH+o=*3+iw62osiV0eDqA0ny zY`}SbV`_=AG#zK^E|!9d@%N>`BMf2)&h^{qahC(OuOtuc^M-o? z^!jId_v&v?OL-^22-G1?R$HU86(KZ5s{<_T_m&NBJtb&o{;#Ac02Pu=&fkpZipzBX zT(`Gd%cRpgsM#Y< zh&DQVbwR-o#ThcI`PX8Euyl2q$8$s zz#9((5YL-EEI9B2meLA@m%-M;kJPmbiK>~eu|Q_vn;f)X1p^l>JdOKoyEHE5#R*+d zKRd%Y>6n|kr_9#ZUCUuNSg@$JhyhRT!0Oq<{2~i?klMv2@%>mum|KlBQYPHARE~Ei z(XNLkUcDxPNAJldhl0$6+L%sh#v_euFweC1e0)Hin z4Ym+0`}98-;5v3sWp!08l+*ail-(E|qn$1=AdnkYItdki)1g^n+OmUtI4c1`zGMq7 zPa6JEddR{TmYI3AXmZ};O2@1}_%1#6bnhAc%!Hm;eIPX?c{ai}?WTvOJgSi-Q}bVYTm*ESfqs0yO)hjz9*}7ngFYF1uk(xr76?BdVP3YP?)fCm z>WlWX^k4z9*ALxYnHN?ot5a!knIN=RFdTHBQ5<-0&!+J(6960g#o3=@zh5l|kUR(9 zm%^Jr<%7{O^rPuHLVO#~wFa}3TCmW1Df#YNmJ0I3L>6Q!nN%b70Z4^lS6dBTMBT#Uoh&S)>AuGFA?VOmm;gn#7HB%V{LXVK7>ag*@VhlBHY$>wd5^H!^sxnN%z zw@+}7eEGSqY|C^2&Y!|>T%Bo27iH#`4mj9vYm3<5C$q9Aq#I0g-?>ZTDouacL_~P9%YKlZ zF-#0Z;~o24y87cA)KLBiZ;yurzBL%X1Nk_S!z^JX4h|IG$el4LJ_maqYXY6nm|MVU zO7Duv*j57*2%;XJhJ4HT^YombG7`YjWb~aPl%f?)(fsbicqh%=br)7`1$+c5c8JvO zejj5-NSSoj4{g6!*R2E3RyjTg(SyJ2j$ZkUu&8v=0}8S)2^B|{TbxG_SWHb+jrdHk zbk$-dFy?t#e;Hrqk!w=_ z?C!E8zqjnLuNWgHNT1FZ0FAVeM#3zFEfG;q)t+}othG1Ph=O(~%i}8ej%Sq2)8ElO zN(+=er_@68pO~pq7@7<*{%PN79V zJ2EmOz<{H4Z@kQmjm=uHfuQ4kx(A>@jMEMGo1{k*8&^Poa`v2mTE!!HT`;ag9CSwE zmlUT{DF^vioe(P^{QW@EnFFS@63|8yY+|rqtw~>KNLS2l@r9oh0(YnG;&Slct9}J> zK945=be-|_M}QvP)uJ?yGOE2>{I!VXSv66pL$VAKNi=AF8U0tob*G3z$j8N0Qb4Wt3(4368HO;Ak0`t0qs{x_yOoydd;Ue0fu@gI@H*oI5*_TTWoNJYcy!CrXH)j& zi$`9Ej7kpYfjc;A$66SI&W%>S&3P2T=!U&ikhhkkt+P@5WDuBFPQ>*$;-OePK##O{ zyq~#sww-S{>Zf`&j{z90OX@#ZUJia#tq}0=Qy4DL)A^#bjF;)MJRTN#+bw;a6{|{E zVhu;#bnDZmXIV_<{kGgAC43WFN#_$TXC8-#7PvkGF?f?BPGc_iL;oJ3C_@44H{mM9 zh~>Th>=WxVzp)O*#-{4%h9mIf$(Mw5PK9+yb{X|w!=tYf^PI^By8!ZHMgN>;AJ<%$ z%RLHt(8Dv3YmQ&*_C>c(#<&=PU}hiI@vw>2Mte**j8!U~Md}z#mD`1qAB5qJrc}F^ zok!PUgW5ks{q}9vid(7FvVcCMC#k?(p}r`-dsKCdJD$cviPL*ru_(N@&}y6}up%1f z14Blz9xJ$GHvYn-NU)E$9=2P6YSD`&C5Of5Kk45tn4eQzkW-|LV$tp5HFP|fxHc9P zucVUQe_9Zeg!w!BuXbioTm@9J1^T-6_fZa0=Z6-ZfbPcK`oScMiyLU4q(S~r)!n5#BSYmv+u)}a@uxk&T^bf<*KgnZrYR!OhwXfZr>$6 zpH7#Z7Sy$uSHReKl=HLWRYv6ZLc>eBs*X>2 zytkk4^}e05DWmc`=GOS-4B&tF{G0?da@(@~wQi0%r0PSaAl9(>Ah$*hmFB@D!+@Gs zn^9Re^&T4tPW5gboSu)6^&;*6vDYLL>7-v<2uvN`-r{^vxcxq?@uxC=0=niytPq9L?fE*Bz&ip(O*1W& z#pCcnO{jfkx*uvXOwneqSQRW_abmp1fS<&*n~hy;#T``iwB$Jl@liBac0lo5DfLXp z_lZkj{@qZ}wMe;O-s1h#aKnJ^wWH*FOh}bc!F`O!mfL*a;SIRlv%{NrsbALN1a-0B zeT@mUy+HA^3oOCQO@^yx#Qs-YVs45ftvMwC^QuA%eVRQ4&9D^u7@t`BMjad*d>I;w z?l*jz3$zmUm#IrOo*NGrt9bFxk(7>QbCn}d{H?j&Z&nQ^0+V07mEOmy{;%|(NygDA zX&P4UU6L?C;gT;T^5WiHt}M-zhTWd(G$XlmUrbRN#832sO}n zw4O9hM26_>I?8T2}h6wrocFr-eJooo1{-pu$5KRIOKKqTDAnBlj?DY95kw>AF4JL~M$leSg>$Lp zM@-$%w+C4qNzH7s2k1I6gS0-jL_Z9>MG>p@ONHb^xb#D(`?qGQqT$4*yg0YCO7Ae@ zRg+RIk$uqVL6^LA**Z@Bp{9{rlVAHo6h+&kQ1eZq&!bOmT?}=sVIuiEPsyJB6IWr< z9ZTd}VT1QN{;4Q80gC@TbBnLmq3KLNR#-{a9pVT-v6Y9E`A?DEXWtE^EV#Bvf!= zDI|z~B2$gV*4g5)JReJn>~X&|Y64=sH2X3?+O^qtEVLBG31)))X)kxUwuO?i=Fu)l z^g}3iuRZ-+fcVSywszdR*h`PYQhn z&BTBo_I8c$KF0apQbHY(S2CdU`yT9i_BH+bMj)bwvWn7@x@V;jvFM5nADl>$^*p#9 z=2$-~ntJbAflktbgA#cfL6FJgWMH%(vnf$*WOR*qkp}&GyI z+1Q#RZbdjTqD98jargPvDa<0lS3)@Ukyk0|q8mp3?_3+kN7eOP_FlB7t_|K7N1I`! zSAG*$`YBsVO}tInmNrjsZ=;{?qvHfH#Oqo&5%zv4Z|o=?}=DA^zTOih8?T7 zpPa`?VLiGlR}cOs1pXhq-ZA~nWI$hy^^kw(`%fAg`Yo6&Iyn0O%rzA=GBVcl?iX)q zd8GY2SMItl$rrfV(jRW#aOk9Uq1gj{ZO}RCsjE!H1xSeq+$cWo=+4C7JBky0T|qvFSSPK%;XK*j73&#_Ih4eNIsEum zUht)4#B*QWEqrKVUL$Xm)d2Z$3^#A4r71l<;7+x=H5&#x_X8dHOm^rO!(X7mP}Qly zGyBDP*$)T4upewzD6u@D9&tSr+ATk1z^|%}|03=ylP3$4ZZ#*)KbvIG^_6>gLD02PJP9iMHPvUK2rxQx%)F`7Yl-9`-Ilr~a>@)N5;g zeEIrVap9uee5}Uz&xRK5m$tlKKSHN1^h6fPedw7i$$j9bZ+W`RgwhgmVh=KB z35>o_Wy7DiT{f})Mo+Iit-0l7*H-Tc9sD)E7Jh$aCPaCk2`5)(Ls5nmyrDL|i21S6 z#%n(QE@>^lg$}x*b%h*VZ9r~m!%W!TA7gvzKbf#W2gX^{L17XxW67tjQ?={sr6lKT z6DP585s0O3w|)b8=N)Ms&klrmmt^&+oNEnGnR;hsStwHHZhrLrb9J@Rvya@o^Q0IR zaA&j4Gm<@`STFmAWG4H`seB{VlC$cGG0m7&UmF4OcMYrd#ies;exkAZ>fxw2ExDg3 zaz*S{G}5Wp~eK&P9%Y1*T zvOrnsU&GtTL6SBviz&XE{JGkudpc&{%tPZ>?1doPL3GJBD$S7nx4xIJp_tIM#i#)T zg6Y{EkVav8kyRL0X+EwuR?vptjV%A0o3?~~6(q`2;B^F~EDQ`#A&8>Rc01Rynb3Q% zthcrtYkHQUAkRk*76K2n1top<1?}b?Ded*fq{UR z`Rd!<*WBluY+D@j9>i`LVb-=}Y0W+Hd=}VS?oXfD7iZ5Icsjov!dp0H*l#>N;OWPm zDHSWvuK1}E5w8J>PRt1V;cB>UU-}vsZc67UuIq{m_ndkbV@*#2zVbRbJc9u-5A(J4 zVv@n0gA5J(sI`8ZPb4Ctv-|$<(4yuBh7Q zVQn#H<3j4v=`Xt=A2BQz<29=@vU=>ZtZ(0If@r?F=W9s!5Fz)Xlw;oh*5v4m7Fzqb zElNZ2&$^SE6=-;0axC1T^zfoS*^AY);w4ru_;g_`TEwKW)P6BA9+0lN5-WXNB%#t$vus zX*5Afyabo3sAH+Qvxn=NazQ^@Uncd4+~u&kDc!P}^NM|l2k*oE<&O)tyFvK?{nD-E zEJ_aP4$nYcj7_-{_uKIFwLPr6phIUGy&PA=B}rurG)`}ScWZAW6Y^C0Q!;cycGkBz^w!fN zkOs1#zA(3%N5wG`PNf%ERr(1Xy?Yce{`C)X%qyc}G>Y#=`TiCBEgSU1`ki@2HM69` zTJgJ8Oo^b1)VnLV8wc(&u3;?_xpPI#J8iv4;dFWZR>a}ObUK;R@mv+yD4=7j0v%Sd z>u-@E_l((>D$5Kpgi;R3!JXc|7urx*UX6vgVdbEcTJp$65uUn`R@)b)7yD*wQQKy^ zsjOtuYi;nsMgoH=WoYIq#3PuU;p=Q=HAOkQi@LFLp;u8WI)f9JE<3m&AoG`N!lSahU3bT3_Dh=*O}FQxLUSt2a_nc7ba z(05Yl_Ah@tfLt~{oOmpx0BOVr4wx|KVDOX-{6M%4dYT|cme%<5OiAY_3&cIl@(#v3 zSV|=V)j8V>R;E?)(e1t#cIy@EzMJJ`%Udpb?GcqbWk{-z6Wi@z!CJ~S@Tg^c-?}zo z`8=&-Y%g?^e|)^(WL-gXiAnaFJ(X5a7VRcSFU1Mb#GTFka(QSGMKv@ISe}b86Np=u zAG@H{*RMn6`VN|DQrmr8i$9h`K1Cr)=++>WUF;nv9v?~RQ}}*=j((CkQYy}72hHU3 zFQ~z4Op~UyM-%FyCv5H~BODab&XI-fY=i^ukAV1y@XyB=kt92pz3@ zL`BUf!vf?*H#)B;wE3`am2tJeS%glfocCpz+L~CaGDUqtn!V8a`(sIznER6;bu)H<>d+QeegF8WW~mZ;J^$PCkz-UR91FABlUX3hJwkp8VL9)#@>Lj$iy( zTre`nUab{z^|1ywMqEq1#)z4ar>n=~w@l#;Q^Yc(1;ehw%ys9la$*T<`6AP8LB_Ku zc8^3%I0Qh z<*ZC#nBFr@U7x3KNdev~bc&`_9Pcy8=p?zG%F&z9FdWb2WF@-CyBOJtSyYzqRDIMN zc=r@z{o5Qi4?dxqJveUOU|;QD2v6w`IhP+P*XST*_&CIyFO2Yfnmm;kaCIuuvsE_z z(XGy!_Vd8jTNnQ%myAiLwQ0zkZzl9YOL4hOz>b%i$b)e`LDB8a6|M3{9%f5wY@)(yTF5+_d#%Vz>LO~F%!|N z=HgHnJ|Wr8DNoyO|J~s!C599;=Vv&4#0>ca!K_nnj;ZUq{Zp?_KQHUgEgWh@dE|V4 zVm4F4Z#R$E#pw8w?h)Br4FTIr6Z7t=Z{#Zjaga&Zs3Kk+49QZd)8E7SABPN1LbvcQ z`jG|GJPqvmuB_gVtOh+H9|&?kKhx-(63wA9j8JKsSa6r>4gECr=jwIHRs@Hmf5~*U zby83FRu3xGwR3o=JlsWey@>apTU2t~U?pl%{o)-@RJw;<9ygQkpBgTqbmxgFU$lH| ze!yL8^UYWwdO4AdPKPz|z2_r8(gPBI~trcww71nfa<4MEc+Q@)o8X4CR{C}ihn;HnptD$M>Xyt zrRe~P)-uYlt%OP*Rj}8oXiX~`aOm&c}X2%fn&B1&ym(Oymp28_|$cg>N5qW>6wUKY~#zI zm&&`LV~ma=cdWTSrhfLT$&n1^r}smCkKh#dGCq@QjiHHVOZZH|nXSc=EqlVY);`?! z#N~S*G`u8orIL1hFgOBGxfSVI9fH zCt2osW|u4(M8lVH=Q!cJb$&Fp4E`^w{dx(E_EStl@|iiqS{)D9;{vx`o~fJ{~Cb&?un2tGT>50>*15=#m_>9zi21o)jvU{z39Oz;-;#97l> zMR#<~U)XziLP=AT9>37dKi!5~(&D$~wexPC9P+@t)r`CEp%Qak%__gZ=A`C=9nt5! zARTc*D@Cpz^HRbnsv4uNe3Wu^@LEtn^L>-oVo85;>q&o`Na$$p@~bZO4;=_laouCE zZ=8Jp>69{ov0+Zz^A!shGW5Z{N_p+d>@YU?V_}QwuC4mhuLZ(7v+>ee$Ceh(@{M+H z{2+}b0?sjde{Vu3!M=nPt!aO=;~o)%>eAS`_?&Ry1Orh6id~Ln{)6?7B zZ0&Y`7(l7nav<~ZFztQOn^ZXpJJUNZk>K8H9xlAQjEk+N;($&n3UK2+*K2vFni|@O z>{u^%!L5jTHaYcds;y`ZVf}2{0+WvCl%Ip_M$E{QSF1w|zh<=7gaBSDu_&}p6Z87j zHd5JT{fGb$9*KjtKH(-?pflD^H1a-n__jIbg1+#^(m+tsA|@_hU0vPUp{`@8TU}*7>piLO zZ&jT7^j#~0KSvn!Y|aPCh(n2uDdfH+Mh*LM_VZm#332DxQq620LwSNvq=dk;B~ zD#Gt8!MyR`9nLoGa~Rufzh*ygsQadq=6Z(;a!+s77h53)Yw9c%BMSUn&ASa$`?q^V zF3Mo>)DRVeU**nlcQv1ig5_2T20;Zy4QUxbdfcrhUhOU6md5TNb{(N_;l<(}Q3ZYy z8|Kk?V>VtrJSwPJD?N~?B6ma)!Z**aL#G6I3%0OCS8F07GSftvJ88BU>%lSHpwD-xZi7E{jhh@X`|N&4ZL6jBxb%6`3?e{%56 zE4?B5S>Mkm6uH0P;J`bxL@hM=M6!wt)0yb#-4Tp8+MebS^48f!ySFNA=iRU`Y{ntg zIK1wCiByo6J^RVUeY^A^+v9L?On3tt75LCz$k0z(J2r^ep%?E2qT)RgsAd!}?*b*g zVTuciGGjaUv)h++p)WjRzr9$GRQxS0$b%4;`oCeJc0Q5Wp>zRtnr!YerD%f*-+55) zoXUVVG^T5DNCGT8wxEqRo9$&t-c1sqs9Nrdnb|K7)DyW<*8&vpbBXK349T#Omx)wwSLY>8)^`_GvQt{u> zPw{Q_asI_f3x-Av3*M`kZ9{Ck5K#lX*RC?&A5XyKwGj^zIQat*~hO zuPejNMFKuk`4xoX4H^+jU2$!mC~>#VHHtNr3&nRO%ctX7^t^oYsdUkhSna6qv;v)E z$GOJC+utt*`wOu?F@92b>unxr{>(}&cWIdxRnY$iT6@I- zwMOh>Ufa{huqmzXZ`9V=tvaRXH5o0UkNTKcjr_vPOH9C{B!f5zFvG@*?#f#`SX(z_!T zaofa7oW!$6ukj(PV}X%7tVVwEn)98<=;@#CkEvIBG<4k-C_YN@h+?1KxjW+U+c>;l zs&nFUx=tuQy`r!GP8>~Na3eJ7lUGG28~9U=<})bK8%jfK zEuppGNh&7_Nc;a|W5Z}V+~CzvcnVf!WrBrf@GM$}kFsT}UrnxXI7_y|7(m|=#%{2DnH7E32rM)nBF79)e+I4AbZ?(cjgUj{_jdDMGBt?ZWxkj3Rd*=OuN<1C|1^$DExrCWE-}7RdaZw&1M6^=**hPu>@CjMnnfIthE2^<;LyAEGX;n}8 zQs$0>d>bF{SB*lGgL%0Xd6dwcQvRN>Au4ei>@}PD?^US>WWbcEW#9@=W}O6y+tXkW z^A(|UW+km-jT>z%%!NwK00&9X6_Y26oA+$&3nqQc@!GtPSBOEA!lq+|Gkb-NQnI6B zROC-bmA&fb<1@%Imvpq^L$B|2IK$gvX`W$H7$Um=AT9 z{D18*QV@|6Ke8cz_>j4{^Tk1YX+qtN!RYX;#%OWP57A*halZXp(;D>a6LeL$GeeEK zb{hz;3%x-N+gCFj*~ZgwB_%CVo~Rsr~MHOvR(e*RyTomW)T&DzEP zfe`6UKmrIzi6TvU2_F>7Y8y^RU@q~E1{QL5zQQLMlXf_T>POdMrkg|E$BatL}g zwBp!s5Q4T0L(x3H$p9$CZgK)#a6^3!2_%a!pl`*y9Pz1DU#e||=fIoZp<^Wok$vXq%8DJd+F1$;e zFmT(@wBbD&FaxaS5ov4K5?XSbz7*eT<5-O7DDYL8483kfj^2`9kzH84Q8&*c%mDbn z=aOxBIz&?T-mlx0L6hX?4U>to9@1Ahs4H5oCM!NIcV6cNrsfX@-7+BPsw+~Cq#qq% zF61hlR6hYi99>=vOz;q|D$136&dS4tH7*GfI9b!+X81?P`g3RuwE)kqa#}GRpQ~1Y zl<%`rSlg{4&Ts6fab>Nv>*`L32Tb(T1M(xG6GvoWpXc`Mi0ROp2*fXfN?&it@u_-Y z`ovwDfQ5b#P43Now5Tp4&aNeRwEyv*!e* z+KA(mqJ?2X%>Acq4Q>Ghjq0F}G60vhFwSNuD)BdN9~iE`ZlY_tJQX8M;~MIV%<_ny z4Aa}U+vVU&W1q`Wm|{QtS%#Vehz~L4L6%Zg&;rmn_4eSIQYC1-^-d-hROBWk zWC1w0XH$@)9mps-f!AUH7=i#Z@0D#E{W{rC_o47ByRQGZt~ucAl(g=feslfiwS_1B z**XF`1)I_waFjpN!ZUAna%jtbRE4IrHj-Lk!PsX`-ppU2zYcTZlxvHePrkF=;gzi5 zb8*B|px>!XC;BQl#Kbb=6O0R!Fru>S7v6eW@TZeKO(sv^Go&47be_+rbShc+fNSIw z11^kSSK8zLhh4aze-l*D(?-y=D12aV64YSt)w$Cn8VfB!Eq<0%PMQ=rj@f-byqCv~ z53sUseCb4{aOpfeZ{D_h35F=K&^CYJJz=Qkg%aH&GR(+1!ASmCUTG0RPUvL9Pt(ZE z)^`-DTAdeI{B7Mvuwx;^Xuryn>5pfr!!f(?tFk~W!xC;0E}Z<^vtkt3ovUZjWji<~ zMs@LfO!kQXt3&r_17r&)1~>1sNR8OJX_X5>nC)0){MDd7I}qhg&O1ecKBNUCld!gq ziVN%U=DAmddh^%I4lgOZcEbNzs!W_{_b2YU50x6ZJQ)~!p>vexhkFA~jxkMn$$vI) zBGjJ>mGSL2T*I@uONj_Tssi29yy)^+U2`+ zh)-vj>oqR$>=P5e`fz&FtP57{Au4)8Cqe7QVj+!d6BJfB@* zwL6yrRzH_yHou}%OlWaS693<1#H}xd9h?~Jk2&hMvm;2^opzm~VSE7Cy~fnxyo;`ktn7h48N#`O`SrnIjg?Y~d!BtX*Y6 z4Rb?pq))Sk7~~tmWjI*gZa=qA>DJEE#Ycw_ZFMr!8xEzI| zju{gl!(=$)bLi33G~ss^%hi003@UJ$mBrmTISe8m32m%9NPxPEl8bsNm3NEVWtwlh zW+O(`@Spq0uBw@n@lzI02=iC!HpQ}{jq-Tjos;^fIV}L)Gu7n!&#dUh%UpW;tm4^p z3_Utk^iL&mOqdwakS@Oe;)b6{1&6Ycciyspx{EhQqWYv$v4H$AQmHpo2&>(lMIq7g z5P3Z8nb~8Urn__&?l+MYwjJ2SQ(Cy zF&d^ek1D116mdm{M|Ls|!JpoUgxL1G6?m^iladn`amL5rNx)~1 zy3=|?aa&nj5x%vOuGTvjScM&)d5N4$!>lIy%abi$c#%8l614{OjdNo!c&WbMzSdh)$NEc z%L;U;^|}U6xo)r@{b}z{tYcSZy&%FMCE>p}Ijt(769O159#sS54^kKCJ^rCsLK?HR zG{9@4vsoO?lqn`qekL`>Oo1$XaArKvN5shMyI3uDwI8ctkZ8Xkp!`K@t&r zp{sA*yKMtq?Iy87PsJg(N0%7wK)(Fi9Q@U5dmg(3ot-Ne0o)0a!8sT*tWV*AA;nm= zx!0r31r@V8&n@~lv?T@*AdJ4q^bfIwBc&Fam+Y;W)hg$BznlS~fg{fGXDCMuCP0Aw zxgy=llSA3IL)d(?fw5Jm%ex=nxXumIdd*{KHHqkgpJiWX$6oX}@<%A2rQZN6t{tI$ zb+0v0-ZEW7;Dk7U`8$o_YxM(6bihi>A#?|{i7d-cHE)wo?9XCJ(XskjA4n(uv`nVo-%X=X zuky>K{YejU-KKhP8&9})m%mTFBQGfc1mi#>ev3rL1Hq03uZTy^LiZpS-wu!qA)5tqQ z5M{yGol-NG68Q^`b!~~g4*8A(+|y4{o`JvWuAKTlc5hyFO;qQFm_DRyGP%BVYpwV7 z`Ow<;d#PItvEIKdU#zA-mU?R2@>NPD%K7GjYGy~mv|o$gwBcR4Y)}eafrdv^z!0F# zWzgq$S^JUAwh}C^^V>{(v(oJF48e%FqqQ(sWc-X_hffFz7RdD#%aZrf8G`~0?qpfR zCx(zgpr3lIxIz7$3q%HXm7VNaH^W5y2ahy?eXCo$V8qzc)IgMHhoz^qYFO@8vA15C zWb%2sxUB3k>`w`a{f+7r@AGF`eLw|2lu`bSkrK?u`t5ck%(Vi+%b3%(aj|y6l?r-B q+E9YY{(npCMV~6u|4#LEE)lb^DcB;r{{u> $GITHUB_PATH - - - name: luacheck install - run: luarocks install --local luacheck - - - name: install cargo - run: sudo apt-get install -y cargo - - - name: install stylua - run: cargo install stylua - - - name: Install pre-commit - run: pip3 install pre-commit - - - name: Run pre-commit - run: pre-commit run --all-files diff --git a/mods/futil/.gitignore b/mods/futil/.gitignore deleted file mode 100644 index 7cd56c2d..00000000 --- a/mods/futil/.gitignore +++ /dev/null @@ -1 +0,0 @@ -*.unfinished.* diff --git a/mods/futil/.pre-commit-config.yaml b/mods/futil/.pre-commit-config.yaml deleted file mode 100644 index 6d4489f9..00000000 --- a/mods/futil/.pre-commit-config.yaml +++ /dev/null @@ -1,41 +0,0 @@ -repos: - - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v3.3.0 - hooks: - - id: fix-byte-order-marker - - id: end-of-file-fixer - - id: trailing-whitespace - - id: mixed-line-ending - args: [ --fix=lf ] - - - repo: local - hooks: - - id: detect_debug - name: detect debug - language: pygrep - entry: DEBUG - pass_filenames: true - exclude: .pre-commit-config.yaml - fail_fast: true - - id: date_version - name: date version - language: script - entry: .check_date.sh - files: mod.conf - always_run: true - fail_fast: true - - id: stylua - name: stylua - language: system - entry: stylua - pass_filenames: true - types: [ file, lua ] - fail_fast: true - - id: luacheck - name: luacheck - language: system - entry: luacheck - pass_filenames: true - types: [ file, lua ] - args: [ -q ] - fail_fast: true diff --git a/mods/futil/API.md b/mods/futil/API.md deleted file mode 100644 index dea83d01..00000000 --- a/mods/futil/API.md +++ /dev/null @@ -1,469 +0,0 @@ -# WARNING - -this is *VERY OUT OF DATE*. this is a mod for my (flux's) personal use, and maintaining documentation outside the code -isn't worth the time. if other people start using this, i'll reconsider that position. - -## classes - -* `futil.class1(super)` - a simple class w/ optional inheritance -* `futil.class(...)` - a less simple class w/ multiple inheritance and `is_a` support - -## data structures - -* `futil.Deque` - - a [deque](https://en.wikipedia.org/wiki/Double-ended_queue). supported methods: - * `Deque:size()` - * `Deque:push_front(value)` - * `Deque:push_back(value)` - * `Deque:pop_front()` - * `Deque:pop_back()` - -* `futil.PairingHeap` - - a [pairing heap](https://en.wikipedia.org/wiki/Pairing_heap). supported methods: - * `PairingHeap:size()` - * `PairingHeap:peek_max()` - * `PairingHeap:delete(value)` - * `PairingHeap:delete_max()` - * `PairingHeap:get_priority(value)` - * `PairingHeap:set_priority(value, priority)` - -* `futil.DefaultTable` - - a table in which missing keys are automatically filled in. example usage: - ```lua - local default_table = futil.DefaultTable(function(key) return {} end) - default_table.foo.bar = 100 -- foo is automatically created as a table - ``` - -## general routines - -* `futil.check_call(func)` - - wraps `func` in a pcall. if no error occurs, returns the results. otherwise, logs and returns nil. - -* `futil.memoize1(f)` - - memoize a single-argument function - -* `futil.memoize_dumpable(f)` - - memoize a function if the arguments produce a unique result when `dump()`-ed - -* `futil.memoize1_modstorage(id, func)` - - memoize a function and store the results in modstorage, so they persist between sessions. - -* `futil.truncate(s, max_length, suffix)` - - if the string is longer than max_length, truncate it and append suffix. suffix is optional, defaults to "..." - -* `futil.lc_cmp(a, b)` - - case-insensitive comparator - -* `futil.table.set_all(t1, t2)` - - sets all key/value pairs of t2 in t1 - -* `futil.table.pairs_by_value(t, sort_function)` - - iterator which returns key/value pairs, sorted by value - -* `futil.table.pairs_by_key(t, sort_function)` - - iterator which returns key/value pairs, sorted by key - -* `futil.table.size(t)` - - gets the size of a table - -* `futil.table.is_empty(t)` - - returns true if the table is empty - -* `futil.equals(a, b)` - - returns true if the tables (or other values) are equivalent. do not use w/ recursive structures. - currently does not inspect metatables. - -* `futil.table.count_elements(t)` - - given a table in which some values may repeat, returns a table mapping values to their count. - -* `futil.table.sets_intersect(set1, set2)` - - returns true if `set1` and `set2` have any keys in common. - -* `futil.table.iterate(t)` - - iterates the values of an array-like table - -* `futil.table.reversed(t)` - - returns a reversed copy of the table. - -* `futil.table.contains(t, value)` - - returns `true` if value is in table - -* `futil.table.keys(t)` - - returns a table of the keys in the given tables. - -* `futil.table.values(t)` - - returns a table of the values in the given tables. - -* `futil.table.sort_keys(t, sort_function)` - - returns a table of the sorted keys of the given table. - -* `futil.wait(n)` - - busy-waits n microseconds - -* `futil.file_exists(path)` - - returns true if the path points to a file that can be opened - -* `futil.load_file(filename)` - - returns the contents of the file if it exists, otherwise nil. - -* `futil.write_file(filename, contents)` - - writes to a file. returns true if success, false if not. - -* `futil.path_concat(...)` - - concatenates part of a file path. - -* `futil.path_split(path)` - - splits a path into parts. - -* `futil.string.truncate(s, max_length, suffix)` - - truncate a string if it is longer than max_length, adding suffix (default "..."). - -* `futil.string.lc_cmp(a, b)` - - compares the lower-case values of strings a and b. - -* `futil.seconds_to_interval(time)` - - transforms a time (in seconds) to a format like "\[\[\[\[:]:]:]:]"p - -* `futil.format_utc(timestamp)` - - formats a timestamp in UTC. - -### predicates - -* `futil.is_nil(v)` - - true if v is `nil` - -* `futil.is_boolean(v)` - - true if `v` is a boolean. - -* `futil.is_number(v)` - - true if `v` is a number. - -* `futil.is_string(v)` - - true if `v` is a string. - -* `futil.is_userdata(v)` - - true if `v` is userdata. - -* `futil.is_function(v)` - - true if `v` is a function. - -* `futil.is_thread(v)` - - true if `v` is a thread. - -* `futil.is_table(v)` - - true if `v` is a table. - -### functional - -* `futil.functional.noop()` - - the NOTHING function does nothing. - -* `futil.functional.identity(x)` - - returns x - -* `futil.functional.izip(...)` - - [zips](https://docs.python.org/3/library/functions.html#zip) iterators. - -* `futil.functional.zip(...)` - - [zips](https://docs.python.org/3/library/functions.html#zip) tables. - -* `futil.functional.imap(func, ...)` - - maps a function to a sequence of iterators. the first arg to func is the first element of each iterator, etc. - -* `futil.functional.map(func, ...)` - - maps a function to a sequence of tables. the first arg to func is the first element of each table, etc. - -* `futil.functional.apply(func, t)` - - for all keys `k`, set `t[k] = func(t[k])` - -* `futil.functional.reduce(func, t, initial)` - - applies binary function `func` to successive elements in t and a "total". supply `initial` if possibly `#t == 0`. - e.g. `local sum = function(values) return reduce(function(a, b) return a + b end, values, 0) end`. - -* `futil.functional.partial(func, ...)` - - curries `func`. `partial(func, a, b, c)(d, e, f) == func(a, b, c, d, e, f) - -* `futil.functional.compose(a, b)` - - binary operator which composes two functions. `compose(a, b)(x) == a(b(x))` - -* `futil.functional.ifilter(pred, i)` - - returns an interator which returns the values of iterator `i` which match predicate `pred` - -* `futil.functional.filter(pred, t)` - - returns an interator which returns the values of table `t` which match predicate `pred` - -* `futil.functional.iall(i)` - - given an iterator, returns true if all non-nil values of the iterator are not false. - -* `futil.functional.all(t)` - - given a table, returns true if the table doesn't contain any `false` values - -* `futil.functional.iany(i)` - - given an iterator, returns true if the iterator produces any non-false values. - -* `futil.functional.any(t)` - - given a table, returns true if it contains any non-false values. - -### iterators - -* `futil.iterators.range(...)` - - * one arg: return an iterator from 1 to x. - * two args: return an iterator from x to y - * three args: return an iterator from x to y, incrementing by z - -* `iterators.repeat_(value, times)` - - * times = nil: return `value` forever - * times = positive number: return `value` `times` times - -* `futil.iterators.chain(...)` - - given a sequence of iterators, return an iterator which will return the values from each in turn. - -* `futil.iterators.count(start, step)` - - returns an infinite iterator which counts from start by step. if step is not specified, counts by 1. - -* `futil.iterators.values(t)` - - returns an iterator of the values in the table. - -* `futil.list(iterator)` - - given an iterator, returns a table of the values of the iterator. - -* `futil.list_multiple(iterator)` - - given an iterator which returns multiple values on each step, create a table of tables of those values. - -### math - -* `futil.math.idiv(a, b)` - - returns the whole part of a division and the remainder, e.g. `math.floor(a/b), a%b`. - -* futil.math.bound(m, v, M) - - if v is less than m, return m. if v is greater than M, return M. else return v. - -* futil.math.in_bounds(m, v, M) - - return true if m <= v and v <= M - -* futil.math.is_integer(v) - - returns true if v is an integer. - -* futil.math.is_u8(i) - - returns true if i is a valid unsigned 8 bit value. - -* futil.math.is_u16(i) - - returns true if i is an unsigned 16 bit value. - -* `futil.math.sum(t, initial)` - - given a table, get the sum of the values in the table. initial is the value from which to start counting. - if initial is nil and the table is empty, will return nil. - -* `futil.math.isum(i, initial)` - - like the above, but given an iterator. - -## minetest-specific routines - -* `futil.add_groups(itemstring, new_groups)` - - `new_groups` should be a table of groups to add to the item's existing groups - -* `futil.remove_groups(itemstring, ...)` - - `...` should be a list of groups to remove from the item's existing groups - -* `futil.get_items_with_group(group)` - - returns a list of itemstrings which belong to the specified group - -* `futil.get_location_string(inv)` - - given an `InvRef`, get a location string suitable for use in formspec - -* `futil.resolve_item(item)` - - given an itemstring or `ItemStack`, follows aliases until it finds the real item. - returns an itemstring. - -* `futil.items_equals(item1, item2)` - - returns true if two itemstrings/stacks represent identical stacks. - -* `futil.get_blockpos(pos)` - - converts a position vector into a blockpos - -* `futil.get_block_bounds(blockpos)` - - gets the bound vectors of a blockpos - -* `futil.formspec_pos(pos)` - - convert a position into a string suitable for use in formspecs - -* `futil.iterate_area(minp, maxp)` - - creates an iterator for every point in the volume between minp and maxp - -* `futil.iterate_volume(pos, radius)` - - like the above, given a position and radius (L∞ metric) - -* `futil.serialize(x)` - - turns a simple lua data structure (e.g. a table no userdata or functions) into a string - -* `futil.deserialize(data)` - - the reverse of the above. not safe; do not use w/ untrusted data - -* `futil.strip_translation(msg)` - - strips minetest's translation escape sequences from a message - -* `futil.get_safe_short_description(item)` - - gets a short description which won't contain unmatched translation escapes - -* `futil.escape_texture(texturestring)` - - escapes a texture modifier, for use within another modifier - -* `futil.get_horizontal_speed(player)` - - get's a player's horizontal speed. - -* `futil.is_on_ground(player)` - - returns true if a player is standing on the ground. - NOTE: this is currently unfinished, and doesn't report correctly if a player is standing on things with complex - collision boxes which are rotated via `paramtype2="facedir"` or similar. - -### fake inventory -this is useful for testing multiple actions on an inventory without having to worry about changing the inventory or -reverting it. this is a better solution than a detached inventory, as actions on a detached inventory are still sent -to clients. fake inventories support all the regular methods of a -[minetest inventory object](https://github.com/minetest/minetest/blob/master/doc/lua_api.md#invref), -with some additions. - -* `futil.FakeInventory()` - - create a fake inventory. - -* `futil.FakeInventory.create_copy(inv)` - - copy all the inventory lists from inv into a new fake inventory. will also create a copy of another fake inventory. - -* `futil.FakeInventory.room_for_all(inv, listname, items)` - - create a copy of inv, then tests if all items in the list `items` can be inserted into listname. - -### globalstep - -implements common boilerplate for globalsteps which are intended to execute every so often. - -```lua -futil.register_globalstep({ - period = 1, -- the globalstep should be run every seconds - catchup = "single", -- whether to "catch up" if lag prevents the callback from running - -- if not specified, no catchup will be attempted. - -- if "single", the callback will be run at most once per server-step until we've caught up. - -- if "full", will re-run the callback within the current step until we've caught up. - func = function(dtime) end, -- code to execute -}) -``` - -### hud manager - -code to manage HUDs - -```lua -local hud = futil.define_hud("my_hud", { - period = nil, -- if a number is given, will automatically update the hud for all players every seconds. - name_field = nil, -- which hud field to use to store an identifier. this should be a field not used by the given - -- hud_elem_type. defaults to "name", which is good for most types. waypoints are an exception. - get_hud_def = function(player) return {} end, -- return the expected hud definition for the player. - -- if nil is returned, the hud will be removed. - enabled_by_default = false, -- whether the hud should be enabled by default. -}) - -local player = minetest.get_player_by_name("flux") -if hud:toggle_enabled(player) then - print("hud now enabled") -else - print("hud now disabled") -end - -print("hud is " .. (hud:is_enabled(player) and "enabled" or "disabled")) - -hud:update(player) -- calls hud.get_hud_def(player) and updates the players hud -``` diff --git a/mods/futil/LICENSE.txt b/mods/futil/LICENSE.txt deleted file mode 100644 index b6ff27cc..00000000 --- a/mods/futil/LICENSE.txt +++ /dev/null @@ -1,168 +0,0 @@ -this license is for the code. -any non-code media included in this repository is covered by the contents of MEDIA_LICENSE.txt. - - GNU LESSER GENERAL PUBLIC LICENSE - Version 3, 29 June 2007 - - Copyright (C) 2007 Free Software Foundation, Inc. - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - - This version of the GNU Lesser General Public License incorporates -the terms and conditions of version 3 of the GNU General Public -License, supplemented by the additional permissions listed below. - - 0. Additional Definitions. - - As used herein, "this License" refers to version 3 of the GNU Lesser -General Public License, and the "GNU GPL" refers to version 3 of the GNU -General Public License. - - "The Library" refers to a covered work governed by this License, -other than an Application or a Combined Work as defined below. - - An "Application" is any work that makes use of an interface provided -by the Library, but which is not otherwise based on the Library. -Defining a subclass of a class defined by the Library is deemed a mode -of using an interface provided by the Library. - - A "Combined Work" is a work produced by combining or linking an -Application with the Library. The particular version of the Library -with which the Combined Work was made is also called the "Linked -Version". - - The "Minimal Corresponding Source" for a Combined Work means the -Corresponding Source for the Combined Work, excluding any source code -for portions of the Combined Work that, considered in isolation, are -based on the Application, and not on the Linked Version. - - The "Corresponding Application Code" for a Combined Work means the -object code and/or source code for the Application, including any data -and utility programs needed for reproducing the Combined Work from the -Application, but excluding the System Libraries of the Combined Work. - - 1. Exception to Section 3 of the GNU GPL. - - You may convey a covered work under sections 3 and 4 of this License -without being bound by section 3 of the GNU GPL. - - 2. Conveying Modified Versions. - - If you modify a copy of the Library, and, in your modifications, a -facility refers to a function or data to be supplied by an Application -that uses the facility (other than as an argument passed when the -facility is invoked), then you may convey a copy of the modified -version: - - a) under this License, provided that you make a good faith effort to - ensure that, in the event an Application does not supply the - function or data, the facility still operates, and performs - whatever part of its purpose remains meaningful, or - - b) under the GNU GPL, with none of the additional permissions of - this License applicable to that copy. - - 3. Object Code Incorporating Material from Library Header Files. - - The object code form of an Application may incorporate material from -a header file that is part of the Library. You may convey such object -code under terms of your choice, provided that, if the incorporated -material is not limited to numerical parameters, data structure -layouts and accessors, or small macros, inline functions and templates -(ten or fewer lines in length), you do both of the following: - - a) Give prominent notice with each copy of the object code that the - Library is used in it and that the Library and its use are - covered by this License. - - b) Accompany the object code with a copy of the GNU GPL and this license - document. - - 4. Combined Works. - - You may convey a Combined Work under terms of your choice that, -taken together, effectively do not restrict modification of the -portions of the Library contained in the Combined Work and reverse -engineering for debugging such modifications, if you also do each of -the following: - - a) Give prominent notice with each copy of the Combined Work that - the Library is used in it and that the Library and its use are - covered by this License. - - b) Accompany the Combined Work with a copy of the GNU GPL and this license - document. - - c) For a Combined Work that displays copyright notices during - execution, include the copyright notice for the Library among - these notices, as well as a reference directing the user to the - copies of the GNU GPL and this license document. - - d) Do one of the following: - - 0) Convey the Minimal Corresponding Source under the terms of this - License, and the Corresponding Application Code in a form - suitable for, and under terms that permit, the user to - recombine or relink the Application with a modified version of - the Linked Version to produce a modified Combined Work, in the - manner specified by section 6 of the GNU GPL for conveying - Corresponding Source. - - 1) Use a suitable shared library mechanism for linking with the - Library. A suitable mechanism is one that (a) uses at run time - a copy of the Library already present on the user's computer - system, and (b) will operate properly with a modified version - of the Library that is interface-compatible with the Linked - Version. - - e) Provide Installation Information, but only if you would otherwise - be required to provide such information under section 6 of the - GNU GPL, and only to the extent that such information is - necessary to install and execute a modified version of the - Combined Work produced by recombining or relinking the - Application with a modified version of the Linked Version. (If - you use option 4d0, the Installation Information must accompany - the Minimal Corresponding Source and Corresponding Application - Code. If you use option 4d1, you must provide the Installation - Information in the manner specified by section 6 of the GNU GPL - for conveying Corresponding Source.) - - 5. Combined Libraries. - - You may place library facilities that are a work based on the -Library side by side in a single library together with other library -facilities that are not Applications and are not covered by this -License, and convey such a combined library under terms of your -choice, if you do both of the following: - - a) Accompany the combined library with a copy of the same work based - on the Library, uncombined with any other library facilities, - conveyed under the terms of this License. - - b) Give prominent notice with the combined library that part of it - is a work based on the Library, and explaining where to find the - accompanying uncombined form of the same work. - - 6. Revised Versions of the GNU Lesser General Public License. - - The Free Software Foundation may publish revised and/or new versions -of the GNU Lesser General Public License from time to time. Such new -versions will be similar in spirit to the present version, but may -differ in detail to address new problems or concerns. - - Each version is given a distinguishing version number. If the -Library as you received it specifies that a certain numbered version -of the GNU Lesser General Public License "or any later version" -applies to it, you have the option of following the terms and -conditions either of that published version or of any later version -published by the Free Software Foundation. If the Library as you -received it does not specify a version number of the GNU Lesser -General Public License, you may choose any version of the GNU Lesser -General Public License ever published by the Free Software Foundation. - - If the Library as you received it specifies that a proxy can decide -whether future versions of the GNU Lesser General Public License shall -apply, that proxy's public statement of acceptance of any version is -permanent authorization for you to choose that version for the -Library. diff --git a/mods/futil/MEDIA_LICENSE.txt b/mods/futil/MEDIA_LICENSE.txt deleted file mode 100644 index 7d4f96c5..00000000 --- a/mods/futil/MEDIA_LICENSE.txt +++ /dev/null @@ -1,427 +0,0 @@ -Attribution-ShareAlike 4.0 International - -======================================================================= - -Creative Commons Corporation ("Creative Commons") is not a law firm and -does not provide legal services or legal advice. Distribution of -Creative Commons public licenses does not create a lawyer-client or -other relationship. Creative Commons makes its licenses and related -information available on an "as-is" basis. Creative Commons gives no -warranties regarding its licenses, any material licensed under their -terms and conditions, or any related information. Creative Commons -disclaims all liability for damages resulting from their use to the -fullest extent possible. - -Using Creative Commons Public Licenses - -Creative Commons public licenses provide a standard set of terms and -conditions that creators and other rights holders may use to share -original works of authorship and other material subject to copyright -and certain other rights specified in the public license below. The -following considerations are for informational purposes only, are not -exhaustive, and do not form part of our licenses. - - Considerations for licensors: Our public licenses are - intended for use by those authorized to give the public - permission to use material in ways otherwise restricted by - copyright and certain other rights. Our licenses are - irrevocable. Licensors should read and understand the terms - and conditions of the license they choose before applying it. - Licensors should also secure all rights necessary before - applying our licenses so that the public can reuse the - material as expected. Licensors should clearly mark any - material not subject to the license. This includes other CC- - licensed material, or material used under an exception or - limitation to copyright. More considerations for licensors: - wiki.creativecommons.org/Considerations_for_licensors - - Considerations for the public: By using one of our public - licenses, a licensor grants the public permission to use the - licensed material under specified terms and conditions. If - the licensor's permission is not necessary for any reason--for - example, because of any applicable exception or limitation to - copyright--then that use is not regulated by the license. Our - licenses grant only permissions under copyright and certain - other rights that a licensor has authority to grant. Use of - the licensed material may still be restricted for other - reasons, including because others have copyright or other - rights in the material. A licensor may make special requests, - such as asking that all changes be marked or described. - Although not required by our licenses, you are encouraged to - respect those requests where reasonable. More considerations - for the public: - wiki.creativecommons.org/Considerations_for_licensees - -======================================================================= - -Creative Commons Attribution-ShareAlike 4.0 International Public -License - -By exercising the Licensed Rights (defined below), You accept and agree -to be bound by the terms and conditions of this Creative Commons -Attribution-ShareAlike 4.0 International Public License ("Public -License"). To the extent this Public License may be interpreted as a -contract, You are granted the Licensed Rights in consideration of Your -acceptance of these terms and conditions, and the Licensor grants You -such rights in consideration of benefits the Licensor receives from -making the Licensed Material available under these terms and -conditions. - - -Section 1 -- Definitions. - - a. Adapted Material means material subject to Copyright and Similar - Rights that is derived from or based upon the Licensed Material - and in which the Licensed Material is translated, altered, - arranged, transformed, or otherwise modified in a manner requiring - permission under the Copyright and Similar Rights held by the - Licensor. For purposes of this Public License, where the Licensed - Material is a musical work, performance, or sound recording, - Adapted Material is always produced where the Licensed Material is - synched in timed relation with a moving image. - - b. Adapter's License means the license You apply to Your Copyright - and Similar Rights in Your contributions to Adapted Material in - accordance with the terms and conditions of this Public License. - - c. BY-SA Compatible License means a license listed at - creativecommons.org/compatiblelicenses, approved by Creative - Commons as essentially the equivalent of this Public License. - - d. Copyright and Similar Rights means copyright and/or similar rights - closely related to copyright including, without limitation, - performance, broadcast, sound recording, and Sui Generis Database - Rights, without regard to how the rights are labeled or - categorized. For purposes of this Public License, the rights - specified in Section 2(b)(1)-(2) are not Copyright and Similar - Rights. - - e. Effective Technological Measures means those measures that, in the - absence of proper authority, may not be circumvented under laws - fulfilling obligations under Article 11 of the WIPO Copyright - Treaty adopted on December 20, 1996, and/or similar international - agreements. - - f. Exceptions and Limitations means fair use, fair dealing, and/or - any other exception or limitation to Copyright and Similar Rights - that applies to Your use of the Licensed Material. - - g. License Elements means the license attributes listed in the name - of a Creative Commons Public License. The License Elements of this - Public License are Attribution and ShareAlike. - - h. Licensed Material means the artistic or literary work, database, - or other material to which the Licensor applied this Public - License. - - i. Licensed Rights means the rights granted to You subject to the - terms and conditions of this Public License, which are limited to - all Copyright and Similar Rights that apply to Your use of the - Licensed Material and that the Licensor has authority to license. - - j. Licensor means the individual(s) or entity(ies) granting rights - under this Public License. - - k. Share means to provide material to the public by any means or - process that requires permission under the Licensed Rights, such - as reproduction, public display, public performance, distribution, - dissemination, communication, or importation, and to make material - available to the public including in ways that members of the - public may access the material from a place and at a time - individually chosen by them. - - l. Sui Generis Database Rights means rights other than copyright - resulting from Directive 96/9/EC of the European Parliament and of - the Council of 11 March 1996 on the legal protection of databases, - as amended and/or succeeded, as well as other essentially - equivalent rights anywhere in the world. - - m. You means the individual or entity exercising the Licensed Rights - under this Public License. Your has a corresponding meaning. - - -Section 2 -- Scope. - - a. License grant. - - 1. Subject to the terms and conditions of this Public License, - the Licensor hereby grants You a worldwide, royalty-free, - non-sublicensable, non-exclusive, irrevocable license to - exercise the Licensed Rights in the Licensed Material to: - - a. reproduce and Share the Licensed Material, in whole or - in part; and - - b. produce, reproduce, and Share Adapted Material. - - 2. Exceptions and Limitations. For the avoidance of doubt, where - Exceptions and Limitations apply to Your use, this Public - License does not apply, and You do not need to comply with - its terms and conditions. - - 3. Term. The term of this Public License is specified in Section - 6(a). - - 4. Media and formats; technical modifications allowed. The - Licensor authorizes You to exercise the Licensed Rights in - all media and formats whether now known or hereafter created, - and to make technical modifications necessary to do so. The - Licensor waives and/or agrees not to assert any right or - authority to forbid You from making technical modifications - necessary to exercise the Licensed Rights, including - technical modifications necessary to circumvent Effective - Technological Measures. For purposes of this Public License, - simply making modifications authorized by this Section 2(a) - (4) never produces Adapted Material. - - 5. Downstream recipients. - - a. Offer from the Licensor -- Licensed Material. Every - recipient of the Licensed Material automatically - receives an offer from the Licensor to exercise the - Licensed Rights under the terms and conditions of this - Public License. - - b. Additional offer from the Licensor -- Adapted Material. - Every recipient of Adapted Material from You - automatically receives an offer from the Licensor to - exercise the Licensed Rights in the Adapted Material - under the conditions of the Adapter's License You apply. - - c. No downstream restrictions. You may not offer or impose - any additional or different terms or conditions on, or - apply any Effective Technological Measures to, the - Licensed Material if doing so restricts exercise of the - Licensed Rights by any recipient of the Licensed - Material. - - 6. No endorsement. Nothing in this Public License constitutes or - may be construed as permission to assert or imply that You - are, or that Your use of the Licensed Material is, connected - with, or sponsored, endorsed, or granted official status by, - the Licensor or others designated to receive attribution as - provided in Section 3(a)(1)(A)(i). - - b. Other rights. - - 1. Moral rights, such as the right of integrity, are not - licensed under this Public License, nor are publicity, - privacy, and/or other similar personality rights; however, to - the extent possible, the Licensor waives and/or agrees not to - assert any such rights held by the Licensor to the limited - extent necessary to allow You to exercise the Licensed - Rights, but not otherwise. - - 2. Patent and trademark rights are not licensed under this - Public License. - - 3. To the extent possible, the Licensor waives any right to - collect royalties from You for the exercise of the Licensed - Rights, whether directly or through a collecting society - under any voluntary or waivable statutory or compulsory - licensing scheme. In all other cases the Licensor expressly - reserves any right to collect such royalties. - - -Section 3 -- License Conditions. - -Your exercise of the Licensed Rights is expressly made subject to the -following conditions. - - a. Attribution. - - 1. If You Share the Licensed Material (including in modified - form), You must: - - a. retain the following if it is supplied by the Licensor - with the Licensed Material: - - i. identification of the creator(s) of the Licensed - Material and any others designated to receive - attribution, in any reasonable manner requested by - the Licensor (including by pseudonym if - designated); - - ii. a copyright notice; - - iii. a notice that refers to this Public License; - - iv. a notice that refers to the disclaimer of - warranties; - - v. a URI or hyperlink to the Licensed Material to the - extent reasonably practicable; - - b. indicate if You modified the Licensed Material and - retain an indication of any previous modifications; and - - c. indicate the Licensed Material is licensed under this - Public License, and include the text of, or the URI or - hyperlink to, this Public License. - - 2. You may satisfy the conditions in Section 3(a)(1) in any - reasonable manner based on the medium, means, and context in - which You Share the Licensed Material. For example, it may be - reasonable to satisfy the conditions by providing a URI or - hyperlink to a resource that includes the required - information. - - 3. If requested by the Licensor, You must remove any of the - information required by Section 3(a)(1)(A) to the extent - reasonably practicable. - - b. ShareAlike. - - In addition to the conditions in Section 3(a), if You Share - Adapted Material You produce, the following conditions also apply. - - 1. The Adapter's License You apply must be a Creative Commons - license with the same License Elements, this version or - later, or a BY-SA Compatible License. - - 2. You must include the text of, or the URI or hyperlink to, the - Adapter's License You apply. You may satisfy this condition - in any reasonable manner based on the medium, means, and - context in which You Share Adapted Material. - - 3. You may not offer or impose any additional or different terms - or conditions on, or apply any Effective Technological - Measures to, Adapted Material that restrict exercise of the - rights granted under the Adapter's License You apply. - - -Section 4 -- Sui Generis Database Rights. - -Where the Licensed Rights include Sui Generis Database Rights that -apply to Your use of the Licensed Material: - - a. for the avoidance of doubt, Section 2(a)(1) grants You the right - to extract, reuse, reproduce, and Share all or a substantial - portion of the contents of the database; - - b. if You include all or a substantial portion of the database - contents in a database in which You have Sui Generis Database - Rights, then the database in which You have Sui Generis Database - Rights (but not its individual contents) is Adapted Material, - including for purposes of Section 3(b); and - - c. You must comply with the conditions in Section 3(a) if You Share - all or a substantial portion of the contents of the database. - -For the avoidance of doubt, this Section 4 supplements and does not -replace Your obligations under this Public License where the Licensed -Rights include other Copyright and Similar Rights. - - -Section 5 -- Disclaimer of Warranties and Limitation of Liability. - - a. UNLESS OTHERWISE SEPARATELY UNDERTAKEN BY THE LICENSOR, TO THE - EXTENT POSSIBLE, THE LICENSOR OFFERS THE LICENSED MATERIAL AS-IS - AND AS-AVAILABLE, AND MAKES NO REPRESENTATIONS OR WARRANTIES OF - ANY KIND CONCERNING THE LICENSED MATERIAL, WHETHER EXPRESS, - IMPLIED, STATUTORY, OR OTHER. THIS INCLUDES, WITHOUT LIMITATION, - WARRANTIES OF TITLE, MERCHANTABILITY, FITNESS FOR A PARTICULAR - PURPOSE, NON-INFRINGEMENT, ABSENCE OF LATENT OR OTHER DEFECTS, - ACCURACY, OR THE PRESENCE OR ABSENCE OF ERRORS, WHETHER OR NOT - KNOWN OR DISCOVERABLE. WHERE DISCLAIMERS OF WARRANTIES ARE NOT - ALLOWED IN FULL OR IN PART, THIS DISCLAIMER MAY NOT APPLY TO YOU. - - b. TO THE EXTENT POSSIBLE, IN NO EVENT WILL THE LICENSOR BE LIABLE - TO YOU ON ANY LEGAL THEORY (INCLUDING, WITHOUT LIMITATION, - NEGLIGENCE) OR OTHERWISE FOR ANY DIRECT, SPECIAL, INDIRECT, - INCIDENTAL, CONSEQUENTIAL, PUNITIVE, EXEMPLARY, OR OTHER LOSSES, - COSTS, EXPENSES, OR DAMAGES ARISING OUT OF THIS PUBLIC LICENSE OR - USE OF THE LICENSED MATERIAL, EVEN IF THE LICENSOR HAS BEEN - ADVISED OF THE POSSIBILITY OF SUCH LOSSES, COSTS, EXPENSES, OR - DAMAGES. WHERE A LIMITATION OF LIABILITY IS NOT ALLOWED IN FULL OR - IN PART, THIS LIMITATION MAY NOT APPLY TO YOU. - - c. The disclaimer of warranties and limitation of liability provided - above shall be interpreted in a manner that, to the extent - possible, most closely approximates an absolute disclaimer and - waiver of all liability. - - -Section 6 -- Term and Termination. - - a. This Public License applies for the term of the Copyright and - Similar Rights licensed here. However, if You fail to comply with - this Public License, then Your rights under this Public License - terminate automatically. - - b. Where Your right to use the Licensed Material has terminated under - Section 6(a), it reinstates: - - 1. automatically as of the date the violation is cured, provided - it is cured within 30 days of Your discovery of the - violation; or - - 2. upon express reinstatement by the Licensor. - - For the avoidance of doubt, this Section 6(b) does not affect any - right the Licensor may have to seek remedies for Your violations - of this Public License. - - c. For the avoidance of doubt, the Licensor may also offer the - Licensed Material under separate terms or conditions or stop - distributing the Licensed Material at any time; however, doing so - will not terminate this Public License. - - d. Sections 1, 5, 6, 7, and 8 survive termination of this Public - License. - - -Section 7 -- Other Terms and Conditions. - - a. The Licensor shall not be bound by any additional or different - terms or conditions communicated by You unless expressly agreed. - - b. Any arrangements, understandings, or agreements regarding the - Licensed Material not stated herein are separate from and - independent of the terms and conditions of this Public License. - - -Section 8 -- Interpretation. - - a. For the avoidance of doubt, this Public License does not, and - shall not be interpreted to, reduce, limit, restrict, or impose - conditions on any use of the Licensed Material that could lawfully - be made without permission under this Public License. - - b. To the extent possible, if any provision of this Public License is - deemed unenforceable, it shall be automatically reformed to the - minimum extent necessary to make it enforceable. If the provision - cannot be reformed, it shall be severed from this Public License - without affecting the enforceability of the remaining terms and - conditions. - - c. No term or condition of this Public License will be waived and no - failure to comply consented to unless expressly agreed to by the - Licensor. - - d. Nothing in this Public License constitutes or may be interpreted - as a limitation upon, or waiver of, any privileges and immunities - that apply to the Licensor or You, including from the legal - processes of any jurisdiction or authority. - - -======================================================================= - -Creative Commons is not a party to its public -licenses. Notwithstanding, Creative Commons may elect to apply one of -its public licenses to material it publishes and in those instances -will be considered the “Licensor.” The text of the Creative Commons -public licenses is dedicated to the public domain under the CC0 Public -Domain Dedication. Except for the limited purpose of indicating that -material is shared under a Creative Commons public license or as -otherwise permitted by the Creative Commons policies published at -creativecommons.org/policies, Creative Commons does not authorize the -use of the trademark "Creative Commons" or any other trademark or logo -of Creative Commons without its prior written consent including, -without limitation, in connection with any unauthorized modifications -to any of its public licenses or any other arrangements, -understandings, or agreements concerning use of licensed material. For -the avoidance of doubt, this paragraph does not form part of the -public licenses. - -Creative Commons may be contacted at creativecommons.org. diff --git a/mods/futil/README.md b/mods/futil/README.md deleted file mode 100644 index f7415259..00000000 --- a/mods/futil/README.md +++ /dev/null @@ -1,5 +0,0 @@ -# futil - flux's utility mod - -a bunch of simple lua routines and data structures. this is a library which is used by other mods, which doesn't change -any behavior or add any features itself. it mostly provides the creator (flux) w/ a toolkit for solving common problems -without having to re-implement the same code in multiple mods. diff --git a/mods/futil/data_structures/bitarray.lua b/mods/futil/data_structures/bitarray.lua deleted file mode 100644 index 71ffa7aa..00000000 --- a/mods/futil/data_structures/bitarray.lua +++ /dev/null @@ -1,125 +0,0 @@ --- pack bits into doubles --- this is quite slow compared to how you'd do this in c or something. --- there's https://bitop.luajit.org/api.html but that seems limited to 32 bits. we can use the full 53 bit mantissa. - -local BITS_PER_NUMBER = 53 - -local f = string.format - -local m_floor = math.floor -local s_byte = string.byte -local s_char = string.char - -local BitArray = futil.class1() - -function BitArray:_init(size_or_bitmap) - if type(size_or_bitmap) == "number" then - local data = {} - self._size = size_or_bitmap - for i = 1, math.ceil(size_or_bitmap / BITS_PER_NUMBER) do - data[i] = 0 - end - self._data = data - elseif type(size_or_bitmap) == "table" then - if size_or_bitmap.is_a and size_or_bitmap:is_a(BitArray) then - self._size = size_or_bitmap._size - self._data = table.copy(size_or_bitmap._data) - end - end - if not self._data then - error("bitmap must be initialized w/ a size or another bitmap") - end -end - -function BitArray:__eq(other) - if self._size ~= other._size then - return false - end - for i = 1, self._size do - if self._data[i] ~= other._data[i] then - return false - end - end - return true -end - -local function get_bit(n, j) - n = n % (2 ^ j) - return m_floor(n / (2 ^ (j - 1))) == 1 -end - -function BitArray:get(k) - if type(k) ~= "number" then - return nil - elseif k <= 0 or k > self._size then - return nil - end - local i = math.ceil(k / BITS_PER_NUMBER) - local n = self._data[i] - local j = ((k - 1) % BITS_PER_NUMBER) + 1 - return get_bit(n, j) -end - -local function set_bit(n, j, v) - local current = get_bit(n, j) - if current == v then - return n - elseif v then - return n + (2 ^ (j - 1)) - else - return n - (2 ^ (j - 1)) - end -end - -function BitArray:set(k, v) - if type(v) == "number" then - if v < 0 or v > 1 then - error(f("invalid argument %s", v)) - end - v = v == 1 - elseif type(v) ~= "boolean" then - error(f("invalid argument of type %s", type(v))) - end - local i = math.ceil(k / BITS_PER_NUMBER) - local n = self._data[i] - local j = ((k - 1) % BITS_PER_NUMBER) + 1 - self._data[i] = set_bit(n, j, v) -end - -function BitArray:serialize() - local data = self._data - local parts = {} - for i = 1, #data do - local datum = data[i] - parts[i] = s_char(datum % 256) - .. s_char(m_floor(datum / 256) % 256) - .. s_char(m_floor(datum / (256 ^ 2)) % 256) - .. s_char(m_floor(datum / (256 ^ 3)) % 256) - .. s_char(m_floor(datum / (256 ^ 4)) % 256) - .. s_char(m_floor(datum / (256 ^ 5)) % 256) - .. s_char(m_floor(datum / (256 ^ 6)) % 256) - end - return table.concat(parts, "") -end - -function BitArray.deserialize(s) - if type(s) ~= "string" then - error(f("invalid argument of type %s", type(s))) - elseif #s % 7 ~= 0 then - error(f("invalid serialized string (wrong length)")) - end - local ba = BitArray(#s / 7) - local i = 1 - for a = 1, #s, 7 do - local bs = {} - for j = 0, 6 do - bs[j + 1] = s_byte(s:sub(a + j, a + j)) - end - ba._data[i] = bs[1] - + 256 * (bs[2] + 256 * (bs[3] + 256 * (bs[4] + 256 * (bs[5] + 256 * (bs[6] + 256 * bs[7]))))) - i = i + 1 - end - return ba -end - -futil.BitArray = BitArray diff --git a/mods/futil/data_structures/default_table.lua b/mods/futil/data_structures/default_table.lua deleted file mode 100644 index 3aa5e9f0..00000000 --- a/mods/futil/data_structures/default_table.lua +++ /dev/null @@ -1,11 +0,0 @@ --- https://www.lua.org/pil/13.4.3.html - -function futil.DefaultTable(initializer) - return setmetatable({}, { - __index = function(t, k) - local v = initializer(k) - t[k] = v - return v - end, - }) -end diff --git a/mods/futil/data_structures/deque.lua b/mods/futil/data_structures/deque.lua deleted file mode 100644 index 57c30313..00000000 --- a/mods/futil/data_structures/deque.lua +++ /dev/null @@ -1,88 +0,0 @@ --- inspired by https://www.lua.org/pil/11.4.html - -local Deque = futil.class1() - -function Deque:_init(def) - self._a = 0 - self._z = -1 - self._m = def and def.max_size -end - -function Deque:size() - return self._z - self._a + 1 -end - -function Deque:push_front(value) - local max_size = self._m - if max_size and (self._z - self._a + 1) >= max_size then - return false - end - local a = self._a - 1 - self._a = a - self[a] = value - return true, a -end - -function Deque:peek_front() - return self[self._a] -end - -function Deque:pop_front() - local a = self._a - if a > self._z then - return nil - end - local value = self[a] - self[a] = nil - self._a = a + 1 - return value -end - -function Deque:push_back(value) - local max_size = self._m - if max_size and (self._z - self._a + 1) >= max_size then - return false - end - local z = self._z + 1 - self._z = z - self[z] = value - return true, z -end - -function Deque:peek_back() - return self[self._z] -end - -function Deque:pop_back() - local z = self._z - if self._a > z then - return nil - end - local value = self[z] - self[z] = nil - self._z = z + 1 - return value -end - --- this iterator is kinda wonky, and the behavior may be changed in the future. --- unexpected behavior may result from modifying a deque *while* iterating it. --- note that you *cannot* iterate the deque directly using `pairs()` because of e.g. "_a" and "_z" -function Deque:iterate() - local i = self._a - 1 - return function() - i = i + 1 - return self[i] - end -end - -function Deque:clear() - for k in pairs(self) do - if type(k) == "number" then - self[k] = nil - end - end - self._a = 0 - self._z = -1 -end - -futil.Deque = Deque diff --git a/mods/futil/data_structures/init.lua b/mods/futil/data_structures/init.lua deleted file mode 100644 index 222dacad..00000000 --- a/mods/futil/data_structures/init.lua +++ /dev/null @@ -1,7 +0,0 @@ -futil.dofile("data_structures", "bitarray") -futil.dofile("data_structures", "default_table") -futil.dofile("data_structures", "deque") -futil.dofile("data_structures", "pairing_heap") -futil.dofile("data_structures", "point_search_tree") -futil.dofile("data_structures", "set") -futil.dofile("data_structures", "sparse_graph") -- requires default_table and set diff --git a/mods/futil/data_structures/pairing_heap.lua b/mods/futil/data_structures/pairing_heap.lua deleted file mode 100644 index 82d5947c..00000000 --- a/mods/futil/data_structures/pairing_heap.lua +++ /dev/null @@ -1,156 +0,0 @@ --- https://en.wikipedia.org/wiki/Pairing_heap --- https://www.cs.cmu.edu/~sleator/papers/pairing-heaps.pdf --- https://www.cise.ufl.edu/~sahni/dsaaj/enrich/c13/pairing.htm - -local inf = math.huge - -local function add_child(node1, node2) - node2.parent = node1 - node2.sibling = node1.child - node1.child = node2 -end - -local function meld(node1, node2) - if node1 == nil or node1.value == nil then - return node2 - elseif node2 == nil or node2.value == nil then - return node1 - elseif node1.priority > node2.priority then - add_child(node1, node2) - return node1 - else - add_child(node2, node1) - return node2 - end -end - -local function merge_pairs(node) - if node.value == nil or not node.sibling then - return - end - - local sibling = node.sibling - local siblingsibling = sibling.sibling - - node.sibling = nil - sibling.sibling = nil - - node = meld(node, sibling) - - if siblingsibling then - return meld(node, merge_pairs(siblingsibling)) - else - return node - end -end - -local function cut(node) - local parent = node.parent - - if parent.child == node then - parent.child = node.sibling - else - parent = parent.child - local sibling = parent.sibling - while sibling ~= node do - parent = sibling - sibling = parent.sibling - end - parent.sibling = node.sibling - end - - node.parent = nil - node.sibling = nil -end - -local function need_to_move(node, new_priority) - local cur_priority = node.priority - if cur_priority < new_priority then - -- priority increase, make sure we don't dominate our parent - local parent = node.parent - return (parent and new_priority > parent.priority) - elseif cur_priority > new_priority then - -- priority decrease, make sure our children don't dominate us - local child = node.child - while child and child ~= node do - if child.priority > new_priority then - return true - end - child = child.sibling - end - return false - else - return false - end -end - -local PairingHeap = futil.class1() - -function PairingHeap:_new() - self._nodes_by_value = {} - self._size = 0 -end - -function PairingHeap:size() - return self._size -end - -function PairingHeap:peek() - local hn = self._max_node - - if not hn then - error("empty") - end - - return hn.value, hn.priority -end - -function PairingHeap:remove(value) - self:set_priority(value, inf) - return self:pop() -end - -function PairingHeap:pop() - local max = self._max_node - - if not max then - error("empty") - end - - local child = max.child - if child then - self._max_node = merge_pairs(child) - end - - local value = max._value - - self._nodes_by_value[value] = nil - self._size = self._size - 1 - - return value -end - -function PairingHeap:get_priority(value) - return self._nodes_by_value[value].priority -end - -function PairingHeap:set_priority(value, priority) - local cur_node = self._nodes_by_value[value] - if cur_node then - local need_to = need_to_move(cur_node, priority) - - if need_to then - cut(cur_node) - self._max_node = meld(cur_node, self._max_node) - else - cur_node.priority = priority - end - else - local node = { value = value, priority = priority } - self._nodes_by_value[value] = node - self._max_node = meld(self._max_node, node) - self._size = self._size + 1 - end -end - -futil.PairingHeap = PairingHeap diff --git a/mods/futil/data_structures/point_search_tree.lua b/mods/futil/data_structures/point_search_tree.lua deleted file mode 100644 index 2c328115..00000000 --- a/mods/futil/data_structures/point_search_tree.lua +++ /dev/null @@ -1,268 +0,0 @@ ---[[ -a data structure which can efficiently retrieve values within specific rectangular regions of 3d space. - -the closest relevant descriptions of this problem and solution are in the following: -https://en.wikipedia.org/wiki/Min/max_kd-tree -https://medium.com/omarelgabrys-blog/geometric-applications-of-bsts-e58f0a5019f3 - -creation is O(n log n) -finding objects in a region is O(m + log n) if there's m objects in the region. - -the hope here is that this will provide a faster alternative to `minetest.get_objects_in_area()`. that currently -iterates over *all* active objects in the world, which can be slow when there's ten thousand or more of objects in the -world, and you are only interested in a few of them. in particular, the your-land server usually has 5-8 thousand -objects loaded at once, and can have hundreds of mobs calling `get_objects_in_area` every couple server steps. perftop -definitively implicated this routine as being a major source of lag. the question, now, is what to do about it. - -the current implementation doesn't allow for insertion, deletion, or changes in location. if your points move around, -you're gonna have to rebuild the whole tree from scratch, which currently limits the usefulness. - -TODO: read this and incorporate if applicable: https://arxiv.org/abs/1410.5420 - -== footnotes about the algorithms == -currently, we're hard-coding the usage of the [median of medians](https://en.wikipedia.org/wiki/Median_of_medians) -algorithm as the pivot strategy, as this resulted in unexpectedly dramatic improvements over random selection in -some informal performance tests i did. - -== footnotes about results == -currently, performance can range from taking 1/20th of the time of the engine call, to 100 times as long. this -makes me realize that this is worth pursuing, but probably this will need to be ported to c++ to consistently provide -a benefit. but, i'll absolutely need to figure out a self-balancing strategy before that'll be appropriate. -]] -local sort = table.sort - -local in_area = vector.in_area - or function(pos, pmin, pmax) - local x, y, z = pos.x, pos.y, pos.z - return pmin.x <= x and x <= pmax.x and pmin.y <= y and y <= pmax.y and pmin.z <= z and z <= pmax.z - end - -local axes = { "x", "y", "z" } -local POS = 1 -local VALUE = 2 - -local Leaf = futil.class1() - -function Leaf:_init(pos_and_value) - self[POS] = pos_and_value[POS] - self[VALUE] = pos_and_value[VALUE] -end - -local Node = futil.class1() - -function Node:_init(min, max, left, right) - self.min = min - self.max = max - self.left = left - self.right = right -end - -local PointSearchTree = futil.class1() - -futil.min_median_max = {} - -function futil.min_median_max.sort(t, indexer) - if indexer then - sort(t, function(a, b) - return indexer(a) < indexer(b) - end) - else - sort(t) - end - return t[1], math.floor(#t / 2), t[#t] -end - -function futil.min_median_max.gen_select(pivot_alg) - return function(t, indexer) - local median = futil.selection.select(t, pivot_alg, function(a, b) - return indexer(a) < indexer(b) - end) - local min = indexer(t[1]) - local max = min - for i = 2, #t do - local v = indexer(t[i]) - if v < min then - min = v - elseif v > max then - max = v - end - end - return min, median, max - end -end - -local function bisect(pos_and_values, axis_i, min_median_max) - if #pos_and_values == 1 then - return Leaf(pos_and_values[1]) - end - - local axis = axes[axis_i] - - local min, median, max = min_median_max(pos_and_values, function(i) - return i[POS][axis] - end) - - local next_axis_i = (axis_i % #axes) + 1 - return Node( - min, - max, - bisect({ unpack(pos_and_values, 1, median) }, next_axis_i, min_median_max), - bisect({ unpack(pos_and_values, median + 1) }, next_axis_i, min_median_max) - ) -end - -function PointSearchTree:_init(pos_and_values, min_median_max) - pos_and_values = pos_and_values or {} - min_median_max = min_median_max or futil.min_median_max.gen_select(futil.selection.pivot.median_of_medians) - self._len = #pos_and_values - if #pos_and_values > 0 then - self._root = bisect(pos_and_values, 1, min_median_max) - end -end - --- -DLUAJIT_ENABLE_LUA52COMPAT -function PointSearchTree:__len() - return self._len -end - -function PointSearchTree:dump() - local function getlines(node, axis_i) - local axis = axes[axis_i] - if not node then - return {} - elseif node:is_a(Leaf) then - return { minetest.pos_to_string(node[POS], 1) } - else - local lines = {} - for _, line in ipairs(getlines(node.left, (axis_i % #axes) + 1)) do - lines[#lines + 1] = string.format("%s=[%.1f,%.1f] %s", axis, node.min, node.max, line) - end - for _, line in ipairs(getlines(node.right, (axis_i % #axes) + 1)) do - lines[#lines + 1] = string.format("%s=[%.1f,%.1f] %s", axis, node.min, node.max, line) - end - return lines - end - end - - return table.concat(getlines(self._root, 1), "\n") -end - -local function make_iterator(pmin, pmax, predicate, accumulate) - local function iterate(node, axis_i) - local next_axis_i = (axis_i % 3) + 1 - local next_axis = axes[next_axis_i] - - local left = node.left - if left then - if left:is_a(Leaf) then - if predicate(left) then - accumulate(left) - end - elseif pmin[next_axis] <= left.max then - iterate(left, next_axis_i) - end - end - - local right = node.right - if right then - if right:is_a(Leaf) then - if predicate(right) then - accumulate(right) - end - elseif right.min <= pmax[next_axis] then - iterate(right, next_axis_i) - end - end - end - return iterate -end - -function PointSearchTree:iterate_values_in_area(pmin, pmax) - if not self._root then - return function() end - end - - pmin, pmax = vector.sort(pmin, pmax) - - if self._root.max < pmin.x or pmax.x < self._root.min then - return function() end - end - - return coroutine.wrap(function() - make_iterator(pmin, pmax, function(leaf) - return in_area(leaf[POS], pmin, pmax) - end, function(leaf) - coroutine.yield(leaf[POS], leaf[VALUE]) - end)(self._root, 1) - end) -end - -function PointSearchTree:get_values_in_area(pmin, pmax) - local via = {} - if not self._root then - return via - end - - pmin, pmax = vector.sort(pmin, pmax) - - if self._root.max < pmin.x or pmax.x < self._root.min then - return via - end - - make_iterator(pmin, pmax, function(leaf) - return in_area(leaf[POS], pmin, pmax) - end, function(leaf) - via[#via + 1] = leaf[VALUE] - end)(self._root, 1) - - return via -end - -function PointSearchTree:iterate_values_inside_radius(center, radius) - if not self._root then - return function() end - end - - local pmin = vector.subtract(center, radius) - local pmax = vector.add(center, radius) - - if self._root.max < pmin.x or pmax.x < self._root.min then - return function() end - end - - local v_distance = vector.distance - - return coroutine.wrap(function() - make_iterator(pmin, pmax, function(leaf) - return v_distance(center, leaf[POS]) <= radius - end, function(leaf) - coroutine.yield(leaf[POS], leaf[VALUE]) - end)(self._root, 1) - end) -end - -function PointSearchTree:get_values_inside_radius(center, radius) - local vir = {} - if not self._root then - return vir - end - - local pmin = vector.subtract(center, radius) - local pmax = vector.add(center, radius) - - if self._root.max < pmin.x or pmax.x < self._root.min then - return vir - end - - local v_distance = vector.distance - - make_iterator(pmin, pmax, function(leaf) - return v_distance(center, leaf[POS]) <= radius - end, function(leaf) - vir[#vir + 1] = leaf[VALUE] - end)(self._root, 1) - - return vir -end - -futil.PointSearchTree = PointSearchTree diff --git a/mods/futil/data_structures/set.lua b/mods/futil/data_structures/set.lua deleted file mode 100644 index 269cf606..00000000 --- a/mods/futil/data_structures/set.lua +++ /dev/null @@ -1,267 +0,0 @@ --- based more-or-less on python's set - -local f = string.format - -local Set = futil.class1() - -local function is_a_set(thing) - return type(thing) == "table" and type(thing.is_a) == "function" and thing:is_a(Set) -end - -function Set:_init(t_or_i) - self._size = 0 - self._set = {} - if t_or_i then - if type(t_or_i.is_a) == "function" then - if t_or_i:is_a(Set) then - self._set = table.copy(t_or_i._set) - self._size = t_or_i._size - else - for v in t_or_i:iterate() do - self:add(v) - end - end - elseif type(t_or_i) == "table" then - for i = 1, #t_or_i do - self:add(t_or_i[i]) - end - elseif type(t_or_i) == "function" or getmetatable(t_or_i).__call then - for v in t_or_i do - self:add(v) - end - else - error(f("unknown argument of type %s", type(t_or_i))) - end - end -end - --- turn a table like {foo=true, bar=true} into a Set -function Set.convert(t) - local set = Set() - set._set = t - set._size = futil.table.size(t) - return set -end - --- -DLUAJIT_ENABLE_LUA52COMPAT -function Set:__len() - return self._size -end - -function Set:len() - return self._size -end - -function Set:size() - return self._size -end - -function Set:is_empty() - return self._size == 0 -end - -function Set:__tostring() - local elements = {} - for element in pairs(self._set) do - elements[#elements + 1] = f("%q", element) - end - return f("Set({%s})", table.concat(elements, ", ")) -end - -function Set:__eq(other) - if not is_a_set(other) then - return false - end - for k in pairs(self._set) do - if not other._set[k] then - return false - end - end - return self._size == other._size -end - -function Set:contains(element) - return self._set[element] == true -end - -function Set:add(element) - if not self:contains(element) then - self._set[element] = true - self._size = self._size + 1 - end -end - -function Set:remove(element) - if not self:contains(element) then - error(f("set does not contain %s", element)) - end - self._set[element] = nil - self._size = self._size - 1 -end - -function Set:discard(element) - if self:contains(element) then - self._set[element] = nil - self._size = self._size - 1 - end -end - -function Set:clear() - self._set = {} - self._size = 0 -end - -function Set:iterate() - return futil.table.ikeys(self._set) -end - -function Set:intersects(other) - if not is_a_set(other) then - other = Set(other) - end - local smaller, bigger - if other:size() < self:size() then - smaller = other - bigger = self - else - smaller = self - bigger = other - end - for element in smaller:iterate() do - if bigger:contains(element) then - return true - end - end - return false -end - -function Set:isdisjoint(other) - if not is_a_set(other) then - other = Set(other) - end - local smaller, bigger - if other:size() < self:size() then - smaller = other - bigger = self - else - smaller = self - bigger = other - end - for element in smaller:iterate() do - if bigger:contains(element) then - return false - end - end - return true -end - -function Set:issubset(other) - if not is_a_set(other) then - other = Set(other) - end - if self:size() > other:size() then - return false - end - for element in self:iterate() do - if not other:contains(element) then - return false - end - end - return true -end - -function Set:__le(other) - return self:issubset(other) -end - -function Set:__lt(other) - if not is_a_set(other) then - other = Set(other) - end - if self:size() >= other:size() then - return false - end - for element in self:iterate() do - if not other:contains(element) then - return false - end - end - return true -end - -function Set:issuperset(other) - if not is_a_set(other) then - other = Set(other) - end - return other:issubset(self) -end - -function Set:update(other) - if not is_a_set(other) then - other = Set(other) - end - for element in other:iterate() do - self:add(element) - end -end - -function Set:union(other) - if not is_a_set(other) then - other = Set(other) - end - local union = Set(self) - union:update(other) - return union -end - -function Set:__add(other) - return self:union(other) -end - -function Set:intersection_update(other) - if not is_a_set(other) then - other = Set(other) - end - for element in self:iterate() do - if not other:contains(element) then - self:remove(element) - end - end -end - -function Set:intersection(other) - if not is_a_set(other) then - other = Set(other) - end - local intersection = Set() - for element in self:iterate() do - if other:contains(element) then - intersection:add(element) - end - end - return intersection -end - -function Set:difference_update(other) - if not is_a_set(other) then - other = Set(other) - end - for element in other:iterate() do - self:discard(element) - end -end - -function Set:difference(other) - if not is_a_set(other) then - other = Set(other) - end - local difference = Set(self) - difference:difference_update(other) - return difference -end - -function Set:__sub(other) - return self:difference(other) -end - -futil.Set = Set diff --git a/mods/futil/data_structures/sparse_graph.lua b/mods/futil/data_structures/sparse_graph.lua deleted file mode 100644 index b5acc20d..00000000 --- a/mods/futil/data_structures/sparse_graph.lua +++ /dev/null @@ -1,32 +0,0 @@ -local f = string.format - -local SparseGraph = futil.class1() - -function SparseGraph:_init(size) - self._size = size or 0 - self._adj_by_vertex = futil.DefaultTable(function() - return futil.Set() - end) -end - -function SparseGraph:size() - return self._size -end - -function SparseGraph:add_vertex() - self._size = self._size + 1 -end - -function SparseGraph:add_edge(a, b) - assert(1 <= a and a <= self._size, f("invalid vertex a %s", a)) - assert(1 <= b and b <= self._size, f("invalid vertex b %s", b)) - self._adj_by_vertex[a]:add(b) -end - -function SparseGraph:has_edge(a, b) - assert(1 <= a and a <= self._size, f("invalid vertex a %s", a)) - assert(1 <= b and b <= self._size, f("invalid vertex b %s", b)) - return self._adj_by_vertex[a]:contains(b) -end - -futil.SparseGraph = SparseGraph diff --git a/mods/futil/init.lua b/mods/futil/init.lua deleted file mode 100644 index 136d3552..00000000 --- a/mods/futil/init.lua +++ /dev/null @@ -1,11 +0,0 @@ -fmod.check_version({ year = 2023, month = 7, day = 14 }) -- async dofile - -futil = fmod.create() - -futil.dofile("util", "init") -futil.dofile("data_structures", "init") -- depends on util -futil.dofile("minetest", "init") -- depends on util and data_structures - -if INIT == "game" then - futil.async_dofile("init") -end diff --git a/mods/futil/minetest/box.lua b/mods/futil/minetest/box.lua deleted file mode 100644 index 472ff446..00000000 --- a/mods/futil/minetest/box.lua +++ /dev/null @@ -1,186 +0,0 @@ --- box definition below node boxes: https://github.com/minetest/minetest/blob/master/doc/lua_api.md#node-boxes - -local x1 = 1 -local y1 = 2 -local z1 = 3 -local x2 = 4 -local y2 = 5 -local z2 = 6 - -function futil.boxes_intersect(box1, box2) - return not ( - (box1[x2] < box2[x1] or box2[x2] < box1[x1]) - or (box1[y2] < box2[y1] or box2[y2] < box1[y1]) - or (box1[z2] < box2[z1] or box2[z2] < box1[z1]) - ) -end - -function futil.box_offset(box, number_or_vector) - if type(number_or_vector) == "number" then - return { - box[1] + number_or_vector, - box[2] + number_or_vector, - box[3] + number_or_vector, - box[4] + number_or_vector, - box[5] + number_or_vector, - box[6] + number_or_vector, - } - else - return { - box[1] + number_or_vector.x, - box[2] + number_or_vector.y, - box[3] + number_or_vector.z, - box[4] + number_or_vector.x, - box[5] + number_or_vector.y, - box[6] + number_or_vector.z, - } - end -end - -function futil.is_box(box) - if type(box) == "table" and #box == 6 then - for _, x in ipairs(box) do - if type(x) ~= "number" then - return false - end - end - return box[1] <= box[4] and box[2] <= box[5] and box[3] <= box[6] - end - return false -end - -function futil.is_boxes(boxes) - if type(boxes) ~= "table" or #boxes == 0 then - return false - end - - for _, box in ipairs(boxes) do - if not futil.is_box(box) then - return false - end - end - - return true -end - --- given a set of boxes, return a single box that covers all of them -function futil.cover_boxes(boxes) - if not futil.is_boxes(boxes) then - return { 0, 0, 0, 0, 0, 0 } - end - - local cover = boxes[1] - for i = 2, #boxes do - for j = 1, 3 do - cover[j] = math.min(cover[j], boxes[i][j]) - end - for j = 4, 6 do - cover[j] = math.max(cover[j], boxes[i][j]) - end - end - - return cover -end - ---[[ -for nodes: - A nodebox is defined as any of: - - { - -- A normal cube; the default in most things - type = "regular" - } - { - -- A fixed box (or boxes) (facedir param2 is used, if applicable) - type = "fixed", - fixed = box OR {box1, box2, ...} - } - { - -- A variable height box (or boxes) with the top face position defined - -- by the node parameter 'leveled = ', or if 'paramtype2 == "leveled"' - -- by param2. - -- Other faces are defined by 'fixed = {}' as with 'type = "fixed"'. - type = "leveled", - fixed = box OR {box1, box2, ...} - } - { - -- A box like the selection box for torches - -- (wallmounted param2 is used, if applicable) - type = "wallmounted", - wall_top = box, - wall_bottom = box, - wall_side = box - } - { - -- A node that has optional boxes depending on neighboring nodes' - -- presence and type. See also `connects_to`. - type = "connected", - fixed = box OR {box1, box2, ...} - connect_top = box OR {box1, box2, ...} - connect_bottom = box OR {box1, box2, ...} - connect_front = box OR {box1, box2, ...} - connect_left = box OR {box1, box2, ...} - connect_back = box OR {box1, box2, ...} - connect_right = box OR {box1, box2, ...} - -- The following `disconnected_*` boxes are the opposites of the - -- `connect_*` ones above, i.e. when a node has no suitable neighbor - -- on the respective side, the corresponding disconnected box is drawn. - disconnected_top = box OR {box1, box2, ...} - disconnected_bottom = box OR {box1, box2, ...} - disconnected_front = box OR {box1, box2, ...} - disconnected_left = box OR {box1, box2, ...} - disconnected_back = box OR {box1, box2, ...} - disconnected_right = box OR {box1, box2, ...} - disconnected = box OR {box1, box2, ...} -- when there is *no* neighbor - disconnected_sides = box OR {box1, box2, ...} -- when there are *no* - -- neighbors to the sides - } - -for objects: - collisionbox = { -0.5, -0.5, -0.5, 0.5, 0.5, 0.5 }, -- default - selectionbox = { -0.5, -0.5, -0.5, 0.5, 0.5, 0.5, rotate = false }, - -- { xmin, ymin, zmin, xmax, ymax, zmax } in nodes from object position. - -- Collision boxes cannot rotate, setting `rotate = true` on it has no effect. - -- If not set, the selection box copies the collision box, and will also not rotate. - -- If `rotate = false`, the selection box will not rotate with the object itself, remaining fixed to the axes. - -- If `rotate = true`, it will match the object's rotation and any attachment rotations. - -- Raycasts use the selection box and object's rotation, but do *not* obey attachment rotations -]] - -futil.default_collision_box = { -0.5, -0.5, -0.5, 0.5, 0.5, 0.5 } - -function futil.node_collision_box_to_object_collisionbox(collision_box) - if type(collision_box) ~= "table" then - return table.copy(futil.default_collision_box) - elseif collision_box.type == "regular" then - return table.copy(futil.default_collision_box) - elseif collision_box.type == "fixed" or collision_box.type == "leveled" or collision_box.type == "connected" then - if futil.is_box(collision_box.fixed) then - return collision_box.fixed - elseif futil.is_boxes(collision_box.fixed) then - return futil.cover_boxes(collision_box.fixed) - else - return table.copy(futil.default_collision_box) - end - elseif collision_box.type == "wallmounted" then - local boxes = {} - if collision_box.wall_top then - table.insert(boxes, collision_box.wall_top) - end - if collision_box.wall_bottom then - table.insert(boxes, collision_box.wall_bottom) - end - if collision_box.wall_side then - table.insert(boxes, collision_box.wall_side) - end - return futil.cover_boxes(boxes) - else - return table.copy(futil.default_collision_box) - end -end - -function futil.node_selection_box_to_object_selectionbox(selection_box, rotate) - local selectionbox = futil.node_collision_box_to_object_collisionbox(selection_box) - selectionbox.rotate = rotate or false - return selectionbox -end diff --git a/mods/futil/minetest/dedupe.lua b/mods/futil/minetest/dedupe.lua deleted file mode 100644 index 2b59843e..00000000 --- a/mods/futil/minetest/dedupe.lua +++ /dev/null @@ -1,31 +0,0 @@ --- utilities to dedupe messages -local last_by_func = {} -function futil.dedupe(func, ...) - local cur = { ... } - if futil.equals(last_by_func[func], cur) then - return - end - last_by_func[func] = cur - return func(...) -end - -local last_by_player_name_by_func = futil.DefaultTable(function() - return {} -end) -function futil.dedupe_by_player(func, player, ...) - local cur = { ... } - local last_by_player_name = last_by_player_name_by_func[func] - local player_name - - if type(player) == "string" then - player_name = player - else - player_name = player:get_player_name() - end - - if futil.equals(last_by_player_name[player_name], cur) then - return - end - last_by_player_name[player_name] = cur - return func(player, ...) -end diff --git a/mods/futil/minetest/dump.lua b/mods/futil/minetest/dump.lua deleted file mode 100644 index 671169c0..00000000 --- a/mods/futil/minetest/dump.lua +++ /dev/null @@ -1,111 +0,0 @@ --- adapted from https://github.com/minetest/minetest/blob/master/builtin/common/misc_helpers.lua --- but tables are sorted - -local function sorter(a, b) - local ta, tb = type(a), type(b) - if ta ~= tb then - return ta < tb - end - if ta == "function" or ta == "userdata" or ta == "thread" or ta == "table" then - return tostring(a) < tostring(b) - else - return a < b - end -end - -local keywords = { - ["and"] = true, - ["break"] = true, - ["do"] = true, - ["else"] = true, - ["elseif"] = true, - ["end"] = true, - ["false"] = true, - ["for"] = true, - ["function"] = true, - ["goto"] = true, -- Lua 5.2 - ["if"] = true, - ["in"] = true, - ["local"] = true, - ["nil"] = true, - ["not"] = true, - ["or"] = true, - ["repeat"] = true, - ["return"] = true, - ["then"] = true, - ["true"] = true, - ["until"] = true, - ["while"] = true, -} - -local function is_valid_identifier(str) - if not str:find("^[a-zA-Z_][a-zA-Z0-9_]*$") or keywords[str] then - return false - end - return true -end - -local function basic_dump(o) - local tp = type(o) - if tp == "number" then - return tostring(o) - elseif tp == "string" then - return string.format("%q", o) - elseif tp == "boolean" then - return tostring(o) - elseif tp == "nil" then - return "nil" - -- Uncomment for full function dumping support. - -- Not currently enabled because bytecode isn't very human-readable and - -- dump's output is intended for humans. - --elseif tp == "function" then - -- return string.format("loadstring(%q)", string.dump(o)) - elseif tp == "userdata" then - return tostring(o) - else - return string.format("<%s>", tp) - end -end - -function futil.dump(o, indent, nested, level) - local t = type(o) - if not level and t == "userdata" then - -- when userdata (e.g. player) is passed directly, print its metatable: - return "userdata metatable: " .. futil.dump(getmetatable(o)) - end - if t ~= "table" then - return basic_dump(o) - end - - -- Contains table -> true/nil of currently nested tables - nested = nested or {} - if nested[o] then - return "" - end - nested[o] = true - indent = indent or "\t" - level = level or 1 - - local ret = {} - local dumped_indexes = {} - for i, v in ipairs(o) do - ret[#ret + 1] = futil.dump(v, indent, nested, level + 1) - dumped_indexes[i] = true - end - for k, v in futil.table.pairs_by_key(o, sorter) do - if not dumped_indexes[k] then - if type(k) ~= "string" or not is_valid_identifier(k) then - k = "[" .. futil.dump(k, indent, nested, level + 1) .. "]" - end - v = futil.dump(v, indent, nested, level + 1) - ret[#ret + 1] = k .. " = " .. v - end - end - nested[o] = nil - if indent ~= "" then - local indent_str = "\n" .. string.rep(indent, level) - local end_indent_str = "\n" .. string.rep(indent, level - 1) - return string.format("{%s%s%s}", indent_str, table.concat(ret, "," .. indent_str), end_indent_str) - end - return "{" .. table.concat(ret, ", ") .. "}" -end diff --git a/mods/futil/minetest/fake_inventory.lua b/mods/futil/minetest/fake_inventory.lua deleted file mode 100644 index 096f7124..00000000 --- a/mods/futil/minetest/fake_inventory.lua +++ /dev/null @@ -1,271 +0,0 @@ -local FakeInventory = futil.class1() - -local function copy_list(list) - local copy = {} - for i = 1, #list do - copy[i] = ItemStack(list[i]) - end - return copy -end - -function FakeInventory:_init() - self._lists = {} -end - -function FakeInventory.create_copy(inv) - local fake_inv = FakeInventory() - for listname, contents in pairs(inv:get_lists()) do - fake_inv:set_size(listname, inv:get_size(listname)) - fake_inv:set_width(listname, inv:get_width(listname)) - fake_inv:set_list(listname, contents) - end - return fake_inv -end - -function FakeInventory.room_for_all(inv, listname, items) - local fake_inv = FakeInventory.create_copy(inv) - for i = 1, #items do - local item = items[i] - local remainder = fake_inv:add_item(listname, item) - if not remainder:is_empty() then - return false - end - end - return true -end - -function FakeInventory:is_empty(listname) - local list = self._lists[listname] - if not list then - return true - end - for _, stack in ipairs(list) do - if not stack:is_empty() then - return false - end - end - return true -end - -function FakeInventory:get_size(listname) - local list = self._lists[listname] - if not list then - return 0 - end - return #list -end - -function FakeInventory:set_size(listname, size) - if size == 0 then - self._lists[listname] = nil - return - end - - local list = self._lists[listname] or {} - - while #list < size do - list[#list + 1] = ItemStack() - end - - for i = size + 1, #list do - list[i] = nil - end - - self._lists[listname] = list -end - -function FakeInventory:get_width(listname) - local list = self._lists[listname] or {} - return list.width or 0 -end - -function FakeInventory:set_width(listname, width) - local list = self._lists[listname] or {} - list.width = width - self._lists[listname] = list -end - -function FakeInventory:get_stack(listname, i) - local list = self._lists[listname] - if not list or i > #list then - return ItemStack() - end - return ItemStack(list[i]) -end - -function FakeInventory:set_stack(listname, i, stack) - local list = self._lists[listname] - if not list or i > #list then - return - end - list[i] = ItemStack(stack) -end - -function FakeInventory:get_list(listname) - local list = self._lists[listname] - if not list then - return - end - return copy_list(list) -end - -function FakeInventory:set_list(listname, list) - local ourlist = self._lists[listname] - if not ourlist then - return - end - - for i = 1, #ourlist do - ourlist[i] = ItemStack(list[i]) - end -end - -function FakeInventory:get_lists() - local lists = {} - for listname, list in pairs(self._lists) do - lists[listname] = copy_list(list) - end - return lists -end - -function FakeInventory:set_lists(lists) - for listname, list in pairs(lists) do - self:set_list(listname, list) - end -end - --- add item somewhere in list, returns leftover `ItemStack`. -function FakeInventory:add_item(listname, new_item) - local list = self._lists[listname] - new_item = ItemStack(new_item) - if new_item:is_empty() or not list or #list == 0 then - return new_item - end - - -- first try to find if it could be added to some existing items - for _, our_stack in ipairs(list) do - if not our_stack:is_empty() then - new_item = our_stack:add_item(new_item) - if new_item:is_empty() then - return new_item - end - end - end - - -- then try to add it to empty slots - for _, our_stack in ipairs(list) do - new_item = our_stack:add_item(new_item) - if new_item:is_empty() then - break - end - end - - return new_item -end - --- returns `true` if the stack of items can be fully added to the list -function FakeInventory:room_for_item(listname, stack) - local list = self._lists[listname] - if not list then - return false - end - - stack = ItemStack(stack) - local copy = copy_list(list) - for _, our_stack in ipairs(copy) do - stack = our_stack:add_item(stack) - if stack:is_empty() then - break - end - end - - return stack:is_empty() -end - --- take as many items as specified from the list, returns the items that were actually removed (as an `ItemStack`) --- note that any item metadata is ignored, so attempting to remove a specific unique item this way will likely remove --- the wrong one -- to do that use `set_stack` with an empty `ItemStack`. -function FakeInventory:remove_item(listname, stack) - local removed = ItemStack() - stack = ItemStack(stack) - - local list = self._lists[listname] - if not list or stack:is_empty() then - return removed - end - - local name = stack:get_name() - local count_remaining = stack:get_count() - local taken = 0 - - for i = #list, 1, -1 do - local our_stack = list[i] - if our_stack:get_name() == name then - local n = our_stack:take_item(count_remaining):get_count() - count_remaining = count_remaining - n - taken = taken + n - end - - if count_remaining == 0 then - break - end - end - - stack:set_count(taken) - - return stack -end - --- returns `true` if the stack of items can be fully taken from the list. --- If `match_meta` is false, only the items' names are compared (default: `false`). -function FakeInventory:contains_item(listname, stack, match_meta) - local list = self._lists[listname] - if not list then - return false - end - - stack = ItemStack(stack) - - if match_meta then - local name = stack:get_name() - local wear = stack:get_wear() - local meta = stack:get_meta() - local needed_count = stack:get_count() - - for _, our_stack in ipairs(list) do - if our_stack:get_name() == name and our_stack:get_wear() == wear and our_stack:get_meta():equals(meta) then - local n = our_stack:peek_item(needed_count):get_count() - needed_count = needed_count - n - end - if needed_count == 0 then - break - end - end - - return needed_count == 0 - else - local name = stack:get_name() - local needed_count = stack:get_count() - - for _, our_stack in ipairs(list) do - if our_stack:get_name() == name then - local n = our_stack:peek_item(needed_count):get_count() - needed_count = needed_count - n - end - if needed_count == 0 then - break - end - end - - return needed_count == 0 - end -end - -function FakeInventory:get_location() - return { - type = "undefined", - subtype = "FakeInventory", - } -end - -futil.FakeInventory = FakeInventory diff --git a/mods/futil/minetest/globalstep.lua b/mods/futil/minetest/globalstep.lua deleted file mode 100644 index b9c4d219..00000000 --- a/mods/futil/minetest/globalstep.lua +++ /dev/null @@ -1,88 +0,0 @@ ---[[ -execute the globalstep after the specified period. the actual amount of time elapsed is passed to the function, -and will always be greater than or equal to the length of the period. -futil.register_globalstep({ - period = 1, - func = function(elapsed) end, -}) - -execute the globalstep after the specified period. if more time has elapsed than the period specified, the remainder -will be counted against the next cycle, allowing the execution to "catch up". the expected time between executions -will tend towards the specified period. IMPORTANT: do not specify a period which is less than the length of the -dedicated server step. -futil.register_globalstep({ - period = 1, - catchup = "single" - func = function(period) end, -}) - -execute the globalstep after the specified period. if more time has elapsed than the period specified, the callback -will be executed repeatedly until the elapsed time is less than the period, and the remainder will still be counted -against the next cycle. -futil.register_globalstep({ - period = 1, - catchup = "full" - func = function(period) end, -}) - -this is just a light wrapper over a normal minetest globalstep callback, and is only provided for completeness. -futil.register_globalstep({ - func = function(dtime) end, -}) -]] -local f = string.format - -local dedicated_server_step = tonumber(minetest.settings:get("dedicated_server_step")) or 0.09 - -function futil.register_globalstep(def) - if def.period then - local elapsed = 0 - if def.catchup == "full" then - assert(def.period > 0, "full catchup will cause an infinite loop if period is 0") - minetest.register_globalstep(function(dtime) - elapsed = elapsed + dtime - if elapsed < def.period then - return - end - elapsed = elapsed - def.period - def.func(def.period) - while elapsed > def.period do - elapsed = elapsed - def.period - def.func(def.period) - end - end) - elseif def.catchup == "single" or def.catchup == true then - assert( - def.period >= dedicated_server_step, - f( - "if period (%s) is less than dedicated_server_step (%s), single catchup will never fully catch up.", - def.period, - dedicated_server_step - ) - ) - minetest.register_globalstep(function(dtime) - elapsed = elapsed + dtime - if elapsed < def.period then - return - end - elapsed = elapsed - def.period - def.func(def.period) - end) - else - -- no catchup, just reset - minetest.register_globalstep(function(dtime) - elapsed = elapsed + dtime - if elapsed < def.period then - return - end - def.func(elapsed) - elapsed = 0 - end) - end - else - -- we do nothing useful - minetest.register_globalstep(function(dtime) - def.func(dtime) - end) - end -end diff --git a/mods/futil/minetest/group.lua b/mods/futil/minetest/group.lua deleted file mode 100644 index 76ebf8a4..00000000 --- a/mods/futil/minetest/group.lua +++ /dev/null @@ -1,61 +0,0 @@ -function futil.add_groups(itemstring, new_groups) - local def = minetest.registered_items[itemstring] - if not def then - error(("attempting to override unknown item %s"):format(itemstring)) - end - local groups = table.copy(def.groups or {}) - futil.table.set_all(groups, new_groups) - minetest.override_item(itemstring, { groups = groups }) -end - -function futil.remove_groups(itemstring, ...) - local def = minetest.registered_items[itemstring] - if not def then - error(("attempting to override unknown item %s"):format(itemstring)) - end - local groups = table.copy(def.groups or {}) - for _, group in ipairs({ ... }) do - groups[group] = nil - end - minetest.override_item(itemstring, { groups = groups }) -end - -function futil.get_items_with_group(group) - if futil.items_by_group then - return futil.items_by_group[group] or {} - end - - local items = {} - - for item in pairs(minetest.registered_items) do - if minetest.get_item_group(item, group) > 0 then - table.insert(items, item) - end - end - - return items -end - -function futil.get_item_with_group(group) - return futil.get_items_with_group(group)[1] -end - -function futil.generate_items_by_group() - local items_by_group = {} - - for item, def in pairs(minetest.registered_items) do - for group in pairs(def.groups or {}) do - local items = items_by_group[group] or {} - table.insert(items, item) - items_by_group[group] = items - end - end - - futil.items_by_group = items_by_group -end - -if INIT == "game" then - -- it's not 100% safe to assume items and groups can't change after this point. - -- but please, don't do that :\ - minetest.register_on_mods_loaded(futil.generate_items_by_group) -end diff --git a/mods/futil/minetest/hud_ephemeral.lua b/mods/futil/minetest/hud_ephemeral.lua deleted file mode 100644 index c19ecea8..00000000 --- a/mods/futil/minetest/hud_ephemeral.lua +++ /dev/null @@ -1,100 +0,0 @@ -local f = string.format - -local current_id = 0 - -local function get_next_id() - current_id = current_id + 1 - return current_id -end - -local EphemeralHud = futil.class1() - -function EphemeralHud:_init(player, hud_def) - self._player_name = player:get_player_name() - if (hud_def.type or hud_def.hud_elem_type) == "waypoint" then - self._id_field = "text2" - else - self._id_field = "name" - end - self._id = f("ephemeral_hud:%s:%i", hud_def[self._id_field] or "", get_next_id()) - hud_def[self._id_field] = self._id - self._hud_id = player:hud_add(hud_def) -end - -function EphemeralHud:is_active() - if not self._hud_id then - return false - end - local player = minetest.get_player_by_name(self._player_name) - if not player then - self._hud_id = nil - return false - end - local hud_def = player:hud_get(self._hud_id) - if not hud_def then - self._hud_id = nil - return false - end - if hud_def[self._id_field] ~= self._id then - self._hud_id = nil - return false - end - - return true -end - -function EphemeralHud:change(new_hud_def) - if not self:is_active() then - futil.log("warning", "[ephemeral hud] cannot update an inactive hud") - return false - end - local player = minetest.get_player_by_name(self._player_name) - local old_hud_def = player:hud_get(self._hud_id) - for key, value in pairs(new_hud_def) do - if key == "hud_elem_type" then - if value ~= (old_hud_def.type or old_hud_def.hud_elem_type) then - error("cannot change hud_elem_type") - end - elseif key == "type" then - if value ~= (old_hud_def.type or old_hud_def.hud_elem_type) then - error("cannot change type") - end - elseif key == self._id_field then - if value ~= self._id then - error(f("cannot change the value of %q, as this is an ID", self._id_field)) - end - else - if key == "position" or key == "scale" or key == "align" or key == "offset" then - value = futil.vector.v2f_to_float_32(value) - end - - if not futil.equals(old_hud_def[key], value) then - player:hud_change(self._hud_id, key, value) - end - end - end - return true -end - -function EphemeralHud:remove() - if not self:is_active() then - futil.log("warning", "[ephemeral hud] cannot remove an inactive hud") - return false - end - local player = minetest.get_player_by_name(self._player_name) - player:hud_remove(self._hud_id) - self._hud_id = nil -end - -futil.EphemeralHud = EphemeralHud - --- note: sometimes HUDs can fail to get created. if so, the HUD object returned here will be "inactive". -function futil.create_ephemeral_hud(player, timeout, hud_def) - local hud = EphemeralHud(player, hud_def) - minetest.after(timeout, function() - if hud:is_active() then - hud:remove() - end - end) - return hud -end diff --git a/mods/futil/minetest/hud_manager.lua b/mods/futil/minetest/hud_manager.lua deleted file mode 100644 index 04d9ab06..00000000 --- a/mods/futil/minetest/hud_manager.lua +++ /dev/null @@ -1,172 +0,0 @@ ---[[ -local my_hud = futil.define_hud("my_mod:my_hud", { - period = 1, - catchup = nil, -- not currently supported - name_field = nil, -- in case you want to override the id field - enabled_by_default = nil, -- set to true to enable by default - get_hud_data = function() - -- get data that's identical for all players - -- passed to get_hud_def - end, - get_hud_def = function(player, data) - return {} - end, -}) - -my_hud:toggle_enabled(player) -]] - -local f = string.format - -local ManagedHud = futil.class1() - -function ManagedHud:_init(hud_name, def) - self.name = hud_name - - self._name_field = def.name_field or ((def.type or def.hud_elem_type) == "waypoint" and "text2" or "name") - self._period = def.period - self._get_hud_data = def.get_hud_data - self._get_hud_def = def.get_hud_def - self._enabled_by_default = def.enabled_by_default - - self._hud_id_by_player_name = {} - - self._hud_enabled_key = f("hud_manager:%s_enabled", hud_name) - self._hud_name = f("hud_manager:%s", hud_name) -end - -function ManagedHud:is_enabled(player) - local meta = player:get_meta() - local value = meta:get(self._hud_enabled_key) - if value == nil then - return self._enabled_by_default - else - return minetest.is_yes(value) - end -end - -function ManagedHud:set_enabled(player, value) - local meta = player:get_meta() - if minetest.is_yes(value) then - meta:set_string(self._hud_enabled_key, "y") - else - meta:set_string(self._hud_enabled_key, "n") - end -end - -function ManagedHud:toggle_enabled(player) - local meta = player:get_meta() - local enabled = not self:is_enabled(player) - if enabled then - meta:set_string(self._hud_enabled_key, "y") - else - meta:set_string(self._hud_enabled_key, "n") - end - return enabled -end - -function ManagedHud:update(player, data) - local is_enabled = self:is_enabled(player) - local player_name = player:get_player_name() - local hud_id = self._hud_id_by_player_name[player_name] - local old_hud_def - if hud_id then - old_hud_def = player:hud_get(hud_id) - if old_hud_def and old_hud_def[self._name_field] == self._hud_name then - if not is_enabled then - player:hud_remove(hud_id) - self._hud_id_by_player_name[player_name] = nil - return - end - else - -- hud_id is bad - hud_id = nil - old_hud_def = nil - end - end - - if is_enabled then - local new_hud_def = self._get_hud_def(player, data) - if not new_hud_def then - if hud_id then - player:hud_remove(hud_id) - self._hud_id_by_player_name[player_name] = nil - end - return - elseif new_hud_def[self._name_field] and new_hud_def[self._name_field] ~= self._hud_name then - error(f("you cannot specify the value of the %q field, this is generated", self._name_field)) - end - - if old_hud_def then - for k, v in pairs(new_hud_def) do - if k == "position" or k == "scale" or k == "align" or k == "offset" then - v = futil.vector.v2f_to_float_32(v) - end - - if not futil.equals(old_hud_def[k], v) and k ~= "type" and k ~= "hud_elem_type" then - player:hud_change(hud_id, k, v) - end - end - else - new_hud_def[self._name_field] = self._hud_name - hud_id = player:hud_add(new_hud_def) - end - end - - self._hud_id_by_player_name[player_name] = hud_id -end - -futil.defined_huds = {} - -function futil.define_hud(hud_name, def) - if futil.defined_huds[hud_name] then - error(f("hud %s already exists", hud_name)) - end - local hud = ManagedHud(hud_name, def) - futil.defined_huds[hud_name] = hud - return hud -end - --- TODO: register_hud instead of define_hud, plus alias the old - -local function update_hud(hud, players) - local data - if hud._get_hud_data then - local is_any_enabled = false - for i = 1, #players do - if hud:is_enabled(players[i]) then - is_any_enabled = true - break - end - end - if is_any_enabled then - data = hud._get_hud_data() - end - end - for i = 1, #players do - hud:update(players[i], data) - end -end - --- TODO refactor to use futil.register_globalstep for each hud, to allow use of catchup mechanics --- ... why would HUD updates need catchup mechanics? -local elapsed_by_hud_name = {} -minetest.register_globalstep(function(dtime) - local players = minetest.get_connected_players() - if #players == 0 then - return - end - for hud_name, hud in pairs(futil.defined_huds) do - if hud._period then - local elapsed = (elapsed_by_hud_name[hud_name] or 0) + dtime - if elapsed < hud._period then - elapsed_by_hud_name[hud_name] = elapsed - else - elapsed_by_hud_name[hud_name] = 0 - update_hud(hud, players) - end - else - update_hud(hud, players) - end - end -end) diff --git a/mods/futil/minetest/image.lua b/mods/futil/minetest/image.lua deleted file mode 100644 index 65ced329..00000000 --- a/mods/futil/minetest/image.lua +++ /dev/null @@ -1,171 +0,0 @@ -local f = string.format - -local function is_vertical_frames(animation) - return (animation.type == "vertical_frames" and animation.aspect_w and animation.aspect_h) -end - -local function get_single_frame(animation, image_name) - return ("[combine:%ix%i^[noalpha^[colorize:#FFF:255^[mask:%s"):format( - animation.aspect_w, - animation.aspect_h, - image_name - ) -end - -local function is_sheet_2d(animation) - return (animation.type == "sheet_2d" and animation.frames_w and animation.frames_h) -end - -local function get_sheet_2d(animation, image_name) - return ("%s^[sheet:%ix%i:0,0"):format(image_name, animation.frames_w, animation.frames_h) -end - -local get_image_from_tile = futil.memoize1(function(tile) - if type(tile) == "string" then - return tile - elseif type(tile) == "table" then - local image_name - - if type(tile.image) == "string" then - image_name = tile.image - elseif type(tile.name) == "string" then - image_name = tile.name - end - - if image_name then - local animation = tile.animation - if animation then - if is_vertical_frames(animation) then - return get_single_frame(animation, image_name) - elseif is_sheet_2d(animation) then - return get_sheet_2d(animation, image_name) - end - end - - return image_name - end - end - - return "unknown_node.png" -end) - -local function get_image_cube(tiles) - if #tiles >= 6 then - return minetest.inventorycube( - get_image_from_tile(tiles[1] or "no_texture.png"), - get_image_from_tile(tiles[6] or "no_texture.png"), - get_image_from_tile(tiles[3] or "no_texture.png") - ) - elseif #tiles == 5 then - return minetest.inventorycube( - get_image_from_tile(tiles[1] or "no_texture.png"), - get_image_from_tile(tiles[5] or "no_texture.png"), - get_image_from_tile(tiles[3] or "no_texture.png") - ) - elseif #tiles == 4 then - return minetest.inventorycube( - get_image_from_tile(tiles[1] or "no_texture.png"), - get_image_from_tile(tiles[4] or "no_texture.png"), - get_image_from_tile(tiles[3] or "no_texture.png") - ) - elseif #tiles == 3 then - return minetest.inventorycube( - get_image_from_tile(tiles[1] or "no_texture.png"), - get_image_from_tile(tiles[3] or "no_texture.png"), - get_image_from_tile(tiles[3] or "no_texture.png") - ) - elseif #tiles == 2 then - return minetest.inventorycube( - get_image_from_tile(tiles[1] or "no_texture.png"), - get_image_from_tile(tiles[2] or "no_texture.png"), - get_image_from_tile(tiles[2] or "no_texture.png") - ) - elseif #tiles == 1 then - return minetest.inventorycube( - get_image_from_tile(tiles[1] or "no_texture.png"), - get_image_from_tile(tiles[1] or "no_texture.png"), - get_image_from_tile(tiles[1] or "no_texture.png") - ) - end - - return "no_texture.png" -end - -local function is_normal_node(drawtype) - return ( - drawtype == "normal" - or drawtype == "allfaces" - or drawtype == "allfaces_optional" - or drawtype == "glasslike" - or drawtype == "glasslike_framed" - or drawtype == "glasslike_framed_optional" - or drawtype == "liquid" - ) -end - -local cache = {} - -function futil.get_wield_image(item) - if type(item) == "string" then - item = ItemStack(item) - end - - if item:is_empty() then - return "blank.png" - end - - local def = item:get_definition() - if not def then - return "unknown_item.png" - end - - local itemstring = item:to_string() - local cached = cache[itemstring] - if cached then - return cached - end - - local meta = item:get_meta() - local color = meta:get("color") or def.color - - local image = "no_texture.png" - - if def.wield_image and def.wield_image ~= "" then - local parts = { def.wield_image } - if color then - parts[#parts + 1] = f("[colorize:%s:alpha", futil.escape_texture(color)) - end - if def.wield_overlay then - parts[#parts + 1] = def.wield_overlay - end - image = table.concat(parts, "^") - elseif def.inventory_image and def.inventory_image ~= "" then - local parts = { def.inventory_image } - if color then - parts[#parts + 1] = f("[colorize:%s:alpha", futil.escape_texture(color)) - end - if def.inventory_overlay then - parts[#parts + 1] = def.inventory_overlay - end - image = table.concat(parts, "^") - elseif def.type == "node" then - if def.drawtype == "nodebox" or def.drawtype == "mesh" then - image = "no_texture.png" - else - local tiles = def.tiles - if type(tiles) == "string" then - image = get_image_from_tile(tiles) - elseif type(tiles) == "table" then - if is_normal_node(def.drawtype) then - image = get_image_cube(tiles) - else - image = get_image_from_tile(tiles[1]) - end - end - end - end - - cache[itemstring] = image - - return image -end diff --git a/mods/futil/minetest/init.lua b/mods/futil/minetest/init.lua deleted file mode 100644 index 24dd60a2..00000000 --- a/mods/futil/minetest/init.lua +++ /dev/null @@ -1,23 +0,0 @@ -futil.dofile("minetest", "box") -futil.dofile("minetest", "dedupe") -futil.dofile("minetest", "dump") -futil.dofile("minetest", "fake_inventory") -futil.dofile("minetest", "group") -futil.dofile("minetest", "image") -futil.dofile("minetest", "item") -futil.dofile("minetest", "registration") -futil.dofile("minetest", "serialization") -futil.dofile("minetest", "strip_translation") -futil.dofile("minetest", "texture") -futil.dofile("minetest", "time") -futil.dofile("minetest", "vector") - -if INIT == "game" then - futil.dofile("minetest", "globalstep") - futil.dofile("minetest", "hud_ephemeral") - futil.dofile("minetest", "hud_manager") - futil.dofile("minetest", "inventory") - futil.dofile("minetest", "object") - futil.dofile("minetest", "object_properties") - futil.dofile("minetest", "raycast") -end diff --git a/mods/futil/minetest/inventory.lua b/mods/futil/minetest/inventory.lua deleted file mode 100644 index 46781d9b..00000000 --- a/mods/futil/minetest/inventory.lua +++ /dev/null @@ -1,40 +0,0 @@ -function futil.get_location_string(inv) - local location = inv:get_location() - if location.type == "node" then - return ("nodemeta:%i,%i,%i"):format(location.pos.x, location.pos.y, location.pos.z) - elseif location.type == "player" then - return ("player:%s"):format(location.name) - elseif location.type == "detached" then - return ("detached:%s"):format(location.name) - else - error(("unexpected location? %s"):format(dump(location))) - end -end - --- InvRef:remove_item() ignores metadata, and sometimes that's wrong --- for logic, see InventoryList::removeItem in inventory.cpp -function futil.remove_item_with_meta(inv, listname, itemstack) - itemstack = ItemStack(itemstack) - if itemstack:is_empty() then - return ItemStack() - end - local removed = ItemStack() - for i = 1, inv:get_size(listname) do - local invstack = inv:get_stack(listname, i) - if - invstack:get_name() == itemstack:get_name() - and invstack:get_wear() == itemstack:get_wear() - and invstack:get_meta() == itemstack:get_meta() - then - local still_to_remove = itemstack:get_count() - removed:get_count() - local leftover = removed:add_item(invstack:take_item(still_to_remove)) - -- if we've requested to remove more than the stack size, ignore the limit - removed:set_count(removed:get_count() + leftover:get_count()) - inv:set_stack(listname, i, invstack) - if removed:get_count() == itemstack:get_count() then - break - end - end - end - return removed -end diff --git a/mods/futil/minetest/item.lua b/mods/futil/minetest/item.lua deleted file mode 100644 index 81a6b222..00000000 --- a/mods/futil/minetest/item.lua +++ /dev/null @@ -1,133 +0,0 @@ -local f = string.format - --- if allow_unregistered is false or absent, if the original item or its alias is not a registered item, will return nil -function futil.resolve_item(item_or_string, allow_unregistered) - local item_stack = ItemStack(item_or_string) - local name = item_stack:get_name() - - local seen = { [name] = true } - - local alias = minetest.registered_aliases[name] - while alias do - name = alias - seen[name] = true - alias = minetest.registered_aliases[name] - if seen[alias] then - error(f("alias cycle on %s", name)) - end - end - - if minetest.registered_items[name] or allow_unregistered then - item_stack:set_name(name) - return item_stack:to_string() - end -end - -function futil.resolve_itemstack(item_or_string) - return ItemStack(futil.resolve_item(item_or_string, true)) -end - -if ItemStack().equals then - -- https://github.com/minetest/minetest/pull/12771 - function futil.items_equals(item1, item2) - item1 = type(item1) == "userdata" and item1 or ItemStack(item1) - item2 = type(item2) == "userdata" and item2 or ItemStack(item2) - - return item1 == item2 - end -else - local equals = futil.equals - - function futil.items_equals(item1, item2) - item1 = type(item1) == "userdata" and item1 or ItemStack(item1) - item2 = type(item2) == "userdata" and item2 or ItemStack(item2) - - return equals(item1:to_table(), item2:to_table()) - end -end - --- TODO: probably this should have a 3nd argument to handle tool and tool_group stuff -function futil.get_primary_drop(stack, filter) - stack = ItemStack(stack) - - local name = stack:get_name() - local meta = stack:get_meta() - local palette_index = tonumber(meta:get_int("palette_index")) - local def = stack:get_definition() - - if palette_index then - -- https://github.com/mt-mods/unifieddyes/blob/36c8bb5f5b8a0485225d2547c8978291ff710291/api.lua#L70-L90 - local del_color - - if def.paramtype2 == "color" and palette_index == 240 and def.palette == "unifieddyes_palette_extended.png" then - del_color = true - elseif - def.paramtype2 == "colorwallmounted" - and palette_index == 0 - and def.palette == "unifieddyes_palette_colorwallmounted.png" - then - del_color = true - elseif - def.paramtype2 == "colorfacedir" - and palette_index == 0 - and string.find(def.palette, "unifieddyes_palette_") - then - del_color = true - end - - if del_color then - meta:set_string("palette_index", "") - palette_index = nil - end - end - - local drop = def.drop - - if drop == nil then - stack:set_count(1) - return stack - elseif drop == "" then - return nil - elseif type(drop) == "string" then - drop = ItemStack(drop) - drop:set_count(1) - return drop - elseif type(drop) == "table" then - local most_common_item - local inherit_color = false - local rarity = math.huge - - if not drop.items then - error(f("unexpected drop table for %s: %s", stack:to_string(), dump(drop))) - end - - for _, items in ipairs(drop.items) do - if (items.rarity or 1) < rarity then - for item in ipairs(items.items) do - if (not filter) or filter(item) then - most_common_item = item - inherit_color = items.inherit_color or false - rarity = items.rarity - break - end - end - end - end - - if not most_common_item then - return - end - - most_common_item = ItemStack(most_common_item) - most_common_item:set_count(1) - - if inherit_color and palette_index then - local meta2 = most_common_item:get_meta() - meta2:set_int("palette_index", palette_index) - end - - return most_common_item - else - error(f("invalid drop of %s? %q", dump(name, drop))) - end -end diff --git a/mods/futil/minetest/object.lua b/mods/futil/minetest/object.lua deleted file mode 100644 index b05ee555..00000000 --- a/mods/futil/minetest/object.lua +++ /dev/null @@ -1,200 +0,0 @@ -local v_new = vector.new - --- if object is attached, get the velocity of the object it is attached to -function futil.get_velocity(object) - local parent = object:get_attach() - while parent do - object = parent - parent = object:get_attach() - end - return object:get_velocity() -end - -function futil.get_horizontal_speed(object) - local velocity = futil.get_velocity(object) - velocity.y = 0 - return vector.length(velocity) -end - -local function insert_connected(boxes, something) - if futil.is_box(something) then - table.insert(boxes, something) - elseif futil.is_boxes(something) then - table.insert_all(boxes, something) - end -end - -local function get_boxes(cb) - if not cb then - return { { -0.5, -0.5, -0.5, 0.5, 0.5, 0.5 } } - end - - if cb.type == "regular" then - return { { -0.5, -0.5, -0.5, 0.5, 0.5, 0.5 } } - elseif cb.type == "fixed" then - if futil.is_box(cb.fixed) then - return { cb.fixed } - elseif futil.is_boxes(cb.fixed) then - return cb.fixed - else - return { { -0.5, -0.5, -0.5, 0.5, 0.5, 0.5 } } - end - elseif cb.type == "leveled" then - -- TODO: have to check param2 - if futil.is_box(cb.fixed) then - return { cb.fixed } - elseif futil.is_boxes(cb.fixed) then - return cb.fixed - else - return { { -0.5, -0.5, -0.5, 0.5, 0.5, 0.5 } } - end - elseif cb.type == "wallmounted" then - -- TODO: have to check param2? or? - local boxes = {} - - if futil.is_box(cb.wall_top) then - table.insert(boxes, cb.wall_top) - end - if futil.is_box(cb.wall_bottom) then - table.insert(boxes, cb.wall_bottom) - end - if futil.is_box(cb.wall_side) then - table.insert(boxes, cb.wall_side) - end - - if #boxes > 0 then - return boxes - else - return { { -0.5, -0.5, -0.5, 0.5, 0.5, 0.5 } } - end - elseif cb.type == "connected" then - -- TODO: very very complicated to check, just fudge and add everything - local boxes = {} - - insert_connected(boxes, cb.fixed) - insert_connected(boxes, cb.connect_top) - insert_connected(boxes, cb.connect_bottom) - insert_connected(boxes, cb.connect_front) - insert_connected(boxes, cb.connect_left) - insert_connected(boxes, cb.connect_back) - insert_connected(boxes, cb.connect_right) - insert_connected(boxes, cb.disconnected_top) - insert_connected(boxes, cb.disconnected_bottom) - insert_connected(boxes, cb.disconnected_front) - insert_connected(boxes, cb.disconnected_left) - insert_connected(boxes, cb.disconnected_back) - insert_connected(boxes, cb.disconnected_right) - insert_connected(boxes, cb.disconnected) - insert_connected(boxes, cb.disconnected_sides) - - if #boxes > 0 then - return boxes - else - return { { -0.5, -0.5, -0.5, 0.5, 0.5, 0.5 } } - end - end - - return { { -0.5, -0.5, -0.5, 0.5, 0.5, 0.5 } } -end - -local function get_collision_boxes(node) - local node_def = minetest.registered_nodes[node.name] - - if not node_def then - -- unknown nodes are regular solid nodes - return { { -0.5, -0.5, -0.5, 0.5, 0.5, 0.5 } } - end - - if not node_def.walkable then - return {} - end - - local boxes - if node_def.collision_box then - boxes = get_boxes(node_def.collision_box) - elseif node_def.drawtype == "nodebox" then - boxes = get_boxes(node_def.node_box) - else - boxes = { { -0.5, -0.5, -0.5, 0.5, 0.5, 0.5 } } - end - - --[[ - if node_def.paramtype2 == "facedir" then - -- TODO: re-orient boxes - end - ]] - - return boxes -end - -local function is_pos_on_ground(feet_pos, player_box) - local node = minetest.get_node(feet_pos) - local node_boxes = get_collision_boxes(node) - - for _, node_box in ipairs(node_boxes) do - local actual_node_box = futil.box_offset(node_box, feet_pos) - if futil.boxes_intersect(actual_node_box, player_box) then - return true - end - end - - return false -end - -function futil.is_on_ground(player) - local p_pos = player:get_pos() - local cb = player:get_properties().collisionbox - - -- collect the positions of the nodes below the player's feet - local feet_poss = { - v_new(math.round(p_pos.x + cb[1]), math.ceil(p_pos.y + cb[2] - 0.5), math.round(p_pos.z + cb[3])), - v_new(math.round(p_pos.x + cb[1]), math.ceil(p_pos.y + cb[2] - 0.5), math.round(p_pos.z + cb[6])), - v_new(math.round(p_pos.x + cb[4]), math.ceil(p_pos.y + cb[2] - 0.5), math.round(p_pos.z + cb[3])), - v_new(math.round(p_pos.x + cb[4]), math.ceil(p_pos.y + cb[2] - 0.5), math.round(p_pos.z + cb[6])), - } - - for _, feet_pos in ipairs(feet_poss) do - if is_pos_on_ground(feet_pos, futil.box_offset(cb, p_pos)) then - return true - end - end - - return false -end - -function futil.get_object_center(object) - local pos = object:get_pos() - if not pos then - return - end - local cb = object:get_properties().collisionbox - return v_new(pos.x + (cb[1] + cb[4]) / 2, pos.y + (cb[2] + cb[5]) / 2, pos.z + (cb[3] + cb[6]) / 2) -end - -function futil.is_player(obj) - return minetest.is_player(obj) and not obj.is_fake_player -end - -function futil.is_valid_object(obj) - return obj and type(obj.get_pos) == "function" and vector.check(obj:get_pos()) -end - --- this is meant to be able to get the HP of any object, including "immortal" ones whose health is managed themselves --- it is *NOT* complete - i've got no idea where every mob API stores its hp. --- "health" is mobs_redo (which is actually redundant with `:get_hp()` because they're not actually immortal. --- "hp" is mobkit (and petz, which comes with its own fork of mobkit), and also creatura. -function futil.get_hp(obj) - if not futil.is_valid_object(obj) then - -- not an object or dead - return 0 - end - local ent = obj:get_luaentity() - if ent and (type(ent.hp) == "number" or type(ent.health) == "number") then - return ent.hp or ent.health - end - local armor_groups = obj:get_armor_groups() - if (armor_groups["immortal"] or 0) == 0 then - return obj:get_hp() - end - return math.huge -- presumably actually immortal -end diff --git a/mods/futil/minetest/object_properties.lua b/mods/futil/minetest/object_properties.lua deleted file mode 100644 index 754bb2a5..00000000 --- a/mods/futil/minetest/object_properties.lua +++ /dev/null @@ -1,158 +0,0 @@ -local f = string.format - -local iall = futil.functional.iall -local map = futil.map - -local in_bounds = futil.math.in_bounds - -local is_integer = futil.math.is_integer -local is_number = futil.is_number -local is_string = futil.is_string -local is_table = futil.is_table - -local function valid_box(value) - if value == nil then - return true - elseif not is_table(value) then - return false - elseif #value ~= 6 then - return false - else - return iall(map(is_number, value)) - end -end - -local function valid_visual_size(value) - if not is_table(value) then - return false - end - - local z_type = type(value.z) - return is_number(value.x) and is_integer(value.y) and (z_type == "number" or z_type == nil) -end - -local function valid_textures(value) - if not is_table(value) then - return false - end - - return iall(map(is_string, value)) -end - -local function valid_color_spec(value) - local t = type(value) - if t == "string" then - -- TODO: we could check for valid values, but that's ... tedious - return true - elseif t == "table" then - local is_number_ = is_number - local is_integer_ = is_integer - local in_bounds_ = in_bounds - local x = value.x - local y = value.y - local z = value.z - local a = value.a - - return ( - is_number_(x) - and in_bounds_(0, x, 255) - and is_integer_(x) - and is_number_(y) - and in_bounds_(0, y, 255) - and is_integer_(y) - and is_number_(z) - and in_bounds_(0, z, 255) - and is_integer_(z) - and (a == nil or (is_number_(a) and in_bounds_(0, a, 255) and is_integer_(a))) - ) - end - - return false -end - -local function valid_colors(value) - if not is_table(value) then - return false - end - - return iall(map(valid_color_spec, value)) -end - -local function valid_spritediv(value) - if not is_table(value) then - return false - end - - local x = value.x - local y = value.y - - return is_number(x) and is_integer(x) and is_number(y) and is_number(y) -end - -local function valid_automatic_face_movement_dir(value) - return value == false or is_number(value) -end - -local function valid_hp_max(value) - return is_number(value) and is_integer(value) and in_bounds(1, value, 65535) -end - -local object_property = { - visual = "string", - visual_size = valid_visual_size, - mesh = "string", - textures = valid_textures, - colors = valid_colors, - use_texture_alpha = "boolean", - spritediv = valid_spritediv, - initial_sprite_basepos = valid_spritediv, - is_visible = "boolean", - automatic_rotate = "number", - automatic_face_movement_dir = valid_automatic_face_movement_dir, - automatic_face_movement_max_rotation_per_sec = "number", - backface_culling = "number", - glow = "number", - damage_texture_modifier = "string", - shaded = "boolean", - - hp_max = valid_hp_max, - physical = "boolean", - pointable = "boolean", - collide_with_objects = "boolean", - collisionbox = valid_box, - selectionbox = valid_box, - - makes_footstep_sound = "boolean", - - stepheight = "number", - - nametag = "string", - nametag_color = valid_color_spec, - nametag_bgcolor = valid_color_spec, - - infotext = "string", - - static_save = "boolean", - - show_on_minimap = "boolean", -} - -function futil.is_property_key(key) - return object_property[key] ~= nil -end - -function futil.is_valid_property_value(key, value) - local kind = object_property[key] - - if not kind then - return false - end - - if type(kind) == "string" then - return type(value) == kind - elseif type(kind) == "function" then - return kind(value) - else - error(f("coding error in futil for key %q", key)) - end -end diff --git a/mods/futil/minetest/raycast.lua b/mods/futil/minetest/raycast.lua deleted file mode 100644 index e50a42a8..00000000 --- a/mods/futil/minetest/raycast.lua +++ /dev/null @@ -1,30 +0,0 @@ --- before 5.9, raycasts can miss objects they should hit if the cast is too short --- see https://github.com/minetest/minetest/issues/14337 -function futil.safecast(start, stop, objects, liquids, margin) - margin = margin or 5 - local ray = stop - start - local ray_length = ray:length() - if ray_length == 0 then - return function() end - elseif ray_length >= margin then - return Raycast(start, stop, objects, liquids) - end - - local actual_stop = start + ray:normalize() * margin - local raycast = Raycast(start, actual_stop, objects, liquids) - local stopped = false - return function() - if stopped then - return - end - local pt = raycast() - if pt then - local ip = pt.intersection_point - if (ip - start):length() > ray_length then - stopped = true - return - end - return pt - end - end -end diff --git a/mods/futil/minetest/registration.lua b/mods/futil/minetest/registration.lua deleted file mode 100644 index c17d5ee5..00000000 --- a/mods/futil/minetest/registration.lua +++ /dev/null @@ -1,15 +0,0 @@ -function futil.make_registration() - local t = {} - local registerfunc = function(func) - t[#t + 1] = func - end - return t, registerfunc -end - -function futil.make_registration_reverse() - local t = {} - local registerfunc = function(func) - table.insert(t, 1, func) - end - return t, registerfunc -end diff --git a/mods/futil/minetest/serialization.lua b/mods/futil/minetest/serialization.lua deleted file mode 100644 index 37951ecd..00000000 --- a/mods/futil/minetest/serialization.lua +++ /dev/null @@ -1,87 +0,0 @@ -local f = string.format - -local deserialize = minetest.deserialize - -local pairs_by_key = futil.table.pairs_by_key - -function futil.serialize(x) - if type(x) == "number" or type(x) == "boolean" or type(x) == "nil" then - return tostring(x) - elseif type(x) == "string" then - return f("%q", x) - elseif type(x) == "table" then - local parts = {} - for k, v in pairs_by_key(x) do - table.insert(parts, f("[%s] = %s", futil.serialize(k), futil.serialize(v))) - end - return f("{%s}", table.concat(parts, ", ")) - else - error(f("can't serialize type %s", type(x))) - end -end - -function futil.deserialize(data) - return deserialize(f("return %s", data)) -end - -function futil.serialize_invlist(inv, listname) - local itemstrings = {} - local list = inv:get_list(listname) - - if not list then - error(f("couldn't find list %s of %s", listname, minetest.write_json(inv:get_location()))) - end - - for _, stack in ipairs(list) do - table.insert(itemstrings, stack:to_string()) - end - - return futil.serialize(itemstrings) -end - -function futil.deserialize_invlist(serialized_list, inv, listname) - if not inv:is_empty(listname) then - error(("trying to deserialize into a non-empty list %s (%s)"):format(listname, serialized_list)) - end - - local itemstrings = futil.deserialize(serialized_list) or minetest.parse_json(serialized_list) - - inv:set_size(listname, #itemstrings) - - for i, itemstring in ipairs(itemstrings) do - inv:set_stack(listname, i, ItemStack(itemstring)) - end -end - -function futil.serialize_inv(inv) - local serialized_lists = {} - - for listname in pairs(inv:get_lists()) do - serialized_lists[listname] = futil.serialize_invlist(inv, listname) - end - - return futil.serialize(serialized_lists) -end - -function futil.deserialize_inv(serialized_lists, inv) - for listname, serialized_list in pairs(futil.deserialize(serialized_lists)) do - futil.deserialize_invlist(serialized_list, inv, listname) - end -end - -function futil.serialize_node_meta(pos) - local meta = minetest.get_meta(pos) - local inv = meta:get_inventory() - return futil.serialize({ - fields = meta:to_table().fields, - inventory = futil.serialize_inv(inv), - }) -end - -function futil.deserialize_node_meta(serialized_node_meta, pos) - local meta = minetest.get_meta(pos) - local x = futil.deserialize(serialized_node_meta) - meta:from_table({ fields = x.fields }) - local inv = meta:get_inventory() - futil.deserialize_inv(x.inventory, inv) -end diff --git a/mods/futil/minetest/strip_translation.lua b/mods/futil/minetest/strip_translation.lua deleted file mode 100644 index 4271ff24..00000000 --- a/mods/futil/minetest/strip_translation.lua +++ /dev/null @@ -1,205 +0,0 @@ -local function tokenize(s) - local tokens = {} - - local i = 1 - local j = 1 - - while true do - if s:sub(j, j) == "" then - if i < j then - table.insert(tokens, s:sub(i, j - 1)) - end - return tokens - elseif s:sub(j, j):byte() == 27 then - if i < j then - table.insert(tokens, s:sub(i, j - 1)) - end - - i = j - local n = s:sub(i + 1, i + 1) - - if n == "(" then - local m = s:sub(i + 2, i + 2) - local k = s:find(")", i + 3, true) - if not k then - futil.log("error", "strip_translation: couldn't tokenize %q", s) - return {} - end - if m == "T" then - table.insert(tokens, { - type = "translation", - domain = s:sub(i + 4, k - 1), - }) - elseif m == "c" then - table.insert(tokens, { - type = "color", - color = s:sub(i + 4, k - 1), - }) - elseif m == "b" then - table.insert(tokens, { - type = "bgcolor", - color = s:sub(i + 4, k - 1), - }) - else - futil.log("error", "strip_translation: couldn't tokenize %q", s) - return {} - end - i = k + 1 - j = k + 1 - elseif n == "F" then - table.insert(tokens, { - type = "start", - }) - i = j + 2 - j = j + 2 - elseif n == "E" then - table.insert(tokens, { - type = "stop", - }) - i = j + 2 - j = j + 2 - else - futil.log("error", "strip_translation: couldn't tokenize %q", s) - return {} - end - else - j = j + 1 - end - end -end - -local function parse(tokens, i, parsed) - parsed = parsed or {} - i = i or 1 - while i <= #tokens do - local token = tokens[i] - if type(token) == "string" then - table.insert(parsed, token) - i = i + 1 - elseif token.type == "color" or token.type == "bgcolor" then - table.insert(parsed, token) - i = i + 1 - elseif token.type == "translation" then - local contents = { - type = "translation", - domain = token.domain, - } - i = i + 1 - contents, i = parse(tokens, i, contents) - if i == -1 then - return "", -1 - end - table.insert(parsed, contents) - elseif token.type == "start" then - local contents = { - type = "escape", - } - i = i + 1 - contents, i = parse(tokens, i, contents) - if i == -1 then - return "", -1 - end - table.insert(parsed, contents) - elseif token.type == "stop" then - i = i + 1 - return parsed, i - else - futil.log("error", "strip_translation: couldn't parse %s", dump(token):gsub("%s+", "")) - return "", -1 - end - end - return parsed, i -end - -local function unparse_and_strip_translation(parsed, parts) - parts = parts or {} - for _, part in ipairs(parsed) do - if type(part) == "string" then - table.insert(parts, part) - else - if part.type == "bgcolor" then - table.insert(parts, ("\27(b@%s)"):format(part.color)) - elseif part.type == "color" then - table.insert(parts, ("\27(c@%s)"):format(part.color)) - elseif part.domain then - unparse_and_strip_translation(part, parts) - else - unparse_and_strip_translation(part, parts) - end - end - end - - return parts -end - -local function erase_after_newline(parsed, erasing) - local single_line_parsed = {} - - for _, piece in ipairs(parsed) do - if type(piece) == "string" then - if not erasing then - if piece:find("\n") then - erasing = true - local single_line = piece:match("^([^\n]*)\n") - table.insert(single_line_parsed, single_line) - else - table.insert(single_line_parsed, piece) - end - end - elseif piece.type == "bgcolor" or piece.type == "color" then - table.insert(single_line_parsed, piece) - elseif piece.type == "escape" then - table.insert(single_line_parsed, erase_after_newline(piece, erasing)) - elseif piece.type == "translation" then - local stuff = erase_after_newline(piece, erasing) - stuff.domain = piece.domain - table.insert(single_line_parsed, stuff) - else - futil.log("error", "strip_translation: couldn't erase_after_newline %s", dump(parsed):gsub("%s+", "")) - return {} - end - end - - return single_line_parsed -end - -local function unparse(parsed, parts) - parts = parts or {} - for _, part in ipairs(parsed) do - if type(part) == "string" then - table.insert(parts, part) - else - if part.type == "bgcolor" then - table.insert(parts, ("\27(b@%s)"):format(part.color)) - elseif part.type == "color" then - table.insert(parts, ("\27(c@%s)"):format(part.color)) - elseif part.domain then - table.insert(parts, ("\27(T@%s)"):format(part.domain)) - unparse(part, parts) - table.insert(parts, "\27E") - else - table.insert(parts, "\27F") - unparse(part, parts) - table.insert(parts, "\27E") - end - end - end - - return parts -end - -function futil.strip_translation(msg) - local tokens = tokenize(msg) - local parsed = parse(tokens) - return table.concat(unparse_and_strip_translation(parsed), "") -end - -function futil.get_safe_short_description(item) - item = type(item) == "userdata" and item or ItemStack(item) - local description = item:get_description() - local tokens = tokenize(description) - local parsed = parse(tokens) - local single_line_parsed = erase_after_newline(parsed) - local single_line = table.concat(unparse(single_line_parsed), "") - return single_line -end diff --git a/mods/futil/minetest/texture.lua b/mods/futil/minetest/texture.lua deleted file mode 100644 index ba53fe69..00000000 --- a/mods/futil/minetest/texture.lua +++ /dev/null @@ -1,9 +0,0 @@ --- https://github.com/minetest/minetest/blob/9fc018ded10225589d2559d24a5db739e891fb31/doc/lua_api.txt#L453-L462 -function futil.escape_texture(texturestring) - -- store in a variable so we don't return both rvs of gsub - local v = texturestring:gsub("[%^:]", { - ["^"] = "\\^", - [":"] = "\\:", - }) - return v -end diff --git a/mods/futil/minetest/time.lua b/mods/futil/minetest/time.lua deleted file mode 100644 index 767bcc1e..00000000 --- a/mods/futil/minetest/time.lua +++ /dev/null @@ -1,7 +0,0 @@ -function futil.wait(us) - local wait_until = minetest.get_us_time() + us - local get_us_time = minetest.get_us_time - while get_us_time() < wait_until do - -- the NOTHING function does nothing. - end -end diff --git a/mods/futil/minetest/vector.lua b/mods/futil/minetest/vector.lua deleted file mode 100644 index 5090f19b..00000000 --- a/mods/futil/minetest/vector.lua +++ /dev/null @@ -1,402 +0,0 @@ -local m_abs = math.abs -local m_acos = math.acos -local m_asin = math.asin -local m_atan2 = math.atan2 -local m_cos = math.cos -local m_floor = math.floor -local m_min = math.min -local m_max = math.max -local m_pi = math.pi -local m_pow = math.pow -local m_random = math.random -local m_sin = math.sin - -local v_add = vector.add -local v_new = vector.new -local v_sort = vector.sort -local v_sub = vector.subtract - -local in_bounds = futil.math.in_bounds -local bound = futil.math.bound - -local mapblock_size = 16 -- can be redefined, but effectively hard-coded -local chunksize = m_floor(tonumber(minetest.settings:get("chunksize")) or 5) -- # of mapblocks in a chunk (1 dim) -local chunksize_nodes = mapblock_size * chunksize -- # of nodes in a chunk (1 dim) -local max_mapgen_limit = 31007 -- hard coded -local mapgen_limit = - bound(0, m_floor(tonumber(minetest.settings:get("mapgen_limit")) or max_mapgen_limit), max_mapgen_limit) -local mapgen_limit_b = m_floor(mapgen_limit / mapblock_size) -- # of mapblocks - --- *actual* minimum and maximum coordinates - one mapblock short of the theoretical min and max -local map_min_i = (-mapgen_limit_b * mapblock_size) + chunksize_nodes -local map_max_i = ((mapgen_limit_b + 1) * mapblock_size - 1) - chunksize_nodes - -local map_min_p = v_new(map_min_i, map_min_i, map_min_i) -local map_max_p = v_new(map_max_i, map_max_i, map_max_i) - -futil.vector = {} - -function futil.vector.get_bounds(pos, radius) - return v_sub(pos, radius), v_add(pos, radius) -end - -futil.get_bounds = futil.vector.get_bounds - -function futil.vector.get_world_bounds() - return map_min_p, map_max_p -end - -futil.get_world_bounds = futil.vector.get_world_bounds - -function futil.vector.get_blockpos(pos) - return v_new(m_floor(pos.x / mapblock_size), m_floor(pos.y / mapblock_size), m_floor(pos.z / mapblock_size)) -end - -futil.get_blockpos = futil.vector.get_blockpos - -function futil.vector.get_block_min(blockpos) - return v_new(blockpos.x * mapblock_size, blockpos.y * mapblock_size, blockpos.z * mapblock_size) -end - -function futil.vector.get_block_max(blockpos) - return v_new( - blockpos.x * mapblock_size + (mapblock_size - 1), - blockpos.y * mapblock_size + (mapblock_size - 1), - blockpos.z * mapblock_size + (mapblock_size - 1) - ) -end - -function futil.vector.get_block_bounds(blockpos) - return futil.vector.get_block_min(blockpos), futil.vector.get_block_max(blockpos) -end - -futil.get_block_bounds = futil.vector.get_block_bounds - -function futil.vector.get_block_center(blockpos) - return v_add(futil.vector.get_block_min(blockpos), 8) -- 8 = 16 / 2 -end - -function futil.vector.get_chunkpos(pos) - return v_new( - m_floor((pos.x - map_min_i) / chunksize_nodes), - m_floor((pos.y - map_min_i) / chunksize_nodes), - m_floor((pos.z - map_min_i) / chunksize_nodes) - ) -end - -futil.get_chunkpos = futil.vector.get_chunkpos - -function futil.vector.get_chunk_bounds(chunkpos) - return v_new( - chunkpos.x * chunksize_nodes + map_min_i, - chunkpos.y * chunksize_nodes + map_min_i, - chunkpos.z * chunksize_nodes + map_min_i - ), - v_new( - chunkpos.x * chunksize_nodes + map_min_i + (chunksize_nodes - 1), - chunkpos.y * chunksize_nodes + map_min_i + (chunksize_nodes - 1), - chunkpos.z * chunksize_nodes + map_min_i + (chunksize_nodes - 1) - ) -end - -futil.get_chunk_bounds = futil.vector.get_chunk_bounds - -function futil.vector.formspec_pos(pos) - return ("%i,%i,%i"):format(pos.x, pos.y, pos.z) -end - -futil.formspec_pos = futil.vector.formspec_pos - -function futil.vector.iterate_area(minp, maxp) - minp, maxp = v_sort(minp, maxp) - local min_x = minp.x - local min_z = minp.z - - local x = min_x - 1 - local y = minp.y - local z = min_z - - local max_x = maxp.x - local max_y = maxp.y - local max_z = maxp.z - - return function() - if y > max_y then - return - end - - x = x + 1 - if x > max_x then - x = min_x - z = z + 1 - end - - if z > max_z then - z = min_z - y = y + 1 - end - - if y <= max_y then - return v_new(x, y, z) - end - end -end - -futil.iterate_area = futil.vector.iterate_area - -function futil.vector.iterate_volume(pos, radius) - return futil.iterate_area(futil.get_bounds(pos, radius)) -end - -futil.iterate_volume = futil.vector.iterate_volume - -function futil.is_pos_in_bounds(minp, pos, maxp) - minp, maxp = v_sort(minp, maxp) - return (in_bounds(minp.x, pos.x, maxp.x) and in_bounds(minp.y, pos.y, maxp.y) and in_bounds(minp.z, pos.z, maxp.z)) -end - -function futil.vector.is_inside_world_bounds(pos) - return futil.is_pos_in_bounds(map_min_p, pos, map_max_p) -end - -function futil.vector.is_blockpos_inside_world_bounds(blockpos) - return futil.vector.is_inside_world_bounds(futil.vector.get_block_min(blockpos)) -end - -futil.is_inside_world_bounds = futil.vector.is_inside_world_bounds - -function futil.vector.bound_position_to_world(pos) - return v_new( - bound(map_min_i, pos.x, map_max_i), - bound(map_min_i, pos.y, map_max_i), - bound(map_min_i, pos.z, map_max_i) - ) -end - -futil.bound_position_to_world = futil.vector.bound_position_to_world - -function futil.vector.volume(pos1, pos2) - local minp, maxp = v_sort(pos1, pos2) - return (maxp.x - minp.x + 1) * (maxp.y - minp.y + 1) * (maxp.z - minp.z + 1) -end - -function futil.split_region_by_mapblock(pos1, pos2, num_blocks) - local chunk_size = 16 * (num_blocks or 1) - local chunk_span = chunk_size - 1 - - pos1, pos2 = vector.sort(pos1, pos2) - - local min_x = pos1.x - local min_y = pos1.y - local min_z = pos1.z - local max_x = pos2.x - local max_y = pos2.y - local max_z = pos2.z - - local x1 = min_x - (min_x % chunk_size) - local x2 = max_x - (max_x % chunk_size) + chunk_span - local y1 = min_y - (min_y % chunk_size) - local y2 = max_y - (max_y % chunk_size) + chunk_span - local z1 = min_z - (min_z % chunk_size) - local z2 = max_z - (max_z % chunk_size) + chunk_span - - local chunks = {} - for y = y1, y2, chunk_size do - local y_min = m_max(min_y, y) - local y_max = m_min(max_y, y + chunk_span) - - for x = x1, x2, chunk_size do - local x_min = m_max(min_x, x) - local x_max = m_min(max_x, x + chunk_span) - - for z = z1, z2, chunk_size do - local z_min = m_max(min_z, z) - local z_max = m_min(max_z, z + chunk_span) - - chunks[#chunks + 1] = { v_new(x_min, y_min, z_min), v_new(x_max, y_max, z_max) } - end - end - end - - return chunks -end - -function futil.random_unit_vector() - local u = m_random() - local v = m_random() - local lambda = m_acos(2 * u - 1) - (m_pi / 2) - local phi = 2 * m_pi * v - return v_new(m_cos(lambda) * m_cos(phi), m_cos(lambda) * m_sin(phi), m_sin(lambda)) -end - ----- https://math.stackexchange.com/a/205589 ---function futil.random_unit_vector_in_solid_angle(theta, direction) --- local z = m_random() * (1 - m_cos(theta)) - 1 --- local phi = m_random() * 2 * m_pi --- local z2 = (1 - z*z) ^ 0.5 --- local ruv = v_new(z2 * m_cos(phi), z2 * m_sin(phi), z) --- direction = direction:normalize() --- ... ---end - -function futil.is_indoors(pos, distance, trials, hits_needed) - distance = distance or 20 - trials = trials or 11 - hits_needed = hits_needed or 9 - local num_hits = 0 - for _ = 1, trials do - local ruv = futil.random_unit_vector() - local target = pos + (distance * ruv) - local hit = Raycast(pos, target, false, false)() - if hit then - num_hits = num_hits + 1 - if num_hits == hits_needed then - return true - end - end - end - return false -end - -function futil.can_see_sky(pos, distance, trials, max_hits) - distance = distance or 200 - trials = trials or 11 - max_hits = max_hits or 9 - local num_hits = 0 - for _ = 1, trials do - local ruv = futil.random_unit_vector() - ruv.y = m_abs(ruv.y) -- look up, not at the ground - local target = pos + (distance * ruv) - local hit = Raycast(pos, target, false, false)() - if hit then - num_hits = num_hits + 1 - if num_hits > max_hits then - return false - end - end - end - return true -end - -function futil.vector.is_valid_position(pos) - if type(pos) ~= "table" then - return false - elseif not (type(pos.x) == "number" and type(pos.y) == "number" and type(pos.z) == "number") then - return false - else - return futil.is_inside_world_bounds(vector.round(pos)) - end -end - --- minetest.hash_node_position only works with integer coordinates -function futil.vector.hash(pos) - return string.format("%a:%a:%a", pos.x, pos.y, pos.z) -end - -function futil.vector.unhash(string) - local x, y, z = string:match("^([^:]+):([^:]+):([^:]+)$") - x, y, z = tonumber(x), tonumber(y), tonumber(z) - if not (x and y and z) then - return - end - return v_new(x, y, z) -end - -function futil.vector.ldistance(pos1, pos2, p) - if p == math.huge then - return m_max(m_abs(pos1.x - pos2.x), m_abs(pos1.y - pos2.y), m_abs(pos1.z - pos2.z)) - else - return m_pow( - m_pow(m_abs(pos1.x - pos2.x), p) + m_pow(m_abs(pos1.y - pos2.y), p) + m_pow(m_abs(pos1.z - pos2.z), p), - 1 / p - ) - end -end - -function futil.vector.round(pos, mult) - local round = futil.math.round - return v_new(round(pos.x, mult), round(pos.y, mult), round(pos.z, mult)) -end - --- https://msl.cs.uiuc.edu/planning/node102.html -function futil.vector.rotation_to_matrix(rotation) - local cosp = m_cos(rotation.x) - local sinp = m_sin(rotation.x) - local pitch = { - { cosp, 0, sinp }, - { 0, 1, 0 }, - { -sinp, 0, cosp }, - } - local cosy = m_cos(rotation.y) - local siny = m_sin(rotation.y) - local yaw = { - { cosy, -siny, 0 }, - { siny, cosy, 0 }, - { 0, 0, 1 }, - } - local cosr = m_cos(rotation.z) - local sinr = m_sin(rotation.z) - local roll = { - { 1, 0, 0 }, - { 0, cosr, -sinr }, - { 0, sinr, cosr }, - } - return futil.matrix.multiply(futil.matrix.multiply(yaw, pitch), roll) -end - --- https://msl.cs.uiuc.edu/planning/node103.html -function futil.vector.matrix_to_rotation(matrix) - local pitch = m_atan2(matrix[2][1], matrix[1][1]) - local yaw = m_asin(-matrix[3][1]) - local roll = m_atan2(matrix[3][2], matrix[3][3]) - return v_new(pitch, yaw, roll) -end - -function futil.vector.inverse_rotation(rot) - -- since the determinant of a rotation matrix is 1, the inverse is just the transpose and i don't have to write - -- a matrix inverter - return futil.vector.matrix_to_rotation(futil.matrix.transpose(futil.vector.rotation_to_matrix(rot))) -end - --- assumed in radians -function futil.vector.compose_rotations(rot1, rot2) - local m1 = futil.vector.rotation_to_matrix(rot1) - local m2 = futil.vector.rotation_to_matrix(rot2) - return futil.vector.matrix_to_rotation(futil.matrix.multiply(m1, m2)) -end - --- https://palitri.com/vault/stuff/maths/Rays%20closest%20point.pdf --- this was originally part of the ballistics mod but i don't need it there anymore -function futil.vector.closest_point_to_two_lines(last_pos, last_vel, cur_pos, cur_vel, threshold) - threshold = threshold or 0.0001 -- if certain values are too close to 0, the results will not be good - local a = cur_vel - local b = last_vel - local a2 = a:dot(a) - if a2 < threshold then - return - end - local b2 = b:dot(b) - if b2 < threshold then - return - end - local ab = a:dot(b) - local denom = (a2 * b2) - (ab * ab) - if denom < threshold then - return - end - local A = cur_pos - local B = last_pos - local c = last_pos - cur_pos - local bc = b:dot(c) - local ac = a:dot(c) - local D = A + a * ((ac * b2 - ab * bc) / denom) - local E = B + b * ((ab * ac - bc * a2) / denom) - return (D + E) / 2 -end - -function futil.vector.v2f_to_float_32(v) - return { - x = futil.math.to_float32(v.x), - y = futil.math.to_float32(v.y), - } -end diff --git a/mods/futil/mod.conf b/mods/futil/mod.conf deleted file mode 100644 index 5a7a55d9..00000000 --- a/mods/futil/mod.conf +++ /dev/null @@ -1,11 +0,0 @@ -name = futil -title = futil -description = flux's utility mod -website = https://content.minetest.net/packages/rheo/futil/ -author = fluxionary -license = LGPL-3.0-or-later -media_license = CC-BY-SA-4.0 -version = 2024-03-30 -min_minetest_version = 5.8.0 -supported_games = * -depends = fmod diff --git a/mods/futil/util/bisect.lua b/mods/futil/util/bisect.lua deleted file mode 100644 index 1d9ee0ae..00000000 --- a/mods/futil/util/bisect.lua +++ /dev/null @@ -1,51 +0,0 @@ -futil.bisect = {} - -function futil.bisect.right(t, x, low, high, key) - low = low or 1 - high = high or #t + 1 - if key then - while low < high do - local mid = math.floor((low + high) / 2) - if x < key(t[mid]) then - high = mid - else - low = mid + 1 - end - end - else - while low < high do - local mid = math.floor((low + high) / 2) - if x < t[mid] then - high = mid - else - low = mid + 1 - end - end - end - return low -end - -function futil.bisect.left(t, x, low, high, key) - low = low or 1 - high = high or #t + 1 - if key then - while low < high do - local mid = math.floor((low + high) / 2) - if key(t[mid]) < x then - low = mid + 1 - else - high = mid - end - end - else - while low < high do - local mid = math.floor((low + high) / 2) - if t[mid] < x then - low = mid + 1 - else - high = mid - end - end - end - return low -end diff --git a/mods/futil/util/class.lua b/mods/futil/util/class.lua deleted file mode 100644 index fa8c004a..00000000 --- a/mods/futil/util/class.lua +++ /dev/null @@ -1,89 +0,0 @@ -function futil.class1(super) - local class = {} - class.__index = class -- this becomes the index "metamethod" of objects - - setmetatable(class, { - __index = super and super.__index or super, - __call = function(this_class, ...) - local obj = setmetatable({}, this_class) - local init = obj._init - if init then - init(obj, ...) - end - return obj - end, - }) - - function class:is_a(class2) - if class == class2 then - return true - end - - if super and super:is_a(class2) then - return true - end - - return false - end - - return class -end - -function futil.class(...) - local class = {} - class.__index = class - - local meta = { - __call = function(this_class, ...) - local obj = setmetatable({}, this_class) - local init = obj._init - if init then - init(obj, ...) - end - return obj - end, - } - - local parents = { ... } - class._parents = parents - - if #parents > 0 then - function meta:__index(key) - for i = #parents, 1, -1 do - local parent = parents[i] - local index = parent.__index - local v - if index then - if type(index) == "function" then - v = index(self, key) - else - v = index[key] - end - else - v = parent[key] - end - if v then - return v - end - end - end - end - - setmetatable(class, meta) - - function class:is_a(class2) - if class == class2 then - return true - end - - for _, parent in ipairs(parents) do - if parent:is_a(class2) then - return true - end - end - - return false - end - - return class -end diff --git a/mods/futil/util/coalesce.lua b/mods/futil/util/coalesce.lua deleted file mode 100644 index 1491e3af..00000000 --- a/mods/futil/util/coalesce.lua +++ /dev/null @@ -1,9 +0,0 @@ -function futil.coalesce(...) - local arg = futil.table.pack(...) - for i = 1, arg.n do - local v = arg[i] - if v ~= nil then - return v - end - end -end diff --git a/mods/futil/util/equals.lua b/mods/futil/util/equals.lua deleted file mode 100644 index c5587b3e..00000000 --- a/mods/futil/util/equals.lua +++ /dev/null @@ -1,28 +0,0 @@ -local table_size = futil.table.size - -local function equals(a, b) - local t = type(a) - - if t ~= type(b) then - return false - end - - if t ~= "table" then - return a == b - elseif a == b then - return true - end - - local size_a = 0 - - for key, value in pairs(a) do - if not equals(value, b[key]) then - return false - end - size_a = size_a + 1 - end - - return size_a == table_size(b) -end - -futil.equals = equals diff --git a/mods/futil/util/exception.lua b/mods/futil/util/exception.lua deleted file mode 100644 index 45800a42..00000000 --- a/mods/futil/util/exception.lua +++ /dev/null @@ -1,29 +0,0 @@ -function futil.safe_wrap(func, rv_on_fail, error_callback) - -- wrap a function w/ logic to avoid crashing - return function(...) - local rvs = { xpcall(func, debug.traceback, ...) } - - if rvs[1] then - return unpack(rvs, 2) - else - if error_callback then - error_callback(debug.getinfo(func), { ... }, rvs[2]) - else - futil.log( - "error", - "(check_call): %s args: %s out: %s", - dump(debug.getinfo(func)), - dump({ ... }), - rvs[2] - ) - end - return rv_on_fail - end - end -end - -function futil.safe_call(func, rv_on_fail, error_callback, ...) - return futil.safe_wrap(func, rv_on_fail, error_callback)(...) -end - -futil.check_call = futil.safe_wrap -- backwards compatibility diff --git a/mods/futil/util/file.lua b/mods/futil/util/file.lua deleted file mode 100644 index 999f97b7..00000000 --- a/mods/futil/util/file.lua +++ /dev/null @@ -1,37 +0,0 @@ -function futil.file_exists(path) - local f = io.open(path, "r") - if f then - io.close(f) - return true - else - return false - end -end - -function futil.load_file(filename) - local file = io.open(filename, "r") - - if not file then - return - end - - local contents = file:read("*a") - - file:close() - - return contents -end - --- minetest.safe_file_write is apparently unreliable on windows -function futil.write_file(filename, contents) - local file = io.open(filename, "w") - - if not file then - return false - end - - file:write(contents) - file:close() - - return true -end diff --git a/mods/futil/util/functional.lua b/mods/futil/util/functional.lua deleted file mode 100644 index 9fc56cd0..00000000 --- a/mods/futil/util/functional.lua +++ /dev/null @@ -1,159 +0,0 @@ -local functional = {} - -local t_iterate = futil.table.iterate -local t_insert = table.insert - -function functional.noop() - -- the NOTHING function does nothing. -end - -function functional.identity(x) - return x -end - -function functional.izip(...) - local is = { ... } - if #is == 0 then - return functional.noop - end - - return function() - local t = {} - for i in t_iterate(is) do - local v = i() - if v ~= nil then - t_insert(t, v) - else - return - end - end - - return t - end -end - -function functional.zip(...) - local is = {} - for t in t_iterate({ ... }) do - t_insert(is, t_iterate(t)) - end - return functional.izip(unpack(is)) -end - -function functional.imap(func, ...) - local zipper = functional.izip(...) - return function() - local args = zipper() - if args then - return func(unpack(args)) - end - end -end - -function functional.map(func, ...) - local zipper = functional.zip(...) - return function() - local args = zipper() - if args then - return func(unpack(args)) - end - end -end - -function functional.apply(func, t) - local t2 = {} - for k, v in pairs(t) do - t2[k] = func(v) - end - return t2 -end - -function functional.reduce(func, t, initial) - local i = t_iterate(t) - if not initial then - initial = i() - end - local next = i() - while next do - initial = func(initial, next) - next = i() - end - return initial -end - -function functional.partial(func, ...) - local args = { ... } - return function(...) - return func(unpack(args), ...) - end -end - -function functional.compose(a, b) - return function(...) - return a(b(...)) - end -end - -function functional.ifilter(pred, i) - local v - return function() - v = i() - while v ~= nil and not pred(v) do - v = i() - end - return v - end -end - -function functional.filter(pred, t) - return functional.ifilter(pred, t_iterate(t)) -end - -function functional.iall(i) - while true do - local v = i() - if v == false then - return false - elseif v == nil then - return true - end - end -end - -function functional.all(t) - for i = 1, #t do - if not t[i] then - return false - end - end - - return true -end - -function functional.iany(i) - while true do - local v = i() - if v == nil then - return false - elseif v then - return true - end - end -end - -function functional.any(t) - for i = 1, #t do - if t[i] then - return true - end - end - return false -end - -function functional.wrap(f) - return function(...) - return f(...) - end -end - -futil.functional = functional diff --git a/mods/futil/util/http.lua b/mods/futil/util/http.lua deleted file mode 100644 index 3973d76b..00000000 --- a/mods/futil/util/http.lua +++ /dev/null @@ -1,10 +0,0 @@ -local function char_to_hex(c) - return string.format("%%%02X", string.byte(c)) -end - -function futil.urlencode(text) - text = text:gsub("\n", "\r\n") - text = text:gsub("([^0-9a-zA-Z !'()*._~-])", char_to_hex) - text = text:gsub(" ", "+") - return text -end diff --git a/mods/futil/util/init.lua b/mods/futil/util/init.lua deleted file mode 100644 index e886719a..00000000 --- a/mods/futil/util/init.lua +++ /dev/null @@ -1,24 +0,0 @@ -futil.dofile("util", "bisect") -futil.dofile("util", "class") -futil.dofile("util", "coalesce") -futil.dofile("util", "exception") -futil.dofile("util", "file") -futil.dofile("util", "http") -futil.dofile("util", "list") -futil.dofile("util", "math") -futil.dofile("util", "matrix") -futil.dofile("util", "memoization") -futil.dofile("util", "memory") -futil.dofile("util", "path") -futil.dofile("util", "predicates") -futil.dofile("util", "string") -futil.dofile("util", "table") - -futil.dofile("util", "equals") -- depends on table -futil.dofile("util", "functional") -- depends on table -futil.dofile("util", "iterators") -- depends on functional -futil.dofile("util", "random") -- depends on math -futil.dofile("util", "regex") -- depends on exception -futil.dofile("util", "selection") -- depends on table, math -futil.dofile("util", "time") -- depends on math -futil.dofile("util", "limiters") -- depends on functional diff --git a/mods/futil/util/iterators.lua b/mods/futil/util/iterators.lua deleted file mode 100644 index 0eeaba86..00000000 --- a/mods/futil/util/iterators.lua +++ /dev/null @@ -1,106 +0,0 @@ -local iterators = {} - -function iterators.range(...) - local a, b, c = ... - if type(a) ~= "number" then - error("invalid range") - end - if not b then - a, b = 1, a - end - if type(b) ~= "number" then - error("invalid range") - end - c = c or 1 - if type(c) ~= "number" or c == 0 then - error("invalid range") - end - - if c > 0 then - return function() - if a > b then - return - end - local to_return = a - a = a + c - return to_return - end - else - return function() - if a < b then - return - end - local to_return = a - a = a + c - return to_return - end - end -end - -function iterators.repeat_(value, times) - if times then - local i = 0 - return function() - i = i + 1 - if i <= times then - return value - end - end - else - return function() - return value - end - end -end - -function iterators.chain(...) - local arg = { ... } - local i = 1 - - return function() - while i <= #arg do - local v = arg[i]() - if v then - return v - end - end - end -end - -function iterators.count(start, step) - step = step or 1 - return function() - local rv = start - start = start + step - return rv - end -end - -function iterators.values(t) - local k - return function() - local value - k, value = next(t, k) - return value - end -end - -function iterators.accumulate(t, composer, initial) - local value = initial - local i = futil.table.iterate(t) - return function() - local next_value = i() - if next_value then - if value == nil then - value = next_value - elseif composer then - value = composer(value, next_value) - else - value = value + next_value - end - return value - end - end -end - -futil.iterators = iterators diff --git a/mods/futil/util/limiters.lua b/mods/futil/util/limiters.lua deleted file mode 100644 index 41db21a4..00000000 --- a/mods/futil/util/limiters.lua +++ /dev/null @@ -1,42 +0,0 @@ ---[[ - functions to limit the growth of a variable. - the intention here is to provide a family of functions for which - * f(x) is defined for all x >= 0 - * f(0) = 0 - * f(1) = 1 - * f is continuous - * f is nondecreasing - * f\'(x) is nonincreasing when x > 1 (when the parameters are appropriate) -]] - -local log = math.log -local pow = math.pow -local tanh = math.tanh - -futil.limiters = { - -- no limiting - none = futil.functional.identity, - -- f(x) = x ^ param_1. param_1 should be < 1 for f\'(x) to be nonincreasing - -- f(x) will grow arbitrarily, but at a decreasing rate. - gamma = function(x, param_1) - return pow(x, param_1) - end, - -- the hyperbolic tangent scaled so that f(0) = 0 and f(1) = 1. - -- f(x) will grow approximately linearly for small x, but it will never grow beyond a maximum value, which is - -- approximately equal to param_1 + 1 - tanh = function(x, param_1) - return (tanh((x - 1) / param_1) - tanh(-1 / param_1)) / -tanh(-1 / param_1) - end, - -- f(x) = log^param_2(param_1 * x + 1), scaled so that f(0) = 0 and f(1) = 1. - -- f(x) will grow arbitrarily, but at a much slower rate than a gamma limiter - log__n = function(x, param_1, param_2) - return (log(x + 1) * pow(log(param_1 * x + 1), param_2) / (log(2) * pow(log(param_1 + 1), param_2))) - end, -} - -function futil.create_limiter(name, param_1, param_2) - local f = futil.limiters[name] - return function(x) - return f(x, param_1, param_2) - end -end diff --git a/mods/futil/util/list.lua b/mods/futil/util/list.lua deleted file mode 100644 index ed8103fa..00000000 --- a/mods/futil/util/list.lua +++ /dev/null @@ -1,19 +0,0 @@ -function futil.list(iterator) - local t = {} - local v = iterator() - while v do - t[#t + 1] = v - v = iterator() - end - return t -end - -function futil.list_multiple(iterator) - local t = {} - local v = { iterator() } - while #v > 0 do - t[#t + 1] = v - v = { iterator() } - end - return t -end diff --git a/mods/futil/util/math.lua b/mods/futil/util/math.lua deleted file mode 100644 index f2df95e7..00000000 --- a/mods/futil/util/math.lua +++ /dev/null @@ -1,162 +0,0 @@ -futil.math = {} - -local floor = math.floor -local huge = math.huge -local max = math.max -local min = math.min - -function futil.math.idiv(a, b) - local rem = a % b - return (a - rem) / b, rem -end - -function futil.math.bound(m, v, M) - return max(m, min(v, M)) -end - -function futil.math.in_bounds(m, v, M) - return m <= v and v <= M -end - -local in_bounds = futil.math.in_bounds - -function futil.math.is_integer(v) - return floor(v) == v -end - -local is_integer = futil.math.is_integer - -function futil.math.is_u8(i) - return (type(i) == "number" and is_integer(i) and in_bounds(0, i, 0xFF)) -end - -function futil.math.is_u16(i) - return (type(i) == "number" and is_integer(i) and in_bounds(0, i, 0xFFFF)) -end - -function futil.math.sum(t, initial) - local sum - local start - if initial then - sum = initial - start = 1 - else - sum = t[1] - start = 2 - end - - for i = start, #t do - sum = sum + t[i] - end - - return sum -end - -function futil.math.isum(i, initial) - local sum - - if initial == nil then - sum = i() - else - sum = initial - end - - local v = i() - - while v do - sum = sum + v - v = i() - end - - return sum -end - -function futil.math.product(t, initial) - local product - local start - if initial then - product = initial - start = 1 - else - product = t[1] - start = 2 - end - - for i = start, #t do - product = product * t[i] - end - - return product -end - -function futil.math.iproduct(i, initial) - local product - - if initial == nil then - product = i() - else - product = initial - end - - local v = i() - - while v do - product = product * v - v = i() - end - - return product -end - -function futil.math.probabilistic_round(v) - return floor(v + math.random()) -end - -function futil.math.cmp(a, b) - return a < b -end - -futil.math.deg2rad = math.deg - -futil.math.rad2deg = math.rad - -function futil.math.do_intervals_overlap(min1, max1, min2, max2) - return min1 <= max2 and min2 <= max1 -end - --- i took one class from kahan and can't stop doing this -local function round(n) - local d = n % 1 - local i = n - d - - if i % 2 == 0 then - if d <= 0.5 then - return i - else - return i + 1 - end - else - if d < 0.5 then - return i - else - return i + 1 - end - end -end - -function futil.math.round(number, mult) - if mult then - return round(number / mult) * mult - else - return round(number) - end -end - --- TODO this doesn't handle out-of-bounds exponents -function futil.math.to_float32(number) - if number == huge or number == -huge or number ~= number then - return number - end - local sign, significand, exponent = ("%a"):format(number):match("^(-?)0x([0-9a-f\\.]+)p([0-9+-]+)$") - return tonumber(("%s0x%sp%s"):format(sign, significand:sub(1, 8), exponent)) -end diff --git a/mods/futil/util/matrix.lua b/mods/futil/util/matrix.lua deleted file mode 100644 index 433d9a7c..00000000 --- a/mods/futil/util/matrix.lua +++ /dev/null @@ -1,30 +0,0 @@ -futil.matrix = {} - -function futil.matrix.multiply(m1, m2) - assert(#m1[1] == #m2, "width of first argument must be height of second") - local product = {} - for i = 1, #m1 do - local row = {} - for j = 1, #m2[1] do - local value = 0 - for k = 1, #m2 do - value = value + m1[i][k] * m2[k][j] - end - row[j] = value - end - product[i] = row - end - return product -end - -function futil.matrix.transpose(m) - local t = {} - for i = 1, #m[1] do - local row = {} - for j = 1, #m do - row[j] = m[j][i] - end - t[i] = row - end - return t -end diff --git a/mods/futil/util/memoization.lua b/mods/futil/util/memoization.lua deleted file mode 100644 index 73a86163..00000000 --- a/mods/futil/util/memoization.lua +++ /dev/null @@ -1,51 +0,0 @@ -local private_state = ... -local mod_storage = private_state.mod_storage - -function futil.memoize1(func) - local memo = {} - return function(arg) - if arg == nil then - return func(arg) - end - local rv = memo[arg] - - if not rv then - rv = func(arg) - memo[arg] = rv - end - - return rv - end -end - -function futil.memoize_dumpable(func) - local memo = {} - return function(...) - local key = dump({ ... }) - local rv = memo[key] - - if not rv then - rv = func(...) - memo[key] = rv - end - - return rv - end -end - -function futil.memoize1_modstorage(id, func) - local key_format = ("%%s:%s:memoize"):format(id) - return function(arg) - local key_key = key_format:format(tostring(arg)) - local rv = mod_storage:get(key_key) - - if not rv then - rv = func(arg) - mod_storage:set_string(key_key, tostring(rv)) - end - - return rv - end -end - -futil.memoize1ms = futil.memoize1_modstorage -- backwards compatibility diff --git a/mods/futil/util/memory.lua b/mods/futil/util/memory.lua deleted file mode 100644 index 7ad6da8b..00000000 --- a/mods/futil/util/memory.lua +++ /dev/null @@ -1,45 +0,0 @@ --- i have no idea how accurate this is, i use documentation from the below link for a few things --- https://wowwiki-archive.fandom.com/wiki/Lua_object_memory_sizes - -local function estimate_memory_usage(thing, seen) - local typ = type(thing) - if typ == "nil" then - return 0 - end - - seen = seen or {} - if seen[thing] then - return 0 - end - seen[thing] = true - - if typ == "boolean" then - return 4 - elseif typ == "number" then - return 8 -- this is probably larger? - elseif typ == "string" then - return 25 + typ:len() - elseif typ == "function" then - -- TODO: we can calculate the usage of upvalues, but that's complicated - return 40 - elseif typ == "userdata" then - return 0 -- this is probably larger - elseif typ == "thread" then - return 1224 -- this is probably larger - elseif typ == "table" then - local size = 64 - for k, v in pairs(thing) do - if type(k) == "number" then - size = size + 16 + estimate_memory_usage(v, seen) - else - size = size + 40 + estimate_memory_usage(k, seen) + estimate_memory_usage(v, seen) - end - end - return size - else - futil.log("warning", "estimate_memory_usage: unknown type %s", typ) - return 0 -- ???? - end -end - -futil.estimate_memory_usage = estimate_memory_usage diff --git a/mods/futil/util/path.lua b/mods/futil/util/path.lua deleted file mode 100644 index 9c225742..00000000 --- a/mods/futil/util/path.lua +++ /dev/null @@ -1,7 +0,0 @@ -function futil.path_concat(...) - return table.concat({ ... }, DIR_DELIM) -end - -function futil.path_split(path) - return string.split(path, DIR_DELIM, true) -end diff --git a/mods/futil/util/predicates.lua b/mods/futil/util/predicates.lua deleted file mode 100644 index 61aa26b2..00000000 --- a/mods/futil/util/predicates.lua +++ /dev/null @@ -1,43 +0,0 @@ -function futil.is_nil(v) - return v == nil -end - -function futil.is_boolean(v) - return v == true or v == false -end - -function futil.is_number(v) - return type(v) == "number" -end - -function futil.is_positive(v) - return v > 0 -end - -function futil.is_integer(v) - return v % 1 == 0 -end - -function futil.is_positive_integer(v) - return type(v) == "number" and v > 0 and v % 1 == 0 -end - -function futil.is_string(v) - return type(v) == "string" -end - -function futil.is_userdata(v) - return type(v) == "userdata" -end - -function futil.is_function(v) - return type(v) == "function" -end - -function futil.is_thread(v) - return type(v) == "thread" -end - -function futil.is_table(v) - return type(v) == "table" -end diff --git a/mods/futil/util/random.lua b/mods/futil/util/random.lua deleted file mode 100644 index 81a38321..00000000 --- a/mods/futil/util/random.lua +++ /dev/null @@ -1,84 +0,0 @@ -local f = string.format - -futil.random = {} - -function futil.random.choice(t, random) - random = random or math.random - return t[random(#t)] -end - -function futil.random.weighted_choice(t, random) - random = random or math.random - local elements, weights = {}, {} - local i = 1 - for element, weight in pairs(t) do - elements[i] = element - weights[i] = weight - i = i + 1 - end - local breaks = futil.list(futil.iterators.accumulate(weights)) - local value = random() * breaks[#breaks] - return elements[futil.bisect.right(breaks, value)] -end - -local WeightedChooser = futil.class1() - -function WeightedChooser:_init(t) - local elements, weights = {}, {} - local i = 1 - for element, weight in pairs(t) do - elements[i] = element - weights[i] = weight - i = i + 1 - end - self._elements = elements - self._breaks = futil.list(futil.iterators.accumulate(weights)) -end - -function WeightedChooser:next(random) - random = random or math.random - local breaks = self._breaks - local value = random() * breaks[#breaks] - return self._elements[futil.bisect.right(breaks, value)] -end - -futil.random.WeightedChooser = WeightedChooser - -function futil.random.choice(t, random) - assert(#t > 0, "cannot get choice from an empty table") - random = random or math.random - return t[random(#t)] -end - --- https://stats.stackexchange.com/questions/569647/ -function futil.random.sample(t, k, random) - assert(k <= #t, f("cannot sample %i items from a set of size %i", k, #t)) - random = random or math.random - local sample = {} - for i = 1, k do - sample[i] = t[i] - end - for j = k + 1, #t do - if random() < k / j then - sample[random(1, k)] = t[j] - end - end - - return sample -end - -function futil.random.sample_with_indices(t, k, random) - assert(k <= #t, f("cannot sample %i items from a set of size %i", k, #t)) - random = random or math.random - local sample = {} - for i = 1, k do - sample[i] = { i, t[i] } - end - for j = k + 1, #t do - if random() < k / j then - sample[random(1, k)] = { j, t[j] } - end - end - - return sample -end diff --git a/mods/futil/util/regex.lua b/mods/futil/util/regex.lua deleted file mode 100644 index f691c9f4..00000000 --- a/mods/futil/util/regex.lua +++ /dev/null @@ -1,6 +0,0 @@ -function futil.is_valid_regex(pattern) - return futil.safe_call(function() - (""):match(pattern) - return true - end, false, futil.functional.noop) -end diff --git a/mods/futil/util/selection.lua b/mods/futil/util/selection.lua deleted file mode 100644 index 3e2c99f7..00000000 --- a/mods/futil/util/selection.lua +++ /dev/null @@ -1,109 +0,0 @@ -local floor = math.floor -local min = math.min -local random = math.random - -local swap = futil.table.swap -local default_cmp = futil.math.cmp - -futil.selection = {} - -local function partition5(t, left, right, cmp) - cmp = cmp or default_cmp - local i = left + 1 - while i <= right do - local j = i - while j > left and cmp(t[j], t[j - 1]) do - swap(t, j - 1, j) - j = j - 1 - end - i = i + 1 - end - return floor((left + right) / 2) -end - -local function partition(t, left, right, pivot_i, i, cmp) - cmp = cmp or default_cmp - local pivot_v = t[pivot_i] - swap(t, pivot_i, right) - local store_i = left - for j = left, right - 1 do - if cmp(t[j], pivot_v) then - swap(t, store_i, j) - store_i = store_i + 1 - end - end - local store_i_eq = store_i - for j = store_i, right - 1 do - if t[j] == pivot_v then - swap(t, store_i_eq, j) - store_i_eq = store_i_eq + 1 - end - end - swap(t, right, store_i_eq) - if i < store_i then - return store_i - elseif i <= store_i_eq then - return i - else - return store_i_eq - end -end - -local function quickselect(t, left, right, i, pivot_alg, cmp) - cmp = cmp or default_cmp - while true do - if left == right then - return left - end - local pivot_i = partition(t, left, right, pivot_alg(t, left, right, cmp), i, cmp) - if i == pivot_i then - return i - elseif i < pivot_i then - right = pivot_i - 1 - else - left = pivot_i + 1 - end - end -end - -futil.selection.quickselect = quickselect - -futil.selection.pivot = {} - -function futil.selection.pivot.random(t, left, right, cmp) - return random(left, right) -end - -local function pivot_medians_of_medians(t, left, right, cmp) - cmp = cmp or default_cmp - if right - left < 5 then - return partition5(t, left, right, cmp) - end - for i = left, right, 5 do - local sub_right = min(i + 4, right) - local median5 = partition5(t, i, sub_right, cmp) - swap(t, median5, left + floor((i - left) / 5)) - end - local mid = floor((right - left) / 10) + left + 1 - return quickselect(t, left, left + floor((right - left) / 5), mid, pivot_medians_of_medians, cmp) -end - -futil.selection.pivot.median_of_medians = pivot_medians_of_medians - ---[[ -make use of quickselect to munge a table: - median_index = math.floor(#t / 2) - after calling this, - t[1] through t[median_index - 1] will be the elements less than t[median_index] - t[median_index] will be the median (or element less-than-the-median for even length tables) - t[median_index + 1] through t[#t] will be the elements greater than t[median_index] -pivot is a pivot algorithm, defaults to random selection -cmp is a comparison function. -returns median_index. -]] -function futil.selection.select(t, pivot_alg, cmp) - cmp = cmp or default_cmp - pivot_alg = pivot_alg or futil.selection.pivot.random - local median_index = math.floor(#t / 2) - return quickselect(t, 1, #t, median_index, pivot_alg, cmp) -end diff --git a/mods/futil/util/string.lua b/mods/futil/util/string.lua deleted file mode 100644 index 16877294..00000000 --- a/mods/futil/util/string.lua +++ /dev/null @@ -1,62 +0,0 @@ -futil.string = {} - -function futil.string.truncate(s, max_length, suffix) - suffix = suffix or "..." - - if s:len() > max_length then - return s:sub(1, max_length - suffix:len()) .. suffix - else - return s - end -end - -function futil.string.lc_cmp(a, b) - return a:lower() < b:lower() -end - -function futil.string.startswith(s, start, start_i, end_i) - return s:sub(start_i or 0, end_i or #s):sub(1, #start) == start -end - -local escape_pattern = "([%(%)%.%%%+%-%*%?%[%^%$])" -local function escape_regex(str) - return str:gsub(escape_pattern, "%%%1") -end - -local glob_patterns = { - ["?"] = ".", - ["*"] = ".*", -} - -local function transform_pattern(pattern) - local parts = {} - local start = 1 - for i = 1, #pattern do - local glob_pattern = glob_patterns[pattern:sub(i)] - if glob_pattern then - if start < i then - parts[#parts + 1] = escape_regex(pattern:sub(start, i - 1)) - end - parts[#parts + 1] = glob_pattern - start = i + 1 - end - end - if start < #pattern then - parts[#parts + 1] = escape_regex(pattern:sub(start, #pattern)) - end - return table.concat(parts, "") -end - -function futil.string.globmatch(str, pattern) - return str:match(transform_pattern(pattern)) -end - -futil.GlobMatcher = futil.class1() - -function futil.GlobMatcher:_init(pattern) - self._pattern = transform_pattern(pattern) -end - -function futil.GlobMatcher:match(str) - return str:match(self._pattern) -end diff --git a/mods/futil/util/table.lua b/mods/futil/util/table.lua deleted file mode 100644 index 0a2ae296..00000000 --- a/mods/futil/util/table.lua +++ /dev/null @@ -1,188 +0,0 @@ -local default_cmp = futil.math.cmp - -futil.table = {} - -function futil.table.set_all(t1, t2) - for k, v in pairs(t2) do - t1[k] = v - end - return t1 -end - -function futil.table.compose(t1, t2) - local t = table.copy(t1) - futil.table.set_all(t, t2) - return t -end - -function futil.table.pairs_by_value(t, cmp) - cmp = cmp or default_cmp - local s = {} - for k, v in pairs(t) do - table.insert(s, { k, v }) - end - - table.sort(s, function(a, b) - return cmp(a[2], b[2]) - end) - - local i = 0 - return function() - i = i + 1 - local v = s[i] - if v then - return unpack(v) - else - return nil - end - end -end - -function futil.table.pairs_by_key(t, cmp) - cmp = cmp or default_cmp - local s = {} - for k, v in pairs(t) do - table.insert(s, { k, v }) - end - - table.sort(s, function(a, b) - return cmp(a[1], b[1]) - end) - - local i = 0 - return function() - i = i + 1 - local v = s[i] - if v then - return unpack(v) - else - return nil - end - end -end - -function futil.table.size(t) - local size = 0 - for _ in pairs(t) do - size = size + 1 - end - return size -end - -function futil.table.is_empty(t) - return next(t) == nil -end - -function futil.table.count_elements(t) - local counts = {} - for _, item in ipairs(t) do - counts[item] = (counts[item] or 0) + 1 - end - return counts -end - -function futil.table.sets_intersect(set1, set2) - for k in pairs(set1) do - if set2[k] then - return true - end - end - - return false -end - -function futil.table.iterate(t) - local i = 0 - return function() - i = i + 1 - return t[i] - end -end - -function futil.table.reversed(t) - local len = #t - local reversed = {} - - for i = len, 1, -1 do - reversed[len - i + 1] = t[i] - end - - return reversed -end - -function futil.table.contains(t, value) - for _, v in ipairs(t) do - if v == value then - return true - end - end - - return false -end - -function futil.table.keys(t) - local keys = {} - for key in pairs(t) do - keys[#keys + 1] = key - end - return keys -end - -function futil.table.ikeys(t) - local key - return function() - key = next(t, key) - return key - end -end - -function futil.table.values(t) - local values = {} - for _, value in pairs(t) do - values[#values + 1] = value - end - return values -end - -function futil.table.sort_keys(t, cmp) - local keys = futil.table.keys(t) - table.sort(keys, cmp) - return keys -end - --- https://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle -function futil.table.shuffle(t, rnd) - rnd = rnd or math.random - for i = #t, 2, -1 do - local j = rnd(i) - t[i], t[j] = t[j], t[i] - end - return t -end - -local function swap(t, i, j) - t[i], t[j] = t[j], t[i] -end - -futil.table.swap = swap - -function futil.table.get(t, key, default) - local value = t[key] - if value == nil then - return default - end - return value -end - -function futil.table.setdefault(t, key, default) - local value = t[key] - if value == nil then - t[key] = default - return default - end - return value -end - -function futil.table.pack(...) - return { n = select("#", ...), ... } -end diff --git a/mods/futil/util/time.lua b/mods/futil/util/time.lua deleted file mode 100644 index ec7de0cb..00000000 --- a/mods/futil/util/time.lua +++ /dev/null @@ -1,29 +0,0 @@ -local idiv = futil.math.idiv - --- convert a number of seconds into a more human-readable value --- ignores the actual passage of time and assumes all years are 365 days -function futil.seconds_to_interval(time) - local s, m, h, d - - time, s = idiv(time, 60) - time, m = idiv(time, 60) - time, h = idiv(time, 24) - time, d = idiv(time, 365) - - if time ~= 0 then - return ("%d years %d days %02d:%02d:%02d"):format(time, d, h, m, s) - elseif d ~= 0 then - return ("%d days %02d:%02d:%02d"):format(d, h, m, s) - elseif h ~= 0 then - return ("%02d:%02d:%02d"):format(h, m, s) - elseif m ~= 0 then - return ("%02d:%02d"):format(m, s) - else - return ("%ds"):format(s) - end -end - --- ISO 8601 date format -function futil.format_utc(timestamp) - return os.date("!%Y-%m-%dT%TZ", timestamp) -end diff --git a/mods/minetest-fmod b/mods/minetest-fmod new file mode 160000 index 00000000..b414049b --- /dev/null +++ b/mods/minetest-fmod @@ -0,0 +1 @@ +Subproject commit b414049bbb6356bc8d21740899225b3dfb328efe diff --git a/mods/minetest-futil b/mods/minetest-futil new file mode 160000 index 00000000..b7ed1ebb --- /dev/null +++ b/mods/minetest-futil @@ -0,0 +1 @@ +Subproject commit b7ed1ebbb7e5ab5bd77706479e905571855583b7 diff --git a/mods/sbz_planets/mod.conf b/mods/sbz_planets/mod.conf index 30c13cf4..5e91f86f 100644 --- a/mods/sbz_planets/mod.conf +++ b/mods/sbz_planets/mod.conf @@ -1,2 +1,2 @@ name = sbz_planets -depends = sbz_base, biomegen, sbz_resources, sbz_chem, sbz_bio \ No newline at end of file +depends = sbz_base, sbz_resources, sbz_chem, sbz_bio From cb812d68fe0f5fe9979d31fd85f92db326b77648 Mon Sep 17 00:00:00 2001 From: TheEt1234 Date: Fri, 3 Oct 2025 20:55:35 +0200 Subject: [PATCH 14/28] Properly introduce annotations --- .luarc.json | 2 +- mods/stubes/routing_blocks.lua | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/.luarc.json b/.luarc.json index 7a95a52e..987b422d 100644 --- a/.luarc.json +++ b/.luarc.json @@ -1,6 +1,6 @@ { "runtime.version": "LuaJIT", "completion.autoRequire": false, - "workspace.library": [ "types/core.d.lua" ], + "workspace.library": [ "luanti_lsp_definitions/" ], "diagnostic.disable": [ "lowercase-global" ] } diff --git a/mods/stubes/routing_blocks.lua b/mods/stubes/routing_blocks.lua index b60b80c7..194959bb 100644 --- a/mods/stubes/routing_blocks.lua +++ b/mods/stubes/routing_blocks.lua @@ -2,13 +2,14 @@ -- Transport is handled in stube_transport.lua ---@class stube.RoutingState: table ----@field items { [any]: stube.TubedItem } Routing nodes can organize items hovewer they like +---@field items table Routing nodes can store tubes hovewer they like ---@field updated_at number ---@field to_remove? boolean ---@class stube.RoutingNodeDef ---@field update fun(state:stube.RoutingState, hpos: number):nil ---@field accept fun(state:stube.RoutingState, tubed_item:stube.TubedItem, dir: table):boolean +---@field iterate_items fun(state:stube.RoutingState, f:fun(item:stube.TubedItem, dir:vector?):nil) Used when deleting all items or something ---@field speed number Delay between updates, but routing nodes always update after tubes ---@type { [string]: stube.RoutingNodeDef } From 22a73a47c7f2fe0461021b0d3086625d95482ddb Mon Sep 17 00:00:00 2001 From: TheEt1234 Date: Sun, 5 Oct 2025 20:13:39 +0200 Subject: [PATCH 15/28] STube junctions --- luanti_lsp_definitions | 2 +- mods/sbz_base/pick_block.lua | 1 + mods/stubes/README.md | 47 ++++--- mods/stubes/basic_routing_blocks.lua | 172 ++++++++++++++++++++++++ mods/stubes/basic_tubes.lua | 7 +- mods/stubes/entity.lua | 2 +- mods/stubes/init.lua | 6 +- mods/stubes/place.lua | 41 ++++-- mods/stubes/register.lua | 6 +- mods/stubes/register_routing_blocks.lua | 153 +++++++++++++++++++++ mods/stubes/routing_blocks.lua | 21 --- mods/stubes/stube_transport.lua | 31 +++-- mods/stubes/textures/stube_junction.png | Bin 0 -> 186 bytes 13 files changed, 414 insertions(+), 75 deletions(-) create mode 100644 mods/stubes/basic_routing_blocks.lua create mode 100644 mods/stubes/register_routing_blocks.lua delete mode 100644 mods/stubes/routing_blocks.lua create mode 100644 mods/stubes/textures/stube_junction.png diff --git a/luanti_lsp_definitions b/luanti_lsp_definitions index bdbb099e..9ccb084f 160000 --- a/luanti_lsp_definitions +++ b/luanti_lsp_definitions @@ -1 +1 @@ -Subproject commit bdbb099e4fc5f2c7a75abfc91ac820dd093b3249 +Subproject commit 9ccb084f989bc15898c05bb6bf8ba15c88879115 diff --git a/mods/sbz_base/pick_block.lua b/mods/sbz_base/pick_block.lua index 262c76e0..9a65e20d 100644 --- a/mods/sbz_base/pick_block.lua +++ b/mods/sbz_base/pick_block.lua @@ -46,6 +46,7 @@ end controls.register_on_press(function(player, key) if not (key == 'LMB' or key == 'RMB') then return end + if not player:get_player_control().zoom then return end local node_name = get_pointed_node_type(player) if node_name then pick_block(player, node_name) end end) diff --git a/mods/stubes/README.md b/mods/stubes/README.md index 8917c690..96f4c594 100644 --- a/mods/stubes/README.md +++ b/mods/stubes/README.md @@ -1,29 +1,34 @@ # Stubes -Attempting to be luanti's best tubes. -Though, they are in a weird stage of still being dependant on pipeworks. +An attempt to be luanti's best item transport. I am using 32x32 textures for the tubes, because i could not fit a recognizable arrow into a 32x32 texture without making the node bigger. +I am also doing the textures in the style of Skyblock Zero. PRs for textures for other games are welcome. -This mod was heavily inspired by pipeworks. +This mod was inspired by pipeworks and by mindustry. + +## Terminology +In-game, Stubes should refer to themselves as just item tubes, but in code/comparisons they should be referred to as stubes to distinguish them from other implementations of item tubes. + +## Compatibility +STubes don't implement their own way of letting nodes accept stube tubed items. +The preffered way for a node to accept STube tubed items is using pipeworks, but there will be other ways in the future. + +| Name | Status | Notes | +| --------------- | ----------------- | ---------------------------------------------------------------- | +| **Pipeworks** | Mostly compatible | Currently, stube to pipeworks *tube* transport does not exist. | +| Tubelib | Not compatible | PRs welcome! Although i am unsure if there is demand. | +| Others? | Not compatible | Let me know if there is anything else worth adding to this table | + +### MAJOR INTERNAL IMPROVEMENTS/INTERNAL-ONLY BREAKING CHANGES ARE WELCOME + +If you don't think therere is no need for internal restructuring/breaking changes, make an issue. + +Currently i am interested in major improvements because: +- the stubes/routing block split is kinda strange? i dunno if stubes sohuld just ## Performance - Tubed item visuals which aren't near the player aren't shown (so that gets rid of the need to perform costly `move_to` calls) -- It should be able to handle 10 000 items quite easily - -# Docs - TODO: THEY ARE INACCURATE CURRENTLY -## Groups -- `stube=1` - if it's an stube -- `tubedevice`/`tubedevice_receiver` - these are groups from pipeworks -## Functions -### Registration -- `stube.register_tube(name, def)` - - It's the same as `core.register_node`, but there are a few special fields you need to put: - - `tube_textures` - a table of `{ plain = , noctr = , ends = , plain_up = , noctr_up = }` - - You can use `stube.make_tube_textures_from(filename)` to generate this, it needs to be a 3x2 texture sheet, check `textures/` directory for examples -### Placement -- `stube.place_tube(pos, dir)` - places a tube properly -- `stube.update_placement(pos)` - Use with `after_dig`/`after_place`, it updates the tube connections, useful if something got removed/placed - - Does not get rid of connections that were manually removed/made by a user -### Weird internals -- `stube.parse_tube_name(tube_name)` - Parses the `:_` into `{ dir (0 to 5), xc, yc, zc, nxc, nyc, nzc }` where, for example `xc` means if it's connected to the west, and `nxc` means if it's connected to the east (-X direction), and for the dir, see wallmounted param2 +- It should be able to handle 10 000 items easily + +# API: TODO diff --git a/mods/stubes/basic_routing_blocks.lua b/mods/stubes/basic_routing_blocks.lua new file mode 100644 index 00000000..59e57356 --- /dev/null +++ b/mods/stubes/basic_routing_blocks.lua @@ -0,0 +1,172 @@ +--- Game design: There should be a reason to not use the fastest tube all the time +--- So i am going to passionately give you that reason: Some routing blocks are too slow for them +--- +--- Oh btw, the routing blocks will have the speed of a fast tube, because if you want to replace slow tubes with just routing blocks, sure go ahead! that's a creative solution to a fun problem! +--- Also, under no situation should routing blocks put things into the air, that's not cool +--- FIXME: Routing nodes should also be tubedevice receivers +--- FIXME: Peacefully remove routing state when dug +--- FIXME: Routing state update loop + +local speed = 1 / 3 +local IG = core.get_item_group + +--- JUNCTIONS + +---@class stube.JunctionItem: stube.TubedItem +---@field dir integer Where the item wants to go, interesting behavior happens if you mess with this +---@field just_moved_to_center? boolean + +---@class stube.JunctionState: stube.RoutingState +---@field items { [integer]: stube.JunctionItem[]? } + +local function move_entity(ent, pos, dir) + ent:move_to(stube.get_precise_connection_pos(pos, dir), true) +end + +--- Okay, so i think the junction code is a little bit confusing, so let me clear up the confusion a little bit +--- Each item in a junction wants to go somewhere (junctionitem.dir) +--- so first it goes to the center +--- then it goes where it wants to go +--- then it gets out +--- +--- center can hold 6 items (one for each direction), non-center can hold only 2 items, but theoretically more (one going to the side, one going away, theoretically if this junction code is re-used, you can have wild shenanigans) +--- as you can see, there is a lot of code to enforce that too +--- +--- This is a lot simpler than tube routing :D + +-- try to output to a node or something +local function junction_try_output(state, out_pos, out_node, side, items) + local index, item + + for i, test_item in pairs(items) do + if test_item.dir == side then + index = i + item = test_item + break + end + end + + if not item then return end + if stube.insert_tubed_item(item, out_node, out_pos, side) then + item.dir = nil + table.remove(items, index) + end + if items[1] == nil and items[2] == nil then state[side] = nil end +end + +local function junction_move_to_center(state, side, items, pos) + for i, item in pairs(items) do + if item.dir ~= side then -- move to center + local can_move = true + for _, potential_duplicate in pairs(state.items[6] or {}) do + if potential_duplicate.dir == item.dir then can_move = false end + end + if can_move then + state.items[6] = state.items[6] or {} + state.items[6][#state.items[6] + 1] = item + if item.entity then move_entity(item.entity, pos, 6) end + + table.remove(items, i) + end + end + end +end + +local function junction_move_away_from_center(state, item_index, item, pos) + local items_at_target = state.items[item.dir] + if items_at_target == nil then + state.items[item.dir] = {} + items_at_target = state.items[item.dir] + end + + if #items_at_target > 2 then return end + for _, other_item in pairs(items_at_target) do + if other_item.dir == item.dir then return end + end + + items_at_target[#items_at_target + 1] = item + + if item.entity then move_entity(item.entity, pos, item.dir) end + table.remove(state.items[6], item_index) +end + +-- can hold 6*2 + 6 items... that's a lot compared to just 7 items, kinda like a mini chest +-- though i wouldn't use it for that xD + +local junction_size = 0.5 - 0.0001 +stube.register_routing_node('stubes:junction', { + description = 'Tube Junction', + groups = { stube_routing_node = 1 }, + + -- visuals: + tiles = { { name = 'stube_junction.png', backface_culling = false } }, + use_texture_alpha = 'clip', + drawtype = 'nodebox', + sunlight_propagates = true, + node_box = { + type = 'fixed', + fixed = { -junction_size, -junction_size, -junction_size, junction_size, junction_size, junction_size }, -- avoid z fighting + }, + paramtype2 = 'color', + paramtype = 'light', +}, { + speed = speed, + accept = function(state, tubed_item, dir, pos) + state = state ---@type stube.JunctionState + + local accept_dir = stube.opposite_wallmounted(dir) + + local accept_side = state.items[accept_dir] + if not accept_side then + state.items[accept_dir] = {} + accept_side = state.items[accept_dir] --- @type stube.JunctionItem[] + end + + if #accept_side == 2 then return false end + for _, item in pairs(accept_side) do + if item.dir == dir then return false end -- If its going the same direction + end + + -- okay excellent, so we can just accept + tubed_item = tubed_item ---@type stube.JunctionItem + tubed_item.dir = dir + table.insert(accept_side, tubed_item) + if tubed_item.entity then move_entity(tubed_item.entity, pos, accept_dir) end + return true + end, + iterate_items = function(state, f) + for side, items in pairs(state.items) do + for _, item in pairs(items) do + f(item, side) + end + end + end, + update = function(state, hpos) + local pos = core.get_position_from_hash(hpos) + -- output + for side, items in pairs(state.items) do + if side ~= 6 then + local out_pos = vector.add(stube.tube_state_connection_to_dir(side), pos) + local out_node = stube.get_or_load_node(out_pos) + junction_try_output(state, out_pos, out_node, side, items) + end + end + + -- internal transport + + -- move everything possible away from the center + local center_items = state.items[6] + if center_items then + for i, item in pairs(center_items) do + junction_move_away_from_center(state, i, item, pos) + end + end + + -- move everything possible to the center + for side, items in pairs(state.items) do + if side ~= 6 and (state.items[6] == nil or #state.items[6] < 6) then -- center is a true special case + junction_move_to_center(state, side, items, pos) + end + end + end, +}) diff --git a/mods/stubes/basic_tubes.lua b/mods/stubes/basic_tubes.lua index 211e7263..3d5d8a14 100644 --- a/mods/stubes/basic_tubes.lua +++ b/mods/stubes/basic_tubes.lua @@ -1,10 +1,9 @@ -local testing = 1 --- FIXME: Unified dyes support stube.register_tube('stubes:basic_tube', { paramtype2 = 'color', description = 'Basic Item Tube', use_texture_alpha = 'blend', - groups = { matter = 1, not_in_creative_inventory = testing }, + groups = { matter = 1 }, after_dig_node = stube.update_placement, on_punch = stube.default_tube_punch, @@ -25,7 +24,7 @@ stube.register_tube('stubes:fast_tube', { paramtype2 = 'color', description = 'Fast Item Tube', use_texture_alpha = 'blend', - groups = { matter = 1, not_in_creative_inventory = testing }, + groups = { matter = 1 }, after_dig_node = stube.update_placement, on_punch = stube.default_tube_punch, @@ -45,7 +44,7 @@ stube.register_tube('stubes:fast_tube', { stube.register_tube('stubes:very_fast_tube', { description = core.colorize('cyan', 'Very ') .. 'Fast Item Tube', use_texture_alpha = 'blend', - groups = { matter = 1, not_in_creative_inventory = testing }, + groups = { matter = 1 }, after_dig_node = stube.update_placement, on_punch = stube.default_tube_punch, diff --git a/mods/stubes/entity.lua b/mods/stubes/entity.lua index 383eecc0..56bdd5e0 100644 --- a/mods/stubes/entity.lua +++ b/mods/stubes/entity.lua @@ -6,7 +6,7 @@ core.register_entity('stubes:item_visual', { pointable = false, visual = 'wielditem', - visual_size = { x = stube.tube_size, y = stube.tube_size }, + visual_size = { x = stube.tube_size - 0.001, y = stube.tube_size - 0.001 }, -- prevent z-fighting glow = 1, }, on_activate = function(self, staticdata) diff --git a/mods/stubes/init.lua b/mods/stubes/init.lua index ade362a7..0ee17d9f 100644 --- a/mods/stubes/init.lua +++ b/mods/stubes/init.lua @@ -22,8 +22,8 @@ stube = { --- Creating a utils file is silly, so i am putting it here --- ALSO: This is a trick from the mt-mods/technic luanti mod ----@param pos vector ----@return node +---@param pos ivec +---@return core.Node.get stube.get_or_load_node = function(pos) local get_or_load_node_node = core.get_node_or_nil(pos) if get_or_load_node_node then return get_or_load_node_node end @@ -39,6 +39,8 @@ dofile(mp .. '/register.lua') -- Registering all the variants dofile(mp .. '/stube_transport.lua') -- Moving tubed items and their entities, named "stube_transport.lua" for easier debugging (As there may be multiple transpurt.luas) dofile(mp .. '/entity.lua') -- Only for defining the entity, and spawning/despawning them when needed dofile(mp .. '/hud.lua') -- When hovering over a tube with items you can see the counts +dofile(mp .. '/register_routing_blocks.lua') --- Content: dofile(mp .. '/basic_tubes.lua') +dofile(mp .. '/basic_routing_blocks.lua') diff --git a/mods/stubes/place.lua b/mods/stubes/place.lua index e719874f..d307c588 100644 --- a/mods/stubes/place.lua +++ b/mods/stubes/place.lua @@ -138,38 +138,47 @@ function stube.place_tube(name, pos, tube_dir, pointed_thing, sneaking) end end - --- Automatically connect any tubedevices + --- Automatically connect any tubedevices or routing blocks if not sneaking then for i = 0, 5 do local neighbor_dir = core.wallmounted_to_dir(i) local neighbor_pos = vector.add(pos, neighbor_dir) local neighbor_node = stube.get_or_load_node(neighbor_pos) + local should_connect = false if stube.is_tubedevice(neighbor_node.name) == true then local connect_sides = core.registered_nodes[neighbor_node.name].tube.connect_sides - local should_connect = true if connect_sides then should_connect = stube.process_pipeworks_connect_sides(connect_sides, -neighbor_dir, neighbor_node) + else + should_connect = true end - if should_connect then make_connection(connections, i) end + elseif core.get_item_group(neighbor_node.name, 'stube_routing_node') == 1 then + should_connect = true end + if should_connect then make_connection(connections, i) end end else -- Only connect the tubedevice we are sneaking at local under_node = stube.get_or_load_node(pointed_thing.under) local under_dir = vector.subtract(pointed_thing.above, pointed_thing.under) + local should_connect = false if stube.is_tubedevice(under_node.name) == true then local connect_sides = core.registered_nodes[under_node.name].tube.connect_sides - local should_connect = true if connect_sides then should_connect = stube.process_pipeworks_connect_sides(connect_sides, under_dir, under_node) + else + should_connect = true end - if should_connect then - make_connection( - connections, - core.dir_to_wallmounted(vector.subtract(pointed_thing.under, pointed_thing.above)) - ) - end + elseif core.get_item_group(under_node.name, 'stube_routing_node') == 1 then + should_connect = true + end + + if should_connect then + make_connection( + connections, + core.dir_to_wallmounted(vector.subtract(pointed_thing.under, pointed_thing.above)) + ) end end @@ -251,7 +260,13 @@ function stube.update_placement_single(pos) if connection == 1 then -- first case: pointing to air/incompatible node - if not (ig(connection_node.name, 'stube') == 1 or stube.is_tubedevice(connection_node.name) == true) then + if + not ( + ig(connection_node.name, 'stube') == 1 + or stube.is_tubedevice(connection_node.name) == true + or ig(connection_node.name, 'stube_routing_node') == 1 + ) + then split.connections[i] = 0 end @@ -283,7 +298,7 @@ function stube.update_placement_single(pos) local straight_tube_index = (stube.wallmounted_to_connections_index[split.dir] + 3) % 6 -- the index opposite to the dir, if that makes sense if straight_tube_index == 0 then straight_tube_index = 6 end - -- case 2.5: "We could totally be connected to that tubedevice right now actually, we don't need to be a short tube" + -- case 2.5: "We could totally be connected to that tubedevice/routing block right now actually, we don't need to be a short tube" if amount_of_connections == 1 and split.connections[straight_tube_index] == 1 then local dir = core.wallmounted_to_dir(split.dir) local next_pos = pos + dir @@ -299,6 +314,8 @@ function stube.update_placement_single(pos) ) end if should_connect then make_connection(split.connections, split.dir) end + elseif core.get_item_group(next_node.name, 'stube_routing_node') == 1 then + make_connection(split.connections, split.dir) end end diff --git a/mods/stubes/register.lua b/mods/stubes/register.lua index 1198d25e..c21b52ca 100644 --- a/mods/stubes/register.lua +++ b/mods/stubes/register.lua @@ -2,8 +2,8 @@ ---@class stube.TubeDef ---@field textures table ---@field speed number The amount of time between updates, lower is faster ----@field should_update fun(tube_hpos:integer, tube_state:stube.TubeState, node:node):boolean ----@field get_next_pos_and_node fun(tube_hpos:integer, tube_state:stube.TubeState, dir:integer):vector, node +---@field should_update fun(tube_hpos:integer, tube_state:stube.TubeState, node:core.Node.Get):boolean +---@field get_next_pos_and_node fun(tube_hpos:integer, tube_state:stube.TubeState, dir:integer):vector, core.Node.get ---@type {[string]: stube.TubeDef } stube.registered_tubes = {} @@ -190,7 +190,7 @@ function stube.register_tube(name, def, tubedef) -- Alias core.register_alias(name, name .. '_0000000') - def.drop = 'stubes:test_tube' + def.drop = name -- i saw what pipeworks was doing, so i think i am going with whatever this "old aproach" is https://github.com/mt-mods/pipeworks/blob/6e11868d1b32d316d60061c78460d260ac92ed6a/tubes/registration.lua#L176 -- because it mentioned something about "the textures must be rotated" with the "new aproach", and uh i think that will complicate things, and i don't want to deal with rotating them. diff --git a/mods/stubes/register_routing_blocks.lua b/mods/stubes/register_routing_blocks.lua new file mode 100644 index 00000000..80f32392 --- /dev/null +++ b/mods/stubes/register_routing_blocks.lua @@ -0,0 +1,153 @@ +-- Group: `stube_routing_node`=1 +-- Transport is handled in stube_transport.lua +-- Routing blocks also keep their entities, they can be transparent + +--- You must not add any new non-optional parameters +--- i mean thats not part of the license, its just, i'd rather you not, or it will be a real pain in the butt to update? +---@class stube.RoutingState: table +---@field items table Routing nodes can store tubes hovewer they like +---@field updated_at number Not really used, as routing blocks can't update outside of their trigger +---@field to_remove? boolean + +---@class stube.RoutingNodeDef +---@field update fun(state:stube.RoutingState, hpos: number):nil +---@field accept fun(state:stube.RoutingState, tubed_item:stube.TubedItem, dir: integer, pos: vector):boolean +---@field iterate_items fun(state:stube.RoutingState, f:fun(item:stube.TubedItem, dir:vector?):nil) Used when deleting all items or something +---@field speed number Delay between updates, but routing nodes always update after tubes + +---@type { [string]: stube.RoutingNodeDef } +stube.registered_routing_node = {} + +---@type table> +stube.routing_states = {} + +---FIXME: Also remove routing states if they are empty, thats important yknwoww +--- FIXME: add pipeworks tubedevice support +---@param routing_def stube.RoutingNodeDef +---@param def core.NodeDef +function stube.register_routing_node(name, def, routing_def) + stube.registered_routing_node[name] = routing_def + core.register_node(name, def) +end + +-- UTILS + +local IG = core.get_item_group + +---@param dir integer +local function move_entity(ent, pos, dir) + ent:move_to(stube.get_precise_connection_pos(pos, dir), true) +end + +local function move_connection(tube_state, dir1, dir2, pos) + if dir1 ~= dir2 then -- if it is equal, you are just moving the entity + assert( + not tube_state.connections[dir2], + '[stubes]Tried overriding with `local function move_connection(...)` in stubes/transport.lua, report this is a bug' + ) + tube_state.connections[dir2] = tube_state.connections[dir1] + tube_state.connections[dir1] = nil + end + + local ent = tube_state.connections[dir2].entity + if ent then move_entity(ent, pos, dir2) end +end + +--- If you have some sort of special tubed item, you can modify it after the fact +--- This does NOT handle actually removing the tubed item +--- The only thing it handles: It puts the tubed item in a node/routing node/tube +--- Inserting from pipeworks is handled with pipeworks's insert_object, don't worry about that +--- +--- So, when making a roouting device, you only have to worry about internal transport hopefully +---@return boolean success +function stube.insert_tubed_item(tubed_item, out_node, out_pos, dir) + local out_poshash = core.hash_node_position(out_pos) + local opposite_dir = stube.opposite_wallmounted(dir) + + if IG(out_node.name, 'stube') == 1 then + local prefix = stube.get_prefix_tube_name(out_node.name) + local tube_states_of_prefix = stube.all_stubes[prefix] + local tube_state = tube_states_of_prefix[out_poshash] + if not tube_state then + tube_states_of_prefix[out_poshash] = { + connections = {}, + updated_at = stube.current_update_time, + } + tube_state = tube_states_of_prefix[out_poshash] + end + + if tube_state.connections[opposite_dir] then return false end + tube_state.connections[opposite_dir] = tubed_item + move_connection(tube_state, opposite_dir, opposite_dir, out_pos) + return true + elseif IG(out_node.name, 'stube_routing_node') == 1 then + local routing_state = stube.routing_states[out_node.name][out_poshash] + if not routing_state then + stube.routing_states[out_node.name][out_poshash] = { + items = {}, + updated_at = stube.current_update_time, + } + routing_state = stube.routing_states[out_node.name][out_poshash] + end + + local def = stube.registered_routing_node[out_node.name] + local success = def.accept(routing_state, tubed_item, opposite_dir) + return success + elseif IG(out_node.name, 'tubedevice_receiver') == 1 then + --- FIXME: + end + return false +end + +--- bad = its empty or state.to_remove == true or type~=node.name +function stube.remove_bad_routing_states(type, state, hpos, node) + local empty = true + local def = stube.registered_routing_node[type] + local pos = core.get_position_from_hash(hpos) + + def.iterate_items(state, function() + empty = false + end) + + if empty then state.to_remove = true end + if node.name ~= type then state.to_remove = true end + if state.to_remove then + stube.routing_states[type][hpos] = nil + def.iterate_items(state, function(item, dir) + local item_pos = pos + if dir then item_pos = stube.get_precise_connection_pos(pos, dir) end + core.add_item(item_pos, item.stack) + end) + end +end + +local timers = {} +core.register_on_mods_loaded(function() + for name, def in pairs(stube.registered_routing_node) do + timers[name] = { current = 0, max = def.speed } + stube.routing_states[name] = {} + end +end) + +local function process_routing_type(type) + for hpos, state in pairs(stube.routing_states[type]) do + local node = stube.get_or_load_node(core.get_position_from_hash(hpos)) + if node.name ~= type then + state.to_remove = true + else + stube.registered_routing_node[node.name].update(state, hpos) + end + stube.remove_bad_routing_states(type, state, hpos, node) + end +end + +--- Called by stube.globalstep +function stube.routing_globalstep(dtime) + for name, timer in pairs(timers) do + timer.current = timer.current + dtime + if timer.current >= timer.max then + process_routing_type(name) + timer.current = 0 + end + end +end diff --git a/mods/stubes/routing_blocks.lua b/mods/stubes/routing_blocks.lua deleted file mode 100644 index 194959bb..00000000 --- a/mods/stubes/routing_blocks.lua +++ /dev/null @@ -1,21 +0,0 @@ --- Group: `stube_routing_node`=1 --- Transport is handled in stube_transport.lua - ----@class stube.RoutingState: table ----@field items table Routing nodes can store tubes hovewer they like ----@field updated_at number ----@field to_remove? boolean - ----@class stube.RoutingNodeDef ----@field update fun(state:stube.RoutingState, hpos: number):nil ----@field accept fun(state:stube.RoutingState, tubed_item:stube.TubedItem, dir: table):boolean ----@field iterate_items fun(state:stube.RoutingState, f:fun(item:stube.TubedItem, dir:vector?):nil) Used when deleting all items or something ----@field speed number Delay between updates, but routing nodes always update after tubes - ----@type { [string]: stube.RoutingNodeDef } -stube.registered_routing_node = {} - -function stube.register_routing_node(name, def, routing_def) - stube.registered_routing_node[name] = routing_def - core.register_node(name, def) -end diff --git a/mods/stubes/stube_transport.lua b/mods/stubes/stube_transport.lua index 19db7810..aac1aa0a 100644 --- a/mods/stubes/stube_transport.lua +++ b/mods/stubes/stube_transport.lua @@ -2,10 +2,10 @@ local h, uh = core.hash_node_position, core.get_position_from_hash ----@class stube.TubedItem ----@field stack ItemStack +---@class stube.TubedItem:table +---@field stack core.ItemStack ---@field owner? string ----@field entity? userdata +---@field entity? core.Entity --- The state of any active tube --- The node underneeth a tube state can be anything, and it can change at any time @@ -28,10 +28,12 @@ core.register_on_mods_loaded(function() end end) -local function opposite_wallmounted(wallmounted) - return core.dir_to_wallmounted(-core.wallmounted_to_dir(wallmounted)) -- efficiency :D (joke) +---@param wallmounted integer +function stube.opposite_wallmounted(wallmounted) + return core.dir_to_wallmounted(-core.wallmounted_to_dir(wallmounted)) end +---@return ivec function stube.tube_state_connection_to_dir(connection) if connection == 6 then return vector.zero() -- The center @@ -124,7 +126,7 @@ local function push_items_to_next_tube(next_node, next_pos, tube_state, tube_dir local is_empty = next_tube_state == nil local can_insert = true local next_tube_dir = stube.get_tube_dir(next_node.name) - local opposite_tube_dir = opposite_wallmounted(tube_dir) + local opposite_tube_dir = stube.opposite_wallmounted(tube_dir) if is_empty == false then can_insert = next_tube_state.connections[opposite_tube_dir] == nil -- If there isn't an item in the way @@ -225,6 +227,18 @@ function stube.update_tube(tube_hpos, tube_def, tube_state, prefix) push_items_to_next_tube(next_node, next_pos, tube_state, tube_dir, tube_vpos) delete_if_empty_state(tube_hpos, tube_state, stubes[prefix]) end + elseif IG(next_node.name, 'stube_routing_node') == 1 then + local def = stube.registered_routing_node[next_node.name] + local next_poshash = h(next_pos) + + local state = stube.routing_states[next_node.name][next_poshash] + if not state then + stube.routing_states[next_node.name][next_poshash] = { items = {}, updated_at = 0 } + state = stube.routing_states[next_node.name][next_poshash] + end + + local accepted = def.accept(state, tube_state.connections[tube_dir], tube_dir, next_pos) + if accepted then tube_state.connections[tube_dir] = nil end elseif IG(next_node.name, 'tubedevice_receiver') == 1 then stube.transfer_items(tube_state, next_node, next_pos, tube_dir) end @@ -244,6 +258,7 @@ end ---@return nil function stube.globalstep(dtime) stube.current_update_time = stube.current_update_time + 1 + stube.routing_globalstep(dtime) for name, timer in pairs(timers) do timer.current = timer.current + dtime if timer.current >= timer.max then @@ -251,7 +266,6 @@ function stube.globalstep(dtime) timer.current = 0 end end - stube.routing_globalstep(dtime) end core.register_globalstep(stube.globalstep) @@ -305,6 +319,3 @@ function stube.tube_input_insert_object(pos, node, stack, vel, owner) return stack end end - ---- Called by stube.globalstep -function stube.routing_globalstep(dtime) end diff --git a/mods/stubes/textures/stube_junction.png b/mods/stubes/textures/stube_junction.png new file mode 100644 index 0000000000000000000000000000000000000000..1f05ddd2714b11d150c15d8311b5e3afecf6d578 GIT binary patch literal 186 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`jKx9jP7LeL$-D$|N<3X0Lo9le z*KEo9ao&M3Au%B#!Q$U%qppPB9qi7hPs_3#)wx+JIYVRP+{VU40f_^L4lsO_H!8R{ z>(GNU6Pi}ulAgNz`{CdY#utr`&rCRU;KYd&9Xj9s1A(%pfTV;%otwCGc)PKH Date: Mon, 13 Oct 2025 19:45:51 +0200 Subject: [PATCH 16/28] Push changes (whatever they may be) --- .gitmodules | 3 + luanti_lsp_definitions | 2 +- mods/hotbar_switching | 2 +- mods/stubes | 1 + mods/stubes/README.md | 34 -- mods/stubes/basic_routing_blocks.lua | 172 -------- mods/stubes/basic_tubes.lua | 62 --- mods/stubes/entity.lua | 94 ----- mods/stubes/hud.lua | 67 --- mods/stubes/init.lua | 46 --- mods/stubes/mod.conf | 2 - mods/stubes/place.lua | 391 ------------------ mods/stubes/register.lua | 312 -------------- mods/stubes/register_routing_blocks.lua | 153 ------- mods/stubes/stube_transport.lua | 321 -------------- mods/stubes/textures/stube_basic_tube.png | Bin 517 -> 0 bytes mods/stubes/textures/stube_fast_tube.png | Bin 519 -> 0 bytes mods/stubes/textures/stube_junction.png | Bin 186 -> 0 bytes mods/stubes/textures/stube_very_fast_tube.png | Bin 475 -> 0 bytes 19 files changed, 6 insertions(+), 1656 deletions(-) create mode 160000 mods/stubes delete mode 100644 mods/stubes/README.md delete mode 100644 mods/stubes/basic_routing_blocks.lua delete mode 100644 mods/stubes/basic_tubes.lua delete mode 100644 mods/stubes/entity.lua delete mode 100644 mods/stubes/hud.lua delete mode 100644 mods/stubes/init.lua delete mode 100644 mods/stubes/mod.conf delete mode 100644 mods/stubes/place.lua delete mode 100644 mods/stubes/register.lua delete mode 100644 mods/stubes/register_routing_blocks.lua delete mode 100644 mods/stubes/stube_transport.lua delete mode 100644 mods/stubes/textures/stube_basic_tube.png delete mode 100644 mods/stubes/textures/stube_fast_tube.png delete mode 100644 mods/stubes/textures/stube_junction.png delete mode 100644 mods/stubes/textures/stube_very_fast_tube.png diff --git a/.gitmodules b/.gitmodules index d6598e95..4fb51292 100644 --- a/.gitmodules +++ b/.gitmodules @@ -34,3 +34,6 @@ [submodule "mods/minetest-futil"] path = mods/minetest-futil url = https://github.com/fluxionary/minetest-futil +[submodule "mods/stubes"] + path = mods/stubes + url = https://github.com/TheEt1234/luanti-stubes diff --git a/luanti_lsp_definitions b/luanti_lsp_definitions index 9ccb084f..fe88552d 160000 --- a/luanti_lsp_definitions +++ b/luanti_lsp_definitions @@ -1 +1 @@ -Subproject commit 9ccb084f989bc15898c05bb6bf8ba15c88879115 +Subproject commit fe88552d68b2a6778cca69d1bc01bb14c5c743e1 diff --git a/mods/hotbar_switching b/mods/hotbar_switching index 2ff96c52..5bb3910b 160000 --- a/mods/hotbar_switching +++ b/mods/hotbar_switching @@ -1 +1 @@ -Subproject commit 2ff96c5288853b2c294b76b6c9c892b5350805eb +Subproject commit 5bb3910bd9c1b3cb715bc400dea723c391b82211 diff --git a/mods/stubes b/mods/stubes new file mode 160000 index 00000000..93240982 --- /dev/null +++ b/mods/stubes @@ -0,0 +1 @@ +Subproject commit 932409829247f628ac5cb28771161527b87dcaf3 diff --git a/mods/stubes/README.md b/mods/stubes/README.md deleted file mode 100644 index 96f4c594..00000000 --- a/mods/stubes/README.md +++ /dev/null @@ -1,34 +0,0 @@ -# Stubes - -An attempt to be luanti's best item transport. - -I am using 32x32 textures for the tubes, because i could not fit a recognizable arrow into a 32x32 texture without making the node bigger. -I am also doing the textures in the style of Skyblock Zero. PRs for textures for other games are welcome. - -This mod was inspired by pipeworks and by mindustry. - -## Terminology -In-game, Stubes should refer to themselves as just item tubes, but in code/comparisons they should be referred to as stubes to distinguish them from other implementations of item tubes. - -## Compatibility -STubes don't implement their own way of letting nodes accept stube tubed items. -The preffered way for a node to accept STube tubed items is using pipeworks, but there will be other ways in the future. - -| Name | Status | Notes | -| --------------- | ----------------- | ---------------------------------------------------------------- | -| **Pipeworks** | Mostly compatible | Currently, stube to pipeworks *tube* transport does not exist. | -| Tubelib | Not compatible | PRs welcome! Although i am unsure if there is demand. | -| Others? | Not compatible | Let me know if there is anything else worth adding to this table | - -### MAJOR INTERNAL IMPROVEMENTS/INTERNAL-ONLY BREAKING CHANGES ARE WELCOME - -If you don't think therere is no need for internal restructuring/breaking changes, make an issue. - -Currently i am interested in major improvements because: -- the stubes/routing block split is kinda strange? i dunno if stubes sohuld just - -## Performance -- Tubed item visuals which aren't near the player aren't shown (so that gets rid of the need to perform costly `move_to` calls) -- It should be able to handle 10 000 items easily - -# API: TODO diff --git a/mods/stubes/basic_routing_blocks.lua b/mods/stubes/basic_routing_blocks.lua deleted file mode 100644 index 59e57356..00000000 --- a/mods/stubes/basic_routing_blocks.lua +++ /dev/null @@ -1,172 +0,0 @@ ---- Game design: There should be a reason to not use the fastest tube all the time ---- So i am going to passionately give you that reason: Some routing blocks are too slow for them ---- ---- Oh btw, the routing blocks will have the speed of a fast tube, because if you want to replace slow tubes with just routing blocks, sure go ahead! that's a creative solution to a fun problem! ---- Also, under no situation should routing blocks put things into the air, that's not cool ---- FIXME: Routing nodes should also be tubedevice receivers ---- FIXME: Peacefully remove routing state when dug ---- FIXME: Routing state update loop - -local speed = 1 / 3 -local IG = core.get_item_group - ---- JUNCTIONS - ----@class stube.JunctionItem: stube.TubedItem ----@field dir integer Where the item wants to go, interesting behavior happens if you mess with this ----@field just_moved_to_center? boolean - ----@class stube.JunctionState: stube.RoutingState ----@field items { [integer]: stube.JunctionItem[]? } - -local function move_entity(ent, pos, dir) - ent:move_to(stube.get_precise_connection_pos(pos, dir), true) -end - ---- Okay, so i think the junction code is a little bit confusing, so let me clear up the confusion a little bit ---- Each item in a junction wants to go somewhere (junctionitem.dir) ---- so first it goes to the center ---- then it goes where it wants to go ---- then it gets out ---- ---- center can hold 6 items (one for each direction), non-center can hold only 2 items, but theoretically more (one going to the side, one going away, theoretically if this junction code is re-used, you can have wild shenanigans) ---- as you can see, there is a lot of code to enforce that too ---- ---- This is a lot simpler than tube routing :D - --- try to output to a node or something -local function junction_try_output(state, out_pos, out_node, side, items) - local index, item - - for i, test_item in pairs(items) do - if test_item.dir == side then - index = i - item = test_item - break - end - end - - if not item then return end - if stube.insert_tubed_item(item, out_node, out_pos, side) then - item.dir = nil - table.remove(items, index) - end - if items[1] == nil and items[2] == nil then state[side] = nil end -end - -local function junction_move_to_center(state, side, items, pos) - for i, item in pairs(items) do - if item.dir ~= side then -- move to center - local can_move = true - for _, potential_duplicate in pairs(state.items[6] or {}) do - if potential_duplicate.dir == item.dir then can_move = false end - end - if can_move then - state.items[6] = state.items[6] or {} - state.items[6][#state.items[6] + 1] = item - if item.entity then move_entity(item.entity, pos, 6) end - - table.remove(items, i) - end - end - end -end - -local function junction_move_away_from_center(state, item_index, item, pos) - local items_at_target = state.items[item.dir] - if items_at_target == nil then - state.items[item.dir] = {} - items_at_target = state.items[item.dir] - end - - if #items_at_target > 2 then return end - for _, other_item in pairs(items_at_target) do - if other_item.dir == item.dir then return end - end - - items_at_target[#items_at_target + 1] = item - - if item.entity then move_entity(item.entity, pos, item.dir) end - table.remove(state.items[6], item_index) -end - --- can hold 6*2 + 6 items... that's a lot compared to just 7 items, kinda like a mini chest --- though i wouldn't use it for that xD - -local junction_size = 0.5 - 0.0001 -stube.register_routing_node('stubes:junction', { - description = 'Tube Junction', - groups = { stube_routing_node = 1 }, - - -- visuals: - tiles = { { name = 'stube_junction.png', backface_culling = false } }, - use_texture_alpha = 'clip', - drawtype = 'nodebox', - sunlight_propagates = true, - node_box = { - type = 'fixed', - fixed = { -junction_size, -junction_size, -junction_size, junction_size, junction_size, junction_size }, -- avoid z fighting - }, - paramtype2 = 'color', - paramtype = 'light', -}, { - speed = speed, - accept = function(state, tubed_item, dir, pos) - state = state ---@type stube.JunctionState - - local accept_dir = stube.opposite_wallmounted(dir) - - local accept_side = state.items[accept_dir] - if not accept_side then - state.items[accept_dir] = {} - accept_side = state.items[accept_dir] --- @type stube.JunctionItem[] - end - - if #accept_side == 2 then return false end - for _, item in pairs(accept_side) do - if item.dir == dir then return false end -- If its going the same direction - end - - -- okay excellent, so we can just accept - tubed_item = tubed_item ---@type stube.JunctionItem - tubed_item.dir = dir - table.insert(accept_side, tubed_item) - if tubed_item.entity then move_entity(tubed_item.entity, pos, accept_dir) end - return true - end, - iterate_items = function(state, f) - for side, items in pairs(state.items) do - for _, item in pairs(items) do - f(item, side) - end - end - end, - update = function(state, hpos) - local pos = core.get_position_from_hash(hpos) - -- output - for side, items in pairs(state.items) do - if side ~= 6 then - local out_pos = vector.add(stube.tube_state_connection_to_dir(side), pos) - local out_node = stube.get_or_load_node(out_pos) - junction_try_output(state, out_pos, out_node, side, items) - end - end - - -- internal transport - - -- move everything possible away from the center - local center_items = state.items[6] - if center_items then - for i, item in pairs(center_items) do - junction_move_away_from_center(state, i, item, pos) - end - end - - -- move everything possible to the center - for side, items in pairs(state.items) do - if side ~= 6 and (state.items[6] == nil or #state.items[6] < 6) then -- center is a true special case - junction_move_to_center(state, side, items, pos) - end - end - end, -}) diff --git a/mods/stubes/basic_tubes.lua b/mods/stubes/basic_tubes.lua deleted file mode 100644 index 3d5d8a14..00000000 --- a/mods/stubes/basic_tubes.lua +++ /dev/null @@ -1,62 +0,0 @@ ---- FIXME: Unified dyes support -stube.register_tube('stubes:basic_tube', { - paramtype2 = 'color', - description = 'Basic Item Tube', - use_texture_alpha = 'blend', - groups = { matter = 1 }, - after_dig_node = stube.update_placement, - on_punch = stube.default_tube_punch, - - -- Needed or it will be buggy - drawtype = 'nodebox', - sunlight_propagates = true, - paramtype = 'light', -}, { - textures = stube.make_tube_textures_from 'stube_basic_tube.png', - speed = 1, -- seconds/stack - should_update = stube.default_should_update_tube, - get_next_pos_and_node = stube.default_get_next_pos_and_node, -}) - ---- Game design: This tube should be a lot more expensive than the basic tube ---- Because it's basically 3 basic tubes in one node -stube.register_tube('stubes:fast_tube', { - paramtype2 = 'color', - description = 'Fast Item Tube', - use_texture_alpha = 'blend', - groups = { matter = 1 }, - after_dig_node = stube.update_placement, - on_punch = stube.default_tube_punch, - - drawtype = 'nodebox', - sunlight_propagates = true, - paramtype = 'light', -}, { - textures = stube.make_tube_textures_from 'stube_fast_tube.png', - speed = 1 / 3, -- 3x faster!! - should_update = stube.default_should_update_tube, - get_next_pos_and_node = stube.default_get_next_pos_and_node, -}) - ---- Game design: Let the player have some fun, at a huge cost ---- Actually just kidding it's just 2x faster than pipeworks, and as fast as accelerator tubes ---- so not that fun -stube.register_tube('stubes:very_fast_tube', { - description = core.colorize('cyan', 'Very ') .. 'Fast Item Tube', - use_texture_alpha = 'blend', - groups = { matter = 1 }, - after_dig_node = stube.update_placement, - on_punch = stube.default_tube_punch, - - drawtype = 'nodebox', - sunlight_propagates = true, - paramtype = 'light', -}, { - textures = stube.make_tube_textures_from 'stube_very_fast_tube.png', - speed = 1 / 10, - should_update = stube.default_should_update_tube, - get_next_pos_and_node = stube.default_get_next_pos_and_node, -}) - --- Excercise for the viewer: You can make your own TRULY FAST TUBE --- Copy the definition for very_fast_tube, change the speed to zero, and change the name diff --git a/mods/stubes/entity.lua b/mods/stubes/entity.lua deleted file mode 100644 index 56bdd5e0..00000000 --- a/mods/stubes/entity.lua +++ /dev/null @@ -1,94 +0,0 @@ -core.register_entity('stubes:item_visual', { - initial_properties = { - physical = false, - textures = { '' }, - static_save = false, - - pointable = false, - visual = 'wielditem', - visual_size = { x = stube.tube_size - 0.001, y = stube.tube_size - 0.001 }, -- prevent z-fighting - glow = 1, - }, - on_activate = function(self, staticdata) - local stack = ItemStack(staticdata) - self.object:set_properties { - textures = { stack:get_name() }, - } - end, -}) - -local function create_visual(pos, stack) - return core.add_entity(pos, 'stubes:item_visual', stack:to_string()) -end - ----@param pos vector ----@param tubestate stube.TubeState -function stube.add_visuals_to_tubestate(pos, tubestate) - for dir, connection in pairs(tubestate.connections) do - local vdir = core.wallmounted_to_dir(dir) - if dir == 6 then vdir = vector.zero() end - if not connection.entity then connection.entity = create_visual(vector.add(pos, vdir / 3), connection.stack) end - end -end - ----@param tubestate stube.TubeState -function stube.remove_visuals_from_tubestate(tubestate) - for _, connection in pairs(tubestate.connections) do - if connection.entity then - connection.entity:remove() - connection.entity = nil - end - end -end - -local function get_player_positions() - local ret = {} - for _, player in pairs(core.get_connected_players()) do - ret[#ret + 1] = player:get_pos() - end - return ret -end - ---- Adds/removes tubestate visuals depending on if they are actually needed ---- Time complexity: O(amount_of_tubes*amount_of_players) i think, not great ----@param tubestate stube.TubeState ----@param pos vector ----@param player_positions vector[]? -function stube.add_or_remove_tubestate_visuals(pos, tubestate, player_positions) - if stube.enable_entities == false then return stube.remove_visuals_from_tubestate(tubestate) end - - if not player_positions then player_positions = get_player_positions() end - local should_add = false - for i = 1, #player_positions do - local player_position = player_positions[i] - if vector.distance(pos, player_position) <= stube.entity_radius then - should_add = true - break - end - end - - if should_add then - stube.add_visuals_to_tubestate(pos, tubestate) - else - stube.remove_visuals_from_tubestate(tubestate) - end -end - -local timer = 0 -local timer_max = stube.entity_creation_globalstep_time --- stube.update updates visuals, this is responsible for adding/deleting them -function stube.visual_globalstep(dtime) - timer = timer + dtime - if timer < timer_max then return end - timer = 0 - - local player_positions = get_player_positions() - - for tube_type, tubes_array in pairs(stube.all_stubes) do - for hpos, tube_state in pairs(tubes_array) do - stube.add_or_remove_tubestate_visuals(core.get_position_from_hash(hpos), tube_state, get_player_positions()) - end - end -end - -core.register_globalstep(stube.visual_globalstep) diff --git a/mods/stubes/hud.lua b/mods/stubes/hud.lua deleted file mode 100644 index ffd5e0b8..00000000 --- a/mods/stubes/hud.lua +++ /dev/null @@ -1,67 +0,0 @@ --- Display how many items are inside a tube with a HUD --- ... wow HUDs are dogsh#t - ---- { [player name] = id[] } ----@type table -local ids = {} - -local timer = 0 -local timer_max = 0.25 - -function stube.hud_update(player) - local player_name = player:get_player_name() - local tube_pos, tube_node - - local look_dir = player:get_look_dir() - local eye_pos = player:get_pos() - eye_pos.y = eye_pos.y + (player:get_properties().eye_height or 0) - - local ray = core.raycast(eye_pos, vector.add(eye_pos, vector.multiply(look_dir, 5)), false, false) - for pointed_thing in ray do - if pointed_thing.type == 'node' then - local node = core.get_node(pointed_thing.under) - if core.get_item_group(node.name, 'stube') == 1 then - tube_pos, tube_node = pointed_thing.under, node - break - end - end - end - - if ids[player_name] then - for _, id in pairs(ids[player_name]) do - player:hud_remove(id) - end - ids[player_name] = nil - end - - if not tube_pos then return end - local tube_state = stube.all_stubes[stube.get_prefix_tube_name(tube_node.name)][core.hash_node_position(tube_pos)] - if not tube_state then return end - - ids[player_name] = {} - for dir, connection in pairs(tube_state.connections) do - table.insert( - ids[player_name], - player:hud_add { - type = 'waypoint', - precision = 0, - name = tostring(connection.stack:get_count()), - number = (connection.stack:get_count() / connection.stack:get_stack_max()) * 0xFFFFFF, -- i love the not at all confusing HUD api - world_pos = stube.get_precise_connection_pos(tube_pos, dir), - } - ) - end -end - ----@param dtime number -function stube.hud_globalstep(dtime) - timer = timer + dtime - if timer < timer_max then return end - timer = 0 - - for _, player in pairs(core.get_connected_players()) do - stube.hud_update(player) - end -end - -core.register_globalstep(stube.hud_globalstep) diff --git a/mods/stubes/init.lua b/mods/stubes/init.lua deleted file mode 100644 index 0ee17d9f..00000000 --- a/mods/stubes/init.lua +++ /dev/null @@ -1,46 +0,0 @@ ---- Configuration in init.lua ----@class stube -stube = { - -- The debug mode for STubes - -- Currently, it just pollutes the creative inventory with tube variants - debug = false, - - -- This is mostly an option for testing, there is no actual reason to disable them (You can just set entity_radius to something low if you don't like them) - enable_entities = true, - - -- Item Entities will be shown when the player is this many nodes near to them - -- Set to a huge value to almost always have item entities (Why would you do that?) - -- This feature has been shown to help, as it skips laggy entity move_to calls - entity_radius = 16, - - -- The globalstep for creating/removing entities will be run every seconds - entity_creation_globalstep_time = 1, - - -- For simplicity, each tube must be the same size (simplicity in: each tubed item has to be the same size) - tube_size = 3 / 16, -} - ---- Creating a utils file is silly, so i am putting it here ---- ALSO: This is a trick from the mt-mods/technic luanti mod ----@param pos ivec ----@return core.Node.get -stube.get_or_load_node = function(pos) - local get_or_load_node_node = core.get_node_or_nil(pos) - if get_or_load_node_node then return get_or_load_node_node end - core.load_area(pos) - return core.get_node(pos) -end - -local mp = core.get_modpath(core.get_current_modname()) - ---- Library: -dofile(mp .. '/place.lua') -- Placement of tubes (kinda complicated) -dofile(mp .. '/register.lua') -- Registering all the variants -dofile(mp .. '/stube_transport.lua') -- Moving tubed items and their entities, named "stube_transport.lua" for easier debugging (As there may be multiple transpurt.luas) -dofile(mp .. '/entity.lua') -- Only for defining the entity, and spawning/despawning them when needed -dofile(mp .. '/hud.lua') -- When hovering over a tube with items you can see the counts -dofile(mp .. '/register_routing_blocks.lua') - ---- Content: -dofile(mp .. '/basic_tubes.lua') -dofile(mp .. '/basic_routing_blocks.lua') diff --git a/mods/stubes/mod.conf b/mods/stubes/mod.conf deleted file mode 100644 index 0db7cdcc..00000000 --- a/mods/stubes/mod.conf +++ /dev/null @@ -1,2 +0,0 @@ -name = stubes -depends = pipeworks diff --git a/mods/stubes/place.lua b/mods/stubes/place.lua deleted file mode 100644 index d307c588..00000000 --- a/mods/stubes/place.lua +++ /dev/null @@ -1,391 +0,0 @@ --- Okay so this code is kinda messy? probably better than pipeworks --- just uh be aware --- if you don't understand it thats fine, message me (frog) and i could make a comment explaining - ---- If it's a tube device, and is NOT an stube -function stube.is_tubedevice(node_name) - local reg = core.registered_nodes[node_name] - if reg == nil then return false end - if reg.tube == nil then return false end - if core.get_item_group(node_name, 'stube') == 1 then return false end - return true -end - --- pipeworks has a better solution im not doing for the sake of licensing -function stube.process_pipeworks_connect_sides(connect_sides, neighbor_dir, neighbor_node) - local neighbor_facedir = neighbor_node.param2 - local neighbor_facedir_dir = core.facedir_to_dir(neighbor_facedir) - if neighbor_facedir > 23 then neighbor_facedir = 0 end - local rotate_by = -vector.dir_to_rotation(neighbor_facedir_dir) - if math.floor(neighbor_facedir / 4) ~= 0 and rotate_by.y < -1 then rotate_by.x = -(math.pi / 2) end -- HACK, that i am not going to fix, this was derived from brute force, it allows placing tubes to tubedevices from above work, specifically filter injectors - local correct_dir = vector.rotate(neighbor_dir, rotate_by) - local wallmounted_dir = core.dir_to_wallmounted(correct_dir) - - local index = (wallmounted_dir == 0 and 'top') - or (wallmounted_dir == 1 and 'bottom') - or (wallmounted_dir == 2 and 'right') - or (wallmounted_dir == 3 and 'left') - or (wallmounted_dir == 4 and 'front') - or (wallmounted_dir == 5 and 'back') - return connect_sides[index] == 1 or connect_sides[index] == true -end - -local function has_no_connections(connections) - for i = 1, 6 do - if connections[i] == 1 then return false end - end - return true -end - --- the order in which i chose the connections was kinda stupid, because it isn't the wallmounted direction --- so i have to do this sort of thing instead of just doing connections[wallmounted]=1 --- This table is {[wallmounted] = STube connection} -stube.wallmounted_to_connections_index = { - [0] = 2, - [1] = 5, - [2] = 1, - [3] = 4, - [4] = 3, - [5] = 6, -} - -local connections_to_wallmounted = table.key_value_swap(table.copy(stube.wallmounted_to_connections_index)) - -local function make_connection(connections, wallmounted_dir, remove_connection) - local set_to = 1 - if remove_connection then set_to = 0 end - connections[stube.wallmounted_to_connections_index[wallmounted_dir]] = set_to -end - -function stube.connect_tubes_to(pos, dir, pointed_thing, sneaking) - pos = vector.copy(pos) -- guaranteed to be a vector - - -- Connect to our tube if it is pointing to it - for idir = 0, 5 do - local neighbor_dir_from_origin = core.wallmounted_to_dir(idir) - local neighbor_pos = pos + neighbor_dir_from_origin - local neighbor_node = stube.get_or_load_node(neighbor_pos) - - if core.get_item_group(neighbor_node.name, 'stube') == 1 then - local split = stube.split_tube_name(neighbor_node.name) - local pointing_to = (core.wallmounted_to_dir(split.dir) + neighbor_pos) - - if pointing_to == pos or has_no_connections(split.connections) then - local connection_dir = core.dir_to_wallmounted(pos - neighbor_pos) - - if has_no_connections(split.connections) then split.dir = connection_dir end - make_connection(split.connections, connection_dir) - - core.set_node(neighbor_pos, { name = stube.join_tube_name(split) }) - end - end - end - - -- Switch the direction of the position under - -- Makes making turns actually possible - if pointed_thing then - local node = stube.get_or_load_node(pointed_thing.under) - - if core.get_item_group(node.name, 'stube') == 1 then - local split = stube.split_tube_name(node.name) - split.dir = dir - make_connection(split.connections, dir) - core.set_node(pointed_thing.under, { name = stube.join_tube_name(split) }) - end - end - - -- make the tube that is in front of us, point to us - -- This makes connecting tubes with multiple inputs possible, after they have already been placed - if dir and not sneaking then - local vdir = core.wallmounted_to_dir(dir) - local front_pos = pos + vdir - local front_node = stube.get_or_load_node(front_pos) - - if core.get_item_group(front_node.name, 'stube') == 1 then - local split = stube.split_tube_name(front_node.name) - - make_connection(split.connections, split.dir) - make_connection(split.connections, core.dir_to_wallmounted(pos - front_pos)) - core.set_node(front_pos, { name = stube.join_tube_name(split) }) - end - end -end - -function stube.place_tube(name, pos, tube_dir, pointed_thing, sneaking) - stube.connect_tubes_to(pos, tube_dir, pointed_thing, sneaking) - - local connections = { - -- X, Y, Z - 0, - 0, - 0, - -- -X, -Y, -Z - 0, - 0, - 0, - } - - for neighbor_dir_number = 0, 5 do - local neighbor_dir = core.wallmounted_to_dir(neighbor_dir_number) - local neighbor_pos = vector.add(pos, neighbor_dir) - local neighbor_node = stube.get_or_load_node(neighbor_pos) - - if core.get_item_group(neighbor_node.name, 'stube') == 1 then - local tube_params = stube.get_tube_name_info(neighbor_node.name) - if vector.equals(vector.add(core.wallmounted_to_dir(tube_params[1]), neighbor_pos), pos) then -- If the tube is pointing to ours - make_connection(connections, neighbor_dir_number) - end - end - end - - --- Automatically connect any tubedevices or routing blocks - if not sneaking then - for i = 0, 5 do - local neighbor_dir = core.wallmounted_to_dir(i) - local neighbor_pos = vector.add(pos, neighbor_dir) - local neighbor_node = stube.get_or_load_node(neighbor_pos) - - local should_connect = false - if stube.is_tubedevice(neighbor_node.name) == true then - local connect_sides = core.registered_nodes[neighbor_node.name].tube.connect_sides - if connect_sides then - should_connect = stube.process_pipeworks_connect_sides(connect_sides, -neighbor_dir, neighbor_node) - else - should_connect = true - end - elseif core.get_item_group(neighbor_node.name, 'stube_routing_node') == 1 then - should_connect = true - end - if should_connect then make_connection(connections, i) end - end - else -- Only connect the tubedevice we are sneaking at - local under_node = stube.get_or_load_node(pointed_thing.under) - local under_dir = vector.subtract(pointed_thing.above, pointed_thing.under) - - local should_connect = false - if stube.is_tubedevice(under_node.name) == true then - local connect_sides = core.registered_nodes[under_node.name].tube.connect_sides - if connect_sides then - should_connect = stube.process_pipeworks_connect_sides(connect_sides, under_dir, under_node) - else - should_connect = true - end - elseif core.get_item_group(under_node.name, 'stube_routing_node') == 1 then - should_connect = true - end - - if should_connect then - make_connection( - connections, - core.dir_to_wallmounted(vector.subtract(pointed_thing.under, pointed_thing.above)) - ) - end - end - - local no_connections = true - local amount_of_connections = 0 - for i = 1, 6 do - if connections[i] == 1 then - no_connections = false - amount_of_connections = amount_of_connections + 1 - end - end - - -- the square/no connections tube - if no_connections then tube_dir = 0 end - - -- if a tube is not straight, make a connection - -- Basically, makes short tubes whenever possible - -- and maintain a connection to things which interact with tubes, that is important - - local tube_pointing_to = vector.add(pos, core.wallmounted_to_dir(tube_dir)) - local tube_pointing_to_node = stube.get_or_load_node(tube_pointing_to) - - local straight_tube_index = (stube.wallmounted_to_connections_index[tube_dir] + 3) % 6 - if straight_tube_index == 0 then straight_tube_index = 6 end - if - not ( - ((amount_of_connections == 1 and connections[straight_tube_index] == 1) or amount_of_connections == 0) -- if the tube is straight or a box - and stube.is_tubedevice(tube_pointing_to_node.name) == false - ) - then - make_connection(connections, tube_dir) - end - - -- if there is a tube in the front of us, point to it - -- This makes connecting tubes with multiple inputs possible, after they have already been placed, but sometimes you may not want this behavior - - if not sneaking then - local vdir = core.wallmounted_to_dir(tube_dir) - local front_pos = pos + vdir - local front_node = stube.get_or_load_node(front_pos) - if core.get_item_group(front_node.name, 'stube') == 1 then make_connection(connections, tube_dir) end - end - - core.set_node(pos, { name = stube.get_prefix_tube_name(name) .. '_' .. tube_dir .. table.concat(connections) }) -end - --- When an stube is broken, or something near it was, this should get called --- It cleans up garbage connections (e.g. connection to nowhere, that isn't needed) -function stube.update_placement(pos) - -- All the cases of garbage connections: - -- - When a connection is pointing to air/incompatible node - -- - When a connection is pointing to a tube, which is not connected to it -> weird visual - -- - When a tube could be a short tube instead - - -- So, this function will iterate over the neighboring tubes of this position - pos = vector.copy(pos) -- ensure pos is a vector - stube.update_placement_single(pos) - for i = 0, 5 do - stube.update_placement_single(pos + core.wallmounted_to_dir(i)) - end -end - ----@see stube.update -function stube.update_placement_single(pos) - local node = stube.get_or_load_node(pos) - if core.get_item_group(node.name, 'stube') ~= 1 then return end - - local split = stube.split_tube_name(node.name) - - for i = 1, 6 do - local connection = split.connections[i] - local connection_dir = connections_to_wallmounted[i] - local connection_dirv = core.wallmounted_to_dir(connection_dir) - local connection_pos = pos + connection_dirv - - local connection_node = stube.get_or_load_node(connection_pos) - - local ig = core.get_item_group - - if connection == 1 then - -- first case: pointing to air/incompatible node - if - not ( - ig(connection_node.name, 'stube') == 1 - or stube.is_tubedevice(connection_node.name) == true - or ig(connection_node.name, 'stube_routing_node') == 1 - ) - then - split.connections[i] = 0 - end - - -- second case: connection is pointing to a tube that is not connected to it (=> a weird/out of place connection) - if ig(connection_node.name, 'stube') == 1 then - local other_tube_split = stube.split_tube_name(connection_node.name) - - local other_connection_index = (i + 3) % 6 - if other_connection_index == 0 then other_connection_index = 6 end - if other_tube_split.connections[other_connection_index] == 0 then split.connections[i] = 0 end - - -- another case: The tube wants nothing to do with us (manifests as arrows pointing away from eachother), should disconnect - -- so all connected tubes should point to us, if not disconnect - if - connection_dir ~= split.dir - and not vector.equals((core.wallmounted_to_dir(other_tube_split.dir) + connection_pos), pos) - then - split.connections[i] = 0 - end - end - end - end - - local amount_of_connections = 0 - for i = 1, 6 do - if split.connections[i] == 1 then amount_of_connections = amount_of_connections + 1 end - end - - local straight_tube_index = (stube.wallmounted_to_connections_index[split.dir] + 3) % 6 -- the index opposite to the dir, if that makes sense - if straight_tube_index == 0 then straight_tube_index = 6 end - - -- case 2.5: "We could totally be connected to that tubedevice/routing block right now actually, we don't need to be a short tube" - if amount_of_connections == 1 and split.connections[straight_tube_index] == 1 then - local dir = core.wallmounted_to_dir(split.dir) - local next_pos = pos + dir - local next_node = stube.get_or_load_node(next_pos) - if stube.is_tubedevice(next_node.name) then - local connect_sides = core.registered_nodes[next_node.name].tube.connect_sides - local should_connect = true - if connect_sides then - should_connect = stube.process_pipeworks_connect_sides( - core.registered_nodes[next_node.name].tube.connect_sides, - dir, - next_node - ) - end - if should_connect then make_connection(split.connections, split.dir) end - elseif core.get_item_group(next_node.name, 'stube_routing_node') == 1 then - make_connection(split.connections, split.dir) - end - end - - -- third case: it could be a short tube instead, if not, check if there is a tube in our direction, and check if it is properly connected - if - not ((amount_of_connections == 1 and split.connections[straight_tube_index] == 1) or amount_of_connections == 0) - then -- not a short tube - make_connection(split.connections, split.dir) - - local next_pos = pos + core.wallmounted_to_dir(split.dir) - local next_node = stube.get_or_load_node(next_pos) - -- also make sure the neighboring tube is properly connected, this must not occur with short tubes - if core.get_item_group(next_node.name, 'stube') == 1 then - local next_tube_split = stube.split_tube_name(next_node.name) - make_connection(next_tube_split.connections, core.dir_to_wallmounted(pos - next_pos)) - - -- small complication: if next_node is a short tube, this could make an invalid tube, crashing the game.. ugh - -- if short tubes were just not a thing, this mod's source code would be substantially smaller - -- but the alternative is really ugly (as in, in-game looks, not source code) soo gotta deal with it - - local set_to = stube.join_tube_name(next_tube_split) - if not core.registered_nodes[set_to] then -- okay this is the extremely lazy way, how did i not think of this earlier - make_connection(next_tube_split.connections, next_tube_split.dir) - set_to = stube.join_tube_name(next_tube_split) - end - - core.set_node(next_pos, { name = set_to }) - end - end - - if amount_of_connections == 0 then split.dir = 0 end - - core.set_node(pos, { name = stube.join_tube_name(split) }) -end - -function stube.tube_after_place(pos, placer, stack, pointed) - if not placer then return end - if not placer:is_valid() then return end - if pointed.type ~= 'node' then return end - - local face = vector.subtract(pointed.above, pointed.under) - local dir = core.dir_to_wallmounted(face) - - local sneaking = placer:get_player_control().sneak - stube.place_tube(stack:get_name(), pos, dir, pointed, sneaking) - stube.update_placement(pos) -end - --- Change the direction to the one we are pointing to --- Needs sneak+punch -function stube.default_tube_punch(pos, node, puncher, pointed_thing) - if core.is_protected(pos, puncher) then - core.record_protection_violation(pos, puncher) - return - end - if puncher and puncher:get_player_control().sneak then - local split = stube.split_tube_name(node.name) - split.dir = core.dir_to_wallmounted(pointed_thing.above - pointed_thing.under) - split.connections[stube.wallmounted_to_connections_index[split.dir]] = 1 - core.set_node(pos, { name = stube.join_tube_name(split) }) - end - stube.update_placement(pos) -end - -if core.global_exists 'pipeworks' then -- hijack pipeworks for our benefit nyehehe - local old_scan_for_tube_objects = pipeworks.scan_for_tube_objects -- this runs when ANY PIPEWORKS TUBE OR TUBEDEVICE GETS PLACED, really convenient - - ---@diagnostic disable-next-line: duplicate-set-field - function pipeworks.scan_for_tube_objects(pos) - stube.update_placement(pos) - return old_scan_for_tube_objects(pos) - end -end diff --git a/mods/stubes/register.lua b/mods/stubes/register.lua deleted file mode 100644 index c21b52ca..00000000 --- a/mods/stubes/register.lua +++ /dev/null @@ -1,312 +0,0 @@ ---- Tube capacity is always +1 ----@class stube.TubeDef ----@field textures table ----@field speed number The amount of time between updates, lower is faster ----@field should_update fun(tube_hpos:integer, tube_state:stube.TubeState, node:core.Node.Get):boolean ----@field get_next_pos_and_node fun(tube_hpos:integer, tube_state:stube.TubeState, dir:integer):vector, core.Node.get - ----@type {[string]: stube.TubeDef } -stube.registered_tubes = {} - -local function tube_nodebox(len, stretch_to) - local full = 0.5 - local base_box = { -len, -len, -len, len, len, len } - if stretch_to == 'top' then - base_box[5] = full - elseif stretch_to == 'bottom' then - base_box[2] = -full - elseif stretch_to == 'front' then - base_box[3] = -full - elseif stretch_to == 'back' then - base_box[6] = full - elseif stretch_to == 'right' then - base_box[4] = full - elseif stretch_to == 'left' then - base_box[1] = -full - end - return base_box -end - ---- e* -> expected ---- so edir = expected dir -local function short_check(dir, xc, yc, zc, nxc, nyc, nzc, edir, exc, eyc, ezc, enxc, enyc, enzc) - return dir == edir and xc == exc and yc == eyc and zc == ezc and nxc == enxc and nyc == enyc and nzc == enzc -end - -local function change_tile_dir(arranged_connections, tiles, tube_textures, id, transform) - if arranged_connections[id] == 1 then - tiles[id] = tube_textures.noctr_up .. transform - else - tiles[id] = tube_textures.plain_up .. transform - end -end - -local function register_single_tube(name, def, tubedef, dir, xc, yc, zc, nxc, nyc, nzc) - local is_short = false -- Shorts are tubes that lead to nowhere, so they are the "endings" - local visible = false -- If it's visible in the inventory, the _000000 tube - if - dir == 0 and yc ~= 1 - or dir == 1 and nyc ~= 1 - or dir == 2 and xc ~= 1 - or dir == 3 and nxc ~= 1 - or dir == 4 and zc ~= 1 - or dir == 5 and nzc ~= 1 - then - -- i am horrible at working with large amounts of variables xD - -- good luck understanding this hehe - if - short_check(dir, xc, yc, zc, nxc, nyc, nzc, 0, 0, 0, 0, 0, 1, 0) - or short_check(dir, xc, yc, zc, nxc, nyc, nzc, 1, 0, 1, 0, 0, 0, 0) - or short_check(dir, xc, yc, zc, nxc, nyc, nzc, 2, 0, 0, 0, 1, 0, 0) - or short_check(dir, xc, yc, zc, nxc, nyc, nzc, 3, 1, 0, 0, 0, 0, 0) - or short_check(dir, xc, yc, zc, nxc, nyc, nzc, 4, 0, 0, 0, 0, 0, 1) - or short_check(dir, xc, yc, zc, nxc, nyc, nzc, 5, 0, 0, 1, 0, 0, 0) - then - is_short = true - elseif short_check(dir, xc, yc, zc, nxc, nyc, nzc, 0, 0, 0, 0, 0, 0, 0) then - visible = true - else - return -- invalid tubes, so only 224 nodes should get registered thanks to this - end - end - - name = name .. '_' .. dir .. xc .. yc .. zc .. nxc .. nyc .. nzc - if visible == false then - def.description = def.description - .. table.concat { ', state: ', '\n' } - .. table.concat { 'short: ', tostring(is_short), '\n' } - .. table.concat { 'dir: ', dir, '\n' } - .. table.concat { 'xc: ', xc, '\n' } - .. table.concat { 'yc: ', yc, '\n' } - .. table.concat { 'zc: ', zc, '\n' } - .. table.concat { 'nxc: ', nxc, '\n' } - .. table.concat { 'nyc: ', nyc, '\n' } - .. table.concat { 'nzc: ', nzc, '\n' } - end - - local nodebox = { type = 'fixed', fixed = {} } - local fixed = nodebox.fixed - - if yc == 1 then table.insert(fixed, tube_nodebox(stube.tube_size, 'top')) end - if nyc == 1 then table.insert(fixed, tube_nodebox(stube.tube_size, 'bottom')) end - - if xc == 1 then table.insert(fixed, tube_nodebox(stube.tube_size, 'right')) end - if nxc == 1 then table.insert(fixed, tube_nodebox(stube.tube_size, 'left')) end - - if zc == 1 then table.insert(fixed, tube_nodebox(stube.tube_size, 'back')) end - if nzc == 1 then table.insert(fixed, tube_nodebox(stube.tube_size, 'front')) end - if visible then - table.insert( - fixed, - { -stube.tube_size, -stube.tube_size, -stube.tube_size, stube.tube_size, stube.tube_size, stube.tube_size } - ) - end - def.node_box = nodebox - - -- okay...... now the textures - -- Each side that is connected to, will have the texture be `noctr` - -- Each side that isn't connected to, will have the texture be `plain` - -- On *short* tubes, the ending texture will be `ends` - - -- These connections are arranged in {+Y, -Y, +X, -X, +Z, -Z} - the same order that tiles are - -- This makes some seemingly complicated things trivial - local arranged_connections = { yc, nyc, xc, nxc, zc, nzc } - - def.tiles = {} - for i = 1, 6 do - if arranged_connections[i] == 1 then -- if its a connection, use noctr, if we didn't there would be an annoying glitchy effect - def.tiles[i] = tubedef.textures.noctr - else - def.tiles[i] = tubedef.textures.plain - end - end - - if is_short then - -- wallmounted dir -> tile conversion - def.tiles[dir + 1] = tubedef.textures.ends - else - -- Need to correctly apply the direction - -- Short tubes have it always be correct, so no need to change anything there - -- All we have to do is change one arrow basically - -- I don't know if there is a better way to do this than these if statements, possibly/ - -- - -- If you are asking how i figured out all of this, it's called "brute forcing" (at least it felt like it, but was fun?) - if dir == 0 then - change_tile_dir(arranged_connections, def.tiles, tubedef.textures, 3, '') - change_tile_dir(arranged_connections, def.tiles, tubedef.textures, 4, '') - change_tile_dir(arranged_connections, def.tiles, tubedef.textures, 5, '') - change_tile_dir(arranged_connections, def.tiles, tubedef.textures, 6, '') - elseif dir == 1 then - change_tile_dir(arranged_connections, def.tiles, tubedef.textures, 3, '^[transformFY') - change_tile_dir(arranged_connections, def.tiles, tubedef.textures, 4, '^[transformFY') - change_tile_dir(arranged_connections, def.tiles, tubedef.textures, 5, '^[transformFY') - change_tile_dir(arranged_connections, def.tiles, tubedef.textures, 6, '^[transformFY') - elseif dir == 2 then - change_tile_dir(arranged_connections, def.tiles, tubedef.textures, 1, '^[transformR270') - change_tile_dir(arranged_connections, def.tiles, tubedef.textures, 2, '^[transformR270') - change_tile_dir(arranged_connections, def.tiles, tubedef.textures, 5, '^[transformR90') - change_tile_dir(arranged_connections, def.tiles, tubedef.textures, 6, '^[transformR270') - elseif dir == 3 then - change_tile_dir(arranged_connections, def.tiles, tubedef.textures, 1, '^[transformR90') - change_tile_dir(arranged_connections, def.tiles, tubedef.textures, 2, '^[transformR90') - change_tile_dir(arranged_connections, def.tiles, tubedef.textures, 5, '^[transformR270') - change_tile_dir(arranged_connections, def.tiles, tubedef.textures, 6, '^[transformR90') - elseif dir == 4 then - change_tile_dir(arranged_connections, def.tiles, tubedef.textures, 1, '') - change_tile_dir(arranged_connections, def.tiles, tubedef.textures, 2, '^[transformFY') - change_tile_dir(arranged_connections, def.tiles, tubedef.textures, 3, '^[transformR270') - change_tile_dir(arranged_connections, def.tiles, tubedef.textures, 4, '^[transformR90') - elseif dir == 5 then - change_tile_dir(arranged_connections, def.tiles, tubedef.textures, 1, '^[transformFY') - change_tile_dir(arranged_connections, def.tiles, tubedef.textures, 2, '') - change_tile_dir(arranged_connections, def.tiles, tubedef.textures, 3, '^[transformR90') - change_tile_dir(arranged_connections, def.tiles, tubedef.textures, 4, '^[transformR270') - end - end - - if not stube.debug and not def.groups.not_in_creative_inventory then - def.groups.not_in_creative_inventory = visible and 0 or 1 - end - if visible then def.after_place_node = stube.tube_after_place end - - core.register_node(name, def) -end - ----@param name string ----@param def table ----@param tubedef stube.TubeDef -function stube.register_tube(name, def, tubedef) - stube.registered_tubes[name] = tubedef - def.groups = def.groups or {} - def.groups.stube = 1 - - -- pipeworks -> stube compatibility - def.groups.tubedevice = 1 - def.groups.tubedevice_receiver = 1 - def.tube = { - insert_object = stube.tube_input_insert_object, - --can_insert = stube.tube_input_can_insert, NYI: TODO:? maybe? i mean who will use this with pipeworks tubes wtf - } - - -- Alias - core.register_alias(name, name .. '_0000000') - def.drop = name - - -- i saw what pipeworks was doing, so i think i am going with whatever this "old aproach" is https://github.com/mt-mods/pipeworks/blob/6e11868d1b32d316d60061c78460d260ac92ed6a/tubes/registration.lua#L176 - -- because it mentioned something about "the textures must be rotated" with the "new aproach", and uh i think that will complicate things, and i don't want to deal with rotating them. - -- - -- also tubes are *directional*... so it won't just be 64 tubes - -- so, 384 tubes at maximum, of which some are invalid - -- I calculated there to be about 160 tubes which are invalid, so i will have to register about 224 nodes - - -- naming scheme: - -- c - if that direction is connected - -- nc - if that "negative" direction is connected (e.g. Z+ is north, Z- is south, so nzc would be if its connected from the south) - -- example: - -- 1. assume tube in the shape of "|", and that the direction that "^" is pointing in, is the y axis - -- then yc=1, nyc=1, all else is zero - -- 2. assume tube in the shape of "+", and the direction that ">" is pointing in, is the x axis - -- then yc=1, nyc=1, xc=1, nxc = 1, all else is zero - -- Does this make sense? - -- And also `direction` is just a wallmounted param2 - -- - for direction = 0, 5 do - for xc = 0, 1 do - for yc = 0, 1 do - for zc = 0, 1 do - for nxc = 0, 1 do - for nyc = 0, 1 do - for nzc = 0, 1 do - register_single_tube( - name, - table.copy(def), - tubedef, - direction, - xc, - yc, - zc, - nxc, - nyc, - nzc - ) - end - end - end - end - end - end - end -end - ---- Assumes one tube texture is 64x32 --- See textures/ directory for how this is done, alternatively you can do this manually and split into 4 files (bad, horrible, ew) -function stube.make_tube_textures_from(filename) - return { - plain = filename .. '^[sheet:3x2:0,0', - noctr = filename .. '^[sheet:3x2:1,0', - ends = filename .. '^[sheet:3x2:2,0', - plain_up = filename .. '^[sheet:3x2:0,1', - noctr_up = filename .. '^[sheet:3x2:1,1', - } -end - --- name = name .. '_' .. dir .. xc .. yc .. zc .. nxc .. nyc .. nzc --- so last 7 characters -function stube.get_tube_name_info(name) - local ret = {} - local start = #name - 7 - for i = 1, 7 do - ret[i] = tonumber(string.sub(name, start + i, start + i)) - end - return ret -end - -local is_short_tube_memo = {} - -function stube.is_short_tube(name) - if is_short_tube_memo[name] ~= nil then return is_short_tube_memo[name] end - - local info = stube.get_tube_name_info(name) - local amount_of_connections = 0 - for i = 2, 7 do -- info[1] is direction - if info[i] == 1 then amount_of_connections = amount_of_connections + 1 end - end - - local straight_tube_index = (stube.wallmounted_to_connections_index[info[1]] + 3) % 6 -- the index opposite to the dir, if that makes sense - if straight_tube_index == 0 then straight_tube_index = 6 end - - is_short_tube_memo[name] = amount_of_connections == 1 and info[1 + straight_tube_index] == 1 - return is_short_tube_memo[name] -end - -function stube.get_prefix_tube_name(name) - return name:sub(1, -9) -end - -function stube.get_tube_dir(name) - return assert(tonumber(name:sub(-7, -7)), '!? report this as a bug') -end - -function stube.split_tube_name(name) - local ret = {} - - ret.prefix = stube.get_prefix_tube_name(name) - ret.connections = stube.get_tube_name_info(name) - ret.dir = table.remove(ret.connections, 1) - - return ret -end - -function stube.join_tube_name(split) - return split.prefix .. '_' .. split.dir .. table.concat(split.connections, '') -end - -function stube.default_should_update_tube(tube_hpos, tube_state, node) - -- Don't update if its a short tube - return not stube.is_short_tube(node.name) -end -function stube.default_get_next_pos_and_node(tube_hpos, tube_state, tube_dir) - local cdir = core.wallmounted_to_dir(tube_dir) - local pos = core.get_position_from_hash(tube_hpos) + cdir - return pos, stube.get_or_load_node(pos) -end diff --git a/mods/stubes/register_routing_blocks.lua b/mods/stubes/register_routing_blocks.lua deleted file mode 100644 index 80f32392..00000000 --- a/mods/stubes/register_routing_blocks.lua +++ /dev/null @@ -1,153 +0,0 @@ --- Group: `stube_routing_node`=1 --- Transport is handled in stube_transport.lua --- Routing blocks also keep their entities, they can be transparent - ---- You must not add any new non-optional parameters ---- i mean thats not part of the license, its just, i'd rather you not, or it will be a real pain in the butt to update? ----@class stube.RoutingState: table ----@field items table Routing nodes can store tubes hovewer they like ----@field updated_at number Not really used, as routing blocks can't update outside of their trigger ----@field to_remove? boolean - ----@class stube.RoutingNodeDef ----@field update fun(state:stube.RoutingState, hpos: number):nil ----@field accept fun(state:stube.RoutingState, tubed_item:stube.TubedItem, dir: integer, pos: vector):boolean ----@field iterate_items fun(state:stube.RoutingState, f:fun(item:stube.TubedItem, dir:vector?):nil) Used when deleting all items or something ----@field speed number Delay between updates, but routing nodes always update after tubes - ----@type { [string]: stube.RoutingNodeDef } -stube.registered_routing_node = {} - ----@type table> -stube.routing_states = {} - ----FIXME: Also remove routing states if they are empty, thats important yknwoww ---- FIXME: add pipeworks tubedevice support ----@param routing_def stube.RoutingNodeDef ----@param def core.NodeDef -function stube.register_routing_node(name, def, routing_def) - stube.registered_routing_node[name] = routing_def - core.register_node(name, def) -end - --- UTILS - -local IG = core.get_item_group - ----@param dir integer -local function move_entity(ent, pos, dir) - ent:move_to(stube.get_precise_connection_pos(pos, dir), true) -end - -local function move_connection(tube_state, dir1, dir2, pos) - if dir1 ~= dir2 then -- if it is equal, you are just moving the entity - assert( - not tube_state.connections[dir2], - '[stubes]Tried overriding with `local function move_connection(...)` in stubes/transport.lua, report this is a bug' - ) - tube_state.connections[dir2] = tube_state.connections[dir1] - tube_state.connections[dir1] = nil - end - - local ent = tube_state.connections[dir2].entity - if ent then move_entity(ent, pos, dir2) end -end - ---- If you have some sort of special tubed item, you can modify it after the fact ---- This does NOT handle actually removing the tubed item ---- The only thing it handles: It puts the tubed item in a node/routing node/tube ---- Inserting from pipeworks is handled with pipeworks's insert_object, don't worry about that ---- ---- So, when making a roouting device, you only have to worry about internal transport hopefully ----@return boolean success -function stube.insert_tubed_item(tubed_item, out_node, out_pos, dir) - local out_poshash = core.hash_node_position(out_pos) - local opposite_dir = stube.opposite_wallmounted(dir) - - if IG(out_node.name, 'stube') == 1 then - local prefix = stube.get_prefix_tube_name(out_node.name) - local tube_states_of_prefix = stube.all_stubes[prefix] - local tube_state = tube_states_of_prefix[out_poshash] - if not tube_state then - tube_states_of_prefix[out_poshash] = { - connections = {}, - updated_at = stube.current_update_time, - } - tube_state = tube_states_of_prefix[out_poshash] - end - - if tube_state.connections[opposite_dir] then return false end - tube_state.connections[opposite_dir] = tubed_item - move_connection(tube_state, opposite_dir, opposite_dir, out_pos) - return true - elseif IG(out_node.name, 'stube_routing_node') == 1 then - local routing_state = stube.routing_states[out_node.name][out_poshash] - if not routing_state then - stube.routing_states[out_node.name][out_poshash] = { - items = {}, - updated_at = stube.current_update_time, - } - routing_state = stube.routing_states[out_node.name][out_poshash] - end - - local def = stube.registered_routing_node[out_node.name] - local success = def.accept(routing_state, tubed_item, opposite_dir) - return success - elseif IG(out_node.name, 'tubedevice_receiver') == 1 then - --- FIXME: - end - return false -end - ---- bad = its empty or state.to_remove == true or type~=node.name -function stube.remove_bad_routing_states(type, state, hpos, node) - local empty = true - local def = stube.registered_routing_node[type] - local pos = core.get_position_from_hash(hpos) - - def.iterate_items(state, function() - empty = false - end) - - if empty then state.to_remove = true end - if node.name ~= type then state.to_remove = true end - if state.to_remove then - stube.routing_states[type][hpos] = nil - def.iterate_items(state, function(item, dir) - local item_pos = pos - if dir then item_pos = stube.get_precise_connection_pos(pos, dir) end - core.add_item(item_pos, item.stack) - end) - end -end - -local timers = {} -core.register_on_mods_loaded(function() - for name, def in pairs(stube.registered_routing_node) do - timers[name] = { current = 0, max = def.speed } - stube.routing_states[name] = {} - end -end) - -local function process_routing_type(type) - for hpos, state in pairs(stube.routing_states[type]) do - local node = stube.get_or_load_node(core.get_position_from_hash(hpos)) - if node.name ~= type then - state.to_remove = true - else - stube.registered_routing_node[node.name].update(state, hpos) - end - stube.remove_bad_routing_states(type, state, hpos, node) - end -end - ---- Called by stube.globalstep -function stube.routing_globalstep(dtime) - for name, timer in pairs(timers) do - timer.current = timer.current + dtime - if timer.current >= timer.max then - process_routing_type(name) - timer.current = 0 - end - end -end diff --git a/mods/stubes/stube_transport.lua b/mods/stubes/stube_transport.lua deleted file mode 100644 index aac1aa0a..00000000 --- a/mods/stubes/stube_transport.lua +++ /dev/null @@ -1,321 +0,0 @@ --- Items are transferred 1 item/update - -local h, uh = core.hash_node_position, core.get_position_from_hash - ----@class stube.TubedItem:table ----@field stack core.ItemStack ----@field owner? string ----@field entity? core.Entity - ---- The state of any active tube ---- The node underneeth a tube state can be anything, and it can change at any time ---- Therefore it is wise not to store things like direction ----@class stube.TubeState ----@field connections table items[wallmounted_dir]=item, items[6] = item at the center ----@field updated_at integer ----@field to_remove? boolean - ----@type table> -local stubes = {} -- A table of all the tubed items, t[tube_name][h(tube_pos)] = TubeState -stube.all_stubes = stubes -stube.current_update_time = 0 -- used in tubed items - -local timers = {} -core.register_on_mods_loaded(function() - for name, def in pairs(stube.registered_tubes) do - timers[name] = { current = 0, max = def.speed } - stubes[name] = {} - end -end) - ----@param wallmounted integer -function stube.opposite_wallmounted(wallmounted) - return core.dir_to_wallmounted(-core.wallmounted_to_dir(wallmounted)) -end - ----@return ivec -function stube.tube_state_connection_to_dir(connection) - if connection == 6 then - return vector.zero() -- The center - end - return core.wallmounted_to_dir(connection) -end - -function stube.get_precise_connection_pos(pos, connection) - return vector.add(pos, stube.tube_state_connection_to_dir(connection) / 3) -end - ----@param dir number|nil -local function move_entity(ent, pos, dir) - ent:move_to(stube.get_precise_connection_pos(pos, dir), true) -end - -local function move_connection(tube_state, dir1, dir2, pos) - if dir1 ~= dir2 then -- if it is equal, you are just moving the entity - assert( - not tube_state.connections[dir2], - '[stubes]Tried overriding with `local function move_connection(...)` in stubes/transport.lua, report this is a bug' - ) - tube_state.connections[dir2] = tube_state.connections[dir1] - tube_state.connections[dir1] = nil - end - - local ent = tube_state.connections[dir2].entity - if ent then move_entity(ent, pos, dir2) end -end - -local function delete_connection(tube_state, dir) - local ent = tube_state.connections[dir].entity - tube_state.connections[dir] = nil - if ent then ent:remove() end -end - -local IG = core.get_item_group - ---- Transfer items to foreign nodes (pipeworks receivers) -function stube.transfer_items(tube_state, transfer_to_node, transfer_to_pos, tube_dir) - local next_node_def = core.registered_nodes[transfer_to_node.name] - if not (next_node_def.tube and next_node_def.tube.insert_object) then return false end - - local connection = tube_state.connections[tube_dir] - if not connection then return end - - local vel = table.copy(core.wallmounted_to_dir(tube_dir)) - vel.speed = 1 - - connection.stack = next_node_def.tube.insert_object( - transfer_to_pos, - transfer_to_node, - connection.stack, - vel, - connection.owner or '' - ) - if connection.stack == nil or connection.stack:is_empty() then delete_connection(tube_state, tube_dir) end -end - --- Every item gets pushed to the center (in a set order, even if random would make more sense), center gets pushed to tube dir, tube dir item get transported ----@param tube_state stube.TubeState -local function inter_tube_transport(tube_state, tube_dir, tube_vpos, is_short, already_transported_to_center) - local connections = tube_state.connections - if connections[6] == nil then - for i = 0, 5 do - if i ~= tube_dir and connections[i] ~= nil then -- one non-empty item from all directions except tube dir gets put into the center - move_connection(tube_state, i, 6, tube_vpos) - break - end - end - elseif connections[tube_dir] == nil and connections[6] ~= nil and not already_transported_to_center then -- if center is empty, the item from the center will come to replace it.. - -- actually don't do this if it is a short tube - if is_short then return end - - move_connection(tube_state, 6, tube_dir, tube_vpos) - inter_tube_transport(tube_state, tube_dir, tube_vpos, is_short, true) -- May look worrysome to some, but makes sense if you think about it - end - - -- FIXME: Drop items which are in impossible places - -- Do that after verifying they can't get there naturally -end - ---- 1 item/update ----@param tube_state stube.TubeState -local function push_items_to_next_tube(next_node, next_pos, tube_state, tube_dir, tube_vpos) - local prefix = stube.get_prefix_tube_name(next_node.name) - local next_tube_def = stube.registered_tubes[prefix] - local next_tube_hpos = core.hash_node_position(next_pos) - local next_tube_state = stubes[prefix][next_tube_hpos] - local is_empty = next_tube_state == nil - local can_insert = true - local next_tube_dir = stube.get_tube_dir(next_node.name) - local opposite_tube_dir = stube.opposite_wallmounted(tube_dir) - - if is_empty == false then - can_insert = next_tube_state.connections[opposite_tube_dir] == nil -- If there isn't an item in the way - end - can_insert = can_insert and next_tube_dir ~= opposite_tube_dir -- And the tube must not be pointing away from us - - if is_empty then - stubes[prefix][next_tube_hpos] = { - connections = {}, - updated_at = stube.current_update_time, - } - next_tube_state = stubes[prefix][next_tube_hpos] - end - - if can_insert then - local item = tube_state.connections[tube_dir] - if not item then return true, next_tube_hpos, next_tube_def, stubes[prefix], prefix end -- There is nothing to push, so don't bother with updating next tubes - - next_tube_state.connections[opposite_tube_dir] = item - tube_state.connections[tube_dir] = nil - - move_connection(next_tube_state, opposite_tube_dir, opposite_tube_dir, next_pos) -- just update entity - - return true, next_tube_hpos, next_tube_def, stubes[prefix], prefix - else - return false, next_tube_hpos, next_tube_def, stubes[prefix], prefix - end -end - ----@param tube_state stube.TubeState -function stube.delete_tube_state(tube_state, tubes_array, tube_hpos) - local tube_vpos = uh(tube_hpos) - for dir, connection in pairs(tube_state.connections) do - if connection.entity then connection.entity:remove() end - local pos = stube.get_precise_connection_pos(tube_vpos, dir) - core.add_item(pos, connection.stack) - end - tubes_array[tube_hpos] = nil -end - ----@param tube_state stube.TubeState -local function delete_if_empty_state(tube_hpos, tube_state, tubes_array) - local empty = true - for i = 0, 6 do - if tube_state.connections[i] ~= nil then - empty = false - break - end - end - if empty then tube_state.to_remove = true end - - if tube_state.to_remove then stube.delete_tube_state(tube_state, tubes_array, tube_hpos) end -end - ---- This is a very recursive function ----@param tube_state stube.TubeState ----@param tube_def stube.TubeDef ----@param tube_hpos integer ----@param prefix string -function stube.update_tube(tube_hpos, tube_def, tube_state, prefix) - if tube_state.updated_at == stube.current_update_time then return end - tube_state.updated_at = stube.current_update_time - - local tube_vpos = uh(tube_hpos) - - local this_node = stube.get_or_load_node(tube_vpos) - if stube.get_prefix_tube_name(this_node.name) ~= prefix then - tube_state.to_remove = true - return - end - - if - not tube_def.should_update( - tube_hpos, - tube_state, - stube.get_or_load_node(core.get_position_from_hash(tube_hpos)) - ) - then - return - end -- In cases like short tubes you don't want to update the tube, as there is nowhere that items can go, there basically wouldn't be a next node - - local tube_dir = stube.get_tube_dir(this_node.name) - - if tube_state.connections[tube_dir] ~= nil then - local next_pos, next_node = tube_def.get_next_pos_and_node(tube_hpos, tube_state, tube_dir) - - if IG(next_node.name, 'stube') == 1 then -- Worst case: another tube, oh no xD - local success, next_tube_hpos, next_tube_def, next_tube_type_array, next_tube_prefix = - push_items_to_next_tube(next_node, next_pos, tube_state, tube_dir, tube_vpos) - if success == true then -- HACK: HACK: I don't know how this works but it does - -- So sometimes tubes were randomly going faster than they should??? and this fixed that? - next_tube_type_array[next_tube_hpos].updated_at = stube.current_update_time - end - - if success == false then - ---@diagnostic disable-next-line - stube.update_tube(next_tube_hpos, next_tube_def, next_tube_type_array[next_tube_hpos], next_tube_prefix) - push_items_to_next_tube(next_node, next_pos, tube_state, tube_dir, tube_vpos) - delete_if_empty_state(tube_hpos, tube_state, stubes[prefix]) - end - elseif IG(next_node.name, 'stube_routing_node') == 1 then - local def = stube.registered_routing_node[next_node.name] - local next_poshash = h(next_pos) - - local state = stube.routing_states[next_node.name][next_poshash] - if not state then - stube.routing_states[next_node.name][next_poshash] = { items = {}, updated_at = 0 } - state = stube.routing_states[next_node.name][next_poshash] - end - - local accepted = def.accept(state, tube_state.connections[tube_dir], tube_dir, next_pos) - if accepted then tube_state.connections[tube_dir] = nil end - elseif IG(next_node.name, 'tubedevice_receiver') == 1 then - stube.transfer_items(tube_state, next_node, next_pos, tube_dir) - end - end - inter_tube_transport(tube_state, tube_dir, tube_vpos, stube.is_short_tube(this_node.name)) -end - -function stube.process_tube_type(tube_name, tube_def) - local tubes = stubes[tube_name] - for tube_hpos, tube_state in pairs(tubes) do - stube.update_tube(tube_hpos, tube_def, tube_state, tube_name) - delete_if_empty_state(tube_hpos, tube_state, tubes) - end -end - ----@param dtime number ----@return nil -function stube.globalstep(dtime) - stube.current_update_time = stube.current_update_time + 1 - stube.routing_globalstep(dtime) - for name, timer in pairs(timers) do - timer.current = timer.current + dtime - if timer.current >= timer.max then - stube.process_tube_type(name, stube.registered_tubes[name]) - timer.current = 0 - end - end -end -core.register_globalstep(stube.globalstep) - ----@return boolean Success Returns false if it can't -function stube.add_tubed_item(pos, stack) - local hpos = core.hash_node_position(pos) - local node = stube.get_or_load_node(pos) - if core.get_item_group(node.name, 'stube') == 0 then return false end - - local prefix = stube.get_prefix_tube_name(node.name) - local tube_state = stubes[prefix][hpos] - if not tube_state then - stubes[prefix][hpos] = { - connections = {}, - updated_at = stube.current_update_time, - } - tube_state = stubes[prefix][hpos] - end - - local tube_dir = stube.get_tube_dir(node.name) - if tube_state.connections[tube_dir] == nil then - tube_state.connections[tube_dir] = { stack = stack } - stube.add_or_remove_tubestate_visuals(pos, tube_state) - return true - else - return false - end -end - -function stube.tube_input_insert_object(pos, node, stack, vel, owner) - local prefix = stube.get_prefix_tube_name(node.name) - local all_stubes_of_our_type = stubes[prefix] - local hpos = h(pos) - local tube_state = all_stubes_of_our_type[hpos] - if not tube_state then - all_stubes_of_our_type[hpos] = { - connections = {}, - updated_at = stube.current_update_time, - } - tube_state = all_stubes_of_our_type[hpos] - end - - local insert_dir = core.dir_to_wallmounted( - vector.rotate(pipeworks.facedir_to_right_dir(node.param2), vector.new(0, math.pi / 2, 0)) - ) - if tube_state.connections[insert_dir] == nil then - tube_state.connections[insert_dir] = { stack = stack, owner = owner } - stube.add_or_remove_tubestate_visuals(pos, tube_state) - return - else - return stack - end -end diff --git a/mods/stubes/textures/stube_basic_tube.png b/mods/stubes/textures/stube_basic_tube.png deleted file mode 100644 index 673af81b04d7b0818a7df4bc00a6e780ebb9dcd5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 517 zcmeAS@N?(olHy`uVBq!ia0vp^2|(yU#;t9s^A>-ml)PnQJ*+^^4Vbuy3L`bF}NsOC#29Y*1~_vfTM`>n9rr)ZMQ z`to-L$0fY4tlk{e0Cr98WJkUv#c6Z<1^OKMeyJoHN+_@~A4zDKacW!E@1LdGdh_KTJv-iiK76_K zvK4K?4lErT|Ap#`&psxRyl)@B`TC8r=B9drU;mZ;-a0S-Tw}WQ#{YsB!sC`N@LnDA zch~zP0*~~bA6sTW`~B)~4_DVuWe%!inO!}7nZJ-&ajL_quc9DM{C#PIBhEg7|4Z(e zzC9ei|DE;3Npr4!cK*7u<>-W#irQhw3Sy&wY$6)w|UjRe_g9FL}QqHPAsyty&Zp~lc y#v#zm2r*-!p*K%&WKzZ%A?M_25|cK}uosD)!#(3$;B;WTGI+ZBxvXPx$!AV3xRCt{2n?Y{FAP_~dln@o*A7lU+830BGfa!8%jXC)G{8+W& z)iN%508I3(@-u2_CdRg_4L`2)_xWwR%g@C*7eD@CnogIBtLIYq7WMn7Xo<6x(BQS| z`|pOou~xtL4=J5k%bd5htglTNrgv_BX6((}Olw)c_$GXRTsyBBx_eFfsY_L;KhQ_H z1pi52nJ|nt;aZ6Ox4%SHf+c-<0E`R(BLl$505F>ja6FtwvN+0uzDg5e{UigtD^4we zCH+lH(Au-`y|JLL(!^Tyt!AP$3PWKOhQcTeg;5v^qc9XkVJM95h`}ffg^>YZny-qW ztGML>wP5uuhNk)Z0d(}#{QZF3dQ0ej0E{+a7~Kzm>52OR{y99)C-igcEus4XFv^6L z35zJ`OqkZsg**U827r+PU}OLo6=uPxFbhV7SuiThf>B`>%r5}laoTJ=2(thH002ov JPDHLkV1jw%>>2<7 diff --git a/mods/stubes/textures/stube_junction.png b/mods/stubes/textures/stube_junction.png deleted file mode 100644 index 1f05ddd2714b11d150c15d8311b5e3afecf6d578..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 186 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`jKx9jP7LeL$-D$|N<3X0Lo9le z*KEo9ao&M3Au%B#!Q$U%qppPB9qi7hPs_3#)wx+JIYVRP+{VU40f_^L4lsO_H!8R{ z>(GNU6Pi}ulAgNz`{CdY#utr`&rCRU;KYd&9Xj9s1A(%pfTV;%otwCGc)PKHq-aZ3fBAwN}G3-%{4P#;yd@&<|QZC;uMu70<PZz2Ftvfke!&Cd0 zr|5?F+hfmcjM=heehj0k_?=Drd?nnN6HFL@#4efOWIj9ldugV7qpqd09&oV_eJuR- z{$z>j*xa7iRkii=_Pl%fQME;2|37b5ne)pR9x18xPG9>=ocY*6rRTmq|7}e@uPxgD ze*4|;@vHXPf{Zj_c;+t5r}*A|-OBGdxxbQ)=U(2k{^j@m{?DFGI~VnJZcE}D#;q5! zv>LB%XM#AwgduHXOu)-2PTIfJ9w+=gTI9HNa@N`xvwNDq<{mOQxqiV`!QZ-B@65He zLFUgvLOF*Fq!<=68m#try`Y(=y+G_mh|}sF_6*1VG8%kikl<~&$RP2Z{QyYB^M+@{ zq6O-SQTF0t3_WZIGC;%(?j}QVmSjDSV=)3fz7o&4ZDy^iU3|UvH!!vsJYD@<);T3K F0RW3O%AEiJ From 0519a47a2112b99d0614bdd6320c09e60ffc6811 Mon Sep 17 00:00:00 2001 From: TheEt1234 Date: Mon, 13 Oct 2025 20:04:51 +0200 Subject: [PATCH 17/28] Fix #191 --- mods/sbz_power/manual_crafter.lua | 37 ++++++++++++++++++++++++------- 1 file changed, 29 insertions(+), 8 deletions(-) diff --git a/mods/sbz_power/manual_crafter.lua b/mods/sbz_power/manual_crafter.lua index 5292bc6e..1152d41e 100644 --- a/mods/sbz_power/manual_crafter.lua +++ b/mods/sbz_power/manual_crafter.lua @@ -53,6 +53,7 @@ end -- aux1+punch -- craft 10 -- punch - craft 1 -- Do not use to implement some sort of autocrafter this may perform badly at scale +---@param user core.PlayerRef local function craft(user, meta) local control = user:get_player_control() local craft_amount = 1 @@ -112,12 +113,24 @@ local function craft(user, meta) local items_crafted = can_craft * craft_result:get_count() -- the amount of items that gets crafted can_craft = math.floor(math.min(max_space, items_crafted) / craft_result:get_count()) - -- okay.. so we just craft - for name, amount in pairs(required_items) do - user_inv:remove_item('main', name .. ' ' .. tonumber(amount * can_craft)) - end - if can_craft > 0 then + --- Prepare for crafting + for name, amount in pairs(required_items) do + local remove_amount = tonumber(amount * can_craft) + local max_stack = ItemStack(name):get_stack_max() + + local stacks = remove_amount / max_stack + local remaining = (stacks - math.floor(stacks)) * max_stack + stacks = math.floor(stacks) + + if stacks > 0 then + for _ = 1, stacks do + user_inv:remove_item('main', name .. ' ' .. max_stack) + end + end + if remaining > 0 then user_inv:remove_item('main', name .. ' ' .. remaining) end + end + items_crafted = can_craft * craft_result:get_count() local split_into = math.floor(items_crafted / craft_result_max) if split_into > 0 then @@ -196,9 +209,17 @@ core.register_node('sbz_power:manual_crafter', { local from_inv = core.get_meta(pos):get_inventory() from_inv:set_stack(listname, index, '') if listname == 'configure_craft_output' then - from_inv:set_list('configure_craft', { '', '', '', - '', '', '', - '', '', '' }) + from_inv:set_list('configure_craft', { + '', + '', + '', + '', + '', + '', + '', + '', + '', + }) else validate_craft(pos) end From 5446d33153c7f68cd850d05d3bc7da48f9ffdc17 Mon Sep 17 00:00:00 2001 From: TheEt1234 Date: Fri, 24 Oct 2025 22:07:33 +0200 Subject: [PATCH 18/28] Fix bizzare autocrafter bug --- mods/sbz_pipeworks/autocrafter.lua | 1 + mods/stubes | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/mods/sbz_pipeworks/autocrafter.lua b/mods/sbz_pipeworks/autocrafter.lua index 299d1894..0e52edc0 100644 --- a/mods/sbz_pipeworks/autocrafter.lua +++ b/mods/sbz_pipeworks/autocrafter.lua @@ -429,6 +429,7 @@ minetest.register_node('pipeworks:autocrafter', { if that_stack:get_name() == stackname or that_stack:get_name() == '' then leftover = math.max(0, new_count - stack_max) that_stack:set_count(new_count - leftover) + that_stack:set_name(stackname) srclist[i] = that_stack stack:set_count(leftover) stack:set_name(stackname) diff --git a/mods/stubes b/mods/stubes index 93240982..1d4c554b 160000 --- a/mods/stubes +++ b/mods/stubes @@ -1 +1 @@ -Subproject commit 932409829247f628ac5cb28771161527b87dcaf3 +Subproject commit 1d4c554b8a0e5fdf628acf84c6c0f028c6777210 From 661c1b318870a60a98876fbd05341c1e2655d43e Mon Sep 17 00:00:00 2001 From: TheEt1234 Date: Tue, 6 Jan 2026 21:06:34 +0100 Subject: [PATCH 19/28] Stashing for later i guess? --- mods/sbz_resources/strange_matter.lua | 138 ++++++++++++-------------- mods/stubes | 2 +- 2 files changed, 67 insertions(+), 73 deletions(-) diff --git a/mods/sbz_resources/strange_matter.lua b/mods/sbz_resources/strange_matter.lua index 56fc2c80..7fda5b8b 100644 --- a/mods/sbz_resources/strange_matter.lua +++ b/mods/sbz_resources/strange_matter.lua @@ -1,38 +1,38 @@ -minetest.register_craftitem("sbz_resources:strange_dust", { - description = "Strange Dust", - inventory_image = "strange_dust.png", +minetest.register_craftitem('sbz_resources:strange_dust', { + description = 'Strange Dust', + inventory_image = 'strange_dust.png', }) -minetest.register_node("sbz_resources:strange_blob", { - description = "Strange Blob", - info_extra = "It sure is strange looking... never before seen green color...\n wait did it just- oh no....", - tiles = { "strange_blob.png" }, +minetest.register_node('sbz_resources:strange_blob', { + description = 'Strange Blob', + info_extra = 'It sure is strange looking... never before seen green color...\n wait did it just- oh no....', + tiles = { 'strange_blob.png' }, groups = { matter = 1, antimatter = 1, strange = 1, explody = 100 }, sounds = sbz_api.sounds.strange(), light_source = 14, }) minetest.register_craft { - output = "sbz_resources:strange_blob", + output = 'sbz_resources:strange_blob', recipe = { - { "sbz_resources:strange_dust", "sbz_resources:strange_dust", "sbz_resources:strange_dust", }, - { "sbz_resources:strange_dust", "sbz_resources:strange_dust", "sbz_resources:strange_dust", }, - { "sbz_resources:strange_dust", "sbz_resources:strange_dust", "sbz_resources:strange_dust", }, - } + { 'sbz_resources:strange_dust', 'sbz_resources:strange_dust', 'sbz_resources:strange_dust' }, + { 'sbz_resources:strange_dust', 'sbz_resources:strange_dust', 'sbz_resources:strange_dust' }, + { 'sbz_resources:strange_dust', 'sbz_resources:strange_dust', 'sbz_resources:strange_dust' }, + }, } minetest.register_craft { - output = "sbz_resources:strange_dust 9", - type = "shapeless", - recipe = { "sbz_resources:strange_blob" } + output = 'sbz_resources:strange_dust 9', + type = 'shapeless', + recipe = { 'sbz_resources:strange_blob' }, } -- its been a while since i got to use theese -- - frog -minetest.register_abm({ - label = "Strange blob infecting", - nodenames = { "group:strange" }, - neighbors = { "group:antimatter", "group:matter" }, +minetest.register_abm { + label = 'Strange blob infecting', + nodenames = { 'group:strange' }, + neighbors = { 'group:antimatter', 'group:matter' }, interval = 1, chance = 20, catch_up = false, @@ -40,15 +40,14 @@ minetest.register_abm({ local to_spread = sbz_api.filter_node_neighbors(pos, 1, function(filtering_pos) local filtering_node = minetest.get_node(filtering_pos) local name = filtering_node.name - if minetest.get_item_group(name, "strange") ~= 0 then return end - if minetest.get_item_group(name, "sbz_machine") ~= 0 then return end - if minetest.get_item_group(name, "matter") == 0 and - minetest.get_item_group(name, "antimatter") == 0 then + if minetest.get_item_group(name, 'strange') ~= 0 then return end + if minetest.get_item_group(name, 'sbz_machine') ~= 0 then return end + if minetest.get_item_group(name, 'matter') == 0 and minetest.get_item_group(name, 'antimatter') == 0 then return end - if minetest.get_item_group(name, "no_spread") ~= 0 then return end - if minetest.get_item_group(name, "charged") ~= 0 then return end - if minetest.is_protected(filtering_pos, ".strange_blob_spread") then return end + if minetest.get_item_group(name, 'no_spread') ~= 0 then return end + if minetest.get_item_group(name, 'charged') ~= 0 then return end + if minetest.is_protected(filtering_pos, '.strange_blob_spread') then return end return filtering_pos end) @@ -59,35 +58,33 @@ minetest.register_abm({ local old_meta = minetest.get_meta(v) local meta = minetest.get_meta(v) if next(old_meta:to_table().inventory) == nil then -- you can't serialize userdata - core.swap_node(v, { name = "sbz_resources:strange_blob" }) - meta:set_string("old_meta", minetest.serialize(old_meta:to_table())) - meta:set_string("old_node", minetest.serialize(old_node)) + core.swap_node(v, { name = 'sbz_resources:strange_blob' }) + meta:set_string('old_meta', minetest.serialize(old_meta:to_table())) + meta:set_string('old_node', minetest.serialize(old_node)) end - end -}) - + end, +} local strange_cleaner_radius = 5 local power_per_1_use = 10 local max_wear = power_per_1_use * 200 - -minetest.register_tool("sbz_resources:strange_cleaner", { - description = "Strange Blob Cleaner", +minetest.register_tool('sbz_resources:strange_cleaner', { + description = 'Strange Blob Cleaner', info_extra = { - "Restores what was.... done.... by strange blobs.", - "\"Place\" it into a battery to charge.", + 'Restores what was.... done.... by strange blobs.', + '"Place" it into a battery to charge.', }, - inventory_image = "strange_cleaner.png", + inventory_image = 'strange_cleaner.png', groups = { disable_repair = 1, power_tool = 1 }, on_place = sbz_api.on_place_recharge((max_wear / 65535) * power_per_1_use), powertool_charge = sbz_api.powertool_charge((max_wear / 65535) * power_per_1_use), - wear_represents = "power", + wear_represents = 'power', charge_per_use = power_per_1_use, charge_in_wielders = false, on_use = function(stack, user, pointed) -- boilerplate - if pointed.type ~= "node" then return end + if pointed.type ~= 'node' then return end local target = pointed.under if core.is_protected(target, user:get_player_name()) then return core.record_protection_violation(target, user:get_player_name()) @@ -96,7 +93,6 @@ minetest.register_tool("sbz_resources:strange_cleaner", { -- take away wear - local deferred = {} for x = -strange_cleaner_radius, strange_cleaner_radius do @@ -105,13 +101,11 @@ minetest.register_tool("sbz_resources:strange_cleaner", { local pos = vector.add(target, vector.new(x, y, z)) local node = minetest.get_node(pos) local name = node.name - if minetest.get_item_group(name, "strange") ~= 0 then + if minetest.get_item_group(name, 'strange') ~= 0 then local meta = minetest.get_meta(pos) - local old_node = minetest.deserialize(meta:get_string("old_node")) - local old_meta = minetest.deserialize(meta:get_string("old_meta")) - if old_node == nil then - old_node = { name = "air" } - end + local old_node = minetest.deserialize(meta:get_string 'old_node') + local old_meta = minetest.deserialize(meta:get_string 'old_meta') + if old_node == nil then old_node = { name = 'air' } end deferred[#deferred + 1] = { pos, old_node } meta = minetest.get_meta(pos) if old_meta ~= nil then @@ -125,44 +119,44 @@ minetest.register_tool("sbz_resources:strange_cleaner", { local wear = stack:get_wear() local new_wear = wear + (power_per_1_use * #deferred) - if new_wear >= 65535 then - return - end + if new_wear >= 65535 then return end stack:set_wear(new_wear) for k, v in pairs(deferred) do minetest.swap_node(v[1], v[2]) - if v[3] then - v[3]:from_table(v[4]) - end + if v[3] then v[3]:from_table(v[4]) end end return stack - end + end, }) minetest.register_craft { - output = "sbz_resources:strange_cleaner", + output = 'sbz_resources:strange_cleaner', recipe = { - { "sbz_power:simple_charged_field", "sbz_power:simple_charged_field", "sbz_power:simple_charged_field" }, - { "", "sbz_resources:emittrium_circuit", "" }, - { "", "sbz_resources:matter_blob", "" } - } + { 'sbz_power:simple_charged_field', 'sbz_power:simple_charged_field', 'sbz_power:simple_charged_field' }, + { '', 'sbz_resources:emittrium_circuit', '' }, + { '', 'sbz_resources:matter_blob', '' }, + }, } -minetest.register_node("sbz_resources:stable_strange_blob", unifieddyes.def { - description = "Stabilized Strange Blob", - tiles = { "stable_strange_blob.png" }, - paramtype2 = "color", - paramtype = "light", - groups = { matter = 1, antimatter = 1, strange = 0, charged = 1, explody = 5 }, - light_source = 14, - info_extra = "Now i can enjoy the never-before seen green color with less of the... strange-ness..." -}) +minetest.register_node( + 'sbz_resources:stable_strange_blob', + unifieddyes.def { + description = 'Stabilized Strange Blob', + tiles = { 'stable_strange_blob.png' }, + paramtype2 = 'color', + paramtype = 'light', + groups = { matter = 1, antimatter = 1, strange = 0, charged = 1, explody = 5 }, + light_source = 14, + info_extra = 'Now i can enjoy the never-before seen green color with less of the... strange-ness...', + } +) minetest.register_craft { - output = "sbz_resources:stable_strange_blob", - type = "shapeless", + output = 'sbz_resources:stable_strange_blob', + type = 'shapeless', recipe = { - "sbz_resources:charged_particle", "sbz_resources:strange_blob" - } + 'sbz_resources:charged_particle', + 'sbz_resources:strange_blob', + }, } diff --git a/mods/stubes b/mods/stubes index 1d4c554b..b969831d 160000 --- a/mods/stubes +++ b/mods/stubes @@ -1 +1 @@ -Subproject commit 1d4c554b8a0e5fdf628acf84c6c0f028c6777210 +Subproject commit b969831db0e0eae4dbae1c81e6672c031b7ca2ad From 7264175ed93e915678109f77425abfe50d8ad353 Mon Sep 17 00:00:00 2001 From: TheEt1234 Date: Wed, 7 Jan 2026 10:11:29 +0100 Subject: [PATCH 20/28] Fix #194 --- luanti_lsp_definitions | 2 +- mods/sbz_base/init.lua | 15 ++++++++++----- mods/sbz_player_settings/apply.lua | 2 ++ mods/stubes | 2 +- 4 files changed, 14 insertions(+), 7 deletions(-) diff --git a/luanti_lsp_definitions b/luanti_lsp_definitions index fe88552d..d2c647a0 160000 --- a/luanti_lsp_definitions +++ b/luanti_lsp_definitions @@ -1 +1 @@ -Subproject commit fe88552d68b2a6778cca69d1bc01bb14c5c743e1 +Subproject commit d2c647a0c06295351dfba49846576c9967ec87a6 diff --git a/mods/sbz_base/init.lua b/mods/sbz_base/init.lua index 2a8a7a02..7b621904 100644 --- a/mods/sbz_base/init.lua +++ b/mods/sbz_base/init.lua @@ -208,16 +208,22 @@ local function playRandomBGM(player) if player:get_meta() == nil then return end local player_name = player:get_player_name() + local player_meta = player:get_meta() + local random_index = math.random(1, #bgm_sounds) local sound_name = bgm_sounds[random_index] local sound_length = bgm_lengths[random_index] if handles[player_name] then core.sound_stop(handles[player_name]) end - local volume = player:get_meta():get_int 'volume' / 100 - if volume == 0 and player:get_meta():get_int 'has_set_volume' == 0 then volume = 1 end + + local volume = player_meta:get_int 'bgm_volume' / 100 + if volume == 0 and player_meta:get_int 'has_set_volume' == 0 then volume = 1 end + + core.debug('PLAYING: ' .. dump(volume)) handles[player_name] = core.sound_play(sound_name, { to_player = player_name, gain = volume, }) + core.after( sound_length + math.random(10, 100), function() -- i introduce one second of complete silence here, just because -- yeah well I introduce three hundred -- yeah well guess what its random now @@ -239,7 +245,7 @@ core.register_chatcommand('bgm_volume', { local player = core.get_player_by_name(name or '') if not player then return end local meta = player:get_meta() - meta:set_int('volume', volume) + meta:set_int('bgm_volume', volume) meta:set_int('has_set_volume', 1) local handle = sbz_api.bgm_handles[player:get_player_name()] if handle then core.sound_fade(handle, 4, (volume / 100) + 0.001) end -- HACK: +0.001 so it doesn't delete the sound xDD @@ -255,8 +261,7 @@ core.register_on_joinplayer(function(player) '‼ reminder: If you fall off, use /core to teleport back to the core.' ) core.chat_send_player(player:get_player_name(), '‼ reminder: If lose your Quest Book, use /qb to get it back.') - -- core.chat_send_player(player:get_player_name(), - -- "‼ Also, you can hold right click on the core, instead of having to spam your mouse, on mobile you might need to just hold tap") + -- play bgm playRandomBGM(player) diff --git a/mods/sbz_player_settings/apply.lua b/mods/sbz_player_settings/apply.lua index ea190c00..2726ebbe 100644 --- a/mods/sbz_player_settings/apply.lua +++ b/mods/sbz_player_settings/apply.lua @@ -5,6 +5,7 @@ local on_join = core.register_on_joinplayer --- BGM receive(function(player, formname, fields) if formname ~= (base_formname .. '_bgm') then return end + core.debug 'HERE' local scrollbar = core.explode_scrollbar_event(fields.bgm_slider) if scrollbar.type ~= 'CHG' then return end @@ -12,6 +13,7 @@ receive(function(player, formname, fields) local pmeta = player:get_meta() local new_value = math.min(200, math.max(0, scrollbar.value)) pmeta:set_int('bgm_volume', new_value) + pmeta:set_int('has_set_volume', 1) local handle = sbz_api.bgm_handles[player:get_player_name()] if handle then core.sound_fade(handle, 4, (new_value / 100) + 0.001) end -- HACK: +0.001 so that it doesn't delete the sound diff --git a/mods/stubes b/mods/stubes index b969831d..46fb8664 160000 --- a/mods/stubes +++ b/mods/stubes @@ -1 +1 @@ -Subproject commit b969831db0e0eae4dbae1c81e6672c031b7ca2ad +Subproject commit 46fb86643f91b89e633082fbff876be90d2fd4ab From ed48511acada15184836a985a468780bc6e589db Mon Sep 17 00:00:00 2001 From: TheEt1234 Date: Wed, 7 Jan 2026 10:14:09 +0100 Subject: [PATCH 21/28] Kill MTT, because it doesn't work with submodules? --- .github/workflows/test.yml | 15 --------------- 1 file changed, 15 deletions(-) delete mode 100644 .github/workflows/test.yml diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml deleted file mode 100644 index fdcc8eaf..00000000 --- a/.github/workflows/test.yml +++ /dev/null @@ -1,15 +0,0 @@ -name: test -on: [push, pull_request] -jobs: - test: - timeout-minutes: 3 - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v2 - - uses: buckaroobanzay/mtt@main - with: - test_mode: game - mapgen: v7 - additional_config: | - secure.trusted_mods = mtt, libox - secure.http_mods = sbz_logic_devices \ No newline at end of file From acbf2d336e089b8250fb8701f56b8d8c4fe94295 Mon Sep 17 00:00:00 2001 From: TheEt1234 Date: Wed, 7 Jan 2026 10:17:41 +0100 Subject: [PATCH 22/28] Remove some debug logging --- mods/drawers/api.lua | 664 ++++++++++++++--------------- mods/sbz_base/init.lua | 1 - mods/sbz_instatube/init.lua | 1 + mods/sbz_player_settings/apply.lua | 1 - 4 files changed, 313 insertions(+), 354 deletions(-) diff --git a/mods/drawers/api.lua b/mods/drawers/api.lua index 3f9a932d..f1a749ac 100755 --- a/mods/drawers/api.lua +++ b/mods/drawers/api.lua @@ -25,430 +25,390 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ]] -local S = minetest.get_translator('drawers') +local S = minetest.get_translator 'drawers' drawers.node_box_simple = { - { -0.5, -0.5, -0.4375, 0.5, 0.5, 0.5 }, - { -0.5, -0.5, -0.5, -0.4375, 0.5, -0.4375 }, - { 0.4375, -0.5, -0.5, 0.5, 0.5, -0.4375 }, - { -0.4375, 0.4375, -0.5, 0.4375, 0.5, -0.4375 }, - { -0.4375, -0.5, -0.5, 0.4375, -0.4375, -0.4375 }, + { -0.5, -0.5, -0.4375, 0.5, 0.5, 0.5 }, + { -0.5, -0.5, -0.5, -0.4375, 0.5, -0.4375 }, + { 0.4375, -0.5, -0.5, 0.5, 0.5, -0.4375 }, + { -0.4375, 0.4375, -0.5, 0.4375, 0.5, -0.4375 }, + { -0.4375, -0.5, -0.5, 0.4375, -0.4375, -0.4375 }, } -drawers.drawer_formspec = "size[9,6.7]" .. - "list[context;upgrades;2,0.5;5,1;]" .. - drawers.inventory_list(2.5) .. - "listring[context;upgrades]" .. - "listring[current_player;main]" .. - drawers.get_upgrade_slots_bg(2, 0.5) +drawers.drawer_formspec = 'size[9,6.7]' + .. 'list[context;upgrades;2,0.5;5,1;]' + .. drawers.inventory_list(2.5) + .. 'listring[context;upgrades]' + .. 'listring[current_player;main]' + .. drawers.get_upgrade_slots_bg(2, 0.5) -- construct drawer function drawers.drawer_on_construct(pos) - local node = core.get_node(pos) - local ndef = core.registered_nodes[node.name] - local drawerType = ndef.groups.drawer - - local base_stack_max = core.nodedef_default.stack_max or 99 - local stack_max_factor = ndef.drawer_stack_max_factor or 24 -- 3x8 - stack_max_factor = math.floor(stack_max_factor / drawerType) -- drawerType => number of drawers in node - - -- meta - local meta = core.get_meta(pos) - - local i = 1 - while i <= drawerType do - local vid = i - -- 1x1 drawers don't have numbers in the meta fields - if drawerType == 1 then vid = "" end - meta:set_string("name" .. vid, "") - meta:set_int("count" .. vid, 0) - meta:set_int("max_count" .. vid, base_stack_max * stack_max_factor) - meta:set_int("base_stack_max" .. vid, base_stack_max) - meta:set_string("entity_infotext" .. vid, drawers.gen_info_text(S("Empty"), 0, - stack_max_factor, base_stack_max)) - meta:set_int("stack_max_factor" .. vid, stack_max_factor) - - i = i + 1 - end - - -- spawn all visuals - drawers.spawn_visuals(pos) - - -- create drawer upgrade inventory - meta:get_inventory():set_size("upgrades", 5) - - -- set the formspec - meta:set_string("formspec", drawers.drawer_formspec) + local node = core.get_node(pos) + local ndef = core.registered_nodes[node.name] + local drawerType = ndef.groups.drawer + + local base_stack_max = core.nodedef_default.stack_max or 99 + local stack_max_factor = ndef.drawer_stack_max_factor or 24 -- 3x8 + stack_max_factor = math.floor(stack_max_factor / drawerType) -- drawerType => number of drawers in node + + -- meta + local meta = core.get_meta(pos) + + local i = 1 + while i <= drawerType do + local vid = i + -- 1x1 drawers don't have numbers in the meta fields + if drawerType == 1 then vid = '' end + meta:set_string('name' .. vid, '') + meta:set_int('count' .. vid, 0) + meta:set_int('max_count' .. vid, base_stack_max * stack_max_factor) + meta:set_int('base_stack_max' .. vid, base_stack_max) + meta:set_string('entity_infotext' .. vid, drawers.gen_info_text(S 'Empty', 0, stack_max_factor, base_stack_max)) + meta:set_int('stack_max_factor' .. vid, stack_max_factor) + + i = i + 1 + end + + -- spawn all visuals + drawers.spawn_visuals(pos) + + -- create drawer upgrade inventory + meta:get_inventory():set_size('upgrades', 5) + + -- set the formspec + meta:set_string('formspec', drawers.drawer_formspec) end -- destruct drawer function drawers.drawer_on_destruct(pos) - drawers.remove_visuals(pos) + drawers.remove_visuals(pos) - -- clean up visual cache - if drawers.drawer_visuals[core.hash_node_position(pos)] then - drawers.drawer_visuals[core.hash_node_position(pos)] = nil - end + -- clean up visual cache + if drawers.drawer_visuals[core.hash_node_position(pos)] then + drawers.drawer_visuals[core.hash_node_position(pos)] = nil + end end -- don't drop all items function drawers.drawer_on_dig(pos, node, player) - local drawerType = 1 - if core.registered_nodes[node.name] then - drawerType = core.registered_nodes[node.name].groups.drawer - end - if core.is_protected(pos, player:get_player_name()) then - core.record_protection_violation(pos, player:get_player_name()) - return false - end - - - local meta = core.get_meta(pos) - local k = 1 - while k <= drawerType do - -- don't add a number in meta fields for 1x1 drawers - local vid = tostring(k) - if drawerType == 1 then vid = "" end - local count = meta:get_int("count" .. vid) - k = k + 1 - if count > 0 then return end - end - - -- drop all drawer upgrades - local upgrades = meta:get_inventory():get_list("upgrades") - if upgrades then - for _, itemStack in pairs(upgrades) do - if itemStack:get_count() > 0 then - return false - end - end - end - -- remove node - core.node_dig(pos, node, player) + local drawerType = 1 + if core.registered_nodes[node.name] then drawerType = core.registered_nodes[node.name].groups.drawer end + if core.is_protected(pos, player:get_player_name()) then + core.record_protection_violation(pos, player:get_player_name()) + return false + end + + local meta = core.get_meta(pos) + local k = 1 + while k <= drawerType do + -- don't add a number in meta fields for 1x1 drawers + local vid = tostring(k) + if drawerType == 1 then vid = '' end + local count = meta:get_int('count' .. vid) + k = k + 1 + if count > 0 then return end + end + + -- drop all drawer upgrades + local upgrades = meta:get_inventory():get_list 'upgrades' + if upgrades then + for _, itemStack in pairs(upgrades) do + if itemStack:get_count() > 0 then return false end + end + end + -- remove node + core.node_dig(pos, node, player) end function drawers.drawer_allow_metadata_inventory_put(pos, listname, index, stack, player) - if core.is_protected(pos, player:get_player_name()) then - core.record_protection_violation(pos, player:get_player_name()) - return 0 - end - if listname ~= "upgrades" then - return 0 - end - if stack:get_count() > 1 then - return 0 - end - if core.get_item_group(stack:get_name(), "drawer_upgrade") < 1 then - return 0 - end - return 1 + if core.is_protected(pos, player:get_player_name()) then + core.record_protection_violation(pos, player:get_player_name()) + return 0 + end + if listname ~= 'upgrades' then return 0 end + if stack:get_count() > 1 then return 0 end + if core.get_item_group(stack:get_name(), 'drawer_upgrade') < 1 then return 0 end + return 1 end function drawers.add_drawer_upgrade(pos, listname, index, stack, player) - -- only do anything if adding to upgrades - if listname ~= "upgrades" then return end + -- only do anything if adding to upgrades + if listname ~= 'upgrades' then return end - drawers.update_drawer_upgrades(pos) + drawers.update_drawer_upgrades(pos) end function drawers.remove_drawer_upgrade(pos, listname, index, stack, player) - -- only do anything if adding to upgrades - if listname ~= "upgrades" then return end + -- only do anything if adding to upgrades + if listname ~= 'upgrades' then return end - drawers.update_drawer_upgrades(pos) + drawers.update_drawer_upgrades(pos) end --[[ Inserts an incoming stack into a specific slot of a drawer. ]] function drawers.drawer_insert_object(pos, stack, visualid) - local visual = drawers.get_visual(pos, visualid) - if not visual then - return stack - end + local visual = drawers.get_visual(pos, visualid) + if not visual then return stack end - return visual:try_insert_stack(stack, true) + return visual:try_insert_stack(stack, true) end --[[ Inserts an incoming stack into a drawer and uses all slots. ]] function drawers.drawer_insert_object_from_tube(pos, node, stack, direction) - local drawer_visuals = drawers.drawer_visuals[core.hash_node_position(pos)] - if not drawer_visuals then - return stack - end - - -- first try to insert in the correct slot (if there are already items) - local leftover = stack - for _, visual in pairs(drawer_visuals) do - if visual.itemName == stack:get_name() then - leftover = visual:try_insert_stack(leftover, true) - end - end - - -- if there's still something left, also use other slots - if leftover:get_count() > 0 then - for _, visual in pairs(drawer_visuals) do - leftover = visual:try_insert_stack(leftover, true) - end - end - return leftover + local drawer_visuals = drawers.drawer_visuals[core.hash_node_position(pos)] + if not drawer_visuals then return stack end + + -- first try to insert in the correct slot (if there are already items) + local leftover = stack + for _, visual in pairs(drawer_visuals) do + if visual.itemName == stack:get_name() then leftover = visual:try_insert_stack(leftover, true) end + end + + -- if there's still something left, also use other slots + if leftover:get_count() > 0 then + for _, visual in pairs(drawer_visuals) do + leftover = visual:try_insert_stack(leftover, true) + end + end + return leftover end --[[ Returns how much (count) of a stack can be inserted to a drawer slot. ]] function drawers.drawer_can_insert_stack(pos, stack, visualid) - local visual = drawers.get_visual(pos, visualid) - if not visual then - return 0 - end + local visual = drawers.get_visual(pos, visualid) + if not visual then return 0 end - return visual:can_insert_stack(stack) + return visual:can_insert_stack(stack) end --[[ Returns whether a stack can be (partially) inserted to any slot of a drawer. ]] function drawers.drawer_can_insert_stack_from_tube(pos, node, stack, direction) - local drawer_visuals = drawers.drawer_visuals[core.hash_node_position(pos)] - if not drawer_visuals then - return false - end - - for _, visual in pairs(drawer_visuals) do - if visual:can_insert_stack(stack) > 0 then - return true - end - end - return false + local drawer_visuals = drawers.drawer_visuals[core.hash_node_position(pos)] + if not drawer_visuals then return false end + + for _, visual in pairs(drawer_visuals) do + if visual:can_insert_stack(stack) > 0 then return true end + end + return false end function drawers.drawer_take_item(pos, itemstack) - local drawer_visuals = drawers.drawer_visuals[core.hash_node_position(pos)] + local drawer_visuals = drawers.drawer_visuals[core.hash_node_position(pos)] - if not drawer_visuals then - return ItemStack("") - end + if not drawer_visuals then return ItemStack '' end - -- check for max count - if itemstack:get_count() > itemstack:get_stack_max() then - itemstack:set_count(itemstack:get_stack_max()) - end + -- check for max count + if itemstack:get_count() > itemstack:get_stack_max() then itemstack:set_count(itemstack:get_stack_max()) end - for _, visual in pairs(drawer_visuals) do - if visual.itemName == itemstack:get_name() then - return visual:take_items(itemstack:get_count()) - end - end + for _, visual in pairs(drawer_visuals) do + if visual.itemName == itemstack:get_name() then return visual:take_items(itemstack:get_count()) end + end - return ItemStack() + return ItemStack() end --[[ Returns the content of a drawer slot. ]] function drawers.drawer_get_content(pos, visualid) - local drawer_meta = core.get_meta(pos) + local drawer_meta = core.get_meta(pos) - return { - name = drawer_meta:get_string("name" .. visualid), - count = drawer_meta:get_int("count" .. visualid), - maxCount = drawer_meta:get_int("max_count" .. visualid) - } + return { + name = drawer_meta:get_string('name' .. visualid), + count = drawer_meta:get_int('count' .. visualid), + maxCount = drawer_meta:get_int('max_count' .. visualid), + } end function drawers.register_drawer(name, def) - def.description = def.description - def.drawtype = "nodebox" - def.node_box = { type = "fixed", fixed = drawers.node_box_simple } - def.collision_box = { type = "regular" } - def.selection_box = { type = "fixed", fixed = drawers.node_box_simple } - def.paramtype = "light" - def.paramtype2 = "colorfacedir" - def.light_source = 10 - def.groups = def.groups or {} - def.is_ground_content = false - - -- events - def.on_construct = drawers.drawer_on_construct - def.on_destruct = drawers.drawer_on_destruct - def.on_dig = drawers.drawer_on_dig - def.allow_metadata_inventory_put = drawers.drawer_allow_metadata_inventory_put - def.allow_metadata_inventory_take = drawers.drawer_allow_metadata_inventory_put - def.on_metadata_inventory_put = drawers.add_drawer_upgrade - def.on_metadata_inventory_take = drawers.remove_drawer_upgrade - - if minetest.get_modpath("screwdriver") and screwdriver then - def.on_rotate = def.on_rotate or screwdriver.disallow - end - - if minetest.get_modpath("pipeworks") and pipeworks then - def.groups.tubedevice = 1 - def.groups.tubedevice_receiver = 1 - def.groups.tubedevice_use_item_entities = 1 - def.tube = def.tube or {} - def.tube.insert_object = def.tube.insert_object or - drawers.drawer_insert_object_from_tube - def.tube.can_insert = def.tube.can_insert or - drawers.drawer_can_insert_stack_from_tube - - def.tube.connect_sides = { - left = 1, - right = 1, - back = 1, - top = 1, - bottom = 1 - } - def.after_place_node = pipeworks.after_place - def.after_dig_node = pipeworks.after_dig - - def.tube.return_input_invref = function(pos, node, dir, owner) - local inv = core.get_meta(pos):get_inventory() -- fakelib.create_inventory() -- fakelib is WEEIRD - local vis = drawers.drawer_visuals[core.hash_node_position(pos)] - if not vis then return false end - for i = 1, 4 do - local this_vis = vis[i] - if not this_vis then break end - - local content = drawers.drawer_get_content(pos, this_vis.visualId) - local stack = ItemStack({ - name = content.name, - count = math.min(content.count, ItemStack(content.name):get_stack_max()) - }) - - inv:set_size("slot" .. i, 1) - inv:set_size("old_slot" .. i, 1) - inv:set_stack("slot" .. i, 1, stack) - inv:set_stack("old_slot" .. i, 1, stack) -- to determine how much has been taken - end - return inv - end - def.tube.after_filter = function(pos, inv) - local vis = drawers.drawer_visuals[core.hash_node_position(pos)] - for i = 1, 4 do - local this_vis = vis[i] - if not this_vis then break end - local stack = inv:get_stack("slot" .. i, 1) - local old_stack = inv:get_stack("old_slot" .. i, 1) - local diff = old_stack:get_count() - stack:get_count() - old_stack:set_count(diff) - drawers.drawer_take_item(pos, old_stack) - -- local content = drawers.drawer_get_content(pos, this_vis.visualId) - -- local count = content.count - diff - end - end - -- def.tube.remove_items = function(pos, node, stack, dir, count, invname, spos, inv) - -- local oldstack = inv:get_stack(invname, 1) - -- oldstack:set_count(oldstack:get_count() - stack:get_count()) - -- inv:set_stack(invname, 1, oldstack) - -- core.debug(inv:get_stack(invname, 1):to_string()) - -- return stack - -- end - - def.tube.ignore_metadata_inventory_take = true - def.tube.input_inventory = { - "slot1", "slot2", "slot3", "slot4" - } - end - def.on_movenode = function(_, to_pos) - minetest.after(0.1, function() - drawers.spawn_visuals(to_pos) - end) - end - def = unifieddyes.def(def, false) - if drawers.enable_1x1 then - -- normal drawer 1x1 = 1 - local def1 = table.copy(def) - def1.tiles = def.tiles or def.tiles1 - def1.tiles1 = nil - def1.tiles2 = nil - def1.tiles4 = nil - def1.groups.drawer = 1 - core.register_node(name .. "1", def1) - core.register_alias(name, name .. "1") -- 1x1 drawer is the default one - end - - if drawers.enable_1x2 then - -- 1x2 = 2 - local def2 = table.copy(def) - def2.description = def.description .. " (1x2)" - def2.tiles = def.tiles2 - def2.tiles1 = nil - def2.tiles2 = nil - def2.tiles4 = nil - def2.groups.drawer = 2 - core.register_node(name .. "2", def2) - end - - if drawers.enable_2x2 then - -- 2x2 = 4 - local def4 = table.copy(def) - def4.description = def.description .. " (2x2)" - def4.tiles = def.tiles4 - def4.tiles1 = nil - def4.tiles2 = nil - def4.tiles4 = nil - def4.groups.drawer = 4 - core.register_node(name .. "4", def4) - end - if (not def.no_craft) and def.material then - if drawers.enable_1x1 then - core.register_craft({ - output = name .. "1", - recipe = { - { def.material, def.material, def.material }, - { "", drawers.CHEST_ITEMSTRING, "" }, - { def.material, def.material, def.material } - } - }) - end - if drawers.enable_1x2 then - core.register_craft({ - output = name .. "2 2", - recipe = { - { def.material, drawers.CHEST_ITEMSTRING, def.material }, - { def.material, def.material, def.material }, - { def.material, drawers.CHEST_ITEMSTRING, def.material } - } - }) - end - if drawers.enable_2x2 then - core.register_craft({ - output = name .. "4 4", - recipe = { - { drawers.CHEST_ITEMSTRING, def.material, drawers.CHEST_ITEMSTRING }, - { def.material, def.material, def.material }, - { drawers.CHEST_ITEMSTRING, def.material, drawers.CHEST_ITEMSTRING } - } - }) - end - end + def.description = def.description + def.drawtype = 'nodebox' + def.node_box = { type = 'fixed', fixed = drawers.node_box_simple } + def.collision_box = { type = 'regular' } + def.selection_box = { type = 'fixed', fixed = drawers.node_box_simple } + def.paramtype = 'light' + def.paramtype2 = 'colorfacedir' + def.light_source = 10 + def.groups = def.groups or {} + def.is_ground_content = false + + -- events + def.on_construct = drawers.drawer_on_construct + def.on_destruct = drawers.drawer_on_destruct + def.on_dig = drawers.drawer_on_dig + def.allow_metadata_inventory_put = drawers.drawer_allow_metadata_inventory_put + def.allow_metadata_inventory_take = drawers.drawer_allow_metadata_inventory_put + def.on_metadata_inventory_put = drawers.add_drawer_upgrade + def.on_metadata_inventory_take = drawers.remove_drawer_upgrade + + if minetest.get_modpath 'screwdriver' and screwdriver then def.on_rotate = def.on_rotate or screwdriver.disallow end + + if minetest.get_modpath 'pipeworks' and pipeworks then + def.groups.tubedevice = 1 + def.groups.tubedevice_receiver = 1 + def.groups.tubedevice_use_item_entities = 1 + def.tube = def.tube or {} + def.tube.insert_object = def.tube.insert_object or drawers.drawer_insert_object_from_tube + def.tube.can_insert = def.tube.can_insert or drawers.drawer_can_insert_stack_from_tube + + def.tube.connect_sides = { + left = 1, + right = 1, + back = 1, + top = 1, + bottom = 1, + } + def.after_place_node = pipeworks.after_place + def.after_dig_node = pipeworks.after_dig + + def.tube.return_input_invref = function(pos, node, dir, owner) + local inv = core.get_meta(pos):get_inventory() -- fakelib.create_inventory() -- fakelib is WEEIRD + local vis = drawers.drawer_visuals[core.hash_node_position(pos)] + if not vis then return false end + for i = 1, 4 do + local this_vis = vis[i] + if not this_vis then break end + + local content = drawers.drawer_get_content(pos, this_vis.visualId) + local stack = ItemStack { + name = content.name, + count = math.min(content.count, ItemStack(content.name):get_stack_max()), + } + + inv:set_size('slot' .. i, 1) + inv:set_size('old_slot' .. i, 1) + inv:set_stack('slot' .. i, 1, stack) + inv:set_stack('old_slot' .. i, 1, stack) -- to determine how much has been taken + end + return inv + end + def.tube.after_filter = function(pos, inv) + local vis = drawers.drawer_visuals[core.hash_node_position(pos)] + for i = 1, 4 do + local this_vis = vis[i] + if not this_vis then break end + local stack = inv:get_stack('slot' .. i, 1) + local old_stack = inv:get_stack('old_slot' .. i, 1) + local diff = old_stack:get_count() - stack:get_count() + old_stack:set_count(diff) + drawers.drawer_take_item(pos, old_stack) + end + end + + def.tube.ignore_metadata_inventory_take = true + def.tube.input_inventory = { + 'slot1', + 'slot2', + 'slot3', + 'slot4', + } + end + def.on_movenode = function(_, to_pos) + minetest.after(0.1, function() + drawers.spawn_visuals(to_pos) + end) + end + def = unifieddyes.def(def, false) + if drawers.enable_1x1 then + -- normal drawer 1x1 = 1 + local def1 = table.copy(def) + def1.tiles = def.tiles or def.tiles1 + def1.tiles1 = nil + def1.tiles2 = nil + def1.tiles4 = nil + def1.groups.drawer = 1 + core.register_node(name .. '1', def1) + core.register_alias(name, name .. '1') -- 1x1 drawer is the default one + end + + if drawers.enable_1x2 then + -- 1x2 = 2 + local def2 = table.copy(def) + def2.description = def.description .. ' (1x2)' + def2.tiles = def.tiles2 + def2.tiles1 = nil + def2.tiles2 = nil + def2.tiles4 = nil + def2.groups.drawer = 2 + core.register_node(name .. '2', def2) + end + + if drawers.enable_2x2 then + -- 2x2 = 4 + local def4 = table.copy(def) + def4.description = def.description .. ' (2x2)' + def4.tiles = def.tiles4 + def4.tiles1 = nil + def4.tiles2 = nil + def4.tiles4 = nil + def4.groups.drawer = 4 + core.register_node(name .. '4', def4) + end + if (not def.no_craft) and def.material then + if drawers.enable_1x1 then + core.register_craft { + output = name .. '1', + recipe = { + { def.material, def.material, def.material }, + { '', drawers.CHEST_ITEMSTRING, '' }, + { def.material, def.material, def.material }, + }, + } + end + if drawers.enable_1x2 then + core.register_craft { + output = name .. '2 2', + recipe = { + { def.material, drawers.CHEST_ITEMSTRING, def.material }, + { def.material, def.material, def.material }, + { def.material, drawers.CHEST_ITEMSTRING, def.material }, + }, + } + end + if drawers.enable_2x2 then + core.register_craft { + output = name .. '4 4', + recipe = { + { drawers.CHEST_ITEMSTRING, def.material, drawers.CHEST_ITEMSTRING }, + { def.material, def.material, def.material }, + { drawers.CHEST_ITEMSTRING, def.material, drawers.CHEST_ITEMSTRING }, + }, + } + end + end end -local template = "drawers:upgrade_template" +local template = 'drawers:upgrade_template' function drawers.register_drawer_upgrade(name, def) - def.groups = def.groups or {} - def.groups.drawer_upgrade = def.groups.drawer_upgrade or 100 - def.inventory_image = def.inventory_image or "drawers_upgrade_template.png" - def.stack_max = 1 - - local recipe_item = def.recipe_item or "air" - def.recipe_item = nil - - core.register_craftitem(name, def) - - if not def.no_craft then - core.register_craft({ - output = name, - recipe = { - { recipe_item, recipe_item, recipe_item }, - { recipe_item, template, recipe_item }, - { recipe_item, recipe_item, recipe_item } - } - }) - template = name - end + def.groups = def.groups or {} + def.groups.drawer_upgrade = def.groups.drawer_upgrade or 100 + def.inventory_image = def.inventory_image or 'drawers_upgrade_template.png' + def.stack_max = 1 + + local recipe_item = def.recipe_item or 'air' + def.recipe_item = nil + + core.register_craftitem(name, def) + + if not def.no_craft then + core.register_craft { + output = name, + recipe = { + { recipe_item, recipe_item, recipe_item }, + { recipe_item, template, recipe_item }, + { recipe_item, recipe_item, recipe_item }, + }, + } + template = name + end end diff --git a/mods/sbz_base/init.lua b/mods/sbz_base/init.lua index 7b621904..eb1b8eed 100644 --- a/mods/sbz_base/init.lua +++ b/mods/sbz_base/init.lua @@ -218,7 +218,6 @@ local function playRandomBGM(player) local volume = player_meta:get_int 'bgm_volume' / 100 if volume == 0 and player_meta:get_int 'has_set_volume' == 0 then volume = 1 end - core.debug('PLAYING: ' .. dump(volume)) handles[player_name] = core.sound_play(sound_name, { to_player = player_name, gain = volume, diff --git a/mods/sbz_instatube/init.lua b/mods/sbz_instatube/init.lua index 333d4a24..1dd5e8ac 100644 --- a/mods/sbz_instatube/init.lua +++ b/mods/sbz_instatube/init.lua @@ -831,6 +831,7 @@ instatube.show_network = function(p1, p2, net) end end +--- This is a function meant for debugging instatube.get_machine = function(pos, net_id) local net = instatube.networks[net_id] for k, v in pairs(net.machines) do diff --git a/mods/sbz_player_settings/apply.lua b/mods/sbz_player_settings/apply.lua index 2726ebbe..83768a98 100644 --- a/mods/sbz_player_settings/apply.lua +++ b/mods/sbz_player_settings/apply.lua @@ -5,7 +5,6 @@ local on_join = core.register_on_joinplayer --- BGM receive(function(player, formname, fields) if formname ~= (base_formname .. '_bgm') then return end - core.debug 'HERE' local scrollbar = core.explode_scrollbar_event(fields.bgm_slider) if scrollbar.type ~= 'CHG' then return end From e71a8e6a7efe5a5640a760243fadead2350db1a9 Mon Sep 17 00:00:00 2001 From: TheEt1234 Date: Wed, 7 Jan 2026 10:47:54 +0100 Subject: [PATCH 23/28] Fix #164 --- mods/sbz_bio/plants.lua | 421 +++++++++++++++++++++------------------- 1 file changed, 221 insertions(+), 200 deletions(-) diff --git a/mods/sbz_bio/plants.lua b/mods/sbz_bio/plants.lua index f1347bcc..33ffbe8c 100644 --- a/mods/sbz_bio/plants.lua +++ b/mods/sbz_bio/plants.lua @@ -11,56 +11,57 @@ function sbz_api.plant_grow(next_stage) end local warpshroom_family = { - "sbz_bio:warpshroom", - "sbz_bio:shockshroom", - "sbz_bio:stemfruit_plant" + 'sbz_bio:warpshroom', + 'sbz_bio:shockshroom', + 'sbz_bio:stemfruit_plant', } local pyrograss_family = { - "sbz_bio:pyrograss", - "sbz_bio:razorgrass", - "sbz_bio:cleargrass", - "sbz_bio:stemfruit_plant", + 'sbz_bio:pyrograss', + 'sbz_bio:razorgrass', + 'sbz_bio:cleargrass', + 'sbz_bio:stemfruit_plant', } local fiberweed_family = { - "sbz_bio:fiberweed", + 'sbz_bio:fiberweed', } local can_turn_into = { - ["sbz_bio:stemfruit_plant"] = { - "sbz_bio:pyrograss", - "sbz_bio:razorgrass", - "sbz_bio:cleargrass", - "sbz_bio:warpshroom", - "sbz_bio:shockshroom", + ['sbz_bio:stemfruit_plant'] = { + 'sbz_bio:pyrograss', + 'sbz_bio:razorgrass', + 'sbz_bio:cleargrass', + 'sbz_bio:warpshroom', + 'sbz_bio:shockshroom', -- "sbz_bio:fiberweed", }, - ["sbz_bio:warpshroom"] = warpshroom_family, - ["sbz_bio:shockshroom"] = warpshroom_family, - ["sbz_bio:pyrograss"] = pyrograss_family, - ["sbz_bio:razorgrass"] = pyrograss_family, - ["sbz_bio:cleargrass"] = pyrograss_family, - ["sbz_bio:fiberweed"] = fiberweed_family, + ['sbz_bio:warpshroom'] = warpshroom_family, + ['sbz_bio:shockshroom'] = warpshroom_family, + ['sbz_bio:pyrograss'] = pyrograss_family, + ['sbz_bio:razorgrass'] = pyrograss_family, + ['sbz_bio:cleargrass'] = pyrograss_family, + ['sbz_bio:fiberweed'] = fiberweed_family, } -local special_cases = { ["sbz_bio:fiberweed"] = true } +local special_cases = { ['sbz_bio:fiberweed'] = true } + +-- i actually forgot what this is for +-- i assume it's for checking if the stuff above is good core.after(0, function() - -- dev script for checking if the stuff i write is actually valid for initial_node, node_list in pairs(can_turn_into) do - if not core.registered_nodes[initial_node .. "_1"] and not special_cases[initial_node] then - error("Uh oh: " .. - initial_node) + if not core.registered_nodes[initial_node .. '_1'] and not special_cases[initial_node] then + error('Uh oh: ' .. initial_node) end for k, v in pairs(node_list) do - if not core.registered_nodes[v .. "_1"] and not special_cases[v] then error("Uh oh:" .. v) end + if not core.registered_nodes[v .. '_1'] and not special_cases[v] then error('Uh oh:' .. v) end end end end) local radiation_check = function(pos) - local nodes = core.find_nodes_in_area(pos - vector.new(5, 5, 5), pos + vector.new(5, 5, 5), - { "group:radioactive" }, true) + local nodes = + core.find_nodes_in_area(pos - vector.new(5, 5, 5), pos + vector.new(5, 5, 5), { 'group:radioactive' }, true) local rad = 0 for nodename, poslist in pairs(nodes) do - local val = core.get_item_group(nodename, "radioactive") + local val = core.get_item_group(nodename, 'radioactive') for _, radpos in ipairs(poslist) do local dist = vector.distance(pos, radpos) rad = rad + ((val ^ 2) / math.max(0.75, dist ^ 2)) @@ -69,8 +70,6 @@ local radiation_check = function(pos) return rad -- so rad end - - function sbz_api.plant_growth_tick(num_ticks, mutation_chance) return function(pos, node) local rad = radiation_check(pos) @@ -86,10 +85,10 @@ function sbz_api.plant_growth_tick(num_ticks, mutation_chance) local newnode = table.copy(node) local nodepos = vector.copy(pos) if special_cases[should_turn_into] then - if should_turn_into == "sbz_bio:fiberweed" then - if core.get_node(vector.subtract(nodepos, vector.new(0, 1, 0))).name == "sbz_bio:dirt" then + if should_turn_into == 'sbz_bio:fiberweed' then + if core.get_node(vector.subtract(nodepos, vector.new(0, 1, 0))).name == 'sbz_bio:dirt' then nodepos = vector.subtract(nodepos, vector.new(0, 1, 0)) - should_turn_into = "sbz_bio:fiberweed" + should_turn_into = 'sbz_bio:fiberweed' else return true -- can't mutate end @@ -103,30 +102,30 @@ function sbz_api.plant_growth_tick(num_ticks, mutation_chance) end if sbz_api.get_node_heat(pos) > 7 and sbz_api.is_hydrated(pos) then local meta = minetest.get_meta(pos) - local count = meta:get_int("count") + 1 + local count = meta:get_int 'count' + 1 local under = vector.copy(pos) under.y = under.y - 1 local growth_multiplier = 1 - local soil = core.get_item_group((sbz_api.get_or_load_node(under) or { name = "" }).name, "soil") + local soil = core.get_item_group((sbz_api.get_or_load_node(under) or { name = '' }).name, 'soil') growth_multiplier = math.max(0, growth_multiplier + (soil - 1)) iterate_around_pos(pos, function(ipos) local n = sbz_api.get_or_load_node(ipos) - if n and core.get_item_group(n.name, "growth_boost") > 0 then - growth_multiplier = growth_multiplier + - (growth_multiplier * (core.get_item_group(n.name, "growth_boost") / 100)) + if n and core.get_item_group(n.name, 'growth_boost') > 0 then + growth_multiplier = growth_multiplier + + (growth_multiplier * (core.get_item_group(n.name, 'growth_boost') / 100)) end end) - meta:set_float("growth_multiplier", growth_multiplier) + meta:set_float('growth_multiplier', growth_multiplier) if count >= (num_ticks / growth_multiplier) then count = 0 minetest.registered_nodes[node.name].grow(pos, node) end - meta:set_int("count", count) + meta:set_int('count', count) return true end end @@ -134,9 +133,9 @@ end function sbz_api.plant_wilt(stages) return function(pos, node) - if core.get_item_group(node.name, "no_wilt") == 0 then + if core.get_item_group(node.name, 'no_wilt') == 0 then node.param2 = node.param2 + 1 - minetest.swap_node(pos, node.param2 >= stages and { name = "air" } or node) + minetest.swap_node(pos, node.param2 >= stages and { name = 'air' } or node) end end end @@ -144,13 +143,14 @@ end function sbz_api.plant_plant(plant, nodes) return sbz_api.on_place_precedence(function(itemstack, user, pointed) for _, node in ipairs(nodes) do - local use_pointed = "above" - if pointed.switched then - use_pointed = "under" - end + local use_pointed = 'above' + if pointed.switched then use_pointed = 'under' end local soil_node = core.get_node(pointed[use_pointed] - up) - if string.sub(node, 1, 6) == "group:" and minetest.get_item_group(soil_node.name, string.sub(node, 7)) > 0 - or soil_node.name == node then + if + string.sub(node, 1, 6) == 'group:' + and minetest.get_item_group(soil_node.name, string.sub(node, 7)) > 0 + or soil_node.name == node + then local _, pos = minetest.item_place_node(ItemStack(plant), user, pointed) if pos then itemstack:take_item() @@ -163,7 +163,7 @@ function sbz_api.plant_plant(plant, nodes) end function sbz_api.register_plant(name, defs) - defs.description = defs.description or "" + defs.description = defs.description or '' defs.drop = defs.drop defs.growth_rate = defs.growth_rate or 1 defs.co2_demand = defs.co2_demand or 0 @@ -178,16 +178,19 @@ function sbz_api.register_plant(name, defs) for i = 1, defs.stages - 1 do local interpolant = (i - 1) / (defs.stages - 1) local height = defs.height_min * (1 - interpolant) + defs.height_max * interpolant - minetest.register_node("sbz_bio:" .. name .. "_" .. i, { + minetest.register_node('sbz_bio:' .. name .. '_' .. i, { description = defs.description, - drawtype = "plantlike", - tiles = { name .. "_" .. i .. ".png" }, - inventory_image = name .. "_" .. i .. ".png", - selection_box = { type = "fixed", fixed = { -defs.width, -0.5, -defs.width, defs.width, height, defs.width } }, - paramtype = "light", + drawtype = 'plantlike', + tiles = { name .. '_' .. i .. '.png' }, + inventory_image = name .. '_' .. i .. '.png', + selection_box = { + type = 'fixed', + fixed = { -defs.width, -0.5, -defs.width, defs.width, height, defs.width }, + }, + paramtype = 'light', sunlight_propagates = true, - paramtype2 = "color", - palette = "wilting_palette.png", + paramtype2 = 'color', + palette = 'wilting_palette.png', walkable = false, groups = { dig_immediate = 2, @@ -200,26 +203,29 @@ function sbz_api.register_plant(name, defs) burn = 1, nb_nodig = 1, no_wilt = defs.no_wilt and 1 or 0, - growth_boost = growth_boost_base * i + growth_boost = growth_boost_base * i, }, drop = {}, growth_tick = sbz_api.plant_growth_tick(defs.growth_rate, defs.mutation_chance or 10), - grow = sbz_api.plant_grow("sbz_bio:" .. name .. "_" .. (i + 1)), + grow = sbz_api.plant_grow('sbz_bio:' .. name .. '_' .. (i + 1)), wilt = sbz_api.plant_wilt(2), sbz_player_inside = defs.sbz_player_inside, - power_per_co2 = power_per_co2_base * i + power_per_co2 = power_per_co2_base * i, }) end - minetest.register_node("sbz_bio:" .. name .. "_" .. defs.stages, { + minetest.register_node('sbz_bio:' .. name .. '_' .. defs.stages, { description = defs.description, - drawtype = "plantlike", - tiles = { name .. "_" .. defs.stages .. ".png" }, - inventory_image = name .. "_" .. defs.stages .. ".png", - selection_box = { type = "fixed", fixed = { -defs.width, -0.5, -defs.width, defs.width, defs.height_max, defs.width } }, - paramtype = "light", + drawtype = 'plantlike', + tiles = { name .. '_' .. defs.stages .. '.png' }, + inventory_image = name .. '_' .. defs.stages .. '.png', + selection_box = { + type = 'fixed', + fixed = { -defs.width, -0.5, -defs.width, defs.width, defs.height_max, defs.width }, + }, + paramtype = 'light', sunlight_propagates = true, - paramtype2 = "color", - palette = "wilting_palette.png", + paramtype2 = 'color', + palette = 'wilting_palette.png', walkable = false, groups = { oddly_breakable_by_hand = 3, @@ -231,35 +237,39 @@ function sbz_api.register_plant(name, defs) not_in_creative_inventory = 1, burn = 1, needs_co2 = defs.use_co2_in_final_stage and defs.co2_demand or 0, - growth_boost = defs.growth_boost + growth_boost = defs.growth_boost, }, drop = defs.drop, sbz_player_inside = defs.sbz_player_inside, power_per_co2 = defs.power_per_co2, - growth_tick = defs.use_co2_in_final_stage and function() return true end, - grow = defs.use_co2_in_final_stage and function() return true end, - wilt = defs.use_co2_in_final_stage and sbz_api.plant_wilt(2) + growth_tick = defs.use_co2_in_final_stage and function() + return true + end, + grow = defs.use_co2_in_final_stage and function() + return true + end, + wilt = defs.use_co2_in_final_stage and sbz_api.plant_wilt(2), }) end -- PYROGRASS FAMILY --Pyrograss, hardy and quick to grow, highly flammable due to its carbon content --To be used in rockets and explosives and stuff -sbz_api.register_plant("pyrograss", { - description = "Pyrograss Plant", - drop = "sbz_bio:pyrograss 2", +sbz_api.register_plant('pyrograss', { + description = 'Pyrograss Plant', + drop = 'sbz_bio:pyrograss 2', growth_rate = 4, - family = "sbz_bio:pyrograss", + family = 'sbz_bio:pyrograss', width = 0.25, height_min = -0.375, height_max = 0, no_wilt = true, }) -minetest.register_craftitem("sbz_bio:pyrograss", { - description = "Pyrograss", - inventory_image = "pyrograss_4.png", +minetest.register_craftitem('sbz_bio:pyrograss', { + description = 'Pyrograss', + inventory_image = 'pyrograss_4.png', groups = { burn = 30, eat = 1 }, - on_place = sbz_api.plant_plant("sbz_bio:pyrograss_1", { "group:soil" }) + on_place = sbz_api.plant_plant('sbz_bio:pyrograss_1', { 'group:soil' }), }) -- uses: @@ -270,48 +280,59 @@ minetest.register_craftitem("sbz_bio:pyrograss", { -- grows slightly slower than pyro -- no co2 demand - -playereffects.register_effect_type("poison", "Poisoned", "fx_poison.png", - { "clearable", "negative", "speed", "health", "negative_health" }, +playereffects.register_effect_type( + 'poison', + 'Poisoned', + 'fx_poison.png', + { 'clearable', 'negative', 'speed', 'health', 'negative_health' }, function(player) - unlock_achievement(player:get_player_name(), "Poisoned") + unlock_achievement(player:get_player_name(), 'Poisoned') player:set_hp(math.max(0, player:get_hp() - 1)) - player_monoids.speed:add_change(player, 0.5, "sbz_bio:poison") - end, function(fx, player) - player_monoids.speed:del_change(player, "sbz_bio:poison") - end, false, true, 2) - -sbz_api.register_plant("razorgrass", { - description = "Razorgrass Plant", - drop = "sbz_bio:razorgrass 2", + player_monoids.speed:add_change(player, 0.5, 'sbz_bio:poison') + end, + function(fx, player) + player_monoids.speed:del_change(player, 'sbz_bio:poison') + end, + false, + true, + 2 +) + +sbz_api.register_plant('razorgrass', { + description = 'Razorgrass Plant', + drop = 'sbz_bio:razorgrass 2', growth_rate = 8, - family = "pyrograss", + family = 'pyrograss', width = 0.25, height_min = -0.375, height_max = 0, sbz_player_inside = function(pos, player) - playereffects.apply_effect_type("poison", 2, player) - end + if not player:is_valid() then return end + player:set_hp(player:get_hp() - 1) + playereffects.apply_effect_type('poison', 2, player) + end, }) core.register_craft { - type = "shapeless", - output = "sbz_bio:fertilizer 20", + type = 'shapeless', + output = 'sbz_bio:fertilizer 20', recipe = { - "sbz_bio:razorgrass", "sbz_bio:razorgrass", "sbz_bio:razorgrass" - } + 'sbz_bio:razorgrass', + 'sbz_bio:razorgrass', + 'sbz_bio:razorgrass', + }, } -minetest.register_craftitem("sbz_bio:razorgrass", { - description = "Razorgrass", - inventory_image = "razorgrass_4.png", +minetest.register_craftitem('sbz_bio:razorgrass', { + description = 'Razorgrass', + inventory_image = 'razorgrass_4.png', groups = { burn = 2, eat = -8 }, - eat_fx = { "Poisoned", "Slowed" }, - on_place = sbz_api.plant_plant("sbz_bio:razorgrass_1", { "group:soil" }), + eat_fx = { 'Poisoned', 'Slowed' }, + on_place = sbz_api.plant_plant('sbz_bio:razorgrass_1', { 'group:soil' }), on_use = function(stack, user, pointed) if user.is_fake_player then return end - playereffects.apply_effect_type("poison", 10, user) + playereffects.apply_effect_type('poison', 10, user) return core.item_eat(-8)(stack, user, pointed) - end + end, }) -- cleargass, uses: @@ -321,49 +342,46 @@ minetest.register_craftitem("sbz_bio:razorgrass", { -- boosts plants near it by 15% when in full growth stage, consumes co2, makes plants consume more co2 -- grows slowly -playereffects.register_effect_type("immune", "Immune", "fx_immunity.png", { "immunity" }, - function(player) - unlock_achievement(player:get_player_name(), "Immune") - playereffects.cancel_effect_group("clearable", player:get_player_name()) - end, function(fx, player) end, false, true, 0.1) +playereffects.register_effect_type('immune', 'Immune', 'fx_immunity.png', { 'immunity' }, function(player) + unlock_achievement(player:get_player_name(), 'Immune') + playereffects.cancel_effect_group('clearable', player:get_player_name()) +end, function(fx, player) end, false, true, 0.1) -sbz_api.register_plant("cleargrass", { - description = "Cleargrass Plant", - drop = "sbz_bio:cleargrass 2", +sbz_api.register_plant('cleargrass', { + description = 'Cleargrass Plant', + drop = 'sbz_bio:cleargrass 2', growth_rate = 4, co2_demand = 5, - family = "pyrograss", + family = 'pyrograss', width = 0.25, height_min = -0.375, height_max = 0, sbz_player_inside = function(pos, player) - playereffects.apply_effect_type("immune", 10, player) + playereffects.apply_effect_type('immune', 10, player) end, use_co2_in_final_stage = true, growth_boost = 25, - }) -minetest.register_craftitem("sbz_bio:cleargrass", { - description = "Cleargrass", - inventory_image = "cleargrass_4.png", +minetest.register_craftitem('sbz_bio:cleargrass', { + description = 'Cleargrass', + inventory_image = 'cleargrass_4.png', groups = { burn = 0, eat = 0 }, - eat_fx = { "Cleared" }, - on_place = sbz_api.plant_plant("sbz_bio:cleargrass_1", { "group:soil" }), + eat_fx = { 'Cleared' }, + on_place = sbz_api.plant_plant('sbz_bio:cleargrass_1', { 'group:soil' }), on_use = function(stack, user, pointed) - playereffects.apply_effect_type("immune", 30 / 0.1, user) + playereffects.apply_effect_type('immune', 30 / 0.1, user) return core.item_eat(0)(stack, user, pointed) - end + end, }) - -- STEMFRUIT: base of all plants --Stemfruit, generic plant, quite versatile --To be used to craft other plants -sbz_api.register_plant("stemfruit_plant", { - description = "Stemfruit Plant", - drop = "sbz_bio:stemfruit 3", - family = "stemfruit", +sbz_api.register_plant('stemfruit_plant', { + description = 'Stemfruit Plant', + drop = 'sbz_bio:stemfruit 3', + family = 'stemfruit', growth_rate = 8, co2_demand = 1, width = 0.125, @@ -372,40 +390,37 @@ sbz_api.register_plant("stemfruit_plant", { mutation_chance = 80, }) -minetest.register_craftitem("sbz_bio:stemfruit", { - description = "Stemfruit", - inventory_image = "stemfruit.png", +minetest.register_craftitem('sbz_bio:stemfruit', { + description = 'Stemfruit', + inventory_image = 'stemfruit.png', groups = { burn = 12, eat = 5 }, on_place = sbz_api.on_place_precedence(function(itemstack, user, pointed) - local use_pointed = "above" - if pointed.switched then - use_pointed = "under" - end + local use_pointed = 'above' + if pointed.switched then use_pointed = 'under' end local soil_node = core.get_node(pointed[use_pointed] - up) local water_node = core.get_node(pointed[use_pointed] + up) - if minetest.get_item_group(soil_node.name, "soil") > 0 then - if core.get_item_group(water_node.name, "water") > 0 then - return core.registered_items["sbz_bio:fiberweed"].on_place(itemstack, user, pointed) + if minetest.get_item_group(soil_node.name, 'soil') > 0 then + if core.get_item_group(water_node.name, 'water') > 0 then + return core.registered_items['sbz_bio:fiberweed'].on_place(itemstack, user, pointed) end - local _, pos = minetest.item_place_node(ItemStack("sbz_bio:stemfruit_plant_1"), user, pointed) + local _, pos = minetest.item_place_node(ItemStack 'sbz_bio:stemfruit_plant_1', user, pointed) if pos then itemstack:take_item() return itemstack end return end - end) --sbz_api.plant_plant("sbz_bio:stemfruit_plant_1", { "group:soil" }) + end), --sbz_api.plant_plant("sbz_bio:stemfruit_plant_1", { "group:soil" }) }) - -- SHROOM FAMILY --Warpshroom, grows slowly, has teleportation powers --To be used later in teleporters -sbz_api.register_plant("warpshroom", { - description = "Warpshroom Plant", - drop = "sbz_bio:warpshroom 2", - family = "warpshroom", +sbz_api.register_plant('warpshroom', { + description = 'Warpshroom Plant', + drop = 'sbz_bio:warpshroom 2', + family = 'warpshroom', growth_rate = 16, co2_demand = 1, width = 0.25, @@ -417,13 +432,17 @@ local warpshroom_teleport_radius = 16 local function teleport_randomly(user) local user_pos = vector.round(user:get_pos()) for _ = 1, 1000 do - local pos = user_pos + - vector.new(math.random(-warpshroom_teleport_radius, warpshroom_teleport_radius), + local pos = user_pos + + vector.new( math.random(-warpshroom_teleport_radius, warpshroom_teleport_radius), - math.random(-warpshroom_teleport_radius, warpshroom_teleport_radius)) - if not minetest.registered_nodes[minetest.get_node(pos).name].walkable + math.random(-warpshroom_teleport_radius, warpshroom_teleport_radius), + math.random(-warpshroom_teleport_radius, warpshroom_teleport_radius) + ) + if + not minetest.registered_nodes[minetest.get_node(pos).name].walkable and not minetest.registered_nodes[minetest.get_node(pos + up).name].walkable - and minetest.registered_nodes[minetest.get_node(pos - up).name].walkable then + and minetest.registered_nodes[minetest.get_node(pos - up).name].walkable + then return user:set_pos(pos - up * 0.5) -- this was missing a "return"... yeah... bad bad end end @@ -431,16 +450,16 @@ end local eat = core.item_eat(6) -minetest.register_craftitem("sbz_bio:warpshroom", { - description = "Warpshroom", - inventory_image = "warpshroom_4.png", - on_place = sbz_api.plant_plant("sbz_bio:warpshroom_1", { "group:matter" }), +minetest.register_craftitem('sbz_bio:warpshroom', { + description = 'Warpshroom', + inventory_image = 'warpshroom_4.png', + on_place = sbz_api.plant_plant('sbz_bio:warpshroom_1', { 'group:matter' }), on_use = function(itemstack, user, pointed) teleport_randomly(user) - unlock_achievement(user:get_player_name(), "Not Chorus Fruit") + unlock_achievement(user:get_player_name(), 'Not Chorus Fruit') return eat(itemstack, user, pointed) end, - groups = { ui_bio = 1, eat = 6 } + groups = { ui_bio = 1, eat = 6 }, }) --[[ minetest.register_craft({ @@ -451,7 +470,7 @@ minetest.register_craft({ ]] -- Shockshroom, +40 power, needs 2 co2 -- ingredient in powered dirt -playereffects.register_effect_type("shocked", "Shocked", "fx_shocked.png", { "clearable", "speed" }, function(player) +playereffects.register_effect_type('shocked', 'Shocked', 'fx_shocked.png', { 'clearable', 'speed' }, function(player) ---modifies the vector, returns it local abs_y = function(vec) vec.y = math.abs(vec.y) @@ -459,13 +478,13 @@ playereffects.register_effect_type("shocked", "Shocked", "fx_shocked.png", { "cl end -- mild loss of control and bad combo with wet - unlock_achievement(player:get_player_name(), "Shocked") + unlock_achievement(player:get_player_name(), 'Shocked') player:add_velocity(vector.multiply(vector.random_direction(), 2)) - player_monoids.speed:add_change(player, 1.2, "sbz_bio:shocked") - if playereffects.has_effect_type(player:get_player_name(), "wet") then + player_monoids.speed:add_change(player, 1.2, 'sbz_bio:shocked') + if playereffects.has_effect_type(player:get_player_name(), 'wet') then player:set_hp(math.max(0, player:get_hp() - 8)) local pos = player:get_pos() - minetest.add_particlespawner({ + minetest.add_particlespawner { amount = 50, time = 0.1, radius = { min = 0.1, max = 0.5 }, @@ -475,93 +494,95 @@ playereffects.register_effect_type("shocked", "Shocked", "fx_shocked.png", { "cl size = { min = 0.5, max = 1 }, collisiondetection = false, vertical = false, - texture = "star.png^[colorize:yellow:255", - glow = 14 - }) + texture = 'star.png^[colorize:yellow:255', + glow = 14, + } player:add_velocity(abs_y(vector.multiply(vector.random_direction(), 8))) - playereffects.cancel_effect_type("shocked", false, player:get_player_name()) + playereffects.cancel_effect_type('shocked', false, player:get_player_name()) end end, function(fx, player) - player_monoids.speed:del_change(player, "sbz_bio:shocked") + player_monoids.speed:del_change(player, 'sbz_bio:shocked') end, false, true, 0.5) -sbz_api.register_plant("shockshroom", { - description = "Shockshroom Plant", - drop = "sbz_bio:shockshroom 2", - family = "warpshroom", +sbz_api.register_plant('shockshroom', { + description = 'Shockshroom Plant', + drop = 'sbz_bio:shockshroom 2', + family = 'warpshroom', growth_rate = 6, co2_demand = 2, width = 0.25, height_min = -0.3125, height_max = 0.25, sbz_player_inside = function(pos, player) - playereffects.apply_effect_type("shocked", 2 / 0.5, player) + playereffects.apply_effect_type('shocked', 2 / 0.5, player) end, power_per_co2 = 30, use_co2_in_final_stage = true, }) -minetest.register_craftitem("sbz_bio:shockshroom", { - description = "Shockshroom", - inventory_image = "shockshroom_4.png", - on_place = sbz_api.plant_plant("sbz_bio:shockshroom_1", { "group:soil" }), +minetest.register_craftitem('sbz_bio:shockshroom', { + description = 'Shockshroom', + inventory_image = 'shockshroom_4.png', + on_place = sbz_api.plant_plant('sbz_bio:shockshroom_1', { 'group:soil' }), groups = { ui_bio = 1, eat = -1 }, on_use = function(stack, user, pointed) if user.is_fake_player then return end - playereffects.apply_effect_type("shocked", 180 / 0.5, user, 0.5) + playereffects.apply_effect_type('shocked', 180 / 0.5, user, 0.5) return core.item_eat(-1)(stack, user, pointed) - end + end, }) -- STARFRUIT FAMILY (unlike the others, there is no base "starfruit" plant) -- todo - --Fiberweed, multi-node seaweed which grows vertically, requires water along its entire stem --To be used in making string and fabric for various uses local function is_all_water(pos, leveled) for i = 1, math.ceil(leveled / 16) do local nodename = minetest.get_node(pos + up * i).name - if nodename ~= "sbz_resources:water_source" and nodename ~= "sbz_resources:water_flowing" then return false end + if nodename ~= 'sbz_resources:water_source' and nodename ~= 'sbz_resources:water_flowing' then return false end end return true end -minetest.register_node("sbz_bio:fiberweed", { - description = "Fiberweed", - drawtype = "plantlike_rooted", - tiles = { "dirt.png^fiberweed_overlay.png", "dirt.png" }, - special_tiles = { { name = "fiberweed_plant.png", tileable_vertical = true } }, - inventory_image = "fiberweed_plant.png", - selection_box = { type = "fixed", fixed = { { -0.5, -0.5, -0.5, 0.5, 0.5, 0.5 }, { -0.25, 0.5, -0.25, 0.25, 1.25, 0.25 } } }, - paramtype2 = "leveled", +minetest.register_node('sbz_bio:fiberweed', { + description = 'Fiberweed', + drawtype = 'plantlike_rooted', + tiles = { 'dirt.png^fiberweed_overlay.png', 'dirt.png' }, + special_tiles = { { name = 'fiberweed_plant.png', tileable_vertical = true } }, + inventory_image = 'fiberweed_plant.png', + selection_box = { + type = 'fixed', + fixed = { { -0.5, -0.5, -0.5, 0.5, 0.5, 0.5 }, { -0.25, 0.5, -0.25, 0.25, 1.25, 0.25 } }, + }, + paramtype2 = 'leveled', place_param2 = 8, groups = { matter = 1, plant = 1, needs_co2 = 1, transparent = 1, burn = 2 }, drop = {}, - node_dig_prediction = "sbz_bio:dirt", - node_placement_prediction = "", + node_dig_prediction = 'sbz_bio:dirt', + node_placement_prediction = '', on_place = function(itemstack, user, pointed) - if pointed.type ~= "node" or minetest.get_node(pointed.under).name ~= "sbz_bio:dirt" then return end - minetest.set_node(pointed.under, { name = "sbz_bio:fiberweed", param2 = 8 }) + if pointed.type ~= 'node' or minetest.get_node(pointed.under).name ~= 'sbz_bio:dirt' then return end + minetest.set_node(pointed.under, { name = 'sbz_bio:fiberweed', param2 = 8 }) itemstack:take_item() return itemstack end, after_dig_node = function(pos, node, meta, user) - minetest.set_node(pos, { name = "sbz_bio:dirt" }) - unlock_achievement(user:get_player_name(), "Fiberweed") + minetest.set_node(pos, { name = 'sbz_bio:dirt' }) + unlock_achievement(user:get_player_name(), 'Fiberweed') local inv = user:get_inventory() - local drop = inv:add_item("main", "sbz_bio:fiberweed " .. math.floor(node.param2 / 8)) + local drop = inv:add_item('main', 'sbz_bio:fiberweed ' .. math.floor(node.param2 / 8)) if drop then minetest.add_item(pos + up, drop) end end, growth_tick = function(pos, node) if sbz_api.get_node_heat(pos + up) > 7 and is_all_water(pos, node.param2) then local meta = minetest.get_meta(pos) - local count = meta:get_int("count") + 1 + local count = meta:get_int 'count' + 1 if count >= 4 then count = 0 minetest.registered_nodes[node.name].grow(pos, node) end - meta:set_int("count", count) + meta:set_int('count', count) return true end end, @@ -573,8 +594,8 @@ minetest.register_node("sbz_bio:fiberweed", { end, wilt = function(pos, node) node.param2 = node.param2 - 8 - minetest.swap_node(pos, node.param2 <= 0 and { name = "sbz_bio:dirt" } or node) - end + minetest.swap_node(pos, node.param2 <= 0 and { name = 'sbz_bio:dirt' } or node) + end, }) --[[ minetest.register_craft({ From 6a86e7211a6d96ae3bc9c4c2e4fd919ea8897e56 Mon Sep 17 00:00:00 2001 From: TheEt1234 Date: Sat, 10 Jan 2026 18:41:28 +0100 Subject: [PATCH 24/28] Balance autocrafter crafting processors --- CHANGELOG.md | 8 + README.md | 21 +- mods/sbz_decor/init.lua | 420 ++++++++++-------- mods/sbz_meteorites/visualiser.lua | 76 ++-- mods/sbz_pipeworks/autocrafter.lua | 33 +- mods/sbz_power/init.lua | 2 +- mods/sbz_power/manual_crafter.lua | 5 +- mods/sbz_progression/annoy.lua | 32 +- mods/sbz_progression/quests/Introduction.md | 35 +- mods/sbz_progression/quests/Meteorites.md | 17 +- .../quests/Pipeworks_and_fluid_transport.md | 9 +- mods/sbz_progression/quests/Storage.md | 40 +- .../sbz_resources/processors_and_circuits.lua | 342 ++++++++------ ...eedlessly_expensive_crafting_processor.png | Bin 0 -> 240 bytes ...black_hole_whatever_crafting_processor.png | Bin 0 -> 303 bytes mods/sbz_resources/tools.lua | 118 +++-- 16 files changed, 630 insertions(+), 528 deletions(-) create mode 100644 mods/sbz_resources/textures/needlessly_expensive_crafting_processor.png create mode 100644 mods/sbz_resources/textures/omega_quantum_black_hole_whatever_crafting_processor.png diff --git a/CHANGELOG.md b/CHANGELOG.md index e9df0cba..98e473c0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,12 @@ # Release 40 +- Development resumed again! + - We are still looking for contributors, if you enjoy SBZ and want to contribute, please do so! +- **Fixed various bugs** - main point of the release +- Added new background music +- Reworked autocrafters (They now require a crafting processor, old autocrafters will remain functioning with 1 craft/s speed) +- Made robotic arms and annihilators stackable, and removed wear from them +- Made manual crafters slightly cheaper +- Re-worded some quests to be more..... readable # Release 38 diff --git a/README.md b/README.md index 67957234..e62784fd 100644 --- a/README.md +++ b/README.md @@ -3,16 +3,16 @@ Start from absolutely nothing in a skyblock world. Time is your resource. Get lo ## Playing There is an in-game Quest Book to get you started. Have fun!
-- **Please report bugs in the package threads, i will fix them ASAP.** +- **Please report bugs in the package threads or github issues, i will fix them ASAP.**
I have included a CHANGELOG.md with the download for those interested. ## Licenses -Code: Zander (content db: @zanderdev) GPL-3.0
-Textures: Zander (content db: @zanderdev) CC BY-SA 4.0
-See LICENSE.txt (for code) and LICENSE-TEXTURES.txt for more information. -IMPORTANT: Part of the code may be licensed diffrently. Make sure to check if there are any other notices. -This Game uses part of the code of Mesecons, Minetest Game, and potentially others. Their licenses can be found inside the repository. +Code: Zander and contributors GPL-3.0
+Textures: Zander and contributors CC BY-SA 4.0
+See LICENSE.txt (for code) and LICENSE-TEXTURES.txt for more information.
+ +Also: Parts of the code/other mods may be licensed differently. Make sure to check if there are any other notices. ## Soundtrack & SFX #### Main Menu @@ -30,6 +30,7 @@ Art by StumpyStrust, CC0, https://opengameart.org/content/space-skyboxes-0 - A Choice With Many Regrets by Tsorthan Grove, CC-BY 4.0, https://opengameart.org/content/a-choice-with-many-regrets #### SFX + - hard_drive_shut_down_01.wav by Noisehag -- https://freesound.org/s/110552/ -- License: Creative Commons 0 - [SFX Hit] deep kick boom by waveplaySFX -- https://freesound.org/s/231349/ -- License: Attribution 4.0 - 5.wav by steveygos93 -- https://freesound.org/s/103585/ -- License: Attribution 3.0 @@ -39,10 +40,10 @@ Art by StumpyStrust, CC0, https://opengameart.org/content/space-skyboxes-0 - MP5 Mag In (2) pt2.ogg by smill.and.welson -- https://freesound.org/s/698840/ -- License: Attribution 4.0 - pop.ogg by dodrio -- https://freesound.org/s/554022/ -- License: Creative Commons 0 - Page Turn by redagee -- https://freesound.org/s/737004/ -- License: Creative Commons 0 -- https://pixabay.com/sound-effects/rocket-loop-99748/ -- https://pixabay.com/sound-effects/distant-explosion-47562/ & https://pixabay.com/sound-effects/explosion-80108/ (edited) -- https://pixabay.com/sound-effects/door-lock-43124/ -- https://pixabay.com/sound-effects/050597-ice-crusher-38522/ (edited) +- Rocket Loop by Mozfoo -- https://freesound.org/s/458377/ -- License: Creative Commons 0 +- Explosion by morganpurkis -- https://freesound.org/s/397691/ -- License: Creative Commons 0 *AND* Distant Explosion by VanEngelen -- https://freesound.org/s/784660/ -- License: Creative Commons 0 (edited togheter) +- Door Lock by dster777 -- https://freesound.org/s/344551/ -- License: Creative Commons 0 +- Ice Crusher by karinalarasart -- https://freesound.org/s/440759/ -- License: Creative Commons 0 (edited) - https://freesound.org/people/dibko/sounds/619103/ -- License: Attribution 4.0 (edited) - https://freesound.org/people/newlocknew/sounds/536655/ -- License: Attribution 4.0 - https://freesound.org/people/MilanKovanda/sounds/624414/ -- License: Attribution 4.0 diff --git a/mods/sbz_decor/init.lua b/mods/sbz_decor/init.lua index d2dcf63d..97583511 100644 --- a/mods/sbz_decor/init.lua +++ b/mods/sbz_decor/init.lua @@ -1,150 +1,172 @@ -local modpath = minetest.get_modpath("sbz_decor") +local modpath = minetest.get_modpath 'sbz_decor' - -minetest.register_node("sbz_decor:photonlamp", { - description = "Photon Lamp", - drawtype = "mesh", - mesh = "photonlamp.obj", - tiles = { "photonlamp.png" }, +minetest.register_node('sbz_decor:photonlamp', { + description = 'Photon Lamp', + drawtype = 'mesh', + mesh = 'photonlamp.obj', + tiles = { 'photonlamp.png' }, groups = { matter = 1, habitat_conducts = 1, }, light_source = 14, selection_box = { - type = "fixed", + type = 'fixed', fixed = { -0.2, -0.2, -0.2, 0.2, 0.2, 0.2 }, }, collision_box = { - type = "fixed", + type = 'fixed', fixed = { -0.2, -0.2, -0.2, 0.2, 0.2, 0.2 }, }, - use_texture_alpha = "clip", + use_texture_alpha = 'clip', }) -minetest.register_craft({ - output = "sbz_decor:photonlamp", +minetest.register_craft { + output = 'sbz_decor:photonlamp', recipe = { - { "sbz_resources:matter_plate", "sbz_resources:emitter_imitator", "sbz_resources:matter_plate" }, - { "sbz_resources:emitter_imitator", "sbz_resources:matter_blob", "sbz_resources:emitter_imitator" }, - { "sbz_resources:matter_plate", "sbz_resources:emitter_imitator", "sbz_resources:matter_plate" } - } -}) - + { 'sbz_resources:matter_plate', 'sbz_resources:emitter_imitator', 'sbz_resources:matter_plate' }, + { 'sbz_resources:emitter_imitator', 'sbz_resources:matter_blob', 'sbz_resources:emitter_imitator' }, + { 'sbz_resources:matter_plate', 'sbz_resources:emitter_imitator', 'sbz_resources:matter_plate' }, + }, +} -minetest.register_node("sbz_decor:factory_floor", unifieddyes.def { - description = "Factory Floor", - tiles = { "factory_floor.png" }, - groups = { matter = 1, cracky = 3, explody = 3, moss_growable = 1 }, - sunlight_propagates = true, - walkable = true, - sounds = sbz_api.sounds.matter(), -}) -minetest.register_craft({ - output = "sbz_decor:factory_floor 2", - type = "shapeless", - recipe = { - "sbz_resources:matter_blob", - "sbz_resources:matter_blob", - "sbz_resources:matter_blob", - "sbz_resources:matter_blob" +minetest.register_node( + 'sbz_decor:factory_floor', + unifieddyes.def { + description = 'Factory Floor', + tiles = { 'factory_floor.png' }, + groups = { matter = 1, cracky = 3, explody = 3, moss_growable = 1 }, + sunlight_propagates = true, + walkable = true, + sounds = sbz_api.sounds.matter(), } -}) +) +minetest.register_craft { + output = 'sbz_decor:factory_floor 2', + type = 'shapeless', + recipe = { + 'sbz_resources:matter_blob', + 'sbz_resources:matter_blob', + 'sbz_resources:matter_blob', + 'sbz_resources:matter_blob', + }, +} -stairs.register("sbz_decor:factory_floor", { - stair_front = "factory_floor_sf.png", - stair_side = "factory_floor_ss.png", - stair_cross = "factory_floor_sc.png" +stairs.register('sbz_decor:factory_floor', { + stair_front = 'factory_floor_sf.png', + stair_side = 'factory_floor_ss.png', + stair_cross = 'factory_floor_sc.png', }) -minetest.register_node("sbz_decor:factory_floor_tiling", unifieddyes.def { - description = "Factory Floor (Tiled)", - tiles = { "factory_floor_tiling.png" }, - groups = { matter = 1, cracky = 3, explody = 3, moss_growable = 1, ud_param2_colorable = 1 }, - sunlight_propagates = true, - walkable = true, - sounds = sbz_api.sounds.matter(), -}) +minetest.register_node( + 'sbz_decor:factory_floor_tiling', + unifieddyes.def { + description = 'Factory Floor (Tiled)', + tiles = { 'factory_floor_tiling.png' }, + groups = { matter = 1, cracky = 3, explody = 3, moss_growable = 1, ud_param2_colorable = 1 }, + sunlight_propagates = true, + walkable = true, + sounds = sbz_api.sounds.matter(), + } +) -stairs.register("sbz_decor:factory_floor_tiling") +stairs.register 'sbz_decor:factory_floor_tiling' -minetest.register_craft({ - output = "sbz_decor:factory_floor_tiling 4", - type = "shapeless", - recipe = { "sbz_decor:factory_floor", "sbz_decor:factory_floor", "sbz_decor:factory_floor", "sbz_decor:factory_floor" } -}) +minetest.register_craft { + output = 'sbz_decor:factory_floor_tiling 4', + type = 'shapeless', + recipe = { + 'sbz_decor:factory_floor', + 'sbz_decor:factory_floor', + 'sbz_decor:factory_floor', + 'sbz_decor:factory_floor', + }, +} -minetest.register_node("sbz_decor:factory_ventilator", { - description = "Factory Ventilator", +minetest.register_node('sbz_decor:factory_ventilator', { + description = 'Factory Ventilator', tiles = { - { name = "factory_ventilator.png", animation = { type = "vertical_frames", length = 1 } }, + { name = 'factory_ventilator.png', animation = { type = 'vertical_frames', length = 1 } }, }, groups = { matter = 1, cracky = 3, explody = 3, moss_growable = 1 }, sunlight_propagates = true, walkable = true, sounds = sbz_api.sounds.matter(), }) -minetest.register_craft({ - output = "sbz_decor:factory_ventilator", - type = "shapeless", - recipe = { "sbz_decor:factory_floor", "sbz_decor:factory_floor", "sbz_chem:lithium_powder", "sbz_chem:cobalt_powder" } -}) +minetest.register_craft { + output = 'sbz_decor:factory_ventilator', + type = 'shapeless', + recipe = { + 'sbz_decor:factory_floor', + 'sbz_decor:factory_floor', + 'sbz_chem:lithium_powder', + 'sbz_chem:cobalt_powder', + }, +} -minetest.register_node("sbz_decor:factory_warning", unifieddyes.def { - description = "Factory Warning", - tiles = { "factory_warning.png" }, - groups = { matter = 1, cracky = 3, explody = 3, moss_growable = 1 }, - sunlight_propagates = true, - walkable = true, - sounds = sbz_api.sounds.matter(), -}) -stairs.register("sbz_decor:factory_warning") -minetest.register_craft({ - output = "sbz_decor:factory_warning 4", - type = "shapeless", - recipe = { "sbz_decor:factory_floor", "sbz_decor:factory_floor", "sbz_chem:gold_powder", "sbz_chem:gold_powder" } -}) +minetest.register_node( + 'sbz_decor:factory_warning', + unifieddyes.def { + description = 'Factory Warning', + tiles = { 'factory_warning.png' }, + groups = { matter = 1, cracky = 3, explody = 3, moss_growable = 1 }, + sunlight_propagates = true, + walkable = true, + sounds = sbz_api.sounds.matter(), + } +) +stairs.register 'sbz_decor:factory_warning' +minetest.register_craft { + output = 'sbz_decor:factory_warning 4', + type = 'shapeless', + recipe = { 'sbz_decor:factory_floor', 'sbz_decor:factory_floor', 'sbz_chem:gold_powder', 'sbz_chem:gold_powder' }, +} -minetest.register_node("sbz_decor:mystery_terrarium", { - description = "Mystery Terrarium", +minetest.register_node('sbz_decor:mystery_terrarium', { + description = 'Mystery Terrarium', tiles = { - { name = "mystery_terrarium.png", animation = { type = "vertical_frames", length = 1 } }, + { name = 'mystery_terrarium.png', animation = { type = 'vertical_frames', length = 1 } }, }, - groups = { matter = 1, cracky = 3, explody = 3}, + groups = { matter = 1, cracky = 3, explody = 3 }, sunlight_propagates = true, walkable = true, sounds = sbz_api.sounds.matter(), }) -minetest.register_craft({ - output = "sbz_decor:mystery_terrarium", - type = "shapeless", - recipe = {"sbz_bio:habitat_regulator", "sbz_bio:screen_inverter_potion", "sbz_chem:thorium_fluid_cell"} -}) +minetest.register_craft { + output = 'sbz_decor:mystery_terrarium', + type = 'shapeless', + recipe = { 'sbz_bio:habitat_regulator', 'sbz_bio:screen_inverter_potion', 'sbz_chem:thorium_fluid_cell' }, +} -minetest.register_node("sbz_decor:large_server_rack", { - description = "Large Server Rack", - tiles = { -- how do i make it turn depending on how the player places it? - { name = "large_server_rack_back.png" }, - { name = "large_server_rack_back.png" }, - { name = "large_server_rack.png", animation = { type = "vertical_frames", length = 3 } }, - { name = "large_server_rack_back.png" }, - { name = "large_server_rack_back.png" }, - { name = "large_server_rack_back.png" }, - }, - groups = { matter = 1, cracky = 3, explody = 3}, - light_source = 10, - sunlight_propagates = true, - walkable = true, - sounds = sbz_api.sounds.matter(), -}) -minetest.register_craft({ - output = "sbz_decor:large_server_rack", - type = "shapeless", - recipe = {"sbz_resources:simple_processor 100", "sbz_logic:lua_controller_off", "sbz_resources:ram_stick_1mb 100"} -}) +minetest.register_node( + 'sbz_decor:large_server_rack', + unifieddyes.def { + description = 'Large Server Rack', + info_extra = 'Just decoration.', + tiles = { + { name = 'large_server_rack_back.png' }, + { name = 'large_server_rack_back.png' }, + { name = 'large_server_rack.png', animation = { type = 'vertical_frames', length = 3 } }, + { name = 'large_server_rack_back.png' }, + { name = 'large_server_rack_back.png' }, + { name = 'large_server_rack_back.png' }, + }, + paramtype2 = 'colorfacedir', + groups = { matter = 1, cracky = 3, explody = 3 }, + light_source = 10, + sunlight_propagates = true, + sounds = sbz_api.sounds.matter(), + } +) -local MP = minetest.get_modpath("sbz_decor") -dofile(MP .. "/signs.lua") -dofile(MP .. "/cnc.lua") +minetest.register_craft { + output = 'sbz_decor:large_server_rack', + type = 'shapeless', + recipe = { 'sbz_resources:matter_blob', 'sbz_resources:luanium' }, +} + +local MP = minetest.get_modpath 'sbz_decor' +dofile(MP .. '/signs.lua') +dofile(MP .. '/cnc.lua') -- now... Ladders -- inspired by what i saw from mtg ladders @@ -153,7 +175,7 @@ local ladder_autoplace_limit = 16 local get_ladder_on_place = function(ladder_name) return sbz_api.on_place_precedence(function(stack, placer, pointed, recursed) if (recursed or 0) > ladder_autoplace_limit then return end - if pointed.type == "node" then + if pointed.type == 'node' then local target = pointed.under local node = core.get_node(target) if node.name == ladder_name then @@ -162,8 +184,8 @@ local get_ladder_on_place = function(ladder_name) pointed.under = vector.add(pointed.under, up) pointed.above = vector.add(pointed.above, up) if core.get_node(pointed.under).name == ladder_name then - local result = minetest.registered_nodes[ladder_name].on_place(stack, placer, pointed, - (recursed or 0) + 1) + local result = + minetest.registered_nodes[ladder_name].on_place(stack, placer, pointed, (recursed or 0) + 1) return result end return core.item_place_node(stack, placer, pointed, node.param2) @@ -173,93 +195,109 @@ local get_ladder_on_place = function(ladder_name) end) end -core.register_node("sbz_decor:ladder", unifieddyes.def { - description = "Matter Ladder", - drawtype = "nodebox", - node_box = { -- nodebox inspired by that one 3d ladders mod, but i made this myself with nodebox editor - type = "fixed", - fixed = { - { -0.5, -0.5, 0.375, -0.375, 0.5, 0.5 }, -- NodeBox1 - { 0.375, -0.5, 0.375, 0.5, 0.5, 0.5 }, -- NodeBox3 - { -0.375, 0.3125, 0.375, 0.375, 0.4375, 0.5 }, -- NodeBox5 - { -0.375, 0.0625, 0.375, 0.375, 0.1875, 0.5 }, -- NodeBox8 - { -0.375, -0.1875, 0.375, 0.375, -0.0625, 0.5 }, -- NodeBox9 - { -0.375, -0.4375, 0.375, 0.375, -0.3125, 0.5 }, -- NodeBox10 - } - }, - selection_box = { - type = "fixed", - fixed = { - -8 / 16, -8 / 16, 3 / 16, 8 / 16, 8 / 16, 8 / 16 - } - }, - tiles = { "matter_blob.png" }, - inventory_image = "ladder.png", - groups = { - matter = 3, - explody = 3, - habitat_conducts = 1, - }, - paramtype = "light", - paramtype2 = "facedir", - sunlight_propagates = true, - on_place = get_ladder_on_place("sbz_decor:ladder"), - node_placement_prediction = "", - climbable = true, -}) +core.register_node( + 'sbz_decor:ladder', + unifieddyes.def { + description = 'Matter Ladder', + drawtype = 'nodebox', + node_box = { -- nodebox inspired by that one 3d ladders mod, but i made this myself with nodebox editor + type = 'fixed', + fixed = { + { -0.5, -0.5, 0.375, -0.375, 0.5, 0.5 }, -- NodeBox1 + { 0.375, -0.5, 0.375, 0.5, 0.5, 0.5 }, -- NodeBox3 + { -0.375, 0.3125, 0.375, 0.375, 0.4375, 0.5 }, -- NodeBox5 + { -0.375, 0.0625, 0.375, 0.375, 0.1875, 0.5 }, -- NodeBox8 + { -0.375, -0.1875, 0.375, 0.375, -0.0625, 0.5 }, -- NodeBox9 + { -0.375, -0.4375, 0.375, 0.375, -0.3125, 0.5 }, -- NodeBox10 + }, + }, + selection_box = { + type = 'fixed', + fixed = { + -8 / 16, + -8 / 16, + 3 / 16, + 8 / 16, + 8 / 16, + 8 / 16, + }, + }, + tiles = { 'matter_blob.png' }, + inventory_image = 'ladder.png', + groups = { + matter = 3, + explody = 3, + habitat_conducts = 1, + }, + paramtype = 'light', + paramtype2 = 'facedir', + sunlight_propagates = true, + on_place = get_ladder_on_place 'sbz_decor:ladder', + node_placement_prediction = '', + climbable = true, + } +) -core.register_node("sbz_decor:antimatter_ladder", unifieddyes.def { - description = "Antimatter Ladder", - drawtype = "nodebox", - node_box = { -- nodebox inspired by that one 3d ladders mod, but i made this myself with nodebox editor - type = "fixed", - fixed = { - { -0.5, -0.5, 0.375, -0.375, 0.5, 0.5 }, -- NodeBox1 - { 0.375, -0.5, 0.375, 0.5, 0.5, 0.5 }, -- NodeBox3 - { -0.375, 0.3125, 0.375, 0.375, 0.4375, 0.5 }, -- NodeBox5 - { -0.375, 0.0625, 0.375, 0.375, 0.1875, 0.5 }, -- NodeBox8 - { -0.375, -0.1875, 0.375, 0.375, -0.0625, 0.5 }, -- NodeBox9 - { -0.375, -0.4375, 0.375, 0.375, -0.3125, 0.5 }, -- NodeBox10 - } - }, - selection_box = { - type = "fixed", - fixed = { - -8 / 16, -8 / 16, 3 / 16, 8 / 16, 8 / 16, 8 / 16 - } - }, - tiles = { "antimatter_blob.png" }, - inventory_image = "antimatter_ladder.png", - groups = { - matter = 3, - explody = 3, - habitat_conducts = 1, - }, - light_source = 3, - paramtype = "light", - paramtype2 = "colorfacedir", --"facedir", - sunlight_propagates = true, - on_place = get_ladder_on_place("sbz_decor:antimatter_ladder"), - node_placement_prediction = "", - climbable = true, -}) +core.register_node( + 'sbz_decor:antimatter_ladder', + unifieddyes.def { + description = 'Antimatter Ladder', + drawtype = 'nodebox', + node_box = { -- nodebox inspired by that one 3d ladders mod, but i made this myself with nodebox editor + type = 'fixed', + fixed = { + { -0.5, -0.5, 0.375, -0.375, 0.5, 0.5 }, -- NodeBox1 + { 0.375, -0.5, 0.375, 0.5, 0.5, 0.5 }, -- NodeBox3 + { -0.375, 0.3125, 0.375, 0.375, 0.4375, 0.5 }, -- NodeBox5 + { -0.375, 0.0625, 0.375, 0.375, 0.1875, 0.5 }, -- NodeBox8 + { -0.375, -0.1875, 0.375, 0.375, -0.0625, 0.5 }, -- NodeBox9 + { -0.375, -0.4375, 0.375, 0.375, -0.3125, 0.5 }, -- NodeBox10 + }, + }, + selection_box = { + type = 'fixed', + fixed = { + -8 / 16, + -8 / 16, + 3 / 16, + 8 / 16, + 8 / 16, + 8 / 16, + }, + }, + tiles = { 'antimatter_blob.png' }, + inventory_image = 'antimatter_ladder.png', + groups = { + matter = 3, + explody = 3, + habitat_conducts = 1, + }, + light_source = 3, + paramtype = 'light', + paramtype2 = 'colorfacedir', --"facedir", + sunlight_propagates = true, + on_place = get_ladder_on_place 'sbz_decor:antimatter_ladder', + node_placement_prediction = '', + climbable = true, + } +) -core.register_alias_force("sbz_decor:anitmatter_ladder", "sbz_decor:antimatter_ladder") +core.register_alias_force('sbz_decor:anitmatter_ladder', 'sbz_decor:antimatter_ladder') core.register_craft { - output = "sbz_decor:antimatter_ladder 12", + output = 'sbz_decor:antimatter_ladder 12', recipe = { - { "sbz_resources:antimatter_blob", "", "sbz_resources:antimatter_blob", }, - { "sbz_resources:antimatter_blob", "sbz_resources:antimatter_blob", "sbz_resources:antimatter_blob", }, - { "sbz_resources:antimatter_blob", "", "sbz_resources:antimatter_blob", }, - } + { 'sbz_resources:antimatter_blob', '', 'sbz_resources:antimatter_blob' }, + { 'sbz_resources:antimatter_blob', 'sbz_resources:antimatter_blob', 'sbz_resources:antimatter_blob' }, + { 'sbz_resources:antimatter_blob', '', 'sbz_resources:antimatter_blob' }, + }, } core.register_craft { - output = "sbz_decor:ladder 12", + output = 'sbz_decor:ladder 12', recipe = { - { "sbz_resources:matter_blob", "", "sbz_resources:matter_blob", }, - { "sbz_resources:matter_blob", "sbz_resources:matter_blob", "sbz_resources:matter_blob", }, - { "sbz_resources:matter_blob", "", "sbz_resources:matter_blob", }, - } + { 'sbz_resources:matter_blob', '', 'sbz_resources:matter_blob' }, + { 'sbz_resources:matter_blob', 'sbz_resources:matter_blob', 'sbz_resources:matter_blob' }, + { 'sbz_resources:matter_blob', '', 'sbz_resources:matter_blob' }, + }, } diff --git a/mods/sbz_meteorites/visualiser.lua b/mods/sbz_meteorites/visualiser.lua index 239d9158..19ff0ad8 100644 --- a/mods/sbz_meteorites/visualiser.lua +++ b/mods/sbz_meteorites/visualiser.lua @@ -1,25 +1,27 @@ -sbz_api.register_machine("sbz_meteorites:meteorite_radar", { +sbz_api.register_machine('sbz_meteorites:meteorite_radar', { disallow_pipeworks = true, - description = "Meteorite Radar", - drawtype = "mesh", - paramtype = "light", - mesh = "meteorite_radar.obj", - tiles = { "meteorite_radar.png" }, + description = 'Meteorite Radar', + info_extra = "Detects if meteorites are nearby. Uses 10Cj if there aren't, uses 40Cj if there are.", + drawtype = 'mesh', + paramtype = 'light', + mesh = 'meteorite_radar.obj', + tiles = { 'meteorite_radar.png' }, collision_box = { - type = "fixed", - fixed = { -0.5, -0.5, -0.5, 0.5, 0.25, 0.5 } + type = 'fixed', + fixed = { -0.5, -0.5, -0.5, 0.5, 0.25, 0.5 }, }, selection_box = { - type = "fixed", - fixed = { -0.5, -0.5, -0.5, 0.5, 0.25, 0.5 } + type = 'fixed', + fixed = { -0.5, -0.5, -0.5, 0.5, 0.25, 0.5 }, }, groups = { matter = 1 }, - power_needed = 20, - action_interval = 0, + power_needed = 40, on_construct = function(pos) - minetest.sound_play({ name = "machine_build" }, { pos = pos }) + minetest.sound_play({ name = 'machine_build' }, { pos = pos }) end, action = function(radar_pos) + local power_consume = 10 + local players = {} local meteorites = {} local attractors = {} @@ -28,31 +30,28 @@ sbz_api.register_machine("sbz_meteorites:meteorite_radar", { if obj then local entity = obj:get_luaentity() if not entity then - if obj:is_player() then - table.insert(players, obj:get_player_name()) - end - elseif entity.name == "sbz_meteorites:meteorite" then + if obj:is_player() then table.insert(players, obj:get_player_name()) end + elseif entity.name == 'sbz_meteorites:meteorite' then table.insert(meteorites, obj) - elseif entity.name == "sbz_meteorites:gravitational_attractor_entity" then + elseif entity.name == 'sbz_meteorites:gravitational_attractor_entity' then table.insert(entity.type < 0 and repulsors or attractors, vector.round(obj:get_pos())) end end end if #meteorites > 0 then - minetest.add_particle({ + minetest.add_particle { pos = radar_pos + vector.new(0, 1.5, 0), expiration_time = 1, size = 10, - texture = "antenna.png", - animation = { type = "vertical_frames", aspect_width = 18, aspect_height = 18, length = 0.5 }, - glow = 14 - }) + texture = 'antenna.png', + animation = { type = 'vertical_frames', aspect_width = 18, aspect_height = 18, length = 0.5 }, + glow = 14, + } - minetest.sound_play( - { name = "alarm", gain = 0.7 }, - { pos = radar_pos, max_hear_distance = 64 } - ) + minetest.sound_play({ name = 'alarm', gain = 0.7 }, { pos = radar_pos, max_hear_distance = 64 }) + power_consume = 40 end + for _, obj in ipairs(meteorites) do obj:get_luaentity():show_waypoint() local pos = obj:get_pos() @@ -69,27 +68,28 @@ sbz_api.register_machine("sbz_meteorites:meteorite_radar", { end local collides = minetest.registered_nodes[minetest.get_node(vector.round(pos)).name].walkable for _, player in ipairs(players) do - minetest.add_particle({ + minetest.add_particle { pos = pos, expiration_time = 1, size = collides and 50 or 10, - texture = "visualiser_trail.png", - animation = { type = "vertical_frames", aspect_width = 8, aspect_height = 8, length = 0.2 }, + texture = 'visualiser_trail.png', + animation = { type = 'vertical_frames', aspect_width = 8, aspect_height = 8, length = 0.2 }, glow = 14, - playername = player - }) + playername = player, + } end if collides then break end end end - end + return power_consume + end, }) core.register_craft { - output = "sbz_meteorites:meteorite_radar", + output = 'sbz_meteorites:meteorite_radar', recipe = { - { "", "sbz_chem:titanium_alloy_ingot", "" }, - { "", "sbz_chem:titanium_alloy_ingot", "" }, - { "sbz_resources:reinforced_matter", "sbz_resources:prediction_circuit", "sbz_resources:reinforced_matter" } - } + { '', 'sbz_chem:titanium_alloy_ingot', '' }, + { '', 'sbz_chem:titanium_alloy_ingot', '' }, + { 'sbz_resources:reinforced_matter', 'sbz_resources:prediction_circuit', 'sbz_resources:reinforced_matter' }, + }, } diff --git a/mods/sbz_pipeworks/autocrafter.lua b/mods/sbz_pipeworks/autocrafter.lua index 0e52edc0..8a1dca12 100644 --- a/mods/sbz_pipeworks/autocrafter.lua +++ b/mods/sbz_pipeworks/autocrafter.lua @@ -329,15 +329,16 @@ end local function update_meta(pos, meta) reserve_slots(pos, meta) local fs = 'formspec_version[7]' - .. 'size[11.4,10.5]' + .. 'size[11.4,11]' .. 'list[context;recipe;0.22,0.22;3,3;]' .. 'image[4,1.45;1,1;[combine:16x16^[noalpha^[colorize:#141318:255]' .. 'list[context;output;4,1.45;1,1;]' + .. 'item_image[4,2.7;1,1;sbz_resources:simple_crafting_processor]' .. 'list[context;processor;4,2.7;1,1;]' .. 'list[context;dst;5.28,0.22;4,3;]' .. reserved_items_formspec(pos) - .. 'list[context;src;0.22,4;9,1;]' - .. pipeworks.fs_helpers.get_inv(5.5) + .. 'list[context;src;0.22,4.3;9,1;]' + .. pipeworks.fs_helpers.get_inv(6) .. 'listring[current_player;main]' .. 'listring[context;src]' .. 'listring[current_player;main]' @@ -370,13 +371,7 @@ local list_cache = sbz_api.make_cache('list_cache', 0, true) -- crafting processors & stats -- might want to introduce a register_crafting_processor function sometime -local processor_stats_map = { - ['sbz_resources:simple_crafting_processor'] = { crafts = 1, power = 10 }, - ['sbz_resources:quick_crafting_processor'] = { crafts = 2, power = 25 }, - ['sbz_resources:fast_crafting_processor'] = { crafts = 4, power = 50 }, - ['sbz_resources:accelerated_silicon_crafting_processor'] = { crafts = 8, power = 100 }, - ['sbz_resources:nuclear_crafting_processor'] = { crafts = 16, power = 175 }, -} +-- WARN: sbz_api.crafting_processor_stats moved to sbz_resources/processors_and_circuits.lua and this depends on them minetest.register_node('pipeworks:autocrafter', { description = S 'Autocrafter', @@ -584,7 +579,7 @@ minetest.register_node('pipeworks:autocrafter', { end local item_name = processor_stack:get_name() - local stats = processor_stats_map[item_name] + local stats = sbz_api.crafting_processor_stats[item_name] if not stats then meta:set_string('infotext', 'This item is not a crafting processor.') @@ -669,3 +664,19 @@ minetest.register_craft { { 'sbz_chem:titanium_alloy_ingot', 'sbz_meteorites:neutronium', 'sbz_chem:titanium_alloy_ingot' }, }, } + +-- legacy compatibility +core.register_lbm { + label = 'Upgrade autocrafters, and give them a free processor', + name = 'pipeworks:update_autocrafters', + nodenames = { 'pipeworks:autocrafter' }, + action = function(pos, node, dtime_s) + local meta = core.get_meta(pos) + local inv = meta:get_inventory() + local has_processor = inv:get_size 'processor' ~= 0 + if not has_processor then + inv:set_size('processor', 1) + inv:set_stack('processor', 1, 'sbz_resources:simple_crafting_processor 1') + end + end, +} diff --git a/mods/sbz_power/init.lua b/mods/sbz_power/init.lua index e48d49bd..1650eba7 100644 --- a/mods/sbz_power/init.lua +++ b/mods/sbz_power/init.lua @@ -87,10 +87,10 @@ function sbz_api.register_machine(name, def) meta:set_string('infotext', 'Not enough power, needs: ' .. def.power_needed) return def.power_needed else - meta:set_string('infotext', 'Running') local power_consumed = old_action(pos, node, meta, supply, demand) or def.idle_consume or def.power_needed + meta:set_string('infotext', ('Running (%s)'):format(sbz_api.format_power(power_consumed))) return power_consumed end diff --git a/mods/sbz_power/manual_crafter.lua b/mods/sbz_power/manual_crafter.lua index 85ac41d2..99ee270a 100644 --- a/mods/sbz_power/manual_crafter.lua +++ b/mods/sbz_power/manual_crafter.lua @@ -237,12 +237,13 @@ core.register_node('sbz_power:manual_crafter', { }) local blob = 'sbz_resources:matter_blob' +local emit = 'sbz_resources:raw_emittrium' core.register_craft { type = 'shaped', output = 'sbz_power:manual_crafter', recipe = { - { blob, blob, blob }, + { emit, blob, emit }, { blob, 'sbz_resources:simple_circuit', blob }, - { blob, blob, blob }, + { emit, blob, emit }, }, } diff --git a/mods/sbz_progression/annoy.lua b/mods/sbz_progression/annoy.lua index 6146e3a5..ad991bd9 100644 --- a/mods/sbz_progression/annoy.lua +++ b/mods/sbz_progression/annoy.lua @@ -6,11 +6,13 @@ minetest.register_globalstep(function(dtime) for _, player in ipairs(minetest.get_connected_players()) do local inv = player:get_inventory() if inv then - if not inv:contains_item("main", "sbz_progression:questbook") then - if player:get_meta():get_int("questbookwarning") == 0 then - sbz_api.displayDialogLine(player:get_player_name(), - "Lost your questbook? Use /qb to get it back.") - player:get_meta():set_int("questbookwarning", 1) + if not inv:contains_item('main', 'sbz_progression:questbook') then + if player:get_meta():get_int 'questbookwarning' == 0 then + sbz_api.displayDialogLine( + player:get_player_name(), + 'Lost your questbook? Use /qb to get it back.' + ) + player:get_meta():set_int('questbookwarning', 1) end end end @@ -18,21 +20,21 @@ minetest.register_globalstep(function(dtime) end end) -minetest.register_chatcommand("qb", { +minetest.register_chatcommand('qb', { description = "Gives you a questbook if you don't have one.", privs = {}, func = function(name, param) local inv = minetest.get_player_by_name(name):get_inventory() - if inv then - if inv:contains_item("main", "sbz_progression:questbook") then - sbz_api.displayDialogLine(name, "You already have a Quest Book.") + if not inv then return end + + if inv:contains_item('main', 'sbz_progression:questbook') then + sbz_api.displayDialogLine(name, 'You already have a Quest Book.') + else + if inv:room_for_item('main', 'sbz_progression:questbook') then + inv:add_item('main', 'sbz_progression:questbook') + sbz_api.displayDialogLine(name, 'You have been given a Quest Book.') else - if inv:room_for_item("main", "sbz_progression:questbook") then - inv:add_item("main", "sbz_progression:questbook") - sbz_api.displayDialogLine(name, "You have been given a Quest Book.") - else - sbz_api.displayDialogLine(name, "Your inventory is full.") - end + sbz_api.displayDialogLine(name, 'Your inventory is full.') end end end, diff --git a/mods/sbz_progression/quests/Introduction.md b/mods/sbz_progression/quests/Introduction.md index add55432..aab5f467 100644 --- a/mods/sbz_progression/quests/Introduction.md +++ b/mods/sbz_progression/quests/Introduction.md @@ -22,8 +22,8 @@ Some commands useful for survival: - `/qb` - gives you the questbook if you don't have one - `/home` - teleports you to home - `/sethome` - sets your home -- `/drawers_fix` - if drawers appear broken just run that, command was taken from pandorabox_custom -- `/toggle_areas_hud` - Toggles the areas hud, may be useful if you dont want to always see it. +- `/drawers_fix` - if drawers appear broken just run that, yes that command is from pandorabox_custom +- `/toggle_areas_hud` - Toggles the areas hud, useful if you don't want to always see it. - `/bgm_volume` \ - sets the background music's volume **Hotbar switching** @@ -61,18 +61,18 @@ Requires: ### Text -Welcome, player. This is the Quest Book. Here, you can check out what tasks you have to do, and the materials you will need for each quest. - +Welcome, player. This is the Quest Book. Here, you can check out what tasks you can do and information about them. + You can also just ignore the Quest Book if you are an experienced player. - + Now, to get started: look down at the core. Punching it will give you some of your first resources. -You can also just **hold right-click on the core**, it will be easier on you. - +You can also **hold right-click on the core**, it will be easier on you. + These quests are in no particular order, but you might need items from one quest for another. The Introduction questline is designed to get you started into a couple other questlines, so it is recommended you jump between questlines occasionally. - + If you need to know a recipe, search the item in the inventory, and click on it, it will bring up what it can be used for or how it can be crafted. - + TIP: If you lose your Quest Book, you can use /qb to get it back. ### Meta @@ -84,7 +84,7 @@ Requires: ### Text Isn't this one node a little too crammed? Let's do something about that. - + Punch the Core a little more. With nine 'Matter Dust', you can craft yourself a 'Matter Blob'. If you are unable to place a matter blob next to the core, try sneaking while placing it. On multiplayer servers the area around the core may be protected. @@ -108,7 +108,6 @@ Requires: Introduction ### Text Doesn't it feel weird to be holding antimatter? To break nodes you'll need a **Matter** Annihilator, you should craft it up now since it's used in some other crafts down the line. -TIP: Half-broken Annihilators can also be used to craft with. Also, make sure you are crafting the **Matter** annihilator, not the **Anti**matter annihilator. @@ -160,7 +159,7 @@ Requires: A bigger platform ### Text The Switching Station is an important node, because it is the heart of any Power Grid. -You need to have one switching station per power grid. +You **need** to have **one** switching station per power grid. Every machine needs to be connected to a switching station. The Switching Station also displays statistics about the Power Grid when hovered over in-world. When a machine says "no network found", it's not connected to the switching station and won't do anything. @@ -225,8 +224,8 @@ Requires: A bigger platform ### Text -Manual crafters are nodes that allow you to craft things very quickly. They do not require power, and **CANNOT be used with automation**. -They also won't work with crafting recipes that have "replacements", it will instead simply consume those items. (Recipes like that are very rare in sbz.) +Manual crafters are nodes that allow you to craft things very quickly. They do not require power, and **cannot** be used with automation. +They also won't work with crafting recipes that have "replacements", it will instead simply consume those items. (Recipes like that are very rare in sbz, unless you modified it.) **Controls:** - `place`: Configure @@ -260,6 +259,8 @@ Retaining Circuits are a type of Circuit often used in nodes which store items, Unlike Simple Circuits, this will only craft one Retaining Circuit. +TIP: With retaining circuits, you can craft **storinators** to permanently store items outside of your inventory. (They are documented in the storage questline) + ### Meta Requires: Antimatter, Circuitry @@ -270,7 +271,7 @@ Requires: Antimatter, Circuitry We're making the jump from generic matter to stone now! Here is where building a space station gets fun! -First, before we can make Stone nodes we will need Pebbles. They are quite difficult to make, requiring three matter blobs, so **having at least 4 advanced matter extractors is recommended**, as you will need a lot of pebbles. +First, before we can make Stone nodes we will need Pebbles. They are quite difficult to make, requiring **three matter blobs**, so **having at least 4 advanced matter extractors is recommended**, as you will need a lot of pebbles. Pebbles will unlock a lot of decorational nodes to spice up your island, as well as plenty of tech, and if you want you can even start building your own planet. It's all up to your imagination! ### Meta @@ -296,9 +297,9 @@ Requires: Pretty Pebbles The questbook isn't meant to be explored linearly. You should do quests in whichever order you like. If you have inventory issues, the storage questline is within your reach. If you want to explore more machines, check out the emittrium and chemistry questline. -You should also check out the meteorites questline, if you don't, you will wish you saw it sooner. +You should also check out the meteorites questline, if you don't, you might wish that you saw it sooner. If you are a decorator, there is a questline for you too. -If you want to actually automate (you know, the fun part), see the pipeworks questline. **Do that as soon as you can.** +If you want to actually automate (you know, the fun part), see the pipeworks questline. Do that as soon as you can. You can also filter reachable quests (Quests that you can see the descriptions of, but haven't completed yet) by typing "reachable" into the questbook search bar diff --git a/mods/sbz_progression/quests/Meteorites.md b/mods/sbz_progression/quests/Meteorites.md index ff8146ae..9f1c437c 100644 --- a/mods/sbz_progression/quests/Meteorites.md +++ b/mods/sbz_progression/quests/Meteorites.md @@ -6,7 +6,11 @@ ### Text -By this point you've probably been here for at least an hour. You've almost certainly noticed the funny meteorites that whiz past your core occasionally. These are actually a source of metal as well. If you can stop them, which is really hard when you don't know where they're going. But with the alloys you've got, you can craft Meteorite Radar, which shows you their trajectory and makes them much easier to catch. When there is no meteorite nearby, it will do nothing. It'll probably still take a few tries though. When meteorites explode, they will turn into neutronium and some meteoric matter, all meteoric matter decays after a hour. Neutronium or strange matter do not decay. +By this point you've probably been here for at least an hour. You've almost certainly noticed the funny meteorites that whiz past your core occasionally. +These are actually a source of metal as well. If you can stop them, which is really hard when you don't know where they're going. But with the alloys you've got, you can craft a **Meteorite Radar**, which shows you their trajectory and makes them much easier to catch. +When there is no meteorite nearby, it will do nothing. It'll probably still take a few tries though. When meteorites explode, they will turn into neutronium and some meteoric matter, all meteoric matter decays after a hour. Neutronium or strange matter do not decay. + +TIP: The meteorite radar consumes **40 Cj** when a meteorite is nearby, but it will consume only **10 Cj** if it can't detect a meteorite. Be sure to have a battery when using it. ### Meta @@ -16,9 +20,8 @@ Requires: Simple Alloy Furnace, Emittrium Circuits ### Text -Soo... i'm guessing you would have a lot of trouble getting to the meteorites by bridging... -Well don't fear, there is the laser now... - +The laser is a tool that allows you to shoot down meteorites from far away. It is useful if you have trouble bridging/jumping to meteorites. + To charge the laser, "place it" into a battery. (right-click the battery with it in your hand) It also does some damage to other players if PVP is enabled. @@ -31,7 +34,7 @@ Requires: Simple Alloy Furnace, Emittrium Circuits ### Text In the core of a meteorite, you can find a single piece of very dense matter called Neutronium. It's so dense that you can craft it into a Gravitational Attractor, which attracts other passing meteorites and gets you even more metal, or a Gravitational Repulsor which drives them away. -To complete this quest, make a gravitational attractor, or a repulsor. +To complete this quest, make a Gravitational attractor. ### Meta @@ -43,6 +46,8 @@ Requires: Meteorites Sometimes, meteorites whizzing by will be made of antimatter instead of regular matter. These meteorites have Antineutronium in their core. Antineutronium can be crafted into a Gravitational Repulsor, which repulses meteorites. + +To complete this quest, make a Gravitational Repulsor. TIP: Build a shield out of compressed core dust to protect against antimatter meteorites. @@ -68,7 +73,7 @@ Requires: Autocrafters, Neutronium ### Text -Be aware, strange matter can... spread... to both matter and antimatter... +Strange matter can spread to both matter and antimatter. Strange matter won't spread to "charged" nodes or machines, or protected areas. So it's best to protect your area, even if you are in singleplayer, to defend against strange matter. diff --git a/mods/sbz_progression/quests/Pipeworks_and_fluid_transport.md b/mods/sbz_progression/quests/Pipeworks_and_fluid_transport.md index 7da37897..8cd0e6fe 100644 --- a/mods/sbz_progression/quests/Pipeworks_and_fluid_transport.md +++ b/mods/sbz_progression/quests/Pipeworks_and_fluid_transport.md @@ -89,7 +89,7 @@ Requires: Automatic Filter-Injectors, Bear Arms, Emittrium Circuits ### Text -Autocrafters automatically craft. They require a crafting processor to run, which you can upgrade as you progress through the game, to increase crafting speed. +Autocrafters automatically craft. They require a crafting processor item to run, which you can upgrade as you progress through the game, to increase crafting speed. ### Meta @@ -116,7 +116,6 @@ Requires: Autocrafters ### Text Item voids delete every item that goes in, and yes these are pipeworks trash cans. But unlike pipeworks trash cans, they show the amount of items they've destroyed. -That number can "overflow" into the negatives, if you actually manage to do this, don't consider it a bug, but consider it an achievement :) ### Meta @@ -133,15 +132,15 @@ Then, there might be an issue with it if the storinator that we are putting item In cases where there is only one tube, the item will simply drop, but when there are at least 2 tubes, the items will wonder around, until eventually there will be too many of them. In that case, the tubes will break. How do we prevent our tubes breaking, or items dropping? -Well... a simple answer would be to have more storinators :D... but that's not practical +Wel a simple answer would be to have more storinators :D..... but that's not practical **Instead, consider using item voids like this:** \ Item voids have the lowest priority, so items really don't want to go there. -Storinator, has a higher priority than the item void, so if the storinator isn't full, items will go there. +Storinator, has a higher priority than the item void, so if the storinator isn't full, items will want to go there. Item voids, have a lower priority, so if the item can't go to the storinator, it will go into the item void. -The default priority is 100. +The default priority of nodes is 100. ### Meta diff --git a/mods/sbz_progression/quests/Storage.md b/mods/sbz_progression/quests/Storage.md index 6d6a5dd8..ebf2919d 100644 --- a/mods/sbz_progression/quests/Storage.md +++ b/mods/sbz_progression/quests/Storage.md @@ -1,8 +1,6 @@ - # Questline: Storage -So... i assume you need some sort of storage... to store items.... Well don't worry, Skyblock Zero provides multiple ways to do that. - +Mainly about drawers and storinators. ## Storinators @@ -19,8 +17,8 @@ Requires: Matter Plates, Charged Field, Retaining Circuits ### Text -Soo... i don't think the storinator's 32 slots is enough for you, is it? -Well don't worry.. you can craft more storinators.... OR you can upgrade them :\> +At some point only having 32 slots of storage is not enough. +You can make more storinators, or you can make an upgraded one. Each upgrade adds 1 row and 1 collumn to the inventory space. To complete this quest, you need to craft the bronze storinator. @@ -43,8 +41,8 @@ Requires: Storinators ### Text -Do you have chaos in your storinators, are you struggling to figure out which one is which.... Do you need labels, but signs get in the way? -Well, you can use neutronium storinators, they are a little expensive, requiring 4 neutronium, but if you can afford them, they are great for this. +Do you have chaos in your storinators, are you struggling to figure out which one is which, do you need labels, but signs get in the way? +You can use neutronium storinators, they are a little expensive, requiring 4 neutronium, but if you can afford them, they are great for this. ### Meta @@ -54,17 +52,13 @@ Requires: Better Storinators, Neutronium ### Text -Do you have some some sort of automation set-up, that produces LARGE amounts of 1 type of item? -Or do you just have a large amount of some junk, but you don't want to throw it away for some reason? - -Well... introducing DRAWERS, they are like storinators... but only store 1 type of item... and don't store tools... -But yeah they are really good at that... -They store 3200 of 1 type of item (without upgrades). With upgrades they can store a lot more. - +Do you have some some automation that produces large amounts of 1 type of item? +Or do you just have large amounts of one item type? + +Drawers will help here, they are like storinators but they can only store a few item types. +They store 3200 items (without upgrades). With upgrades they can store a lot more. + Drawers also come with 1x2 and 4x4 variants. - -**Tip: These support the automatic filter injector.** -**Tip: Unlike the regular minetest-mods/drawers, these ones can't get dug when they contain something** ### Meta @@ -74,10 +68,10 @@ Requires: Storinators ### Text -Soo... i'm guessing that one drawer just won't meet all of your needs... well... -You can upgrade it! By clicking on the sides of the drawer, or the edges (if you are only facing the front fase) you can see an inventory, in which you put the upgrades... - -The upgrades don't work as you expect them to, if you have 2 bronze upgrades, each bronze upgrade adds an extra 3200 items, it doesn't multiply 3200 by 4 +Drawers by default store the same amount of items as a storinator, that's a bit boring. What if you could store more? + +TIP: The upgrades don't work as you expect them to, if you have 2 bronze upgrades, each bronze upgrade adds an extra 3200 items, it doesn't multiply 3200 by 4 or anything like that. +TIP: To insert the upgrade into a drawer, you need to right-click the edge of it, or right-click a side that doesn't have the item display. ### Meta @@ -89,9 +83,9 @@ Requires: Drawers, Bronze Age I think you have noticed that drawers still may not work so amazingly for automation, the drawer controller is here to solve that. If you send it an item with a tube, or manually provide it an item, it will automatically put it in one of the drawers near it. - + For taking out items, you can use a luacontroller, sending an itemstack (a string like "sbz_bio:dirt 100"), and it will try to give you that dirt by injecting it out of itself. ### Meta -Requires: Drawers \ No newline at end of file +Requires: Drawers diff --git a/mods/sbz_resources/processors_and_circuits.lua b/mods/sbz_resources/processors_and_circuits.lua index adcea415..8e453e72 100644 --- a/mods/sbz_resources/processors_and_circuits.lua +++ b/mods/sbz_resources/processors_and_circuits.lua @@ -1,213 +1,261 @@ -minetest.register_craftitem("sbz_resources:simple_circuit", { - description = "Simple Circuit", - inventory_image = "simple_circuit.png", +minetest.register_craftitem('sbz_resources:simple_circuit', { + description = 'Simple Circuit', + inventory_image = 'simple_circuit.png', stack_max = 256, }) -minetest.register_craft({ - type = "shapeless", - output = "sbz_resources:simple_circuit 2", - recipe = { "sbz_resources:core_dust", "sbz_resources:matter_blob" } -}) - -minetest.register_craftitem("sbz_resources:mosfet", { - description = "Metal-Oxide-Semiconductor Field-Effect Transistor (MOSFET)", - inventory_image = "mosfet.png", -- REPLACE THIS - stack_max = 256, -}) - -minetest.register_craft({ - type = "shapeless", - output = "sbz_resources:mosfet", - recipe = { "sbz_chem:iron_ingot", "sbz_power:power_pipe" } -}) +minetest.register_craft { + type = 'shapeless', + output = 'sbz_resources:simple_circuit 2', + recipe = { 'sbz_resources:core_dust', 'sbz_resources:matter_blob' }, +} -minetest.register_craftitem("sbz_resources:retaining_circuit", { - description = "Retaining Circuit", - inventory_image = "retaining_circuit.png", +minetest.register_craftitem('sbz_resources:retaining_circuit', { + description = 'Retaining Circuit', + inventory_image = 'retaining_circuit.png', stack_max = 256, }) -minetest.register_craft({ - type = "shapeless", - output = "sbz_resources:retaining_circuit", - recipe = { "sbz_resources:charged_particle", "sbz_resources:antimatter_dust", "sbz_resources:simple_circuit" } -}) +minetest.register_craft { + type = 'shapeless', + output = 'sbz_resources:retaining_circuit', + recipe = { 'sbz_resources:charged_particle', 'sbz_resources:antimatter_dust', 'sbz_resources:simple_circuit' }, +} -minetest.register_craftitem("sbz_resources:emittrium_circuit", { - description = "Emittrium Circuit", - inventory_image = "emittrium_circuit.png", +minetest.register_craftitem('sbz_resources:emittrium_circuit', { + description = 'Emittrium Circuit', + inventory_image = 'emittrium_circuit.png', stack_max = 256, }) -minetest.register_craft({ - type = "shapeless", - output = "sbz_resources:emittrium_circuit", - recipe = { "sbz_resources:charged_particle", "sbz_resources:retaining_circuit", "sbz_resources:raw_emittrium", "sbz_resources:matter_plate" } -}) +minetest.register_craft { + type = 'shapeless', + output = 'sbz_resources:emittrium_circuit', + recipe = { + 'sbz_resources:charged_particle', + 'sbz_resources:retaining_circuit', + 'sbz_resources:raw_emittrium', + 'sbz_resources:matter_plate', + }, +} -core.register_craftitem("sbz_resources:phlogiston_circuit", { - description = "Phlogiston Circuit", - inventory_image = "phlogiston_circuit.png" +core.register_craftitem('sbz_resources:phlogiston_circuit', { + description = 'Phlogiston Circuit', + inventory_image = 'phlogiston_circuit.png', }) core.register_craft { - type = "shapeless", - output = "sbz_resources:phlogiston_circuit 4", + type = 'shapeless', + output = 'sbz_resources:phlogiston_circuit 4', recipe = { - "sbz_resources:emittrium_circuit", "sbz_resources:emittrium_circuit", "sbz_resources:phlogiston", - "sbz_resources:emittrium_circuit", "sbz_resources:emittrium_circuit", "sbz_resources:phlogiston", - "sbz_power:simple_charged_field", "sbz_resources:antimatter_blob", "sbz_resources:compressed_core_dust", - } + 'sbz_resources:emittrium_circuit', + 'sbz_resources:emittrium_circuit', + 'sbz_resources:phlogiston', + 'sbz_resources:emittrium_circuit', + 'sbz_resources:emittrium_circuit', + 'sbz_resources:phlogiston', + 'sbz_power:simple_charged_field', + 'sbz_resources:antimatter_blob', + 'sbz_resources:compressed_core_dust', + }, } -- used in meteorite radars and weapons -core.register_craftitem("sbz_resources:prediction_circuit", { - description = "Prediction Circuit", - inventory_image = "prediction_circuit.png", +core.register_craftitem('sbz_resources:prediction_circuit', { + description = 'Prediction Circuit', + inventory_image = 'prediction_circuit.png', }) core.register_craft { - type = "shapeless", - output = "sbz_resources:prediction_circuit", + type = 'shapeless', + output = 'sbz_resources:prediction_circuit', recipe = { - "sbz_resources:emittrium_circuit", "sbz_resources:emittrium_circuit", "sbz_chem:titanium_alloy_ingot", - "sbz_resources:raw_emittrium", "sbz_resources:raw_emittrium", "sbz_resources:raw_emittrium" - } + 'sbz_resources:emittrium_circuit', + 'sbz_resources:emittrium_circuit', + 'sbz_chem:titanium_alloy_ingot', + 'sbz_resources:raw_emittrium', + 'sbz_resources:raw_emittrium', + 'sbz_resources:raw_emittrium', + }, } - -minetest.register_craftitem("sbz_resources:simple_logic_circuit", { - description = "Simple Logic Circuit", - inventory_image = "simple_logic_circuit.png", +minetest.register_craftitem('sbz_resources:simple_logic_circuit', { + description = 'Simple Logic Circuit', + inventory_image = 'simple_logic_circuit.png', stack_max = 256, }) -minetest.register_craft({ - type = "shapeless", - output = "sbz_resources:simple_logic_circuit 12", +minetest.register_craft { + type = 'shapeless', + output = 'sbz_resources:simple_logic_circuit 12', recipe = { - "sbz_bio:cleargrass", "sbz_bio:cleargrass", "sbz_bio:cleargrass", - "sbz_resources:emittrium_circuit", "sbz_resources:emittrium_circuit", "sbz_resources:emittrium_circuit", - "sbz_bio:razorgrass", "sbz_bio:razorgrass", "sbz_bio:razorgrass", - } -}) + 'sbz_bio:cleargrass', + 'sbz_bio:cleargrass', + 'sbz_bio:cleargrass', + 'sbz_resources:emittrium_circuit', + 'sbz_resources:emittrium_circuit', + 'sbz_resources:emittrium_circuit', + 'sbz_bio:razorgrass', + 'sbz_bio:razorgrass', + 'sbz_bio:razorgrass', + }, +} -minetest.register_craftitem("sbz_resources:simple_inverted_logic_circuit", { - description = "Simple Inverted Logic Circuit", - inventory_image = "simple_inverting_circuit.png", +minetest.register_craftitem('sbz_resources:simple_inverted_logic_circuit', { + description = 'Simple Inverted Logic Circuit', + inventory_image = 'simple_inverting_circuit.png', stack_max = 256, }) minetest.register_craft { - type = "shapeless", - output = "sbz_resources:simple_inverted_logic_circuit", + type = 'shapeless', + output = 'sbz_resources:simple_inverted_logic_circuit', recipe = { - "sbz_resources:compressed_core_dust", "sbz_resources:compressed_core_dust", "sbz_resources:compressed_core_dust", - "sbz_resources:compressed_core_dust", "sbz_resources:simple_logic_circuit", "sbz_resources:compressed_core_dust", - "sbz_resources:compressed_core_dust", "sbz_resources:compressed_core_dust", "sbz_resources:compressed_core_dust", - } + 'sbz_resources:compressed_core_dust', + 'sbz_resources:compressed_core_dust', + 'sbz_resources:compressed_core_dust', + 'sbz_resources:compressed_core_dust', + 'sbz_resources:simple_logic_circuit', + 'sbz_resources:compressed_core_dust', + 'sbz_resources:compressed_core_dust', + 'sbz_resources:compressed_core_dust', + 'sbz_resources:compressed_core_dust', + }, } minetest.register_craft { - type = "shapeless", - output = "sbz_resources:simple_logic_circuit", + type = 'shapeless', + output = 'sbz_resources:simple_logic_circuit', recipe = { - "sbz_resources:compressed_core_dust", "sbz_resources:compressed_core_dust", "sbz_resources:compressed_core_dust", - "sbz_resources:compressed_core_dust", "sbz_resources:simple_inverted_logic_circuit", "sbz_resources:compressed_core_dust", - "sbz_resources:compressed_core_dust", "sbz_resources:compressed_core_dust", "sbz_resources:compressed_core_dust", - } + 'sbz_resources:compressed_core_dust', + 'sbz_resources:compressed_core_dust', + 'sbz_resources:compressed_core_dust', + 'sbz_resources:compressed_core_dust', + 'sbz_resources:simple_inverted_logic_circuit', + 'sbz_resources:compressed_core_dust', + 'sbz_resources:compressed_core_dust', + 'sbz_resources:compressed_core_dust', + 'sbz_resources:compressed_core_dust', + }, } --- === PROCESSORS === -core.register_craftitem("sbz_resources:simple_processor", { - description = "Simple Processor", - inventory_image = "simple_procesor.png" -- someone correct the typo lmfao +core.register_craftitem('sbz_resources:simple_processor', { + description = 'Simple Processor', + inventory_image = 'simple_procesor.png', -- someone correct the typo lmfao }) sbz_api.recipe.register_craft { - type = "engraver", - output = "sbz_resources:simple_processor", - items = { "sbz_chem:silicon_crystal 8" } + type = 'engraver', + output = 'sbz_resources:simple_processor', + items = { 'sbz_chem:silicon_crystal 8' }, } -- crafting processors -core.register_craftitem("sbz_resources:simple_crafting_processor", { - description = "Simple Crafting Processor\nCrafts 1 item per second for 10 power.", - inventory_image = "simple_crafting_processor.png", - stack_max = 1 -}) +--[[ +DESIGN: +1st tier: don't even have metal automation +2nd tier: explored into shockshrooms +3rd tier: actively automating shock shrooms, silicon and have nuclear stuff +4th tier: bored +5th tier: and should be doing something else +]] +sbz_api.crafting_processor_stats = { + ['sbz_resources:simple_crafting_processor'] = { crafts = 1, power = 5 }, + ['sbz_resources:quick_crafting_processor'] = { crafts = 8, power = 20 }, + ['sbz_resources:fast_crafting_processor'] = { crafts = 32, power = 140 }, + + ['sbz_resources:needlessly_expensive_crafting_processor'] = { crafts = 128, power = 640 }, + ['sbz_resources:omega_quantum_black_hole_whatever_crafting_processor'] = { crafts = 100000, power = 800 }, +} -minetest.register_craft({ - type = "shapeless", - output = "sbz_resources:simple_crafting_processor", - recipe = { "sbz_resources:mosfet", "sbz_resources:simple_circuit", "sbz_meteorites:neutronium" } +core.register_craftitem('sbz_resources:simple_crafting_processor', { + description = 'Simple Crafting Processor', + info_extra = 'Crafts 1 item/s for 5Cj', + inventory_image = 'simple_crafting_processor.png', + stack_max = 1, }) +core.register_craft { + output = 'sbz_resources:simple_crafting_processor', + recipe = { + { 'sbz_resources:matter_blob', 'sbz_resources:emittrium_circuit', 'sbz_resources:matter_blob' }, + { 'sbz_resources:emittrium_circuit', 'sbz_chem:cobalt_ingot', 'sbz_resources:emittrium_circuit' }, + { 'sbz_resources:matter_blob', 'sbz_resources:emittrium_circuit', 'sbz_resources:matter_blob' }, + }, +} - -core.register_craftitem("sbz_resources:quick_crafting_processor", { - description = "Quick Crafting Processor\nCrafts 2 items per second for 25 power.", - inventory_image = "quick_crafting_processor.png", - stack_max = 1 +core.register_craftitem('sbz_resources:fast_crafting_processor', { + description = 'Fast Crafting Processor', + info_extra = 'Crafts 8 items/s for 20Cj', + inventory_image = 'quick_crafting_processor.png', + stack_max = 1, }) -minetest.register_craft({ - type = "shaped", - output = "sbz_resources:quick_crafting_processor", +-- stylua: ignore start +minetest.register_craft { + output = 'sbz_resources:fast_crafting_processor', recipe = { - {"sbz_resources:simple_crafting_processor", "sbz_resources:prediction_circuit", "sbz_resources:simple_crafting_processor"}, - {"sbz_meteorites:neutronium", "sbz_resources:mosfet", "sbz_meteorites:neutronium"}, - {"sbz_resources:simple_crafting_processor", "sbz_meteorites:neutronium", "sbz_resources:simple_crafting_processor"}, - } -}) - + {"sbz_resources:simple_crafting_processor","sbz_resources:reinforced_matter","sbz_resources:simple_crafting_processor",}, + {"sbz_resources:reinforced_matter","sbz_resources:shock_crystal","sbz_resources:reinforced_matter",}, + {"sbz_resources:simple_crafting_processor","sbz_resources:reinforced_matter","sbz_resources:simple_crafting_processor",}, + }, +} +core.register_alias('sbz_resources:quick_crafting_processor', 'sbz_resources:fast_crafting_processor') -core.register_craftitem("sbz_resources:fast_crafting_processor", { - description = "Fast Crafting Processor\nCrafts 4 items per second for 50 power.", - inventory_image = "fast_crafting_processor.png", - stack_max = 1 +core.register_craftitem('sbz_resources:very_fast_crafting_processor', { + description = 'Very Fast Crafting Processor\nCrafts 32 items per second for 140 power.', + inventory_image = 'accelerated_silicon_crafting_processor.png', + stack_max = 1, }) -minetest.register_craft({ - type = "shaped", - output = "sbz_resources:fast_crafting_processor", +minetest.register_craft { + output = 'sbz_resources:very_fast_crafting_processor', recipe = { - {"sbz_resources:quick_crafting_processor", "sbz_resources:emittrium_circuit", "sbz_resources:quick_crafting_processor"}, - {"sbz_resources:mosfet", "sbz_resources:emittrium_circuit", "sbz_resources:mosfet"}, - {"sbz_resources:quick_crafting_processor", "sbz_resources:emittrium_circuit", "sbz_resources:quick_crafting_processor"}, - } -}) - + { 'sbz_resources:fast_crafting_processor', 'sbz_chem:silicon_crystal', 'sbz_resources:fast_crafting_processor' }, + { 'sbz_chem:silicon_crystal', 'sbz_chem:thorium_crystal', 'sbz_chem:silicon_crystal' }, + { 'sbz_resources:fast_crafting_processor', 'sbz_chem:silicon_crystal', 'sbz_resources:fast_crafting_processor' }, + }, +} -core.register_craftitem("sbz_resources:accelerated_silicon_crafting_processor", { - description = "Accelerated Silicon Crafting Processor\nCrafts 8 items per second for 100 power.", - inventory_image = "accelerated_silicon_crafting_processor.png", - stack_max = 1 +core.register_craftitem('sbz_resources:needlessly_expensive_crafting_processor', { + description = 'Needlessly Expensive Crafting Processor', + inventory_image = 'needlessly_expensive_crafting_processor.png', + stack_max = 1, + info_extra = "Crafts 128 items/s and uses 640Cj. You shouldn't need this, this item was made as a joke.", }) -minetest.register_craft({ - type = "shaped", - output = "sbz_resources:accelerated_silicon_crafting_processor", +minetest.register_craft { + type = 'shaped', + output = 'sbz_resources:needlessly_expensive_crafting_processor', recipe = { - {"sbz_resources:fast_crafting_processor", "sbz_chem:silicon_crystal", "sbz_resources:fast_crafting_processor"}, - {"sbz_resources:mosfet", "sbz_resources:mosfet", "sbz_resources:mosfet"}, - {"sbz_resources:fast_crafting_processor", "sbz_meteorites:neutronium", "sbz_resources:fast_crafting_processor"}, - } -}) - + { 'sbz_resources:very_fast_crafting_processor', 'drawers:warpshroom_upgrade', 'sbz_resources:very_fast_crafting_processor' }, + { 'sbz_bio:giant_colorium_sapling', 'sbz_chem:thorium_crystal', 'sbz_bio:giant_colorium_sapling' }, + { 'sbz_resources:very_fast_crafting_processor', 'sbz_chem:xray_off', 'sbz_resources:very_fast_crafting_processor' }, + }, +} -core.register_craftitem("sbz_resources:nuclear_crafting_processor", { - description = "Nuclear Crafting Processor\nCrafts 16 items per second for 175 power.", - inventory_image = "nuclear_crafting_processor.png", - stack_max = 1 +core.register_craftitem('sbz_resources:omega_quantum_black_hole_whatever_crafting_processor', { + description = 'Omega Quantum Black Hole Whatever Crafting Processor', + inventory_image = 'omega_quantum_black_hole_whatever_crafting_processor.png', + info_extra = 'Crafts 100000 items/s, consumes 800Cj.\nThe magic of non-commercial volunteer-run free (as in freedom) games is that you can put in whatever you want.\nThis item is a joke. You should not try to get it.', + stack_max = 1, }) -minetest.register_craft({ - type = "shaped", - output = "sbz_resources:nuclear_crafting_processor", +minetest.register_craft { + output = 'sbz_resources:omega_quantum_black_hole_whatever_crafting_processor', recipe = { - {"sbz_resources:accelerated_silicon_crafting_processor", "sbz_resources:phlogiston_circuit", "sbz_resources:accelerated_silicon_crafting_processor"}, - {"sbz_resources:mosfet", "sbz_resources:mosfet", "sbz_resources:mosfet"}, - {"sbz_resources:accelerated_silicon_crafting_processor", "sbz_meteorites:neutronium", "sbz_resources:accelerated_silicon_crafting_processor"}, - } -}) \ No newline at end of file + { 'sbz_resources:needlessly_expensive_crafting_processor', 'sbz_resources:needlessly_expensive_crafting_processor', 'sbz_resources:needlessly_expensive_crafting_processor', }, + { 'sbz_resources:needlessly_expensive_crafting_processor', 'sbz_resources:needlessly_expensive_crafting_processor', 'sbz_resources:needlessly_expensive_crafting_processor', }, + { 'sbz_resources:needlessly_expensive_crafting_processor', 'sbz_resources:needlessly_expensive_crafting_processor', 'sbz_resources:needlessly_expensive_crafting_processor', }, + }, +} +-- stylua: ignore end + +-- deprecated stuff +core.register_craftitem('sbz_resources:mosfet', { + description = 'Metal-Oxide-Semiconductor Field-Effect Transistor (MOSFET)', + info_extra = 'Deprecated. Throw it away.', + inventory_image = 'mosfet.png', + groups = { not_in_creative_inventory = 1 }, + stack_max = 1, +}) diff --git a/mods/sbz_resources/textures/needlessly_expensive_crafting_processor.png b/mods/sbz_resources/textures/needlessly_expensive_crafting_processor.png new file mode 100644 index 0000000000000000000000000000000000000000..628a233bf2204686563ffeb857de4b3a5a04dd32 GIT binary patch literal 240 zcmV%gy9Y*5n~J`_NnY3h^(;I#-imG(s7mi qQ$RH%-nTp83F`6^YyAC{_vZru!AWV2>A>Ou0000?9(-bN z^#5M7am3Xm(U#14OQ)VY00a}ta@G8tBMNppeERL)_Oww`;M+~Tw&!#HL|ip|X!O8R z-TrW|lxdr^X_m&U$B!Qe?rFQ+u(#;F#9XuSLzO~>T8`i zQBXN$s)*0O^Lx+tEZnhU#|*)fKYMt1Dv}=lXtd2xT2^rFP%HPtX^%`Eyg0Zx;^;)v y$EFXiPh?`VOsr%Bf;RVj`A0!+l|gb93=9SuemuI$+gpGkz~JfX=d#Wzp$PyB9)t1# literal 0 HcmV?d00001 diff --git a/mods/sbz_resources/tools.lua b/mods/sbz_resources/tools.lua index 19459c84..c50586f1 100644 --- a/mods/sbz_resources/tools.lua +++ b/mods/sbz_resources/tools.lua @@ -1,10 +1,8 @@ --- Define a new pickaxe -minetest.register_tool("sbz_resources:matter_annihilator", { - description = "Matter Annihilator", - inventory_image = "matter_annihilator.png", -- Replace with your own image file +minetest.register_craftitem('sbz_resources:matter_annihilator', { + description = 'Matter Annihilator', + inventory_image = 'matter_annihilator.png', groups = { core_drop_multi = 1 }, - -- Tool properties tool_capabilities = { full_punch_interval = 2.5, damage_groups = { matter = 2 }, @@ -16,23 +14,23 @@ minetest.register_tool("sbz_resources:matter_annihilator", { sound = { punch_use = { - name = "block_annihilated", + name = 'block_annihilated', gain = 1, - } + }, }, }) -minetest.register_craft({ - output = "sbz_resources:matter_annihilator", +minetest.register_craft { + output = 'sbz_resources:matter_annihilator', recipe = { - { "", "sbz_resources:antimatter_dust", "" }, - { "sbz_resources:matter_blob", "sbz_resources:charged_particle", "sbz_resources:matter_blob" }, - { "", "sbz_resources:matter_blob", "" } - } -}) + { '', 'sbz_resources:antimatter_dust', '' }, + { 'sbz_resources:matter_blob', 'sbz_resources:charged_particle', 'sbz_resources:matter_blob' }, + { '', 'sbz_resources:matter_blob', '' }, + }, +} -minetest.register_tool("sbz_resources:antimatter_annihilator", { - description = "Antimatter Annihilator", - inventory_image = "antimatter_annihilator.png", -- Replace with your own image file +minetest.register_craftitem('sbz_resources:antimatter_annihilator', { + description = 'Antimatter Annihilator', + inventory_image = 'antimatter_annihilator.png', groups = { core_drop_multi = 1 }, tool_capabilities = { @@ -46,25 +44,24 @@ minetest.register_tool("sbz_resources:antimatter_annihilator", { sound = { punch_use = { - name = "block_annihilated", + name = 'block_annihilated', gain = 1, - } + }, }, }) -minetest.register_craft({ - output = "sbz_resources:antimatter_annihilator", +minetest.register_craft { + output = 'sbz_resources:antimatter_annihilator', recipe = { - { "", "sbz_resources:matter_dust", "" }, - { "sbz_resources:antimatter_blob", "sbz_resources:charged_particle", "sbz_resources:antimatter_blob" }, - { "", "sbz_resources:antimatter_blob", "" } - } -}) + { '', 'sbz_resources:matter_dust', '' }, + { 'sbz_resources:antimatter_blob', 'sbz_resources:charged_particle', 'sbz_resources:antimatter_blob' }, + { '', 'sbz_resources:antimatter_blob', '' }, + }, +} -minetest.register_tool("sbz_resources:robotic_arm", { - description = "Robotic Arm", - inventory_image = "robotic_arm.png", +minetest.register_craftitem('sbz_resources:robotic_arm', { + description = 'Robotic Arm', + inventory_image = 'robotic_arm.png', groups = { core_drop_multi = 2 }, - -- Tool properties tool_capabilities = { full_punch_interval = 0.5, damage_groups = { matter = 1, antimatter = 1 }, @@ -76,29 +73,28 @@ minetest.register_tool("sbz_resources:robotic_arm", { sound = { punch_use = { - name = "block_annihilated", + name = 'block_annihilated', gain = 1, - } + }, }, }) minetest.register_craft { - output = "sbz_resources:robotic_arm", + output = 'sbz_resources:robotic_arm', recipe = { - { "sbz_resources:matter_annihilator", "sbz_chem:iron_ingot", "sbz_resources:matter_annihilator" }, - { "sbz_resources:reinforced_matter", "sbz_resources:emittrium_circuit", "sbz_resources:reinforced_matter" }, - { "sbz_resources:reinforced_matter", "sbz_resources:emittrium_circuit", "sbz_resources:reinforced_matter" } - } + { 'sbz_resources:matter_annihilator', 'sbz_chem:iron_ingot', 'sbz_resources:matter_annihilator' }, + { 'sbz_resources:reinforced_matter', 'sbz_resources:emittrium_circuit', 'sbz_resources:reinforced_matter' }, + { 'sbz_resources:reinforced_matter', 'sbz_resources:emittrium_circuit', 'sbz_resources:reinforced_matter' }, + }, } - local drill_times = { [1] = 1.50 / 2, [2] = 0.30 / 2, [3] = 0.10 / 2 } local drill_max_wear = 500 local drill_power_per_1_use = 10 local tool_caps = { full_punch_interval = 0.1, - damage_groups = { -- yeaa slightly deadly + damage_groups = { matter = 3, antimatter = 3, }, @@ -108,52 +104,50 @@ local tool_caps = { matter = { times = drill_times, --uses = 30, - maxlevel = 4 + maxlevel = 4, }, antimatter = { times = drill_times, --uses = 30, - maxlevel = 4 + maxlevel = 4, }, }, } -minetest.register_tool("sbz_resources:drill", { - description = "Electric Drill", - inventory_image = "drill.png", +minetest.register_tool('sbz_resources:drill', { + description = 'Electric Drill', + inventory_image = 'drill.png', info_extra = { - "Powered by electricity. Wear bar indicates the amount of charge left.", - ("%s uses"):format(drill_max_wear), - "\"Place\" it on a battery to re-charge it." + 'Powered by electricity. Wear bar indicates the amount of charge left.', + ('%s uses'):format(drill_max_wear), + '"Place" it on a battery to re-charge it.', }, groups = { core_drop_multi = 4, disable_repair = 1, power_tool = 1 }, - -- Tool properties tool_capabilities = tool_caps, after_use = function(stack, user, node, digparams) stack:add_wear_by_uses(drill_max_wear + digparams.wear) - if stack:get_wear() >= 65535 then - stack:get_meta():set_tool_capabilities({}) - end + if stack:get_wear() >= 65535 then stack:get_meta():set_tool_capabilities {} end return stack end, - on_place = sbz_api.on_place_recharge((drill_max_wear / 65535) * drill_power_per_1_use, function(stack, user, pointed) - if stack:get_wear() < 65530 then - stack:get_meta():set_tool_capabilities(tool_caps) + on_place = sbz_api.on_place_recharge( + (drill_max_wear / 65535) * drill_power_per_1_use, + function(stack, user, pointed) + if stack:get_wear() < 65530 then stack:get_meta():set_tool_capabilities(tool_caps) end end - end), + ), powertool_charge = sbz_api.powertool_charge((drill_max_wear / 65535) * drill_power_per_1_use), charge_per_use = drill_power_per_1_use, - wear_represents = "power", + wear_represents = 'power', - wear_color = { color_stops = { [0] = "lime" } }, - sound = { punch_use = { name = "drill_dig", } }, + wear_color = { color_stops = { [0] = 'lime' } }, + sound = { punch_use = { name = 'drill_dig' } }, }) minetest.register_craft { recipe = { - { "sbz_chem:titanium_ingot", "sbz_resources:robotic_arm", "sbz_chem:titanium_ingot" }, - { "sbz_chem:titanium_ingot", "sbz_power:battery", "sbz_chem:titanium_ingot" }, - { "sbz_resources:reinforced_matter", "sbz_resources:emittrium_circuit", "sbz_resources:reinforced_matter" } + { 'sbz_chem:titanium_ingot', 'sbz_resources:robotic_arm', 'sbz_chem:titanium_ingot' }, + { 'sbz_chem:titanium_ingot', 'sbz_power:battery', 'sbz_chem:titanium_ingot' }, + { 'sbz_resources:reinforced_matter', 'sbz_resources:emittrium_circuit', 'sbz_resources:reinforced_matter' }, }, - output = "sbz_resources:drill" + output = 'sbz_resources:drill', } From d80068acc4a0164602a638f96e4a59434b5c64cc Mon Sep 17 00:00:00 2001 From: TheEt1234 Date: Sat, 10 Jan 2026 23:03:29 +0100 Subject: [PATCH 25/28] Someone didnt like the omega quantum whatever crafting processor texture --- ...m_black_hole_whatever_crafting_processor.png | Bin 303 -> 279 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/mods/sbz_resources/textures/omega_quantum_black_hole_whatever_crafting_processor.png b/mods/sbz_resources/textures/omega_quantum_black_hole_whatever_crafting_processor.png index 2c489fcff9466401c0408bdb98bd4d5df3dd7cc7..c02f039868d00330b5d5db096436fcf0dbb2af18 100644 GIT binary patch delta 251 zcmV{!(?;WEIH^Dhd9f%y1%6tCelKwIu73PuLV zhOqqq|NlP&0|UeHZA~~OtfdNk}96zuJO~e$=TDWi_+)|td96fjx zt2nY|yaxO_QotZ5EYHBez`*e6?L%D3C{M}*4*(hrOB(t-ye0qu002ovPDHLkV1hhO Bb9?{* delta 276 zcmV+v0qg#k0JAE{5lv{8-g7;WFSkCqKiD8a0L+HEJlDjmvo^$duJm=(R*emxQMGn~zmjD0%|7T!eU^ssKI0KBHI)8aNgH-AdhU*N^5xQy_ z77 z40vMU_<=oWBBpTG!i5Xrmf|$v=)t2{#gR4RHQ?8g0tPu@c?Jds28Ks(AL3F*c~TyD a001y3P7Ez0w+(~<0000 Date: Mon, 12 Jan 2026 18:12:18 +0100 Subject: [PATCH 26/28] Fix crash with sbz armor --- mods/sbz_armor/init.lua | 227 ++++++++---------- mods/sbz_base/init.lua | 2 + mods/sbz_pipeworks/autocrafter.lua | 2 +- mods/sbz_resources/init.lua | 33 +-- mods/sbz_resources/parkour.lua | 56 +++++ .../textures/emittrium_block.png | Bin 0 -> 151 bytes 6 files changed, 180 insertions(+), 140 deletions(-) create mode 100644 mods/sbz_resources/parkour.lua create mode 100644 mods/sbz_resources/textures/emittrium_block.png diff --git a/mods/sbz_armor/init.lua b/mods/sbz_armor/init.lua index 148ff5c4..fe745ab5 100644 --- a/mods/sbz_armor/init.lua +++ b/mods/sbz_armor/init.lua @@ -26,13 +26,13 @@ local armor = { -- antimatter weaponery: more powerful than matter, get your armor -- strange weaponery: either it kills you instantly, or it does no damage -- force: explosions or charges - armor_groups = { fall_damage_add_percent = -100, matter = 100, light = 100, antimatter = 100, strange = 100, }, + armor_groups = { fall_damage_add_percent = -100, matter = 100, light = 100, antimatter = 100, strange = 100 }, armor_group_descriptions = { - matter = "Matter Protection", - light = "Laser Protection", - antimatter = "Antimatter Protection", - strange = "Strange Protection", - } + matter = 'Matter Protection', + light = 'Laser Protection', + antimatter = 'Antimatter Protection', + strange = 'Strange Protection', + }, } local disable_setting_texture = false @@ -44,19 +44,19 @@ sbz_api.armor = armor ---@return table armor.get_armor_pieces = function(ref) local meta = ref:get_meta() - local armor_data = core.deserialize(meta:get_string("armor")) or {} + local armor_data = core.deserialize(meta:get_string 'armor') or {} return armor_data end -- does texture and armor group stuff armor.load_armor_pieces = function(ref, data) local armor_groups = table.copy(armor.armor_groups) - local texture_mod = "" + local texture_mod = '' for k, v in pairs(data) do local stack = ItemStack(v) local def = stack:get_definition() local groups - if type(def.armor_groups) == "function" then + if type(def.armor_groups) == 'function' then groups = def.armor_groups(ref, stack) else groups = def.armor_groups @@ -67,7 +67,7 @@ armor.load_armor_pieces = function(ref, data) end -- texture... - texture_mod = texture_mod .. "^" .. def.armor_texture + texture_mod = texture_mod .. '^' .. def.armor_texture else data[k] = nil -- empty stacks end @@ -78,52 +78,44 @@ armor.load_armor_pieces = function(ref, data) local texture_index = 1 if props.textures[3] then texture_index = 3 end local base_texture = props.textures[texture_index] - local concat_find = string.find(base_texture, "%^") - if concat_find and concat_find ~= -1 then - base_texture = string.sub(base_texture, 1, concat_find - 1) - end + local concat_find = string.find(base_texture, '%^') + if concat_find and concat_find ~= -1 then base_texture = string.sub(base_texture, 1, concat_find - 1) end props.textures[texture_index] = base_texture .. texture_mod - if not disable_setting_texture then - ref:set_properties(props) - end + if not disable_setting_texture then ref:set_properties(props) end ref:set_armor_groups(armor_groups) - armor.pieces_to_inventory(data, core.get_inventory { type = "detached", name = "sbz_armor:" .. name }) + armor.pieces_to_inventory(data, core.get_inventory { type = 'detached', name = 'sbz_armor:' .. name }) -- nice trick directly copied from https://github.com/minetest-mods/3d_armor/blob/c224a73df74ae8559507421ee50e82bc1f85b61f/3d_armor_ui/init.lua#L17C1-L20C5 - if unified_inventory.current_page[name] == "armor" then - unified_inventory.set_inventory_formspec(ref, "armor") - end + if unified_inventory.current_page[name] == 'armor' then unified_inventory.set_inventory_formspec(ref, 'armor') end end armor.pieces_to_inventory = function(data, inv) - local mainlist = inv:get_list("main") + local mainlist = inv:get_list 'main' for id, piece_def in pairs(piece_types.by_id) do if not data[piece_def.name] then - mainlist[id] = ItemStack("") + mainlist[id] = ItemStack '' else mainlist[id] = ItemStack(data[piece_def.name]) end end - inv:set_list("main", mainlist) + inv:set_list('main', mainlist) end armor.pieces_from_inventory = function(ref, inv) local data = {} - local mainlist = inv:get_list("main") + local mainlist = inv:get_list 'main' for _, piece_stack in pairs(mainlist) do local def = piece_stack:get_definition() - if def.armor_type then - data[def.armor_type] = piece_stack:to_string() - end + if def.armor_type then data[def.armor_type] = piece_stack:to_string() end end armor.set_armor_pieces(ref, data) end armor.set_armor_pieces = function(ref, armor_data) local meta = ref:get_meta() - meta:set_string("armor", core.serialize(armor_data)) + meta:set_string('armor', core.serialize(armor_data)) armor.load_armor_pieces(ref, armor_data) end @@ -133,19 +125,13 @@ armor.register = function(name, def) local data = armor.get_armor_pieces(user) if data[def.armor_type] == nil then data[def.armor_type] = stack:take_item(1):to_string() - if def.on_equip then - def.on_equip(stack, user) - end + if def.on_equip then def.on_equip(stack, user) end else local data_at_that = data[def.armor_type] data[def.armor_type] = stack:take_item(1):to_string() stack = ItemStack(data_at_that) - if stack:get_definition().on_unequip then - stack:get_definition().on_unequip(user, stack) - end - if def.on_equip then - def.on_equip(ItemStack(data[def.armor_type]), user) - end + if stack:get_definition().on_unequip then stack:get_definition().on_unequip(user, stack) end + if def.on_equip then def.on_equip(ItemStack(data[def.armor_type]), user) end end armor.set_armor_pieces(user, data) return stack @@ -160,68 +146,59 @@ armor.register_piecetype = function(def) end core.register_on_joinplayer(function(player) - local inv = core.create_detached_inventory("sbz_armor:" .. player:get_player_name(), { - allow_move = function(inv, from_list, from_index, to_list, to_index, count, callback_player) - if callback_player:get_player_name() ~= player:get_player_name() then - return 0 + local inv = core.create_detached_inventory('sbz_armor:' .. player:get_player_name(), { + allow_move = function(inv, from_list, from_index, to_list, to_index, count, callback_player) + if callback_player:get_player_name() ~= player:get_player_name() then + return 0 + else + if callback_player:get_inventory():get_stack(from_index, from_index):get_definition().armor_type then + return count else - if callback_player:get_inventory():get_stack(from_index, from_index):get_definition().armor_type then - return count - else - return 0 - end - end - end, - allow_put = function(inv, listname, index, stack, callback_player) - if callback_player:get_player_name() ~= player:get_player_name() then - return 0 - end - local trigger_method = "on_equip" - local stack_def = stack:get_definition() - if not stack_def.armor_type then return 0 end -- thats not armor - - local data = armor.get_armor_pieces(player) - if data[stack_def.armor_type] or not ItemStack(data[stack_def.armor_type]):is_empty() then return 0 end - - if stack_def[trigger_method] then - stack_def[trigger_method](player, stack) - end - return stack:get_count() - end, - allow_take = function(inv, listname, index, stack, callback_player) - if callback_player:get_player_name() ~= player:get_player_name() then return 0 end - local trigger_method = "on_unequip" - local stack_def = stack:get_definition() - if not stack_def.armor_type then return 0 end -- thats not armor - - --local data = armor.get_armor_pieces(player) - --if data[stack_def.armor_type] or ItemStack(data[stack_def.armor_type]):is_empty() then return 0 end - - if stack_def[trigger_method] then - stack_def[trigger_method](player, stack) - end - return stack:get_count() - end, - - on_move = function(inv, from_list, from_index, to_list, to_index, count, player) - armor.pieces_from_inventory(player, inv) - end, - on_put = function(inv, listname, index, stack, player) - armor.pieces_from_inventory(player, inv) - end, - on_take = function(inv, listname, index, stack, player) - armor.pieces_from_inventory(player, inv) - end, - }, - player:get_player_name()) - inv:set_size("main", #piece_types.by_id) + end + end, + allow_put = function(inv, listname, index, stack, callback_player) + if callback_player:get_player_name() ~= player:get_player_name() then return 0 end + local trigger_method = 'on_equip' + local stack_def = stack:get_definition() + if not stack_def.armor_type then return 0 end -- thats not armor + + local data = armor.get_armor_pieces(player) + if data[stack_def.armor_type] or not ItemStack(data[stack_def.armor_type]):is_empty() then return 0 end + + if stack_def[trigger_method] then stack_def[trigger_method](player, stack) end + return stack:get_count() + end, + allow_take = function(inv, listname, index, stack, callback_player) + if callback_player:get_player_name() ~= player:get_player_name() then return 0 end + local trigger_method = 'on_unequip' + local stack_def = stack:get_definition() + if not stack_def.armor_type then return 0 end -- thats not armor + + --local data = armor.get_armor_pieces(player) + --if data[stack_def.armor_type] or ItemStack(data[stack_def.armor_type]):is_empty() then return 0 end + + if stack_def[trigger_method] then stack_def[trigger_method](player, stack) end + return stack:get_count() + end, + + on_move = function(inv, from_list, from_index, to_list, to_index, count, player) + armor.pieces_from_inventory(player, inv) + end, + on_put = function(inv, listname, index, stack, player) + armor.pieces_from_inventory(player, inv) + end, + on_take = function(inv, listname, index, stack, player) + armor.pieces_from_inventory(player, inv) + end, + }, player:get_player_name()) + inv:set_size('main', #piece_types.by_id) armor.load_armor_pieces(player, armor.get_armor_pieces(player)) end) core.register_on_leaveplayer(function(player) - core.remove_detached_inventory("sbz_armor:" .. player:get_player_name()) + core.remove_detached_inventory('sbz_armor:' .. player:get_player_name()) end) local max_wear = 65535 @@ -233,8 +210,8 @@ core.register_on_punchplayer(function(player, hitter, time_from_last_punch, tool local stack = ItemStack(v) local def = stack:get_definition() if def.on_punched then - no_damage = no_damage or - def.on_punched(stack, data, player, hitter, time_from_last_punch, tool_capabilities, dir, damage) + no_damage = no_damage + or def.on_punched(stack, data, player, hitter, time_from_last_punch, tool_capabilities, dir, damage) data[k] = stack:to_string() end end @@ -243,14 +220,13 @@ core.register_on_punchplayer(function(player, hitter, time_from_last_punch, tool for k, v in pairs(data) do local stack = ItemStack(v) local def = stack:get_definition() - if not def.custom_wear then + if not def.custom_wear and def.durability ~= nil then stack:set_wear(stack:get_wear() + ((max_wear / def.durability) * damage)) data[k] = stack:to_string() end end -- re-evaluate the armor groups - local armor_groups = table.copy(armor.armor_groups) for k, v in pairs(data) do @@ -258,7 +234,7 @@ core.register_on_punchplayer(function(player, hitter, time_from_last_punch, tool local def = stack:get_definition() if def.armor_groups then local groups - if type(def.armor_groups) == "function" then + if type(def.armor_groups) == 'function' then groups = def.armor_groups(player, stack) else groups = def.armor_groups @@ -274,56 +250,61 @@ core.register_on_punchplayer(function(player, hitter, time_from_last_punch, tool player:set_armor_groups(armor_groups) end) - -- piece types -armor.register_piecetype({ -- helmet - name = "head", -}) +armor.register_piecetype { -- helmet + name = 'head', +} -armor.register_piecetype({ -- chestplate - name = "torso", -}) +armor.register_piecetype { -- chestplate + name = 'torso', +} -armor.register_piecetype({ -- leggings - name = "legs", -}) -armor.register_piecetype({ -- boots - name = "feet", -}) +armor.register_piecetype { -- leggings + name = 'legs', +} +armor.register_piecetype { -- boots + name = 'feet', +} -- NOW the inventory! -unified_inventory.register_button("armor", { - type = "image", - image = "armor_icon.png", - tooltip = "Armor", +unified_inventory.register_button('armor', { + type = 'image', + image = 'armor_icon.png', + tooltip = 'Armor', }) -- todo: bars for what is protected against, and -unified_inventory.register_page("armor", { +unified_inventory.register_page('armor', { get_formspec = function(player) local hyper_text = {} -- hypertext text, got it? local player_armor = player:get_armor_groups() for group, desc in pairs(armor.armor_group_descriptions) do local protection = (1 - ((player_armor[group] or 0) / armor.armor_groups[group])) * 100 - hyper_text[#hyper_text + 1] = ("%s%% %s"):format(protection, desc) -- HEY THERE!!!! SOMEONE!!! if you don't understand what the hell that format string was, please learn how to use string.format, it's important!!! Its not that difficult like regex + hyper_text[#hyper_text + 1] = ('%s%% %s'):format(protection, desc) -- HEY THERE!!!! SOMEONE!!! if you don't understand what the hell that format string was, please learn how to use string.format, it's important!!! Its not that difficult like regex end local name = player:get_player_name() local props = player:get_properties() return { - formspec = string.format([[ + formspec = string.format( + [[ list[detached:sbz_armor:%s;main;0.2,0.2;2,10;] listring[detached:sbz_armor:%s;main] listring[current_player;main] model[3.3,0.2;3,5;model;%s;%s;0,180] hypertext[6.5,0.2;3,5;htext;%s] - ]], name, name, props.mesh, table.concat(props.textures, ","), - core.formspec_escape(table.concat(hyper_text, "\n"))), + ]], + name, + name, + props.mesh, + table.concat(props.textures, ','), + core.formspec_escape(table.concat(hyper_text, '\n')) + ), } end, }) -local modpath = core.get_modpath("sbz_armor") -dofile(modpath .. "/armor_recipes.lua") -dofile(modpath .. "/armor_types.lua") +local modpath = core.get_modpath 'sbz_armor' +dofile(modpath .. '/armor_recipes.lua') +dofile(modpath .. '/armor_types.lua') diff --git a/mods/sbz_base/init.lua b/mods/sbz_base/init.lua index eb1b8eed..0d858481 100644 --- a/mods/sbz_base/init.lua +++ b/mods/sbz_base/init.lua @@ -365,10 +365,12 @@ core.register_globalstep(function(_) end) -- inter-mod utils +-- use sbz_api.count_nodes_within_radius this is deprecated function count_nodes_within_radius(pos, nodenames, radius) local radius_vector = vector.new(radius, radius, radius) return #core.find_nodes_in_area(vector.subtract(pos, radius_vector), vector.add(pos, radius_vector), nodenames) end +sbz_api.count_nodes_within_radius = count_nodes_within_radius -- returns the first node pos function is_node_within_radius(pos, nodenames, radius) diff --git a/mods/sbz_pipeworks/autocrafter.lua b/mods/sbz_pipeworks/autocrafter.lua index 8a1dca12..d25066f7 100644 --- a/mods/sbz_pipeworks/autocrafter.lua +++ b/mods/sbz_pipeworks/autocrafter.lua @@ -112,7 +112,7 @@ end local function reserved_items_formspec(pos) local fs = {} - local offset = { 0.22, 4 } + local offset = { 0.22, 4.3 } local reserved_slots = get_reserved_slots_or_reserve_them(pos) for i = 1, 9 do local name = reserved_slots[i] diff --git a/mods/sbz_resources/init.lua b/mods/sbz_resources/init.lua index b13b9f75..105235c4 100644 --- a/mods/sbz_resources/init.lua +++ b/mods/sbz_resources/init.lua @@ -1,18 +1,19 @@ -local modpath = minetest.get_modpath("sbz_resources") +local modpath = minetest.get_modpath 'sbz_resources' -- dofiles -dofile(modpath .. "/basic_resources.lua") -dofile(modpath .. "/emitters.lua") -dofile(modpath .. "/nodes.lua") -dofile(modpath .. "/water.lua") -dofile(modpath .. "/tools.lua") -dofile(modpath .. "/storinators.lua") -dofile(modpath .. "/items.lua") -dofile(modpath .. "/logic_craftitems.lua") -dofile(modpath .. "/jetpack.lua") -dofile(modpath .. "/strange_matter.lua") -dofile(modpath .. "/fireworks.lua") -dofile(modpath .. "/laser.lua") -dofile(modpath .. "/bomb.lua") -dofile(modpath .. "/crystals.lua") -dofile(modpath .. "/processors_and_circuits.lua") +dofile(modpath .. '/basic_resources.lua') +dofile(modpath .. '/emitters.lua') +dofile(modpath .. '/nodes.lua') +dofile(modpath .. '/water.lua') +dofile(modpath .. '/tools.lua') +dofile(modpath .. '/storinators.lua') +dofile(modpath .. '/items.lua') +dofile(modpath .. '/logic_craftitems.lua') +dofile(modpath .. '/jetpack.lua') +dofile(modpath .. '/strange_matter.lua') +dofile(modpath .. '/fireworks.lua') +dofile(modpath .. '/laser.lua') +dofile(modpath .. '/bomb.lua') +dofile(modpath .. '/crystals.lua') +dofile(modpath .. '/processors_and_circuits.lua') +dofile(modpath .. '/parkour.lua') diff --git a/mods/sbz_resources/parkour.lua b/mods/sbz_resources/parkour.lua new file mode 100644 index 00000000..6af384ac --- /dev/null +++ b/mods/sbz_resources/parkour.lua @@ -0,0 +1,56 @@ +-- Here should be anything related to parkour +-- Like even ladders +-- but they are in sbz_decor +-- so im not bringing them here + +-- what should sbz_resources even be responsible for... should it have all the nodedefs/machine defs? +-- I think yes! but idk + +core.register_node( + 'sbz_resources:emittrium_block', + unifieddyes.def { + description = 'Emittrium Block', + info_extra = 'You should punch it, and place some close to eachother.', + paramtype2 = 'color', + groups = { matter = 1 }, + tiles = { 'emittrium_block.png' }, + + -- imagine if someone punches it 30 times/the same globalstep + -- now imagine me caring + on_punch = function(pos, node, puncher, _) + if not puncher:is_player() then return end + local dir = puncher:get_pos() - pos + + -- okay, so the punching strength is multiplied by how many emittrium blocks are nearby + -- could do some stupid search but i dont want to + -- so instead.. + local strength = 2 + (sbz_api.count_nodes_within_radius(pos, 'sbz_resources:emittrium_block', 1) * 2) + core.add_particlespawner { + amount = strength * 8, + time = 0.01, + texture = { name = 'star.png^[colorize:cyan', alpha = 2, scale_tween = { 1.5, 0 }, blend = 'add' }, + exptime = 2, + glow = 14, + pos = pos, + radius = 0.5, + vel = vector.multiply(dir, strength / 2), + attract = { + kind = 'point', + strength = -5, + origin = pos, + }, + } + puncher:add_velocity(vector.multiply(dir, strength)) + end, + } +) + +core.register_craft { + type = 'shaped', + output = 'sbz_resources:emittrium_block', + recipe = { + { 'sbz_resources:raw_emittrium', 'sbz_resources:raw_emittrium', 'sbz_resources:raw_emittrium' }, + { 'sbz_resources:raw_emittrium', 'sbz_resources:raw_emittrium', 'sbz_resources:raw_emittrium' }, + { 'sbz_resources:raw_emittrium', 'sbz_resources:raw_emittrium', 'sbz_resources:raw_emittrium' }, + }, +} diff --git a/mods/sbz_resources/textures/emittrium_block.png b/mods/sbz_resources/textures/emittrium_block.png new file mode 100644 index 0000000000000000000000000000000000000000..0cc0e194276d0eeae47eaf426a588939ba9eccf9 GIT binary patch literal 151 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`ah@)YAr`&KAv5dW+cUE^v^F+2 zK8*C$h@7=FD$LkGk^4;Lj-~}_C8j~}D1;f!pGXjn6iv)^jbffbC+ yrx=og6wS73aCY8U(qpVBID5)OM&+e9B^kCyC?r11X*~h7iNVv=&t;ucLK6V*%rP$j literal 0 HcmV?d00001 From 8a606db484c7e4ce7e23225f7aa202823d8c671b Mon Sep 17 00:00:00 2001 From: TheEt1234 Date: Wed, 14 Jan 2026 17:51:07 +0100 Subject: [PATCH 27/28] Add /community --- mods/sbz_base/init.lua | 55 ++++++++++++++++++++--------------- mods/sbz_meteorites/nodes.lua | 8 ++--- 2 files changed, 36 insertions(+), 27 deletions(-) diff --git a/mods/sbz_base/init.lua b/mods/sbz_base/init.lua index 0d858481..a9c9d877 100644 --- a/mods/sbz_base/init.lua +++ b/mods/sbz_base/init.lua @@ -59,24 +59,34 @@ sbz_api.get_simple_version_string = function() return 'SkyBlock: Zero (Release ' .. sbz_api.version .. (sbz_api.is_version_dev and '-dev' or '') .. ')' end ---vector.random_direction was added in 5.10-dev, but this is defined here for support ---code borrowed from builtin/vector.lua in 5.10-dev -if not vector.random_direction then - ---@return vector - function vector.random_direction() - -- Generate a random direction of unit length, via rejection sampling - local x, y, z, l2 - repeat -- expected less than two attempts on average (volume sphere vs. cube) - x, y, z = math.random() * 2 - 1, math.random() * 2 - 1, math.random() * 2 - 1 - l2 = x * x + y * y + z * z - until l2 <= 1 and l2 >= 1e-6 - -- normalize - local l = math.sqrt(l2) - return vector.new(x / l, y / l, z / l) - end -end +-- /community is added here, because it's what a fork is likely to change +core.register_chatcommand('community', { + privs = { ['interact'] = true }, -- useful in a server i guess? if someone has had their interact taken away, they might not have the best things to add to discussions + func = function(name, param) + core.show_formspec( + name, + 'sbz_base:blabla_does_not_matter_and_i_am_thankful_for_it', + [[ +formspec_version[8] +size[15,5] --- not the exact implementations +container[0.2,0.2] +hypertext[0,0;14.8,4.8;_; + + +If you have any bug reports or suggestions for Skyblock: Zero, or simply just want to talk about it with other people, you may reach out to these places: + +Github: https://github.com/ChefZander/skyblock_zero +Discord: https://discord.gg/kHPbzrfcJ4 +] +container_end[] + ]] + ) + end, +}) + +-- not the exact implementations of table.foreach/i +-- try not using them i guess, only when its really elegant and you are like proud of it ---@param key_last boolean ---@diagnostic disable-next-line: duplicate-set-field @@ -253,13 +263,12 @@ core.register_chatcommand('bgm_volume', { }) core.register_on_joinplayer(function(player) + local player_name = player:get_player_name() -- send welcome messages - core.chat_send_player(player:get_player_name(), sbz_api.get_simple_version_string()) - core.chat_send_player( - player:get_player_name(), - '‼ reminder: If you fall off, use /core to teleport back to the core.' - ) - core.chat_send_player(player:get_player_name(), '‼ reminder: If lose your Quest Book, use /qb to get it back.') + core.chat_send_player(player_name, sbz_api.get_simple_version_string()) + core.chat_send_player(player_name, '‼ reminder: If you fall off, use /core to teleport back to the core.') + core.chat_send_player(player_name, '‼ reminder: If lose your Quest Book, use /qb to get it back.') + core.chat_send_player(player_name, '!! If you have any suggestions/bug reports to Skyblock Zero, see /community') -- play bgm playRandomBGM(player) diff --git a/mods/sbz_meteorites/nodes.lua b/mods/sbz_meteorites/nodes.lua index d824b8f4..b3ad0aed 100644 --- a/mods/sbz_meteorites/nodes.lua +++ b/mods/sbz_meteorites/nodes.lua @@ -1,6 +1,6 @@ local matter_items = {} for _ = 1, 8 do - matter_items[#matter_items + 1] = { rarity = 2, items = { 'sbz_resources:matter_dust 8' } } + matter_items[#matter_items + 1] = { rarity = 2, items = { 'sbz_resources:matter_blob 8' } } end minetest.register_node('sbz_meteorites:meteoric_matter', { description = 'Meteoric Matter', @@ -17,7 +17,7 @@ minetest.register_node('sbz_meteorites:meteoric_matter', { local antimatter_items = { max_items = 6 } for _ = 1, 8 do - antimatter_items[#antimatter_items + 1] = { rarity = 2, items = { 'sbz_resources:antimatter_dust 8' } } + antimatter_items[#antimatter_items + 1] = { rarity = 2, items = { 'sbz_resources:antimatter_blob 8' } } end minetest.register_node('sbz_meteorites:meteoric_antimatter', { @@ -35,7 +35,7 @@ minetest.register_node('sbz_meteorites:meteoric_antimatter', { local emittrium_items = {} for _ = 1, 8 do - emittrium_items[#emittrium_items + 1] = { rarity = 2, items = { 'sbz_resources:raw_emittrium 3' } } + emittrium_items[#emittrium_items + 1] = { rarity = 2, items = { 'sbz_resources:raw_emittrium 8' } } end minetest.register_node('sbz_meteorites:meteoric_emittrium', { @@ -56,7 +56,7 @@ local processed_drops = {} for k, v in ipairs(drops) do local item = ItemStack(v) - item:set_count(8) + item:set_count(16) processed_drops[#processed_drops + 1] = { rarity = 2, items = { item:to_string() }, From 814290d198a38a7ae421fbe1897327137ea5a246 Mon Sep 17 00:00:00 2001 From: TheEt1234 Date: Thu, 15 Jan 2026 15:04:20 +0100 Subject: [PATCH 28/28] Fix recipe for bricks --- mods/sbz_decor/init.lua | 2 +- mods/sbz_resources/nodes.lua | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/mods/sbz_decor/init.lua b/mods/sbz_decor/init.lua index 97583511..b1bbe05b 100644 --- a/mods/sbz_decor/init.lua +++ b/mods/sbz_decor/init.lua @@ -134,7 +134,7 @@ minetest.register_node('sbz_decor:mystery_terrarium', { minetest.register_craft { output = 'sbz_decor:mystery_terrarium', type = 'shapeless', - recipe = { 'sbz_bio:habitat_regulator', 'sbz_bio:screen_inverter_potion', 'sbz_chem:thorium_fluid_cell' }, + recipe = { 'sbz_bio:habitat_regulator', 'sbz_bio:screen_inverter_potion', 'sbz_chem:thorium_powder' }, } minetest.register_node( diff --git a/mods/sbz_resources/nodes.lua b/mods/sbz_resources/nodes.lua index 73cc1a19..569c2c04 100644 --- a/mods/sbz_resources/nodes.lua +++ b/mods/sbz_resources/nodes.lua @@ -488,7 +488,7 @@ minetest.register_abm { minetest.register_node('sbz_resources:clay', { description = 'Clay', - tiles = { 'clay.png' }, -- Needs retexture by artist + tiles = { 'clay.png' }, groups = { matter = 1, charged = 1, sand = 1, falling_node = 1, explody = 40 }, walkable = true, sounds = sbz_api.sounds.sand(), @@ -519,7 +519,7 @@ minetest.register_node( minetest.register_craft { type = 'cooking', output = 'sbz_resources:bricks', - recipe = 'sbz_resources:clay', + recipe = 'sbz_bio:dirt', } stairs.register 'sbz_resources:bricks'