Added wireless digilines and added attacked_node group to pressure plates

master
bas080 2013-08-20 01:20:35 +02:00
parent a54d64f317
commit 422075e6e5
7 changed files with 316 additions and 1 deletions

View File

@ -0,0 +1,36 @@
This is digiterm: a [Minetest](http://minetest.net/) mod that provides a couple terminal nodes for providing user interface in [Digilines](https://forum.minetest.net/viewtopic.php?id=5263) networks.
The first of two nodes that this mod provides is a regular digiterm. To use it, simply place it down and right-click it to set the channel that it will operate on. After setup, you'll see two boxes and two buttons. Any messages on the digiline network sent on the channel that this digiterm is set to will show up in the large box, and messages can be sent out to the digiline network by typing them in to the bottom box and pressing the 'submit' button. The 'update' button is necessary because there is no way of automatically updating formspecs without clobbering any in-progress input; pressing it will submit the form and then re-display with updated output and the current (now saved) input. Normal digiterms send and receive their messages as simple strings, do not append newlines automatically on either end of transmission, and store their state on a per-node basis. One can also issue control codes as a table containing a 'code' key; the only one supported thus far is `{code='cls'}` which clears the output area.
As an example, a simple chat machine can be constructed using two digiterms set to the channels `term1` and `term2` and one luacontroller with the following code:
```lua
if event.type == 'digiline' then
if event.channel == 'term1' then digiline_send('term2', event.msg..'\n');
elseif event.channel == 'term2' then digiline_send('term1', event.msg..'\n');
end
end
```
The second node defined by this mod is the secure digiterm. Secure digiterms appear almost exactly the same as their "unsecure" counterparts, but their inner workings are almost entirely different. Secure digiterms manage each user's session on a given node separately, so leftover information from one user will not be visible to another user that logs on after them, and two people can use one secure digiterm simultaneously. Instead of sending messages as plain strings, secure digiterms submit user information in the form of a function that returns a table such as `{player="", seq=0, msg=""}`, where 'player' is a string containing the name of the player sending the message, 'msg' is a string containing the actual message, and 'seq' is a unique integer that is incremented with each message. Secure digiterms will also notify the digiline network when a player starts a session by sending a message in the form of a function returning something like `{player="", seq=0, code='init'}` where 'player' and 'seq' have the same meanings as above and 'code' is always 'init' (to catch responses to this, one will have to press 'update' after opening the terminal). Secure digiterms also take their input in the form of plain strings (in which case messages are routed to the last seen player's session), but, if you want to make sure that you're message gets across, you can send it as a table of the form `{player="", msg=""}`, where 'player' is the name of the intended recipient and 'msg' is the message you wish to send them. Secure digiterms also take control codes; these are tables that look like `{player="", code=""}`, where 'player' is the name of recipient and 'code' is one of the same control codes used by regular digiterms (still only 'cls' at the moment).
What makes secure digiterms secure is their leverage of the fact that luacontrollers cannot define functions. A server receiving messages from a secure digiterm can know that they're authentic because they cannot be forged by an imposter luacontroller (as they cannot define functions) and that they haven't been tampered with since functions are opaque and immutable. Would-be cyber-griefers can store function messages sent across the network and redeploy them later (to a certain extent; functions are impossible to serialize), but they can't increment the 'seq' member, thus well-written servers will be able to easily filter out the re-used messages.
As a demonstration of secure digiterms, if the following code is loaded onto a luacontroller connected to a secure digiterm set to the 'term' channel, it will show users a welcome message and then echo everything that they enter back to them, with their name and sequence number:
```lua
if event.type == 'digiline' and event.channel == 'term' then
local msg = event.msg();
local seq = mem[msg.player..'_seq'];
if seq and seq >= msg.seq then return end
mem[msg.player..'_seq'] = msg.seq;
if msg.code == 'init' then
digiline_send('term', {player=msg.player, code='cls'});
digiline_send('term', {player=msg.player, msg='Hello, '..msg.player..'; welcome to the digiterm demonstration!\n'});
else
digiline_send('term', {player=msg.player, msg='<'..msg.player..'('..tostring(msg.seq)..')> '..msg.msg..'\n'});
end
end
```
This mod is released under the same licensing as the digilines mod (LGPL/WTFPL).

View File

@ -0,0 +1 @@
digilines

View File

