unit_sao.cpp 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369
  1. /*
  2. Minetest
  3. Copyright (C) 2010-2013 celeron55, Perttu Ahola <celeron55@gmail.com>
  4. Copyright (C) 2013-2020 Minetest core developers & community
  5. This program is free software; you can redistribute it and/or modify
  6. it under the terms of the GNU Lesser General Public License as published by
  7. the Free Software Foundation; either version 2.1 of the License, or
  8. (at your option) any later version.
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. GNU Lesser General Public License for more details.
  13. You should have received a copy of the GNU Lesser General Public License along
  14. with this program; if not, write to the Free Software Foundation, Inc.,
  15. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  16. */
  17. #include "unit_sao.h"
  18. #include "scripting_server.h"
  19. #include "serverenvironment.h"
  20. UnitSAO::UnitSAO(ServerEnvironment *env, v3f pos) : ServerActiveObject(env, pos)
  21. {
  22. // Initialize something to armor groups
  23. m_armor_groups["fleshy"] = 100;
  24. }
  25. ServerActiveObject *UnitSAO::getParent() const
  26. {
  27. if (!m_attachment_parent_id)
  28. return nullptr;
  29. // Check if the parent still exists
  30. ServerActiveObject *obj = m_env->getActiveObject(m_attachment_parent_id);
  31. return obj;
  32. }
  33. void UnitSAO::setArmorGroups(const ItemGroupList &armor_groups)
  34. {
  35. m_armor_groups = armor_groups;
  36. m_armor_groups_sent = false;
  37. }
  38. const ItemGroupList &UnitSAO::getArmorGroups() const
  39. {
  40. return m_armor_groups;
  41. }
  42. void UnitSAO::setAnimation(
  43. v2f frame_range, float frame_speed, float frame_blend, bool frame_loop)
  44. {
  45. // store these so they can be updated to clients
  46. m_animation_range = frame_range;
  47. m_animation_speed = frame_speed;
  48. m_animation_blend = frame_blend;
  49. m_animation_loop = frame_loop;
  50. m_animation_sent = false;
  51. }
  52. void UnitSAO::getAnimation(v2f *frame_range, float *frame_speed, float *frame_blend,
  53. bool *frame_loop)
  54. {
  55. *frame_range = m_animation_range;
  56. *frame_speed = m_animation_speed;
  57. *frame_blend = m_animation_blend;
  58. *frame_loop = m_animation_loop;
  59. }
  60. void UnitSAO::setAnimationSpeed(float frame_speed)
  61. {
  62. m_animation_speed = frame_speed;
  63. m_animation_speed_sent = false;
  64. }
  65. void UnitSAO::setBonePosition(const std::string &bone, v3f position, v3f rotation)
  66. {
  67. // store these so they can be updated to clients
  68. m_bone_position[bone] = core::vector2d<v3f>(position, rotation);
  69. m_bone_position_sent = false;
  70. }
  71. void UnitSAO::getBonePosition(const std::string &bone, v3f *position, v3f *rotation)
  72. {
  73. auto it = m_bone_position.find(bone);
  74. if (it != m_bone_position.end()) {
  75. *position = it->second.X;
  76. *rotation = it->second.Y;
  77. }
  78. }
  79. // clang-format off
  80. void UnitSAO::sendOutdatedData()
  81. {
  82. if (!m_armor_groups_sent) {
  83. m_armor_groups_sent = true;
  84. m_messages_out.emplace(getId(), true, generateUpdateArmorGroupsCommand());
  85. }
  86. if (!m_animation_sent) {
  87. m_animation_sent = true;
  88. m_animation_speed_sent = true;
  89. m_messages_out.emplace(getId(), true, generateUpdateAnimationCommand());
  90. } else if (!m_animation_speed_sent) {
  91. // Animation speed is also sent when 'm_animation_sent == false'
  92. m_animation_speed_sent = true;
  93. m_messages_out.emplace(getId(), true, generateUpdateAnimationSpeedCommand());
  94. }
  95. if (!m_bone_position_sent) {
  96. m_bone_position_sent = true;
  97. for (const auto &bone_pos : m_bone_position) {
  98. m_messages_out.emplace(getId(), true, generateUpdateBonePositionCommand(
  99. bone_pos.first, bone_pos.second.X, bone_pos.second.Y));
  100. }
  101. }
  102. if (!m_attachment_sent) {
  103. m_attachment_sent = true;
  104. m_messages_out.emplace(getId(), true, generateUpdateAttachmentCommand());
  105. }
  106. }
  107. // clang-format on
  108. void UnitSAO::setAttachment(int parent_id, const std::string &bone, v3f position,
  109. v3f rotation, bool force_visible)
  110. {
  111. auto *obj = parent_id ? m_env->getActiveObject(parent_id) : nullptr;
  112. if (obj) {
  113. // Do checks to avoid circular references
  114. // The chain of wanted parent must not refer or contain "this"
  115. for (obj = obj->getParent(); obj; obj = obj->getParent()) {
  116. if (obj == this) {
  117. warningstream << "Mod bug: Attempted to attach object " << m_id << " to parent "
  118. << parent_id << " but former is an (in)direct parent of latter." << std::endl;
  119. return;
  120. }
  121. }
  122. }
  123. // Attachments need to be handled on both the server and client.
  124. // If we just attach on the server, we can only copy the position of the parent.
  125. // Attachments are still sent to clients at an interval so players might see them
  126. // lagging, plus we can't read and attach to skeletal bones. If we just attach on
  127. // the client, the server still sees the child at its original location. This
  128. // breaks some things so we also give the server the most accurate representation
  129. // even if players only see the client changes.
  130. int old_parent = m_attachment_parent_id;
  131. m_attachment_parent_id = parent_id;
  132. // The detach callbacks might call to setAttachment() again.
  133. // Ensure the attachment params are applied after this callback is run.
  134. if (parent_id != old_parent)
  135. onDetach(old_parent);
  136. m_attachment_parent_id = parent_id;
  137. m_attachment_bone = bone;
  138. m_attachment_position = position;
  139. m_attachment_rotation = rotation;
  140. m_force_visible = force_visible;
  141. m_attachment_sent = false;
  142. if (parent_id != old_parent)
  143. onAttach(parent_id);
  144. }
  145. void UnitSAO::getAttachment(int *parent_id, std::string *bone, v3f *position,
  146. v3f *rotation, bool *force_visible) const
  147. {
  148. *parent_id = m_attachment_parent_id;
  149. *bone = m_attachment_bone;
  150. *position = m_attachment_position;
  151. *rotation = m_attachment_rotation;
  152. *force_visible = m_force_visible;
  153. }
  154. void UnitSAO::clearChildAttachments()
  155. {
  156. for (int child_id : m_attachment_child_ids) {
  157. // Child can be NULL if it was deleted earlier
  158. if (ServerActiveObject *child = m_env->getActiveObject(child_id))
  159. child->setAttachment(0, "", v3f(0, 0, 0), v3f(0, 0, 0), false);
  160. }
  161. m_attachment_child_ids.clear();
  162. }
  163. void UnitSAO::clearParentAttachment()
  164. {
  165. ServerActiveObject *parent = nullptr;
  166. if (m_attachment_parent_id) {
  167. parent = m_env->getActiveObject(m_attachment_parent_id);
  168. setAttachment(0, "", m_attachment_position, m_attachment_rotation, false);
  169. } else {
  170. setAttachment(0, "", v3f(0, 0, 0), v3f(0, 0, 0), false);
  171. }
  172. // Do it
  173. if (parent)
  174. parent->removeAttachmentChild(m_id);
  175. }
  176. void UnitSAO::addAttachmentChild(int child_id)
  177. {
  178. m_attachment_child_ids.insert(child_id);
  179. }
  180. void UnitSAO::removeAttachmentChild(int child_id)
  181. {
  182. m_attachment_child_ids.erase(child_id);
  183. }
  184. const std::unordered_set<int> &UnitSAO::getAttachmentChildIds() const
  185. {
  186. return m_attachment_child_ids;
  187. }
  188. void UnitSAO::onAttach(int parent_id)
  189. {
  190. if (!parent_id)
  191. return;
  192. ServerActiveObject *parent = m_env->getActiveObject(parent_id);
  193. if (!parent || parent->isGone())
  194. return; // Do not try to notify soon gone parent
  195. if (parent->getType() == ACTIVEOBJECT_TYPE_LUAENTITY) {
  196. // Call parent's on_attach field
  197. m_env->getScriptIface()->luaentity_on_attach_child(parent_id, this);
  198. }
  199. }
  200. void UnitSAO::onDetach(int parent_id)
  201. {
  202. if (!parent_id)
  203. return;
  204. ServerActiveObject *parent = m_env->getActiveObject(parent_id);
  205. if (getType() == ACTIVEOBJECT_TYPE_LUAENTITY)
  206. m_env->getScriptIface()->luaentity_on_detach(m_id, parent);
  207. if (!parent || parent->isGone())
  208. return; // Do not try to notify soon gone parent
  209. if (parent->getType() == ACTIVEOBJECT_TYPE_LUAENTITY)
  210. m_env->getScriptIface()->luaentity_on_detach_child(parent_id, this);
  211. }
  212. ObjectProperties *UnitSAO::accessObjectProperties()
  213. {
  214. return &m_prop;
  215. }
  216. void UnitSAO::notifyObjectPropertiesModified()
  217. {
  218. m_properties_sent = false;
  219. }
  220. std::string UnitSAO::generateUpdateAttachmentCommand() const
  221. {
  222. std::ostringstream os(std::ios::binary);
  223. // command
  224. writeU8(os, AO_CMD_ATTACH_TO);
  225. // parameters
  226. writeS16(os, m_attachment_parent_id);
  227. os << serializeString16(m_attachment_bone);
  228. writeV3F32(os, m_attachment_position);
  229. writeV3F32(os, m_attachment_rotation);
  230. writeU8(os, m_force_visible);
  231. return os.str();
  232. }
  233. std::string UnitSAO::generateUpdateBonePositionCommand(
  234. const std::string &bone, const v3f &position, const v3f &rotation)
  235. {
  236. std::ostringstream os(std::ios::binary);
  237. // command
  238. writeU8(os, AO_CMD_SET_BONE_POSITION);
  239. // parameters
  240. os << serializeString16(bone);
  241. writeV3F32(os, position);
  242. writeV3F32(os, rotation);
  243. return os.str();
  244. }
  245. std::string UnitSAO::generateUpdateAnimationSpeedCommand() const
  246. {
  247. std::ostringstream os(std::ios::binary);
  248. // command
  249. writeU8(os, AO_CMD_SET_ANIMATION_SPEED);
  250. // parameters
  251. writeF32(os, m_animation_speed);
  252. return os.str();
  253. }
  254. std::string UnitSAO::generateUpdateAnimationCommand() const
  255. {
  256. std::ostringstream os(std::ios::binary);
  257. // command
  258. writeU8(os, AO_CMD_SET_ANIMATION);
  259. // parameters
  260. writeV2F32(os, m_animation_range);
  261. writeF32(os, m_animation_speed);
  262. writeF32(os, m_animation_blend);
  263. // these are sent inverted so we get true when the server sends nothing
  264. writeU8(os, !m_animation_loop);
  265. return os.str();
  266. }
  267. std::string UnitSAO::generateUpdateArmorGroupsCommand() const
  268. {
  269. std::ostringstream os(std::ios::binary);
  270. writeU8(os, AO_CMD_UPDATE_ARMOR_GROUPS);
  271. writeU16(os, m_armor_groups.size());
  272. for (const auto &armor_group : m_armor_groups) {
  273. os << serializeString16(armor_group.first);
  274. writeS16(os, armor_group.second);
  275. }
  276. return os.str();
  277. }
  278. std::string UnitSAO::generateUpdatePositionCommand(const v3f &position,
  279. const v3f &velocity, const v3f &acceleration, const v3f &rotation,
  280. bool do_interpolate, bool is_movement_end, f32 update_interval)
  281. {
  282. std::ostringstream os(std::ios::binary);
  283. // command
  284. writeU8(os, AO_CMD_UPDATE_POSITION);
  285. // pos
  286. writeV3F32(os, position);
  287. // velocity
  288. writeV3F32(os, velocity);
  289. // acceleration
  290. writeV3F32(os, acceleration);
  291. // rotation
  292. writeV3F32(os, rotation);
  293. // do_interpolate
  294. writeU8(os, do_interpolate);
  295. // is_end_position (for interpolation)
  296. writeU8(os, is_movement_end);
  297. // update_interval (for interpolation)
  298. writeF32(os, update_interval);
  299. return os.str();
  300. }
  301. std::string UnitSAO::generateSetPropertiesCommand(const ObjectProperties &prop) const
  302. {
  303. std::ostringstream os(std::ios::binary);
  304. writeU8(os, AO_CMD_SET_PROPERTIES);
  305. prop.serialize(os);
  306. return os.str();
  307. }
  308. std::string UnitSAO::generatePunchCommand(u16 result_hp) const
  309. {
  310. std::ostringstream os(std::ios::binary);
  311. // command
  312. writeU8(os, AO_CMD_PUNCHED);
  313. // result_hp
  314. writeU16(os, result_hp);
  315. return os.str();
  316. }
  317. void UnitSAO::sendPunchCommand()
  318. {
  319. m_messages_out.emplace(getId(), true, generatePunchCommand(getHP()));
  320. }