-- Minetest: builtin/register.lua local S = core.get_translator("__builtin") -- -- Make raw registration functions inaccessible to anyone except this file -- local register_item_raw = core.register_item_raw core.register_item_raw = nil local unregister_item_raw = core.unregister_item_raw core.unregister_item_raw = nil local register_alias_raw = core.register_alias_raw core.register_alias_raw = nil -- -- Item / entity / ABM / LBM registration functions -- core.registered_abms = {} core.registered_lbms = {} core.registered_entities = {} core.registered_items = {} core.registered_nodes = {} core.registered_craftitems = {} core.registered_tools = {} core.registered_aliases = {} -- For tables that are indexed by item name: -- If table[X] does not exist, default to table[core.registered_aliases[X]] local alias_metatable = { __index = function(t, name) return rawget(t, core.registered_aliases[name]) end } setmetatable(core.registered_items, alias_metatable) setmetatable(core.registered_nodes, alias_metatable) setmetatable(core.registered_craftitems, alias_metatable) setmetatable(core.registered_tools, alias_metatable) -- These item names may not be used because they would interfere -- with legacy itemstrings local forbidden_item_names = { MaterialItem = true, MaterialItem2 = true, MaterialItem3 = true, NodeItem = true, node = true, CraftItem = true, craft = true, MBOItem = true, ToolItem = true, tool = true, } local function check_modname_prefix(name) if name:sub(1,1) == ":" then -- If the name starts with a colon, we can skip the modname prefix -- mechanism. return name:sub(2) else -- Enforce that the name starts with the correct mod name. local expected_prefix = core.get_current_modname() .. ":" if name:sub(1, #expected_prefix) ~= expected_prefix then error("Name " .. name .. " does not follow naming conventions: " .. "\"" .. expected_prefix .. "\" or \":\" prefix required") end -- Enforce that the name only contains letters, numbers and underscores. local subname = name:sub(#expected_prefix+1) if subname:find("[^%w_]") then error("Name " .. name .. " does not follow naming conventions: " .. "contains unallowed characters") end return name end end function core.register_abm(spec) -- Add to core.registered_abms assert(type(spec.action) == "function", "Required field 'action' of type function") core.registered_abms[#core.registered_abms + 1] = spec spec.mod_origin = core.get_current_modname() or "??" end function core.register_lbm(spec) -- Add to core.registered_lbms check_modname_prefix(spec.name) assert(type(spec.action) == "function", "Required field 'action' of type function") core.registered_lbms[#core.registered_lbms + 1] = spec spec.mod_origin = core.get_current_modname() or "??" end function core.register_entity(name, prototype) -- Check name if name == nil then error("Unable to register entity: Name is nil") end name = check_modname_prefix(tostring(name)) prototype.name = name prototype.__index = prototype -- so that it can be used as a metatable -- Add to core.registered_entities core.registered_entities[name] = prototype prototype.mod_origin = core.get_current_modname() or "??" end function core.register_item(name, itemdef) -- Check name if name == nil then error("Unable to register item: Name is nil") end name = check_modname_prefix(tostring(name)) if forbidden_item_names[name] then error("Unable to register item: Name is forbidden: " .. name) end itemdef.name = name -- Apply defaults and add to registered_* table if itemdef.type == "node" then -- Use the nodebox as selection box if it's not set manually if itemdef.drawtype == "nodebox" and not itemdef.selection_box then itemdef.selection_box = itemdef.node_box elseif itemdef.drawtype == "fencelike" and not itemdef.selection_box then itemdef.selection_box = { type = "fixed", fixed = {-1/8, -1/2, -1/8, 1/8, 1/2, 1/8}, } end if itemdef.light_source and itemdef.light_source > core.LIGHT_MAX then itemdef.light_source = core.LIGHT_MAX core.log("warning", "Node 'light_source' value exceeds maximum," .. " limiting to maximum: " ..name) end setmetatable(itemdef, {__index = core.nodedef_default}) core.registered_nodes[itemdef.name] = itemdef elseif itemdef.type == "craft" then setmetatable(itemdef, {__index = core.craftitemdef_default}) core.registered_craftitems[itemdef.name] = itemdef elseif itemdef.type == "tool" then setmetatable(itemdef, {__index = core.tooldef_default}) core.registered_tools[itemdef.name] = itemdef elseif itemdef.type == "none" then setmetatable(itemdef, {__index = core.noneitemdef_default}) else error("Unable to register item: Type is invalid: " .. dump(itemdef)) end -- Flowing liquid uses param2 if itemdef.type == "node" and itemdef.liquidtype == "flowing" then itemdef.paramtype2 = "flowingliquid" end -- BEGIN Legacy stuff if itemdef.cookresult_itemstring ~= nil and itemdef.cookresult_itemstring ~= "" then core.register_craft({ type="cooking", output=itemdef.cookresult_itemstring, recipe=itemdef.name, cooktime=itemdef.furnace_cooktime }) end if itemdef.furnace_burntime ~= nil and itemdef.furnace_burntime >= 0 then core.register_craft({ type="fuel", recipe=itemdef.name, burntime=itemdef.furnace_burntime }) end -- END Legacy stuff itemdef.mod_origin = core.get_current_modname() or "??" -- Disable all further modifications getmetatable(itemdef).__newindex = {} --core.log("Registering item: " .. itemdef.name) core.registered_items[itemdef.name] = itemdef core.registered_aliases[itemdef.name] = nil register_item_raw(itemdef) end function core.unregister_item(name) if not core.registered_items[name] then core.log("warning", "Not unregistering item " ..name.. " because it doesn't exist.") return end -- Erase from registered_* table local type = core.registered_items[name].type if type == "node" then core.registered_nodes[name] = nil elseif type == "craft" then core.registered_craftitems[name] = nil elseif type == "tool" then core.registered_tools[name] = nil end core.registered_items[name] = nil unregister_item_raw(name) end function core.register_node(name, nodedef) nodedef.type = "node" core.register_item(name, nodedef) end function core.register_craftitem(name, craftitemdef) craftitemdef.type = "craft" -- BEGIN Legacy stuff if craftitemdef.inventory_image == nil and craftitemdef.image ~= nil then craftitemdef.inventory_image = craftitemdef.image end -- END Legacy stuff core.register_item(name, craftitemdef) end function core.register_tool(name, tooldef) tooldef.type = "tool" tooldef.stack_max = 1 -- BEGIN Legacy stuff if tooldef.inventory_image == nil and tooldef.image ~= nil then tooldef.inventory_image = tooldef.image end if tooldef.tool_capabilities == nil and (tooldef.full_punch_interval ~= nil or tooldef.basetime ~= nil or tooldef.dt_weight ~= nil or tooldef.dt_crackiness ~= nil or tooldef.dt_crumbliness ~= nil or tooldef.dt_cuttability ~= nil or tooldef.basedurability ~= nil or tooldef.dd_weight ~= nil or tooldef.dd_crackiness ~= nil or tooldef.dd_crumbliness ~= nil or tooldef.dd_cuttability ~= nil) then tooldef.tool_capabilities = { full_punch_interval = tooldef.full_punch_interval, basetime = tooldef.basetime, dt_weight = tooldef.dt_weight, dt_crackiness = tooldef.dt_crackiness, dt_crumbliness = tooldef.dt_crumbliness, dt_cuttability = tooldef.dt_cuttability, basedurability = tooldef.basedurability, dd_weight = tooldef.dd_weight, dd_crackiness = tooldef.dd_crackiness, dd_crumbliness = tooldef.dd_crumbliness, dd_cuttability = tooldef.dd_cuttability, /* Minetest Copyright (C) 2013-2017 celeron55, Perttu Ahola <celeron55@gmail.com> Copyright (C) 2017 celeron55, Loic Blot <loic.blot@unix-experience.fr> 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 2.1 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 Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #pragma once #include <cassert> #include "threading/thread.h" #include "connection.h" namespace con { class Connection; class ConnectionSendThread : public Thread { public: friend class UDPPeer; ConnectionSendThread(unsigned int max_packet_size, float timeout); void *run(); void Trigger(); void setParent(Connection *parent) { assert(parent != NULL); // Pre-condition m_connection = parent; } void setPeerTimeout(float peer_timeout) { m_timeout = peer_timeout; } private: void runTimeouts(float dtime); void rawSend(const BufferedPacket &packet); bool rawSendAsPacket(session_t peer_id, u8 channelnum, SharedBuffer<u8> data, bool reliable); void processReliableCommand(ConnectionCommand &c); void processNonReliableCommand(ConnectionCommand &c); void serve(Address bind_address); void connect(Address address); void disconnect(); void disconnect_peer(session_t peer_id); void send(session_t peer_id, u8 channelnum, SharedBuffer<u8> data); void sendReliable(ConnectionCommand &c); void sendToAll(u8 channelnum, SharedBuffer<u8> data); void sendToAllReliable(ConnectionCommand &c); void sendPackets(float dtime); void sendAsPacket(session_t peer_id, u8 channelnum, SharedBuffer<u8> data, bool ack = false); void sendAsPacketReliable(BufferedPacket &p, Channel *channel); bool packetsQueued(); Connection *m_connection = nullptr; unsigned int m_max_packet_size; float m_timeout; std::queue<OutgoingPacket> m_outgoing_queue; Semaphore m_send_sleep_semaphore; unsigned int m_iteration_packets_avaialble; unsigned int m_max_commands_per_iteration = 1; unsigned int m_max_data_packets_per_iteration; unsigned int m_max_packets_requeued = 256; }; class ConnectionReceiveThread : public Thread { public: ConnectionReceiveThread(unsigned int max_packet_size); void *run(); void setParent(Connection *parent) { assert(parent); // Pre-condition m_connection = parent; } private: void receive(); // Returns next data from a buffer if possible // If found, returns true; if not, false. // If found, sets peer_id and dst bool getFromBuffers(session_t &peer_id, SharedBuffer<u8> &dst); bool checkIncomingBuffers( Channel *channel, session_t &peer_id, SharedBuffer<u8> &dst); /* Processes a packet with the basic header stripped out. Parameters: packetdata: Data in packet (with no base headers) peer_id: peer id of the sender of the packet in question channelnum: channel on which the packet was sent reliable: true if recursing into a reliable packet */ SharedBuffer<u8> processPacket(Channel *channel, SharedBuffer<u8> packetdata, session_t peer_id, u8 channelnum, bool reliable); SharedBuffer<u8> handlePacketType_Control(Channel *channel, SharedBuffer<u8> packetdata, Peer