register.lua 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411
  1. -- Minetest: builtin/misc_register.lua
  2. --
  3. -- Make raw registration functions inaccessible to anyone except this file
  4. --
  5. local register_item_raw = core.register_item_raw
  6. core.register_item_raw = nil
  7. local register_alias_raw = core.register_alias_raw
  8. core.register_alias_raw = nil
  9. --
  10. -- Item / entity / ABM registration functions
  11. --
  12. core.registered_abms = {}
  13. core.registered_entities = {}
  14. core.registered_items = {}
  15. core.registered_nodes = {}
  16. core.registered_craftitems = {}
  17. core.registered_tools = {}
  18. core.registered_aliases = {}
  19. -- For tables that are indexed by item name:
  20. -- If table[X] does not exist, default to table[core.registered_aliases[X]]
  21. local alias_metatable = {
  22. __index = function(t, name)
  23. return rawget(t, core.registered_aliases[name])
  24. end
  25. }
  26. setmetatable(core.registered_items, alias_metatable)
  27. setmetatable(core.registered_nodes, alias_metatable)
  28. setmetatable(core.registered_craftitems, alias_metatable)
  29. setmetatable(core.registered_tools, alias_metatable)
  30. -- These item names may not be used because they would interfere
  31. -- with legacy itemstrings
  32. local forbidden_item_names = {
  33. MaterialItem = true,
  34. MaterialItem2 = true,
  35. MaterialItem3 = true,
  36. NodeItem = true,
  37. node = true,
  38. CraftItem = true,
  39. craft = true,
  40. MBOItem = true,
  41. ToolItem = true,
  42. tool = true,
  43. }
  44. local function check_modname_prefix(name)
  45. if name:sub(1,1) == ":" then
  46. -- Escape the modname prefix enforcement mechanism
  47. return name:sub(2)
  48. else
  49. -- Modname prefix enforcement
  50. local expected_prefix = core.get_current_modname() .. ":"
  51. if name:sub(1, #expected_prefix) ~= expected_prefix then
  52. error("Name " .. name .. " does not follow naming conventions: " ..
  53. "\"modname:\" or \":\" prefix required")
  54. end
  55. local subname = name:sub(#expected_prefix+1)
  56. if subname:find("[^abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_]") then
  57. error("Name " .. name .. " does not follow naming conventions: " ..
  58. "contains unallowed characters")
  59. end
  60. return name
  61. end
  62. end
  63. function core.register_abm(spec)
  64. -- Add to core.registered_abms
  65. core.registered_abms[#core.registered_abms+1] = spec
  66. end
  67. function core.register_entity(name, prototype)
  68. -- Check name
  69. if name == nil then
  70. error("Unable to register entity: Name is nil")
  71. end
  72. name = check_modname_prefix(tostring(name))
  73. prototype.name = name
  74. prototype.__index = prototype -- so that it can be used as a metatable
  75. -- Add to core.registered_entities
  76. core.registered_entities[name] = prototype
  77. end
  78. function core.register_item(name, itemdef)
  79. -- Check name
  80. if name == nil then
  81. error("Unable to register item: Name is nil")
  82. end
  83. name = check_modname_prefix(tostring(name))
  84. if forbidden_item_names[name] then
  85. error("Unable to register item: Name is forbidden: " .. name)
  86. end
  87. itemdef.name = name
  88. -- Apply defaults and add to registered_* table
  89. if itemdef.type == "node" then
  90. -- Use the nodebox as selection box if it's not set manually
  91. if itemdef.drawtype == "nodebox" and not itemdef.selection_box then
  92. itemdef.selection_box = itemdef.node_box
  93. elseif itemdef.drawtype == "fencelike" and not itemdef.selection_box then
  94. itemdef.selection_box = {
  95. type = "fixed",
  96. fixed = {-1/8, -1/2, -1/8, 1/8, 1/2, 1/8},
  97. }
  98. end
  99. setmetatable(itemdef, {__index = core.nodedef_default})
  100. core.registered_nodes[itemdef.name] = itemdef
  101. elseif itemdef.type == "craft" then
  102. setmetatable(itemdef, {__index = core.craftitemdef_default})
  103. core.registered_craftitems[itemdef.name] = itemdef
  104. elseif itemdef.type == "tool" then
  105. setmetatable(itemdef, {__index = core.tooldef_default})
  106. core.registered_tools[itemdef.name] = itemdef
  107. elseif itemdef.type == "none" then
  108. setmetatable(itemdef, {__index = core.noneitemdef_default})
  109. else
  110. error("Unable to register item: Type is invalid: " .. dump(itemdef))
  111. end
  112. -- Flowing liquid uses param2
  113. if itemdef.type == "node" and itemdef.liquidtype == "flowing" then
  114. itemdef.paramtype2 = "flowingliquid"
  115. end
  116. -- BEGIN Legacy stuff
  117. if itemdef.cookresult_itemstring ~= nil and itemdef.cookresult_itemstring ~= "" then
  118. core.register_craft({
  119. type="cooking",
  120. output=itemdef.cookresult_itemstring,
  121. recipe=itemdef.name,
  122. cooktime=itemdef.furnace_cooktime
  123. })
  124. end
  125. if itemdef.furnace_burntime ~= nil and itemdef.furnace_burntime >= 0 then
  126. core.register_craft({
  127. type="fuel",
  128. recipe=itemdef.name,
  129. burntime=itemdef.furnace_burntime
  130. })
  131. end
  132. -- END Legacy stuff
  133. -- Disable all further modifications
  134. getmetatable(itemdef).__newindex = {}
  135. --core.log("Registering item: " .. itemdef.name)
  136. core.registered_items[itemdef.name] = itemdef
  137. core.registered_aliases[itemdef.name] = nil
  138. register_item_raw(itemdef)
  139. end
  140. function core.register_node(name, nodedef)
  141. nodedef.type = "node"
  142. core.register_item(name, nodedef)
  143. end
  144. function core.register_craftitem(name, craftitemdef)
  145. craftitemdef.type = "craft"
  146. -- BEGIN Legacy stuff
  147. if craftitemdef.inventory_image == nil and craftitemdef.image ~= nil then
  148. craftitemdef.inventory_image = craftitemdef.image
  149. end
  150. -- END Legacy stuff
  151. core.register_item(name, craftitemdef)
  152. end
  153. function core.register_tool(name, tooldef)
  154. tooldef.type = "tool"
  155. tooldef.stack_max = 1
  156. -- BEGIN Legacy stuff
  157. if tooldef.inventory_image == nil and tooldef.image ~= nil then
  158. tooldef.inventory_image = tooldef.image
  159. end
  160. if tooldef.tool_capabilities == nil and
  161. (tooldef.full_punch_interval ~= nil or
  162. tooldef.basetime ~= nil or
  163. tooldef.dt_weight ~= nil or
  164. tooldef.dt_crackiness ~= nil or
  165. tooldef.dt_crumbliness ~= nil or
  166. tooldef.dt_cuttability ~= nil or
  167. tooldef.basedurability ~= nil or
  168. tooldef.dd_weight ~= nil or
  169. tooldef.dd_crackiness ~= nil or
  170. tooldef.dd_crumbliness ~= nil or
  171. tooldef.dd_cuttability ~= nil) then
  172. tooldef.tool_capabilities = {
  173. full_punch_interval = tooldef.full_punch_interval,
  174. basetime = tooldef.basetime,
  175. dt_weight = tooldef.dt_weight,
  176. dt_crackiness = tooldef.dt_crackiness,
  177. dt_crumbliness = tooldef.dt_crumbliness,
  178. dt_cuttability = tooldef.dt_cuttability,
  179. basedurability = tooldef.basedurability,
  180. dd_weight = tooldef.dd_weight,
  181. dd_crackiness = tooldef.dd_crackiness,
  182. dd_crumbliness = tooldef.dd_crumbliness,
  183. dd_cuttability = tooldef.dd_cuttability,
  184. }
  185. end
  186. -- END Legacy stuff
  187. core.register_item(name, tooldef)
  188. end
  189. function core.register_alias(name, convert_to)
  190. if forbidden_item_names[name] then
  191. error("Unable to register alias: Name is forbidden: " .. name)
  192. end
  193. if core.registered_items[name] ~= nil then
  194. core.log("WARNING: Not registering alias, item with same name" ..
  195. " is already defined: " .. name .. " -> " .. convert_to)
  196. else
  197. --core.log("Registering alias: " .. name .. " -> " .. convert_to)
  198. core.registered_aliases[name] = convert_to
  199. register_alias_raw(name, convert_to)
  200. end
  201. end
  202. local register_biome_raw = core.register_biome
  203. core.registered_biomes = {}
  204. function core.register_biome(biome)
  205. core.registered_biomes[biome.name] = biome
  206. register_biome_raw(biome)
  207. end
  208. function core.on_craft(itemstack, player, old_craft_list, craft_inv)
  209. for _, func in ipairs(core.registered_on_crafts) do
  210. itemstack = func(itemstack, player, old_craft_list, craft_inv) or itemstack
  211. end
  212. return itemstack
  213. end
  214. function core.craft_predict(itemstack, player, old_craft_list, craft_inv)
  215. for _, func in ipairs(core.registered_craft_predicts) do
  216. itemstack = func(itemstack, player, old_craft_list, craft_inv) or itemstack
  217. end
  218. return itemstack
  219. end
  220. -- Alias the forbidden item names to "" so they can't be
  221. -- created via itemstrings (e.g. /give)
  222. local name
  223. for name in pairs(forbidden_item_names) do
  224. core.registered_aliases[name] = ""
  225. register_alias_raw(name, "")
  226. end
  227. -- Deprecated:
  228. -- Aliases for core.register_alias (how ironic...)
  229. --core.alias_node = core.register_alias
  230. --core.alias_tool = core.register_alias
  231. --core.alias_craftitem = core.register_alias
  232. --
  233. -- Built-in node definitions. Also defined in C.
  234. --
  235. core.register_item(":unknown", {
  236. type = "none",
  237. description = "Unknown Item",
  238. inventory_image = "unknown_item.png",
  239. on_place = core.item_place,
  240. on_drop = core.item_drop,
  241. groups = {not_in_creative_inventory=1},
  242. diggable = true,
  243. })
  244. core.register_node(":air", {
  245. description = "Air (you hacker you!)",
  246. inventory_image = "unknown_node.png",
  247. wield_image = "unknown_node.png",
  248. drawtype = "airlike",
  249. paramtype = "light",
  250. sunlight_propagates = true,
  251. walkable = false,
  252. pointable = false,
  253. diggable = false,
  254. buildable_to = true,
  255. air_equivalent = true,
  256. drop = "",
  257. groups = {not_in_creative_inventory=1},
  258. })
  259. core.register_node(":ignore", {
  260. description = "Ignore (you hacker you!)",
  261. inventory_image = "unknown_node.png",
  262. wield_image = "unknown_node.png",
  263. drawtype = "airlike",
  264. paramtype = "none",
  265. sunlight_propagates = false,
  266. walkable = false,
  267. pointable = false,
  268. diggable = false,
  269. buildable_to = true, -- A way to remove accidentally placed ignores
  270. air_equivalent = true,
  271. drop = "",
  272. groups = {not_in_creative_inventory=1},
  273. })
  274. -- The hand (bare definition)
  275. core.register_item(":", {
  276. type = "none",
  277. groups = {not_in_creative_inventory=1},
  278. })
  279. function core.override_item(name, redefinition)
  280. if redefinition.name ~= nil then
  281. error("Attempt to redefine name of "..name.." to "..dump(redefinition.name), 2)
  282. end
  283. if redefinition.type ~= nil then
  284. error("Attempt to redefine type of "..name.." to "..dump(redefinition.type), 2)
  285. end
  286. local item = core.registered_items[name]
  287. if not item then
  288. error("Attempt to override non-existent item "..name, 2)
  289. end
  290. for k, v in pairs(redefinition) do
  291. rawset(item, k, v)
  292. end
  293. register_item_raw(item)
  294. end
  295. function core.run_callbacks(callbacks, mode, ...)
  296. assert(type(callbacks) == "table")
  297. local cb_len = #callbacks
  298. if cb_len == 0 then
  299. if mode == 2 or mode == 3 then
  300. return true
  301. elseif mode == 4 or mode == 5 then
  302. return false
  303. end
  304. end
  305. local ret = nil
  306. for i = 1, cb_len do
  307. local cb_ret = callbacks[i](...)
  308. if mode == 0 and i == 1 then
  309. ret = cb_ret
  310. elseif mode == 1 and i == cb_len then
  311. ret = cb_ret
  312. elseif mode == 2 then
  313. if not cb_ret or i == 1 then
  314. ret = cb_ret
  315. end
  316. elseif mode == 3 then
  317. if cb_ret then
  318. return cb_ret
  319. end
  320. ret = cb_ret
  321. elseif mode == 4 then
  322. if (cb_ret and not ret) or i == 1 then
  323. ret = cb_ret
  324. end
  325. elseif mode == 5 and cb_ret then
  326. return cb_ret
  327. end
  328. end
  329. return ret
  330. end
  331. --
  332. -- Callback registration
  333. --
  334. local function make_registration()
  335. local t = {}
  336. local registerfunc = function(func) table.insert(t, func) end
  337. return t, registerfunc
  338. end
  339. local function make_registration_reverse()
  340. local t = {}
  341. local registerfunc = function(func) table.insert(t, 1, func) end
  342. return t, registerfunc
  343. end
  344. core.registered_on_chat_messages, core.register_on_chat_message = make_registration()
  345. core.registered_globalsteps, core.register_globalstep = make_registration()
  346. core.registered_playerevents, core.register_playerevent = make_registration()
  347. core.registered_on_mapgen_inits, core.register_on_mapgen_init = make_registration()
  348. core.registered_on_shutdown, core.register_on_shutdown = make_registration()
  349. core.registered_on_punchnodes, core.register_on_punchnode = make_registration()
  350. core.registered_on_placenodes, core.register_on_placenode = make_registration()
  351. core.registered_on_dignodes, core.register_on_dignode = make_registration()
  352. core.registered_on_generateds, core.register_on_generated = make_registration()
  353. core.registered_on_newplayers, core.register_on_newplayer = make_registration()
  354. core.registered_on_dieplayers, core.register_on_dieplayer = make_registration()
  355. core.registered_on_respawnplayers, core.register_on_respawnplayer = make_registration()
  356. core.registered_on_prejoinplayers, core.register_on_prejoinplayer = make_registration()
  357. core.registered_on_joinplayers, core.register_on_joinplayer = make_registration()
  358. core.registered_on_leaveplayers, core.register_on_leaveplayer = make_registration()
  359. core.registered_on_player_receive_fields, core.register_on_player_receive_fields = make_registration_reverse()
  360. core.registered_on_cheats, core.register_on_cheat = make_registration()
  361. core.registered_on_crafts, core.register_on_craft = make_registration()
  362. core.registered_craft_predicts, core.register_craft_predict = make_registration()
  363. core.registered_on_protection_violation, core.register_on_protection_violation = make_registration()
  364. core.registered_on_item_eats, core.register_on_item_eat = make_registration()