add limited network functionality

This commit is contained in:
unknown 2022-02-20 19:03:52 -05:00
parent 8267c4d71f
commit aca2f138a8
8 changed files with 467 additions and 6 deletions

View File

@ -25,7 +25,7 @@ computers.sandbox.default_env = {}
os.clock os.difftime os.time
string.byte string.char string.format
string.byte string.char
string.len string.lower string.reverse
string.sub string.upper
@ -130,4 +130,13 @@ function computers.api.chat_send_player(player, msg)
local name = player
if type(name) == "userdata" then name = player:get_player_name() end
minetest.chat_send_player(name, msg)
end
--basically for dev usage only
function computers.api.benchmark(func, ...)
local start_time = minetest.get_us_time()
for i=1, 1000 do
func(...)
end
minetest.chat_send_all(minetest.get_us_time()-start_time)
end

View File

@ -0,0 +1,7 @@
{
"name": "net",
"license": "MIT",
"version": 0.1,
"engine": 0.43,
"help": "configuration related to networking"
}

View File

@ -0,0 +1,64 @@
function net(pos, input, data)
input = input or ""
local lookup = {
list = function(param)
if param == "-ids" then
return table.concat(computers.networks.get_networks_in_area(pos), " ")
elseif not param or param == "" then
return table.concat(computers.networks.get_net_names_in_area(pos), " ")
else
return "invalid sub command"
end
end,
join = function(param)
local id = computers.networks.get_id_by_net_name(data.player, param)
if not id then
return "invalid network name"
elseif minetest.get_meta(pos):get("net_id") then
return "already joined to a network"
else
local _, networks = computers.networks.get_net_names_in_area(pos)
if not networks[param] then return "network not in range" end
minetest.get_meta(pos):set_string("net_id", id)
local status = computers.networks.add_device(id, pos)
if status then return "joined network " .. param else return "network join failed" end
end
end,
leave = function(param)
local id = minetest.get_meta(pos):get("net_id")
if id then
computers.networks.remove_device(id, pos)
return "removed device from network " .. computers.networks.get_net_name(id)
else
return "not currently connected to any network"
end
end,
status = function(param)
local id = minetest.get_meta(pos):get("net_id")
if id then
return "connected to network " .. computers.networks.get_net_name(id)
else
return "not connected to any network"
end
end,
dns = function(param)
if minetest.get_item_group(minetest.get_node(pos).name, "computers_server") == 0 then
return "command only available to servers"
end
if not param or param == "" then return "invalid or missing input" end
if param:match("%W") then return "only alphanumerics allowed" end
local id = minetest.get_meta(pos):get("net_id")
if id then
computers.networks.set_dns(id, pos, param)
return "created dns record"
else
return "not connected to network"
end
end
}
if not lookup[input:split(" ")[1]] then return "invalid sub command" end
return lookup[input:split(" ")[1]](input:split(" ", 1)[2])
end
return net

View File

