tweaked operation costs
redo of code preprocessing
This commit is contained in:
parent
db15170554
commit
21158c67eb
@ -19,3 +19,11 @@ GNU General Public License for more details.
|
|||||||
You should have received a copy of the GNU General Public License
|
You should have received a copy of the GNU General Public License
|
||||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
----------------------------------------------------------------------
|
----------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
GAMEPLAY:
|
||||||
|
|
||||||
|
- robot has limited operations available every run ( 1 run per 1 second).
|
||||||
|
- while using for loops, while loops or function calls it is limited to default 48 such code executions per run
|
||||||
|
- while using 'physical' operations like move/dig robot has (default) 10 operations available per run. Default costs are
|
||||||
|
move=2, dig = 6, insert = 2, place = 2, machine.generate = 6, machine.smelt = 6, machine.grind = 6,
|
27
commands.lua
27
commands.lua
@ -115,7 +115,7 @@ end
|
|||||||
|
|
||||||
basic_robot.digcosts = { -- 1 energy = 1 coal
|
basic_robot.digcosts = { -- 1 energy = 1 coal
|
||||||
["default:stone"] = 1/25,
|
["default:stone"] = 1/25,
|
||||||
|
["default:cloud"] = 10^8,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -433,9 +433,18 @@ basic_robot.commands.grab = function(name,target)
|
|||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--local minetest_version = minetest.get_version().string;
|
||||||
basic_robot.commands.read_book = function (itemstack) -- itemstack should contain book
|
basic_robot.commands.read_book = function (itemstack) -- itemstack should contain book
|
||||||
local data = itemstack:get_meta():to_table().fields -- 0.4.16
|
local data;
|
||||||
--local data = minetest.deserialize(itemstack:get_metadata()) -- pre 0.4.16
|
--if minetest_version == "0.4.16" then
|
||||||
|
data = itemstack:get_meta():to_table().fields -- 0.4.16
|
||||||
|
if data and data.text then
|
||||||
|
data.text = data.text:gsub(string.char(13),string.char(10)) --for unknown reason books sometime? convert \n (10) to CR (13)
|
||||||
|
end
|
||||||
|
-- else
|
||||||
|
-- local data = minetest.deserialize(itemstack:get_metadata()) -- pre 0.4.16
|
||||||
|
-- end
|
||||||
|
|
||||||
if data then
|
if data then
|
||||||
return data.title,data.text;
|
return data.title,data.text;
|
||||||
else
|
else
|
||||||
@ -539,6 +548,8 @@ end
|
|||||||
|
|
||||||
local robot_activate_furnace = minetest.registered_nodes["default:furnace"].on_metadata_inventory_put; -- this function will activate furnace
|
local robot_activate_furnace = minetest.registered_nodes["default:furnace"].on_metadata_inventory_put; -- this function will activate furnace
|
||||||
basic_robot.commands.activate = function(name,mode, dir)
|
basic_robot.commands.activate = function(name,mode, dir)
|
||||||
|
|
||||||
|
check_operations(name,2,true);
|
||||||
local obj = basic_robot.data[name].obj;
|
local obj = basic_robot.data[name].obj;
|
||||||
local tpos = pos_in_dir(obj, dir); -- position of target block in front
|
local tpos = pos_in_dir(obj, dir); -- position of target block in front
|
||||||
|
|
||||||
@ -896,7 +907,7 @@ basic_robot.commands.machine = {
|
|||||||
-- convert fuel into energy
|
-- convert fuel into energy
|
||||||
generate_power = function(name,input, amount) -- fuel used, if no fuel then amount specifies how much energy builtin generator should produce
|
generate_power = function(name,input, amount) -- fuel used, if no fuel then amount specifies how much energy builtin generator should produce
|
||||||
|
|
||||||
check_operations(name,1.5, true)
|
check_operations(name,6, true)
|
||||||
|
|
||||||
if amount and amount>0 then -- attempt to generate power from builtin generator
|
if amount and amount>0 then -- attempt to generate power from builtin generator
|
||||||
local pos = basic_robot.data[name].spawnpos; -- position of spawner block
|
local pos = basic_robot.data[name].spawnpos; -- position of spawner block
|
||||||
@ -943,7 +954,7 @@ basic_robot.commands.machine = {
|
|||||||
smelt = function(name,input,amount) -- input material, amount of energy used for smelt
|
smelt = function(name,input,amount) -- input material, amount of energy used for smelt
|
||||||
|
|
||||||
local energy = 0; -- can only do one step at a run time
|
local energy = 0; -- can only do one step at a run time
|
||||||
check_operations(name,2,true)
|
check_operations(name,6,true)
|
||||||
|
|
||||||
if string.find(input," ") then return nil, "0: only one item per smelt" end
|
if string.find(input," ") then return nil, "0: only one item per smelt" end
|
||||||
|
|
||||||
@ -1005,6 +1016,7 @@ basic_robot.commands.machine = {
|
|||||||
-- grind
|
-- grind
|
||||||
grind = function(name,input)
|
grind = function(name,input)
|
||||||
--[in] ={fuel cost, out, quantity of material required for processing}
|
--[in] ={fuel cost, out, quantity of material required for processing}
|
||||||
|
check_operations(name,6,true)
|
||||||
local recipe = basic_robot.technic.grinder_recipes[input];
|
local recipe = basic_robot.technic.grinder_recipes[input];
|
||||||
if not recipe then return nil, "unknown recipe" end
|
if not recipe then return nil, "unknown recipe" end
|
||||||
local cost = recipe[1]; local output = recipe[2];
|
local cost = recipe[1]; local output = recipe[2];
|
||||||
@ -1035,6 +1047,7 @@ basic_robot.commands.machine = {
|
|||||||
-- compress
|
-- compress
|
||||||
compress = function(name,input)
|
compress = function(name,input)
|
||||||
--[in] ={fuel cost, out, quantity of material required for processing}
|
--[in] ={fuel cost, out, quantity of material required for processing}
|
||||||
|
check_operations(name,6,true)
|
||||||
local recipe = basic_robot.technic.compressor_recipes[input];
|
local recipe = basic_robot.technic.compressor_recipes[input];
|
||||||
if not recipe then return nil, "unknown recipe" end
|
if not recipe then return nil, "unknown recipe" end
|
||||||
local cost = recipe[1]; local output = recipe[2];
|
local cost = recipe[1]; local output = recipe[2];
|
||||||
@ -1061,13 +1074,15 @@ basic_robot.commands.machine = {
|
|||||||
end,
|
end,
|
||||||
|
|
||||||
transfer_power = function(name,amount,target)
|
transfer_power = function(name,amount,target)
|
||||||
|
|
||||||
|
check_operations(name,2, true);
|
||||||
local pos = basic_robot.data[name].spawnpos;
|
local pos = basic_robot.data[name].spawnpos;
|
||||||
local data = basic_robot.data[name];
|
local data = basic_robot.data[name];
|
||||||
local tdata = basic_robot.data[target];
|
local tdata = basic_robot.data[target];
|
||||||
if not tdata then return nil, "target inactive" end
|
if not tdata then return nil, "target inactive" end
|
||||||
|
|
||||||
local energy = 0; -- can only do one step at a run time
|
local energy = 0; -- can only do one step at a run time
|
||||||
check_operations(name,0.5, true);
|
|
||||||
|
|
||||||
energy = data.menergy or 0;
|
energy = data.menergy or 0;
|
||||||
if amount>energy then return nil,"energy too low" end
|
if amount>energy then return nil,"energy too low" end
|
||||||
|
139
init.lua
139
init.lua
@ -21,11 +21,11 @@ basic_robot.bad_inventory_blocks = { -- disallow taking from these nodes invento
|
|||||||
|
|
||||||
basic_robot.http_api = minetest.request_http_api();
|
basic_robot.http_api = minetest.request_http_api();
|
||||||
|
|
||||||
basic_robot.version = "2018/07/22a";
|
basic_robot.version = "2018/07/23a";
|
||||||
|
|
||||||
basic_robot.data = {}; -- stores all robot related data
|
basic_robot.data = {}; -- stores all robot related data
|
||||||
--[[
|
--[[
|
||||||
[name] = { sandbox= .., bytecode = ..., ram = ..., obj = robot object, spawnpos= ..., authlevel = ...}
|
[name] = { sandbox= .., bytecode = ..., ram = ..., obj = robot object, spawnpos= ..., authlevel = ... , t = code execution time}
|
||||||
robot object = object of entity, used to manipulate movements and more
|
robot object = object of entity, used to manipulate movements and more
|
||||||
--]]
|
--]]
|
||||||
basic_robot.ids = {}; -- stores maxid for each player
|
basic_robot.ids = {}; -- stores maxid for each player
|
||||||
@ -52,6 +52,7 @@ function getSandboxEnv (name)
|
|||||||
left_up = 11, right_up = 12, forward_up = 13, backward_up = 14
|
left_up = 11, right_up = 12, forward_up = 13, backward_up = 14
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if not basic_robot.data[name].rom then basic_robot.data[name].rom = {} end -- create rom if not yet existing
|
||||||
local env =
|
local env =
|
||||||
{
|
{
|
||||||
pcall=pcall,
|
pcall=pcall,
|
||||||
@ -398,16 +399,6 @@ function getSandboxEnv (name)
|
|||||||
tonumber = tonumber, pairs = pairs,
|
tonumber = tonumber, pairs = pairs,
|
||||||
ipairs = ipairs, error = error, type=type,
|
ipairs = ipairs, error = error, type=type,
|
||||||
|
|
||||||
--_ccounter = basic_robot.data[name].ccounter, -- counts how many executions of critical spots in script
|
|
||||||
|
|
||||||
-- increase_ccounter =
|
|
||||||
-- function()
|
|
||||||
-- local _ccounter = basic_robot.data[name].ccounter;
|
|
||||||
-- if _ccounter > basic_robot.call_limit then
|
|
||||||
-- error("Execution limit " .. basic_robot.call_limit .. " exceeded");
|
|
||||||
-- end
|
|
||||||
-- basic_robot.data[name].ccounter = _ccounter + 1;
|
|
||||||
-- end,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
-- ROBOT FUNCTIONS: move,dig, place,insert,take,check_inventory,activate,read_node,read_text,write_text
|
-- ROBOT FUNCTIONS: move,dig, place,insert,take,check_inventory,activate,read_node,read_text,write_text
|
||||||
@ -565,7 +556,7 @@ end
|
|||||||
|
|
||||||
local identify_strings = function(code) -- returns list of positions {start,end} of literal strings in lua code
|
local identify_strings = function(code) -- returns list of positions {start,end} of literal strings in lua code
|
||||||
|
|
||||||
local i = 0; local j; local length = string.len(code);
|
local i = 0; local j; local _; local length = string.len(code);
|
||||||
local mode = 0; -- 0: not in string, 1: in '...' string, 2: in "..." string, 3. in [==[ ... ]==] string
|
local mode = 0; -- 0: not in string, 1: in '...' string, 2: in "..." string, 3. in [==[ ... ]==] string
|
||||||
local modes = {
|
local modes = {
|
||||||
{"'","'"},
|
{"'","'"},
|
||||||
@ -616,38 +607,24 @@ is_inside_string = function(strings,pos) -- is position inside one of the string
|
|||||||
return strings[mid][1]<=pos and pos<=strings[mid][2]
|
return strings[mid][1]<=pos and pos<=strings[mid][2]
|
||||||
end
|
end
|
||||||
|
|
||||||
--[[
|
|
||||||
is_inside_string = function(pos,script)
|
|
||||||
local i1=string.find (script, "\"", 1);
|
|
||||||
if not i1 then
|
|
||||||
return false
|
|
||||||
end
|
|
||||||
local i2=0;
|
|
||||||
local par = 1;
|
|
||||||
|
|
||||||
if pos<i1 then
|
|
||||||
return false
|
|
||||||
end
|
|
||||||
while i1 do
|
|
||||||
i2=string.find(script,"\"",i1+1);
|
|
||||||
if i2 then
|
|
||||||
par = 1 - par;
|
|
||||||
else
|
|
||||||
return false
|
|
||||||
end
|
|
||||||
if par == 0 then
|
|
||||||
if i1<pos and pos<i2 then
|
|
||||||
return true
|
|
||||||
end
|
|
||||||
end
|
|
||||||
i1=i2;
|
|
||||||
end
|
|
||||||
return false;
|
|
||||||
end
|
|
||||||
--]]
|
|
||||||
|
|
||||||
-- COMPILATION
|
-- COMPILATION
|
||||||
|
|
||||||
|
local find_outside_string = function(script, pattern, pos, strings)
|
||||||
|
local length = string.len(script)
|
||||||
|
local found = true;
|
||||||
|
local i1 = pos;
|
||||||
|
while found do
|
||||||
|
found = false
|
||||||
|
local i2 = string.find(script,pattern,i1);
|
||||||
|
if i2 then
|
||||||
|
if not is_inside_string(strings,i2) then return i2 end
|
||||||
|
found = true;
|
||||||
|
i1 = i2+1;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
|
||||||
preprocess_code = function(script) -- version 07/22/2018
|
preprocess_code = function(script) -- version 07/22/2018
|
||||||
|
|
||||||
--[[ idea: in each local a = function (args) ... end insert counter like:
|
--[[ idea: in each local a = function (args) ... end insert counter like:
|
||||||
@ -655,37 +632,33 @@ preprocess_code = function(script) -- version 07/22/2018
|
|||||||
when counter exceeds limit exit with error
|
when counter exceeds limit exit with error
|
||||||
--]]
|
--]]
|
||||||
|
|
||||||
script = script:gsub("%-%-%[%[.*%-%-%]%]",""):gsub("%-%-[^\n]*\n","\n") -- strip comments in fancy way
|
script = script:gsub("%-%-%[%[.*%-%-%]%]",""):gsub("%-%-[^\n]*\n","\n") -- strip comments
|
||||||
|
script="local _c_ = 0; " .. script;
|
||||||
|
|
||||||
script="_ccounter = 0; " .. script;
|
|
||||||
|
|
||||||
local i1
|
|
||||||
-- process script to insert call counter in every function
|
-- process script to insert call counter in every function
|
||||||
local _increase_ccounter = " if _ccounter > " .. basic_robot.call_limit ..
|
local _increase_ccounter = " _c_ = _c_ + 1; if _c_ > " .. basic_robot.call_limit ..
|
||||||
" then error(\"Execution count \".. _ccounter .. \" exceeded ".. basic_robot.call_limit .. "\") end _ccounter = _ccounter + 1; "
|
" then error(\"Execution count \".. _c_ .. \" exceeded ".. basic_robot.call_limit .. "\") end; "
|
||||||
|
|
||||||
|
|
||||||
local i1=0; local i2 = 0;
|
local i1=0; local i2 = 0;
|
||||||
local found = true;
|
local found = true;
|
||||||
|
|
||||||
|
|
||||||
local strings = identify_strings(script);
|
local strings = identify_strings(script);
|
||||||
|
local inserts = {};
|
||||||
|
|
||||||
while (found) do -- PROCESS SCRIPT AND INSERT COUNTER AT PROBLEMATIC SPOTS
|
while (found) do -- PROCESS SCRIPT AND INSERT COUNTER AT PROBLEMATIC SPOTS
|
||||||
|
|
||||||
found = false;
|
found = false;
|
||||||
i2 = nil;
|
i2 = nil;
|
||||||
|
|
||||||
-- i1 = where its looking in current pass, i2 = hit position
|
-- i1 = where its looking in current pass, i2 = hit position
|
||||||
|
|
||||||
i2=string.find (script, "while%s", i1) -- fix while OK
|
i2=string.find (script, "while%s", i1) -- fix while OK
|
||||||
if i2 then
|
if i2 then
|
||||||
if not is_inside_string(strings,i2) then
|
if not is_inside_string(strings,i2) then
|
||||||
local i21 = i2;
|
local i21 = i2;
|
||||||
i2=string.find(script, "%sdo%s", i2);
|
i2 = find_outside_string(script, "%sdo%s", i2, strings); -- find first do not inside string
|
||||||
if i2 then
|
if i2 then
|
||||||
i2 = i2 + 1
|
i2 = i2 + 2 -- skip space and position at 'o' in ' do'
|
||||||
script = script.sub(script,1, i2+1) .. _increase_ccounter .. script.sub(script, i2+2);
|
inserts[#inserts+1]= i2;
|
||||||
i1=i21+6; -- after while
|
i1=i21+6; -- after while
|
||||||
found = true;
|
found = true;
|
||||||
end
|
end
|
||||||
@ -694,12 +667,11 @@ preprocess_code = function(script) -- version 07/22/2018
|
|||||||
|
|
||||||
i2=string.find (script, "function", i1) -- fix functions
|
i2=string.find (script, "function", i1) -- fix functions
|
||||||
if i2 then
|
if i2 then
|
||||||
--minetest.chat_send_all("func0")
|
|
||||||
if not is_inside_string(strings,i2) then
|
if not is_inside_string(strings,i2) then
|
||||||
i2=string.find(script, ")", i2);
|
i2 = find_outside_string(script, ")", i2, strings);
|
||||||
if i2 then
|
if i2 then
|
||||||
script = script.sub(script,1, i2) .. _increase_ccounter .. script.sub(script, i2+1);
|
inserts[#inserts+1]= i2;
|
||||||
i1=i2+string.len(_increase_ccounter);
|
i1=i2;
|
||||||
found = true;
|
found = true;
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@ -709,45 +681,42 @@ preprocess_code = function(script) -- version 07/22/2018
|
|||||||
i2=string.find (script, "for%s", i1) -- fix for OK
|
i2=string.find (script, "for%s", i1) -- fix for OK
|
||||||
if i2 then
|
if i2 then
|
||||||
if not is_inside_string(strings,i2) then
|
if not is_inside_string(strings,i2) then
|
||||||
i2=string.find(script, "%sdo%s", i2);
|
i2 = find_outside_string(script, "%sdo%s", i2, strings);
|
||||||
if i2 then
|
if i2 then
|
||||||
i2 = i2 + 1
|
i2 = i2 + 2 -- position at 'o' in ' do'
|
||||||
script = script.sub(script,1, i2+1) .. _increase_ccounter .. script.sub(script, i2+2);
|
inserts[#inserts+1]= i2;
|
||||||
i1=i2+string.len(_increase_ccounter);
|
i1=i2;
|
||||||
found = true;
|
found = true;
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
i2=string.find (script, "goto%s", i1) -- fix goto OK
|
i2=string.find(script, "goto%s", i1) -- fix goto OK
|
||||||
if i2 then
|
if i2 then
|
||||||
if not is_inside_string(strings,i2) then
|
if not is_inside_string(strings,i2) then
|
||||||
script = script.sub(script,1, i2-1) .. _increase_ccounter .. script.sub(script, i2);
|
inserts[#inserts+1]= i2-1; -- just before goto
|
||||||
i1=i2+string.len(_increase_ccounter)+5; -- insert + skip goto
|
i1=i2+5; -- insert + skip goto
|
||||||
found = true;
|
found = true;
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
i2=string.find (script, "pause()", i1) -- fix pause ?
|
|
||||||
if i2 then
|
|
||||||
if not is_inside_string(strings,i2) then
|
|
||||||
script = script.sub(script,1, i2-1) .. "_ccounter = 0;" .. script.sub(script,i2)
|
|
||||||
i1=i2+14+7; -- insert + skip _ccounter & pause
|
|
||||||
found = true;
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
return script
|
-- add inserts
|
||||||
|
local ret = {}; i1=1;
|
||||||
|
for i = 1, #inserts do
|
||||||
|
i2 = inserts[i];
|
||||||
|
ret[#ret+1] = string.sub(script,i1,i2);
|
||||||
|
i1 = i2+1;
|
||||||
|
end
|
||||||
|
ret[#ret+1] = string.sub(script,i1);
|
||||||
|
|
||||||
|
script = table.concat(ret,_increase_ccounter)
|
||||||
|
return script:gsub("pause()", "_c_ = 0; pause()") -- reset ccounter at pause
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
local function CompileCode ( script )
|
local function CompileCode ( script )
|
||||||
|
|
||||||
--minetest.chat_send_all(script)
|
|
||||||
--if true then return nil, "" end
|
|
||||||
|
|
||||||
local ScriptFunc, CompileError = loadstring( script )
|
local ScriptFunc, CompileError = loadstring( script )
|
||||||
if CompileError then
|
if CompileError then
|
||||||
return nil, CompileError
|
return nil, CompileError
|
||||||
@ -794,8 +763,8 @@ local function runSandbox( name)
|
|||||||
return "Bytecode missing."
|
return "Bytecode missing."
|
||||||
end
|
end
|
||||||
|
|
||||||
data.ccounter = 0;
|
|
||||||
data.operations = basic_robot.maxoperations;
|
data.operations = basic_robot.maxoperations;
|
||||||
|
data.t = os.clock()
|
||||||
|
|
||||||
setfenv( ScriptFunc, data.sandbox )
|
setfenv( ScriptFunc, data.sandbox )
|
||||||
|
|
||||||
@ -803,11 +772,13 @@ local function runSandbox( name)
|
|||||||
if cor then -- coroutine!
|
if cor then -- coroutine!
|
||||||
local err,ret
|
local err,ret
|
||||||
ret,err = coroutine.resume(cor)
|
ret,err = coroutine.resume(cor)
|
||||||
|
data.t = os.clock()-data.t
|
||||||
if err then return err end
|
if err then return err end
|
||||||
return nil
|
return nil
|
||||||
end
|
end
|
||||||
|
|
||||||
local Result, RuntimeError = pcall( ScriptFunc )
|
local Result, RuntimeError = pcall( ScriptFunc )
|
||||||
|
data.t = os.clock()-data.t
|
||||||
if RuntimeError then
|
if RuntimeError then
|
||||||
return RuntimeError
|
return RuntimeError
|
||||||
end
|
end
|
||||||
@ -1140,7 +1111,7 @@ local spawn_robot = function(pos,node,ttl)
|
|||||||
if not data.sandbox then data.sandbox = getSandboxEnv (name) end
|
if not data.sandbox then data.sandbox = getSandboxEnv (name) end
|
||||||
|
|
||||||
-- actual code run process
|
-- actual code run process
|
||||||
data.ccounter = 0;data.operations = basic_robot.maxoperations;
|
data.operations = basic_robot.maxoperations;
|
||||||
|
|
||||||
setfenv(data.bytecode, data.sandbox )
|
setfenv(data.bytecode, data.sandbox )
|
||||||
|
|
||||||
@ -1183,7 +1154,7 @@ local spawn_robot = function(pos,node,ttl)
|
|||||||
if data == nil then
|
if data == nil then
|
||||||
basic_robot.data[name] = {};
|
basic_robot.data[name] = {};
|
||||||
data = basic_robot.data[name];
|
data = basic_robot.data[name];
|
||||||
data.rom = {};
|
--data.rom = {};
|
||||||
end
|
end
|
||||||
|
|
||||||
data.owner = owner;
|
data.owner = owner;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user