2
0

entity.lua 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236
  1. local log = {}
  2. local function insert_log(...)
  3. log[#log+1] = string.format(...)
  4. end
  5. local function objref_str(self, ref)
  6. if ref and ref:is_player() then
  7. return "player"
  8. end
  9. return self.object == ref and "self" or tostring(ref)
  10. end
  11. core.register_entity("unittests:callbacks", {
  12. initial_properties = {
  13. hp_max = 5,
  14. visual = "upright_sprite",
  15. textures = { "unittests_callback.png" },
  16. static_save = false,
  17. },
  18. on_activate = function(self, staticdata, dtime_s)
  19. self.object:set_armor_groups({test = 100})
  20. assert(self.object:get_hp() == self.initial_properties.hp_max)
  21. insert_log("on_activate(%d)", #staticdata)
  22. end,
  23. on_deactivate = function(self, removal)
  24. insert_log("on_deactivate(%s)", tostring(removal))
  25. end,
  26. on_punch = function(self, puncher, time_from_last_punch, tool_capabilities, dir, damage)
  27. insert_log("on_punch(%s, %.1f, %d)", objref_str(self, puncher),
  28. time_from_last_punch, damage)
  29. end,
  30. on_death = function(self, killer)
  31. assert(self.object:get_hp() == 0)
  32. insert_log("on_death(%s)", objref_str(self, killer))
  33. end,
  34. on_rightclick = function(self, clicker)
  35. insert_log("on_rightclick(%s)", objref_str(self, clicker))
  36. end,
  37. on_attach_child = function(self, child)
  38. insert_log("on_attach_child(%s)", objref_str(self, child))
  39. assert(child:get_attach() == self.object)
  40. local ok = false
  41. for _, obj in ipairs(self.object:get_children()) do
  42. if obj == child then
  43. ok = true
  44. end
  45. end
  46. assert(ok, "Child not found in get_children")
  47. end,
  48. on_detach_child = function(self, child)
  49. insert_log("on_detach_child(%s)", objref_str(self, child))
  50. assert(child:get_attach() == nil)
  51. local ok = true
  52. for _, obj in ipairs(self.object:get_children()) do
  53. if obj == child then
  54. ok = false
  55. end
  56. end
  57. assert(ok, "Former child found in get_children")
  58. end,
  59. on_detach = function(self, parent)
  60. insert_log("on_detach(%s)", objref_str(self, parent))
  61. assert(self.object:get_attach() == nil)
  62. local ok = true
  63. for _, obj in ipairs(parent:get_children()) do
  64. if obj == self.object then
  65. ok = false
  66. end
  67. end
  68. assert(ok, "Former child found in get_children")
  69. end,
  70. get_staticdata = function(self)
  71. assert(false)
  72. end,
  73. })
  74. --
  75. local function check_log(expect)
  76. if #expect ~= #log then
  77. error("Log mismatch: " .. core.write_json(log))
  78. end
  79. for i, s in ipairs(expect) do
  80. if log[i] ~= s then
  81. error("Log mismatch at " .. i .. ": " .. core.write_json(log))
  82. end
  83. end
  84. log = {} -- clear it for next time
  85. end
  86. local function test_entity_lifecycle(_, pos)
  87. log = {}
  88. -- with binary in staticdata
  89. local obj = core.add_entity(pos, "unittests:callbacks", "abc\000def")
  90. assert(obj and obj:is_valid())
  91. check_log({"on_activate(7)"})
  92. obj:set_hp(0)
  93. check_log({"on_death(nil)", "on_deactivate(true)"})
  94. assert(not obj:is_valid())
  95. end
  96. unittests.register("test_entity_lifecycle", test_entity_lifecycle, {map=true})
  97. local function test_entity_interact(_, pos)
  98. log = {}
  99. local obj = core.add_entity(pos, "unittests:callbacks")
  100. check_log({"on_activate(0)"})
  101. -- rightclick
  102. obj:right_click(obj)
  103. check_log({"on_rightclick(self)"})
  104. -- useless punch
  105. obj:punch(obj, 0.5, {})
  106. check_log({"on_punch(self, 0.5, 0)"})
  107. -- fatal punch
  108. obj:punch(obj, 1.9, {
  109. full_punch_interval = 1.0,
  110. damage_groups = { test = 10 },
  111. })
  112. check_log({
  113. -- does 10 damage even though we only have 5 hp
  114. "on_punch(self, 1.9, 10)",
  115. "on_death(self)",
  116. "on_deactivate(true)"
  117. })
  118. end
  119. unittests.register("test_entity_interact", test_entity_interact, {map=true})
  120. local function test_entity_attach(player, pos)
  121. log = {}
  122. local obj = core.add_entity(pos, "unittests:callbacks")
  123. check_log({"on_activate(0)"})
  124. -- attach player to entity
  125. player:set_attach(obj)
  126. check_log({"on_attach_child(player)"})
  127. assert(player:get_attach() == obj)
  128. player:set_detach()
  129. check_log({"on_detach_child(player)"})
  130. assert(player:get_attach() == nil)
  131. -- attach entity to player
  132. obj:set_attach(player)
  133. check_log({})
  134. assert(obj:get_attach() == player)
  135. obj:set_detach()
  136. check_log({"on_detach(player)"})
  137. assert(obj:get_attach() == nil)
  138. obj:remove()
  139. end
  140. unittests.register("test_entity_attach", test_entity_attach, {player=true, map=true})
  141. ---------
  142. core.register_entity("unittests:dummy", {
  143. initial_properties = {
  144. hp_max = 1,
  145. visual = "upright_sprite",
  146. textures = { "no_texture.png" },
  147. static_save = false,
  148. },
  149. })
  150. local function test_entity_raycast(_, pos)
  151. local obj1 = core.add_entity(pos, "unittests:dummy")
  152. local obj2 = core.add_entity(pos:offset(1, 0, 0), "unittests:dummy")
  153. local raycast = core.raycast(pos:offset(-1, 0, 0), pos:offset(2, 0, 0), true, false)
  154. for pt in raycast do
  155. if pt.type == "object" then
  156. assert(pt.ref == obj1)
  157. obj1:remove()
  158. obj2:remove()
  159. obj1 = nil -- object should be hit exactly one
  160. end
  161. end
  162. assert(obj1 == nil)
  163. end
  164. unittests.register("test_entity_raycast", test_entity_raycast, {map=true})
  165. local function test_object_iterator(pos, make_iterator)
  166. local obj1 = core.add_entity(pos, "unittests:dummy")
  167. local obj2 = core.add_entity(pos, "unittests:dummy")
  168. assert(obj1 and obj2)
  169. local found = false
  170. -- As soon as we find one of the objects, we remove both, invalidating the other.
  171. for obj in make_iterator() do
  172. assert(obj:is_valid())
  173. if obj == obj1 or obj == obj2 then
  174. obj1:remove()
  175. obj2:remove()
  176. found = true
  177. end
  178. end
  179. assert(found)
  180. end
  181. unittests.register("test_objects_inside_radius", function(_, pos)
  182. test_object_iterator(pos, function()
  183. return core.objects_inside_radius(pos, 1)
  184. end)
  185. end, {map=true})
  186. unittests.register("test_objects_in_area", function(_, pos)
  187. test_object_iterator(pos, function()
  188. return core.objects_in_area(pos:offset(-1, -1, -1), pos:offset(1, 1, 1))
  189. end)
  190. end, {map=true})
  191. -- Tests that bone rotation euler angles are preserved (see #14992)
  192. local function test_get_bone_rot(_, pos)
  193. local obj = core.add_entity(pos, "unittests:dummy")
  194. for _ = 1, 100 do
  195. local function assert_similar(euler_angles)
  196. local _, rot = obj:get_bone_position("bonename")
  197. assert(euler_angles:distance(rot) < 1e-3)
  198. local override = obj:get_bone_override("bonename")
  199. assert(euler_angles:distance(override.rotation.vec:apply(math.deg)) < 1e-3)
  200. end
  201. local deg = 1e3 * vector.new(math.random(), math.random(), math.random())
  202. obj:set_bone_position("bonename", vector.zero(), deg)
  203. assert_similar(deg)
  204. local rad = 3 * math.pi * vector.new(math.random(), math.random(), math.random())
  205. obj:set_bone_override("bonename", {rotation = {vec = rad}})
  206. assert_similar(rad:apply(math.deg))
  207. end
  208. end
  209. unittests.register("test_get_bone_rot", test_get_bone_rot, {map=true})