register.lua 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511
  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. -- If the name starts with a colon, we can skip the modname prefix
  47. -- mechanism.
  48. return name:sub(2)
  49. else
  50. -- Enforce that the name starts with the correct mod name.
  51. local expected_prefix = core.get_current_modname() .. ":"
  52. if name:sub(1, #expected_prefix) ~= expected_prefix then
  53. error("Name " .. name .. " does not follow naming conventions: " ..
  54. "\"" .. expected_prefix .. "\" or \":\" prefix required")
  55. end
  56. -- Enforce that the name only contains letters, numbers and underscores.
  57. local subname = name:sub(#expected_prefix+1)
  58. if subname:find("[^%w_]") then
  59. error("Name " .. name .. " does not follow naming conventions: " ..
  60. "contains unallowed characters")
  61. end
  62. return name
  63. end
  64. end
  65. function core.register_abm(spec)
  66. -- Add to core.registered_abms
  67. core.registered_abms[#core.registered_abms+1] = spec
  68. spec.mod_origin = core.get_current_modname() or "??"
  69. end
  70. function core.register_entity(name, prototype)
  71. -- Check name
  72. if name == nil then
  73. error("Unable to register entity: Name is nil")
  74. end
  75. name = check_modname_prefix(tostring(name))
  76. prototype.name = name
  77. prototype.__index = prototype -- so that it can be used as a metatable
  78. -- Add to core.registered_entities
  79. core.registered_entities[name] = prototype
  80. prototype.mod_origin = core.get_current_modname() or "??"
  81. end
  82. function core.register_item(name, itemdef)
  83. -- Check name
  84. if name == nil then
  85. error("Unable to register item: Name is nil")
  86. end
  87. name = check_modname_prefix(tostring(name))
  88. if forbidden_item_names[name] then
  89. error("Unable to register item: Name is forbidden: " .. name)
  90. end
  91. itemdef.name = name
  92. -- Apply defaults and add to registered_* table
  93. if itemdef.type == "node" then
  94. -- Use the nodebox as selection box if it's not set manually
  95. if itemdef.drawtype == "nodebox" and not itemdef.selection_box then
  96. itemdef.selection_box = itemdef.node_box
  97. elseif itemdef.drawtype == "fencelike" and not itemdef.selection_box then
  98. itemdef.selection_box = {
  99. type = "fixed",
  100. fixed = {-1/8, -1/2, -1/8, 1/8, 1/2, 1/8},
  101. }
  102. end
  103. setmetatable(itemdef, {__index = core.nodedef_default})
  104. core.registered_nodes[itemdef.name] = itemdef
  105. elseif itemdef.type == "craft" then
  106. setmetatable(itemdef, {__index = core.craftitemdef_default})
  107. core.registered_craftitems[itemdef.name] = itemdef
  108. elseif itemdef.type == "tool" then
  109. setmetatable(itemdef, {__index = core.tooldef_default})
  110. core.registered_tools[itemdef.name] = itemdef
  111. elseif itemdef.type == "none" then
  112. setmetatable(itemdef, {__index = core.noneitemdef_default})
  113. else
  114. error("Unable to register item: Type is invalid: " .. dump(itemdef))
  115. end
  116. -- Flowing liquid uses param2
  117. if itemdef.type == "node" and itemdef.liquidtype == "flowing" then
  118. itemdef.paramtype2 = "flowingliquid"
  119. end
  120. -- BEGIN Legacy stuff
  121. if itemdef.cookresult_itemstring ~= nil and itemdef.cookresult_itemstring ~= "" then
  122. core.register_craft({
  123. type="cooking",
  124. output=itemdef.cookresult_itemstring,
  125. recipe=itemdef.name,
  126. cooktime=itemdef.furnace_cooktime
  127. })
  128. end
  129. if itemdef.furnace_burntime ~= nil and itemdef.furnace_burntime >= 0 then
  130. core.register_craft({
  131. type="fuel",
  132. recipe=itemdef.name,
  133. burntime=itemdef.furnace_burntime
  134. })
  135. end
  136. -- END Legacy stuff
  137. itemdef.mod_origin = core.get_current_modname() or "??"
  138. -- Disable all further modifications
  139. getmetatable(itemdef).__newindex = {}
  140. --core.log("Registering item: " .. itemdef.name)
  141. core.registered_items[itemdef.name] = itemdef
  142. core.registered_aliases[itemdef.name] = nil
  143. register_item_raw(itemdef)
  144. end
  145. function core.register_node(name, nodedef)
  146. nodedef.type = "node"
  147. core.register_item(name, nodedef)
  148. end
  149. function core.register_craftitem(name, craftitemdef)
  150. craftitemdef.type = "craft"
  151. -- BEGIN Legacy stuff
  152. if craftitemdef.inventory_image == nil and craftitemdef.image ~= nil then
  153. craftitemdef.inventory_image = craftitemdef.image
  154. end
  155. -- END Legacy stuff
  156. core.register_item(name, craftitemdef)
  157. end
  158. function core.register_tool(name, tooldef)
  159. tooldef.type = "tool"
  160. tooldef.stack_max = 1
  161. -- BEGIN Legacy stuff
  162. if tooldef.inventory_image == nil and tooldef.image ~= nil then
  163. tooldef.inventory_image = tooldef.image
  164. end
  165. if tooldef.tool_capabilities == nil and
  166. (tooldef.full_punch_interval ~= nil or
  167. tooldef.basetime ~= nil or
  168. tooldef.dt_weight ~= nil or
  169. tooldef.dt_crackiness ~= nil or
  170. tooldef.dt_crumbliness ~= nil or
  171. tooldef.dt_cuttability ~= nil or
  172. tooldef.basedurability ~= nil or
  173. tooldef.dd_weight ~= nil or
  174. tooldef.dd_crackiness ~= nil or
  175. tooldef.dd_crumbliness ~= nil or
  176. tooldef.dd_cuttability ~= nil) then
  177. tooldef.tool_capabilities = {
  178. full_punch_interval = tooldef.full_punch_interval,
  179. basetime = tooldef.basetime,
  180. dt_weight = tooldef.dt_weight,
  181. dt_crackiness = tooldef.dt_crackiness,
  182. dt_crumbliness = tooldef.dt_crumbliness,
  183. dt_cuttability = tooldef.dt_cuttability,
  184. basedurability = tooldef.basedurability,
  185. dd_weight = tooldef.dd_weight,
  186. dd_crackiness = tooldef.dd_crackiness,
  187. dd_crumbliness = tooldef.dd_crumbliness,
  188. dd_cuttability = tooldef.dd_cuttability,
  189. }
  190. end
  191. -- END Legacy stuff
  192. core.register_item(name, tooldef)
  193. end
  194. function core.register_alias(name, convert_to)
  195. if forbidden_item_names[name] then
  196. error("Unable to register alias: Name is forbidden: " .. name)
  197. end
  198. if core.registered_items[name] ~= nil then
  199. core.log("warning", "Not registering alias, item with same name" ..
  200. " is already defined: " .. name .. " -> " .. convert_to)
  201. else
  202. --core.log("Registering alias: " .. name .. " -> " .. convert_to)
  203. core.registered_aliases[name] = convert_to
  204. register_alias_raw(name, convert_to)
  205. end
  206. end
  207. function core.on_craft(itemstack, player, old_craft_list, craft_inv)
  208. for _, func in ipairs(core.registered_on_crafts) do
  209. itemstack = func(itemstack, player, old_craft_list, craft_inv) or itemstack
  210. end
  211. return itemstack
  212. end
  213. function core.craft_predict(itemstack, player, old_craft_list, craft_inv)
  214. for _, func in ipairs(core.registered_craft_predicts) do
  215. itemstack = func(itemstack, player, old_craft_list, craft_inv) or itemstack
  216. end
  217. return itemstack
  218. end
  219. -- Alias the forbidden item names to "" so they can't be
  220. -- created via itemstrings (e.g. /give)
  221. local name
  222. for name in pairs(forbidden_item_names) do
  223. core.registered_aliases[name] = ""
  224. register_alias_raw(name, "")
  225. end
  226. -- Deprecated:
  227. -- Aliases for core.register_alias (how ironic...)
  228. --core.alias_node = core.register_alias
  229. --core.alias_tool = core.register_alias
  230. --core.alias_craftitem = core.register_alias
  231. --
  232. -- Built-in node definitions. Also defined in C.
  233. --
  234. core.register_item(":unknown", {
  235. type = "none",
  236. description = "Unknown Item",
  237. inventory_image = "unknown_item.png",
  238. on_place = core.item_place,
  239. on_secondary_use = core.item_secondary_use,
  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. floodable = true,
  256. air_equivalent = true,
  257. drop = "",
  258. groups = {not_in_creative_inventory=1},
  259. })
  260. core.register_node(":ignore", {
  261. description = "Ignore (you hacker you!)",
  262. inventory_image = "unknown_node.png",
  263. wield_image = "unknown_node.png",
  264. drawtype = "airlike",
  265. paramtype = "none",
  266. sunlight_propagates = false,
  267. walkable = false,
  268. pointable = false,
  269. diggable = false,
  270. buildable_to = true, -- A way to remove accidentally placed ignores
  271. air_equivalent = true,
  272. drop = "",
  273. groups = {not_in_creative_inventory=1},
  274. })
  275. -- The hand (bare definition)
  276. core.register_item(":", {
  277. type = "none",
  278. groups = {not_in_creative_inventory=1},
  279. })
  280. function core.override_item(name, redefinition)
  281. if redefinition.name ~= nil then
  282. error("Attempt to redefine name of "..name.." to "..dump(redefinition.name), 2)
  283. end
  284. if redefinition.type ~= nil then
  285. error("Attempt to redefine type of "..name.." to "..dump(redefinition.type), 2)
  286. end
  287. local item = core.registered_items[name]
  288. if not item then
  289. error("Attempt to override non-existent item "..name, 2)
  290. end
  291. for k, v in pairs(redefinition) do
  292. rawset(item, k, v)
  293. end
  294. register_item_raw(item)
  295. end
  296. core.callback_origins = {}
  297. function core.run_callbacks(callbacks, mode, ...)
  298. assert(type(callbacks) == "table")
  299. local cb_len = #callbacks
  300. if cb_len == 0 then
  301. if mode == 2 or mode == 3 then
  302. return true
  303. elseif mode == 4 or mode == 5 then
  304. return false
  305. end
  306. end
  307. local ret = nil
  308. for i = 1, cb_len do
  309. local origin = core.callback_origins[callbacks[i]]
  310. if origin then
  311. core.set_last_run_mod(origin.mod)
  312. --print("Running " .. tostring(callbacks[i]) ..
  313. -- " (a " .. origin.name .. " callback in " .. origin.mod .. ")")
  314. else
  315. --print("No data associated with callback")
  316. end
  317. local cb_ret = callbacks[i](...)
  318. if mode == 0 and i == 1 then
  319. ret = cb_ret
  320. elseif mode == 1 and i == cb_len then
  321. ret = cb_ret
  322. elseif mode == 2 then
  323. if not cb_ret or i == 1 then
  324. ret = cb_ret
  325. end
  326. elseif mode == 3 then
  327. if cb_ret then
  328. return cb_ret
  329. end
  330. ret = cb_ret
  331. elseif mode == 4 then
  332. if (cb_ret and not ret) or i == 1 then
  333. ret = cb_ret
  334. end
  335. elseif mode == 5 and cb_ret then
  336. return cb_ret
  337. end
  338. end
  339. return ret
  340. end
  341. --
  342. -- Callback registration
  343. --
  344. local function make_registration()
  345. local t = {}
  346. local registerfunc = function(func)
  347. table.insert(t, func)
  348. core.callback_origins[func] = {
  349. mod = core.get_current_modname() or "??",
  350. name = debug.getinfo(1, "n").name or "??"
  351. }
  352. --local origin = core.callback_origins[func]
  353. --print(origin.name .. ": " .. origin.mod .. " registering cbk " .. tostring(func))
  354. end
  355. return t, registerfunc
  356. end
  357. local function make_registration_reverse()
  358. local t = {}
  359. local registerfunc = function(func)
  360. table.insert(t, 1, func)
  361. core.callback_origins[func] = {
  362. mod = core.get_current_modname() or "??",
  363. name = debug.getinfo(1, "n").name or "??"
  364. }
  365. --local origin = core.callback_origins[func]
  366. --print(origin.name .. ": " .. origin.mod .. " registering cbk " .. tostring(func))
  367. end
  368. return t, registerfunc
  369. end
  370. local function make_registration_wrap(reg_fn_name, clear_fn_name)
  371. local list = {}
  372. local orig_reg_fn = core[reg_fn_name]
  373. core[reg_fn_name] = function(def)
  374. local retval = orig_reg_fn(def)
  375. if retval ~= nil then
  376. if def.name ~= nil then
  377. list[def.name] = def
  378. else
  379. list[retval] = def
  380. end
  381. end
  382. return retval
  383. end
  384. local orig_clear_fn = core[clear_fn_name]
  385. core[clear_fn_name] = function()
  386. for k in pairs(list) do
  387. list[k] = nil
  388. end
  389. return orig_clear_fn()
  390. end
  391. return list
  392. end
  393. core.registered_on_player_hpchanges = { modifiers = { }, loggers = { } }
  394. function core.registered_on_player_hpchange(player, hp_change)
  395. local last = false
  396. for i = #core.registered_on_player_hpchanges.modifiers, 1, -1 do
  397. local func = core.registered_on_player_hpchanges.modifiers[i]
  398. hp_change, last = func(player, hp_change)
  399. if type(hp_change) ~= "number" then
  400. local debuginfo = debug.getinfo(func)
  401. error("The register_on_hp_changes function has to return a number at " ..
  402. debuginfo.short_src .. " line " .. debuginfo.linedefined)
  403. end
  404. if last then
  405. break
  406. end
  407. end
  408. for i, func in ipairs(core.registered_on_player_hpchanges.loggers) do
  409. func(player, hp_change)
  410. end
  411. return hp_change
  412. end
  413. function core.register_on_player_hpchange(func, modifier)
  414. if modifier then
  415. table.insert(core.registered_on_player_hpchanges.modifiers, func)
  416. else
  417. table.insert(core.registered_on_player_hpchanges.loggers, func)
  418. end
  419. core.callback_origins[func] = {
  420. mod = core.get_current_modname() or "??",
  421. name = debug.getinfo(1, "n").name or "??"
  422. }
  423. end
  424. core.registered_biomes = make_registration_wrap("register_biome", "clear_registered_biomes")
  425. core.registered_ores = make_registration_wrap("register_ore", "clear_registered_ores")
  426. core.registered_decorations = make_registration_wrap("register_decoration", "clear_registered_decorations")
  427. core.registered_on_chat_messages, core.register_on_chat_message = make_registration()
  428. core.registered_globalsteps, core.register_globalstep = make_registration()
  429. core.registered_playerevents, core.register_playerevent = make_registration()
  430. core.registered_on_shutdown, core.register_on_shutdown = make_registration()
  431. core.registered_on_punchnodes, core.register_on_punchnode = make_registration()
  432. core.registered_on_placenodes, core.register_on_placenode = make_registration()
  433. core.registered_on_dignodes, core.register_on_dignode = make_registration()
  434. core.registered_on_generateds, core.register_on_generated = make_registration()
  435. core.registered_on_newplayers, core.register_on_newplayer = make_registration()
  436. core.registered_on_dieplayers, core.register_on_dieplayer = make_registration()
  437. core.registered_on_respawnplayers, core.register_on_respawnplayer = make_registration()
  438. core.registered_on_prejoinplayers, core.register_on_prejoinplayer = make_registration()
  439. core.registered_on_joinplayers, core.register_on_joinplayer = make_registration()
  440. core.registered_on_leaveplayers, core.register_on_leaveplayer = make_registration()
  441. core.registered_on_player_receive_fields, core.register_on_player_receive_fields = make_registration_reverse()
  442. core.registered_on_cheats, core.register_on_cheat = make_registration()
  443. core.registered_on_crafts, core.register_on_craft = make_registration()
  444. core.registered_craft_predicts, core.register_craft_predict = make_registration()
  445. core.registered_on_protection_violation, core.register_on_protection_violation = make_registration()
  446. core.registered_on_item_eats, core.register_on_item_eat = make_registration()
  447. core.registered_on_punchplayers, core.register_on_punchplayer = make_registration()
  448. --
  449. -- Compatibility for on_mapgen_init()
  450. --
  451. core.register_on_mapgen_init = function(func) func(core.get_mapgen_params()) end