-- TODO: test multiplayer functionality -- -- Note: The x-coordinate is reversed in sign between minetest and minecraft, -- and the API compensates for this. local source = debug.getinfo(1).source:sub(2) -- Detect windows via backslashes in paths local mypath = minetest.get_modpath(minetest.get_current_modname()) local is_windows = (nil ~= string.find(package.path..package.cpath..source..mypath, "%\\%?")) local path_separator if is_windows then path_separator = "\\" else path_separator = "/" end local script_window_id = "minetest-rjm-python-script" package.path = package.path .. ";" .. mypath .. path_separator .. "?.lua" if is_windows then package.cpath = package.cpath .. ";" .. mypath .. path_separator .. "?.dll" else package.cpath = package.cpath .. ";" .. mypath .. path_separator .. "?.so" end local block = require("block") local socket = require("socket") local block_hits = {} local chat_record = {} local player_table = {} local socket_client_list = {} script_running = false restrict_to_sword = true max_player_id = 0 default_player_id = -1 world_immutable = false local settings = Settings(mypath .. path_separator .. "settings.conf") local update_settings = false python_interpreter = settings:get("python") if python_interpreter == nil then python_interpreter = "python" update_settings = true settings:set("python", python_interpreter) end local local_only = settings:get_bool("restrict_to_local_connections") if local_only == nil then local_only = false update_settings = true settings:set("restrict_to_local_connections", tostring(local_only)) end local ws = settings:get_bool("support_websockets") if ws == nil then ws = true update_settings = true settings:set("support_websockets", tostring(ws)) end if update_settings then settings:write() end local remote_address if local_only then remote_address = "127.0.0.1" else remote_address = "*" end local server = socket.bind(remote_address, 4711) server:setoption('tcp-nodelay',true) server:settimeout(0) local ws_server = nil if ws then tools = require("tools") base64 = require("base64") ws_server = socket.bind(remote_address, 14711) ws_server:setoption('tcp-nodelay',true) ws_server:settimeout(0) end minetest.register_globalstep(function(dtime) local newclient,err if server then newclient,err = server:accept() if not err then newclient:settimeout(0) table.insert(socket_client_list, {client=newclient,handler=safe_handle_command,read_mode="*l"}) minetest.log("action", "RJM socket client connected") end end if ws_server then newclient,err = ws_server:accept() if not err then newclient:settimeout(0) table.insert(socket_client_list, {client=newclient,handler=handle_websocket_header,ws={},read_mode="*l"}) minetest.log("action", "RJM websocket client attempting handshake") end end for i = 1, #socket_client_list do err = false local line local finished = false while not err do local source = socket_client_list[i] line,err = source.client:receive(source.read_mode) if err == "closed" then table.remove(socket_client_list,i) minetest.log("action", "RJM socket client disconnected") finished = true elseif not err then err = source:handler(line) if err then source.client:close() table.remove(socket_client_list,i) if err ~= "closed" then minetest.log("error", "Error "..err.." in command: RJM socket client disconnected") end finished = true err = "handling" end end end if finished then break end end end) local old_is_protected = minetest.is_protected function minetest.is_protected(pos, name) return world_immutable or old_is_protected(pos, name) end minetest.register_on_shutdown(function() if (script_running) then minetest.log("action", "Stopping scripts") kill(script_window_id) script_running = false end minetest.log("action", "RJM socket clients disconnected") for i = 1, #socket_client_list do socket_client_list[i].client:close() end socket_client_list = {} player_table = {} max_player_id = 0 default_player_id = -1 end) minetest.register_on_joinplayer(function(player) minetest.log("action", "Hello, player "..player:get_player_name()) max_player_id = max_player_id + 1 player_table[max_player_id] = player if default_player_id < 0 then default_player_id = max_player_id end end) minetest.register_on_leaveplayer(function(player) minetest.log("action", "Goodbye, player "..player:get_player_name()) id = get_player_id(player) if id then player_table[id] = nil end if id == default_player_id then default_player_id = max_player_id for i,p in pairs(player_table) do if p ~= nil and i < default_player_id then default_player_id = i end end end end) minetest.register_on_punchnode(function(pos, oldnode, puncher, pointed_thing) -- TODO: find a way to get right clicks -- TODO: find a way to get clicked side if (puncher:is_player()) then local item = puncher:get_wielded_item() if not restrict_to_sword or (item and item:get_name():find("%:sword")) then table.insert(block_hits, ""..(-pos.x)..","..pos.y..","..pos.z..",7,"..get_entity_id(puncher)) end end end) minetest.register_chatcommand("py", {params="[