commit f9fb013ae0df5cf97bc92bdce4226da59ed00751 Author: bvn13 Date: Sat Dec 7 01:12:37 2024 +0300 working mod diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..153d416 --- /dev/null +++ b/LICENSE @@ -0,0 +1,165 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + + This version of the GNU Lesser General Public License incorporates +the terms and conditions of version 3 of the GNU General Public +License, supplemented by the additional permissions listed below. + + 0. Additional Definitions. + + As used herein, "this License" refers to version 3 of the GNU Lesser +General Public License, and the "GNU GPL" refers to version 3 of the GNU +General Public License. + + "The Library" refers to a covered work governed by this License, +other than an Application or a Combined Work as defined below. + + An "Application" is any work that makes use of an interface provided +by the Library, but which is not otherwise based on the Library. +Defining a subclass of a class defined by the Library is deemed a mode +of using an interface provided by the Library. + + A "Combined Work" is a work produced by combining or linking an +Application with the Library. The particular version of the Library +with which the Combined Work was made is also called the "Linked +Version". + + The "Minimal Corresponding Source" for a Combined Work means the +Corresponding Source for the Combined Work, excluding any source code +for portions of the Combined Work that, considered in isolation, are +based on the Application, and not on the Linked Version. + + The "Corresponding Application Code" for a Combined Work means the +object code and/or source code for the Application, including any data +and utility programs needed for reproducing the Combined Work from the +Application, but excluding the System Libraries of the Combined Work. + + 1. Exception to Section 3 of the GNU GPL. + + You may convey a covered work under sections 3 and 4 of this License +without being bound by section 3 of the GNU GPL. + + 2. Conveying Modified Versions. + + If you modify a copy of the Library, and, in your modifications, a +facility refers to a function or data to be supplied by an Application +that uses the facility (other than as an argument passed when the +facility is invoked), then you may convey a copy of the modified +version: + + a) under this License, provided that you make a good faith effort to + ensure that, in the event an Application does not supply the + function or data, the facility still operates, and performs + whatever part of its purpose remains meaningful, or + + b) under the GNU GPL, with none of the additional permissions of + this License applicable to that copy. + + 3. Object Code Incorporating Material from Library Header Files. + + The object code form of an Application may incorporate material from +a header file that is part of the Library. You may convey such object +code under terms of your choice, provided that, if the incorporated +material is not limited to numerical parameters, data structure +layouts and accessors, or small macros, inline functions and templates +(ten or fewer lines in length), you do both of the following: + + a) Give prominent notice with each copy of the object code that the + Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the object code with a copy of the GNU GPL and this license + document. + + 4. Combined Works. + + You may convey a Combined Work under terms of your choice that, +taken together, effectively do not restrict modification of the +portions of the Library contained in the Combined Work and reverse +engineering for debugging such modifications, if you also do each of +the following: + + a) Give prominent notice with each copy of the Combined Work that + the Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the Combined Work with a copy of the GNU GPL and this license + document. + + c) For a Combined Work that displays copyright notices during + execution, include the copyright notice for the Library among + these notices, as well as a reference directing the user to the + copies of the GNU GPL and this license document. + + d) Do one of the following: + + 0) Convey the Minimal Corresponding Source under the terms of this + License, and the Corresponding Application Code in a form + suitable for, and under terms that permit, the user to + recombine or relink the Application with a modified version of + the Linked Version to produce a modified Combined Work, in the + manner specified by section 6 of the GNU GPL for conveying + Corresponding Source. + + 1) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (a) uses at run time + a copy of the Library already present on the user's computer + system, and (b) will operate properly with a modified version + of the Library that is interface-compatible with the Linked + Version. + + e) Provide Installation Information, but only if you would otherwise + be required to provide such information under section 6 of the + GNU GPL, and only to the extent that such information is + necessary to install and execute a modified version of the + Combined Work produced by recombining or relinking the + Application with a modified version of the Linked Version. (If + you use option 4d0, the Installation Information must accompany + the Minimal Corresponding Source and Corresponding Application + Code. If you use option 4d1, you must provide the Installation + Information in the manner specified by section 6 of the GNU GPL + for conveying Corresponding Source.) + + 5. Combined Libraries. + + You may place library facilities that are a work based on the +Library side by side in a single library together with other library +facilities that are not Applications and are not covered by this +License, and convey such a combined library under terms of your +choice, if you do both of the following: + + a) Accompany the combined library with a copy of the same work based + on the Library, uncombined with any other library facilities, + conveyed under the terms of this License. + + b) Give prominent notice with the combined library that part of it + is a work based on the Library, and explaining where to find the + accompanying uncombined form of the same work. + + 6. Revised Versions of the GNU Lesser General Public License. + + The Free Software Foundation may publish revised and/or new versions +of the GNU Lesser General Public License from time to time. Such new +versions will be similar in spirit to the present version, but may +differ in detail to address new problems or concerns. + + Each version is given a distinguishing version number. If the +Library as you received it specifies that a certain numbered version +of the GNU Lesser General Public License "or any later version" +applies to it, you have the option of following the terms and +conditions either of that published version or of any later version +published by the Free Software Foundation. If the Library as you +received it does not specify a version number of the GNU Lesser +General Public License, you may choose any version of the GNU Lesser +General Public License ever published by the Free Software Foundation. + + If the Library as you received it specifies that a proxy can decide +whether future versions of the GNU Lesser General Public License shall +apply, that proxy's public statement of acceptance of any version is +permanent authorization for you to choose that version for the +Library. \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..fd4df22 --- /dev/null +++ b/README.md @@ -0,0 +1,222 @@ +# Luanti Network API MOD + +It's Luanti MOD adding a Network API. + +*It is an updated project originally started [here](https://github.com/miney-py/mineysocket)* + +--- + +# mineysocket - A network api mod for minetest + +The goal of this mod is to open minetest for other scripting languages. + +For that this mod opens a TCP network port where it receives lua snippets to execute these inside the minetest. +That allows you to write a socket client in your favorite language to wrap api functions over network/internet. + +**The reference implementation is [Miney](https://github.com/miney-py/miney), a python interface to minetest.** + +## Requirements + +* luasockets + +### Running with docker + +Look here: [Documentation](docker/README.md) + +### Installation with Windows + +It's more complicated, because you can't just put some dlls in the right place. +You have to recompile minetest together with luasocket. + +Luckily there are some scripts to do that for you or you just download a precompiled binary that includes all you need. + +* **Miney windows distribution: https://github.com/miney-py/miney_distribution** + + The miney distribution is an all-in-one bundle of minetest, mineysocket, python, miney and a launcher for quickstart. + +* **Precompiled binary: https://github.com/miney-py/minetest_windows/releases** + + Just minetest with mineysocket, nothing else + +* **Build script: https://github.com/miney-py/minetest_windows** + + Use the build script yourself, to compile binaries. + +### Installation with Debian Buster + +The latest minetest version is in the backport repository for buster, so it's very easy to install: https://wiki.minetest.net/Setting_up_a_server/Debian +``` +apt install lua5.1-socket +cd /var/games/minetest-server/.minetest/mods +git clone git@github.com:miney-py/mineysocket.git +``` +* Edit /var/games/minetest-server/.minetest/worlds/\/world.mt and add: +``` +load_mod_mineysocket = true +``` +* Edit /etc/minetest/minetest.conf + * name = \ # This gives you all privileges on your server + * secure.trusted_mods = mineysocket # This is needed for luasocket + * Optional but recommended: + * enable_rollback_recording = true # This allows you to clean up your world +* Connect at least once with minetest to your server and login with a username + password, to get you registered. + +## Settings + +Default is, that mineysocket listens on 127.0.0.1 on port 29999. + +You can change this in the minetest menu (Settings -> All Settings -> Mods -> mineysocket) or in the minetest.conf. + +``` +mineysocket.host_ip = 127.0.0.1 +``` +The IP mineysocket is listening on. +With "127.0.0.1" only you can connect, with "*" or "0.0.0.0" anyone in the network or internet can connect. + +**WARNING: It could be dangerous to open this to everyone in the internet! Only change if you know what you are doing! If you don't know, let it at "127.0.0.1".** +``` +mineysocket.host_port = 29999 +``` +The TCP port mineysocket is listening. + +## Notes + +Clients can only run code after authentication and if the user has "server" privilege (or if connected from 127.0.0.1). + +This may change, but currently authenticated users can do anything in the minetest api, also change their own and other users privileges! + +**You use this at your own risk!** + +## Todo + +- [ ] Authentication without sending cleartext password +- [ ] Implement limited user rights with a fixed set of available commands + +## Protocol description + +mineysocket is a simple JSON-based TCP protocol. Send a valid JSON-String with a tailing linebreak (`\n`) to the port +and mineysocket responds a JSON string with a tailing linebreak. + +### Ping + +A simple alive check, and the only command implemented without json. + +``` +>>> ping\n +<<< pong\n +``` + +### Authentication + +``` +>>> {"playername": "player", "password": "my_password"}\n +<<< {"result": ["auth_ok", "127.0.0.1:31928"], "id": "auth"}\n +``` +Send playername and password and you get auth_ok with your clientid. + +On error you get a error object: +``` +<<< {"error": "authentication error"}\n +``` +Btw: All errors look like this, with different error descriptions. + +Connections from 127.0.0.1 don't need to authenticate. + +### Run lua code + +After authentication, you are ready to send a command. An JSON object key is a command, in this example +"lua" to run lua code. +``` +>>> {"lua": "return 12 + 2, \"something\"", id="myrandomstring"}\n +<<< {"result": [14, "something"], id="myrandomstring"}\n +``` +Lua code runs inside a function definition, so you need to return a value to get a result send back to you. +As you see, you can return multiple values. +Optional you can send a (random) id to identify your result, if you run multiple codes parallel. + +More commands will be added later. + +### Events + +Mineysocket can send JSON objects on global events. + +To receive events, you need to register for this event. This example registers for `chat_message`: +``` +>>> {"register_event": "chat_message"}\n +``` + +To unregister, do this: +``` +>>> {"unregister_event": "chat_message"}\n +``` + +You can register for the following events. + +##### The server was gracefully stopped +``` +<<< { "event" = "shutdown" }\n +``` + +##### A player's health points changed +``` +<<< {"event" = "player_hpchanged", params = ["player_hpchanged", "", "", {'type': '', 'from': ''}]}\n +``` + +##### A player died +``` +<<< {"event" = "player_died", params = ["", ""]}\n +``` + +##### A player respawned +``` +<<< {"event" = "player_respawned", params = [""]}\n +``` + +##### A player joined +``` +<<< {"event" = "player_joined", params = [""]}\n +``` + +##### A player left +``` +<<< {"event"= "player_left", params = [""]}\n +``` + +##### An authentication failed +``` +<<< {"event" = "auth_failed", params = ["", ""]}\n +``` + +##### A player cheated + +With one of the following types + +* `moved_too_fast` +* `interacted_too_far` +* `interacted_while_dead` +* `finished_unknown_dig` +* `dug_unbreakable` +* `dug_too_fast` +``` +<<< {"event" = "player_cheated", params = ["", {"type": ""}]}\n +``` + +##### A new chat message +``` +<<< {"event" = "chat_message", params = ["", ""]}\n +``` + +##### A node was placed +``` +<<< {"event" = "node_placed", params = [, , , , , ]}\n +``` + +##### A node was dug +``` +<<< {"event" = "node_dug", params = [, , ]}\n +``` + +##### A node was punched +``` +<<< {"event" = "node_punched", params = [, , , ]}\n +``` diff --git a/init.lua b/init.lua new file mode 100644 index 0000000..9308395 --- /dev/null +++ b/init.lua @@ -0,0 +1,468 @@ +--[[ +Mineysocket +Copyright (C) 2019 Robert Lieback + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation; either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +--]] + +-- Load external libs +local ie +if minetest.request_insecure_environment then + ie = minetest.request_insecure_environment() +end +if not ie then + error("mineysocket has to be added to the secure.trusted_mods in minetest.conf") +end + + +mineysocket = {} -- global namespace + +-- just a logging function +mineysocket.log = function(level, text, ip, port) + -- if mineysocket.debug or level ~= "action" then + if text then + if ip and port then + minetest.log(level, "mineysocket: " .. text .. " from " .. ip .. ":" .. port) + else + minetest.log(level, "mineysocket: " .. ": " .. text) + end + end + -- end +end + +mineysocket.log("action", "Starting to load mod") + +--[[ +mineysocket.capture = function(cmd, raw) + local f = assert(io.popen(cmd, 'r')) + local s = assert(f:read('*a')) + f:close() + if raw then return s end + s = string.gsub(s, '^%s+', '') + s = string.gsub(s, '%s+$', '') + s = string.gsub(s, '[\n\r]+', ' ') + return s +end +local ttt = mineysocket.capture("ifconfig", false) +mineysocket.log("action", "TEST: " .. ttt) +]]-- + +-- local sh = require('sh') +mineysocket.log("action", os.getenv("HOSTNAME")) +mineysocket.log("action", os.getenv("IPV4")) + +-- configuration +mineysocket.host_ip = minetest.settings:get("mineysocket.host_ip") +mineysocket.host_port = minetest.settings:get("mineysocket.host_port") + +-- Workaround for bug, where default values return only nil +if not mineysocket.host_ip then + mineysocket.host_ip = os.getenv("IPV4") +end +if not mineysocket.host_port then + mineysocket.host_port = 29999 +end + +mineysocket.debug = false -- set to true to show all log levels +mineysocket.max_clients = 10 + +local luasocket = ie.require("socket.core") +if not luasocket then + error("luasocket is not installed or was not found...") +end + +-- setup network server +local server, err = luasocket.tcp() +if not server then + mineysocket.log("action", err) + error("exit") +end + +local bind, err = server:bind(mineysocket.host_ip, mineysocket.host_port) +if not bind then + error("mineysocket: " .. err) +end +local listen, err = server:listen(mineysocket.max_clients) +if not listen then + error("mineysocket: Socket listen error: " .. err) +end +mineysocket.log("action", "listening on " .. mineysocket.host_ip .. ":" .. tostring(mineysocket.host_port)) + +server:settimeout(0) +mineysocket.host_ip, mineysocket.host_port = server:getsockname() +if not mineysocket.host_ip or not mineysocket.host_port then + error("mineysocket: Couldn't open secrver port!") +end + +mineysocket["socket_clients"] = {} -- a table with all connected clients with there options + +-- receive network data and process them +mineysocket.log("action", "Installing socket receiver...") +minetest.register_globalstep(function(dtime) + mineysocket.receive() +end) +mineysocket.log("action", "Installing socket receiver...DONE") + + +-- Clean shutdown +mineysocket.log("action", "Installing shutdown cleaning...") +minetest.register_on_shutdown(function() + mineysocket.log("action", "mineysocket: Closing port...") + for clientid, client in pairs(mineysocket["socket_clients"]) do + mineysocket["socket_clients"][clientid].socket:close() + end + server:close() +end) +mineysocket.log("action", "Installing shutdown cleaning...DONE") + + +-- receive data from clients +mineysocket.log("action", "Describing socket receiving function...") +mineysocket.receive = function() + local data, ip, port, clientid, client, err + local result = false + + -- look for new client connections + client, err = server:accept() + if client then + ip, port = client:getpeername() + clientid = ip .. ":" .. port + mineysocket.log("action", "New connection from " .. ip .. " " .. port) + + client:settimeout(0) + -- register the new client + if not mineysocket["socket_clients"][clientid] then + mineysocket["socket_clients"][clientid] = {} + mineysocket["socket_clients"][clientid].socket = client + mineysocket["socket_clients"][clientid].last_message = minetest.get_server_uptime() + mineysocket["socket_clients"][clientid].buffer = "" + mineysocket["socket_clients"][clientid].eom = nil + + if ip == "127.0.0.1" then -- skip authentication for 127.0.0.1 + mineysocket["socket_clients"][clientid].auth = true + mineysocket["socket_clients"][clientid].playername = "localhost" + mineysocket["socket_clients"][clientid].events = {} + else + mineysocket["socket_clients"][clientid].auth = false + end + end + else + if err ~= "timeout" then + mineysocket.log("error", "Connection error \"" .. err .. "\"") + client:close() + end + end + + -- receive data + for clientid, client in pairs(mineysocket["socket_clients"]) do + local complete_data, err, data = mineysocket["socket_clients"][clientid].socket:receive("*a") + -- there are never complete_data, cause we don't receive lines + -- Note: err is "timeout" every time when there are no client data, cause we set timeout to 0 and + -- we don't want to wait and block lua/minetest for clients to send data + if err ~= "timeout" then + mineysocket["socket_clients"][clientid].socket:close() + -- cleanup + if err == "closed" then + mineysocket["socket_clients"][clientid] = nil + mineysocket.log("action", "Connection to ".. clientid .." was closed") + return + else + mineysocket.log("action", err) + end + end + if data and data ~= "" then + -- store time of the last message for cleanup of old connection + mineysocket["socket_clients"][clientid].last_message = minetest.get_server_uptime() + + if not string.find(data, "\n") then + -- fill a buffer and wait for the linebreak + if not mineysocket["socket_clients"][clientid].buffer then + mineysocket["socket_clients"][clientid].buffer = data + else + mineysocket["socket_clients"][clientid].buffer = mineysocket["socket_clients"][clientid].buffer .. data + end + if mineysocket["socket_clients"][clientid].auth == false then -- limit buffer size for unauthenticated connections + if mineysocket["socket_clients"][clientid].buffer and string.len(mineysocket["socket_clients"][clientid].buffer) + string.len(data) > 10 then + mineysocket["socket_clients"][clientid].buffer = nil + end + end + mineysocket.receive() + return + else + -- get data from buffer and reset em + if mineysocket["socket_clients"][clientid]["buffer"] then + data = mineysocket["socket_clients"][clientid].buffer .. data + mineysocket["socket_clients"][clientid].buffer = nil + end + + mineysocket.log("action", "Received: \n" .. data) + + -- we try to find the eom message terminator for this session + if mineysocket["socket_clients"][clientid].eom == nil then + if string.sub(data, -2) == "\r\n" then + mineysocket["socket_clients"][clientid].eom = "\r\n" + else + mineysocket["socket_clients"][clientid].eom = "\n" + end + end + + -- simple alive check + if data == "ping" .. mineysocket["socket_clients"][clientid].eom then + mineysocket["socket_clients"][clientid].socket:send("pong" .. mineysocket["socket_clients"][clientid].eom) + return + end + + -- parse data as json + local status, input = pcall(minetest.parse_json, data) + if not status then + mineysocket.log("error", minetest.write_json({ error = input })) + mineysocket.log("error", "JSON-Error: " .. input, ip, port) + mineysocket.send(clientid, minetest.write_json({ error = "JSON decode error - " .. input })) + return + end + + -- is it a known client, or do we need authentication? + if mineysocket["socket_clients"][clientid].auth == true then + ---------------------------- + -- commands: + ---------------------------- + + -- we run lua code + if input["lua"] then + result = run_lua(input, clientid, ip, port) + end + + -- append event to callback list + if input["register_event"] then + result = mineysocket.register_event(clientid, input["register_event"]) + end + + -- append event to callback list + if input["unregister_event"] then + result = mineysocket.unregister_event(clientid, input["unregister_event"]) + end + + -- handle reauthentication + if input["playername"] and input["password"] then + result = mineysocket.authenticate(input, clientid, ip, port, mineysocket["socket_clients"][clientid].socket) + end + + -- reattach id + if input["id"] and result ~= false then + result["id"] = input["id"] + end + + -- send result + if result ~= false then + mineysocket.send(clientid, minetest.write_json(result)) + else + mineysocket.send(clientid, minetest.write_json({ error = "Unknown command" })) + end + + else + -- we need authentication + if input["playername"] and input["password"] then + mineysocket.send(clientid, minetest.write_json(mineysocket.authenticate(input, clientid, ip, port, mineysocket["socket_clients"][clientid].socket))) + else + mineysocket.send(clientid, minetest.write_json({ error = "Unknown command" })) + end + end + end + end + end +end +mineysocket.log("action", "Describing socket receiving function...DONE") + + +-- run lua code send by the client +mineysocket.log("action", "Function to run lua code...") +function run_lua(input, clientid, ip, port) + local start_time, err + local output = {} + + start_time = minetest.get_server_uptime() + + -- log the (shortend) code + if string.len(input["lua"]) > 120 then + mineysocket.log("action", "execute: " .. string.sub(input["lua"], 0, 120) .. " ...", ip, port) + else + mineysocket.log("action", "execute: " .. input["lua"], ip, port) + end + + -- run + local f, syntaxError = loadstring(input["lua"]) + -- todo: is there a way to get also warning like "Undeclared global variable ... accessed at ..."? + + if f then + local status, result1, result2, result3, result4, result5 = pcall(f, clientid) -- Get the clientid with "...". Example: "mineysocket.send(..., output)" + -- is there a more elegant way for unlimited results? + + if status then + output["result"] = { result1, result2, result3, result4, result5 } + if mineysocket.debug then + local json_output = minetest.write_json(output) + if string.len(json_output) > 120 then + mineysocket.log("action", string.sub(json_output, 0, 120) .. " ..." .. " in " .. (minetest.get_server_uptime() - start_time) .. " seconds", ip, port) + else + mineysocket.log("action", json_output .. " in " .. (minetest.get_server_uptime() - start_time) .. " seconds", ip, port) + end + end + return output + else + err = result1 + end + else + err = syntaxError + end + + -- send lua errors + if err then + output["error"] = err + mineysocket.log("error", "Error " .. err .. " in command", ip, port) + return output + end +end +mineysocket.log("action", "Function to run lua code...DONE") + + +-- authenticate clients +mineysocket.log("action", "Function to authenticate...") +mineysocket.authenticate = function(input, clientid, ip, port, socket) + local player = minetest.get_auth_handler().get_auth(input["playername"]) + + -- we skip authentication for 127.0.0.1 and just accept everything + if ip == "127.0.0.1" then + mineysocket.log("action", "Player '" .. input["playername"] .. "' connected successful", ip, port) + mineysocket["socket_clients"][clientid].playername = input["playername"] + return { result = { "auth_ok", clientid }, id = "auth" } + else + -- others need a valid playername and password + if player and minetest.check_password_entry(input["playername"], player['password'], input["password"]) and minetest.check_player_privs(input["playername"], { server = true }) then + mineysocket.log("action", "Player '" .. input["playername"] .. "' authentication successful", ip, port) + mineysocket["socket_clients"][clientid].auth = true + mineysocket["socket_clients"][clientid].playername = input["playername"] + mineysocket["socket_clients"][clientid].events = {} + return { result = { "auth_ok", clientid }, id = "auth" } + else + mineysocket.log("error", "Wrong playername ('" .. input["playername"] .. "') or password", ip, port) + mineysocket["socket_clients"][clientid].auth = false + return { error = "authentication error" } + end + end +end +mineysocket.log("action", "Function to authenticate...DONE") + + +-- send data to the client +mineysocket.log("action", "Function to send data to client...") +mineysocket.send = function(clientid, data) + local data = data .. mineysocket["socket_clients"][clientid]["eom"] -- eom is the terminator + local size = string.len(data) + + local chunk_size = 4096 + + if size < chunk_size then + -- we send in one package + mineysocket["socket_clients"][clientid].socket:send(data) + else + -- we split into multiple packages + for i = 0, math.floor(size / chunk_size) do + mineysocket["socket_clients"][clientid].socket:send( + string.sub(data, i * chunk_size, chunk_size + (i * chunk_size) - 1) + ) + luasocket.sleep(0.001) -- Or buffer fills to fast + -- todo: Protocol change, that every chunked message needs a response before sending the next + end + end +end +mineysocket.log("action", "Function to send data to client...") + + +-- register for event +mineysocket.log("action", "Function to register events...") +mineysocket.register_event = function(clientid, eventname) + mineysocket["socket_clients"][clientid].events[#mineysocket["socket_clients"][clientid].events+1] = eventname + return { result = "ok" } +end +mineysocket.log("action", "Function to register events...DONE") + + +-- unregister for event +mineysocket.log("action", "Function to register unevents...") +mineysocket.unregister_event = function(clientid, eventname) + for index, value in pairs(mineysocket["socket_clients"][clientid].events) do + if value == eventname then + table.remove( mineysocket["socket_clients"][clientid].events, index ) + break + end + end + return { result = "ok" } +end +mineysocket.log("action", "Function to register unevents...DONE") + + +-- send event data to clients, who are registered for this event +mineysocket.log("action", "Function to send events...") +mineysocket.send_event = function(data) + for clientid, values in pairs(mineysocket["socket_clients"]) do + local client_events = mineysocket["socket_clients"][clientid].events + + for _, event_data in ipairs(client_events) do + local registered_event_name = event_data["event"] + local received_event_name = data["event"][1] + + if registered_event_name == received_event_name then + mineysocket.log("action", "Sending event: " .. received_event_name) + mineysocket.send(clientid, minetest.write_json(data)) + break + end + end + end +end +mineysocket.log("action", "Function to send events...DONE") + + +-- BEGIN global event registration +mineysocket.log("action", "Registering global fucntions...") +minetest.register_on_shutdown(function() + mineysocket.send_event({ event = { "shutdown" } }) +end) +minetest.register_on_player_hpchange(function(player, hp_change, reason) + mineysocket.send_event({ event = { "player_hpchanged", player:get_player_name(), hp_change, reason } }) +end, false) +minetest.register_on_dieplayer(function(player, reason) + mineysocket.send_event({ event = { "player_died", player:get_player_name(), reason } }) +end) +minetest.register_on_respawnplayer(function(player) + mineysocket.send_event({ event = { "player_respawned", player:get_player_name() } }) +end) +minetest.register_on_joinplayer(function(player) + mineysocket.send_event({ event = { "player_joined", player:get_player_name() } }) +end) +minetest.register_on_leaveplayer(function(player, timed_out) + mineysocket.send_event({ event = { "player_left", player:get_player_name(), timed_out } }) +end) +minetest.register_on_authplayer(function(name, ip) + mineysocket.send_event({ event = { "auth_failed", name, ip } }) +end) +minetest.register_on_cheat(function(player, cheat) + mineysocket.send_event({ event = { "player_cheated", player:get_player_name(), cheat } }) +end) +minetest.register_on_chat_message(function(name, message) + mineysocket.send_event({ event = { "chat_message", name, message } }) +end) +mineysocket.log("action", "Registering global fucntions...DONE") +-- END global event registration + +minetest.log("action", "Initialization - DONE") diff --git a/mod.conf b/mod.conf new file mode 100644 index 0000000..a81c079 --- /dev/null +++ b/mod.conf @@ -0,0 +1,2 @@ +name = mineysocket +description = This mod allows execution of lua code over network. Use at own risk. Needs "secure.trusted_mods = mineysocket" in minetest.conf