diff --git a/raspberryjammod/init.lua b/raspberryjammod/init.lua index d940752..1f955d2 100644 --- a/raspberryjammod/init.lua +++ b/raspberryjammod/init.lua @@ -26,54 +26,158 @@ minetest.register_globalstep(function(dtime) while not err do line,err = clientlist[i]:receive() if err == "closed" then - table.remove(clientlist, i) + table.remove(clientlist,i) print("RJM client disconnected") elseif not err then - handlecommand(clientlist[i], line) + local response = handle_command(line) + if response then clientlist[i]:send(response.."\n") end end end - if err == "closed" then break end end end) -function getplayer() + +function getplayer(id) + -- TODO: handle multiplayer return minetest.get_connected_players()[1] end +function handle_entity(cmd, id, args) + entity = getplayer(id) + if cmd == "getPos" then + local pos = entity:getpos() + return ""..(pos.x)..","..(pos.y)..","..(pos.z) + elseif cmd == "setPos" then + entity:setpos({x=tonumber(args[1]), y=tonumber(args[2]), z=tonumber(args[3])}) + elseif cmd == "getPitch" then + return ""..(entity:getpitch() * 180 / math.pi) + elseif cmd == "getDirection" then + return ""..(entity:getyaw() * 180 / math.pi) + end + return nil +end -function handlecommand(client, line) +function parse_node(args, start) + local nodenum + if #args < start then + nodenum = 0 + elseif #args == start then + nodenum = block.Block(tonumber(args[start]),0) + else + nodenum = block.Block(tonumber(args[start]),tonumber(args[start+1])) + end + local node = block.BLOCK[nodenum] + if node == nil then + node = block.BLOCK[bit.band(nodenum,0xFFF)] + if not node then + node = block.BLOCK[STONE] + end + end + return node +end + +function handle_world(cmd, args) + if cmd == "setBlock" then + local node = parse_node(args, 4) + minetest.set_node({x=tonumber(args[1]),y=tonumber(args[2]),z=tonumber(args[3])},node) + elseif cmd == "setNode" then + minetest.set_node({x=tonumber(args[1]),y=tonumber(args[2]),z=tonumber(args[3])},{name=args[4]}) + elseif cmd == "setBlocks" then + local node = parse_node(args, 7) + x1 = math.min(tonumber(args[1]),tonumber(args[4])) + x2 = math.max(tonumber(args[1]),tonumber(args[4])) + y1 = math.min(tonumber(args[2]),tonumber(args[5])) + y2 = math.max(tonumber(args[2]),tonumber(args[5])) + z1 = math.min(tonumber(args[3]),tonumber(args[6])) + z2 = math.max(tonumber(args[3]),tonumber(args[6])) + for ycoord = y1,y2 do + for xcoord = x1,x2 do + for zcoord = z1,z2 do + minetest.set_node({x=xcoord,y=ycoord,z=zcoord},node) + end + end + end + elseif cmd == "setNodes" then + local node = {node = args[7]} + x1 = math.min(tonumber(args[1]),tonumber(args[4])) + x2 = math.max(tonumber(args[1]),tonumber(args[4])) + y1 = math.min(tonumber(args[2]),tonumber(args[5])) + y2 = math.max(tonumber(args[2]),tonumber(args[5])) + z1 = math.min(tonumber(args[3]),tonumber(args[6])) + z2 = math.max(tonumber(args[3]),tonumber(args[6])) + for ycoord = y1,y2 do + for xcoord = x1,x2 do + for zcoord = z1,z2 do + minetest.set_node({x=xcoord,y=ycoord,z=zcoord},node) + end + end + end + elseif cmd == "getNode" then + return minetest.get_node({x=tonumber(args[1]),y=tonumber(args[2]),z=tonumber(args[3])}).name + elseif cmd == "getBlockWithData" or cmd == "getBlock" then + node = minetest.get_node({x=tonumber(args[1]),y=tonumber(args[2]),z=tonumber(args[3])}) + local id, meta + if node == "ignore" then + id = block.AIR + meta = 0 + else + id = block.STONE + meta = 0 + for key,value in pairs(block.BLOCK) do + if value.name == node.name then + id = math.floor(bit.band(key,0xFFF)) + meta = math.floor(bit.rshift(key,12)) + break + end + end + end + if cmd == "getBlock" then + return ""..id + else + return ""..id..","..meta + end + elseif cmd == "getHeight" then + -- TODO: Handle larger heights than 1024 + local xcoord = tonumber(args[1]) + local zcoord = tonumber(args[2]) + for ycoord = 1024,-1024,-1 do + name = minetest.get_node({x=xcoord,y=ycoord,z=zcoord}).name + if name ~= "ignore" and name ~= "air" then + return ""..ycoord + end + end + return "-1025" + elseif cmd == "getPlayerId" then + return "1" + elseif cmd == "getPlayerIds" then + return "1" + end + return nil + +end + +function handle_command(line) local cmd, argtext = string.match(line, "([^(]+)%((.*)%)") if not cmd then return end local args = {} for arg in string.gmatch(argtext, "([^,]+)") do table.insert(args, arg) end - if cmd == "chat.post" then + if cmd:sub(1,6) == "world." then + return handle_world(cmd:sub(7),args) + elseif cmd:sub(1,7) == "player." then + return handle_entity(cmd:sub(8),1,args) + elseif cmd:sub(1,7) == "entity." then + local player = tonumber(args[1]) + table.remove(args,1) + return handle_entity(cmd:sub(8),player,args) + elseif cmd == "chat.post" then minetest.chat_send_all(argtext) - elseif cmd == "player.getPos" then - local pos = getplayer():getpos() - client:send(""..(pos.x)..","..(pos.y)..","..(pos.z).."\n") - elseif cmd == "player.setPos" then - getplayer():setpos({x=tonumber(args[1]), y=tonumber(args[2]), z=tonumber(args[3])}) - elseif cmd == "world.setBlock" then - local nodenum - if #args == 3 then - nodenum = 0 - elseif #args == 4 then - nodenum = block.Block(tonumber(args[4]),0) - else - nodenum = block.Block(tonumber(args[4]),tonumber(args[5])) - end - local node = block.BLOCK[nodenum] - if not node then - node = block.BLOCK[bit.band(nodenum,0xFFF)] - if not node then - node = block.BLOCK[STONE] - end - end - local pos = {x=tonumber(args[1]),y=tonumber(args[2]),z=tonumber(args[3])} - --print(pos.x,pos.y,pos.z,node.name) - minetest.set_node(pos,node) end + return nil end +-- TODO: +-- world: setting, getPlayerId (need multiplayer support), getPlayerIds (need multiplayer) +-- entity: getPitch (untested), getRotation (untested), getDirection, getTilePos, setTilePos +-- events: clear, block.hits, chat.posts, setting