content_cao.cpp 57 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956
  1. /*
  2. Minetest
  3. Copyright (C) 2010-2013 celeron55, Perttu Ahola <celeron55@gmail.com>
  4. This program is free software; you can redistribute it and/or modify
  5. it under the terms of the GNU Lesser General Public License as published by
  6. the Free Software Foundation; either version 2.1 of the License, or
  7. (at your option) any later version.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU Lesser General Public License for more details.
  12. You should have received a copy of the GNU Lesser General Public License along
  13. with this program; if not, write to the Free Software Foundation, Inc.,
  14. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  15. */
  16. #include "content_cao.h"
  17. #include <IBillboardSceneNode.h>
  18. #include <ICameraSceneNode.h>
  19. #include <ITextSceneNode.h>
  20. #include <IMeshManipulator.h>
  21. #include <IAnimatedMeshSceneNode.h>
  22. #include "client/client.h"
  23. #include "client/renderingengine.h"
  24. #include "client/sound.h"
  25. #include "client/tile.h"
  26. #include "util/basic_macros.h"
  27. #include "util/numeric.h" // For IntervalLimiter & setPitchYawRoll
  28. #include "util/serialize.h"
  29. #include "camera.h" // CameraModes
  30. #include "collision.h"
  31. #include "content_cso.h"
  32. #include "environment.h"
  33. #include "itemdef.h"
  34. #include "localplayer.h"
  35. #include "map.h"
  36. #include "mesh.h"
  37. #include "nodedef.h"
  38. #include "serialization.h" // For decompressZlib
  39. #include "settings.h"
  40. #include "sound.h"
  41. #include "tool.h"
  42. #include "wieldmesh.h"
  43. #include <algorithm>
  44. #include <cmath>
  45. #include "client/shader.h"
  46. #include "client/minimap.h"
  47. class Settings;
  48. struct ToolCapabilities;
  49. std::unordered_map<u16, ClientActiveObject::Factory> ClientActiveObject::m_types;
  50. template<typename T>
  51. void SmoothTranslator<T>::init(T current)
  52. {
  53. val_old = current;
  54. val_current = current;
  55. val_target = current;
  56. anim_time = 0;
  57. anim_time_counter = 0;
  58. aim_is_end = true;
  59. }
  60. template<typename T>
  61. void SmoothTranslator<T>::update(T new_target, bool is_end_position, float update_interval)
  62. {
  63. aim_is_end = is_end_position;
  64. val_old = val_current;
  65. val_target = new_target;
  66. if (update_interval > 0) {
  67. anim_time = update_interval;
  68. } else {
  69. if (anim_time < 0.001 || anim_time > 1.0)
  70. anim_time = anim_time_counter;
  71. else
  72. anim_time = anim_time * 0.9 + anim_time_counter * 0.1;
  73. }
  74. anim_time_counter = 0;
  75. }
  76. template<typename T>
  77. void SmoothTranslator<T>::translate(f32 dtime)
  78. {
  79. anim_time_counter = anim_time_counter + dtime;
  80. T val_diff = val_target - val_old;
  81. f32 moveratio = 1.0;
  82. if (anim_time > 0.001)
  83. moveratio = anim_time_counter / anim_time;
  84. f32 move_end = aim_is_end ? 1.0 : 1.5;
  85. // Move a bit less than should, to avoid oscillation
  86. moveratio = std::min(moveratio * 0.8f, move_end);
  87. val_current = val_old + val_diff * moveratio;
  88. }
  89. void SmoothTranslatorWrapped::translate(f32 dtime)
  90. {
  91. anim_time_counter = anim_time_counter + dtime;
  92. f32 val_diff = std::abs(val_target - val_old);
  93. if (val_diff > 180.f)
  94. val_diff = 360.f - val_diff;
  95. f32 moveratio = 1.0;
  96. if (anim_time > 0.001)
  97. moveratio = anim_time_counter / anim_time;
  98. f32 move_end = aim_is_end ? 1.0 : 1.5;
  99. // Move a bit less than should, to avoid oscillation
  100. moveratio = std::min(moveratio * 0.8f, move_end);
  101. wrappedApproachShortest(val_current, val_target,
  102. val_diff * moveratio, 360.f);
  103. }
  104. void SmoothTranslatorWrappedv3f::translate(f32 dtime)
  105. {
  106. anim_time_counter = anim_time_counter + dtime;
  107. v3f val_diff_v3f;
  108. val_diff_v3f.X = std::abs(val_target.X - val_old.X);
  109. val_diff_v3f.Y = std::abs(val_target.Y - val_old.Y);
  110. val_diff_v3f.Z = std::abs(val_target.Z - val_old.Z);
  111. if (val_diff_v3f.X > 180.f)
  112. val_diff_v3f.X = 360.f - val_diff_v3f.X;
  113. if (val_diff_v3f.Y > 180.f)
  114. val_diff_v3f.Y = 360.f - val_diff_v3f.Y;
  115. if (val_diff_v3f.Z > 180.f)
  116. val_diff_v3f.Z = 360.f - val_diff_v3f.Z;
  117. f32 moveratio = 1.0;
  118. if (anim_time > 0.001)
  119. moveratio = anim_time_counter / anim_time;
  120. f32 move_end = aim_is_end ? 1.0 : 1.5;
  121. // Move a bit less than should, to avoid oscillation
  122. moveratio = std::min(moveratio * 0.8f, move_end);
  123. wrappedApproachShortest(val_current.X, val_target.X,
  124. val_diff_v3f.X * moveratio, 360.f);
  125. wrappedApproachShortest(val_current.Y, val_target.Y,
  126. val_diff_v3f.Y * moveratio, 360.f);
  127. wrappedApproachShortest(val_current.Z, val_target.Z,
  128. val_diff_v3f.Z * moveratio, 360.f);
  129. }
  130. /*
  131. Other stuff
  132. */
  133. static void setBillboardTextureMatrix(scene::IBillboardSceneNode *bill,
  134. float txs, float tys, int col, int row)
  135. {
  136. video::SMaterial& material = bill->getMaterial(0);
  137. core::matrix4& matrix = material.getTextureMatrix(0);
  138. matrix.setTextureTranslate(txs*col, tys*row);
  139. matrix.setTextureScale(txs, tys);
  140. }
  141. // Evaluate transform chain recursively; irrlicht does not do this for us
  142. static void updatePositionRecursive(scene::ISceneNode *node)
  143. {
  144. scene::ISceneNode *parent = node->getParent();
  145. if (parent)
  146. updatePositionRecursive(parent);
  147. node->updateAbsolutePosition();
  148. }
  149. /*
  150. TestCAO
  151. */
  152. class TestCAO : public ClientActiveObject
  153. {
  154. public:
  155. TestCAO(Client *client, ClientEnvironment *env);
  156. virtual ~TestCAO() = default;
  157. ActiveObjectType getType() const
  158. {
  159. return ACTIVEOBJECT_TYPE_TEST;
  160. }
  161. static ClientActiveObject* create(Client *client, ClientEnvironment *env);
  162. void addToScene(ITextureSource *tsrc);
  163. void removeFromScene(bool permanent);
  164. void updateLight(u32 day_night_ratio);
  165. void updateNodePos();
  166. void step(float dtime, ClientEnvironment *env);
  167. void processMessage(const std::string &data);
  168. bool getCollisionBox(aabb3f *toset) const { return false; }
  169. private:
  170. scene::IMeshSceneNode *m_node;
  171. v3f m_position;
  172. };
  173. // Prototype
  174. TestCAO proto_TestCAO(NULL, NULL);
  175. TestCAO::TestCAO(Client *client, ClientEnvironment *env):
  176. ClientActiveObject(0, client, env),
  177. m_node(NULL),
  178. m_position(v3f(0,10*BS,0))
  179. {
  180. ClientActiveObject::registerType(getType(), create);
  181. }
  182. ClientActiveObject* TestCAO::create(Client *client, ClientEnvironment *env)
  183. {
  184. return new TestCAO(client, env);
  185. }
  186. void TestCAO::addToScene(ITextureSource *tsrc)
  187. {
  188. if(m_node != NULL)
  189. return;
  190. //video::IVideoDriver* driver = smgr->getVideoDriver();
  191. scene::SMesh *mesh = new scene::SMesh();
  192. scene::IMeshBuffer *buf = new scene::SMeshBuffer();
  193. video::SColor c(255,255,255,255);
  194. video::S3DVertex vertices[4] =
  195. {
  196. video::S3DVertex(-BS/2,-BS/4,0, 0,0,0, c, 0,1),
  197. video::S3DVertex(BS/2,-BS/4,0, 0,0,0, c, 1,1),
  198. video::S3DVertex(BS/2,BS/4,0, 0,0,0, c, 1,0),
  199. video::S3DVertex(-BS/2,BS/4,0, 0,0,0, c, 0,0),
  200. };
  201. u16 indices[] = {0,1,2,2,3,0};
  202. buf->append(vertices, 4, indices, 6);
  203. // Set material
  204. buf->getMaterial().setFlag(video::EMF_LIGHTING, false);
  205. buf->getMaterial().setFlag(video::EMF_BACK_FACE_CULLING, false);
  206. buf->getMaterial().setTexture(0, tsrc->getTextureForMesh("rat.png"));
  207. buf->getMaterial().setFlag(video::EMF_BILINEAR_FILTER, false);
  208. buf->getMaterial().setFlag(video::EMF_FOG_ENABLE, true);
  209. buf->getMaterial().MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
  210. // Add to mesh
  211. mesh->addMeshBuffer(buf);
  212. buf->drop();
  213. m_node = RenderingEngine::get_scene_manager()->addMeshSceneNode(mesh, NULL);
  214. mesh->drop();
  215. updateNodePos();
  216. }
  217. void TestCAO::removeFromScene(bool permanent)
  218. {
  219. if (!m_node)
  220. return;
  221. m_node->remove();
  222. m_node = NULL;
  223. }
  224. void TestCAO::updateLight(u32 day_night_ratio)
  225. {
  226. }
  227. void TestCAO::updateNodePos()
  228. {
  229. if (!m_node)
  230. return;
  231. m_node->setPosition(m_position);
  232. //m_node->setRotation(v3f(0, 45, 0));
  233. }
  234. void TestCAO::step(float dtime, ClientEnvironment *env)
  235. {
  236. if(m_node)
  237. {
  238. v3f rot = m_node->getRotation();
  239. //infostream<<"dtime="<<dtime<<", rot.Y="<<rot.Y<<std::endl;
  240. rot.Y += dtime * 180;
  241. m_node->setRotation(rot);
  242. }
  243. }
  244. void TestCAO::processMessage(const std::string &data)
  245. {
  246. infostream<<"TestCAO: Got data: "<<data<<std::endl;
  247. std::istringstream is(data, std::ios::binary);
  248. u16 cmd;
  249. is>>cmd;
  250. if(cmd == 0)
  251. {
  252. v3f newpos;
  253. is>>newpos.X;
  254. is>>newpos.Y;
  255. is>>newpos.Z;
  256. m_position = newpos;
  257. updateNodePos();
  258. }
  259. }
  260. /*
  261. GenericCAO
  262. */
  263. #include "clientobject.h"
  264. GenericCAO::GenericCAO(Client *client, ClientEnvironment *env):
  265. ClientActiveObject(0, client, env)
  266. {
  267. if (client == NULL) {
  268. ClientActiveObject::registerType(getType(), create);
  269. } else {
  270. m_client = client;
  271. }
  272. }
  273. bool GenericCAO::getCollisionBox(aabb3f *toset) const
  274. {
  275. if (m_prop.physical)
  276. {
  277. //update collision box
  278. toset->MinEdge = m_prop.collisionbox.MinEdge * BS;
  279. toset->MaxEdge = m_prop.collisionbox.MaxEdge * BS;
  280. toset->MinEdge += m_position;
  281. toset->MaxEdge += m_position;
  282. return true;
  283. }
  284. return false;
  285. }
  286. bool GenericCAO::collideWithObjects() const
  287. {
  288. return m_prop.collideWithObjects;
  289. }
  290. void GenericCAO::initialize(const std::string &data)
  291. {
  292. infostream<<"GenericCAO: Got init data"<<std::endl;
  293. processInitData(data);
  294. if (m_is_player) {
  295. // Check if it's the current player
  296. LocalPlayer *player = m_env->getLocalPlayer();
  297. if (player && strcmp(player->getName(), m_name.c_str()) == 0) {
  298. m_is_local_player = true;
  299. m_is_visible = false;
  300. player->setCAO(this);
  301. m_prop.show_on_minimap = false;
  302. }
  303. }
  304. m_enable_shaders = g_settings->getBool("enable_shaders");
  305. }
  306. void GenericCAO::processInitData(const std::string &data)
  307. {
  308. std::istringstream is(data, std::ios::binary);
  309. const u8 version = readU8(is);
  310. if (version < 1) {
  311. errorstream << "GenericCAO: Unsupported init data version"
  312. << std::endl;
  313. return;
  314. }
  315. // PROTOCOL_VERSION >= 37
  316. m_name = deSerializeString16(is);
  317. m_is_player = readU8(is);
  318. m_id = readU16(is);
  319. m_position = readV3F32(is);
  320. m_rotation = readV3F32(is);
  321. m_hp = readU16(is);
  322. const u8 num_messages = readU8(is);
  323. for (int i = 0; i < num_messages; i++) {
  324. std::string message = deSerializeString32(is);
  325. processMessage(message);
  326. }
  327. m_rotation = wrapDegrees_0_360_v3f(m_rotation);
  328. pos_translator.init(m_position);
  329. rot_translator.init(m_rotation);
  330. updateNodePos();
  331. }
  332. GenericCAO::~GenericCAO()
  333. {
  334. removeFromScene(true);
  335. }
  336. bool GenericCAO::getSelectionBox(aabb3f *toset) const
  337. {
  338. if (!m_prop.is_visible || !m_is_visible || m_is_local_player
  339. || !m_prop.pointable) {
  340. return false;
  341. }
  342. *toset = m_selection_box;
  343. return true;
  344. }
  345. const v3f GenericCAO::getPosition() const
  346. {
  347. if (!getParent())
  348. return pos_translator.val_current;
  349. // Calculate real position in world based on MatrixNode
  350. if (m_matrixnode) {
  351. v3s16 camera_offset = m_env->getCameraOffset();
  352. return m_matrixnode->getAbsolutePosition() +
  353. intToFloat(camera_offset, BS);
  354. }
  355. return m_position;
  356. }
  357. const bool GenericCAO::isImmortal()
  358. {
  359. return itemgroup_get(getGroups(), "immortal");
  360. }
  361. scene::ISceneNode *GenericCAO::getSceneNode() const
  362. {
  363. if (m_meshnode) {
  364. return m_meshnode;
  365. }
  366. if (m_animated_meshnode) {
  367. return m_animated_meshnode;
  368. }
  369. if (m_wield_meshnode) {
  370. return m_wield_meshnode;
  371. }
  372. if (m_spritenode) {
  373. return m_spritenode;
  374. }
  375. return NULL;
  376. }
  377. scene::IAnimatedMeshSceneNode *GenericCAO::getAnimatedMeshSceneNode() const
  378. {
  379. return m_animated_meshnode;
  380. }
  381. void GenericCAO::setChildrenVisible(bool toset)
  382. {
  383. for (u16 cao_id : m_attachment_child_ids) {
  384. GenericCAO *obj = m_env->getGenericCAO(cao_id);
  385. if (obj) {
  386. // Check if the entity is forced to appear in first person.
  387. obj->setVisible(obj->m_force_visible ? true : toset);
  388. }
  389. }
  390. }
  391. void GenericCAO::setAttachment(int parent_id, const std::string &bone,
  392. v3f position, v3f rotation, bool force_visible)
  393. {
  394. int old_parent = m_attachment_parent_id;
  395. m_attachment_parent_id = parent_id;
  396. m_attachment_bone = bone;
  397. m_attachment_position = position;
  398. m_attachment_rotation = rotation;
  399. m_force_visible = force_visible;
  400. ClientActiveObject *parent = m_env->getActiveObject(parent_id);
  401. if (parent_id != old_parent) {
  402. if (auto *o = m_env->getActiveObject(old_parent))
  403. o->removeAttachmentChild(m_id);
  404. if (parent)
  405. parent->addAttachmentChild(m_id);
  406. }
  407. updateAttachments();
  408. // Forcibly show attachments if required by set_attach
  409. if (m_force_visible) {
  410. m_is_visible = true;
  411. } else if (!m_is_local_player) {
  412. // Objects attached to the local player should be hidden in first person
  413. m_is_visible = !m_attached_to_local ||
  414. m_client->getCamera()->getCameraMode() != CAMERA_MODE_FIRST;
  415. m_force_visible = false;
  416. } else {
  417. // Local players need to have this set,
  418. // otherwise first person attachments fail.
  419. m_is_visible = true;
  420. }
  421. }
  422. void GenericCAO::getAttachment(int *parent_id, std::string *bone, v3f *position,
  423. v3f *rotation, bool *force_visible) const
  424. {
  425. *parent_id = m_attachment_parent_id;
  426. *bone = m_attachment_bone;
  427. *position = m_attachment_position;
  428. *rotation = m_attachment_rotation;
  429. *force_visible = m_force_visible;
  430. }
  431. void GenericCAO::clearChildAttachments()
  432. {
  433. // Cannot use for-loop here: setAttachment() modifies 'm_attachment_child_ids'!
  434. while (!m_attachment_child_ids.empty()) {
  435. int child_id = *m_attachment_child_ids.begin();
  436. if (ClientActiveObject *child = m_env->getActiveObject(child_id))
  437. child->setAttachment(0, "", v3f(), v3f(), false);
  438. removeAttachmentChild(child_id);
  439. }
  440. }
  441. void GenericCAO::clearParentAttachment()
  442. {
  443. if (m_attachment_parent_id)
  444. setAttachment(0, "", m_attachment_position, m_attachment_rotation, false);
  445. else
  446. setAttachment(0, "", v3f(), v3f(), false);
  447. }
  448. void GenericCAO::addAttachmentChild(int child_id)
  449. {
  450. m_attachment_child_ids.insert(child_id);
  451. }
  452. void GenericCAO::removeAttachmentChild(int child_id)
  453. {
  454. m_attachment_child_ids.erase(child_id);
  455. }
  456. ClientActiveObject* GenericCAO::getParent() const
  457. {
  458. return m_attachment_parent_id ? m_env->getActiveObject(m_attachment_parent_id) :
  459. nullptr;
  460. }
  461. void GenericCAO::removeFromScene(bool permanent)
  462. {
  463. // Should be true when removing the object permanently
  464. // and false when refreshing (eg: updating visuals)
  465. if (m_env && permanent) {
  466. // The client does not know whether this object does re-appear to
  467. // a later time, thus do not clear child attachments.
  468. clearParentAttachment();
  469. }
  470. if (m_meshnode) {
  471. m_meshnode->remove();
  472. m_meshnode->drop();
  473. m_meshnode = nullptr;
  474. } else if (m_animated_meshnode) {
  475. m_animated_meshnode->remove();
  476. m_animated_meshnode->drop();
  477. m_animated_meshnode = nullptr;
  478. } else if (m_wield_meshnode) {
  479. m_wield_meshnode->remove();
  480. m_wield_meshnode->drop();
  481. m_wield_meshnode = nullptr;
  482. } else if (m_spritenode) {
  483. m_spritenode->remove();
  484. m_spritenode->drop();
  485. m_spritenode = nullptr;
  486. }
  487. if (m_matrixnode) {
  488. m_matrixnode->remove();
  489. m_matrixnode->drop();
  490. m_matrixnode = nullptr;
  491. }
  492. if (m_nametag) {
  493. m_client->getCamera()->removeNametag(m_nametag);
  494. m_nametag = nullptr;
  495. }
  496. if (m_marker && m_client->getMinimap())
  497. m_client->getMinimap()->removeMarker(&m_marker);
  498. }
  499. void GenericCAO::addToScene(ITextureSource *tsrc)
  500. {
  501. m_smgr = RenderingEngine::get_scene_manager();
  502. if (getSceneNode() != NULL) {
  503. return;
  504. }
  505. m_visuals_expired = false;
  506. if (!m_prop.is_visible)
  507. return;
  508. infostream << "GenericCAO::addToScene(): " << m_prop.visual << std::endl;
  509. if (m_enable_shaders) {
  510. IShaderSource *shader_source = m_client->getShaderSource();
  511. MaterialType material_type;
  512. if (m_prop.shaded && m_prop.glow == 0)
  513. material_type = (m_prop.use_texture_alpha) ?
  514. TILE_MATERIAL_ALPHA : TILE_MATERIAL_BASIC;
  515. else
  516. material_type = (m_prop.use_texture_alpha) ?
  517. TILE_MATERIAL_PLAIN_ALPHA : TILE_MATERIAL_PLAIN;
  518. u32 shader_id = shader_source->getShader("object_shader", material_type, NDT_NORMAL);
  519. m_material_type = shader_source->getShaderInfo(shader_id).material;
  520. } else {
  521. m_material_type = (m_prop.use_texture_alpha) ?
  522. video::EMT_TRANSPARENT_ALPHA_CHANNEL : video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
  523. }
  524. auto grabMatrixNode = [this] {
  525. m_matrixnode = RenderingEngine::get_scene_manager()->
  526. addDummyTransformationSceneNode();
  527. m_matrixnode->grab();
  528. };
  529. auto setSceneNodeMaterial = [this] (scene::ISceneNode *node) {
  530. node->setMaterialFlag(video::EMF_LIGHTING, false);
  531. node->setMaterialFlag(video::EMF_BILINEAR_FILTER, false);
  532. node->setMaterialFlag(video::EMF_FOG_ENABLE, true);
  533. node->setMaterialType(m_material_type);
  534. if (m_enable_shaders) {
  535. node->setMaterialFlag(video::EMF_GOURAUD_SHADING, false);
  536. node->setMaterialFlag(video::EMF_NORMALIZE_NORMALS, true);
  537. }
  538. };
  539. if (m_prop.visual == "sprite") {
  540. grabMatrixNode();
  541. m_spritenode = RenderingEngine::get_scene_manager()->addBillboardSceneNode(
  542. m_matrixnode, v2f(1, 1), v3f(0,0,0), -1);
  543. m_spritenode->grab();
  544. m_spritenode->setMaterialTexture(0,
  545. tsrc->getTextureForMesh("unknown_node.png"));
  546. setSceneNodeMaterial(m_spritenode);
  547. m_spritenode->setSize(v2f(m_prop.visual_size.X,
  548. m_prop.visual_size.Y) * BS);
  549. {
  550. const float txs = 1.0 / 1;
  551. const float tys = 1.0 / 1;
  552. setBillboardTextureMatrix(m_spritenode,
  553. txs, tys, 0, 0);
  554. }
  555. } else if (m_prop.visual == "upright_sprite") {
  556. grabMatrixNode();
  557. scene::SMesh *mesh = new scene::SMesh();
  558. double dx = BS * m_prop.visual_size.X / 2;
  559. double dy = BS * m_prop.visual_size.Y / 2;
  560. video::SColor c(0xFFFFFFFF);
  561. { // Front
  562. scene::IMeshBuffer *buf = new scene::SMeshBuffer();
  563. video::S3DVertex vertices[4] = {
  564. video::S3DVertex(-dx, -dy, 0, 0,0,1, c, 1,1),
  565. video::S3DVertex( dx, -dy, 0, 0,0,1, c, 0,1),
  566. video::S3DVertex( dx, dy, 0, 0,0,1, c, 0,0),
  567. video::S3DVertex(-dx, dy, 0, 0,0,1, c, 1,0),
  568. };
  569. if (m_is_player) {
  570. // Move minimal Y position to 0 (feet position)
  571. for (video::S3DVertex &vertex : vertices)
  572. vertex.Pos.Y += dy;
  573. }
  574. u16 indices[] = {0,1,2,2,3,0};
  575. buf->append(vertices, 4, indices, 6);
  576. // Set material
  577. buf->getMaterial().setFlag(video::EMF_LIGHTING, false);
  578. buf->getMaterial().setFlag(video::EMF_BILINEAR_FILTER, false);
  579. buf->getMaterial().setFlag(video::EMF_FOG_ENABLE, true);
  580. buf->getMaterial().MaterialType = m_material_type;
  581. if (m_enable_shaders) {
  582. buf->getMaterial().EmissiveColor = c;
  583. buf->getMaterial().setFlag(video::EMF_GOURAUD_SHADING, false);
  584. buf->getMaterial().setFlag(video::EMF_NORMALIZE_NORMALS, true);
  585. }
  586. // Add to mesh
  587. mesh->addMeshBuffer(buf);
  588. buf->drop();
  589. }
  590. { // Back
  591. scene::IMeshBuffer *buf = new scene::SMeshBuffer();
  592. video::S3DVertex vertices[4] = {
  593. video::S3DVertex( dx,-dy, 0, 0,0,-1, c, 1,1),
  594. video::S3DVertex(-dx,-dy, 0, 0,0,-1, c, 0,1),
  595. video::S3DVertex(-dx, dy, 0, 0,0,-1, c, 0,0),
  596. video::S3DVertex( dx, dy, 0, 0,0,-1, c, 1,0),
  597. };
  598. if (m_is_player) {
  599. // Move minimal Y position to 0 (feet position)
  600. for (video::S3DVertex &vertex : vertices)
  601. vertex.Pos.Y += dy;
  602. }
  603. u16 indices[] = {0,1,2,2,3,0};
  604. buf->append(vertices, 4, indices, 6);
  605. // Set material
  606. buf->getMaterial().setFlag(video::EMF_LIGHTING, false);
  607. buf->getMaterial().setFlag(video::EMF_BILINEAR_FILTER, false);
  608. buf->getMaterial().setFlag(video::EMF_FOG_ENABLE, true);
  609. buf->getMaterial().MaterialType = m_material_type;
  610. if (m_enable_shaders) {
  611. buf->getMaterial().EmissiveColor = c;
  612. buf->getMaterial().setFlag(video::EMF_GOURAUD_SHADING, false);
  613. buf->getMaterial().setFlag(video::EMF_NORMALIZE_NORMALS, true);
  614. }
  615. // Add to mesh
  616. mesh->addMeshBuffer(buf);
  617. buf->drop();
  618. }
  619. m_meshnode = RenderingEngine::get_scene_manager()->
  620. addMeshSceneNode(mesh, m_matrixnode);
  621. m_meshnode->grab();
  622. mesh->drop();
  623. // Set it to use the materials of the meshbuffers directly.
  624. // This is needed for changing the texture in the future
  625. m_meshnode->setReadOnlyMaterials(true);
  626. } else if (m_prop.visual == "cube") {
  627. grabMatrixNode();
  628. scene::IMesh *mesh = createCubeMesh(v3f(BS,BS,BS));
  629. m_meshnode = RenderingEngine::get_scene_manager()->
  630. addMeshSceneNode(mesh, m_matrixnode);
  631. m_meshnode->grab();
  632. mesh->drop();
  633. m_meshnode->setScale(m_prop.visual_size);
  634. m_meshnode->setMaterialFlag(video::EMF_BACK_FACE_CULLING,
  635. m_prop.backface_culling);
  636. setSceneNodeMaterial(m_meshnode);
  637. } else if (m_prop.visual == "mesh") {
  638. grabMatrixNode();
  639. scene::IAnimatedMesh *mesh = m_client->getMesh(m_prop.mesh, true);
  640. if (mesh) {
  641. m_animated_meshnode = RenderingEngine::get_scene_manager()->
  642. addAnimatedMeshSceneNode(mesh, m_matrixnode);
  643. m_animated_meshnode->grab();
  644. mesh->drop(); // The scene node took hold of it
  645. if (!checkMeshNormals(mesh)) {
  646. infostream << "GenericCAO: recalculating normals for mesh "
  647. << m_prop.mesh << std::endl;
  648. m_smgr->getMeshManipulator()->
  649. recalculateNormals(mesh, true, false);
  650. }
  651. m_animated_meshnode->animateJoints(); // Needed for some animations
  652. m_animated_meshnode->setScale(m_prop.visual_size);
  653. // set vertex colors to ensure alpha is set
  654. setMeshColor(m_animated_meshnode->getMesh(), video::SColor(0xFFFFFFFF));
  655. setAnimatedMeshColor(m_animated_meshnode, video::SColor(0xFFFFFFFF));
  656. setSceneNodeMaterial(m_animated_meshnode);
  657. m_animated_meshnode->setMaterialFlag(video::EMF_BACK_FACE_CULLING,
  658. m_prop.backface_culling);
  659. } else
  660. errorstream<<"GenericCAO::addToScene(): Could not load mesh "<<m_prop.mesh<<std::endl;
  661. } else if (m_prop.visual == "wielditem" || m_prop.visual == "item") {
  662. grabMatrixNode();
  663. ItemStack item;
  664. if (m_prop.wield_item.empty()) {
  665. // Old format, only textures are specified.
  666. infostream << "textures: " << m_prop.textures.size() << std::endl;
  667. if (!m_prop.textures.empty()) {
  668. infostream << "textures[0]: " << m_prop.textures[0]
  669. << std::endl;
  670. IItemDefManager *idef = m_client->idef();
  671. item = ItemStack(m_prop.textures[0], 1, 0, idef);
  672. }
  673. } else {
  674. infostream << "serialized form: " << m_prop.wield_item << std::endl;
  675. item.deSerialize(m_prop.wield_item, m_client->idef());
  676. }
  677. m_wield_meshnode = new WieldMeshSceneNode(
  678. RenderingEngine::get_scene_manager(), -1);
  679. m_wield_meshnode->setItem(item, m_client,
  680. (m_prop.visual == "wielditem"));
  681. m_wield_meshnode->setScale(m_prop.visual_size / 2.0f);
  682. m_wield_meshnode->setColor(video::SColor(0xFFFFFFFF));
  683. } else {
  684. infostream<<"GenericCAO::addToScene(): \""<<m_prop.visual
  685. <<"\" not supported"<<std::endl;
  686. }
  687. /* don't update while punch texture modifier is active */
  688. if (m_reset_textures_timer < 0)
  689. updateTextures(m_current_texture_modifier);
  690. scene::ISceneNode *node = getSceneNode();
  691. if (node && m_matrixnode)
  692. node->setParent(m_matrixnode);
  693. updateNametag();
  694. updateMarker();
  695. updateNodePos();
  696. updateAnimation();
  697. updateBonePosition();
  698. updateAttachments();
  699. setNodeLight(m_last_light);
  700. updateMeshCulling();
  701. }
  702. void GenericCAO::updateLight(u32 day_night_ratio)
  703. {
  704. if (m_glow < 0)
  705. return;
  706. u8 light_at_pos = 0;
  707. bool pos_ok = false;
  708. v3s16 pos[3];
  709. u16 npos = getLightPosition(pos);
  710. for (u16 i = 0; i < npos; i++) {
  711. bool this_ok;
  712. MapNode n = m_env->getMap().getNode(pos[i], &this_ok);
  713. if (this_ok) {
  714. u8 this_light = n.getLightBlend(day_night_ratio, m_client->ndef());
  715. light_at_pos = MYMAX(light_at_pos, this_light);
  716. pos_ok = true;
  717. }
  718. }
  719. if (!pos_ok)
  720. light_at_pos = blend_light(day_night_ratio, LIGHT_SUN, 0);
  721. u8 light = decode_light(light_at_pos + m_glow);
  722. if (light != m_last_light) {
  723. m_last_light = light;
  724. setNodeLight(light);
  725. }
  726. }
  727. void GenericCAO::setNodeLight(u8 light)
  728. {
  729. video::SColor color(255, light, light, light);
  730. if (m_prop.visual == "wielditem" || m_prop.visual == "item") {
  731. if (m_wield_meshnode)
  732. m_wield_meshnode->setNodeLightColor(color);
  733. return;
  734. }
  735. if (m_enable_shaders) {
  736. if (m_prop.visual == "upright_sprite") {
  737. if (!m_meshnode)
  738. return;
  739. scene::IMesh *mesh = m_meshnode->getMesh();
  740. for (u32 i = 0; i < mesh->getMeshBufferCount(); ++i) {
  741. scene::IMeshBuffer *buf = mesh->getMeshBuffer(i);
  742. buf->getMaterial().EmissiveColor = color;
  743. }
  744. } else {
  745. scene::ISceneNode *node = getSceneNode();
  746. if (!node)
  747. return;
  748. for (u32 i = 0; i < node->getMaterialCount(); ++i) {
  749. video::SMaterial &material = node->getMaterial(i);
  750. material.EmissiveColor = color;
  751. }
  752. }
  753. } else {
  754. if (m_meshnode) {
  755. setMeshColor(m_meshnode->getMesh(), color);
  756. } else if (m_animated_meshnode) {
  757. setAnimatedMeshColor(m_animated_meshnode, color);
  758. } else if (m_spritenode) {
  759. m_spritenode->setColor(color);
  760. }
  761. }
  762. }
  763. u16 GenericCAO::getLightPosition(v3s16 *pos)
  764. {
  765. const auto &box = m_prop.collisionbox;
  766. pos[0] = floatToInt(m_position + box.MinEdge * BS, BS);
  767. pos[1] = floatToInt(m_position + box.MaxEdge * BS, BS);
  768. // Skip center pos if it falls into the same node as Min or MaxEdge
  769. if ((box.MaxEdge - box.MinEdge).getLengthSQ() < 3.0f)
  770. return 2;
  771. pos[2] = floatToInt(m_position + box.getCenter() * BS, BS);
  772. return 3;
  773. }
  774. void GenericCAO::updateMarker()
  775. {
  776. if (!m_client->getMinimap())
  777. return;
  778. if (!m_prop.show_on_minimap) {
  779. if (m_marker)
  780. m_client->getMinimap()->removeMarker(&m_marker);
  781. return;
  782. }
  783. if (m_marker)
  784. return;
  785. scene::ISceneNode *node = getSceneNode();
  786. if (!node)
  787. return;
  788. m_marker = m_client->getMinimap()->addMarker(node);
  789. }
  790. void GenericCAO::updateNametag()
  791. {
  792. if (m_is_local_player) // No nametag for local player
  793. return;
  794. if (m_prop.nametag.empty()) {
  795. // Delete nametag
  796. if (m_nametag) {
  797. m_client->getCamera()->removeNametag(m_nametag);
  798. m_nametag = nullptr;
  799. }
  800. return;
  801. }
  802. scene::ISceneNode *node = getSceneNode();
  803. if (!node)
  804. return;
  805. v3f pos;
  806. pos.Y = m_prop.selectionbox.MaxEdge.Y + 0.3f;
  807. if (!m_nametag) {
  808. // Add nametag
  809. m_nametag = m_client->getCamera()->addNametag(node,
  810. m_prop.nametag, m_prop.nametag_color, pos);
  811. } else {
  812. // Update nametag
  813. m_nametag->nametag_text = m_prop.nametag;
  814. m_nametag->nametag_color = m_prop.nametag_color;
  815. m_nametag->nametag_pos = pos;
  816. }
  817. }
  818. void GenericCAO::updateNodePos()
  819. {
  820. if (getParent() != NULL)
  821. return;
  822. scene::ISceneNode *node = getSceneNode();
  823. if (node) {
  824. v3s16 camera_offset = m_env->getCameraOffset();
  825. v3f pos = pos_translator.val_current -
  826. intToFloat(camera_offset, BS);
  827. getPosRotMatrix().setTranslation(pos);
  828. if (node != m_spritenode) { // rotate if not a sprite
  829. v3f rot = m_is_local_player ? -m_rotation : -rot_translator.val_current;
  830. setPitchYawRoll(getPosRotMatrix(), rot);
  831. }
  832. }
  833. }
  834. void GenericCAO::step(float dtime, ClientEnvironment *env)
  835. {
  836. // Handle model animations and update positions instantly to prevent lags
  837. if (m_is_local_player) {
  838. LocalPlayer *player = m_env->getLocalPlayer();
  839. m_position = player->getPosition();
  840. pos_translator.val_current = m_position;
  841. m_rotation.Y = wrapDegrees_0_360(player->getYaw());
  842. rot_translator.val_current = m_rotation;
  843. if (m_is_visible) {
  844. int old_anim = player->last_animation;
  845. float old_anim_speed = player->last_animation_speed;
  846. m_velocity = v3f(0,0,0);
  847. m_acceleration = v3f(0,0,0);
  848. const PlayerControl &controls = player->getPlayerControl();
  849. bool walking = false;
  850. if (controls.up || controls.down || controls.left || controls.right ||
  851. controls.forw_move_joystick_axis != 0.f ||
  852. controls.sidew_move_joystick_axis != 0.f)
  853. walking = true;
  854. f32 new_speed = player->local_animation_speed;
  855. v2s32 new_anim = v2s32(0,0);
  856. bool allow_update = false;
  857. // increase speed if using fast or flying fast
  858. if((g_settings->getBool("fast_move") &&
  859. m_client->checkLocalPrivilege("fast")) &&
  860. (controls.aux1 ||
  861. (!player->touching_ground &&
  862. g_settings->getBool("free_move") &&
  863. m_client->checkLocalPrivilege("fly"))))
  864. new_speed *= 1.5;
  865. // slowdown speed if sneeking
  866. if (controls.sneak && walking)
  867. new_speed /= 2;
  868. if (walking && (controls.dig || controls.place)) {
  869. new_anim = player->local_animations[3];
  870. player->last_animation = WD_ANIM;
  871. } else if (walking) {
  872. new_anim = player->local_animations[1];
  873. player->last_animation = WALK_ANIM;
  874. } else if (controls.dig || controls.place) {
  875. new_anim = player->local_animations[2];
  876. player->last_animation = DIG_ANIM;
  877. }
  878. // Apply animations if input detected and not attached
  879. // or set idle animation
  880. if ((new_anim.X + new_anim.Y) > 0 && !getParent()) {
  881. allow_update = true;
  882. m_animation_range = new_anim;
  883. m_animation_speed = new_speed;
  884. player->last_animation_speed = m_animation_speed;
  885. } else {
  886. player->last_animation = NO_ANIM;
  887. if (old_anim != NO_ANIM) {
  888. m_animation_range = player->local_animations[0];
  889. updateAnimation();
  890. }
  891. }
  892. // Update local player animations
  893. if ((player->last_animation != old_anim ||
  894. m_animation_speed != old_anim_speed) &&
  895. player->last_animation != NO_ANIM && allow_update)
  896. updateAnimation();
  897. }
  898. }
  899. if (m_visuals_expired && m_smgr) {
  900. m_visuals_expired = false;
  901. // Attachments, part 1: All attached objects must be unparented first,
  902. // or Irrlicht causes a segmentation fault
  903. for (u16 cao_id : m_attachment_child_ids) {
  904. ClientActiveObject *obj = m_env->getActiveObject(cao_id);
  905. if (obj) {
  906. scene::ISceneNode *child_node = obj->getSceneNode();
  907. // The node's parent is always an IDummyTraformationSceneNode,
  908. // so we need to reparent that one instead.
  909. if (child_node)
  910. child_node->getParent()->setParent(m_smgr->getRootSceneNode());
  911. }
  912. }
  913. removeFromScene(false);
  914. addToScene(m_client->tsrc());
  915. // Attachments, part 2: Now that the parent has been refreshed, put its attachments back
  916. for (u16 cao_id : m_attachment_child_ids) {
  917. ClientActiveObject *obj = m_env->getActiveObject(cao_id);
  918. if (obj)
  919. obj->updateAttachments();
  920. }
  921. }
  922. // Make sure m_is_visible is always applied
  923. scene::ISceneNode *node = getSceneNode();
  924. if (node)
  925. node->setVisible(m_is_visible);
  926. if(getParent() != NULL) // Attachments should be glued to their parent by Irrlicht
  927. {
  928. // Set these for later
  929. m_position = getPosition();
  930. m_velocity = v3f(0,0,0);
  931. m_acceleration = v3f(0,0,0);
  932. pos_translator.val_current = m_position;
  933. pos_translator.val_target = m_position;
  934. } else {
  935. rot_translator.translate(dtime);
  936. v3f lastpos = pos_translator.val_current;
  937. if(m_prop.physical)
  938. {
  939. aabb3f box = m_prop.collisionbox;
  940. box.MinEdge *= BS;
  941. box.MaxEdge *= BS;
  942. collisionMoveResult moveresult;
  943. f32 pos_max_d = BS*0.125; // Distance per iteration
  944. v3f p_pos = m_position;
  945. v3f p_velocity = m_velocity;
  946. moveresult = collisionMoveSimple(env,env->getGameDef(),
  947. pos_max_d, box, m_prop.stepheight, dtime,
  948. &p_pos, &p_velocity, m_acceleration,
  949. this, m_prop.collideWithObjects);
  950. // Apply results
  951. m_position = p_pos;
  952. m_velocity = p_velocity;
  953. bool is_end_position = moveresult.collides;
  954. pos_translator.update(m_position, is_end_position, dtime);
  955. } else {
  956. m_position += dtime * m_velocity + 0.5 * dtime * dtime * m_acceleration;
  957. m_velocity += dtime * m_acceleration;
  958. pos_translator.update(m_position, pos_translator.aim_is_end,
  959. pos_translator.anim_time);
  960. }
  961. pos_translator.translate(dtime);
  962. updateNodePos();
  963. float moved = lastpos.getDistanceFrom(pos_translator.val_current);
  964. m_step_distance_counter += moved;
  965. if (m_step_distance_counter > 1.5f * BS) {
  966. m_step_distance_counter = 0.0f;
  967. if (!m_is_local_player && m_prop.makes_footstep_sound) {
  968. const NodeDefManager *ndef = m_client->ndef();
  969. v3s16 p = floatToInt(getPosition() +
  970. v3f(0.0f, (m_prop.collisionbox.MinEdge.Y - 0.5f) * BS, 0.0f), BS);
  971. MapNode n = m_env->getMap().getNode(p);
  972. SimpleSoundSpec spec = ndef->get(n).sound_footstep;
  973. // Reduce footstep gain, as non-local-player footsteps are
  974. // somehow louder.
  975. spec.gain *= 0.6f;
  976. m_client->sound()->playSoundAt(spec, false, getPosition());
  977. }
  978. }
  979. }
  980. m_anim_timer += dtime;
  981. if(m_anim_timer >= m_anim_framelength)
  982. {
  983. m_anim_timer -= m_anim_framelength;
  984. m_anim_frame++;
  985. if(m_anim_frame >= m_anim_num_frames)
  986. m_anim_frame = 0;
  987. }
  988. updateTexturePos();
  989. if(m_reset_textures_timer >= 0)
  990. {
  991. m_reset_textures_timer -= dtime;
  992. if(m_reset_textures_timer <= 0) {
  993. m_reset_textures_timer = -1;
  994. updateTextures(m_previous_texture_modifier);
  995. }
  996. }
  997. if (!getParent() && node && fabs(m_prop.automatic_rotate) > 0.001f) {
  998. // This is the child node's rotation. It is only used for automatic_rotate.
  999. v3f local_rot = node->getRotation();
  1000. local_rot.Y = modulo360f(local_rot.Y - dtime * core::RADTODEG *
  1001. m_prop.automatic_rotate);
  1002. node->setRotation(local_rot);
  1003. }
  1004. if (!getParent() && m_prop.automatic_face_movement_dir &&
  1005. (fabs(m_velocity.Z) > 0.001f || fabs(m_velocity.X) > 0.001f)) {
  1006. float target_yaw = atan2(m_velocity.Z, m_velocity.X) * 180 / M_PI
  1007. + m_prop.automatic_face_movement_dir_offset;
  1008. float max_rotation_per_sec =
  1009. m_prop.automatic_face_movement_max_rotation_per_sec;
  1010. if (max_rotation_per_sec > 0) {
  1011. wrappedApproachShortest(m_rotation.Y, target_yaw,
  1012. dtime * max_rotation_per_sec, 360.f);
  1013. } else {
  1014. // Negative values of max_rotation_per_sec mean disabled.
  1015. m_rotation.Y = target_yaw;
  1016. }
  1017. rot_translator.val_current = m_rotation;
  1018. updateNodePos();
  1019. }
  1020. if (m_animated_meshnode) {
  1021. // Everything must be updated; the whole transform
  1022. // chain as well as the animated mesh node.
  1023. // Otherwise, bone attachments would be relative to
  1024. // a position that's one frame old.
  1025. if (m_matrixnode)
  1026. updatePositionRecursive(m_matrixnode);
  1027. m_animated_meshnode->updateAbsolutePosition();
  1028. m_animated_meshnode->animateJoints();
  1029. updateBonePosition();
  1030. }
  1031. }
  1032. void GenericCAO::updateTexturePos()
  1033. {
  1034. if(m_spritenode)
  1035. {
  1036. scene::ICameraSceneNode* camera =
  1037. m_spritenode->getSceneManager()->getActiveCamera();
  1038. if(!camera)
  1039. return;
  1040. v3f cam_to_entity = m_spritenode->getAbsolutePosition()
  1041. - camera->getAbsolutePosition();
  1042. cam_to_entity.normalize();
  1043. int row = m_tx_basepos.Y;
  1044. int col = m_tx_basepos.X;
  1045. // Yawpitch goes rightwards
  1046. if (m_tx_select_horiz_by_yawpitch) {
  1047. if (cam_to_entity.Y > 0.75)
  1048. col += 5;
  1049. else if (cam_to_entity.Y < -0.75)
  1050. col += 4;
  1051. else {
  1052. float mob_dir =
  1053. atan2(cam_to_entity.Z, cam_to_entity.X) / M_PI * 180.;
  1054. float dir = mob_dir - m_rotation.Y;
  1055. dir = wrapDegrees_180(dir);
  1056. if (std::fabs(wrapDegrees_180(dir - 0)) <= 45.1f)
  1057. col += 2;
  1058. else if(std::fabs(wrapDegrees_180(dir - 90)) <= 45.1f)
  1059. col += 3;
  1060. else if(std::fabs(wrapDegrees_180(dir - 180)) <= 45.1f)
  1061. col += 0;
  1062. else if(std::fabs(wrapDegrees_180(dir + 90)) <= 45.1f)
  1063. col += 1;
  1064. else
  1065. col += 4;
  1066. }
  1067. }
  1068. // Animation goes downwards
  1069. row += m_anim_frame;
  1070. float txs = m_tx_size.X;
  1071. float tys = m_tx_size.Y;
  1072. setBillboardTextureMatrix(m_spritenode, txs, tys, col, row);
  1073. }
  1074. else if (m_meshnode) {
  1075. if (m_prop.visual == "upright_sprite") {
  1076. int row = m_tx_basepos.Y;
  1077. int col = m_tx_basepos.X;
  1078. // Animation goes downwards
  1079. row += m_anim_frame;
  1080. const auto &tx = m_tx_size;
  1081. v2f t[4] = { // cf. vertices in GenericCAO::addToScene()
  1082. tx * v2f(col+1, row+1),
  1083. tx * v2f(col, row+1),
  1084. tx * v2f(col, row),
  1085. tx * v2f(col+1, row),
  1086. };
  1087. auto mesh = m_meshnode->getMesh();
  1088. setMeshBufferTextureCoords(mesh->getMeshBuffer(0), t, 4);
  1089. setMeshBufferTextureCoords(mesh->getMeshBuffer(1), t, 4);
  1090. }
  1091. }
  1092. }
  1093. // Do not pass by reference, see header.
  1094. void GenericCAO::updateTextures(std::string mod)
  1095. {
  1096. ITextureSource *tsrc = m_client->tsrc();
  1097. bool use_trilinear_filter = g_settings->getBool("trilinear_filter");
  1098. bool use_bilinear_filter = g_settings->getBool("bilinear_filter");
  1099. bool use_anisotropic_filter = g_settings->getBool("anisotropic_filter");
  1100. m_previous_texture_modifier = m_current_texture_modifier;
  1101. m_current_texture_modifier = mod;
  1102. m_glow = m_prop.glow;
  1103. if (m_spritenode) {
  1104. if (m_prop.visual == "sprite") {
  1105. std::string texturestring = "unknown_node.png";
  1106. if (!m_prop.textures.empty())
  1107. texturestring = m_prop.textures[0];
  1108. texturestring += mod;
  1109. m_spritenode->getMaterial(0).MaterialType = m_material_type;
  1110. m_spritenode->getMaterial(0).MaterialTypeParam = 0.5f;
  1111. m_spritenode->setMaterialTexture(0,
  1112. tsrc->getTextureForMesh(texturestring));
  1113. // This allows setting per-material colors. However, until a real lighting
  1114. // system is added, the code below will have no effect. Once MineTest
  1115. // has directional lighting, it should work automatically.
  1116. if (!m_prop.colors.empty()) {
  1117. m_spritenode->getMaterial(0).AmbientColor = m_prop.colors[0];
  1118. m_spritenode->getMaterial(0).DiffuseColor = m_prop.colors[0];
  1119. m_spritenode->getMaterial(0).SpecularColor = m_prop.colors[0];
  1120. }
  1121. m_spritenode->getMaterial(0).setFlag(video::EMF_TRILINEAR_FILTER, use_trilinear_filter);
  1122. m_spritenode->getMaterial(0).setFlag(video::EMF_BILINEAR_FILTER, use_bilinear_filter);
  1123. m_spritenode->getMaterial(0).setFlag(video::EMF_ANISOTROPIC_FILTER, use_anisotropic_filter);
  1124. }
  1125. }
  1126. else if (m_animated_meshnode) {
  1127. if (m_prop.visual == "mesh") {
  1128. for (u32 i = 0; i < m_prop.textures.size() &&
  1129. i < m_animated_meshnode->getMaterialCount(); ++i) {
  1130. std::string texturestring = m_prop.textures[i];
  1131. if (texturestring.empty())
  1132. continue; // Empty texture string means don't modify that material
  1133. texturestring += mod;
  1134. video::ITexture* texture = tsrc->getTextureForMesh(texturestring);
  1135. if (!texture) {
  1136. errorstream<<"GenericCAO::updateTextures(): Could not load texture "<<texturestring<<std::endl;
  1137. continue;
  1138. }
  1139. // Set material flags and texture
  1140. video::SMaterial& material = m_animated_meshnode->getMaterial(i);
  1141. material.MaterialType = m_material_type;
  1142. material.MaterialTypeParam = 0.5f;
  1143. material.TextureLayer[0].Texture = texture;
  1144. material.setFlag(video::EMF_LIGHTING, true);
  1145. material.setFlag(video::EMF_BILINEAR_FILTER, false);
  1146. material.setFlag(video::EMF_BACK_FACE_CULLING, m_prop.backface_culling);
  1147. // don't filter low-res textures, makes them look blurry
  1148. // player models have a res of 64
  1149. const core::dimension2d<u32> &size = texture->getOriginalSize();
  1150. const u32 res = std::min(size.Height, size.Width);
  1151. use_trilinear_filter &= res > 64;
  1152. use_bilinear_filter &= res > 64;
  1153. m_animated_meshnode->getMaterial(i)
  1154. .setFlag(video::EMF_TRILINEAR_FILTER, use_trilinear_filter);
  1155. m_animated_meshnode->getMaterial(i)
  1156. .setFlag(video::EMF_BILINEAR_FILTER, use_bilinear_filter);
  1157. m_animated_meshnode->getMaterial(i)
  1158. .setFlag(video::EMF_ANISOTROPIC_FILTER, use_anisotropic_filter);
  1159. }
  1160. for (u32 i = 0; i < m_prop.colors.size() &&
  1161. i < m_animated_meshnode->getMaterialCount(); ++i)
  1162. {
  1163. // This allows setting per-material colors. However, until a real lighting
  1164. // system is added, the code below will have no effect. Once MineTest
  1165. // has directional lighting, it should work automatically.
  1166. m_animated_meshnode->getMaterial(i).AmbientColor = m_prop.colors[i];
  1167. m_animated_meshnode->getMaterial(i).DiffuseColor = m_prop.colors[i];
  1168. m_animated_meshnode->getMaterial(i).SpecularColor = m_prop.colors[i];
  1169. }
  1170. }
  1171. }
  1172. else if (m_meshnode) {
  1173. if(m_prop.visual == "cube")
  1174. {
  1175. for (u32 i = 0; i < 6; ++i)
  1176. {
  1177. std::string texturestring = "unknown_node.png";
  1178. if(m_prop.textures.size() > i)
  1179. texturestring = m_prop.textures[i];
  1180. texturestring += mod;
  1181. // Set material flags and texture
  1182. video::SMaterial& material = m_meshnode->getMaterial(i);
  1183. material.MaterialType = m_material_type;
  1184. material.MaterialTypeParam = 0.5f;
  1185. material.setFlag(video::EMF_LIGHTING, false);
  1186. material.setFlag(video::EMF_BILINEAR_FILTER, false);
  1187. material.setTexture(0,
  1188. tsrc->getTextureForMesh(texturestring));
  1189. material.getTextureMatrix(0).makeIdentity();
  1190. // This allows setting per-material colors. However, until a real lighting
  1191. // system is added, the code below will have no effect. Once MineTest
  1192. // has directional lighting, it should work automatically.
  1193. if(m_prop.colors.size() > i)
  1194. {
  1195. m_meshnode->getMaterial(i).AmbientColor = m_prop.colors[i];
  1196. m_meshnode->getMaterial(i).DiffuseColor = m_prop.colors[i];
  1197. m_meshnode->getMaterial(i).SpecularColor = m_prop.colors[i];
  1198. }
  1199. m_meshnode->getMaterial(i).setFlag(video::EMF_TRILINEAR_FILTER, use_trilinear_filter);
  1200. m_meshnode->getMaterial(i).setFlag(video::EMF_BILINEAR_FILTER, use_bilinear_filter);
  1201. m_meshnode->getMaterial(i).setFlag(video::EMF_ANISOTROPIC_FILTER, use_anisotropic_filter);
  1202. }
  1203. } else if (m_prop.visual == "upright_sprite") {
  1204. scene::IMesh *mesh = m_meshnode->getMesh();
  1205. {
  1206. std::string tname = "unknown_object.png";
  1207. if (!m_prop.textures.empty())
  1208. tname = m_prop.textures[0];
  1209. tname += mod;
  1210. scene::IMeshBuffer *buf = mesh->getMeshBuffer(0);
  1211. buf->getMaterial().setTexture(0,
  1212. tsrc->getTextureForMesh(tname));
  1213. // This allows setting per-material colors. However, until a real lighting
  1214. // system is added, the code below will have no effect. Once MineTest
  1215. // has directional lighting, it should work automatically.
  1216. if(!m_prop.colors.empty()) {
  1217. buf->getMaterial().AmbientColor = m_prop.colors[0];
  1218. buf->getMaterial().DiffuseColor = m_prop.colors[0];
  1219. buf->getMaterial().SpecularColor = m_prop.colors[0];
  1220. }
  1221. buf->getMaterial().setFlag(video::EMF_TRILINEAR_FILTER, use_trilinear_filter);
  1222. buf->getMaterial().setFlag(video::EMF_BILINEAR_FILTER, use_bilinear_filter);
  1223. buf->getMaterial().setFlag(video::EMF_ANISOTROPIC_FILTER, use_anisotropic_filter);
  1224. }
  1225. {
  1226. std::string tname = "unknown_object.png";
  1227. if (m_prop.textures.size() >= 2)
  1228. tname = m_prop.textures[1];
  1229. else if (!m_prop.textures.empty())
  1230. tname = m_prop.textures[0];
  1231. tname += mod;
  1232. scene::IMeshBuffer *buf = mesh->getMeshBuffer(1);
  1233. buf->getMaterial().setTexture(0,
  1234. tsrc->getTextureForMesh(tname));
  1235. // This allows setting per-material colors. However, until a real lighting
  1236. // system is added, the code below will have no effect. Once MineTest
  1237. // has directional lighting, it should work automatically.
  1238. if (m_prop.colors.size() >= 2) {
  1239. buf->getMaterial().AmbientColor = m_prop.colors[1];
  1240. buf->getMaterial().DiffuseColor = m_prop.colors[1];
  1241. buf->getMaterial().SpecularColor = m_prop.colors[1];
  1242. } else if (!m_prop.colors.empty()) {
  1243. buf->getMaterial().AmbientColor = m_prop.colors[0];
  1244. buf->getMaterial().DiffuseColor = m_prop.colors[0];
  1245. buf->getMaterial().SpecularColor = m_prop.colors[0];
  1246. }
  1247. buf->getMaterial().setFlag(video::EMF_TRILINEAR_FILTER, use_trilinear_filter);
  1248. buf->getMaterial().setFlag(video::EMF_BILINEAR_FILTER, use_bilinear_filter);
  1249. buf->getMaterial().setFlag(video::EMF_ANISOTROPIC_FILTER, use_anisotropic_filter);
  1250. }
  1251. // Set mesh color (only if lighting is disabled)
  1252. if (!m_prop.colors.empty() && m_glow < 0)
  1253. setMeshColor(mesh, m_prop.colors[0]);
  1254. }
  1255. }
  1256. // Prevent showing the player after changing texture
  1257. if (m_is_local_player)
  1258. updateMeshCulling();
  1259. }
  1260. void GenericCAO::updateAnimation()
  1261. {
  1262. if (!m_animated_meshnode)
  1263. return;
  1264. if (m_animated_meshnode->getStartFrame() != m_animation_range.X ||
  1265. m_animated_meshnode->getEndFrame() != m_animation_range.Y)
  1266. m_animated_meshnode->setFrameLoop(m_animation_range.X, m_animation_range.Y);
  1267. if (m_animated_meshnode->getAnimationSpeed() != m_animation_speed)
  1268. m_animated_meshnode->setAnimationSpeed(m_animation_speed);
  1269. m_animated_meshnode->setTransitionTime(m_animation_blend);
  1270. // Requires Irrlicht 1.8 or greater
  1271. #if (IRRLICHT_VERSION_MAJOR == 1 && IRRLICHT_VERSION_MINOR >= 8) || IRRLICHT_VERSION_MAJOR > 1
  1272. if (m_animated_meshnode->getLoopMode() != m_animation_loop)
  1273. m_animated_meshnode->setLoopMode(m_animation_loop);
  1274. #endif
  1275. }
  1276. void GenericCAO::updateAnimationSpeed()
  1277. {
  1278. if (!m_animated_meshnode)
  1279. return;
  1280. m_animated_meshnode->setAnimationSpeed(m_animation_speed);
  1281. }
  1282. void GenericCAO::updateBonePosition()
  1283. {
  1284. if (m_bone_position.empty() || !m_animated_meshnode)
  1285. return;
  1286. m_animated_meshnode->setJointMode(irr::scene::EJUOR_CONTROL); // To write positions to the mesh on render
  1287. for (auto &it : m_bone_position) {
  1288. std::string bone_name = it.first;
  1289. irr::scene::IBoneSceneNode* bone = m_animated_meshnode->getJointNode(bone_name.c_str());
  1290. if (bone) {
  1291. bone->setPosition(it.second.X);
  1292. bone->setRotation(it.second.Y);
  1293. }
  1294. }
  1295. // search through bones to find mistakenly rotated bones due to bug in Irrlicht
  1296. for (u32 i = 0; i < m_animated_meshnode->getJointCount(); ++i) {
  1297. irr::scene::IBoneSceneNode *bone = m_animated_meshnode->getJointNode(i);
  1298. if (!bone)
  1299. continue;
  1300. //If bone is manually positioned there is no need to perform the bug check
  1301. bool skip = false;
  1302. for (auto &it : m_bone_position) {
  1303. if (it.first == bone->getName()) {
  1304. skip = true;
  1305. break;
  1306. }
  1307. }
  1308. if (skip)
  1309. continue;
  1310. // Workaround for Irrlicht bug
  1311. // We check each bone to see if it has been rotated ~180deg from its expected position due to a bug in Irricht
  1312. // when using EJUOR_CONTROL joint control. If the bug is detected we update the bone to the proper position
  1313. // and update the bones transformation.
  1314. v3f bone_rot = bone->getRelativeTransformation().getRotationDegrees();
  1315. float offset = fabsf(bone_rot.X - bone->getRotation().X);
  1316. if (offset > 179.9f && offset < 180.1f) {
  1317. bone->setRotation(bone_rot);
  1318. bone->updateAbsolutePosition();
  1319. }
  1320. }
  1321. // The following is needed for set_bone_pos to propagate to
  1322. // attached objects correctly.
  1323. // Irrlicht ought to do this, but doesn't when using EJUOR_CONTROL.
  1324. for (u32 i = 0; i < m_animated_meshnode->getJointCount(); ++i) {
  1325. auto bone = m_animated_meshnode->getJointNode(i);
  1326. // Look for the root bone.
  1327. if (bone && bone->getParent() == m_animated_meshnode) {
  1328. // Update entire skeleton.
  1329. bone->updateAbsolutePositionOfAllChildren();
  1330. break;
  1331. }
  1332. }
  1333. }
  1334. void GenericCAO::updateAttachments()
  1335. {
  1336. ClientActiveObject *parent = getParent();
  1337. m_attached_to_local = parent && parent->isLocalPlayer();
  1338. /*
  1339. Following cases exist:
  1340. m_attachment_parent_id == 0 && !parent
  1341. This object is not attached
  1342. m_attachment_parent_id != 0 && parent
  1343. This object is attached
  1344. m_attachment_parent_id != 0 && !parent
  1345. This object will be attached as soon the parent is known
  1346. m_attachment_parent_id == 0 && parent
  1347. Impossible case
  1348. */
  1349. if (!parent) { // Detach or don't attach
  1350. if (m_matrixnode) {
  1351. v3s16 camera_offset = m_env->getCameraOffset();
  1352. v3f old_pos = getPosition();
  1353. m_matrixnode->setParent(m_smgr->getRootSceneNode());
  1354. getPosRotMatrix().setTranslation(old_pos - intToFloat(camera_offset, BS));
  1355. m_matrixnode->updateAbsolutePosition();
  1356. }
  1357. }
  1358. else // Attach
  1359. {
  1360. parent->updateAttachments();
  1361. scene::ISceneNode *parent_node = parent->getSceneNode();
  1362. scene::IAnimatedMeshSceneNode *parent_animated_mesh_node =
  1363. parent->getAnimatedMeshSceneNode();
  1364. if (parent_animated_mesh_node && !m_attachment_bone.empty()) {
  1365. parent_node = parent_animated_mesh_node->getJointNode(m_attachment_bone.c_str());
  1366. }
  1367. if (m_matrixnode && parent_node) {
  1368. m_matrixnode->setParent(parent_node);
  1369. parent_node->updateAbsolutePosition();
  1370. getPosRotMatrix().setTranslation(m_attachment_position);
  1371. //setPitchYawRoll(getPosRotMatrix(), m_attachment_rotation);
  1372. // use Irrlicht eulers instead
  1373. getPosRotMatrix().setRotationDegrees(m_attachment_rotation);
  1374. m_matrixnode->updateAbsolutePosition();
  1375. }
  1376. }
  1377. }
  1378. bool GenericCAO::visualExpiryRequired(const ObjectProperties &new_) const
  1379. {
  1380. const ObjectProperties &old = m_prop;
  1381. /* Visuals do not need to be expired for:
  1382. * - nametag props: handled by updateNametag()
  1383. * - textures: handled by updateTextures()
  1384. * - sprite props: handled by updateTexturePos()
  1385. * - glow: handled by updateLight()
  1386. * - any other properties that do not change appearance
  1387. */
  1388. bool uses_legacy_texture = new_.wield_item.empty() &&
  1389. (new_.visual == "wielditem" || new_.visual == "item");
  1390. // Ordered to compare primitive types before std::vectors
  1391. return old.backface_culling != new_.backface_culling ||
  1392. old.is_visible != new_.is_visible ||
  1393. old.mesh != new_.mesh ||
  1394. old.shaded != new_.shaded ||
  1395. old.use_texture_alpha != new_.use_texture_alpha ||
  1396. old.visual != new_.visual ||
  1397. old.visual_size != new_.visual_size ||
  1398. old.wield_item != new_.wield_item ||
  1399. old.colors != new_.colors ||
  1400. (uses_legacy_texture && old.textures != new_.textures);
  1401. }
  1402. void GenericCAO::processMessage(const std::string &data)
  1403. {
  1404. //infostream<<"GenericCAO: Got message"<<std::endl;
  1405. std::istringstream is(data, std::ios::binary);
  1406. // command
  1407. u8 cmd = readU8(is);
  1408. if (cmd == AO_CMD_SET_PROPERTIES) {
  1409. ObjectProperties newprops;
  1410. newprops.show_on_minimap = m_is_player; // default
  1411. newprops.deSerialize(is);
  1412. // Check what exactly changed
  1413. bool expire_visuals = visualExpiryRequired(newprops);
  1414. bool textures_changed = m_prop.textures != newprops.textures;
  1415. // Apply changes
  1416. m_prop = std::move(newprops);
  1417. m_selection_box = m_prop.selectionbox;
  1418. m_selection_box.MinEdge *= BS;
  1419. m_selection_box.MaxEdge *= BS;
  1420. m_tx_size.X = 1.0f / m_prop.spritediv.X;
  1421. m_tx_size.Y = 1.0f / m_prop.spritediv.Y;
  1422. if(!m_initial_tx_basepos_set){
  1423. m_initial_tx_basepos_set = true;
  1424. m_tx_basepos = m_prop.initial_sprite_basepos;
  1425. }
  1426. if (m_is_local_player) {
  1427. LocalPlayer *player = m_env->getLocalPlayer();
  1428. player->makes_footstep_sound = m_prop.makes_footstep_sound;
  1429. aabb3f collision_box = m_prop.collisionbox;
  1430. collision_box.MinEdge *= BS;
  1431. collision_box.MaxEdge *= BS;
  1432. player->setCollisionbox(collision_box);
  1433. player->setEyeHeight(m_prop.eye_height);
  1434. player->setZoomFOV(m_prop.zoom_fov);
  1435. }
  1436. if ((m_is_player && !m_is_local_player) && m_prop.nametag.empty())
  1437. m_prop.nametag = m_name;
  1438. if (m_is_local_player)
  1439. m_prop.show_on_minimap = false;
  1440. if (expire_visuals) {
  1441. expireVisuals();
  1442. } else {
  1443. infostream << "GenericCAO: properties updated but expiring visuals"
  1444. << " not necessary" << std::endl;
  1445. if (textures_changed) {
  1446. // don't update while punch texture modifier is active
  1447. if (m_reset_textures_timer < 0)
  1448. updateTextures(m_current_texture_modifier);
  1449. }
  1450. updateNametag();
  1451. updateMarker();
  1452. }
  1453. } else if (cmd == AO_CMD_UPDATE_POSITION) {
  1454. // Not sent by the server if this object is an attachment.
  1455. // We might however get here if the server notices the object being detached before the client.
  1456. m_position = readV3F32(is);
  1457. m_velocity = readV3F32(is);
  1458. m_acceleration = readV3F32(is);
  1459. m_rotation = readV3F32(is);
  1460. m_rotation = wrapDegrees_0_360_v3f(m_rotation);
  1461. bool do_interpolate = readU8(is);
  1462. bool is_end_position = readU8(is);
  1463. float update_interval = readF32(is);
  1464. // Place us a bit higher if we're physical, to not sink into
  1465. // the ground due to sucky collision detection...
  1466. if(m_prop.physical)
  1467. m_position += v3f(0,0.002,0);
  1468. if(getParent() != NULL) // Just in case
  1469. return;
  1470. if(do_interpolate)
  1471. {
  1472. if(!m_prop.physical)
  1473. pos_translator.update(m_position, is_end_position, update_interval);
  1474. } else {
  1475. pos_translator.init(m_position);
  1476. }
  1477. rot_translator.update(m_rotation, false, update_interval);
  1478. updateNodePos();
  1479. } else if (cmd == AO_CMD_SET_TEXTURE_MOD) {
  1480. std::string mod = deSerializeString16(is);
  1481. // immediately reset a engine issued texture modifier if a mod sends a different one
  1482. if (m_reset_textures_timer > 0) {
  1483. m_reset_textures_timer = -1;
  1484. updateTextures(m_previous_texture_modifier);
  1485. }
  1486. updateTextures(mod);
  1487. } else if (cmd == AO_CMD_SET_SPRITE) {
  1488. v2s16 p = readV2S16(is);
  1489. int num_frames = readU16(is);
  1490. float framelength = readF32(is);
  1491. bool select_horiz_by_yawpitch = readU8(is);
  1492. m_tx_basepos = p;
  1493. m_anim_num_frames = num_frames;
  1494. m_anim_framelength = framelength;
  1495. m_tx_select_horiz_by_yawpitch = select_horiz_by_yawpitch;
  1496. updateTexturePos();
  1497. } else if (cmd == AO_CMD_SET_PHYSICS_OVERRIDE) {
  1498. float override_speed = readF32(is);
  1499. float override_jump = readF32(is);
  1500. float override_gravity = readF32(is);
  1501. // these are sent inverted so we get true when the server sends nothing
  1502. bool sneak = !readU8(is);
  1503. bool sneak_glitch = !readU8(is);
  1504. bool new_move = !readU8(is);
  1505. if(m_is_local_player)
  1506. {
  1507. LocalPlayer *player = m_env->getLocalPlayer();
  1508. player->physics_override_speed = override_speed;
  1509. player->physics_override_jump = override_jump;
  1510. player->physics_override_gravity = override_gravity;
  1511. player->physics_override_sneak = sneak;
  1512. player->physics_override_sneak_glitch = sneak_glitch;
  1513. player->physics_override_new_move = new_move;
  1514. }
  1515. } else if (cmd == AO_CMD_SET_ANIMATION) {
  1516. // TODO: change frames send as v2s32 value
  1517. v2f range = readV2F32(is);
  1518. if (!m_is_local_player) {
  1519. m_animation_range = v2s32((s32)range.X, (s32)range.Y);
  1520. m_animation_speed = readF32(is);
  1521. m_animation_blend = readF32(is);
  1522. // these are sent inverted so we get true when the server sends nothing
  1523. m_animation_loop = !readU8(is);
  1524. updateAnimation();
  1525. } else {
  1526. LocalPlayer *player = m_env->getLocalPlayer();
  1527. if(player->last_animation == NO_ANIM)
  1528. {
  1529. m_animation_range = v2s32((s32)range.X, (s32)range.Y);
  1530. m_animation_speed = readF32(is);
  1531. m_animation_blend = readF32(is);
  1532. // these are sent inverted so we get true when the server sends nothing
  1533. m_animation_loop = !readU8(is);
  1534. }
  1535. // update animation only if local animations present
  1536. // and received animation is unknown (except idle animation)
  1537. bool is_known = false;
  1538. for (int i = 1;i<4;i++)
  1539. {
  1540. if(m_animation_range.Y == player->local_animations[i].Y)
  1541. is_known = true;
  1542. }
  1543. if(!is_known ||
  1544. (player->local_animations[1].Y + player->local_animations[2].Y < 1))
  1545. {
  1546. updateAnimation();
  1547. }
  1548. }
  1549. } else if (cmd == AO_CMD_SET_ANIMATION_SPEED) {
  1550. m_animation_speed = readF32(is);
  1551. updateAnimationSpeed();
  1552. } else if (cmd == AO_CMD_SET_BONE_POSITION) {
  1553. std::string bone = deSerializeString16(is);
  1554. v3f position = readV3F32(is);
  1555. v3f rotation = readV3F32(is);
  1556. m_bone_position[bone] = core::vector2d<v3f>(position, rotation);
  1557. // updateBonePosition(); now called every step
  1558. } else if (cmd == AO_CMD_ATTACH_TO) {
  1559. u16 parent_id = readS16(is);
  1560. std::string bone = deSerializeString16(is);
  1561. v3f position = readV3F32(is);
  1562. v3f rotation = readV3F32(is);
  1563. bool force_visible = readU8(is); // Returns false for EOF
  1564. setAttachment(parent_id, bone, position, rotation, force_visible);
  1565. } else if (cmd == AO_CMD_PUNCHED) {
  1566. u16 result_hp = readU16(is);
  1567. // Use this instead of the send damage to not interfere with prediction
  1568. s32 damage = (s32)m_hp - (s32)result_hp;
  1569. m_hp = result_hp;
  1570. if (m_is_local_player)
  1571. m_env->getLocalPlayer()->hp = m_hp;
  1572. if (damage > 0)
  1573. {
  1574. if (m_hp == 0)
  1575. {
  1576. // TODO: Execute defined fast response
  1577. // As there is no definition, make a smoke puff
  1578. ClientSimpleObject *simple = createSmokePuff(
  1579. m_smgr, m_env, m_position,
  1580. v2f(m_prop.visual_size.X, m_prop.visual_size.Y) * BS);
  1581. m_env->addSimpleObject(simple);
  1582. } else if (m_reset_textures_timer < 0 && !m_prop.damage_texture_modifier.empty()) {
  1583. m_reset_textures_timer = 0.05;
  1584. if(damage >= 2)
  1585. m_reset_textures_timer += 0.05 * damage;
  1586. updateTextures(m_current_texture_modifier + m_prop.damage_texture_modifier);
  1587. }
  1588. }
  1589. if (m_hp == 0) {
  1590. // Same as 'Server::DiePlayer'
  1591. clearParentAttachment();
  1592. // Same as 'ObjectRef::l_remove'
  1593. if (!m_is_player)
  1594. clearChildAttachments();
  1595. }
  1596. } else if (cmd == AO_CMD_UPDATE_ARMOR_GROUPS) {
  1597. m_armor_groups.clear();
  1598. int armor_groups_size = readU16(is);
  1599. for(int i=0; i<armor_groups_size; i++)
  1600. {
  1601. std::string name = deSerializeString16(is);
  1602. int rating = readS16(is);
  1603. m_armor_groups[name] = rating;
  1604. }
  1605. } else if (cmd == AO_CMD_SPAWN_INFANT) {
  1606. u16 child_id = readU16(is);
  1607. u8 type = readU8(is); // maybe this will be useful later
  1608. (void)type;
  1609. addAttachmentChild(child_id);
  1610. } else if (cmd == AO_CMD_OBSOLETE1) {
  1611. // Don't do anything and also don't log a warning
  1612. } else {
  1613. warningstream << FUNCTION_NAME
  1614. << ": unknown command or outdated client \""
  1615. << +cmd << "\"" << std::endl;
  1616. }
  1617. }
  1618. /* \pre punchitem != NULL
  1619. */
  1620. bool GenericCAO::directReportPunch(v3f dir, const ItemStack *punchitem,
  1621. float time_from_last_punch)
  1622. {
  1623. assert(punchitem); // pre-condition
  1624. const ToolCapabilities *toolcap =
  1625. &punchitem->getToolCapabilities(m_client->idef());
  1626. PunchDamageResult result = getPunchDamage(
  1627. m_armor_groups,
  1628. toolcap,
  1629. punchitem,
  1630. time_from_last_punch);
  1631. if(result.did_punch && result.damage != 0)
  1632. {
  1633. if(result.damage < m_hp)
  1634. {
  1635. m_hp -= result.damage;
  1636. } else {
  1637. m_hp = 0;
  1638. // TODO: Execute defined fast response
  1639. // As there is no definition, make a smoke puff
  1640. ClientSimpleObject *simple = createSmokePuff(
  1641. m_smgr, m_env, m_position,
  1642. v2f(m_prop.visual_size.X, m_prop.visual_size.Y) * BS);
  1643. m_env->addSimpleObject(simple);
  1644. }
  1645. if (m_reset_textures_timer < 0 && !m_prop.damage_texture_modifier.empty()) {
  1646. m_reset_textures_timer = 0.05;
  1647. if (result.damage >= 2)
  1648. m_reset_textures_timer += 0.05 * result.damage;
  1649. updateTextures(m_current_texture_modifier + m_prop.damage_texture_modifier);
  1650. }
  1651. }
  1652. return false;
  1653. }
  1654. std::string GenericCAO::debugInfoText()
  1655. {
  1656. std::ostringstream os(std::ios::binary);
  1657. os<<"GenericCAO hp="<<m_hp<<"\n";
  1658. os<<"armor={";
  1659. for(ItemGroupList::const_iterator i = m_armor_groups.begin();
  1660. i != m_armor_groups.end(); ++i)
  1661. {
  1662. os<<i->first<<"="<<i->second<<", ";
  1663. }
  1664. os<<"}";
  1665. return os.str();
  1666. }
  1667. void GenericCAO::updateMeshCulling()
  1668. {
  1669. if (!m_is_local_player)
  1670. return;
  1671. const bool hidden = m_client->getCamera()->getCameraMode() == CAMERA_MODE_FIRST;
  1672. if (m_meshnode && m_prop.visual == "upright_sprite") {
  1673. u32 buffers = m_meshnode->getMesh()->getMeshBufferCount();
  1674. for (u32 i = 0; i < buffers; i++) {
  1675. video::SMaterial &mat = m_meshnode->getMesh()->getMeshBuffer(i)->getMaterial();
  1676. // upright sprite has no backface culling
  1677. mat.setFlag(video::EMF_FRONT_FACE_CULLING, hidden);
  1678. }
  1679. return;
  1680. }
  1681. irr::scene::ISceneNode *node = getSceneNode();
  1682. if (!node)
  1683. return;
  1684. if (hidden) {
  1685. // Hide the mesh by culling both front and
  1686. // back faces. Serious hackyness but it works for our
  1687. // purposes. This also preserves the skeletal armature.
  1688. node->setMaterialFlag(video::EMF_BACK_FACE_CULLING,
  1689. true);
  1690. node->setMaterialFlag(video::EMF_FRONT_FACE_CULLING,
  1691. true);
  1692. } else {
  1693. // Restore mesh visibility.
  1694. node->setMaterialFlag(video::EMF_BACK_FACE_CULLING,
  1695. m_prop.backface_culling);
  1696. node->setMaterialFlag(video::EMF_FRONT_FACE_CULLING,
  1697. false);
  1698. }
  1699. }
  1700. // Prototype
  1701. GenericCAO proto_GenericCAO(NULL, NULL);