diff --git a/.luacheckrc b/.luacheckrc index 2ba39e4..607a8d3 100644 --- a/.luacheckrc +++ b/.luacheckrc @@ -5,6 +5,7 @@ read_globals = { "dump", "ItemStack", "pipeworks", + "unified_inventory", "PseudoRandom", "stairsplus", "intllib", diff --git a/api.lua b/api.lua index 22175f9..28000d9 100644 --- a/api.lua +++ b/api.lua @@ -27,6 +27,7 @@ function microexpansion.register_oredef(ore, defs) for _,d in ipairs(defs) do d.ore = "microexpansion:"..ore + minetest.log("verbose", minetest.serialize(d)) minetest.register_ore(d) end end @@ -72,6 +73,13 @@ end -- [function] Register Node function microexpansion.register_node(itemstring, def) + if minetest.get_modpath("mcl_core") then + def._mcl_hardness = def._mcl_hardness or 3 + def._mcl_blast_resistance = def._mcl_blast_resistance or 3 + def._mcl_hardness = def._mcl_hardness or 3 + def._mcl_silk_touch_drop = def._mcl_silk_touch_drop or true + def.groups.pickaxey = def.groups.pickaxey or 3 + end -- Check if disabled if def.disabled == true then return @@ -133,3 +141,44 @@ function microexpansion.update_node(pos,event) def.me_update(pos,node,ev) end end + +-- [function] Move items from inv to inv +function microexpansion.move_inv(inv1, inv2, max, filter) + if max <= 0 then return end + local finv, tinv = inv1.inv, inv2.inv + local fname, tname = inv1.name, inv2.name + local huge = inv2.huge + local inserted = 0 + + for _,v in ipairs(finv:get_list(fname) or {}) do + local left = max-inserted + if left <= 0 then + break; + end + if not v:is_empty() then + if v:get_count() > left then + v = v:peek_item(left) + end + if tinv and tinv:room_for_item(tname, v) and (not filter or not filter(v)) then + if huge then + microexpansion.insert_item(v, tinv, tname) + finv:remove_item(fname, v) + else + --TODO: continue inserting from the same stack if it is bigger than max + if v:get_count() > v:get_stack_max() then + v = v:peek_item(v:get_stack_max()) + end + local leftover = tinv:add_item(tname, v) + finv:remove_item(fname, v) + if leftover and not(leftover:is_empty()) then + microexpansion.log("leftover items when transferring inventory","warning") + finv:add_item(fname, leftover) + end + end + inserted = inserted + v:get_count() + end + end + end + return inserted +end + diff --git a/depends.txt b/depends.txt index d3f04d8..96b6770 100644 --- a/depends.txt +++ b/depends.txt @@ -1,2 +1,3 @@ default pipeworks? +basic_materials? diff --git a/init.lua b/init.lua index e50a3af..790423a 100644 --- a/init.lua +++ b/init.lua @@ -11,15 +11,18 @@ microexpansion.gui_bg = "bgcolor[#080808BB;true]background[5,5;1,1;gui_formbg.pn microexpansion.gui_slots = "listcolors[#00000069;#5A5A5A;#141318;#30434C;#FFF]" microexpansion.settings = { - huge_stacks = minetest.settings:get_bool("microexpansion_huge_stacks") + huge_stacks = minetest.settings:get_bool("microexpansion_huge_stacks"), + simple_craft = minetest.settings:get_bool("microexpansion_simple_craft") } +microexpansion.uinv_category_enabled = minetest.global_exists("unified_inventory") and unified_inventory.add_category_item and true or false + -- logger function microexpansion.log(content, log_type) - assert(content, "microexpansion.log: missing content") - if not content then return false end - if log_type == nil then log_type = "action" end - minetest.log(log_type, "[MicroExpansion] "..content) + assert(content, "microexpansion.log: missing content") + if not content then return false end + if log_type == nil then log_type = "action" end + minetest.log(log_type, "[MicroExpansion] "..content) end -- Load API @@ -37,45 +40,45 @@ local settings = Settings(modpath.."/modules.conf"):to_table() -- [function] Get module path function microexpansion.get_module_path(name) - local module_path = modpath.."/modules/"..name + local module_path = modpath.."/modules/"..name local handle = io.open(module_path.."/init.lua") - if handle then - io.close(handle) - return module_path - end + if handle then + io.close(handle) + return module_path + end end -- [function] Load module (overrides modules.conf) function microexpansion.load_module(name) - if not loaded_modules[name] then - local module_path = microexpansion.get_module_path(name) + if not loaded_modules[name] then + local module_path = microexpansion.get_module_path(name) - if module_path then - dofile(module_path.."/init.lua") - loaded_modules[name] = true - return true - else - microexpansion.log("Invalid module \""..name.."\". The module either does not exist ".. - "or is missing an init.lua file.", "error") - end - else - return true - end + if module_path then + dofile(module_path.."/init.lua") + loaded_modules[name] = true + return true + else + microexpansion.log("Invalid module \""..name.."\". The module either does not exist ".. + "or is missing an init.lua file.", "error") + end + else + return true + end end -- [function] Require module (does not override modules.conf) function microexpansion.require_module(name) - if settings[name] then - microexpansion.log("loading module " .. name) - return microexpansion.load_module(name) - else - microexpansion.log("not loading module " .. name) - end + if settings[name] then + microexpansion.log("loading module " .. name) + return microexpansion.load_module(name) + else + microexpansion.log("not loading module " .. name) + end end for name,enabled in pairs(settings) do - if enabled ~= false then - microexpansion.load_module(name) - end + if enabled ~= false then + microexpansion.load_module(name) + end end diff --git a/mod.conf b/mod.conf index b1477c3..6a9a29e 100644 --- a/mod.conf +++ b/mod.conf @@ -1,4 +1,5 @@ name = microexpansion description = A storage managing solution to get an overview over all your items. -depends = default -optional_depends = pipeworks, drawers, technic, technic_plus +optional_depends = pipeworks,basic_materials,mcl_furnaces,mcl_core,drawers,technic,technic_plus +supported_games = mineclone2,mineclonia,minetest_game + diff --git a/modules.conf b/modules.conf index 4f08c81..5374f54 100644 --- a/modules.conf +++ b/modules.conf @@ -1,5 +1,6 @@ -shared = true network = true power = false storage = true ores = true +item_transfer = true +crafting = true diff --git a/modules/crafting/alternatives.lua b/modules/crafting/alternatives.lua new file mode 100644 index 0000000..ae4f6a5 --- /dev/null +++ b/modules/crafting/alternatives.lua @@ -0,0 +1,37 @@ +--- +-- craftitems that offer alternative craft recipes + +local me = microexpansion + +--TODO: build specialized integrated circuits / chips out of the ic and other stuff that are required to build the devices / machines instead of the control unit being an alternative + +--- +-- [Microexpansion Control Unit] +-- a different logic chip that uses gold, quartz and wood +-- for use instead of basic_materials:ic that requires sand, coal and copper +me.register_item("logic_chip", { + description = "Control Unit", + recipe = { + { 2, + { + {"basic_materials:gold_wire"}, + {"basic_materials:silicon"}, + {"basic_materials:plastic_sheet"} + }, + }, + { 2, + { + {"basic_materials:gold_wire"}, + {"microexpansion:quartz_crystal"}, + {"basic_materials:plastic_sheet"} + }, + }, + { 2, + { + {"microexpansion:gold_wire"}, + {"microexpansion:quartz_crystal"}, + {"group:wood"} + }, + }, + }, +}) diff --git a/modules/crafting/init.lua b/modules/crafting/init.lua new file mode 100644 index 0000000..c9146dc --- /dev/null +++ b/modules/crafting/init.lua @@ -0,0 +1,8 @@ +local module_path = microexpansion.get_module_path("crafting") + +-- basic_materials replacements +dofile(module_path.."/materials.lua") +-- shared items used for various machine recipes +dofile(module_path.."/shared.lua") +-- items that allow for alternative recipes +dofile(module_path.."/alternatives.lua") diff --git a/modules/crafting/materials.lua b/modules/crafting/materials.lua new file mode 100644 index 0000000..842114c --- /dev/null +++ b/modules/crafting/materials.lua @@ -0,0 +1,32 @@ +--- +-- Craft materials, that are normally registered by basic_materials + +local me = microexpansion +local substitute_basic_materials = microexpansion.settings.simple_craft == true or not minetest.get_modpath("basic_materials") +local gold_wire_recipe + +if minetest.get_modpath("mcl_core") then + gold_wire_recipe = { + { 2, { + {"mcl_core:gold_ingot", "mcl_core:stick"}, + {"mcl_core:stick", ""} + }, + }, + } +else + gold_wire_recipe = { + { 2, { + {"default:gold_ingot", "default:stick"}, + {"default:stick", ""} + }, + }, + } + +end + +-- [register item] Gold Wire +me.register_item("gold_wire", { + description = "Gold Wire", + groups = { wire = 1 }, + recipe = substitute_basic_materials and gold_wire_recipe or nil, +}) diff --git a/modules/crafting/shared.lua b/modules/crafting/shared.lua new file mode 100644 index 0000000..f718043 --- /dev/null +++ b/modules/crafting/shared.lua @@ -0,0 +1,53 @@ +-- crafting/shared.lua + +local me = microexpansion + +-- custom items that are used by multiple devices +local steel_infused_obsidian_ingot_recipe, machine_casing_recipe + +if minetest.get_modpath("mcl_core") then + steel_infused_obsidian_ingot_recipe = { + { 2, { + { "mcl_core:iron_ingot", "mcl_core:obsidian", "mcl_core:iron_ingot" }, + }, + }, + } + + machine_casing_recipe = { + { 1, { + {"mcl_core:iron_ingot", "mcl_core:iron_ingot", "mcl_core:iron_ingot"}, + {"mcl_core:iron_ingot", "mcl_copper:copper_ingot", "mcl_core:iron_ingot"}, + {"mcl_core:iron_ingot", "mcl_core:iron_ingot", "mcl_core:iron_ingot"}, + }, + }, + } + +else + steel_infused_obsidian_ingot_recipe = { + { 2, { + { "default:steel_ingot", "default:obsidian_shard", "default:steel_ingot" }, + }, + }, + } + + machine_casing_recipe = { + { 1, { + {"default:steel_ingot", "default:steel_ingot", "default:steel_ingot"}, + {"default:steel_ingot", "default:copper_ingot", "default:steel_ingot"}, + {"default:steel_ingot", "default:steel_ingot", "default:steel_ingot"}, + }, + }, + } + +end +-- [register item] Steel Infused Obsidian Ingot +me.register_item("steel_infused_obsidian_ingot", { + description = "Steel Infused Obsidian Ingot", + recipe = steel_infused_obsidian_ingot_recipe, +}) + +-- [register item] Machine Casing +me.register_item("machine_casing", { + description = "Machine Casing", + recipe = machine_casing_recipe, +}) diff --git a/modules/item_transfer/api.lua b/modules/item_transfer/api.lua new file mode 100644 index 0000000..2259c1a --- /dev/null +++ b/modules/item_transfer/api.lua @@ -0,0 +1,263 @@ +-- item_transfer/api.lua +local me = microexpansion +local item_transfer = {} +me.item_transfer = item_transfer + +function item_transfer.get_output_inventory(pos,metadata,inventory) + local meta = metadata or minetest.get_meta(pos) + local inv = inventory or meta:get_inventory() + local lists = inv:get_lists() + if not lists then + return + elseif lists["dst"] then + return "dst", inv + elseif lists["main"] then + return "main", inv + end +end + +function item_transfer.get_input_inventory(pos,metadata,inventory) + local meta = metadata or minetest.get_meta(pos) + local inv = inventory or meta:get_inventory() + local lists = inv:get_lists() + if not lists then + return + elseif lists["src"] then + return "src", inv + elseif lists["main"] then + return "main", inv + end +end + +function microexpansion.vector_cross(a, b) + return { + x = a.y * b.z - a.z * b.y, + y = a.z * b.x - a.x * b.z, + z = a.x * b.y - a.y * b.x + } +end + +function microexpansion.facedir_to_top_dir(facedir) + return ({[0] = {x = 0, y = 1, z = 0}, + {x = 0, y = 0, z = 1}, + {x = 0, y = 0, z = -1}, + {x = 1, y = 0, z = 0}, + {x = -1, y = 0, z = 0}, + {x = 0, y = -1, z = 0}}) + [math.floor(facedir / 4)] +end + +function microexpansion.facedir_to_right_dir(facedir) + return microexpansion.vector_cross( + microexpansion.facedir_to_top_dir(facedir), + minetest.facedir_to_dir(facedir) + ) +end + +function microexpansion.count_upgrades(inv) + local upgrades = {} + for i = 0, inv:get_size("upgrades") do + local stack = inv:get_stack("upgrades", i) + local item = stack:get_name() + if item == "microexpansion:upgrade_filter" then + upgrades.filter = (upgrades.filter or 0) + stack:get_count() + elseif item == "microexpansion:upgrade_bulk" then + upgrades.bulk = (upgrades.bulk or 0) + stack:get_count() + end + end + return upgrades +end + +function item_transfer.update_timer_based(pos,_,ev) + if ev then + if ev.type ~= "disconnect" + and ev.type ~= "connect" + and ev.type ~= "construct" then + return + end + end + local meta = minetest.get_meta(pos) + if me.get_connected_network(pos) then + meta:set_string("infotext", "Network connected") + if not minetest.get_node_timer(pos):is_started() then + minetest.get_node_timer(pos):start(2) + end + else + meta:set_string("infotext", "No Network") + minetest.get_node_timer(pos):stop() + end +end + +function item_transfer.setup_io_device(title, pos, metadata, inventory) + local meta = metadata or minetest.get_meta(pos) + local inv = inventory or meta:get_inventory() + local formspec = [[ + formspec_version[2] + size[11,11] + ]] .. + microexpansion.gui_bg .. + microexpansion.gui_slots + if title then + formspec = formspec .. "label[9,0.5;"..title.."]" + end + local upgrades = me.count_upgrades(inv) + if upgrades.filter then + inv:set_size("filter", math.pow(2, upgrades.filter - 1)) + formspec = formspec .. [[ + label[0.5,0.75;filter] + list[context;filter;0.5,1;5,3] + ]] + else + inv:set_size("filter",0) + end + --TODO: target inventory dropdown + inv:set_size("upgrades", 4) + meta:set_string("formspec", + formspec .. + [[ + label[8.5,2.5;upgrades] + list[context;upgrades;8,2.75;2,2] + list[current_player;main;0.5,5.5;8,1;] + list[current_player;main;0.5,7;8,3;8] + listring[current_name;upgrades] + listring[current_player;main] + ]]) +end + +local access_level = microexpansion.constants.security.access_levels +local io_device_base = { + is_ground_content = false, + groups = { crumbly = 1, me_connect = 1 }, + paramtype = "light", + paramtype2 = "facedir", + me_update = item_transfer.update_timer_based, + after_place_node = function(pos, placer) + if not placer then + return false + end + local name = placer:get_player_name() + local net,cp = me.get_connected_network(pos) + if net then + if net:get_access_level(name) < access_level.modify then + -- prevent placing exporters on a network that a player doesn't have access to + --Do we need to send a disconnect or stop any node timers? + minetest.remove_node(pos) + return true + else + return false + end + elseif minetest.is_protected(pos, name) then + minetest.record_protection_violation(pos, name) + --protection probably handles this itself + --minetest.remove_node(pos) + return true + end + end, + can_dig = function(pos, player) + if not player then + return false + end + local name = player:get_player_name() + local net,cp = me.get_connected_network(pos) + if net then + if net:get_access_level(name) < access_level.modify then + return false + end + elseif minetest.is_protected(pos, name) then + minetest.record_protection_violation(pos, name) + return false + end + local meta = minetest.get_meta(pos) + local inv = meta:get_inventory() + return inv:is_empty("upgrades") + end, + allow_metadata_inventory_put = function(pos, listname, _, stack, player) + local max_allowed = stack:get_count() + if listname == "upgrades" then + local item = stack:get_name() + if item == "microexpansion:upgrade_filter" then + local filter_upgrades = me.count_upgrades(minetest.get_meta(pos):get_inventory()).filter + if filter_upgrades then + max_allowed = math.max(0, math.min(stack:get_count(), 5 - filter_upgrades)) + else + max_allowed = math.min(stack:get_count(), 5) + end + elseif item == "microexpansion:upgrade_bulk" then + local bulk_upgrades = me.count_upgrades(minetest.get_meta(pos):get_inventory()).bulk + if bulk_upgrades then + max_allowed = math.max(0, math.min(stack:get_count(), 10 - bulk_upgrades)) + else + max_allowed = math.min(stack:get_count(), 10) + end + else + return 0 + end + end + if not player then + return max_allowed + end + local name = player:get_player_name() + local net,cp = me.get_connected_network(pos) + if net then + if net:get_access_level(name) < access_level.modify then + return 0 + end + elseif minetest.is_protected(pos, name) then + --minetest.record_protection_violation(pos, name) + return 0 + end + if listname == "filter" then + local meta = minetest.get_meta(pos) + local inv = meta:get_inventory() + local filter = stack:peek_item() + if inv:room_for_item(listname,filter) and not inv:contains_item(listname, filter) then + inv:add_item(listname, filter) + end + return 0 + else + return max_allowed + end + end, + allow_metadata_inventory_take = function(pos, listname, _, stack, player) + if not player then + return 0 + end + local name = player:get_player_name() + local net,cp = me.get_connected_network(pos) + if net then + if net:get_access_level(name) < access_level.modify then + return 0 + end + elseif minetest.is_protected(pos, name) then + --minetest.record_protection_violation(pos, name) + return 0 + end + if listname == "filter" then + local meta = minetest.get_meta(pos) + local inv = meta:get_inventory() + inv:remove_item(listname, stack) + return 0 + else + return stack:get_count() + end + end, + allow_metadata_inventory_move = function(pos, from_list, _, to_list, _, count, player) + --perhaps allow filtering for upgrades and removing filters in this way + if from_list ~= to_list then + return 0 + end + return count + end, +} + +function item_transfer.register_io_device(itemstring, def) + for k,v in pairs(io_device_base) do + if def[k] == nil then + def[k] = v + end + end + if not def.groups.me_connect then + def.groups.me_connect = 1 + end + microexpansion.register_node(itemstring, def) +end diff --git a/modules/item_transfer/exporter.lua b/modules/item_transfer/exporter.lua new file mode 100644 index 0000000..609887b --- /dev/null +++ b/modules/item_transfer/exporter.lua @@ -0,0 +1,93 @@ +-- microexpansion/machines.lua + +local me = microexpansion +local item_transfer = me.item_transfer +local access_level = microexpansion.constants.security.access_levels + +local function exporter_timer(pos, elapsed) + local net, cp = me.get_connected_network(pos) + if not net then + return false + end + local node = minetest.get_node(pos) + local target = vector.add(pos, microexpansion.facedir_to_right_dir(node.param2)) + --TODO: allow setting list with control upgrade + --TODO: perhaps allow setting limits with control upgrade + local list, inv = item_transfer.get_input_inventory(target) + if list then + --TODO: move more with upgrades + local own_inv = minetest.get_meta(pos):get_inventory() + local upgrades = me.count_upgrades(own_inv) + local export_filter = upgrades.filter and function(stack) + return not own_inv:contains_item("filter",stack:peek_item()) + end + local max_count = math.pow(2, upgrades.bulk or 0) + microexpansion.move_inv({inv=net:get_inventory(),name="main",huge=true}, {inv=inv,name=list}, max_count, export_filter) + --TODO: perhaps call allow_insert and on_insert callbacks + end + return true +end + +-- [MicroExpansion Exporter] Register node +item_transfer.register_io_device("exporter", { + description = "ME exporter", + usedfor = "Exports items from ME Networks into machines", + tiles = { + "exporter", + "exporter", + "interface", + "cable", + "microexpansion_exporter.png^[transform4", + "exporter", + }, + drawtype = "nodebox", + node_box = { + --perhaps convert to connectable + type = "fixed", + fixed = { + {-0.5, -0.25, -0.25, 0.25, 0.25, 0.25}, + {0.25, -0.375, -0.375, 0.5, 0.375, 0.375}, + }, + }, + connect_sides = { "left" }, + recipe = { + { 1, { + {"", "basic_materials:ic", microexpansion.iron_ingot_ingredient }, + {"", "microexpansion:cable", "group:shovel" }, + {"", "", microexpansion.iron_ingot_ingredient }, + }, + }, + { 1, { + {"", "microexpansion:logic_chip", microexpansion.iron_ingot_ingredient }, + {"", "microexpansion:cable", "group:shovel" }, + {"", "", microexpansion.iron_ingot_ingredient }, + }, + } + }, + groups = { crumbly = 1 }, + on_timer = exporter_timer, + on_construct = function(pos) + item_transfer.setup_io_device("ME Exporter",pos) + me.send_event(pos,"connect") + --perhaps write a propper update self function + item_transfer.update_timer_based(pos,nil,{type="construct"}) + end, + after_destruct = function(pos) + minetest.get_node_timer(pos):stop() + me.send_event(pos,"disconnect") + end, + on_metadata_inventory_put = function(pos, listname, _, stack, player) + if listname == "upgrades" then + item_transfer.setup_io_device("ME Exporter",pos) + end + end, + on_metadata_inventory_take = function(pos, listname, _, stack, player) + if listname == "upgrades" then + item_transfer.setup_io_device("ME Exporter",pos) + end + end +}) + +if me.uinv_category_enabled then + unified_inventory.add_category_item("storage", "microexpansion:exporter") +end diff --git a/modules/item_transfer/importer.lua b/modules/item_transfer/importer.lua new file mode 100644 index 0000000..a563fef --- /dev/null +++ b/modules/item_transfer/importer.lua @@ -0,0 +1,100 @@ +-- microexpansion/machines.lua + +local me = microexpansion +local item_transfer = me.item_transfer +local access_level = microexpansion.constants.security.access_levels + +function importer_timer(pos, elapsed) + local net, cp = me.get_connected_network(pos) + if not net then + return false + end + local node = minetest.get_node(pos) + local target = vector.add(pos, microexpansion.facedir_to_right_dir(node.param2)) + --TODO: allow setting list with upgrade + local list, inv = item_transfer.get_output_inventory(target) + if list then + local own_inv = minetest.get_meta(pos):get_inventory() + local upgrades = me.count_upgrades(own_inv) + local count = math.min(net:get_inventory_space(),math.pow(2, upgrades.bulk or 0)) + if count <= 0 then + return true + end + local import_filter = function(stack) + local stack_name = stack:get_name() + if minetest.get_item_group(stack_name, "microexpansion_cell") > 0 then + return true + end + if upgrades.filter then + return not own_inv:contains_item("filter",stack:peek_item()) + end + return false + end + microexpansion.move_inv({inv=inv,name=list}, {inv=net:get_inventory(),name="main",huge=true}, count, import_filter) + net:set_storage_space(true) + end + return true +end + +-- [MicroExpansion Importer] Register node +item_transfer.register_io_device("importer", { + description = "ME Importer", + usedfor = "Imports items from machines into ME Networks", + tiles = { + "importer", + "importer", + "interface", + "cable", + "microexpansion_importer.png^[transform4", + "importer", + }, + drawtype = "nodebox", + node_box = { + type = "fixed", + fixed = { + {-0.5, -0.25, -0.25, 0.25, 0.25, 0.25}, + {0.25, -0.375, -0.375, 0.5, 0.375, 0.375}, + }, + }, + connect_sides = { "left" }, + recipe = { + { 1, { + {"", "basic_materials:ic", microexpansion.iron_ingot_ingredient }, + {"", "microexpansion:cable", "group:hoe" }, + {"", "", microexpansion.iron_ingot_ingredient }, + }, + }, + { 1, { + {"", "microexpansion:logic_chip", microexpansion.iron_ingot_ingredient }, + {"", "microexpansion:cable", "group:hoe" }, + {"", "", microexpansion.iron_ingot_ingredient }, + }, + } + }, + is_ground_content = false, + groups = { crumbly = 1 }, + on_timer = importer_timer, + on_construct = function(pos) + item_transfer.setup_io_device("ME Importer",pos) + me.send_event(pos,"connect") + item_transfer.update_timer_based(pos) + end, + after_destruct = function(pos) + minetest.get_node_timer(pos):stop() + me.send_event(pos,"disconnect") + end, + on_metadata_inventory_put = function(pos, listname, _, stack, player) + if listname == "upgrades" then + item_transfer.setup_io_device("ME Importer",pos) + end + end, + on_metadata_inventory_take = function(pos, listname, _, stack, player) + if listname == "upgrades" then + item_transfer.setup_io_device("ME Importer",pos) + end + end +}) + +if me.uinv_category_enabled then + unified_inventory.add_category_item("storage", "microexpansion:importer") +end diff --git a/modules/item_transfer/init.lua b/modules/item_transfer/init.lua new file mode 100644 index 0000000..086c5cc --- /dev/null +++ b/modules/item_transfer/init.lua @@ -0,0 +1,25 @@ +-- storage/init.lua + +local module_path = microexpansion.get_module_path("item_transfer") + +microexpansion.require_module("network") + + +-- Iron Ingot Ingredient for MineClone2 +microexpansion.iron_ingot_ingredient = nil +if minetest.get_modpath("mcl_core") then + microexpansion.iron_ingot_ingredient = "mcl_core:iron_ingot" +else + microexpansion.iron_ingot_ingredient = "default:steel_ingot" +end + +-- Load API +dofile(module_path.."/api.lua") + +-- Load upgrade cards +dofile(module_path.."/upgrades.lua") + +-- Load ports +dofile(module_path.."/importer.lua") +dofile(module_path.."/exporter.lua") +--dofile(module_path.."/interface.lua") diff --git a/modules/item_transfer/upgrades.lua b/modules/item_transfer/upgrades.lua new file mode 100644 index 0000000..8631ba3 --- /dev/null +++ b/modules/item_transfer/upgrades.lua @@ -0,0 +1,67 @@ +-- shared/init.lua + +local me = microexpansion + +-- TODO: regulation upgrade (1: disable in formspec, mesecon control; 2: requests from the me network and perhaps digiline) + +-- [register item] Upgrade Base +me.register_item("upgrade_base", { + description = "Upgrade Base", + usedfor = "the base for crafting upgrades", + recipe = { + { 1, { + { "microexpansion:quartz_crystal" }, + { microexpansion.iron_ingot_ingredient }, + }, + }, + }, +}) + +-- [register item] Bulk Upgrade +me.register_item("upgrade_bulk", { + description = "Bulk Upgrade", + usedfor = "upgrades components to process more at the same time", + recipe = { + { 1, { + {"basic_materials:gold_wire"}, + {"microexpansion:upgrade_base"} + }, + }, + { 1, { + {"microexpansion:gold_wire"}, + {"microexpansion:upgrade_base"} + }, + }, + }, +}) + +-- [register item] Filter Upgrade +me.register_item("upgrade_filter", { + description = "Filter Upgrade", + usedfor = "allows setting up filters for components", + recipe = { + { 1, { + {"microexpansion:quartz_crystal"}, + {"microexpansion:upgrade_base"} + }, + }, + }, +}) + +-- [register item] Control Upgrade +me.register_item("upgrade_control", { + description = "Control Upgrade", + usedfor = "allows more fine tuned control over components", + recipe = { + { 1, { + {"basic_materials:ic"}, + {"microexpansion:upgrade_base"} + }, + }, + { 1, { + {"microexpansion:logic_chip"}, + {"microexpansion:upgrade_base"} + }, + }, + }, +}) diff --git a/modules/network/constants.lua b/modules/network/constants.lua new file mode 100644 index 0000000..57fed8b --- /dev/null +++ b/modules/network/constants.lua @@ -0,0 +1,57 @@ +local me = microexpansion +if not me.constants then + me.constants = {} +end +local constants = me.constants + +local access_levels = { + -- cannot interact at all with the network or it's components + blocked = 0, + -- can only look into the network but not move, modify, etc. + view = 20, + -- can use chests, craft terminals, etc. + interact = 40, + -- can use all components except security, can build and dig (except core) + modify = 60, + -- can use security terminal, can modify all players with less access + manage = 80, + -- can modify all players with less access and self + full = 100 +} + +local access_level_descriptions = {} +access_level_descriptions[access_levels.blocked] = { + name = "Blocked", + color = "gray", + index = 1 +} +access_level_descriptions[access_levels.view] = { + name = "View", + color = "orange", + index = 2 +} +access_level_descriptions[access_levels.interact] = { + color = "yellow", + name = "Interact", + index = 3 +} +access_level_descriptions[access_levels.modify] = { + name = "Modify", + color = "yellowgreen", + index = 4 +} +access_level_descriptions[access_levels.manage] = { + name = "Manage", + color = "green", + index = 5 +} +access_level_descriptions[access_levels.full] = { + name = "Full", + color = "blue", + index = 6 +} + +constants.security = { + access_levels = access_levels, + access_level_descriptions = access_level_descriptions +} diff --git a/modules/network/ctrl.lua b/modules/network/ctrl.lua index a30c7a8..073faee 100644 --- a/modules/network/ctrl.lua +++ b/modules/network/ctrl.lua @@ -2,9 +2,19 @@ local me = microexpansion local network = me.network +local access_level = microexpansion.constants.security.access_levels ---FIXME: accept multiple controllers in one network +local ctrl_recipe = nil +ctrl_recipe = { + { 1, { + {microexpansion.iron_ingot_ingredient, "microexpansion:steel_infused_obsidian_ingot", microexpansion.iron_ingot_ingredient}, + {microexpansion.iron_ingot_ingredient, "microexpansion:machine_casing", microexpansion.iron_ingot_ingredient}, + {microexpansion.iron_ingot_ingredient, "microexpansion:cable", microexpansion.iron_ingot_ingredient}, + }, + } +} + -- [register node] Controller me.register_node("ctrl", { description = "ME Controller", @@ -16,14 +26,7 @@ me.register_node("ctrl", { "ctrl_sides", "ctrl_sides" }, - recipe = { - { 1, { - {"default:steel_ingot", "microexpansion:steel_infused_obsidian_ingot", "default:steel_ingot"}, - {"default:steel_ingot", "microexpansion:machine_casing", "default:steel_ingot"}, - {"default:steel_ingot", "microexpansion:cable", "default:steel_ingot"}, - }, - } - }, + recipe = ctrl_recipe, drawtype = "nodebox", paramtype = "light", node_box = { @@ -48,6 +51,7 @@ me.register_node("ctrl", { -- for on/off switch to conserve power mesecon_effector_off = 1, mesecon = 2, }, + connect_sides = "nobottom", --HV_EU_demand = 10, -- typical technic connections: -- connect_sides = {"bottom", "front", "left", "right"}, @@ -74,11 +78,14 @@ me.register_node("ctrl", { me.send_event(pos, "power") end end, - connect_sides = "nobottom", me_update = function(pos,_,ev) - local net = me.get_network(pos) - if net == nil then - me.log("no network for ctrl at pos "..minetest.pos_to_string(pos),"error") + local meta = minetest.get_meta(pos) + if meta:get_string("source") ~= "" then + return + end + local cnet = me.get_network(pos) + if cnet == nil then + microexpansion.log("no network for ctrl at pos "..minetest.pos_to_string(pos),"error") return end net:update() @@ -103,8 +110,13 @@ me.register_node("ctrl", { }}, on_construct = function(pos) local meta = minetest.get_meta(pos) - local net = network.new({controller_pos = pos}) - table.insert(me.networks,net) + local net,cp = me.get_connected_network(pos) + if net then + meta:set_string("source", vector.to_string(cp)) + else + net = network.new({controller_pos = pos}) + table.insert(me.networks,net) + end me.send_event(pos,"connect",{net=net}) meta:set_int("enabled", 0) @@ -116,12 +128,59 @@ me.register_node("ctrl", { meta:set_string("infotext", "Network Controller (owned by "..name..")") meta:set_string("owner", name) end, + after_place_node = function(pos, player) + local name = player:get_player_name() + local meta = minetest.get_meta(pos) + meta:set_string("infotext", "Network Controller") + meta:set_string("owner", name) + local net,idx = me.get_network(pos) + if net then + net:set_access_level(name, me.constants.security.access_levels.full) + elseif meta:get_string("source") == "" then + me.log("no network after placing controller", "warning") + end + end, + can_dig = function(pos, player) + if not player then + return false + end + local name = player:get_player_name() + if minetest.is_protected(pos, name) then + minetest.record_protection_violation(pos, name) + return false + end + local meta = minetest.get_meta(pos) + local net + if meta:get_string("source") == "" then + net = me.get_network(pos) + else + net = me.get_connected_network(pos) + end + if not net then + me.log("ME Network Controller without Network","error") + return true + end + return net:get_access_level(name) >= access_level.full + end, on_destruct = function(pos) local net,idx = me.get_network(pos) --disconnect all those who need the network me.send_event(pos,"disconnect",{net=net}) if net then - net:destruct() + if me.promote_controller(pos,net) then + --reconnect with new controller + me.send_event(pos,"reconnect",{net=net}) + else + net:destruct() + if idx then + table.remove(me.networks,idx) + end + --disconnect all those that haven't realized the network is gone + me.send_event(pos,"disconnect") + end + else + -- disconnect just in case + me.send_event(pos,"disconnect") end if idx then table.remove(me.networks,idx) @@ -137,6 +196,8 @@ me.register_node("ctrl", { type = "controller", }, on_timer = function(pos, elapsed) + --FIXME: we don't do that here (no goto statements please) + -- replace with loop or zero timer (next worldstep) ::top:: me.log("TIMER: starting service", "error") local net = me.get_network(pos) @@ -170,6 +231,39 @@ me.register_node("ctrl", { end, }) +minetest.register_lbm({ + name = "microexpansion:update_network", + label = "integrate new ME Network data", + nodenames = {"microexpansion:ctrl"}, + run_at_every_load = true, + action = function(pos) + local meta = minetest.get_meta(pos) + local net,idx = me.get_network(pos) + if not meta then + me.log("activated controller before metadata was available", "warning") + return + end + local source = meta:get_string("source") + if not net then + if source == "" then + me.log("activated controller without network", "warning") + return + else + net = me.get_network(vector.from_string(source)) + if not net then + me.log("activated controller that is linked to an unloaded controller", "info") + return + end + end + end + if not net.access then + me.log("added access table to old network", "action") + net.access = {} + end + net:fallback_access() + end +}) + -- [register node] Cable me.register_machine("cable", { description = "ME Cable", @@ -196,10 +290,49 @@ me.register_machine("cable", { paramtype = "light", groups = { crumbly = 1, }, --TODO: move these functions into the registration + can_dig = function(pos, player) + if not player then + return false + end + local name = player:get_player_name() + if minetest.is_protected(pos, name) then + minetest.record_protection_violation(pos, name) + return false + end + local net,cp = me.get_connected_network(pos) + if not net then + return true + end + return net:get_access_level(name) >= access_level.modify + end, on_construct = function(pos) + --perhaps this needs to be done after the check if it can be placed me.send_event(pos,"connect") end, + after_place_node = function(pos, placer) + if not placer then + return false + end + local name = placer:get_player_name() + if minetest.is_protected(pos, name) then + minetest.record_protection_violation(pos, name) + --protection probably handles this itself + --minetest.remove_node(pos) + return true + end + --TODO: prevent connecting multiple networks + local net,cp = me.get_connected_network(pos) + if not net then + return false + end + if net:get_access_level(name) < access_level.modify then + -- prevent placing cables on a network that a player doesn't have access to + minetest.remove_node(pos) + return true + end + end, after_destruct = function(pos) + --FIXME: write drives before disconnecting me.send_event(pos,"disconnect") end, me_update = function(pos,_,ev) @@ -207,14 +340,12 @@ me.register_machine("cable", { if ev.type ~= "disconnect" then return end end --maybe this shouldn't be called on every update - if false then local meta = minetest.get_meta(pos) if me.get_connected_network(pos) then meta:set_string("infotext", "Network connected") else meta:set_string("infotext", "No Network") end - end end, machine = { type = "conductor", @@ -226,3 +357,9 @@ if technic then -- producer receiver, producer_receiver, battery technic.register_machine("HV", "microexpansion:ctrl", technic.receiver) end + +if me.uinv_category_enabled then + unified_inventory.add_category_item("storage", "microexpansion:ctrl") + unified_inventory.add_category_item("storage", "microexpansion:cable") +end + diff --git a/modules/network/init.lua b/modules/network/init.lua index 9dab9c9..0a03103 100644 --- a/modules/network/init.lua +++ b/modules/network/init.lua @@ -2,6 +2,9 @@ local me = microexpansion me.networks = {} local networks = me.networks local path = me.get_module_path("network") +local storage = minetest.get_mod_storage() + +dofile(path.."/constants.lua") local annotate_large_stack = function(stack, count) local description = minetest.registered_items[stack:get_name()] @@ -361,7 +364,7 @@ function me.connected_nodes(start_pos,include_ctrl) if vector.equals(closed,current.pos) then --found one was closed open = false - end + end end end -- get all connected nodes @@ -382,14 +385,36 @@ end function me.get_connected_network(start_pos) for npos,nn in me.connected_nodes(start_pos,true) do if nn == "microexpansion:ctrl" then - local net = me.get_network(npos) - if net then - return net,npos + local source = minetest.get_meta(npos):get_string("source") + local network + if source == "" then + network = me.get_network(npos) + else + network = me.get_network(vector.from_string(source)) + end + if network then + return network,npos end end end end +function me.promote_controller(start_pos,net) + local promoted = false + for npos,nn in me.connected_nodes(start_pos,true) do + if nn == "microexpansion:ctrl" and npos ~= start_pos then + if promoted then + minetest.get_meta(npos):set_string("source", promoted) + else + promoted = vector.to_string(npos) + minetest.get_meta(npos):set_string("source", "") + net.controller_pos = npos + end + end + end + return promoted and true or false +end + function me.update_connected_machines(start_pos,event,include_start) me.log("updating connected machines", "action") local ev = event or {type = "n/a"} @@ -430,20 +455,33 @@ function me.get_network(pos) end dofile(path.."/ctrl.lua") -- Controller/wires +dofile(path.."/security.lua") --Security Terminal -- load networks function me.load() - local f = io.open(me.worldpath.."/microexpansion_networks", "r") - if f then - local res = minetest.deserialize(f:read("*all")) - f:close() - if type(res) == "table" then - for _,n in pairs(res) do - local net = me.network.new(n) - net:load() - table.insert(me.networks,net) - end + local res = storage:get_string("networks") + if res == "" then + local f = io.open(me.worldpath.."/microexpansion_networks", "r") + if f then + me.log("loading network data from file","action") + res = minetest.deserialize(f:read("*all")) + f:close() + else + me.log("no network data loaded","action") + return end + else + me.log("loading network data from mod storage","action") + res = minetest.deserialize(res) + end + if type(res) == "table" then + for _,n in pairs(res) do + local net = me.network.new(n) + net:load() + table.insert(me.networks,net) + end + else + me.log("network data in unexpected format","error") end end @@ -461,9 +499,35 @@ function me.save() net.process = nil table.insert(data,net:serialize()) end - local f = io.open(me.worldpath.."/microexpansion_networks", "w") - f:write(minetest.serialize(data)) - f:close() + if storage then + me.log("saving network data to mod storage","info") + storage:set_string("networks", minetest.serialize(data)) + else + me.log("saving network data to file","info") + local f = io.open(me.worldpath.."/microexpansion_networks", "w") + f:write(minetest.serialize(data)) + f:close() + end +end + +function me.do_autosave() + me.last_autosave = -1 + minetest.after(1, function() + --print("autosaving ME Networks") + me.save() + me.last_autosave = minetest.get_server_uptime() + end) +end + +function me.autosave() + --TODO: make max autosave interval settable + if not me.last_autosave then + me.do_autosave() + elseif me.last_autosave == -1 then + return + elseif minetest.get_server_uptime() - me.last_autosave >= 600 then + me.do_autosave() + end end -- save on server shutdown diff --git a/modules/network/network.lua b/modules/network/network.lua index f2cde63..48f84ee 100644 --- a/modules/network/network.lua +++ b/modules/network/network.lua @@ -1,15 +1,20 @@ --- Microexpansion network -- @type network -- @field #table controller_pos the position of the controller +-- @field #table access a table of players and their respective access levels +-- @field #number default_access_level the access level of unlisted players -- @field #number power_load the power currently provided to the network -- @field #number power_storage the power that can be stored for the next tick local network = { + default_access_level = microexpansion.constants.security.access_levels.view, power_load = 0, power_storage = 0 } local me = microexpansion me.network = network +local access_level = microexpansion.constants.security.access_levels + --- construct a new network -- @function [parent=#network] new -- @param #table or the object to become a network or nil @@ -82,16 +87,79 @@ function network.adjacent_connected_nodes(pos, include_ctrl) if include_ctrl == false then if nn ~= "microexpansion:ctrl" then table.insert(nodes,{pos = apos, name = nn}) - end + end else table.insert(nodes,{pos = apos, name = nn}) end - end + end end - return nodes end +function network:get_access_level(player) + local name + local has_bypass = minetest.check_player_privs(player, "protection_bypass") + if not player then + return self.default_access_level + elseif has_bypass then + return me.constants.security.access_levels.full + elseif type(player) == "string" then + name = player + else + name = player:get_player_name() + end + if not self.access and not has_bypass then + return self.default_access_level + end + return self.access[name] or self.default_access_level +end + +function network:set_access_level(player, level) + local name + if not player then + self.default_access_level = level + elseif type(player) == "string" then + name = player + else + name = player:get_player_name() + end + if not self.access then + self.access = {} + end + self.access[name] = level + self:fallback_access() + -- autosave network data + me.autosave() +end + +function network:fallback_access() + local full_access = access_level.full + if not self.access then + --something must have gone badly wrong + me.log("no network access table in fallback method","error") + self.access = {} + end + for _,l in pairs(self.access) do + if l == full_access then + return + end + end + local meta = minetest.get_meta(self.controller_pos) + local owner = meta:get_string("owner") + if owner == "" then + me.log("ME Network Controller without owner at: " .. vector.to_string(self.controller_pos), "warning") + else + self.access[owner] = full_access + end +end + +function network:list_access() + if not self.access then + self.access = {} + end + return self.access +end + --- provide power to the network -- @function [parent=#network] provide -- @param #number power the amount of power provided @@ -169,7 +237,7 @@ function network:get_item_capacity() end end self.capacity_cache = cap - me.log("total capacity is "..cap, "error") + me.log("total capacity is "..cap, "verbose") return cap end @@ -233,6 +301,8 @@ function network:set_storage_space(count, listname) needed = needed + csize self:remove_slots(inv, listname, needed, csize) end + -- autosave network data + me.autosave() end function network:update() @@ -279,10 +349,33 @@ function network:find_loan(inv, stack) return nil end +function network:get_inventory_space(inv, list) + local inv = inv or self:get_inventory() + local listname = list or "main" + local max_slots = inv:get_size(listname) + local max_items = self.capacity_cache + + local slots, items = 0, 0 + -- Get amount of items in drive + for i = 1, max_slots do + local dstack = inv:get_stack(listname, i) + if dstack:get_name() ~= "" then + slots = slots + 1 + local num = dstack:get_count() + if num == 0 then num = 1 end + items = items + num + end + end + return math.max(max_items-items,0) +end + local function create_inventory(net) local invname = net:get_inventory_name() net.inv = minetest.create_detached_inventory(invname, { - allow_put = function(inv, listname, index, stack) + allow_put = function(inv, listname, index, stack, player) + if net:get_access_level(player) < access_level.interact then + return 0 + end local inside_stack = inv:get_stack(listname, index) local stack_name = stack:get_name() if minetest.get_item_group(stack_name, "microexpansion_cell") > 0 and @@ -318,6 +411,9 @@ local function create_inventory(net) net:set_storage_space(true) end, allow_take = function(inv, listname, slot, stack, player) + if net:get_access_level(player) < access_level.interact then + return 0 + end -- This is not remove_item, we only remove the loan. This real -- item will be removed. me.log("REMOVE: network allow taking of "..stack:get_name().." from "..listname, "error") diff --git a/modules/network/security.lua b/modules/network/security.lua new file mode 100644 index 0000000..72d821d --- /dev/null +++ b/modules/network/security.lua @@ -0,0 +1,292 @@ +-- microexpansion/network/security.lua + +local me = microexpansion +local access_level = me.constants.security.access_levels +local access_desc = me.constants.security.access_level_descriptions + +-- [me security] Get formspec +local function security_formspec(pos, player, rule, q) + local list + local buttons + local logout = true + local query = q or "" + local net,cp = me.get_connected_network(pos) + if player and cp then + local access = net:get_access_level(player) + if access < access_level.manage then -- Blocked dialog + logout = false + list = "label[2.5,3;"..minetest.colorize("red", "Access Denied").."]" + buttons = "button[3.5,6;2,1;logout;back]" + elseif (not rule) or rule == "" then -- Main Screen + --TODO: show button or entry for default access level + list = "tablecolumns[color,span=1;text;color,span=1;text]" + .. "table[0.5,2;6,7;access_table;" + local first = true + --TODO: filter + local name_list = {} + for p,l in pairs(net:list_access()) do + if first then + first = false + else + list = list .. "," + end + table.insert(name_list, p) + local desc = access_desc[l] or {name = "Unknown", color = "red"} + list = list .. "cyan," .. p .. "," .. desc.color .. "," .. desc.name + end + list = list .. ";]" + minetest.get_meta(pos):set_string("table_index", minetest.serialize(name_list)) + + list = list .. [[ + field[0.5,1;2,0.5;filter;;]]..query..[[] + button[3,1;0.8,0.5;search;?] + button[4,1;0.8,0.5;clear;X] + tooltip[search;Search] + tooltip[clear;Reset] + field_close_on_enter[filter;false] + ]] + buttons = [[ + button[7,7;1.5,0.8;new;new rule] + button[7,8;1.5,0.8;edit_sel;edit rule] + ]] + --button[7,6;1.5,0.8;del_sel;delete rule] + elseif rule == "" then -- Creation screen + logout = false + local players = "" + for _,p in pairs(minetest.get_connected_players()) do + if players ~= "" then + players = players .. "," + end + players = players .. p:get_player_name() + end + --TODO: add a text field (maybe toggelable) + list = [[ + dropdown[3,2.75;5,0.5;new_player;]]..players..[[;] + label[1.5,3;rule for:] + ]] + buttons = [[ + button[2,6;2,0.8;edit;add/edit] + button[5,6;2,0.8;back;cancel] + ]] + elseif (access < access_level.full and net:get_access_level(rule) >= access_level.manage) or (player ~= rule and access >= access_level.full and net:get_access_level(rule) >= access_level.full) then + -- low access dialog + list = "label[1,3;"..minetest.colorize("red", "You can only modify rules with lower access than yourself.").."]" + buttons = "button[3.5,6;2,1;back;back]" + else + local rule_level = net:get_access_level(rule) + local current = rule_level == access_level.blocked and "1" or + rule_level == access_level.view and "2" or + rule_level == access_level.interact and "3" or + rule_level == access_level.modify and "4" or + rule_level == access_level.manage and "5" or + rule_level == access_level.full and "6" or "" + list = [[ + label[1,3;rule for:]].."\t"..minetest.colorize("cyan", rule)..[[] + label[1,4;access level:] + dropdown[3,3.75;2,0.5;access;Blocked,View,Interact,Modify,Manage,Full;]]..current..[[] + ]] + buttons = [[ + button[1,6;1,0.8;save;save] + button[3,6;2,0.8;reset;reset to default] + button[6,6;1,0.8;back;cancel] + ]] + end + elseif cp then + logout = false + list = "label[2.5,3;Welcome to the security Terminal!]" + buttons = [[ + button[3.5,6;2,1;login;login] + button_exit[8,0.5;0.5,0.5;close;x] + ]] + else + logout = false + list = "label[2.5,3;" .. minetest.colorize("red", "No connected network!") .. "]" + buttons = "button_exit[3,6;2,1;close;close]" + end + + return [[ + formspec_version[2] + size[9,9.5] + ]].. + microexpansion.gui_bg .. + list .. + (logout and "button[7.5,0.5;1,0.5;logout;logout]" or "") .. + "label[0.5,0.5;ME Security Terminal]" .. + buttons +end + +local function update_security(pos,_,ev) + --for now all events matter + + local network = me.get_connected_network(pos) + local meta = minetest.get_meta(pos) + if network == nil then + meta:set_string("editing_rule", "") + meta:set_string("formspec", security_formspec(pos)) + end + meta:set_string("formspec", security_formspec(pos)) +end + +local security_recipe = nil +if minetest.get_modpath("mcl_core") then + security_recipe = { + { 1, { + {"mcl_core:iron_ingot", "mcl_copper:copper_ingot", "mcl_core:iron_ingot"}, + {"mcl_core:iron_ingot", "microexpansion:machine_casing", "mcl_core:iron_ingot"}, + {"mcl_core:iron_ingot", "microexpansion:cable", "mcl_core:iron_ingot"}, + }, + } + } + +else + security_recipe = { + { 1, { + {"default:steel_ingot", "default:copper_ingot", "default:steel_ingot"}, + {"default:steel_ingot", "microexpansion:machine_casing", "default:steel_ingot"}, + {"default:steel_ingot", "microexpansion:cable", "default:steel_ingot"}, + }, + } + } +end + +-- [me chest] Register node +microexpansion.register_node("security", { + description = "ME Security Terminal", + usedfor = "Allows controlling access to ME networks", + tiles = { + "security_bottom", + "security_bottom", + "chest_side", + "chest_side", + "chest_side", + "security_front", + }, + recipe = security_recipe, + is_ground_content = false, + groups = { cracky = 1, me_connect = 1 }, + paramtype = "light", + paramtype2 = "facedir", + me_update = update_security, + on_construct = function(pos) + local meta = minetest.get_meta(pos) + local net = me.get_connected_network(pos) + me.send_event(pos,"connect",{net=net}) + update_security(pos) + end, + after_destruct = function(pos) + me.send_event(pos,"disconnect") + end, + can_dig = function(pos, player) + if not player then + return false + end + local name = player:get_player_name() + if minetest.is_protected(pos, name) then + minetest.record_protection_violation(pos, name) + return false + end + local net,cp = me.get_connected_network(pos) + if not net then + return true + end + return net:get_access_level(name) >= access_level.manage + end, + on_receive_fields = function(pos, _, fields, sender) + if fields.close then + return + end + local net,cp = me.get_connected_network(pos) + if net then + if cp then + microexpansion.log("network and ctrl_pos","info") + else + microexpansion.log("network but no ctrl_pos","warning") + end + else + if cp then + microexpansion.log("no network but ctrl_pos","warning") + else + microexpansion.log("no network and no ctrl_pos","info") + end + end + local meta = minetest.get_meta(pos) + local name = sender:get_player_name() + if not net then + microexpansion.log("no network connected to security terminal","warning") + return + end + if fields.logout then + meta:set_string("formspec", security_formspec(pos)) + elseif fields.login or fields.back then + -- carry over networks from old versions + net:fallback_access() + meta:set_string("formspec", security_formspec(pos, name)) + elseif fields.search or fields.key_enter_field == "filter" then + meta:set_string("formspec", security_formspec(pos, name), false, fields.filter) + elseif fields.clear then + meta:set_string("formspec", security_formspec(pos, name)) + elseif fields.new then + meta:set_string("formspec", security_formspec(pos, name, "")) + elseif fields.edit then + local access = net:get_access_level(name) + if not fields.new_player then + me.log("edit button without new player field","warning") + meta:set_string("formspec", security_formspec(pos, name)) + return + end + if net:get_access_level(fields.new_player) == nil then + if access >= access_level.manage then + net:set_access_level(fields.new_player, net:get_access_level()) + end + end + meta:set_string("editing_rule", fields.new_player) + meta:set_string("formspec", security_formspec(pos, name, fields.new_player)) + elseif fields.edit_sel then + meta:set_string("formspec", security_formspec(pos, name, meta:get_string("editing_rule"))) + elseif fields.access_table then + local ev = minetest.explode_table_event(fields.access_table) + local table_index = minetest.deserialize(meta:get_string("table_index")) + local edit_player = table_index[ev.row] + if net:get_access_level(edit_player) == nil then + me.log("playerlist changed before editing","warning") + meta:set_string("formspec", security_formspec(pos, name)) + return + else + meta:set_string("editing_rule", edit_player) + if ev.type == "DCL" then + meta:set_string("formspec", security_formspec(pos, name, edit_player)) + end + end + elseif fields.reset then + local rule = meta:get_string("editing_rule") + local access = net:get_access_level(name) + local old_level = net:get_access_level(rule) + local new_level = net.default_access_level + if (access > old_level or name == rule) and (access > new_level or access >= access_level.full) then + net:set_access_level(rule, nil) + --TODO: show fail dialog if access violation + end + meta:set_string("formspec", security_formspec(pos, name)) + elseif fields.save then + local rule = meta:get_string("editing_rule") + local access = net:get_access_level(name) + local old_level = net:get_access_level(rule) + local new_level = fields.access == "Blocked" and access_level.blocked or + fields.access == "View" and access_level.view or + fields.access == "Interact" and access_level.interact or + fields.access == "Modify" and access_level.modify or + fields.access == "Manage" and access_level.manage or + fields.access == "Full" and access_level.full + if not new_level then + me.log("unknown access level selection " .. fields.access, "error") + --TODO: show fail dialog + return + end + if (access > old_level or name == rule) and access > new_level then + net:set_access_level(rule, new_level) + --TODO: show fail dialog if access violation + end + meta:set_string("formspec", security_formspec(pos, name)) + end + end, +}) diff --git a/modules/ores/init.lua b/modules/ores/init.lua index 89296e6..29ca3ee 100644 --- a/modules/ores/init.lua +++ b/modules/ores/init.lua @@ -1,45 +1,86 @@ -- ores/init.lua local me = microexpansion +local mcl_core_modpath = minetest.get_modpath("mcl_core") +stone_ingrediant = mcl_core_modpath and "mcl_core:stone" or "default:stone" + + +local incranium_y_min = -300 +local incranium_y_max = -90 + +local quartz_y_min = -31000 +local quartz_y_max = -5 + +local incranium_cracky = 3 +local quartz_cracky = 3 + +if mcl_core_modpath then + incranium_y_min = -55 + incranium_y_max = -20 + quartz_y_min = -50 + quartz_y_max = 0 + incranium_cracky = 3 + quartz_cracky = 3 +end + +local quartz_nodedef = { + description = "Quartz Ore", + tiles = { "default_stone.png^microexpansion_ore_quartz.png" }, + is_ground_content = true, + type = "ore", + groups = {cracky=quartz_cracky,material_stone=1, stone=1, pickaxey=3}, + drop = "microexpansion:quartz_crystal", + oredef = {{ + ore_type = "scatter", + wherein = stone_ingrediant, + clust_scarcity = 10*10*10, + clust_num_ores = 6, + clust_size = 5, + y_min = quartz_y_min, + y_max = quartz_y_max, + }}, +} + +incranium_nodedef = { + description = "Incranium Ore", + tiles = { "incranium" }, + is_ground_content = true, + groups = {cracky=incranium_cracky, material_stone=1, stone=1,pickaxey=3 }, + type = "ore", + oredef = { + { + ore_type = "blob", + wherein = stone_ingrediant, + clust_scarcity = 4*4*4, + clust_num_ores = 4, + clust_size = 3, + y_min = incranium_y_min, + y_max = incranium_y_max, + }, + }, + disabled = true, +} + +if mcl_core_modpath then + quartz_nodedef._mcl_hardness = 3 + quartz_nodedef._mcl_blast_resistance = 3 + quartz_nodedef._mcl_hardness = 3 + quartz_nodedef._mcl_silk_touch_drop = true + quartz_nodedef._mcl_fortune_drop = mcl_core.fortune_drop_ore + + incranium_nodedef._mcl_hardness = 3 + incranium_nodedef._mcl_blast_resistance = 3 + incranium_nodedef._mcl_hardness = 3 + incranium_nodedef._mcl_silk_touch_drop = true + incranium_nodedef._mcl_fortune_drop = mcl_core.fortune_drop_ore +end -- [register] Incranium Ore -me.register_node("incranium", { - description = "Incranium Ore", - tiles = { "incranium" }, - is_ground_content = true, - groups = { cracky=3, stone=1 }, - type = "ore", - oredef = { - { - ore_type = "blob", - wherein = "default:stone", - clust_scarcity = 4*4*4, - clust_num_ores = 4, - clust_size = 3, - y_min = -300, - y_max = -90, - }, - }, - disabled = true, +me.register_node("incranium", incranium_nodedef) + +me.register_item("quartz_crystal", { + description = "Quartz Crystal", }) --- "Supernatet", pronounced "Super-nat-et" is Latin for "float", this ore will --- float up if there are no blocks above it, so be careful! --- Supernatet ore will be used to craft wings of flight -me.register_node("supernatet", { - description = "Supernatant Ore", - tiles = { "default_stone.png^microexpansion_ore_supernatet.png" }, - is_ground_content = true, - type = "ore", - groups = { cracky=3, stone=1 }, - oredef = { - ore_type = "blob", - wherein = "default:stone", - clust_scarcity = 4*4*4, - clust_num_ores = 4, - clust_size = 3, - y_min = -300, - y_max = -90, - }, - status = "unstable", -}) + +me.register_node("quartz", quartz_nodedef) diff --git a/modules/power/gen.lua b/modules/power/gen.lua index d9e6f0d..fa685bc 100644 --- a/modules/power/gen.lua +++ b/modules/power/gen.lua @@ -1,90 +1,104 @@ -- power/gen.lua local me = microexpansion +local fuel_fired_generator_recipe = nil +if minetest.get_modpath("mcl_core") then +fuel_fired_generator_recipe = { + { 1, { + {"mcl_core:iron_ingot", "mcl_furnaces:furnace", "mcl_core:iron_ingot"}, + {"mcl_core:iron_ingot", "microexpansion:machine_casing", "mcl_core:iron_ingot"}, + {"mcl_core:iron_ingot", "mcl_core:iron_ingot", "mcl_core:iron_ingot"}, + }, + } +} + +else +fuel_fired_generator_recipe = { + { 1, { + {"default:steel_ingot", "default:furnace", "default:steel_ingot"}, + {"default:steel_ingot", "microexpansion:machine_casing", "default:steel_ingot"}, + {"default:steel_ingot", "default:steel_ingot", "default:steel_ingot"}, + }, + } +} +end -- [register node] Fuel Fired Generator me.register_machine("fuel_fired_generator", { - description = "Fuel-Fired Generator", - tiles = { - "machine_sides", - "machine_sides", - "machine_sides", - "machine_sides", - "machine_sides", - "machine_sides", - "fuelgen_front", - }, - recipe = { - { 1, { - { "default:steel_ingot", "default:furnace", "default:steel_ingot" }, - {"default:steel_ingot", "microexpansion:machine_casing", "default:steel_ingot" }, - { "default:steel_ingot", "default:steel_ingot", "default:steel_ingot" }, - }, - } - }, - groups = { cracky = 1 }, - connect_sides = "machine", - paramtype2 = "facedir", - status = "unstable", - machine = { - type = "provider", - on_survey = function() -- args: pos - --TODO: burn fuel - return 5 -- Generate 5 ME/tick - end, - }, + description = "Fuel-Fired Generator", + tiles = { + "machine_sides", + "machine_sides", + "machine_sides", + "machine_sides", + "machine_sides", + "machine_sides", + "fuelgen_front", + }, + recipe = fuel_fired_generator_recipe, + groups = { cracky = 1 }, + connect_sides = "machine", + paramtype2 = "facedir", + status = "unstable", + machine = { + type = "provider", + on_survey = function() -- args: pos + --TODO: burn fuel + return 5 -- Generate 5 ME/tick + end, + }, }) --[[register node] Super Smelter me.register_node("super_smelter", { - description = "Super Smelter", - tiles = { - "machine_sides", - "machine_sides", - "machine_sides", - "machine_sides", - "machine_sides", - "super_smelter_front", - }, - recipe = { - { 1, { - { "default:furnace", "default:furnace", "default:furnace" }, - { "default:steel_ingot", "microexpansion:machine_casing", "default:steel_ingot" }, - { "default:steel_ingot", "default:steel_ingot", "default:steel_ingot" }, - }, - }, - }, - groups = { cracky = 1, me_connect = 1, }, - connect_sides = "machine", - paramtype2 = "facedir", - status = "unstable", - machine = { - type = "consumer", - on_survey = function(pos) - return 5 -- Consume 5 ME/tick - end, - }, + description = "Super Smelter", + tiles = { + "machine_sides", + "machine_sides", + "machine_sides", + "machine_sides", + "machine_sides", + "super_smelter_front", + }, + recipe = { + { 1, { + {"default:furnace", "default:furnace", "default:furnace"}, + {"default:steel_ingot", "microexpansion:machine_casing", "default:steel_ingot"}, + {"default:steel_ingot", "default:steel_ingot", "default:steel_ingot"}, + }, + }, + }, + groups = { cracky = 1, me_connect = 1, }, + connect_sides = "machine", + paramtype2 = "facedir", + status = "unstable", + machine = { + type = "consumer", + on_survey = function(pos) + return 5 -- Consume 5 ME/tick + end, + }, }) -- [register item] Geothermal Generator me.register_node("geo_generator", { - description = "Geothermal Generator", - tiles = { - "machine_sides", - "machine_sides", - "machine_sides", - "machine_sides", - "machine_sides", - "geogen_front", - }, - groups = { cracky = 1, me_connect = 1, }, - connect_sides = "machine", - paramtype2 = "facedir", - status = "unstable", - machine = { - type = "provider", - on_survey = function(pos) - return 10 -- Generate 10 ME/tick - end, - }, + description = "Geothermal Generator", + tiles = { + "machine_sides", + "machine_sides", + "machine_sides", + "machine_sides", + "machine_sides", + "geogen_front", + }, + groups = { cracky = 1, me_connect = 1, }, + connect_sides = "machine", + paramtype2 = "facedir", + status = "unstable", + machine = { + type = "provider", + on_survey = function(pos) + return 10 -- Generate 10 ME/tick + end, + }, })]] diff --git a/modules/power/network.lua b/modules/power/network.lua index 57dbac2..bd36bd2 100644 --- a/modules/power/network.lua +++ b/modules/power/network.lua @@ -9,16 +9,16 @@ local power = me.power -- [local function] Get netitem by position local function get_netitem_by_pos(list, pos) - for _, i in pairs(list) do - if vector.equals(pos, i.pos) then - return i - end - end + for _, i in pairs(list) do + if vector.equals(pos, i.pos) then + return i + end + end end -- [function] Generate new network ID function power.new_id() - return "network_"..#me.networks+1 + return "network_"..#me.networks+1 end -- [function] Add machine to network @@ -28,84 +28,84 @@ end -- [function] Remove machine from network function power.remove_machine(pos) - local meta = minetest.get_meta(pos) - meta:set_string("network_ignore", "true") + local meta = minetest.get_meta(pos) + meta:set_string("network_ignore", "true") end -- [function] Trace network function power.trace(pos) - local netpos = me.networks[minetest.get_meta(pos):get_string("network_id")] + local netpos = me.networks[minetest.get_meta(pos):get_string("network_id")] - -- if no network, return - if not netpos then - return - end + -- if no network, return + if not netpos then + return + end - local meta = minetest.get_meta(netpos) - local netid = meta:get_string("network_id") - local list = {} + local meta = minetest.get_meta(netpos) + local netid = meta:get_string("network_id") + local list = {} - local delete = false - if meta:get_string("network_ignore") == "true" then - delete = true - end + local delete = false + if meta:get_string("network_ignore") == "true" then + delete = true + end - -- [local function] Indexed - local function indexed(p) - for _, i in pairs(list) do - if vector.equals(p, i.pos) then - return true - end - end - end + -- [local function] Indexed + local function indexed(p) + for _, i in pairs(list) do + if vector.equals(p, i.pos) then + return true + end + end + end - -- [local function] Trace - local function trace(nodes) - for _, p in pairs(nodes) do - if not indexed(p) then - local machine = minetest.get_meta(p) - if machine:get_string("network_ignore") ~= "true" then - local node = me.get_node(p).name - local desc = minetest.registered_nodes[node].description - if delete then - machine:set_string("network_id", nil) - machine:set_string("infotext", desc.."\nNo Network") - me.network_set_demand(p, 0) - else - machine:set_string("network_id", netid) - machine:set_string("infotext", desc.."\nNetwork ID: "..netid) - end + -- [local function] Trace + local function trace(nodes) + for _, p in pairs(nodes) do + if not indexed(p) then + local machine = minetest.get_meta(p) + if machine:get_string("network_ignore") ~= "true" then + local node = me.get_node(p).name + local desc = minetest.registered_nodes[node].description + if delete then + machine:set_string("network_id", nil) + machine:set_string("infotext", desc.."\nNo Network") + me.network_set_demand(p, 0) + else + machine:set_string("network_id", netid) + machine:set_string("infotext", desc.."\nNetwork ID: "..netid) + end - list[#list + 1] = { pos = p, demand = machine:get_int("demand") } - trace(power.get_connected_nodes(p, false)) - end - end - end - end + list[#list + 1] = { pos = p, demand = machine:get_int("demand") } + trace(power.get_connected_nodes(p, false)) + end + end + end + end - trace(power.get_connected_nodes(netpos)) + trace(power.get_connected_nodes(netpos)) - -- Check original list - local original = minetest.deserialize(meta:get_string("netitems")) - if original then - for _, i in pairs(original) do - if not indexed(i.pos) then - local node = me.get_node(i.pos).name - local desc = minetest.registered_nodes[node].description - local machine = minetest.get_meta(i.pos) - machine:set_string("network_id", nil) - machine:set_string("infotext", desc.."\nNo Network") - me.network_set_demand(pos, 0) - end - end - end + -- Check original list + local original = minetest.deserialize(meta:get_string("netitems")) + if original then + for _, i in pairs(original) do + if not indexed(i.pos) then + local node = me.get_node(i.pos).name + local desc = minetest.registered_nodes[node].description + local machine = minetest.get_meta(i.pos) + machine:set_string("network_id", nil) + machine:set_string("infotext", desc.."\nNo Network") + me.network_set_demand(pos, 0) + end + end + end - meta:set_string("netitems", minetest.serialize(list)) + meta:set_string("netitems", minetest.serialize(list)) - -- Update infotext - meta:set_string("infotext", "Network Controller (owned by ".. - meta:get_string("owner")..")\nNetwork ID: "..meta:get_string("network_id").. - "\nDemand: "..dump(me.network_get_demand(netpos))) + -- Update infotext + meta:set_string("infotext", "Network Controller (owned by ".. + meta:get_string("owner")..")\nNetwork ID: "..meta:get_string("network_id").. + "\nDemand: "..dump(me.network_get_demand(netpos))) end --- @@ -114,11 +114,11 @@ end -- [function] Get load information function me.network_get_load(pos) - local ctrl = me.networks[minetest.get_meta(pos):get_string("network_id")] - if ctrl then - local meta = minetest.get_meta(ctrl) - local list = minetest.deserialize(meta:get_string("netitems")) - end + local ctrl = me.networks[minetest.get_meta(pos):get_string("network_id")] + if ctrl then + local meta = minetest.get_meta(ctrl) + local list = minetest.deserialize(meta:get_string("netitems")) + end end ---- Generators ---- @@ -127,53 +127,53 @@ end -- [function] Get total network demand function me.network_get_demand(pos) - local ctrl = me.networks[minetest.get_meta(pos):get_string("network_id")] + local ctrl = me.networks[minetest.get_meta(pos):get_string("network_id")] - -- if no network, return - if not ctrl then - return - end + -- if no network, return + if not ctrl then + return + end - local meta = minetest.get_meta(ctrl) - local list = minetest.deserialize(meta:get_string("netitems")) + local meta = minetest.get_meta(ctrl) + local list = minetest.deserialize(meta:get_string("netitems")) - local demand = 0 - for _, i in pairs(list) do - if i.demand then - demand = demand + i.demand - end - end + local demand = 0 + for _, i in pairs(list) do + if i.demand then + demand = demand + i.demand + end + end - return demand + return demand end -- [function] Set demand for machine function me.network_set_demand(pos, demand) - -- Update original metadata - minetest.get_meta(pos):set_int("demand", demand) + -- Update original metadata + minetest.get_meta(pos):set_int("demand", demand) - local ctrl = me.networks[minetest.get_meta(pos):get_string("network_id")] + local ctrl = me.networks[minetest.get_meta(pos):get_string("network_id")] - -- if no network, return - if not ctrl then - return - end + -- if no network, return + if not ctrl then + return + end - local meta = minetest.get_meta(ctrl) - local list = minetest.deserialize(meta:get_string("netitems")) - local item = get_netitem_by_pos(list, pos) + local meta = minetest.get_meta(ctrl) + local list = minetest.deserialize(meta:get_string("netitems")) + local item = get_netitem_by_pos(list, pos) - if not item then - return - end + if not item then + return + end - item.demand = demand - meta:set_string("netitems", minetest.serialize(list)) + item.demand = demand + meta:set_string("netitems", minetest.serialize(list)) - -- Update infotext - meta:set_string("infotext", "Network Controller (owned by ".. - meta:get_string("owner")..")\nNetwork ID: "..meta:get_string("network_id").. - "\nDemand: "..dump(me.network_get_demand(pos))) + -- Update infotext + meta:set_string("infotext", "Network Controller (owned by ".. + meta:get_string("owner")..")\nNetwork ID: "..meta:get_string("network_id").. + "\nDemand: "..dump(me.network_get_demand(pos))) end ---- Storage ---- diff --git a/modules/shared/init.lua b/modules/shared/init.lua deleted file mode 100644 index befb806..0000000 --- a/modules/shared/init.lua +++ /dev/null @@ -1,30 +0,0 @@ --- shared/init.lua - -local me = microexpansion - --- This mostly contains items that are used by multiple modules and --- don't really fit with anything else. - --- [register item] Steel Infused Obsidian Ingot -me.register_item("steel_infused_obsidian_ingot", { - description = "Steel Infused Obsidian Ingot", - recipe = { - { 2, { - { "default:steel_ingot", "default:obsidian_shard", "default:steel_ingot" }, - }, - }, - }, -}) - --- [register item] Machine Casing -me.register_item("machine_casing", { - description = "Machine Casing", - recipe = { - { 1, { - {"default:steel_ingot", "default:steel_ingot", "default:steel_ingot"}, - {"default:steel_ingot", "default:copper_ingot", "default:steel_ingot"}, - {"default:steel_ingot", "default:steel_ingot", "default:steel_ingot"}, - }, - }, - }, -}) diff --git a/modules/storage/api.lua b/modules/storage/api.lua index e03c531..9464ebd 100644 --- a/modules/storage/api.lua +++ b/modules/storage/api.lua @@ -2,53 +2,60 @@ local BASENAME = "microexpansion" +--FIXME: either consolidate or forbid crafting with filled cells + -- [function] register cell function microexpansion.register_cell(itemstring, def) - if not def.inventory_image then - def.inventory_image = itemstring - end + if not def.inventory_image then + def.inventory_image = itemstring + end - -- register craftitem - minetest.register_craftitem(BASENAME..":"..itemstring, { - description = def.description, - inventory_image = BASENAME.."_"..def.inventory_image..".png", - groups = {microexpansion_cell = 1}, - stack_max = 1, - microexpansion = { - base_desc = def.description, - drive = { - capacity = def.capacity or 5000, - }, - }, - }) + -- register craftitem + minetest.register_craftitem(BASENAME..":"..itemstring, { + description = def.description, + inventory_image = BASENAME.."_"..def.inventory_image..".png", + groups = {microexpansion_cell = 1}, + stack_max = 1, + microexpansion = { + base_desc = def.description, + drive = { + capacity = def.capacity or 5000, + }, + }, + }) - -- if recipe, register recipe - if def.recipe then - microexpansion.register_recipe(BASENAME..":"..itemstring, def.recipe) - end + -- if recipe, register recipe + if def.recipe then + microexpansion.register_recipe(BASENAME..":"..itemstring, def.recipe) + end + + if microexpansion.uinv_category_enabled then + unified_inventory.add_category_item("storage", BASENAME..":"..itemstring) + end end -- [function] Get cell size function microexpansion.get_cell_size(name) - if minetest.get_item_group(name, "microexpansion_cell") == 0 then - return 0 - end - local item = minetest.registered_craftitems[name] - return item.microexpansion.drive.capacity + if minetest.get_item_group(name, "microexpansion_cell") == 0 then + return 0 + end + local item = minetest.registered_craftitems[name] + return item.microexpansion.drive.capacity end -- [function] Calculate max stacks function microexpansion.int_to_stacks(int) - return math.ceil(int / 99) + return math.ceil(int / 99) end -- [function] Calculate number of pages function microexpansion.int_to_pagenum(int) - return math.floor(microexpansion.int_to_stacks(int) / 32) + return math.floor(microexpansion.int_to_stacks(int) / 32) end --- [function] Move items from inv to inv -function microexpansion.move_inv(net, inv1, inv2, max) +--[[ [function] Move items from inv to inv +function microexpansion.move_inv(inv1, inv2, max) +>>>>>>> a21dbd9b825ab9727a42d597bc86f52342da7d44 if max <= 0 then return end local finv, tinv = inv1.inv, inv2.inv local fname, tname = inv1.name, inv2.name @@ -81,3 +88,5 @@ function microexpansion.move_inv(net, inv1, inv2, max) end end end +]] + diff --git a/modules/storage/drive.lua b/modules/storage/drive.lua index c40762e..21adfb6 100644 --- a/modules/storage/drive.lua +++ b/modules/storage/drive.lua @@ -1,6 +1,7 @@ -- microexpansion/machines.lua local me = microexpansion +local access_level = microexpansion.constants.security.access_levels local netdrives @@ -312,6 +313,26 @@ local function update_drive(pos,_,ev) end end +if minetest.get_modpath("mcl_core") then + drive_recipe = { + { 1, { + {"mcl_core:iron_ingot", "mcl_chests:chest", "mcl_core:iron_ingot"}, + {"mcl_core:iron_ingot", "microexpansion:machine_casing", "mcl_core:iron_ingot"}, + {"mcl_core:iron_ingot", "mcl_chests:chest", "mcl_core:iron_ingot"}, +}, +}} + +else + drive_recipe = { + { 1, { + {"default:steel_ingot", "default:chest", "default:steel_ingot" }, + {"default:steel_ingot", "microexpansion:machine_casing", "default:steel_ingot" }, + {"default:steel_ingot", "default:chest", "default:steel_ingot" }, + }, + } + } +end + -- [me chest] Register node microexpansion.register_node("drive", { description = "ME Drive", @@ -324,14 +345,7 @@ microexpansion.register_node("drive", { "chest_side", "drive_full", }, - recipe = { - { 1, { - {"default:steel_ingot", "default:chest", "default:steel_ingot" }, - {"default:steel_ingot", "microexpansion:machine_casing", "default:steel_ingot" }, - {"default:steel_ingot", "default:chest", "default:steel_ingot" }, - }, - } - }, + recipe = drive_recipe, is_ground_content = false, groups = { cracky = 1, me_connect = 1 }, paramtype = "light", @@ -340,14 +354,14 @@ microexpansion.register_node("drive", { on_construct = function(pos) local meta = minetest.get_meta(pos) meta:set_string("formspec", - "size[9,7.5]".. + "size[9,9.5]".. microexpansion.gui_bg .. microexpansion.gui_slots .. [[ label[0,-0.23;ME Drive] - list[context;main;0,0.3;5,2] - list[current_player;main;0,3.5;8,1;] - list[current_player;main;0,4.73;8,3;8] + list[context;main;0,0.3;8,4] + list[current_player;main;0,5.5;8,1;] + list[current_player;main;0,6.73;8,3;8] listring[current_name;main] listring[current_player;main] field_close_on_enter[filter;false] @@ -357,7 +371,19 @@ microexpansion.register_node("drive", { me.send_event(pos, "connect") end, can_dig = function(pos, player) - if minetest.is_protected(pos, player) then + if not player then + return false + end + local name = player:get_player_name() + if minetest.is_protected(pos, name) then + minetest.record_protection_violation(pos, name) + return false + end + local net,cp = me.get_connected_network(pos) + if not net then + return true + end + if net:get_access_level(name) < access_level.modify then return false end local meta = minetest.get_meta(pos) @@ -368,11 +394,21 @@ microexpansion.register_node("drive", { me.send_event(pos, "disconnect") end, allow_metadata_inventory_put = function(pos, _, _, stack, player) - if minetest.is_protected(pos, player) - or minetest.get_item_group(stack:get_name(), "microexpansion_cell") == 0 then + local name = player:get_player_name() + local network = me.get_connected_network(pos) + if network then + if network:get_access_level(player) < access_level.interact then + return 0 + end + elseif minetest.is_protected(pos, name) then + minetest.record_protection_violation(pos, name) return 0 end - return 1 + if minetest.get_item_group(stack:get_name(), "microexpansion_cell") == 0 then + return 0 + else + return 1 + end end, on_metadata_inventory_put = function(pos, _, _, stack) me.send_event(pos, "item_cap") @@ -387,8 +423,10 @@ microexpansion.register_node("drive", { me.send_event(pos, "items", {net=network}) return end + -- TODO: adjust for correct space -- network:set_storage_space(#items) for _,stack in pairs(items) do + -- TODO: do not change storage space in a loop network:set_storage_space(true) me.insert_item(stack, network, ctrl_inv, "main") end @@ -396,10 +434,19 @@ microexpansion.register_node("drive", { me.send_event(pos, "items", {net=network}) end, allow_metadata_inventory_take = function(pos,_,_,stack, player) --args: pos, listname, index, stack, player - if minetest.is_protected(pos, player) then + local name = player:get_player_name() + local network = me.get_connected_network(pos) + if network then + write_drive_cells(pos,network) + if network:get_access_level(player) < access_level.interact then + return 0 + end + elseif minetest.is_protected(pos, name) then + minetest.record_protection_violation(pos, name) return 0 end local network = me.get_connected_network(pos) + -- should the drives really be written every take action? (performance) write_drive_cells(pos,network) return stack:get_count() end, @@ -418,8 +465,7 @@ microexpansion.register_node("drive", { for _,ostack in pairs(items) do local postack = ItemStack(ostack) -- me.log("drive meta_inv_take remove_item "..tostring(postack:get_count()).." "..postack:get_name(), "error") - -- TODO: this was here, but did nothing? me.remove_item(network, ctrl_inv, "main", postack) - -- No, this is the main item removal on cell removal from drive + -- This is the main item removal on cell removal from drive me.remove_item(network, ctrl_inv, "main", postack) --this returns 99 (max count) even if it removes more --ctrl_inv:remove_item("main", ostack) @@ -430,3 +476,7 @@ microexpansion.register_node("drive", { me.send_event(pos, "items", {net=network}) end, }) + +if me.uinv_category_enabled then + unified_inventory.add_category_item("storage", "microexpansion:drive") +end diff --git a/modules/storage/storage.lua b/modules/storage/storage.lua index a6f5569..881054f 100644 --- a/modules/storage/storage.lua +++ b/modules/storage/storage.lua @@ -2,15 +2,42 @@ --TODO: use storagecomp for crafting +if minetest.get_modpath("mcl_core") then +microexpansion.register_cell("cell_1k", { + description = "1k ME Storage Cell", + capacity = 1000, + recipe = { + { 1, { + {"moreores:tin_ingot", "mcl_copper:copper_ingot", "moreores:tin_ingot"}, + {"mcl_copper:copper_ingot", "microexpansion:steel_infused_obsidian_ingot", "mcl_copper:copper_ingot"}, + {"moreores:tin_ingot", "mcl_copper:copper_ingot", "moreores:tin_ingot"} + }}, + }, +}) + +microexpansion.register_cell("cell_2k", { + description = "2k ME Storage Cell", + capacity = 2000, + recipe = { + { 1, { + {"mcl_copper:copper_ingot", "mcl_core:iron_ingot", "mcl_copper:copper_ingot"}, + {"mcl_core:iron_ingot", "mcl_core:obsidian", "mcl_core:iron_ingot"}, + {"mcl_copper:copper_ingot", "mcl_core:iron_ingot", "mcl_copper:copper_ingot"} + }}, + { 1, "shapeless", {"microexpansion:cell_1k", "microexpansion:cell_1k"}} + }, +}) +else + -- [drive] 1k microexpansion.register_cell("cell_1k", { - description = "1k ME Storage Cell", - capacity = 1000, - recipe = { - { 1, { - {"default:tin_ingot", "default:copper_ingot", "default:tin_ingot"}, - {"default:copper_ingot","microexpansion:steel_infused_obsidian_ingot","default:copper_ingot"}, - {"default:tin_ingot", "default:copper_ingot", "default:tin_ingot"}, + description = "1k ME Storage Cell", + capacity = 1000, + recipe = { + { 1, { + {"default:tin_ingot", "default:copper_ingot", "default:tin_ingot"}, + {"default:copper_ingot", "microexpansion:steel_infused_obsidian_ingot", "default:copper_ingot"}, + {"default:tin_ingot", "default:copper_ingot", "default:tin_ingot"}, }, } }, @@ -18,64 +45,66 @@ microexpansion.register_cell("cell_1k", { -- [drive] 2k microexpansion.register_cell("cell_2k", { - description = "2k ME Storage Cell", - capacity = 2000, - recipe = { + description = "2k ME Storage Cell", + capacity = 2000, + recipe = { { 1, { - {"default:copper_ingot","default:steel_ingot", "default:copper_ingot"}, - {"default:steel_ingot", "default:obsidian_shard", "default:steel_ingot"}, - {"default:copper_ingot","default:steel_ingot", "default:copper_ingot"}, + {"default:copper_ingot", "default:steel_ingot", "default:copper_ingot"}, + {"default:steel_ingot", "default:obsidian_shard", "default:steel_ingot"}, + {"default:copper_ingot", "default:steel_ingot", "default:copper_ingot"}, }, }, - { 1, "shapeless", {"microexpansion:cell_1k","microexpansion:cell_1k"}} + { 1, "shapeless", {"microexpansion:cell_1k", "microexpansion:cell_1k"}} }, }) +end + -- [drive] 4k microexpansion.register_cell("cell_4k", { - description = "4k ME Storage Cell", - capacity = 4000, - recipe = { - { 1, "shapeless", { + description = "4k ME Storage Cell", + capacity = 4000, + recipe = { + { 1, "shapeless", { "microexpansion:steel_infused_obsidian_ingot", "microexpansion:machine_casing", "microexpansion:steel_infused_obsidian_ingot" }, }, - { 1, "shapeless", {"microexpansion:cell_2k","microexpansion:cell_2k"}} + { 1, "shapeless", {"microexpansion:cell_2k", "microexpansion:cell_2k"}} }, }) -- [drive] 8k microexpansion.register_cell("cell_8k", { - description = "8k ME Storage Cell", - capacity = 8000, - recipe = { - { 1, "shapeless", {"microexpansion:cell_4k","microexpansion:cell_4k"}} - }, + description = "8k ME Storage Cell", + capacity = 8000, + recipe = { + { 1, "shapeless", {"microexpansion:cell_4k", "microexpansion:cell_4k"}} + }, }) -- [drive] 16k microexpansion.register_cell("cell_16k", { - description = "16k ME Storage Cell", - capacity = 16000, - recipe = { - { 1, "shapeless", {"microexpansion:cell_8k","microexpansion:cell_8k"}} + description = "16k ME Storage Cell", + capacity = 16000, + recipe = { + { 1, "shapeless", {"microexpansion:cell_8k", "microexpansion:cell_8k"}} }, }) -- [drive] 32k microexpansion.register_cell("cell_32k", { - description = "32k ME Storage Cell", - capacity = 32000, - recipe = { - { 1, "shapeless", {"microexpansion:cell_16k","microexpansion:cell_16k"}} + description = "32k ME Storage Cell", + capacity = 32000, + recipe = { + { 1, "shapeless", {"microexpansion:cell_16k", "microexpansion:cell_16k"}} }, }) -- [drive] 64k microexpansion.register_cell("cell_64k", { - description = "64k ME Storage Cell", - capacity = 64000, - recipe = { - { 1, "shapeless", {"microexpansion:cell_32k","microexpansion:cell_32k"}} + description = "64k ME Storage Cell", + capacity = 64000, + recipe = { + { 1, "shapeless", {"microexpansion:cell_32k", "microexpansion:cell_32k"}} }, }) diff --git a/modules/storage/terminal.lua b/modules/storage/terminal.lua index a69c567..fba46cc 100644 --- a/modules/storage/terminal.lua +++ b/modules/storage/terminal.lua @@ -3,6 +3,7 @@ local me = microexpansion local pipeworks_enabled = minetest.get_modpath("pipeworks") and true or false +local access_level = microexpansion.constants.security.access_levels -- [me chest] Get formspec local function chest_formspec(pos, start_id, listname, page_max, q) @@ -16,10 +17,10 @@ local function chest_formspec(pos, start_id, listname, page_max, q) if listname and net:get_item_capacity() > 0 then local ctrlinvname = net:get_inventory_name() if listname == "main" then - list = "list[detached:"..ctrlinvname..";" - .. listname .. ";0,0.3;8,4;" .. (start_id - 1) .. "]" + list = "list[detached:"..ctrlinvname..";" + .. listname .. ";0,0.3;8,4;" .. (start_id - 1) .. "]" else - list = "list[context;" .. listname .. ";0,0.3;8,4;" .. (start_id - 1) .. "]" + list = "list[context;" .. listname .. ";0,0.3;8,4;" .. (start_id - 1) .. "]" end if minetest.get_modpath("i3") then list = list .. [[ @@ -32,8 +33,8 @@ local function chest_formspec(pos, start_id, listname, page_max, q) ]] end list = list .. [[ - listring[detached:]]..ctrlinvname..[[;main] - listring[current_player;main] + listring[detached:]]..ctrlinvname..[[;main] + listring[current_player;main] ]] buttons = [[ button[3.56,4.35;1.8,0.9;tochest;To Drive] @@ -64,7 +65,6 @@ local function chest_formspec(pos, start_id, listname, page_max, q) buttons = "" page_number = "" end - return [[ size[9,9.5] ]].. @@ -96,8 +96,31 @@ local function update_chest(pos,_,ev) meta:set_string("formspec", chest_formspec(pos, 1, "main", page_max)) end +local term_recipe = nil +if minetest.get_modpath("mcl_core") then +term_recipe = { + { 1, { + {"mcl_core:iron_ingot", "mcl_chests:chest", "mcl_core:iron_ingot"}, + {"mcl_core:iron_ingot", "microexpansion:machine_casing", "mcl_core:iron_ingot"}, + {"mcl_core:iron_ingot", "microexpansion:cable", "mcl_core:iron_ingot"}, + }, + } +} + +else + +term_recipe = { + { 1, { + {"default:steel_ingot", "default:chest", "default:steel_ingot"}, + {"default:steel_ingot", "microexpansion:machine_casing", "default:steel_ingot"}, + {"default:steel_ingot", "microexpansion:cable", "default:steel_ingot"}, + }, + } + } +end + -- [me chest] Register node -me.register_node("term", { +microexpansion.register_node("term", { description = "ME Terminal", usedfor = "Can interact with storage cells in ME networks", tiles = { @@ -108,14 +131,7 @@ me.register_node("term", { "chest_side", "chest_front", }, - recipe = { - { 1, { - {"default:steel_ingot", "default:chest", "default:steel_ingot"}, - {"default:steel_ingot", "microexpansion:machine_casing", "default:steel_ingot"}, - {"default:steel_ingot", "microexpansion:cable", "default:steel_ingot"}, - }, - } - }, + recipe = term_recipe, is_ground_content = false, groups = { cracky = 1, me_connect = 1, tubedevice = 1, tubedevice_receiver = 1 }, paramtype = "light", @@ -123,6 +139,7 @@ me.register_node("term", { me_update = update_chest, on_construct = function(pos) local meta = minetest.get_meta(pos) + meta:set_string("formspec", chest_formspec(pos, 1)) meta:set_string("inv_name", "none") meta:set_int("page", 1) @@ -131,13 +148,38 @@ me.register_node("term", { local net = me.get_connected_network(pos) me.send_event(pos, "connect", {net=net}) - update_chest(pos) + if net then + update_chest(pos) + end end, after_destruct = function(pos) me.send_event(pos, "disconnect") end, - allow_metadata_inventory_put = function(pos, listname, index, stack, player) - -- TODO: Check capacity, only allow if room + can_dig = function(pos, player) + if not player then + return false + end + local name = player:get_player_name() + if minetest.is_protected(pos, name) then + minetest.record_protection_violation(pos, name) + return false + end + local net,cp = me.get_connected_network(pos) + if not net then + return true + end + return net:get_access_level(name) >= access_level.modify + end, + allow_metadata_inventory_put = function(pos, _, _, stack, player) + local network = me.get_connected_network(pos) + if network then + if network:get_access_level(player) < access_level.interact then + return 0 + end + elseif minetest.is_protected(pos, player) then + minetest.record_protection_violation(pos, player) + return 0 + end return stack:get_count() end, on_metadata_inventory_put = function(pos, listname, _, stack) @@ -146,6 +188,18 @@ me.register_node("term", { me.insert_item(stack, net, inv, "main") net:set_storage_space(true) end, + allow_metadata_inventory_take = function(pos,_,_,stack, player) + local network = me.get_connected_network(pos) + if network then + if network:get_access_level(player) < access_level.interact then + return 0 + end + elseif minetest.is_protected(pos, player) then + minetest.record_protection_violation(pos, player) + return 0 + end + return math.min(stack:get_count(),stack:get_stack_max()) + end, on_metadata_inventory_take = function(pos, listname, _, stack) local net = me.get_connected_network(pos) local inv = net:get_inventory() @@ -154,6 +208,9 @@ me.register_node("term", { tube = { can_insert = function(pos, _, stack) --pos, node, stack, direction local net = me.get_connected_network(pos) + if not net then + return false + end local inv = net:get_inventory() local max_slots = inv:get_size("main") local max_items = net.capacity_cache @@ -174,6 +231,9 @@ me.register_node("term", { end, insert_object = function(pos, _, stack) local net = me.get_connected_network(pos) + if not net then + return stack + end local inv = net:get_inventory() local leftovers = me.insert_item(stack, net, inv, "main") net:set_storage_space(true) @@ -206,7 +266,7 @@ me.register_node("term", { if cp then ctrl_inv = net:get_inventory() else - me.log("no network connected","warning") + microexpansion.log("no network connected","warning") return end local inv @@ -258,8 +318,12 @@ me.register_node("term", { meta:set_string("inv_name", "main") meta:set_string("formspec", chest_formspec(pos, 1, "main", page_max)) elseif fields.tochest then + if net:get_access_level(sender) < access_level.interact then + return + end local pinv = minetest.get_inventory({type="player", name=sender:get_player_name()}) - -- TODO: test and fix, net:set_storage_space(pinv:get_size("main")) + -- TODO: test and fix + -- net:set_storage_space(pinv:get_size("main")) local space = net:get_item_capacity() local contents = ctrl_inv:get_list("main") or {} for _,s in pairs(contents) do @@ -272,3 +336,7 @@ me.register_node("term", { end end, }) + +if me.uinv_category_enabled then + unified_inventory.add_category_item("storage", "microexpansion:term") +end diff --git a/register.lua b/register.lua index 00d5be6..5ca039b 100644 --- a/register.lua +++ b/register.lua @@ -5,90 +5,99 @@ local me = microexpansion local power = me.power +if me.uinv_category_enabled and unified_inventory.registered_categories then + if not unified_inventory.registered_categories["storage"] then + unified_inventory.register_category("storage", { + symbol = "default:chest", + label = "Storage" + }) + end +end + -- [function] Register machine function me.register_machine(itemstring, def) - -- Set after_place_node - local def_afterplace = def.after_place_node - def.after_place_node = function(pos, player) - if def_afterplace then - def_afterplace(pos, player) - end + -- Set after_place_node + local def_afterplace = def.after_place_node + def.after_place_node = function(pos, player) + if def_afterplace then + def_afterplace(pos, player) + end - local meta = minetest.get_meta(pos) - local nodes = me.network.adjacent_connected_nodes(pos) + local meta = minetest.get_meta(pos) + local nodes = me.network.adjacent_connected_nodes(pos) - meta:set_string("infotext", def.description.."\nNo Network") + meta:set_string("infotext", def.description.."\nNo Network") - for _, pos2 in pairs(nodes) do - local id = minetest.get_meta(pos2):get_string("network_id") + for _, pos2 in pairs(nodes) do + local id = minetest.get_meta(pos2):get_string("network_id") - if id ~= "" then - meta:set_string("infotext", def.description.."\nNetwork ID: "..id) - meta:set_string("network_id", id) - end - end + if id ~= "" then + meta:set_string("infotext", def.description.."\nNetwork ID: "..id) + meta:set_string("network_id", id) + end + end - -- Trace Network - --power.trace(pos) + -- Trace Network + --power.trace(pos) - -- Set demand - if def.demand then - me.network_set_demand(pos, def.demand) - end + -- Set demand + if def.demand then + me.network_set_demand(pos, def.demand) + end - if type(def.machine) == "table" then - if power then - power.add_machine(pos, def.machine) - end - end - end - -- Set on_destruct - local def_destruct = def.on_destruct - def.on_destruct = function(pos, player) - if def_destruct then - def_destruct(pos, player) - end + if type(def.machine) == "table" then + if power then + power.add_machine(pos, def.machine) + end + end + end + -- Set on_destruct + local def_destruct = def.on_destruct + def.on_destruct = function(pos, player) + if def_destruct then + def_destruct(pos, player) + end - local meta = minetest.get_meta(pos) + local meta = minetest.get_meta(pos) - if meta:get_string("network_id") ~= "" then - -- Set demand - me.network_set_demand(pos, 0) - -- Remove item from network - me.network_remove(pos) - -- Retrace Network - --power.trace(pos) - end - end - -- Set connects_to - def.connects_to = {"group:me_connect"} - -- Set me_connect group - def.groups = def.groups or {} - def.groups.me_connect = 1 + if meta:get_string("network_id") ~= "" then + -- Set demand + me.network_set_demand(pos, 0) + -- Remove item from network + me.network_remove(pos) + -- Retrace Network + --power.trace(pos) + end + end + -- Set connects_to + def.connects_to = {"group:me_connect"} + -- Set me_connect group + def.groups = def.groups or {} + def.groups.me_connect = 1 - me.register_node(itemstring, def) + me.register_node(itemstring, def) end -- [function] Get machine definition function me.get_def(name, key) - if type(name) == "table" then - local node = me.get_node(name) - if node then - name = node.name - end - end + if type(name) == "table" then + local node = me.get_node(name) + if node then + name = node.name + end + end - local def = minetest.registered_nodes[name] - -- Check name and if registered - if not name or not def then - return - end + local def = minetest.registered_nodes[name] + -- Check name and if registered + if not name or not def then + return + end - if key then - return def[key] - else - return def - end + if key then + return def[key] + else + return def + end end microexpansion.log("Machine Registration API loaded") diff --git a/settingtypes.txt b/settingtypes.txt index c908126..f9fc99f 100644 --- a/settingtypes.txt +++ b/settingtypes.txt @@ -1,2 +1,5 @@ #Stack items in networks higher than their max size. microexpansion_huge_stacks (huge stacks) bool true + +#Enable the "simple" craft recipes that do not require basic_materials even if basic_materials is present. +microexpansion_simple_craft (simple craft recipes) bool false diff --git a/textures/microexpansion_exporter.png b/textures/microexpansion_exporter.png new file mode 100644 index 0000000..16bfcda Binary files /dev/null and b/textures/microexpansion_exporter.png differ diff --git a/textures/microexpansion_gold_wire.png b/textures/microexpansion_gold_wire.png new file mode 100644 index 0000000..8bb14e6 Binary files /dev/null and b/textures/microexpansion_gold_wire.png differ diff --git a/textures/microexpansion_importer.png b/textures/microexpansion_importer.png new file mode 100644 index 0000000..d6069b9 Binary files /dev/null and b/textures/microexpansion_importer.png differ diff --git a/textures/me_interface.png b/textures/microexpansion_interface.png similarity index 100% rename from textures/me_interface.png rename to textures/microexpansion_interface.png diff --git a/textures/microexpansion_logic_chip.png b/textures/microexpansion_logic_chip.png new file mode 100644 index 0000000..651896a Binary files /dev/null and b/textures/microexpansion_logic_chip.png differ diff --git a/textures/microexpansion_ore_supernatet.png b/textures/microexpansion_ore_quartz.png similarity index 100% rename from textures/microexpansion_ore_supernatet.png rename to textures/microexpansion_ore_quartz.png diff --git a/textures/me_quartz_crystal.png b/textures/microexpansion_quartz_crystal.png similarity index 100% rename from textures/me_quartz_crystal.png rename to textures/microexpansion_quartz_crystal.png diff --git a/textures/microexpansion_security_bottom.png b/textures/microexpansion_security_bottom.png new file mode 100644 index 0000000..4694331 Binary files /dev/null and b/textures/microexpansion_security_bottom.png differ diff --git a/textures/microexpansion_security_front.png b/textures/microexpansion_security_front.png new file mode 100644 index 0000000..29449ec Binary files /dev/null and b/textures/microexpansion_security_front.png differ diff --git a/textures/microexpansion_upgrade_base.png b/textures/microexpansion_upgrade_base.png new file mode 100644 index 0000000..42f0c12 Binary files /dev/null and b/textures/microexpansion_upgrade_base.png differ diff --git a/textures/microexpansion_upgrade_bulk.png b/textures/microexpansion_upgrade_bulk.png new file mode 100644 index 0000000..92bdf9e Binary files /dev/null and b/textures/microexpansion_upgrade_bulk.png differ diff --git a/textures/microexpansion_upgrade_control.png b/textures/microexpansion_upgrade_control.png new file mode 100644 index 0000000..8f447c3 Binary files /dev/null and b/textures/microexpansion_upgrade_control.png differ diff --git a/textures/microexpansion_upgrade_filter.png b/textures/microexpansion_upgrade_filter.png new file mode 100644 index 0000000..43d200f Binary files /dev/null and b/textures/microexpansion_upgrade_filter.png differ diff --git a/textures/microexpansion_upgrade_regulation.png b/textures/microexpansion_upgrade_regulation.png new file mode 100644 index 0000000..4fdf0f4 Binary files /dev/null and b/textures/microexpansion_upgrade_regulation.png differ