clientenvironment.cpp 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620
  1. /*
  2. Minetest
  3. Copyright (C) 2010-2017 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 "util/serialize.h"
  17. #include "util/pointedthing.h"
  18. #include "client.h"
  19. #include "clientenvironment.h"
  20. #include "clientsimpleobject.h"
  21. #include "clientmap.h"
  22. #include "scripting_client.h"
  23. #include "mapblock_mesh.h"
  24. #include "event.h"
  25. #include "collision.h"
  26. #include "nodedef.h"
  27. #include "profiler.h"
  28. #include "raycast.h"
  29. #include "voxelalgorithms.h"
  30. #include "settings.h"
  31. #include <algorithm>
  32. #include "client/renderingengine.h"
  33. /*
  34. ClientEnvironment
  35. */
  36. ClientEnvironment::ClientEnvironment(ClientMap *map,
  37. ITextureSource *texturesource, Client *client):
  38. Environment(client),
  39. m_map(map),
  40. m_texturesource(texturesource),
  41. m_client(client)
  42. {
  43. char zero = 0;
  44. memset(attachement_parent_ids, zero, sizeof(attachement_parent_ids));
  45. }
  46. ClientEnvironment::~ClientEnvironment()
  47. {
  48. // delete active objects
  49. for (auto &active_object : m_active_objects) {
  50. delete active_object.second;
  51. }
  52. for (auto &simple_object : m_simple_objects) {
  53. delete simple_object;
  54. }
  55. // Drop/delete map
  56. m_map->drop();
  57. delete m_local_player;
  58. }
  59. Map & ClientEnvironment::getMap()
  60. {
  61. return *m_map;
  62. }
  63. ClientMap & ClientEnvironment::getClientMap()
  64. {
  65. return *m_map;
  66. }
  67. void ClientEnvironment::setLocalPlayer(LocalPlayer *player)
  68. {
  69. /*
  70. It is a failure if already is a local player
  71. */
  72. FATAL_ERROR_IF(m_local_player != NULL,
  73. "Local player already allocated");
  74. m_local_player = player;
  75. }
  76. void ClientEnvironment::step(float dtime)
  77. {
  78. /* Step time of day */
  79. stepTimeOfDay(dtime);
  80. // Get some settings
  81. bool fly_allowed = m_client->checkLocalPrivilege("fly");
  82. bool free_move = fly_allowed && g_settings->getBool("free_move");
  83. // Get local player
  84. LocalPlayer *lplayer = getLocalPlayer();
  85. assert(lplayer);
  86. // collision info queue
  87. std::vector<CollisionInfo> player_collisions;
  88. /*
  89. Get the speed the player is going
  90. */
  91. bool is_climbing = lplayer->is_climbing;
  92. f32 player_speed = lplayer->getSpeed().getLength();
  93. /*
  94. Maximum position increment
  95. */
  96. //f32 position_max_increment = 0.05*BS;
  97. f32 position_max_increment = 0.1*BS;
  98. // Maximum time increment (for collision detection etc)
  99. // time = distance / speed
  100. f32 dtime_max_increment = 1;
  101. if(player_speed > 0.001)
  102. dtime_max_increment = position_max_increment / player_speed;
  103. // Maximum time increment is 10ms or lower
  104. if(dtime_max_increment > 0.01)
  105. dtime_max_increment = 0.01;
  106. // Don't allow overly huge dtime
  107. if(dtime > 0.5)
  108. dtime = 0.5;
  109. f32 dtime_downcount = dtime;
  110. /*
  111. Stuff that has a maximum time increment
  112. */
  113. u32 loopcount = 0;
  114. do
  115. {
  116. loopcount++;
  117. f32 dtime_part;
  118. if(dtime_downcount > dtime_max_increment)
  119. {
  120. dtime_part = dtime_max_increment;
  121. dtime_downcount -= dtime_part;
  122. }
  123. else
  124. {
  125. dtime_part = dtime_downcount;
  126. /*
  127. Setting this to 0 (no -=dtime_part) disables an infinite loop
  128. when dtime_part is so small that dtime_downcount -= dtime_part
  129. does nothing
  130. */
  131. dtime_downcount = 0;
  132. }
  133. /*
  134. Handle local player
  135. */
  136. {
  137. // Apply physics
  138. if(!free_move && !is_climbing)
  139. {
  140. // Gravity
  141. v3f speed = lplayer->getSpeed();
  142. if(!lplayer->in_liquid)
  143. speed.Y -= lplayer->movement_gravity * lplayer->physics_override_gravity * dtime_part * 2;
  144. // Liquid floating / sinking
  145. if(lplayer->in_liquid && !lplayer->swimming_vertical)
  146. speed.Y -= lplayer->movement_liquid_sink * dtime_part * 2;
  147. // Liquid resistance
  148. if(lplayer->in_liquid_stable || lplayer->in_liquid)
  149. {
  150. // How much the node's viscosity blocks movement, ranges between 0 and 1
  151. // Should match the scale at which viscosity increase affects other liquid attributes
  152. const f32 viscosity_factor = 0.3;
  153. v3f d_wanted = -speed / lplayer->movement_liquid_fluidity;
  154. f32 dl = d_wanted.getLength();
  155. if(dl > lplayer->movement_liquid_fluidity_smooth)
  156. dl = lplayer->movement_liquid_fluidity_smooth;
  157. dl *= (lplayer->liquid_viscosity * viscosity_factor) + (1 - viscosity_factor);
  158. v3f d = d_wanted.normalize() * dl;
  159. speed += d;
  160. }
  161. lplayer->setSpeed(speed);
  162. }
  163. /*
  164. Move the lplayer.
  165. This also does collision detection.
  166. */
  167. lplayer->move(dtime_part, this, position_max_increment,
  168. &player_collisions);
  169. }
  170. }
  171. while(dtime_downcount > 0.001);
  172. //std::cout<<"Looped "<<loopcount<<" times."<<std::endl;
  173. for (const CollisionInfo &info : player_collisions) {
  174. v3f speed_diff = info.new_speed - info.old_speed;;
  175. // Handle only fall damage
  176. // (because otherwise walking against something in fast_move kills you)
  177. if (speed_diff.Y < 0 || info.old_speed.Y >= 0)
  178. continue;
  179. // Get rid of other components
  180. speed_diff.X = 0;
  181. speed_diff.Z = 0;
  182. f32 pre_factor = 1; // 1 hp per node/s
  183. f32 tolerance = BS*14; // 5 without damage
  184. f32 post_factor = 1; // 1 hp per node/s
  185. if (info.type == COLLISION_NODE) {
  186. const ContentFeatures &f = m_client->ndef()->
  187. get(m_map->getNodeNoEx(info.node_p));
  188. // Determine fall damage multiplier
  189. int addp = itemgroup_get(f.groups, "fall_damage_add_percent");
  190. pre_factor = 1.0 + (float)addp/100.0;
  191. }
  192. float speed = pre_factor * speed_diff.getLength();
  193. if (speed > tolerance) {
  194. f32 damage_f = (speed - tolerance) / BS * post_factor;
  195. u8 damage = (u8)MYMIN(damage_f + 0.5, 255);
  196. if (damage != 0) {
  197. damageLocalPlayer(damage, true);
  198. MtEvent *e = new SimpleTriggerEvent("PlayerFallingDamage");
  199. m_client->event()->put(e);
  200. }
  201. }
  202. }
  203. if (m_client->moddingEnabled()) {
  204. m_script->environment_step(dtime);
  205. }
  206. // Protocol v29 make this behaviour obsolete
  207. if (getGameDef()->getProtoVersion() < 29) {
  208. if (m_lava_hurt_interval.step(dtime, 1.0)) {
  209. v3f pf = lplayer->getPosition();
  210. // Feet, middle and head
  211. v3s16 p1 = floatToInt(pf + v3f(0, BS * 0.1, 0), BS);
  212. MapNode n1 = m_map->getNodeNoEx(p1);
  213. v3s16 p2 = floatToInt(pf + v3f(0, BS * 0.8, 0), BS);
  214. MapNode n2 = m_map->getNodeNoEx(p2);
  215. v3s16 p3 = floatToInt(pf + v3f(0, BS * 1.6, 0), BS);
  216. MapNode n3 = m_map->getNodeNoEx(p3);
  217. u32 damage_per_second = 0;
  218. damage_per_second = MYMAX(damage_per_second,
  219. m_client->ndef()->get(n1).damage_per_second);
  220. damage_per_second = MYMAX(damage_per_second,
  221. m_client->ndef()->get(n2).damage_per_second);
  222. damage_per_second = MYMAX(damage_per_second,
  223. m_client->ndef()->get(n3).damage_per_second);
  224. if (damage_per_second != 0)
  225. damageLocalPlayer(damage_per_second, true);
  226. }
  227. /*
  228. Drowning
  229. */
  230. if (m_drowning_interval.step(dtime, 2.0)) {
  231. v3f pf = lplayer->getPosition();
  232. // head
  233. v3s16 p = floatToInt(pf + v3f(0, BS * 1.6, 0), BS);
  234. MapNode n = m_map->getNodeNoEx(p);
  235. ContentFeatures c = m_client->ndef()->get(n);
  236. u8 drowning_damage = c.drowning;
  237. if (drowning_damage > 0 && lplayer->hp > 0) {
  238. u16 breath = lplayer->getBreath();
  239. if (breath > 10) {
  240. breath = 11;
  241. }
  242. if (breath > 0) {
  243. breath -= 1;
  244. }
  245. lplayer->setBreath(breath);
  246. updateLocalPlayerBreath(breath);
  247. }
  248. if (lplayer->getBreath() == 0 && drowning_damage > 0) {
  249. damageLocalPlayer(drowning_damage, true);
  250. }
  251. }
  252. if (m_breathing_interval.step(dtime, 0.5)) {
  253. v3f pf = lplayer->getPosition();
  254. // head
  255. v3s16 p = floatToInt(pf + v3f(0, BS * 1.6, 0), BS);
  256. MapNode n = m_map->getNodeNoEx(p);
  257. ContentFeatures c = m_client->ndef()->get(n);
  258. if (!lplayer->hp) {
  259. lplayer->setBreath(11);
  260. } else if (c.drowning == 0) {
  261. u16 breath = lplayer->getBreath();
  262. if (breath <= 10) {
  263. breath += 1;
  264. lplayer->setBreath(breath);
  265. updateLocalPlayerBreath(breath);
  266. }
  267. }
  268. }
  269. }
  270. // Update lighting on local player (used for wield item)
  271. u32 day_night_ratio = getDayNightRatio();
  272. {
  273. // Get node at head
  274. // On InvalidPositionException, use this as default
  275. // (day: LIGHT_SUN, night: 0)
  276. MapNode node_at_lplayer(CONTENT_AIR, 0x0f, 0);
  277. v3s16 p = lplayer->getLightPosition();
  278. node_at_lplayer = m_map->getNodeNoEx(p);
  279. u16 light = getInteriorLight(node_at_lplayer, 0, m_client->ndef());
  280. final_color_blend(&lplayer->light_color, light, day_night_ratio);
  281. }
  282. /*
  283. Step active objects and update lighting of them
  284. */
  285. g_profiler->avg("CEnv: num of objects", m_active_objects.size());
  286. bool update_lighting = m_active_object_light_update_interval.step(dtime, 0.21);
  287. for (auto &ao_it : m_active_objects) {
  288. ClientActiveObject* obj = ao_it.second;
  289. // Step object
  290. obj->step(dtime, this);
  291. if (update_lighting) {
  292. // Update lighting
  293. u8 light = 0;
  294. bool pos_ok;
  295. // Get node at head
  296. v3s16 p = obj->getLightPosition();
  297. MapNode n = m_map->getNodeNoEx(p, &pos_ok);
  298. if (pos_ok)
  299. light = n.getLightBlend(day_night_ratio, m_client->ndef());
  300. else
  301. light = blend_light(day_night_ratio, LIGHT_SUN, 0);
  302. obj->updateLight(light);
  303. }
  304. }
  305. /*
  306. Step and handle simple objects
  307. */
  308. g_profiler->avg("CEnv: num of simple objects", m_simple_objects.size());
  309. for (auto i = m_simple_objects.begin(); i != m_simple_objects.end();) {
  310. auto cur = i;
  311. ClientSimpleObject *simple = *cur;
  312. simple->step(dtime);
  313. if(simple->m_to_be_removed) {
  314. delete simple;
  315. i = m_simple_objects.erase(cur);
  316. }
  317. else {
  318. ++i;
  319. }
  320. }
  321. }
  322. void ClientEnvironment::addSimpleObject(ClientSimpleObject *simple)
  323. {
  324. m_simple_objects.push_back(simple);
  325. }
  326. GenericCAO* ClientEnvironment::getGenericCAO(u16 id)
  327. {
  328. ClientActiveObject *obj = getActiveObject(id);
  329. if (obj && obj->getType() == ACTIVEOBJECT_TYPE_GENERIC)
  330. return (GenericCAO*) obj;
  331. return NULL;
  332. }
  333. ClientActiveObject* ClientEnvironment::getActiveObject(u16 id)
  334. {
  335. auto n = m_active_objects.find(id);
  336. if (n == m_active_objects.end())
  337. return NULL;
  338. return n->second;
  339. }
  340. bool isFreeClientActiveObjectId(const u16 id,
  341. ClientActiveObjectMap &objects)
  342. {
  343. return id != 0 && objects.find(id) == objects.end();
  344. }
  345. u16 getFreeClientActiveObjectId(ClientActiveObjectMap &objects)
  346. {
  347. //try to reuse id's as late as possible
  348. static u16 last_used_id = 0;
  349. u16 startid = last_used_id;
  350. for(;;) {
  351. last_used_id ++;
  352. if (isFreeClientActiveObjectId(last_used_id, objects))
  353. return last_used_id;
  354. if (last_used_id == startid)
  355. return 0;
  356. }
  357. }
  358. u16 ClientEnvironment::addActiveObject(ClientActiveObject *object)
  359. {
  360. assert(object); // Pre-condition
  361. if(object->getId() == 0)
  362. {
  363. u16 new_id = getFreeClientActiveObjectId(m_active_objects);
  364. if(new_id == 0)
  365. {
  366. infostream<<"ClientEnvironment::addActiveObject(): "
  367. <<"no free ids available"<<std::endl;
  368. delete object;
  369. return 0;
  370. }
  371. object->setId(new_id);
  372. }
  373. if (!isFreeClientActiveObjectId(object->getId(), m_active_objects)) {
  374. infostream<<"ClientEnvironment::addActiveObject(): "
  375. <<"id is not free ("<<object->getId()<<")"<<std::endl;
  376. delete object;
  377. return 0;
  378. }
  379. infostream<<"ClientEnvironment::addActiveObject(): "
  380. <<"added (id="<<object->getId()<<")"<<std::endl;
  381. m_active_objects[object->getId()] = object;
  382. object->addToScene(m_texturesource);
  383. { // Update lighting immediately
  384. u8 light = 0;
  385. bool pos_ok;
  386. // Get node at head
  387. v3s16 p = object->getLightPosition();
  388. MapNode n = m_map->getNodeNoEx(p, &pos_ok);
  389. if (pos_ok)
  390. light = n.getLightBlend(getDayNightRatio(), m_client->ndef());
  391. else
  392. light = blend_light(getDayNightRatio(), LIGHT_SUN, 0);
  393. object->updateLight(light);
  394. }
  395. return object->getId();
  396. }
  397. void ClientEnvironment::addActiveObject(u16 id, u8 type,
  398. const std::string &init_data)
  399. {
  400. ClientActiveObject* obj =
  401. ClientActiveObject::create((ActiveObjectType) type, m_client, this);
  402. if(obj == NULL)
  403. {
  404. infostream<<"ClientEnvironment::addActiveObject(): "
  405. <<"id="<<id<<" type="<<type<<": Couldn't create object"
  406. <<std::endl;
  407. return;
  408. }
  409. obj->setId(id);
  410. try
  411. {
  412. obj->initialize(init_data);
  413. }
  414. catch(SerializationError &e)
  415. {
  416. errorstream<<"ClientEnvironment::addActiveObject():"
  417. <<" id="<<id<<" type="<<type
  418. <<": SerializationError in initialize(): "
  419. <<e.what()
  420. <<": init_data="<<serializeJsonString(init_data)
  421. <<std::endl;
  422. }
  423. addActiveObject(obj);
  424. }
  425. void ClientEnvironment::removeActiveObject(u16 id)
  426. {
  427. verbosestream<<"ClientEnvironment::removeActiveObject(): "
  428. <<"id="<<id<<std::endl;
  429. ClientActiveObject* obj = getActiveObject(id);
  430. if (obj == NULL) {
  431. infostream<<"ClientEnvironment::removeActiveObject(): "
  432. <<"id="<<id<<" not found"<<std::endl;
  433. return;
  434. }
  435. obj->removeFromScene(true);
  436. delete obj;
  437. m_active_objects.erase(id);
  438. }
  439. void ClientEnvironment::processActiveObjectMessage(u16 id, const std::string &data)
  440. {
  441. ClientActiveObject *obj = getActiveObject(id);
  442. if (obj == NULL) {
  443. infostream << "ClientEnvironment::processActiveObjectMessage():"
  444. << " got message for id=" << id << ", which doesn't exist."
  445. << std::endl;
  446. return;
  447. }
  448. try {
  449. obj->processMessage(data);
  450. } catch (SerializationError &e) {
  451. errorstream<<"ClientEnvironment::processActiveObjectMessage():"
  452. << " id=" << id << " type=" << obj->getType()
  453. << " SerializationError in processMessage(): " << e.what()
  454. << std::endl;
  455. }
  456. }
  457. /*
  458. Callbacks for activeobjects
  459. */
  460. void ClientEnvironment::damageLocalPlayer(u8 damage, bool handle_hp)
  461. {
  462. LocalPlayer *lplayer = getLocalPlayer();
  463. assert(lplayer);
  464. if (handle_hp) {
  465. if (lplayer->hp > damage)
  466. lplayer->hp -= damage;
  467. else
  468. lplayer->hp = 0;
  469. }
  470. ClientEnvEvent event;
  471. event.type = CEE_PLAYER_DAMAGE;
  472. event.player_damage.amount = damage;
  473. event.player_damage.send_to_server = handle_hp;
  474. m_client_event_queue.push(event);
  475. }
  476. void ClientEnvironment::updateLocalPlayerBreath(u16 breath)
  477. {
  478. ClientEnvEvent event;
  479. event.type = CEE_PLAYER_BREATH;
  480. event.player_breath.amount = breath;
  481. m_client_event_queue.push(event);
  482. }
  483. /*
  484. Client likes to call these
  485. */
  486. void ClientEnvironment::getActiveObjects(v3f origin, f32 max_d,
  487. std::vector<DistanceSortedActiveObject> &dest)
  488. {
  489. for (auto &ao_it : m_active_objects) {
  490. ClientActiveObject* obj = ao_it.second;
  491. f32 d = (obj->getPosition() - origin).getLength();
  492. if (d > max_d)
  493. continue;
  494. dest.emplace_back(obj, d);
  495. }
  496. }
  497. ClientEnvEvent ClientEnvironment::getClientEnvEvent()
  498. {
  499. FATAL_ERROR_IF(m_client_event_queue.empty(),
  500. "ClientEnvironment::getClientEnvEvent(): queue is empty");
  501. ClientEnvEvent event = m_client_event_queue.front();
  502. m_client_event_queue.pop();
  503. return event;
  504. }
  505. void ClientEnvironment::getSelectedActiveObjects(
  506. const core::line3d<f32> &shootline_on_map,
  507. std::vector<PointedThing> &objects)
  508. {
  509. std::vector<DistanceSortedActiveObject> allObjects;
  510. getActiveObjects(shootline_on_map.start,
  511. shootline_on_map.getLength() + 10.0f, allObjects);
  512. const v3f line_vector = shootline_on_map.getVector();
  513. for (const auto &allObject : allObjects) {
  514. ClientActiveObject *obj = allObject.obj;
  515. aabb3f selection_box;
  516. if (!obj->getSelectionBox(&selection_box))
  517. continue;
  518. const v3f &pos = obj->getPosition();
  519. aabb3f offsetted_box(selection_box.MinEdge + pos,
  520. selection_box.MaxEdge + pos);
  521. v3f current_intersection;
  522. v3s16 current_normal;
  523. if (boxLineCollision(offsetted_box, shootline_on_map.start, line_vector,
  524. &current_intersection, &current_normal)) {
  525. objects.emplace_back((s16) obj->getId(), current_intersection, current_normal,
  526. (current_intersection - shootline_on_map.start).getLengthSQ());
  527. }
  528. }
  529. }