@ -11,4 +11,211 @@ old_node = minetest.registered_nodes["computers:shefriendSOO_off"]
old_node.groups.not_in_creative_inventory = nil
minetest.override_item("computers:shefriendSOO_off", {
groups = old_node.groups
})
old_node = minetest.registered_nodes["computers:server_on"]
old_node.groups.computers_server = 1
minetest.override_item("computers:server_on", {
on_rightclick = function(pos, node, clicker, itemstack, pointed_thing)
computers.load_gui(pos, node, clicker)
end,
groups = old_node.groups
})
minetest.override_item("computers:router", {
on_rightclick = function(pos, node, clicker, itemstack, pointed_thing)
local formspec = {
formspec_version = 4,
{
type = "size",
w = 10,
h = 5,
},
{
type = "no_prepend"
},
{
type = "bgcolor",
bgcolor = "black",
fullscreen = "neither"
},
{
type = "background9",
x = 0,
y = 0,
w = 10,
h = 5,
texture_name = "kuto_button.png^[combine:16x16^[noalpha^[colorize:#ffffff70",
auto_clip = false,
middle_x = 4,
middle_y = 4,
},
{
type = "hypertext",
name = "label",
x = 0,
y = 0,
w = 10,
h = 2,
text = "<global valign=middle><center><big>Choose Option Below</big></center>",
},
{
type = "button",
x = 0.5,
y = 3.5,
w = 4,
h = 1,
name = "newnetwork_btn",
label = "New Network",
on_event = function(form, player, element, value, fields)
if element.label == "New Network" then
element.label = "Submit"
table.remove(form, computers.formspec.get_index_by_name(form, "existingnetwork_btn"))
form[computers.formspec.get_index_by_name(form, "label")].text = [[
<global valign=middle><center><big>Enter New Network Name</big></center>
]]
table.insert(
form,
{
type = "box",
x = 3,
y = 1.75,
w = 4,
h = 1,
color = "#ffffff"
}
)
table.insert(
form,
{
type = "field",
x = 3,
y = 1.75,
w = 4,
h = 1,
name = "id_field",
close_on_enter = false,
props = {
border = false,
},
}
)
else
if fields.id_field == "" and not computers.formspec.get_index_by_name(form, "warning") then
table.insert(
form,
{
type = "hypertext",
name = "warning",
x = 5.5,
y = 3.5,
w = 4,
h = 1,
text = [[
<global valign=middle>
<center><style color=red>empty or invalid network name</style></center>
]]
}
)
elseif fields.id_field ~= "" then
local status, id = computers.networks.create(player, fields.id_field)
if status then
form = nil
minetest.get_meta(pos):set_string("net_id", id)
computers.networks.add_device(id, pos)
computers.api.chat_send_player(player, "network " .. fields.id_field .. " created")
computers.formspec.close_formspec(player)
elseif not computers.formspec.get_index_by_name(form, "warning") then
table.insert(
form,
{
type = "hypertext",
name = "warning",
x = 5.5,
y = 3.5,
w = 4,
h = 1,
text = [[
<global valign=middle>
<center><style color=red>empty or invalid network name</style></center>
]]
}
)
end
end
end
--minetest.chat_send_all("test")
if form then return form end
end,
props = {
border = false,
bgimg = "kuto_button.png^[combine:16x16^[noalpha^[colorize:#ffffff70",
bgimg_hovered = "kuto_button.png^[combine:16x16^[noalpha^[colorize:#ffffff90",
bgimg_middle = "4,4",
}
},
{
type = "button",
x = 5.5,
y = 3.5,
w = 4,
h = 1,
name = "existingnetwork_btn",
label = "Existing Network",
on_event = function(form, player, element, value, fields)
if element.label == "Existing Network" then
element.label = "Submit"
table.remove(form, computers.formspec.get_index_by_name(form, "newnetwork_btn"))
form[computers.formspec.get_index_by_name(form, "label")].text = [[
<global valign=middle><center>Enter Network</center>
]]
table.insert(
form,
{
type = "box",
x = 3,
y = 1.75,
w = 4,
h = 1,
color = "#ffffff"
}
)
table.insert(
form,
{
type = "field",
x = 3,
y = 1.75,
w = 4,
h = 1,
name = "id_field",
close_on_enter = false,
props = {
border = false,
},
}
)
else
minetest.chat_send_all("submitted")
end
return form
end,
props = {
border = false,
bgimg = "kuto_button.png^[combine:16x16^[noalpha^[colorize:#ffffff70",
bgimg_hovered = "kuto_button.png^[combine:16x16^[noalpha^[colorize:#ffffff90",
bgimg_middle = "4,4",
}
},
}
if minetest.get_meta(pos):get("net_id") then
local net_name = computers.networks.get_net_name(minetest.get_meta(pos):get("net_id"))
computers.api.chat_send_player(clicker, "router attached to network: " .. net_name)
else
computers.formspec.show_formspec(clicker, "computers:router", formspec)
end
end
})

View File

@ -75,6 +75,8 @@ function computers.formspec.convert_to_ast(form)
return fs
end
local forms = {}
function computers.formspec.show_formspec(player, formname, fs)
local playername = player
local formspec = fs
@ -87,11 +89,21 @@ function computers.formspec.show_formspec(player, formname, fs)
formspec = formspec_ast.unparse(computers.formspec.convert_to_ast(fs))
end
forms[formname] = true
minetest.show_formspec(playername, formname, formspec)
end
function computers.formspec.close_formspec(player, formname)
local name = player
if type(name) == "userdata" then name = player:get_player_name() end
minetest.close_formspec(name, formname or "")
end
minetest.register_on_player_receive_fields(function(player, formname, fields)
if formname ~= "computers:gui" then return end
--if formname ~= "computers:gui" then return end
if not forms[formname] then return end
local pname = player:get_player_name()
if fields.quit then computers.formspec.registered_kast[pname] = nil return end
@ -117,7 +129,7 @@ minetest.register_on_player_receive_fields(function(player, formname, fields)
btn_override or keys[1]
)
--minetest.chat_send_all(keys[1])
--minetest.chat_send_all(btn_override or keys[1])
--minetest.chat_send_all(fields[keys[1]])
if element and element.on_event then

View File

@ -243,8 +243,17 @@ function computers.gui.load(pos, node, clicker)
border = false,
},
on_event = function(form, player, element, value, fields)
--minetest.chat_send_all("url entered")
computers.api.chat_send_player(player, "[computers]: networking not currently supported")
local id = minetest.get_meta(pos):get("net_id")
if id then
local status, data = computers.networks.resolve_url(id, pos, value)
if status and data then
local cindex = futil.get_index_by_name(form, "browser_ctn")
local eindex = futil.get_index_by_name(form[cindex], "browser_content")
form[cindex][eindex].text = data
end
else
computers.api.chat_send_player(player, "[computers]: not attached to a network")
end
return form
end,

View File

