From 8cc1c827177a72be5a5b1ac9fb49978afd1fe220 Mon Sep 17 00:00:00 2001 From: Luke aka SwissalpS <161979+SwissalpS@users.noreply.github.com> Date: Fri, 29 Nov 2024 10:45:55 +0100 Subject: [PATCH] Limit texture size (#6) * whitespace and minetest. -> core. - use same whitespace style throughout and fix some indents. - change from minetest. to core. namespace. * Update Readme: Minetest -> Luanti * add luacheck * update optional depends * luacheck cleanups - unused arguments - shaddowed vars - var redeclarations - some whitespace involved in above lines * clean close of file after reading * avoid duplicate code save some lines and some extra method calls. * avoid error: "unknown global" * stray whitespace fixups * whitespace: switch all files to same indent character tabs -> spaces * refactor weird declaration * whitespace: two stray spaces ...that slipped through the cracks on previous whitespace edit * fix shaddowing global table * reduce amount of times transformation string is calculated * use ipairs feature or use the faster repeat-until-loop * cap max amount of layers fixes #5 * fix #5 make transform history non-global fixes #5 transformation history was shared by all users and kept growing as it was never truely reset. Every time a user used a banner a white background was dumped on top of the stack making it possible to crash the server through an overflow to core.serialize() function. * minimize metadata size also changed banners.max_transformations to banners.max_undo_levels and lowered the value substantially. * add versioning * add recoverable per player history with saved colour * rename update_all -> update_preview_inv since it isn't updating everything, only the preview and the inventory item * dynamically update masks to reflect the currently selected colour. --- .github/workflows/luacheck.yml | 10 + .luacheckrc | 12 + README.md | 4 +- crafts.lua | 123 ++- factions.lua | 212 +++-- init.lua | 229 ++++-- items.lua | 65 +- mod.conf | 3 +- nodes.lua | 100 ++- smartfs.lua | 1386 ++++++++++++++++---------------- 10 files changed, 1105 insertions(+), 1039 deletions(-) create mode 100644 .github/workflows/luacheck.yml create mode 100644 .luacheckrc diff --git a/.github/workflows/luacheck.yml b/.github/workflows/luacheck.yml new file mode 100644 index 0000000..3c99a99 --- /dev/null +++ b/.github/workflows/luacheck.yml @@ -0,0 +1,10 @@ +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 diff --git a/.luacheckrc b/.luacheckrc new file mode 100644 index 0000000..77837ad --- /dev/null +++ b/.luacheckrc @@ -0,0 +1,12 @@ +globals = { + "banners", + "smartfs", +} + +read_globals = { + "core", + "dump", + "factions", + "inventory_plus", + "unified_inventory", +} diff --git a/README.md b/README.md index cd4e270..9457854 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -###Banners mod for Minetest -This is the banner mod for minetest. +###Banners mod for Luanti (formerly Minetest) +This is a banner mod for Luanti. The source code is licensed under GPLv3, and the game assets are licensed under Creative Commons 0 (CC0, [https://wiki.creativecommons.org/wiki/CC0](see here)). diff --git a/crafts.lua b/crafts.lua index dadaebc..8f6aa89 100644 --- a/crafts.lua +++ b/crafts.lua @@ -1,78 +1,73 @@ -- craft recipes -minetest.register_craft( -- wooden flag pole - { - output = "banners:wooden_pole 1", - recipe = { - {"", "", "default:stick"}, - {"", "default:stick", ""}, - {"default:stick", "", ""} - } - } -) -minetest.register_craft( -- steel flag pole - { - output = "banners:steel_pole 1", - recipe = { - {"", "", "default:steel_ingot"}, - {"default:stick", "default:steel_ingot", "default:stick"}, - {"default:steel_ingot", "", ""} - } +-- wooden flag pole +core.register_craft({ + output = "banners:wooden_pole 1", + recipe = { + { "", "", "default:stick" }, + { "", "default:stick", "" }, + { "default:stick", "", "" } } -) +}) -minetest.register_craft( -- wooden flag support base - { - output = "banners:wooden_base 1", - recipe = { - {"", "default:stick", ""}, - {"default:stick", "", "default:stick"}, - {"group:wood", "group:wood", "group:wood"} - } +-- steel flag pole +core.register_craft({ + output = "banners:steel_pole 1", + recipe = { + { "", "", "default:steel_ingot" }, + { "default:stick", "default:steel_ingot", "default:stick" }, + { "default:steel_ingot", "", "" } } -) +}) -minetest.register_craft( -- steel support - { - output = "banners:steel_base", - recipe = { - {"", "default:steel_ingot", ""}, - {"default:steel_ingot", "", "default:steel_ingot"}, - {"", "default:steelblock", ""} - } +-- wooden flag support base +core.register_craft({ + output = "banners:wooden_base 1", + recipe = { + { "", "default:stick", "" }, + { "default:stick", "", "default:stick" }, + { "group:wood", "group:wood", "group:wood" } } -) +}) -minetest.register_craft( -- banner sheet - { - output = "banners:banner_sheet 1", - recipe = { - {"", "", ""}, - {"farming:cotton", "farming:cotton", "farming:cotton"}, - {"farming:cotton", "farming:cotton", "farming:cotton"} - } +-- steel support +core.register_craft({ + output = "banners:steel_base", + recipe = { + { "", "default:steel_ingot", "" }, + { "default:steel_ingot", "", "default:steel_ingot" }, + { "", "default:steelblock", "" } } -) +}) -minetest.register_craft( -- wooden support - { - output = "banners:wooden_banner 1", - recipe = { - {"", "banners:banner_sheet", ""}, - {"", "banners:wooden_pole", ""}, - {"", "banners:wooden_base", ""} - } +-- banner sheet +core.register_craft({ + output = "banners:banner_sheet 1", + recipe = { + { "", "", "" }, + { "farming:cotton", "farming:cotton", "farming:cotton" }, + { "farming:cotton", "farming:cotton", "farming:cotton" } } -) +}) -minetest.register_craft( -- steel support - { - output = "banners:steel_banner 1", - recipe = { - {"", "banners:banner_sheet", ""}, - {"", "banners:steel_pole", ""}, - {"", "banners:steel_base", ""} - } +-- wooden support +core.register_craft({ + output = "banners:wooden_banner 1", + recipe = { + { "", "banners:banner_sheet", "" }, + { "", "banners:wooden_pole", "" }, + { "", "banners:wooden_base", "" } } -) +}) + +-- steel support +core.register_craft({ + output = "banners:steel_banner 1", + recipe = { + { "", "banners:banner_sheet", "" }, + { "", "banners:steel_pole", "" }, + { "", "banners:steel_base", "" } + } +}) + diff --git a/factions.lua b/factions.lua index 9a327ae..aab0cf1 100644 --- a/factions.lua +++ b/factions.lua @@ -1,43 +1,43 @@ banners.power_per_banner = 10. -- items -minetest.register_craftitem("banners:golden_finial", { +core.register_craftitem("banners:golden_finial", { groups = {}, description = "Golden finial", inventory_image = "gold_finial.png", }) -minetest.register_craftitem("banners:silver_pole", { +core.register_craftitem("banners:silver_pole", { groups = {}, description = "Silver pole", inventory_image = "silver_pole.png" }) -minetest.register_craftitem("banners:power_pole", { +core.register_craftitem("banners:power_pole", { groups = {}, description = "Power pole", inventory_image = "power_pole.png" }) -minetest.register_craftitem("banners:golden_sheet", { +core.register_craftitem("banners:golden_sheet", { groups = {}, description = "Golden sheet", inventory_image = "golden_sheet.png" }) -minetest.register_craftitem("banners:death_pole", { +core.register_craftitem("banners:death_pole", { groups = {}, description = "Death pole", inventory_image = "death_pole.png" }) -minetest.register_craftitem("banners:death_sheet", { +core.register_craftitem("banners:death_sheet", { groups = {}, description = "Death sheet", inventory_image = "death_sheet.png" }) -minetest.register_craftitem("banners:death_base", { +core.register_craftitem("banners:death_base", { groups = {}, description = "Death base", inventory_image = "death_base.png" @@ -46,107 +46,98 @@ minetest.register_craftitem("banners:death_base", { -- crafts -minetest.register_craft( -- silver flag pole - { - output = "banners:silver_pole 1", - recipe = { - {"", "", "moreores:silver_ingot"}, - {"", "moreores:silver_ingot", ""}, - {"moreores:silver_ingot", "", ""} - } +-- silver flag pole +core.register_craft({ + output = "banners:silver_pole 1", + recipe = { + { "", "", "moreores:silver_ingot" }, + { "", "moreores:silver_ingot", "" }, + { "moreores:silver_ingot", "", "" } } -) +}) -minetest.register_craft( -- death flag pole - { - output = "banners:death_pole 1", - recipe = { - {"", "", "default:diamond"}, - {"", "default:obsidian", ""}, - {"default:obsidian", "", ""} - } +-- death flag pole +core.register_craft({ + output = "banners:death_pole 1", + recipe = { + { "", "", "default:diamond" }, + { "", "default:obsidian", "" }, + { "default:obsidian", "", "" } } -) +}) -minetest.register_craft( -- golden finial - { - output = "banners:golden_finial", - recipe = { - {"", "default:gold_ingot", "default:gold_ingot"}, - {"", "default:gold_ingot", "default:gold_ingot"}, - {"default:gold_ingot", "", ""} - } +-- golden finial +core.register_craft({ + output = "banners:golden_finial", + recipe = { + { "", "default:gold_ingot", "default:gold_ingot" }, + { "", "default:gold_ingot", "default:gold_ingot" }, + { "default:gold_ingot", "", "" } } -) +}) -minetest.register_craft( -- power flag pole - { - output = "banners:power_pole 1", - recipe = { - {"", "", ""}, - {"", "banners:golden_finial", ""}, - {"banners:silver_pole", "", ""} - } +-- power flag pole +core.register_craft({ + output = "banners:power_pole 1", + recipe = { + { "", "", "" }, + { "", "banners:golden_finial", "" }, + { "banners:silver_pole", "", "" } } -) +}) -minetest.register_craft( -- golden sheet - { - output = "banners:golden_sheet 1", - type = "shapeless", - recipe = { "default:gold_ingot", "banners:banner_sheet"} - } -) +-- golden sheet +core.register_craft({ + output = "banners:golden_sheet 1", + type = "shapeless", + recipe = { "default:gold_ingot", "banners:banner_sheet" } +}) -minetest.register_craft( -- death sheet - { - output = "banners:death_sheet 1", - type = "shapeless", - recipe = { "default:obsidian", "banners:banner_sheet"} - } -) +-- death sheet +core.register_craft({ + output = "banners:death_sheet 1", + type = "shapeless", + recipe = { "default:obsidian", "banners:banner_sheet" } +}) -minetest.register_craft( -- death sheet - { - output = "banners:death_base 1", - recipe = { - {"", "", ""}, - {"", "banners:steel_base", ""}, - {"default:obsidian", "default:obsidian", "default:obsidian"} - } +-- death sheet +core.register_craft({ + output = "banners:death_base 1", + recipe = { + { "", "", "" }, + { "", "banners:steel_base", "" }, + { "default:obsidian", "default:obsidian", "default:obsidian" } } -) +}) -minetest.register_craft( -- power banner - { - output = "banners:power_banner", - recipe = { - {"", "banners:golden_sheet", ""}, - {"", "banners:power_pole", ""}, - {"", "banners:steel_base", ""} - } +-- power banner +core.register_craft({ + output = "banners:power_banner", + recipe = { + { "", "banners:golden_sheet", "" }, + { "", "banners:power_pole", "" }, + { "", "banners:steel_base", "" } } -) +}) -minetest.register_craft( -- death banner - { - output = "banners:death_banner", - recipe = { - {"", "banners:death_sheet", ""}, - {"", "banners:death_pole", ""}, - {"", "banners:death_base", ""} - } +-- death banner +core.register_craft({ + output = "banners:death_banner", + recipe = { + { "", "banners:death_sheet", "" }, + { "", "banners:death_pole", "" }, + { "", "banners:death_base", "" } } -) +}) -- nodes -minetest.register_node("banners:power_banner", { +core.register_node("banners:power_banner", { drawtype = "mesh", mesh = "banner_support.x", - tiles = {"gold_support.png"}, + tiles = { "gold_support.png" }, description = "Power Banner", - groups = {cracky=3}, + groups = { cracky = 3 }, is_ground_content = false, diggable = true, stack_max = 1, @@ -154,15 +145,15 @@ minetest.register_node("banners:power_banner", { paramtype2 = "facedir", after_place_node = function (pos, player, itemstack, pointed_thing) banners.after_powerbanner_placed(pos, player, itemstack, pointed_thing) - end, + end, on_destruct = function(pos) banners.banner_on_destruct(pos) end, on_dig = function(pos, n, p) - if minetest.is_protected(pos, p:get_player_name()) then + if core.is_protected(pos, p:get_player_name()) then return end - local meta = minetest.get_meta(pos) + local meta = core.get_meta(pos) local facname = meta:get_string("faction") if facname then local faction = factions.factions[facname] @@ -174,12 +165,12 @@ minetest.register_node("banners:power_banner", { end, }) -minetest.register_node("banners:death_banner", { +core.register_node("banners:death_banner", { drawtype = "mesh", mesh = "banner_support.x", - tiles = {"death_uv.png"}, + tiles = { "death_uv.png" }, description = "Death Banner", - groups = {cracky=3}, + groups = { cracky = 3 }, is_ground_content = false, diggable = true, stack_max = 1, @@ -187,15 +178,16 @@ minetest.register_node("banners:death_banner", { paramtype2 = "facedir", after_place_node = function (pos, player, itemstack, pointed_thing) banners.after_deathbanner_placed(pos, player, itemstack, pointed_thing) - end, + end, on_destruct = function(pos) banners.banner_on_destruct(pos) end, - on_dig = function(pos, n, p) - if minetest.is_protected(pos, p:get_player_name()) then + -- (pos, node, player) + on_dig = function(pos, _, player) + if core.is_protected(pos, player:get_player_name()) then return end - local meta = minetest.get_meta(pos) + local meta = core.get_meta(pos) local defending_facname = meta:get_string("faction") local parcelpos = factions.get_parcel_pos(pos) if defending_facname then @@ -204,34 +196,36 @@ minetest.register_node("banners:death_banner", { faction:stop_attack(parcelpos) end end - minetest.remove_node(pos) + core.remove_node(pos) end, }) -banners.after_powerbanner_placed = function(pos, player, itemstack, pointed_thing) - minetest.get_node(pos).param2 = banners.determine_flag_direction(pos, pointed_thing) +-- (pos, player, itemstack, pointed_thing) +banners.after_powerbanner_placed = function(pos, player, _, pointed_thing) + core.get_node(pos).param2 = banners.determine_flag_direction(pos, pointed_thing) local faction = factions.players[player:get_player_name()] if not faction then - minetest.get_meta(pos):set_string("banner", "bg_white.png") + core.get_meta(pos):set_string("banner", "bg_white.png") else local banner_string = factions.factions[faction].banner - minetest.get_meta(pos):set_string("banner", banner_string) - minetest.get_meta(pos):set_string("faction", faction) + core.get_meta(pos):set_string("banner", banner_string) + core.get_meta(pos):set_string("faction", faction) factions.factions[faction]:increase_maxpower(banners.power_per_banner) end - minetest.add_entity(pos, "banners:banner_ent") + core.add_entity(pos, "banners:banner_ent") end -banners.after_deathbanner_placed = function(pos, player, itemstack, pointed_thing) - minetest.get_node(pos).param2 = banners.determine_flag_direction(pos, pointed_thing) +-- (pos, player, itemstack, pointed_thing) +banners.after_deathbanner_placed = function(pos, player, _, pointed_thing) + core.get_node(pos).param2 = banners.determine_flag_direction(pos, pointed_thing) local attacking_faction = factions.players[player:get_player_name()] if attacking_faction then local parcelpos = factions.get_parcel_pos(pos) attacking_faction = factions.factions[attacking_faction] attacking_faction:attack_parcel(parcelpos) - minetest.get_meta(pos):set_string("faction", attacking_faction.name) + core.get_meta(pos):set_string("faction", attacking_faction.name) end - minetest.get_meta(pos):set_string("banner", "death_uv.png") - minetest.add_entity(pos, "banners:banner_ent") + core.get_meta(pos):set_string("banner", "death_uv.png") + core.add_entity(pos, "banners:banner_ent") end diff --git a/init.lua b/init.lua index a080bf7..427294c 100644 --- a/init.lua +++ b/init.lua @@ -1,6 +1,9 @@ -dofile(minetest.get_modpath("banners").."/smartfs.lua") +local MP = core.get_modpath("banners") .. "/" +dofile(MP .. "smartfs.lua") -banners = {} +banners = { + version = 20241128.1533 +} banners.masks = { "bend_left", "bend_left_outline", @@ -28,6 +31,15 @@ banners.masks = { "star_chevron", "checkered_8_4", "checkered_16_8" } +-- It is now unlikely for the server to crash from too long +-- history since we now trim out garbage when converting to +-- metadata. This limit is now just to avoid run-time +-- memory bloat. +banners.max_undo_levels = 256 + +-- cache of player histories +local histories = {} + banners.colors = { "black", "cyan", "green", "white", "blue", "darkblue", "red", "yellow", @@ -35,58 +47,71 @@ banners.colors = { "brown", "darkbrown" } -banners.base_transform = ({texture = "bg_white.png", - mask="mask_background.png"}) +banners.base_transform = { + texture = "bg_white.png", + mask = "mask_background.png" +} banners.creation_form_func = function(state) -- helper functions - state.update_player_inv = function(self) - local player = minetest.get_player_by_name(self.player) + state.update_player_inv = function(self, transform_string) + local player = core.get_player_by_name(self.player) local newbanner = player:get_wielded_item() - newbanner:get_meta():set_string("", state.banner:get_transform_string()) + newbanner:get_meta():set_string("", transform_string) player:set_wielded_item(newbanner) end - state.update_preview = function(self) - self:get("banner_preview"):setImage(self.banner:get_transform_string()) + state.update_preview = function(self, transform_string) + self:get("banner_preview"):setImage(transform_string) self:get("color_indicator"):setImage(self.current_color) end - state.update_all = function(self) - self:update_preview() - self:update_player_inv() + state.update_preview_inv = function(self) + local transform_string = self.banner:get_transform_string() + self:update_preview(transform_string) + self:update_player_inv(transform_string) end - -- initialize with empty banner - state.banner = banners.Banner:new(nil) - state.banner:push_transform(banners.base_transform) - state.current_color = "bg_white.png" - state:size(20,10) + if histories[state.player] then + -- initialize with saved history + state.banner = histories[state.player] + else + -- initialize with empty banner + state.banner = banners.Banner:new(nil) + state.banner:push_transform(banners.base_transform) + histories[state.player] = state.banner + end + state.current_color = state.banner.color + state:size(20, 10) state:image(3, 0.4, 4, 2, "banner_preview", nil) state:image(2.4, 0.8, 0.7, 0.7, "color_indicator", state.current_color) - state:update_all() + state:update_preview_inv() -- color indicator -- undo button - state:button(0.5, 0.3, 2, 1, "undo", "Undo"):click(function(self, state) - if #state.banner.transforms > 1 then - state.banner:pop_transform() - state:update_all() - end - end) + state:button(0.5, 0.3, 2, 1, "undo", "Undo"):click(function(_, state2) + if #state2.banner.transforms > 1 then + state2.banner:pop_transform() + state2:update_preview_inv() + end + end) -- delete button - state:button(0.5, 1.3, 2, 1, "delete", "Delete"):click(function(self, state) - state.banner.transforms = {banners.base_transform} - state:update_all() - end) + state:button(0.5, 1.3, 2, 1, "delete", "Delete"):click(function(_, state2) + state2.banner.transforms = { banners.base_transform } + state2:update_preview_inv() + end) -- add banners colors local x = 7 local y = .3 - for i in ipairs(banners.colors) do - local b = state:button(x, y, 1, 1, banners.colors[i], "") - b:setImage("bg_"..banners.colors[i]..".png") - b:click(function(self, state) - state.current_color = "bg_"..self.name..".png" - state:update_preview() - -- todo: update masks or something - end - ) + for _, color in ipairs(banners.colors) do + local b = state:button(x, y, 1, 1, color, "") + b:setImage("bg_" .. color .. ".png") + b:click(function(self, state2) + state2.current_color = "bg_" .. self.name .. ".png" + state2:get("color_indicator"):setImage(state2.current_color) + state2.banner.color = state2.current_color + -- update masks + for _, mask in ipairs(banners.masks) do + state2:get(mask):setImage("(" .. state2.current_color + .. "^[mask:" .. mask .. ".png^[makealpha:0,0,0)") + end + end) x = x + 1 if x > 19 then y = y + 1 @@ -94,16 +119,19 @@ banners.creation_form_func = function(state) end end -- add banners buttons - local x = 1 - local y = 3 - for i in ipairs(banners.masks) do - local b = state:button(x, y, 2, 1, banners.masks[i], "") - b:setImage(banners.masks[i]..".png") - b:click(function(self, state) - state.banner:push_transform({texture=state.current_color, mask=self.name..".png"}) - state:update_all() - end - ) + x = 1 + y = 3 + for _, mask in ipairs(banners.masks) do + local b = state:button(x, y, 2, 1, mask, "") + b:setImage("(" .. state.current_color + .. "^[mask:" .. mask .. ".png^[makealpha:0,0,0)") + b:click(function(self, state2) + state2.banner:push_transform({ + texture = state2.current_color, + mask = self.name .. ".png" + }) + state2:update_preview_inv() + end) x = x + 2 if x > 17.5 then y = y + 1 @@ -114,63 +142,90 @@ banners.creation_form_func = function(state) end banners.creation_form = smartfs.create("banners:banner_creation", - banners.creation_form_func); + banners.creation_form_func) -- banner definition -banners.Banner = { - transforms = {} -} +banners.Banner = {} + function banners.Banner:new(banner) - banner = banner or {} + banner = banner or { color = "bg_black.png", transforms = {} } setmetatable(banner, self) self.__index = self return banner end function banners.Banner.push_transform(self, transform) table.insert(self.transforms, transform) + if #self.transforms > banners.max_undo_levels then + table.remove(self.transforms, 1) + end end function banners.Banner.pop_transform(self) table.remove(self.transforms) end function banners.Banner.get_transform_string(self) local final = {} - for i in ipairs(self.transforms) do - table.insert(final, "("..self.transforms[i].texture.."^[mask:"..self.transforms[i].mask.."^[makealpha:0,0,0)") - end + local used = {} + local transform + -- work backwards to keep resulting data small + local i = #self.transforms + repeat + transform = self.transforms[i] + -- same mask can be trimmed out only using most recent + if not used[transform.mask] then + used[transform.mask] = true + table.insert(final, 1, "(" .. transform.texture + .. "^[mask:" .. transform.mask .. "^[makealpha:0,0,0)") + -- anything before a background is fully covered + if "mask_background.png" == transform.mask then + break + end + end + i = i - 1 + until i == 0 local ret = table.concat(final, "^") return ret end -- helper function for determining the flag's direction -banners.determine_flag_direction = function(pos, pointed_thing) +-- (pos, pointed_thing) +banners.determine_flag_direction = function(_, pointed_thing) local above = pointed_thing.above local under = pointed_thing.under - local dir = {x = under.x - above.x, - y = under.y - above.y, - z = under.z - above.z} - return minetest.dir_to_wallmounted(dir) + local dir = { + x = under.x - above.x, + y = under.y - above.y, + z = under.z - above.z + } + return core.dir_to_wallmounted(dir) end -banners.banner_on_use = function(itemstack, player, pointed_thing) +-- (itemstack, player, pointed_thing) +banners.banner_on_use = function(_, player) if player.is_player then banners.creation_form:show(player:get_player_name()) end end banners.banner_on_dig = function(pos, node, player) - if not player or minetest.is_protected(pos, player:get_player_name()) then + if not player or core.is_protected(pos, player:get_player_name()) then return end - local meta = minetest.get_meta(pos) + local meta = core.get_meta(pos) local inventory = player:get_inventory() - inventory:add_item("main", {name=node.name, count=1, wear=0, metadata=meta:get_string("banner")}) - minetest.remove_node(pos) + inventory:add_item("main", { + name = node.name, + count = 1, + wear = 0, + metadata = meta:get_string("banner") + }) + core.remove_node(pos) end -banners.banner_on_destruct = function(pos, node, player) - local objects = minetest.get_objects_inside_radius(pos, 0.5) - for _,v in ipairs(objects) do +-- (pos, node, player) +banners.banner_on_destruct = function(pos) + local objects = core.get_objects_inside_radius(pos, 0.5) + for _, v in ipairs(objects) do local e = v:get_luaentity() if e and e.name == "banners:banner_ent" then v:remove() @@ -178,23 +233,23 @@ banners.banner_on_destruct = function(pos, node, player) end end -banners.banner_after_place = function (pos, player, itemstack, pointed_thing) - minetest.get_node(pos).param2 = banners.determine_flag_direction(pos, pointed_thing) - minetest.get_meta(pos):set_string("banner", itemstack:get_meta():get_string("")) - minetest.add_entity(pos, "banners:banner_ent") +-- (pos, player, itemstack, pointed_thing) +banners.banner_after_place = function(pos, _, itemstack, pointed_thing) + core.get_node(pos).param2 = banners.determine_flag_direction(pos, pointed_thing) + core.get_meta(pos):set_string("banner", itemstack:get_meta():get_string("")) + core.add_entity(pos, "banners:banner_ent") end -- banner entity -local set_banner_texture -set_banner_texture = function (obj, texture) - obj:set_properties({textures={"banner_uv_text.png^"..texture}}) +local set_banner_texture = function(obj, texture) + obj:set_properties({ textures = { "banner_uv_text.png^" .. texture } }) end banners.banner_on_activate = function(self) local pos = self.object:get_pos() - local banner = minetest.get_meta(pos):get_string("banner") - local banner_face = minetest.get_node(pos).param2 + local banner = core.get_meta(pos):get_string("banner") + local banner_face = core.get_node(pos).param2 local yaw = 0. if banner_face == 2 then yaw = 0. @@ -211,21 +266,25 @@ banners.banner_on_activate = function(self) end end -minetest.register_entity("banners:banner_ent", { +core.register_entity("banners:banner_ent", { initial_properties = { - collisionbox = {0,0,0,0,0,0}, + collisionbox = { 0, 0, 0, 0, 0, 0 }, visual = "mesh", - textures = {"banner_uv_text"}, + textures = { "banner_uv_text" }, mesh = "banner_pole.x", }, on_activate = banners.banner_on_activate, }) -if minetest.get_modpath("factions") then - dofile(minetest.get_modpath("banners").."/factions.lua") +core.register_on_leaveplayer(function(player) + histories[player:get_player_name()] = nil +end) + +if core.get_modpath("factions") then + dofile(MP .. "factions.lua") end -dofile(minetest.get_modpath("banners").."/items.lua") -dofile(minetest.get_modpath("banners").."/nodes.lua") -dofile(minetest.get_modpath("banners").."/crafts.lua") +dofile(MP .. "items.lua") +dofile(MP .. "nodes.lua") +dofile(MP .. "crafts.lua") diff --git a/items.lua b/items.lua index 576f97c..8a40da5 100644 --- a/items.lua +++ b/items.lua @@ -2,44 +2,35 @@ -- items -minetest.register_craftitem("banners:banner_sheet", - { - groups = {}, - description = "Banner sheet", - inventory_image = "banner_sheet.png", - stack_max = 1, - metadata = "", - } -) +core.register_craftitem("banners:banner_sheet", { + groups = {}, + description = "Banner sheet", + inventory_image = "banner_sheet.png", + stack_max = 1, + metadata = "", +}) -minetest.register_craftitem("banners:wooden_pole", - { - groups = {}, - description = "Wooden pole", - inventory_image = "wooden_pole.png" - } -) +core.register_craftitem("banners:wooden_pole", { + groups = {}, + description = "Wooden pole", + inventory_image = "wooden_pole.png" +}) -minetest.register_craftitem("banners:wooden_base", - { - groups = {}, - description = "Wooden base", - inventory_image = "wooden_base.png" - } -) +core.register_craftitem("banners:wooden_base", { + groups = {}, + description = "Wooden base", + inventory_image = "wooden_base.png" +}) -minetest.register_craftitem("banners:steel_pole", - { - groups = {}, - description = "Steel pole", - inventory_image = "steel_pole.png" - } -) +core.register_craftitem("banners:steel_pole", { + groups = {}, + description = "Steel pole", + inventory_image = "steel_pole.png" +}) + +core.register_craftitem("banners:steel_base", { + groups = {}, + description = "Steel base", + inventory_image = "steel_base.png" +}) -minetest.register_craftitem("banners:steel_base", - { - groups = {}, - description = "Steel base", - inventory_image = "steel_base.png" - } -) diff --git a/mod.conf b/mod.conf index 342d3b8..66bc024 100644 --- a/mod.conf +++ b/mod.conf @@ -1,3 +1,4 @@ name = banners description = Adds customisable banners. -depends = default,farming \ No newline at end of file +depends = default, farming +optional_depends = factions, inventory_plus, unified_inventory diff --git a/nodes.lua b/nodes.lua index 3b869d4..ad2991c 100644 --- a/nodes.lua +++ b/nodes.lua @@ -1,57 +1,53 @@ -- da wooden banner -minetest.register_node("banners:wooden_banner", - { - drawtype = "mesh", - mesh = "banner_support.x", - tiles = {"banner_support.png"}, - description = "Wooden banner", - groups = {choppy=2, dig_immediate=2}, - is_ground_content = false, - diggable = true, - stack_max = 1, - paramtype="light", - paramtype2="facedir", - after_place_node = function (pos, player, itemstack, pointed_thing) - banners.banner_after_place(pos, player, itemstack, pointed_thing) - end, - on_destruct = function(pos) - banners.banner_on_destruct(pos) - end, - on_use = function(i, p, pt) - banners.banner_on_use(i, p, pt) - end, - on_dig = function(pos, n, p) - banners.banner_on_dig(pos, n, p) - end - } -) +core.register_node("banners:wooden_banner", { + drawtype = "mesh", + mesh = "banner_support.x", + tiles = { "banner_support.png" }, + description = "Wooden banner", + groups = { choppy = 2, dig_immediate = 2 }, + is_ground_content = false, + diggable = true, + stack_max = 1, + paramtype = "light", + paramtype2 = "facedir", + after_place_node = function (pos, player, itemstack, pointed_thing) + banners.banner_after_place(pos, player, itemstack, pointed_thing) + end, + on_destruct = function(pos) + banners.banner_on_destruct(pos) + end, + on_use = function(i, p, pt) + banners.banner_on_use(i, p, pt) + end, + on_dig = function(pos, n, p) + banners.banner_on_dig(pos, n, p) + end +}) -- steel banner -minetest.register_node("banners:steel_banner", - { - drawtype = "mesh", - mesh = "banner_support.x", - tiles = {"steel_support.png"}, - description = "Steel banner", - groups = {cracky=2}, - is_ground_content = false, - diggable = true, - stack_max = 1, - paramtype = "light", - paramtype2 = "facedir", - after_place_node = function (pos, player, itemstack, pointed_thing) - banners.banner_after_place(pos, player, itemstack, pointed_thing) - end, - on_destruct = function(pos) - banners.banner_on_destruct(pos) - end, - on_use = function(i, p, pt) - banners.banner_on_use(i, p, pt) - end, - on_dig = function(pos, n, p) - banners.banner_on_dig(pos, n, p) - end +core.register_node("banners:steel_banner", { + drawtype = "mesh", + mesh = "banner_support.x", + tiles = { "steel_support.png" }, + description = "Steel banner", + groups = { cracky = 2 }, + is_ground_content = false, + diggable = true, + stack_max = 1, + paramtype = "light", + paramtype2 = "facedir", + after_place_node = function (pos, player, itemstack, pointed_thing) + banners.banner_after_place(pos, player, itemstack, pointed_thing) + end, + on_destruct = function(pos) + banners.banner_on_destruct(pos) + end, + on_use = function(i, p, pt) + banners.banner_on_use(i, p, pt) + end, + on_dig = function(pos, n, p) + banners.banner_on_dig(pos, n, p) + end - } -) +}) diff --git a/smartfs.lua b/smartfs.lua index b93aaac..7675e61 100644 --- a/smartfs.lua +++ b/smartfs.lua @@ -4,311 +4,373 @@ -- by Rubenwardy --------------------------- +local has_inventory_plus = core.get_modpath("inventory_plus") and true or false +local has_unified_inventory = core.get_modpath("unified_inventory") and true or false + smartfs = { - _fdef = {}, - _edef = {}, - opened = {}, - inv = {} + _fdef = {}, + _edef = {}, + opened = {}, + inv = {} } -- the smartfs() function -function smartfs.__call(self, name) - return smartfs._fdef[name] +function smartfs.__call(_, name) + return smartfs._fdef[name] end -- Register forms and elements -function smartfs.create(name,onload) - if smartfs._fdef[name] then - error("SmartFS - (Error) Form "..name.." already exists!") - end - if smartfs.loaded and not smartfs._loaded_override then - error("SmartFS - (Error) Forms should be declared while the game loads.") - end +function smartfs.create(name, onload) + if smartfs._fdef[name] then + error("SmartFS - (Error) Form " .. name .. " already exists!") + end + if smartfs.loaded and not smartfs._loaded_override then + error("SmartFS - (Error) Forms should be declared while the game loads.") + end - smartfs._fdef[name] = { - _reg = onload, - name = name, - show = smartfs._show_ - } + smartfs._fdef[name] = { + _reg = onload, + name = name, + show = smartfs._show_ + } - return smartfs._fdef[name] + return smartfs._fdef[name] end function smartfs.override_load_checks() - smartfs._loaded_override = true + smartfs._loaded_override = true end -minetest.after(0, function() - smartfs.loaded = true +core.after(0, function() + smartfs.loaded = true end) -function smartfs.dynamic(name,player) - if not smartfs._dynamic_warned then - smartfs._dynamic_warned = true - print("SmartFS - (Warning) On the fly forms are being used. May cause bad things to happen") - end - local state = smartfs._makeState_({name=name},player,nil,false) - state.show = state._show_ - smartfs.opened[player] = state - return state +function smartfs.dynamic(name, player) + if not smartfs._dynamic_warned then + smartfs._dynamic_warned = true + print("SmartFS - (Warning) On the fly forms are being used. May cause bad things to happen") + end + local state = smartfs._makeState_({ name = name }, player, nil, false) + state.show = state._show_ + smartfs.opened[player] = state + return state end -function smartfs.element(name,data) - if smartfs._edef[name] then - error("SmartFS - (Error) Element type "..name.." already exists!") - end - smartfs._edef[name] = data - return smartfs._edef[name] +function smartfs.element(name, data) + if smartfs._edef[name] then + error("SmartFS - (Error) Element type " .. name .. " already exists!") + end + smartfs._edef[name] = data + return smartfs._edef[name] end function smartfs.inventory_mod() - if unified_inventory then - return "unified_inventory" - elseif inventory_plus then - return "inventory_plus" - else - return nil - end + if has_unified_inventory then + return "unified_inventory" + elseif has_inventory_plus then + return "inventory_plus" + else + return nil + end end -function smartfs.add_to_inventory(form,icon,title) - if unified_inventory then - unified_inventory.register_button(form.name, { - type = "image", - image = icon, - }) - unified_inventory.register_page(form.name, { - get_formspec = function(player, formspec) - local name = player:get_player_name() - local opened = smartfs._show_(form, name, nil, true) - return {formspec = opened:_getFS_(false)} - end - }) - return true - elseif inventory_plus then - minetest.register_on_joinplayer(function(player) - inventory_plus.register_button(player, form.name, title) - end) - minetest.register_on_player_receive_fields(function(player, formname, fields) - if formname == "" and fields[form.name] then - local name = player:get_player_name() - local opened = smartfs._show_(form, name, nil, true) - inventory_plus.set_inventory_formspec(player, opened:_getFS_(true)) - end - end) - return true - else - return false - end +function smartfs.add_to_inventory(form, icon, title) + if has_unified_inventory then + unified_inventory.register_button(form.name, { + type = "image", + image = icon, + }) + unified_inventory.register_page(form.name, { + -- (player, formspec) + get_formspec = function(player) + local name = player:get_player_name() + local opened = smartfs._show_(form, name, nil, true) + return { formspec = opened:_getFS_(false) } + end + }) + return true + elseif has_inventory_plus then + core.register_on_joinplayer(function(player) + inventory_plus.register_button(player, form.name, title) + end) + core.register_on_player_receive_fields(function(player, formname, fields) + if formname == "" and fields[form.name] then + local name = player:get_player_name() + local opened = smartfs._show_(form, name, nil, true) + inventory_plus.set_inventory_formspec(player, opened:_getFS_(true)) + end + end) + return true + else + return false + end end -function smartfs._makeState_(form,player,params,is_inv) - return { - _ele = {}, - def = form, - player = player, - param = params or {}, - is_inv = is_inv, - get = function(self,name) - return self._ele[name] - end, - close = function(self) - self.closed = true - end, - size = function(self,w,h) - self._size = {w=w,h=h} - end, - _getFS_ = function(self,size) - local res = "" - if self._size and size then - res = "size["..self._size.w..","..self._size.h.."]" - end - for key,val in pairs(self._ele) do - res = res .. val:build() - end - return res - end, - _show_ = function(self) - if self.is_inv then - if unified_inventory then - unified_inventory.set_inventory_formspec(minetest.get_player_by_name(self.player), self.def.name) - elseif inventory_plus then - inventory_plus.set_inventory_formspec(minetest.get_player_by_name(self.player), self:_getFS_(true)) - end - else - local res = self:_getFS_(true) - minetest.show_formspec(player,form.name,res) - end - end, - load = function(self,file) - local file = io.open(file, "r") - if file then - local table = minetest.deserialize(file:read("*all")) - if type(table) == "table" then - if table.size then - self._size = table.size - end - for key,val in pairs(table.ele) do - self:element(val.type,val) - end - return true - end - end - return false - end, - save = function(self,file) - local res = {ele={}} +function smartfs._makeState_(form, player, params, is_inv) + return { + _ele = {}, + def = form, + player = player, + param = params or {}, + is_inv = is_inv, + get = function(self,name) + return self._ele[name] + end, + close = function(self) + self.closed = true + end, + size = function(self, w, h) + self._size = { w = w, h = h } + end, + _getFS_ = function(self,size) + local res = "" + if self._size and size then + res = "size[" .. self._size.w .. "," .. self._size.h .. "]" + end + for _, val in pairs(self._ele) do + res = res .. val:build() + end + return res + end, + _show_ = function(self) + if self.is_inv then + if has_unified_inventory then + unified_inventory.set_inventory_formspec( + core.get_player_by_name(self.player), self.def.name) + elseif has_inventory_plus then + inventory_plus.set_inventory_formspec( + core.get_player_by_name(self.player), self:_getFS_(true)) + end + else + local res = self:_getFS_(true) + core.show_formspec(player, form.name, res) + end + end, + load = function(self, file_name) + local file = io.open(file_name, "r") + if file then + local data = core.deserialize(file:read("*all")) + file:close() + if type(data) == "table" then + if data.size then + self._size = data.size + end + for _, val in pairs(data.ele) do + self:element(val.type, val) + end + return true + end + end + return false + end, + save = function(self, file_name) + local res = { ele = {} } - if self._size then - res.size = self._size - end + if self._size then + res.size = self._size + end - for key,val in pairs(self._ele) do - res.ele[key] = val.data - end + for key, val in pairs(self._ele) do + res.ele[key] = val.data + end - local file = io.open(file, "w") - if file then - file:write(minetest.serialize(res)) - file:close() - return true - end - return false - end, - setparam = function(self,key,value) - if not key then return end - self.param[key] = value - return true - end, - getparam = function(self,key,default) - if not key then return end - return self.param[key] or default - end, - button = function(self,x,y,w,h,name,text,exitf) - if exitf == nil then exitf = false end - return self:element("button",{pos={x=x,y=y},size={w=w,h=h},name=name,value=text,closes=exitf}) - end, - label = function(self,x,y,name,text) - return self:element("label",{pos={x=x,y=y},name=name,value=text}) - end, - toggle = function(self,x,y,w,h,name,list) - return self:element("toggle",{pos={x=x,y=y},size={w=w,h=h},name=name,id=1,list=list}) - end, - field = function(self,x,y,w,h,name,label) - return self:element("field",{pos={x=x,y=y},size={w=w,h=h},name=name,value="",label=label}) - end, - pwdfield = function(self,x,y,w,h,name,label) - local res = self:element("field",{pos={x=x,y=y},size={w=w,h=h},name=name,value="",label=label}) - res:isPassword(true) - return res - end, - textarea = function(self,x,y,w,h,name,label) - local res = self:element("field",{pos={x=x,y=y},size={w=w,h=h},name=name,value="",label=label}) - res:isMultiline(true) - return res - end, - image = function(self,x,y,w,h,name,img) - return self:element("image",{pos={x=x,y=y},size={w=w,h=h},name=name,value=img}) - end, - checkbox = function(self,x,y,name,label,selected) - return self:element("checkbox",{pos={x=x,y=y},name=name,value=selected,label=label}) - end, - listbox = function(self,x,y,w,h,name,selected,transparent) - return self:element("list", { pos={x=x,y=y}, size={w=w,h=h}, name=name, selected=selected, transparent=transparent }) - end, - inventory = function(self,x,y,w,h,name) - return self:element("inventory", { pos={x=x,y=y}, size={w=w,h=h}, name=name }) - end, - element = function(self,typen,data) - local type = smartfs._edef[typen] + local file = io.open(file_name, "w") + if file then + file:write(core.serialize(res)) + file:close() + return true + end + return false + end, + setparam = function(self, key, value) + if not key then return end + self.param[key] = value + return true + end, + getparam = function(self, key, default) + if not key then return end + return self.param[key] or default + end, + button = function(self, x, y, w, h, name, text, exitf) + if exitf == nil then exitf = false end + return self:element("button", { + pos = { x = x, y = y }, + size = { w = w, h = h }, + name = name, + value = text, + closes = exitf + }) + end, + label = function(self, x, y, name, text) + return self:element("label", { + pos = { x = x, y = y }, + name = name, + value = text + }) + end, + toggle = function(self, x, y, w, h, name, list) + return self:element("toggle", { + pos = { x = x, y = y }, + size = { w = w, h = h }, + name = name, + id = 1, + list = list + }) + end, + field = function(self, x, y, w, h, name, label) + return self:element("field", { + pos = { x = x, y = y }, + size = { w = w, h = h }, + name = name, + value = "", + label = label + }) + end, + pwdfield = function(self, x, y, w, h, name, label) + local res = self:element("field", { + pos = { x = x, y = y }, + size = { w = w, h = h }, + name = name, + value = "", + label = label + }) + res:isPassword(true) + return res + end, + textarea = function(self, x, y, w, h, name, label) + local res = self:element("field", { + pos = { x = x, y = y }, + size = { w = w, h = h }, + name = name, + value = "", + label = label + }) + res:isMultiline(true) + return res + end, + image = function(self, x, y, w, h, name, img) + return self:element("image", { + pos = { x = x, y = y }, + size = { w = w, h = h }, + name = name, + value = img + }) + end, + checkbox = function(self, x, y, name, label, selected) + return self:element("checkbox", { + pos = { x = x, y = y }, + name = name, + value = selected, + label = label + }) + end, + listbox = function(self, x, y, w, h, name, selected, transparent) + return self:element("list", { + pos = { x = x, y = y }, + size = { w = w, h = h }, + name = name, + selected = selected, + transparent = transparent + }) + end, + inventory = function(self, x, y, w, h, name) + return self:element("inventory", { + pos = { x = x, y = y }, + size = { w = w, h = h }, + name = name + }) + end, + element = function(self, typen, data) + local type = smartfs._edef[typen] - if not type then - error("Element type "..typen.." does not exist!") - end + if not type then + error("Element type " .. typen .. " does not exist!") + end - if self._ele[data.name] then - error("Element "..data.name.." already exists") - end - data.type = typen + if self._ele[data.name] then + error("Element " .. data.name .. " already exists") + end + data.type = typen - local ele = { - name = data.name, - root = self, - data = data, - remove = function(self) - self.root._ele[self.name] = nil - end - } + local ele = { + name = data.name, + root = self, + data = data, + remove = function(self2) + self2.root._ele[self2.name] = nil + end + } - for key,val in pairs(type) do - ele[key] = val - end + for key, val in pairs(type) do + ele[key] = val + end - self._ele[data.name] = ele + self._ele[data.name] = ele - return self._ele[data.name] - end - } + return self._ele[data.name] + end + } end -- Show a formspec to a user function smartfs._show_(form, player, params, is_inv) - local state = smartfs._makeState_(form, player, params, is_inv) - state.show = state._show_ - if form._reg(state)~=false then - if not is_inv then - smartfs.opened[player] = state - state:_show_() - else - smartfs.inv[player] = state - end - end - return state + local state = smartfs._makeState_(form, player, params, is_inv) + state.show = state._show_ + if form._reg(state) ~= false then + if not is_inv then + smartfs.opened[player] = state + state:_show_() + else + smartfs.inv[player] = state + end + end + return state end -- Receive fields from formspec -local function _sfs_recieve_(state,name,fields) - if (fields.quit == "true") then - if not state.is_inv then - smartfs.opened[name] = nil - end - return true - end +local function _sfs_recieve_(state, name, fields) + if fields.quit == "true" then + if not state.is_inv then + smartfs.opened[name] = nil + end + return true + end - for key,val in pairs(fields) do - if state._ele[key] then - state._ele[key].data.value = val - end - end - for key,val in pairs(state._ele) do - if val.submit then - if (val:submit(fields)==true) then - return true - end - end - end - if state.closed ~= true then - state:_show_() - else - minetest.show_formspec(name,"","size[5,1]label[0,0;Formspec closing not yet created!]") - if not state.is_inv then - smartfs.opened[name] = nil - end - end - return true + for key, val in pairs(fields) do + if state._ele[key] then + state._ele[key].data.value = val + end + end + for _, val in pairs(state._ele) do + if val.submit then + if val:submit(fields) == true then + return true + end + end + end + if state.closed ~= true then + state:_show_() + else + core.show_formspec(name, "", + "size[5,1]label[0,0;Formspec closing not yet created!]") + if not state.is_inv then + smartfs.opened[name] = nil + end + end + return true end -minetest.register_on_player_receive_fields(function(player, formname, fields) - local name = player:get_player_name() - if smartfs.opened[name] and not smartfs.opened[name].is_inv then - if smartfs.opened[name].def.name == formname then - local state = smartfs.opened[name] - return _sfs_recieve_(state,name,fields) - else - smartfs.opened[name] = nil - end - elseif smartfs.inv[name] and smartfs.inv[name].is_inv then - local state = smartfs.inv[name] - _sfs_recieve_(state,name,fields) - end - return false +core.register_on_player_receive_fields(function(player, formname, fields) + local name = player:get_player_name() + if smartfs.opened[name] and not smartfs.opened[name].is_inv then + if smartfs.opened[name].def.name == formname then + local state = smartfs.opened[name] + return _sfs_recieve_(state, name, fields) + else + smartfs.opened[name] = nil + end + elseif smartfs.inv[name] and smartfs.inv[name].is_inv then + local state = smartfs.inv[name] + _sfs_recieve_(state, name, fields) + end + return false end) @@ -316,448 +378,394 @@ end) ------------------------- ELEMENTS ---------------------------- ----------------------------------------------------------------- -smartfs.element("button",{ - build = function(self) - if self.data.img then - return "image_button[".. - self.data.pos.x..","..self.data.pos.y.. - ";".. - self.data.size.w..","..self.data.size.h.. - ";".. - self.data.img.. - ";".. - self.name.. - ";".. - self.data.value.. - "]" - else - if self.data.closes then - return "button_exit[".. - self.data.pos.x..","..self.data.pos.y.. - ";".. - self.data.size.w..","..self.data.size.h.. - ";".. - self.name.. - ";".. - self.data.value.. - "]" - else - return "button[".. - self.data.pos.x..","..self.data.pos.y.. - ";".. - self.data.size.w..","..self.data.size.h.. - ";".. - self.name.. - ";".. - self.data.value.. - "]" - end - end - end, - submit = function(self,fields,state) - if fields[self.name] and self._click then - self:_click(self.root) - end +smartfs.element("button", { + build = function(self) + local common_prefix = self.data.pos.x .. "," .. self.data.pos.y + .. ";" .. self.data.size.w .. "," ..self.data.size.h + local common_sufix = ";" .. self.name + .. ";" .. self.data.value + .. "]" + if self.data.img then + return "image_button[" + .. common_prefix + .. ";" .. self.data.img + .. common_sufix + else + if self.data.closes then + return "button_exit[" .. common_prefix .. common_sufix + else + return "button[" .. common_prefix .. common_sufix + end + end + end, + -- (self, fields, state) + submit = function(self, fields) + if fields[self.name] and self._click then + self:_click(self.root) + end - if self.data.closes then - return true - end - end, - setPosition = function(self,x,y) - self.data.pos = {x=x,y=y} - end, - getPosition = function(self,x,y) - return self.data.pos - end, - setSize = function(self,w,h) - self.data.size = {w=w,h=h} - end, - getSize = function(self,x,y) - return self.data.size - end, - onClick = function(self,func) - self._click = func - end, - click = function(self,func) - self._click = func - end, - setText = function(self,text) - self.data.value = text - end, - getText = function(self) - return self.data.value - end, - setImage = function(self,image) - self.data.img = image - end, - getImage = function(self) - return self.data.img - end, - setClose = function(self,bool) - self.data.closes = bool - end + if self.data.closes then + return true + end + end, + setPosition = function(self, x, y) + self.data.pos = { x = x, y = y } + end, + getPosition = function(self) + return self.data.pos + end, + setSize = function(self, w, h) + self.data.size = { w = w, h = h } + end, + getSize = function(self) + return self.data.size + end, + onClick = function(self, func) + self._click = func + end, + click = function(self, func) + self._click = func + end, + setText = function(self, text) + self.data.value = text + end, + getText = function(self) + return self.data.value + end, + setImage = function(self, image) + self.data.img = image + end, + getImage = function(self) + return self.data.img + end, + setClose = function(self, bool) + self.data.closes = bool + end }) -smartfs.element("toggle",{ - build = function(self) - return "button[".. - self.data.pos.x..","..self.data.pos.y.. - ";".. - self.data.size.w..","..self.data.size.h.. - ";".. - self.name.. - ";".. - self.data.list[self.data.id].. - "]" - end, - submit = function(self,fields) - if fields[self.name] then - self.data.id = self.data.id + 1 - if self.data.id > #self.data.list then - self.data.id = 1 - end - if self._tog then - self:_tog(self.root) - end - end - end, - onToggle = function(self,func) - self._tog = func - end, - setPosition = function(self,x,y) - self.data.pos = {x=x,y=y} - end, - getPosition = function(self,x,y) - return self.data.pos - end, - setSize = function(self,w,h) - self.data.size = {w=w,h=h} - end, - getSize = function(self,x,y) - return self.data.size - end, - setId = function(self,id) - self.data.id = id - end, - getId = function(self) - return self.data.id - end, - getText = function(self) - return self.data.list[self.data.id] - end +smartfs.element("toggle", { + build = function(self) + return "button[" + .. self.data.pos.x .. "," .. self.data.pos.y + .. ";" .. self.data.size.w .. "," .. self.data.size.h + .. ";" .. self.name + .. ";" .. self.data.list[self.data.id] + .. "]" + end, + submit = function(self, fields) + if fields[self.name] then + self.data.id = self.data.id + 1 + if self.data.id > #self.data.list then + self.data.id = 1 + end + if self._tog then + self:_tog(self.root) + end + end + end, + onToggle = function(self, func) + self._tog = func + end, + setPosition = function(self, x, y) + self.data.pos = { x = x, y = y } + end, + getPosition = function(self) + return self.data.pos + end, + setSize = function(self, w, h) + self.data.size = { w = w, h = h } + end, + getSize = function(self) + return self.data.size + end, + setId = function(self, id) + self.data.id = id + end, + getId = function(self) + return self.data.id + end, + getText = function(self) + return self.data.list[self.data.id] + end }) -smartfs.element("label",{ - build = function(self) - return "label[".. - self.data.pos.x..","..self.data.pos.y.. - ";".. - self.data.value.. - "]" - end, - setPosition = function(self,x,y) - self.data.pos = {x=x,y=y} - end, - getPosition = function(self,x,y) - return self.data.pos - end, - setText = function(self,text) - self.data.value = text - end, - getText = function(self) - return self.data.value - end +smartfs.element("label", { + build = function(self) + return "label[" + .. self.data.pos.x .. "," .. self.data.pos.y + .. ";" .. self.data.value + .. "]" + end, + setPosition = function(self, x, y) + self.data.pos = { x = x, y = y } + end, + getPosition = function(self) + return self.data.pos + end, + setText = function(self, text) + self.data.value = text + end, + getText = function(self) + return self.data.value + end }) -smartfs.element("field",{ - build = function(self) - if self.data.ml then - return "textarea[".. - self.data.pos.x..","..self.data.pos.y.. - ";".. - self.data.size.w..","..self.data.size.h.. - ";".. - self.name.. - ";".. - self.data.label.. - ";".. - self.data.value.. - "]" - elseif self.data.pwd then - return "pwdfield[".. - self.data.pos.x..","..self.data.pos.y.. - ";".. - self.data.size.w..","..self.data.size.h.. - ";".. - self.name.. - ";".. - self.data.label.. - "]" - else - return "field[".. - self.data.pos.x..","..self.data.pos.y.. - ";".. - self.data.size.w..","..self.data.size.h.. - ";".. - self.name.. - ";".. - self.data.label.. - ";".. - self.data.value.. - "]" - end - end, - setPosition = function(self,x,y) - self.data.pos = {x=x,y=y} - end, - getPosition = function(self,x,y) - return self.data.pos - end, - setSize = function(self,w,h) - self.data.size = {w=w,h=h} - end, - getSize = function(self,x,y) - return self.data.size - end, - setText = function(self,text) - self.data.value = text - end, - getText = function(self) - return self.data.value - end, - isPassword = function(self,bool) - self.data.pwd = bool - end, - isMultiline = function(self,bool) - self.data.ml = bool - end +smartfs.element("field", { + build = function(self) + local common = self.data.pos.x .. "," .. self.data.pos.y + .. ";" .. self.data.size.w .. "," .. self.data.size.h + .. ";" .. self.name + .. ";" .. self.data.label + if self.data.ml then + return "textarea[" + .. common + .. ";" .. self.data.value + .. "]" + elseif self.data.pwd then + return "pwdfield[" + .. common + .. "]" + else + return "field[" + .. common + .. ";" .. self.data.value + .. "]" + end + end, + setPosition = function(self, x, y) + self.data.pos = { x = x, y = y } + end, + getPosition = function(self) + return self.data.pos + end, + setSize = function(self, w, h) + self.data.size = { w = w, h = h } + end, + getSize = function(self) + return self.data.size + end, + setText = function(self, text) + self.data.value = text + end, + getText = function(self) + return self.data.value + end, + isPassword = function(self, bool) + self.data.pwd = bool + end, + isMultiline = function(self, bool) + self.data.ml = bool + end }) -smartfs.element("image",{ - build = function(self) - return "image[".. - self.data.pos.x..","..self.data.pos.y.. - ";".. - self.data.size.w..","..self.data.size.h.. - ";".. - self.data.value.. - "]" - end, - setPosition = function(self,x,y) - self.data.pos = {x=x,y=y} - end, - getPosition = function(self,x,y) - return self.data.pos - end, - setSize = function(self,w,h) - self.data.size = {w=w,h=h} - end, - getSize = function(self,x,y) - return self.data.size - end, - setImage = function(self,text) - self.data.value = text - end, - getImage = function(self) - return self.data.value - end +smartfs.element("image", { + build = function(self) + return "image[" + .. self.data.pos.x .. "," .. self.data.pos.y + .. ";" .. self.data.size.w .. "," .. self.data.size.h + .. ";" .. self.data.value + .. "]" + end, + setPosition = function(self, x, y) + self.data.pos = { x = x, y = y } + end, + getPosition = function(self) + return self.data.pos + end, + setSize = function(self, w, h) + self.data.size = { w = w, h = h } + end, + getSize = function(self) + return self.data.size + end, + setImage = function(self, text) + self.data.value = text + end, + getImage = function(self) + return self.data.value + end }) -smartfs.element("checkbox",{ - build = function(self) - if self.data.value then - return "checkbox[".. - self.data.pos.x..","..self.data.pos.y.. - ";".. - self.name.. - ";".. - self.data.label.. - ";true]" - else - return "checkbox[".. - self.data.pos.x..","..self.data.pos.y.. - ";".. - self.name.. - ";".. - self.data.label.. - ";false]" - end - end, - setPosition = function(self,x,y) - self.data.pos = {x=x,y=y} - end, - getPosition = function(self,x,y) - return self.data.pos - end, - setSize = function(self,w,h) - self.data.size = {w=w,h=h} - end, - getSize = function(self,x,y) - return self.data.size - end, - setText = function(self,text) - self.data.value = text - end, - getText = function(self) - return self.data.value - end +smartfs.element("checkbox", { + build = function(self) + local out = "checkbox[" + .. self.data.pos.x .. "," .. self.data.pos.y + .. ";" .. self.name + .. ";" .. self.data.label + if self.data.value then + return out .. ";true]" + else + return out .. ";false]" + end + end, + setPosition = function(self, x, y) + self.data.pos = { x = x, y = y } + end, + getPosition = function(self) + return self.data.pos + end, + setSize = function(self, w, h) + self.data.size = { w = w, h = h } + end, + getSize = function(self) + return self.data.size + end, + setText = function(self, text) + self.data.value = text + end, + getText = function(self) + return self.data.value + end }) -smartfs.element("list",{ - build = function(self) - if not self.data.items then - self.data.items = {} - end - local listformspec = "textlist[".. - self.data.pos.x..","..self.data.pos.y.. - ";".. - self.data.size.w..","..self.data.size.h.. - ";".. - self.data.name.. - ";".. - table.concat(self.data.items, ",").. - ";".. - tostring(self.data.selected or "").. - ";".. - tostring(self.data.transparent or "false").."]" +smartfs.element("list", { + build = function(self) + if not self.data.items then + self.data.items = {} + end + local listformspec = "textlist[" + .. self.data.pos.x .. "," .. self.data.pos.y + .. ";" .. self.data.size.w .. "," .. self.data.size.h + .. ";" .. self.data.name + .. ";" .. table.concat(self.data.items, ",") + .. ";" .. tostring(self.data.selected or "") + .. ";" .. tostring(self.data.transparent or "false") + .. "]" - return listformspec - end, - submit = function(self,fields) - if fields[self.name] then - local _type = string.sub(fields[self.data.name],1,3) - local index = string.sub(fields[self.data.name],5) - if _type == "CHG" and self._click then - self:_click(self.root, index) - elseif _type == "DCL" and self._doubleClick then - self:_doubleClick(self.root, index) - end - end - end, - onClick = function(self, func) - self._click = func - end, - click = function(self, func) - self._click = func - end, - onDoubleClick = function(self, func) - self._doubleClick = func - end, - doubleclick = function(self, func) - self._doubleClick = func - end, - setPosition = function(self,x,y) - self.data.pos = {x=x,y=y} - end, - getPosition = function(self,x,y) - return self.data.pos - end, - setSize = function(self,w,h) - self.data.size = {w=w,h=h} - end, - getSize = function(self,x,y) - return self.data.size - end, - addItem = function(self, item) - if not self.data.items then - self.data.items = {} - end - table.insert(self.data.items, item) - end, - removeItem = function(self,idx) - if not self.data.items then - self.data.items = {} - end - table.remove(self.data.items,idx) - end, - popItem = function(self) - if not self.data.items then - self.data.items = {} - end - local item = self.data.items[#self.data.items] - table.remove(self.data.items) - return item - end + return listformspec + end, + submit = function(self, fields) + if fields[self.name] then + local _type = string.sub(fields[self.data.name], 1, 3) + local index = string.sub(fields[self.data.name], 5) + if _type == "CHG" and self._click then + self:_click(self.root, index) + elseif _type == "DCL" and self._doubleClick then + self:_doubleClick(self.root, index) + end + end + end, + onClick = function(self, func) + self._click = func + end, + click = function(self, func) + self._click = func + end, + onDoubleClick = function(self, func) + self._doubleClick = func + end, + doubleclick = function(self, func) + self._doubleClick = func + end, + setPosition = function(self, x, y) + self.data.pos = { x = x, y = y } + end, + getPosition = function(self) + return self.data.pos + end, + setSize = function(self, w, h) + self.data.size = { w = w, h = h } + end, + getSize = function(self) + return self.data.size + end, + addItem = function(self, item) + if not self.data.items then + self.data.items = {} + end + table.insert(self.data.items, item) + end, + removeItem = function(self, idx) + if not self.data.items then + self.data.items = {} + end + table.remove(self.data.items, idx) + end, + popItem = function(self) + if not self.data.items then + self.data.items = {} + end + local item = self.data.items[#self.data.items] + table.remove(self.data.items) + return item + end }) -smartfs.element("inventory",{ - build = function(self) - return "list[".. - (self.data.location or "current_player") .. - ";".. - self.name.. - ";".. - self.data.pos.x..","..self.data.pos.y.. - ";".. - self.data.size.w..","..self.data.size.h.. - ";".. - (self.data.index or "") .. - "]" - end, - setPosition = function(self,x,y) - self.data.pos = {x=x,y=y} - end, - getPosition = function(self,x,y) - return self.data.pos - end, - setSize = function(self,w,h) - self.data.size = {w=w,h=h} - end, - getSize = function(self,x,y) - return self.data.size - end, - -- available inventory locations - -- "current_player": Player to whom the menu is shown - -- "player:": Any player - -- "nodemeta:,,": Any node metadata - -- "detached:": A detached inventory - -- "context" does not apply to smartfs, since there is no node-metadata as context available - setLocation = function(self,location) - self.data.location = location - end, - getLocation = function(self) - return self.data.location or "current_player" - end, - usePosition = function(self, pos) - self.data.location = string.format("nodemeta:%d,%d,%d", pos.x, pos.y, pos.z) - end, - usePlayer = function(self, name) - self.data.location = "player:" .. name - end, - useDetached = function(self, name) - self.data.location = "detached:" .. name - end, - setIndex = function(self,index) - self.data.index = index - end, - getIndex = function(self) - return self.data.index - end +smartfs.element("inventory", { + build = function(self) + return "list[" + .. (self.data.location or "current_player") + .. ";" .. self.name + .. ";" .. self.data.pos.x .. "," .. self.data.pos.y + .. ";" .. self.data.size.w .. "," .. self.data.size.h + .. ";" .. (self.data.index or "") + .. "]" + end, + setPosition = function(self, x, y) + self.data.pos = { x = x, y = y } + end, + getPosition = function(self) + return self.data.pos + end, + setSize = function(self, w, h) + self.data.size = { w = w, h = h } + end, + getSize = function(self) + return self.data.size + end, + -- available inventory locations + -- "current_player": Player to whom the menu is shown + -- "player:": Any player + -- "nodemeta:,,": Any node metadata + -- "detached:": A detached inventory + -- "context" does not apply to smartfs, since there is no node-metadata as context available + setLocation = function(self, location) + self.data.location = location + end, + getLocation = function(self) + return self.data.location or "current_player" + end, + usePosition = function(self, pos) + self.data.location = string.format("nodemeta:%d,%d,%d", pos.x, pos.y, pos.z) + end, + usePlayer = function(self, name) + self.data.location = "player:" .. name + end, + useDetached = function(self, name) + self.data.location = "detached:" .. name + end, + setIndex = function(self, index) + self.data.index = index + end, + getIndex = function(self) + return self.data.index + end }) -smartfs.element("code",{ - build = function(self) - if self._build then - self:_build() - end +smartfs.element("code", { + build = function(self) + if self._build then + self:_build() + end - return self.data.code - end, - submit = function(self,fields) - if self._sub then - self:_sub(fields) - end - end, - onSubmit = function(self,func) - self._sub = func - end, - onBuild = function(self,func) - self._build = func - end, - setCode = function(self,code) - self.data.code = code - end, - getCode = function(self) - return self.data.code - end + return self.data.code + end, + submit = function(self, fields) + if self._sub then + self:_sub(fields) + end + end, + onSubmit = function(self, func) + self._sub = func + end, + onBuild = function(self, func) + self._build = func + end, + setCode = function(self, code) + self.data.code = code + end, + getCode = function(self) + return self.data.code + end }) +