@ -0,0 +1,278 @@
--a function for producing a digiterm form with specified output and input
local function digiterm_formspec(output, input)
return 'size[10,11] textarea[.25,.25;10,10.5;output;;'..output..'] button[0,9.5;10,1;update;update] field[.25,10.75;9,1;input;;'..input..'] button[9,10.5;1,1;submit;submit]'
end
--extremely hacky
--but neccessary since there doesn't seem to be any better way to refresh a formspec
local function hacky_quote_new_digiterm_formspec(startspace)
return (startspace and ' ' or '')..digiterm_formspec('${output}', '${input}');
end
--a basic digiterm!
minetest.register_node('digiterm:digiterm', {
description = 'digiterm',
--set graphics
tiles = {'digiterm_side.png', 'digiterm_side.png', 'digiterm_side.png', 'digiterm_side.png', 'digiterm_side.png', 'digiterm_front.png'},
paramtype2 = 'facedir',
--it's kind of stone-like
groups = {cracky = 2},
sounds = default.node_sound_stone_defaults(),
--digiline stuff (mostly based on other digiline things as suggested)
digiline = {
receptor = {},
effector = {
action = function(pos, node, channel, msg)
local meta = minetest.get_meta(pos);
--ignore anything that isn't our channel
if channel ~= meta:get_string('channel') then return end
--if it's a string, append to the end of our output string
if type(msg) == 'string' then meta:set_string('output', meta:get_string('output')..msg);
--it may also be a control code; check if it's a table with a 'code' member
elseif type(msg) == 'table' and msg.code then
--the code 'cls' clears out the output
if msg.code == 'cls' then meta:set_string('output', ''); end
end
end
},
},
on_construct = function(pos)
local meta = minetest.get_meta(pos);
--initialize the input and output buffers
meta:set_string('output', '');
meta:set_string('input', '');
--set an initial formspec for specifying the channel
meta:set_string('formspec', 'field[channel;channel;${channel}]');
--start on an empty channel
meta:set_string('channel', '');
end,
on_receive_fields = function(pos, formname, fields, sender)
local meta = minetest.get_meta(pos);
--are we to set the channel?
if fields.channel then
--if so, set it
meta:set_string('channel', fields.channel);
--replace with the operating formspec
meta:set_string('formspec', hacky_quote_new_digiterm_formspec(false));
--and disregard the rest of this callback
return;
end
--has the user touched the submit button?
if fields.submit then
--if so, submit and reset the input field
digiline:receptor_send(pos, digiline.rules.default, meta:get_string('channel'), fields.input);
meta:set_string('input', '');
else
--otherwise, update the input so that it doesn't change
meta:set_string('input', fields.input);
end
--refresh the formspec hackishly
meta:set_string('formspec', hacky_quote_new_digiterm_formspec(meta:get_string('formspec'):sub(0, 1) ~= ' '));
end,
});
--add a craft recipe for digiterms
minetest.register_craft({
output = 'digiterm:digiterm',
recipe = {
{'default:glass', 'default:glass', 'default:glass'},
{'digilines:wire_std_00000000', 'mesecons_luacontroller:luacontroller0000', 'digilines:wire_std_00000000'},
{'default:stone', 'default:steel_ingot', 'default:stone'},
},
});
--creation and usage of node positions encoded into formspec names
local function make_secure_digiterm_formspec_name(pos)
return 'digitermspec{x='..tostring(pos.x)..',y='..tostring(pos.y)..',z='..tostring(pos.z)..'}';
end
local function retrieve_secure_digiterm_pos(formname)
--try to pull the vector out of the form name
local possstr;
posstr = formname:match('^digitermspec({x=%-?%d*%.?%d*,y=%-?%d*%.?%d*,z=%-?%d*%.?%d*})$');
--if we didn't get one, give up
if not posstr then return; end
--otherwise, grab the position
return loadstring('return '..posstr)();
end
--a secure digiterm!
minetest.register_node('digiterm:digiterm_secure', {
description = 'secure digiterm',
--set graphics
tiles = {'digiterm_side.png', 'digiterm_side.png', 'digiterm_side.png', 'digiterm_side.png', 'digiterm_side.png', 'digiterm_secure_front.png'},
paramtype2 = 'facedir',
--it's kind of stone-like
groups = {cracky = 2},
sounds = default.node_sound_stone_defaults(),
--digiline stuff (mostly based on other digiline things as suggested)
digiline = {
receptor = {},
effector = {
action = function(pos, node, channel, msg)
local meta = minetest.get_meta(pos);
--ignore anything that isn't our channel
if channel ~= meta:get_string('channel') then return end
--try to find some id
local player;
if type(msg) == 'table' and msg.player then
--attempt to grab the player name if it's a string
player = msg.player == 'string' and msg.player;
--if the id is passed correctly and the field msg exists, than that's the actual msg
msg = msg.msg or msg;
end
--otherwise, assume the last encountered player is the target of the message
if not player then player = meta:get_string('last_player'); end
--if there is no such player, give up
if not player then return; end
--if the player in question doesn't have a session here, give up
if not meta:get_int(player..'_seq') then return; end
--for strings, append at the end of the player's output
if type(msg) == 'string' then meta:set_string(player..'_output', meta:get_string(player..'_output')..msg);
--handle control codes too
elseif type(msg) == 'table' and msg.code then
--the code 'cls' clears out the output
if msg.code == 'cls' then meta:set_string(player..'_output', ''); end
end
end
},
},
on_construct = function(pos)
local meta = minetest.get_meta(pos);
--set an initial formspec for specifying the channel
meta:set_string('formspec', 'field[channel;channel;${channel}]');
--start on an empty channel
meta:set_string('channel', '');
end,
on_receive_fields = function(pos, formname, fields, sender)
local meta = minetest.get_meta(pos);
--are we to set the channel?
if fields.channel then
--if so, set it
meta:set_string('channel', fields.channel);
--and dump the formspec
meta:set_string('formspec', '');
end
end,
on_rightclick = function(pos, node, player, itemstack)
local meta = minetest.get_meta(pos);
--grab the player's name
local name = player:get_player_name();
--log this person as the last visitor
meta:set_string('last_player', name);
--grab the input, output, and current message sequence number for this player
local output, input, seq = meta:get_string(name..'_output'), meta:get_string(name..'_input'), meta:get_int(name..'_seq');
--if any are nil, re-initialize all
if not output or not input or not seq then
output, input, seq = '', '', 0;
meta:set_string(name..'_output', output);
meta:set_string(name..'_input', input);
meta:set_int(name..'_seq', seq);
end
--send a message to let the network so that it can send a greeting
digiline:receptor_send(pos, digiline.rules.default, meta:get_string('channel'), function() return {player=name, seq=seq, code='init'} end);
--bump the sequence number
meta:set_int(name..'_seq', seq + 1);
--show them the formspec
minetest.show_formspec(name, make_secure_digiterm_formspec_name(pos), digiterm_formspec(output, input));
--we don't need to do anything with itemstack
return itemstack;
end,
});
--we need to register something to pick up our formspec submissions
minetest.register_on_player_receive_fields(function (player, formname, fields)
--we shall attempt to obtain the node coordinates from the formname
local pos = retrieve_secure_digiterm_pos(formname);
--if that failed, then we pass execution on
if not pos then return false; end
--otherwise, grab some metadata and the player name
local meta = minetest.get_meta(pos);
local name = player:get_player_name();
--has the user touched the submit button?
if fields.submit then
--if so, submit and reset the input field
local seq = meta:get_int(name..'_seq');
digiline:receptor_send(pos, digiline.rules.default, meta:get_string('channel'), function() return {player=name, seq=seq, msg=fields.input} end);
meta:set_string(name..'_input', '');
--and bump the sequence number
meta:set_int(name..'_seq', seq + 1);
else
--otherwise, update the input so that it doesn't change
meta:set_string(name..'_input', fields.input);
end
--re-show the formspec
minetest.show_formspec(name, make_secure_digiterm_formspec_name(pos), digiterm_formspec(meta:get_string(name..'_output'), meta:get_string(name..'_input')));
end);
--add a craft recipe for the secure variant
minetest.register_craft({
output = 'digiterm:digiterm_secure',
recipe = {
{'', 'default:steel_ingot', ''},
{'default:steel_ingot', 'digiterm:digiterm', 'default:steel_ingot'},
{'', 'default:steel_ingot', ''},
},
});

Binary file not shown.

After

Width:  |  Height:  |  Size: 181 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 186 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 159 B

View File

@ -63,7 +63,7 @@ function mesecon:register_pressure_plate(offstate, onstate, description, texture
paramtype = "light",
selection_box = pp_box_off,
node_box = pp_box_off,
groups = {snappy = 2, oddly_breakable_by_hand = 3},
groups = {snappy = 2, oddly_breakable_by_hand = 3, attached_node=1},
description = description,
pressureplate = ppspec,
on_timer = pp_on_timer,