@ -8,7 +8,7 @@ minetest.mkdir(computers.devicepath) --make sure it exists
minetest.mkdir(computers.networkpath) --make sure it exists
computers.os = {
version = 0.42,
version = 0.43,
name = "kuto",
authors = {"wsor", "luk3yx"},
license = "MIT",
@ -17,6 +17,7 @@ computers.os = {
dofile(computers.modpath .. "/old_stuff/init.lua")
dofile(computers.modpath .. "/api.lua")
dofile(computers.modpath .. "/networks.lua")
dofile(computers.modpath .. "/formspec.lua")
dofile(computers.modpath .. "/commands.lua")
dofile(computers.modpath .. "/gui.lua")

152
computers/networks.lua Normal file
View File

@ -0,0 +1,152 @@
local networks = {}
local network_lookup = {}
computers.networks = {}
local function init_networks()
local path = computers.networkpath
local files = minetest.get_dir_list(computers.networkpath, false)
for _, file in pairs(files) do
local id = file:sub(1,-6)
local f = io.open(path .. "/" .. file)
networks[id] = minetest.parse_json(f:read("*all"))
f:close()
if not network_lookup[networks[id].pname] then network_lookup[networks[id].pname] = {} end
network_lookup[networks[id].pname][networks[id].net_name] = id
end
end
init_networks()
local function update_file(id)
local data = networks[id]
local path = computers.networkpath .. "/" .. id .. ".json"
minetest.safe_file_write(path, minetest.write_json(data))
end
function computers.networks.create(player, net_name)
local pname = player
if type(player) == "userdata" then pname = player:get_player_name() end
local id = pname .. "_" .. minetest.get_us_time()
if net_name:match("%W") then return false end --pnly accept alphanumerics
if not network_lookup[pname] then network_lookup[pname] = {} end
if network_lookup[pname][net_name] then return false end
if networks[id] then return false end
--create storage on disk
local path = computers.networkpath .. "/" .. id .. ".json"
local data = {
pname = pname,
net_name = net_name,
devices = {},
dns = {
}
}
minetest.safe_file_write(path, minetest.write_json(data))
--store data in memory
networks[id] = data
network_lookup[pname][net_name] = id
return true, id
end
function computers.networks.verify_network(id)
if networks[id] then return true else return false end
end
function computers.networks.get_net_name(id)
return networks[id].net_name
end
function computers.networks.get_network_devices(id)
return table.copy(networks[id].devices)
end
function computers.networks.get_network_dns(id)
return table.copy(networks[id].dns)
end
function computers.networks.get_id_by_net_name(player, net_name)
local pname = player
if type(player) == "userdata" then pname = player:get_player_name() end
if not network_lookup[pname] then network_lookup[pname] = {} end
return network_lookup[pname][net_name]
end
function computers.networks.get_networks_in_area(pos, rad)
rad = rad or 10
local locations = {}
local keyed_locations = {}
local meta_nodes = minetest.find_nodes_with_meta(
vector.new(pos.x+rad, pos.y+rad, pos.z+rad),
vector.new(pos.x-rad, pos.y-rad, pos.z-rad)
)
for _, location in pairs(meta_nodes) do
local status = minetest.get_meta(location):get("net_id")
if status and networks[status] then
table.insert(locations, status)
keyed_locations[status] = true
end
end
return locations, keyed_locations
end
function computers.networks.get_net_names_in_area(pos, rad)
rad = rad or 10
local locations = {}
local keyed_locations = {}
local meta_nodes = minetest.find_nodes_with_meta(
vector.new(pos.x+rad, pos.y+rad, pos.z+rad),
vector.new(pos.x-rad, pos.y-rad, pos.z-rad)
)
for _, location in pairs(meta_nodes) do
local status = minetest.get_meta(location):get("net_id")
if status and networks[status] and not keyed_locations[networks[status].net_name] then
table.insert(locations, networks[status].net_name)
keyed_locations[networks[status].net_name] = true
end
end
return locations, keyed_locations
end
function computers.networks.add_device(id, pos)
if type(pos) ~= "table" or not networks[id] then return false end
networks[id].devices[minetest.pos_to_string(pos)] = minetest.get_node(pos).name
minetest.get_meta(pos):set_string("net_id", id)
update_file(id)
return true
end
function computers.networks.remove_device(id, pos)
if type(pos) ~= "table" or not networks[id] then return false end
networks[id].devices[minetest.pos_to_string(pos)] = nil
minetest.get_meta(pos):set_string("net_id", "")
update_file(id)
return true
end
function computers.networks.set_dns(id, pos, url)
if type(pos) ~= "table" or not networks[id] then return false end
if url:match("%W") then return false end
networks[id].dns = networks[id].dns or {}
networks[id].dns[url] = minetest.hash_node_position(pos) .. "/public_pages"
update_file(id)
return true
end
function computers.networks.resolve_url(id, pos, url)
if type(pos) ~= "table" or not networks[id] then return false end
if networks[id].dns[url:split("/")[1]] then
local path = computers.devicepath .. "/" .. networks[id].dns[url:split("/")[1]].."/index.page"
local f = io.open(path)
if not f then return false end
local data = f:read("*all")
f:close()
if data then return true, data else return false end
else
return false
end
end