init.lua 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155
  1. --mt_api_addons
  2. --License: MIT License
  3. --Event registration lists
  4. minetest.registered_removeentity_events = {}
  5. minetest.registered_clear_objects_events = {}
  6. minetest.registered_playerstep_events = {}
  7. --Hooks a function onto a function
  8. local function hook(func, func2)
  9. if type(func) == "function" then
  10. return function(...)
  11. func2(...)
  12. return func(...)
  13. end
  14. end
  15. return nil
  16. end
  17. --Handler needed for specific events
  18. local function do_handler(category, ...)
  19. local events = minetest["registered_"..category.."_events"]
  20. if events then
  21. for count,func in pairs(events) do
  22. func(...)
  23. end
  24. end
  25. end
  26. --Handle playerstep events
  27. local function handle_playerstep_events(dtime)
  28. local events = minetest.registered_playerstep_events
  29. if events then
  30. for _,player in pairs(minetest.get_connected_players()) do
  31. for count,event in pairs(events) do
  32. local name = player:get_player_name()
  33. local interval = event.interval
  34. if not minetest.registered_playerstep_events[count].players[name] then
  35. minetest.registered_playerstep_events[count].players[name] = {time = 0}
  36. end
  37. local time = minetest.registered_playerstep_events[count].players[name].time
  38. time = time + dtime
  39. if time >= interval then
  40. event.func(player, dtime)
  41. minetest.registered_playerstep_events[count].players[name].time = 0
  42. else
  43. minetest.registered_playerstep_events[count].players[name].time = time
  44. end
  45. end
  46. end
  47. else
  48. return
  49. end
  50. end
  51. --Use globalstep to handle playerstep events
  52. minetest.register_globalstep(function(dtime)
  53. handle_playerstep_events(dtime)
  54. end)
  55. --Safely injects a hook to builtin function clear_objects
  56. core.clear_objects = hook(core.clear_objects, function(option)
  57. do_handler("clear_objects", option)
  58. end)
  59. --Safely Inject hooks to all registered entities after all mods have been loaded
  60. minetest.register_on_mods_loaded(function(player)
  61. for name,def in pairs(minetest.registered_entities) do
  62. minetest.registered_entities[name].get_staticdata = hook(def.get_staticdata, function(self)
  63. if not self.hook_injected then
  64. local meta = getmetatable(self.object)
  65. meta.remove = hook(meta.remove, function(self)
  66. --get entity properties
  67. self = self:get_luaentity()
  68. if not(self.removed or self.removed == true) then
  69. self.removed = true
  70. do_handler("removeentity", self)
  71. end
  72. end)
  73. --Update objectref's Metatable
  74. setmetatable(meta, meta)
  75. end
  76. end)
  77. end
  78. minetest.log("action", "Entity on_remove hook injected successfully.")
  79. end)
  80. --Backwards compatability substitute for on_rightclickplayer (for those who are using outdated clients)
  81. if not minetest.register_on_rightclickplayer then
  82. local update_interval = minetest.settings:get("player_rightclick_step") or 0.1
  83. minetest.registered_rightclickplayer_events = {}
  84. --Check if the player right-clicked a player
  85. local function verify_clicked_player(clicker, range)
  86. local result = nil
  87. local ray_start = vector.add(clicker:get_pos(), {x=0, y= clicker:get_properties().eye_height, z=0})
  88. local ray_modif = vector.add(vector.multiply(clicker:get_look_dir(), range), clicker:get_eye_offset())
  89. local ray_end = vector.add(ray_start, ray_modif)
  90. local ray = minetest.raycast(ray_start, ray_end, true, false)
  91. local clicked = ray:next()
  92. clicked = ray:next()
  93. if clicked and clicked.type == "object" and clicked.ref:is_player() and clicked.ref ~= clicker then
  94. result = clicked.ref
  95. end
  96. return result
  97. end
  98. --Handle rightclicking for older minetest versions
  99. local function handle_rightclickplayer()
  100. local events = minetest.registered_rightclickplayer_events
  101. if events then
  102. for _,clicker in pairs(minetest.get_connected_players()) do
  103. local right_click = clicker:get_player_control().RMB or false
  104. if clicker and right_click == true then
  105. local name = clicker:get_player_name()
  106. local clicked = verify_clicked_player(clicker, 4)
  107. if clicked then
  108. for _,func in pairs(events) do
  109. func(clicker, clicked)
  110. end
  111. end
  112. break
  113. end
  114. end
  115. minetest.after(update_interval, function()
  116. handle_rightclickplayer()
  117. end)
  118. end
  119. end
  120. --Register on rightclick player (Called when a player rightclicked a fellow player)
  121. function minetest.register_on_rightclickplayer(func)
  122. assert(type(func) == "function", "you must include a function with the following arguements (player, clicker).")
  123. table.insert(minetest.registered_rightclickplayer_events, func)
  124. end
  125. end
  126. --Register on playerstep (Just like globalstep, but specifically for players. interval included for convenience and performance reasons)
  127. function minetest.register_playerstep(interval, func)
  128. assert(interval and type(interval) == "number", "must include a interval number value.")
  129. assert(func and type(func) == "function", "must include a function with the following arguements (dtime).")
  130. table.insert(minetest.registered_playerstep_events, {["players"] = {}, ["interval"] = interval, ["func"] = func})
  131. end
  132. --Register on remove entity (Called after objectref:remove() gets called)
  133. function minetest.register_on_removeentity(func)
  134. assert(type(func) == "function", "you must include a function with the following arguement (self).")
  135. table.insert(minetest.registered_removeentity_events, func)
  136. end
  137. --Register on remove entity (Called when builtin core.clear_objects() gets called)
  138. function minetest.register_on_clearobjects(func)
  139. assert(type(func) == "function", "you must include a function with the following arguement (option).")
  140. table.insert(minetest.registered_clear_objects_events, func)
  141. end