content_cao.cpp 58 KB

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