This commit is contained in:
arpruss 2015-09-25 21:24:23 -05:00
parent 8d8570718d
commit ddfca3924d

View File

@ -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