This commit is contained in:
theFox6 2024-01-24 11:06:44 +01:00
commit 593d477583
44 changed files with 2069 additions and 496 deletions

@ -5,6 +5,7 @@ read_globals = {
"dump",
"ItemStack",
"pipeworks",
"unified_inventory",
"PseudoRandom",
"stairsplus",
"intllib",

49
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

@ -1,2 +1,3 @@
default
pipeworks?
basic_materials?

@ -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

@ -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

@ -1,5 +1,6 @@
shared = true
network = true
power = false
storage = true
ores = true
item_transfer = true
crafting = true

@ -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"}
},
},
},
})

@ -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")

@ -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,
})

@ -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,
})

@ -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

@ -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

@ -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

@ -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")

@ -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"}
},
},
},
})

@ -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
}

@ -2,8 +2,18 @@
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", {
@ -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

@ -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

@ -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")

@ -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 == "<new>" 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, "<new>"))
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,
})

@ -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)

@ -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,
},
})]]

@ -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 ----

@ -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"},
},
},
},
})

@ -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
]]

@ -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

@ -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"}}
},
})

@ -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

@ -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")

@ -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

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.7 KiB

Before

Width:  |  Height:  |  Size: 213 B

After

Width:  |  Height:  |  Size: 213 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.0 KiB

Before

Width:  |  Height:  |  Size: 309 B

After

Width:  |  Height:  |  Size: 309 B

Before

Width:  |  Height:  |  Size: 303 B

After

Width:  |  Height:  |  Size: 303 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.8 KiB