- authlevel to set levels of access player has in robot sandbox (0 = ordinary, 1 = robot, 2 = puzzle, 3 = admin)

- authlevel is stored in metadata of robot and digitally signed using server private password to prevent abuses
- minor bugfixes
- new giver and checker blocks for puzzle, can create locks and keys now
This commit is contained in:
rnd1 2017-12-18 11:19:05 +01:00
parent 046bcc445a
commit 8a8d22416d
5 changed files with 82 additions and 48 deletions

View File

@ -49,7 +49,7 @@ local function pos_in_dir(obj, dir) -- position after we move in specified direc
elseif dir == 13 then -- forward_up
pos.y=pos.y+1
elseif dir == 14 then -- backward_up
yaw = yaw + pi; pos.y=pos.y-1
yaw = yaw + pi; pos.y=pos.y+1
end
if dir ~= 5 and dir ~= 6 then
@ -571,7 +571,7 @@ local register_robot_button = function(R,G,B,type)
on_punch = function(pos, node, player)
local name = player:get_player_name(); if name==nil then return end
local round = math.floor;
local r = 32; local ry = 2*r; -- note: this is skyblock adjusted
local r = basic_robot.radius; local ry = 2*r; -- note: this is skyblock adjusted
local ppos = {x=round(pos.x/r+0.5)*r,y=round(pos.y/ry+0.5)*ry+1,z=round(pos.z/r+0.5)*r}; -- just on top of basic_protect:protector!
local meta = minetest.get_meta(ppos);
local name = meta:get_string("name");
@ -595,7 +595,7 @@ minetest.register_node("basic_robot:button"..number,
on_punch = function(pos, node, player)
local name = player:get_player_name(); if name==nil then return end
local round = math.floor;
local r = 32; local ry = 2*r;
local r = basic_robot.radius; local ry = 2*r;
local ppos = {x=round(pos.x/r+0.5)*r,y=round(pos.y/ry+0.5)*ry+1,z=round(pos.z/r+0.5)*r};
local meta = minetest.get_meta(ppos);
local name = meta:get_string("name");
@ -618,7 +618,7 @@ minetest.register_node("basic_robot:button_"..number,
on_punch = function(pos, node, player)
local name = player:get_player_name(); if name==nil then return end
local round = math.floor;
local r = 32; local ry = 2*r;
local r = basic_robot.radius; local ry = 2*r;
local ppos = {x=round(pos.x/r+0.5)*r,y=round(pos.y/ry+0.5)*ry+1,z=round(pos.z/r+0.5)*r};
local meta = minetest.get_meta(ppos);
local name = meta:get_string("name");
@ -640,7 +640,7 @@ minetest.register_node("basic_robot:button_"..number,
on_punch = function(pos, node, player)
local name = player:get_player_name(); if name==nil then return end
local round = math.floor;
local r = 32; local ry = 2*r;
local r = basic_robot.radius; local ry = 2*r;
local ppos = {x=round(pos.x/r+0.5)*r,y=round(pos.y/ry+0.5)*ry+1,z=round(pos.z/r+0.5)*r};
local meta = minetest.get_meta(ppos);
local name = meta:get_string("name");
@ -675,6 +675,9 @@ register_robot_button_custom(281,"puzzle_NOT")
register_robot_button_custom(282,"puzzle_delayer")
register_robot_button_custom(283,"puzzle_platform")
register_robot_button_custom(284,"puzzle_giver")
register_robot_button_custom(285,"puzzle_checker")
-- interactive button for robot: place robot on top of protector to intercept events
@ -1184,7 +1187,7 @@ basic_robot.commands.crypto = {encrypt = encrypt, decrypt = decrypt, scramble =
local is_same_block = function(pos1,pos2)
local round = math.floor;
local r = 32; local ry = 2*r; -- note: this is skyblock adjusted
local r = basic_robot.radius; local ry = 2*r; -- note: this is skyblock adjusted
local ppos1 = {round(pos1.x/r+0.5)*r,round(pos1.y/ry+0.5)*ry,round(pos1.z/r+0.5)*r};
local ppos2 = {round(pos2.x/r+0.5)*r,round(pos2.y/ry+0.5)*ry,round(pos2.z/r+0.5)*r};
return ppos1[1]==ppos2[1] and ppos1[2]==ppos2[2] and ppos1[3] == ppos2[3]

111
init.lua
View File

@ -6,9 +6,10 @@ basic_robot = {};
basic_robot.call_limit = 48; -- how many execution calls per script run allowed
basic_robot.entry_count = 2 -- how many robot ordinary player can have
basic_robot.advanced_count = 16 -- how many robots player with robot privs can have
basic_robot.radius = 32; -- divide whole world into blocks of this size - used for managing events like keyboard punches
basic_robot.password = "robot passw0rd"; -- IMPORTANT: change it before running mod, server private password used for authentifications
basic_robot.bad_inventory_blocks = { -- disallow taking from these nodes inventories
basic_robot.bad_inventory_blocks = { -- disallow taking from these nodes inventories to prevent player abuses
["craft_guide:sign_wall"] = true,
}
basic_robot.maxoperations = 2; -- how many operations (dig, generate energy,..) available per run, 0 = unlimited
@ -17,14 +18,14 @@ basic_robot.dig_require_energy = true; -- does robot require energy to dig?
basic_robot.http_api = minetest.request_http_api();
basic_robot.version = "2017/10 /07a";
basic_robot.version = "2017/12/18a";
basic_robot.data = {}; -- stores all robot data
--[[
[name] = { sandbox= .., bytecode = ..., ram = ..., obj = robot object,spawnpos=...}
robot object = object of entity, used to manipulate movements and more
--]]
basic_robot.ids = {}; -- stores maxid for all players
basic_robot.ids = {}; -- stores maxid for each player
--[name] = {id = .., maxid = .. }, current id, how many robot ids player can use
basic_robot.data.listening = {}; -- which robots listen to chat
@ -38,6 +39,8 @@ local check_code, preprocess_code,is_inside_string;
function getSandboxEnv (name)
local authlevel = basic_robot.data[name].authlevel or 0;
local commands = basic_robot.commands;
local directions = {left = 1, right = 2, forward = 3, backward = 4, up = 5, down = 6,
left_down = 7, right_down = 8, forward_down = 9, backward_down = 10,
@ -114,17 +117,6 @@ function getSandboxEnv (name)
return sender,mail
end,
read_form = function()
local fields = basic_robot.data[name].read_form;
local sender = basic_robot.data[name].form_sender;
basic_robot.data[name].read_form = nil;
basic_robot.data[name].form_sender = nil;
return sender,fields
end,
show_form = function(playername, form)
commands.show_form(name, playername, form)
end,
send_mail = function(target,mail)
if not basic_robot.data[target] then return false end
@ -328,7 +320,7 @@ function getSandboxEnv (name)
write = function(i,title,text)
if i<=0 or i > 32 then return nil end
local inv = minetest.get_meta(basic_robot.data[name].spawnpos):get_inventory();
local stack = basic_robot.commands.write_book(name,title,text);
local stack = basic_robot.commands.write_book(basic_robot.data[name].owner,title,text);
if stack then inv:set_stack("library", i, stack) end
end
},
@ -346,7 +338,7 @@ function getSandboxEnv (name)
end,
run = function(script)
if basic_robot.data[name].isadmin ~= 1 then
if basic_robot.data[name].authlevel < 3 then
local err = check_code(script);
script = preprocess_code(script);
if err then
@ -485,10 +477,23 @@ function getSandboxEnv (name)
env.write_text[dir] = function(text) return commands.write_text(name, dir_id,text) end
end
-- set up sandbox for puzzle
if authlevel>=1 then -- robot privs
env.self.read_form = function()
local fields = basic_robot.data[name].read_form;
local sender = basic_robot.data[name].form_sender;
basic_robot.data[name].read_form = nil;
basic_robot.data[name].form_sender = nil;
return sender,fields
end
env.self.show_form = function(playername, form)
commands.show_form(name, playername, form)
end
end
local ispuzzle = basic_robot.data[name].ispuzzle; -- need puzzle privs
if ispuzzle == 1 then
-- set up sandbox for puzzle
if authlevel>=2 then -- puzzle privs
basic_robot.data[name].puzzle = {};
local data = basic_robot.data[name];
local pdata = data.puzzle;
@ -516,13 +521,13 @@ function getSandboxEnv (name)
pdata = pdata,
ItemStack = ItemStack,
}
end
--special sandbox for admin
local isadmin=basic_robot.data[name].isadmin
if isadmin~=1 then
if authlevel<3 then -- is admin?
env._G = env;
else
env.minetest = minetest;
@ -675,7 +680,7 @@ end
local function setCode( name, script ) -- to run script: 1. initSandbox 2. setCode 3. runSandbox
local err;
if basic_robot.data[name].isadmin~=1 then
if basic_robot.data[name].authlevel<3 then -- not admin
err = check_code(script);
script = preprocess_code(script);
end
@ -806,9 +811,7 @@ local function init_robot(obj)
basic_robot.data[name].quiet_mode = false; -- can chat globally
-- check if admin robot
if self.isadmin then basic_robot.data[name].isadmin = 1 end
-- can we do puzzles?
if self.ispuzzle then basic_robot.data[name].ispuzzle = 1 end
basic_robot.data[name].authlevel = self.authlevel or 0
--robot appearance,armor...
obj:set_properties({infotext = "robot " .. name});
@ -856,6 +859,8 @@ minetest.register_entity("basic_robot:robot",{
end
self.owner = data.owner;
self.authlevel = data.authlevel;
self.spawnpos = {x=data.spawnpos.x,y=data.spawnpos.y,z=data.spawnpos.z};
init_robot(self.object);
self.running = 1;
@ -985,7 +990,13 @@ local spawn_robot = function(pos,node,ttl)
basic_robot.data[name] = {}; data = basic_robot.data[name];
meta:set_string("infotext",minetest.get_gametime().. " code changed ")
data.owner = owner;
if meta:get_int("admin") == 1 then data.isadmin = 1 end
data.authlevel = meta:get_int("authlevel")
local sec_hash = minetest.get_password_hash("",data.authlevel.. owner .. basic_robot.password)
if meta:get_string("sec_hash")~= sec_hash then
minetest.chat_send_all("#ROBOT: " .. name .. " is using fake auth level. dig and place again.")
return
end
if not data.obj then
--create virtual robot that reports position and other properties
@ -1007,8 +1018,8 @@ local spawn_robot = function(pos,node,ttl)
if not data.bytecode then
local script = meta:get_string("code");
if data.isadmin~=1 then
if data.authlevel<3 then -- not admin
err = check_code(script);
script = preprocess_code(script);
end
@ -1059,8 +1070,14 @@ local spawn_robot = function(pos,node,ttl)
luaent.name = name;
luaent.code = meta:get_string("code");
luaent.spawnpos = {x=pos.x,y=pos.y-1,z=pos.z};
if meta:get_int("admin") == 1 then luaent.isadmin = 1 end
if meta:get_int("puzzle") == 1 then luaent.ispuzzle = 1 end
luaent.authlevel = meta:get_int("authlevel")
local sec_hash = minetest.get_password_hash("",luaent.authlevel.. owner .. basic_robot.password)
if meta:get_string("sec_hash")~= sec_hash then
minetest.chat_send_all("#ROBOT: " .. name .. " is using fake auth level. dig and place again.")
obj:remove();
return
end
local data = basic_robot.data[name];
if data == nil then
@ -1720,10 +1737,24 @@ minetest.register_node("basic_robot:spawner", {
alpha = 150,
after_place_node = function(pos, placer)
local meta = minetest.env:get_meta(pos)
meta:set_string("owner", placer:get_player_name());
local owner = placer:get_player_name();
meta:set_string("owner", owner);
local privs = minetest.get_player_privs(placer:get_player_name());
if privs.privs then meta:set_int("admin",1) end
if privs.puzzle then meta:set_int("puzzle",1) end
local authlevel = 0;
if privs.privs then -- set auth level depending on privs
authlevel = 3
elseif privs.puzzle then
authlevel = 2
elseif privs.robot then
authlevel = 1
else
authlevel = 0
end
meta:set_int("authlevel",authlevel)
local sec_hash = minetest.get_password_hash("",authlevel .. owner .. basic_robot.password) -- 'digitally sign' authlevel using password
meta:set_string("sec_hash", sec_hash);
meta:set_string("code","");
meta:set_int("id",1); -- initial robot id
@ -1827,9 +1858,9 @@ minetest.register_craftitem("basic_robot:control", {
local owner = user:get_player_name();
local script = itemstack:get_metadata();
if script == "@" then -- remote control as a tool - notify robot in current block of pointed position
if script == "@" then -- remote control as a tool - notify robot in current block of pointed position, using keyboard event type 0
local round = math.floor;
local r = 32; local ry = 2*r; -- note: this is skyblock adjusted
local r = basic_robot.radius; local ry = 2*r; -- note: this is skyblock adjusted
local pos = pointed_thing.under
if not pos then return end
local ppos = {x=round(pos.x/r+0.5)*r,y=round(pos.y/ry+0.5)*ry+1,z=round(pos.z/r+0.5)*r}; -- just on top of basic_protect:protector!
@ -1850,7 +1881,7 @@ minetest.register_craftitem("basic_robot:control", {
if data and data.sandbox then
else
minetest.chat_send_player(name, "#remote control: your robot must be running");
minetest.chat_send_player(owner, "#remote control: your robot must be running");
return
end
@ -1859,7 +1890,7 @@ minetest.register_craftitem("basic_robot:control", {
if t1-t0<1 then return end
data.remoteuse = t1;
if data.isadmin == 1 then
if data.authlevel >= 3 then
local privs = minetest.get_player_privs(owner); -- only admin can run admin robot
if not privs.privs then
return
@ -1872,7 +1903,7 @@ minetest.register_craftitem("basic_robot:control", {
return
end
if not data.isadmin then
if data.authlevel<3 then
if check_code(script)~=nil then return end
end

View File

@ -1,7 +1,7 @@
-- SOKOBAN GAME, by rnd, robots port
if not sokoban then
sokoban = {};
local players = find_player(4);
local players = find_player(5);
if not players then error("sokoban: no player near") end
name = players[1];
@ -37,7 +37,7 @@
if lvl == nil then return end
if lvl <0 or lvl >89 then return end
local file = _G.io.open(minetest.get_modpath("basic_robot").."/scripts/sokoban.txt","r")
local file = _G.io.open(minetest.get_modpath("basic_robot").."\\scripts\\sokoban.txt","r")
if not file then return end
local str = ""; local s; local p = {x=pos.x,y=pos.y,z=pos.z}; local i,j;i=0;
local lvl_found = false

BIN
textures/puzzle_checker.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 732 B

BIN
textures/puzzle_giver.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 762 B