clientenvironment.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542
  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 "shader.h"
  32. #include "content_cao.h"
  33. #include <algorithm>
  34. #include "client/renderingengine.h"
  35. /*
  36. CAOShaderConstantSetter
  37. */
  38. //! Shader constant setter for passing material emissive color to the CAO object_shader
  39. class CAOShaderConstantSetter : public IShaderConstantSetter
  40. {
  41. public:
  42. CAOShaderConstantSetter():
  43. m_emissive_color_setting("emissiveColor")
  44. {}
  45. ~CAOShaderConstantSetter() override = default;
  46. void onSetConstants(video::IMaterialRendererServices *services,
  47. bool is_highlevel) override
  48. {
  49. if (!is_highlevel)
  50. return;
  51. // Ambient color
  52. video::SColorf emissive_color(m_emissive_color);
  53. float as_array[4] = {
  54. emissive_color.r,
  55. emissive_color.g,
  56. emissive_color.b,
  57. emissive_color.a,
  58. };
  59. m_emissive_color_setting.set(as_array, services);
  60. }
  61. void onSetMaterial(const video::SMaterial& material) override
  62. {
  63. m_emissive_color = material.EmissiveColor;
  64. }
  65. private:
  66. video::SColor m_emissive_color;
  67. CachedPixelShaderSetting<float, 4> m_emissive_color_setting;
  68. };
  69. class CAOShaderConstantSetterFactory : public IShaderConstantSetterFactory
  70. {
  71. public:
  72. CAOShaderConstantSetterFactory()
  73. {}
  74. virtual IShaderConstantSetter* create()
  75. {
  76. return new CAOShaderConstantSetter();
  77. }
  78. };
  79. /*
  80. ClientEnvironment
  81. */
  82. ClientEnvironment::ClientEnvironment(ClientMap *map,
  83. ITextureSource *texturesource, Client *client):
  84. Environment(client),
  85. m_map(map),
  86. m_texturesource(texturesource),
  87. m_client(client)
  88. {
  89. auto *shdrsrc = m_client->getShaderSource();
  90. shdrsrc->addShaderConstantSetterFactory(new CAOShaderConstantSetterFactory());
  91. }
  92. ClientEnvironment::~ClientEnvironment()
  93. {
  94. m_ao_manager.clear();
  95. for (auto &simple_object : m_simple_objects) {
  96. delete simple_object;
  97. }
  98. // Drop/delete map
  99. m_map->drop();
  100. delete m_local_player;
  101. }
  102. Map & ClientEnvironment::getMap()
  103. {
  104. return *m_map;
  105. }
  106. ClientMap & ClientEnvironment::getClientMap()
  107. {
  108. return *m_map;
  109. }
  110. void ClientEnvironment::setLocalPlayer(LocalPlayer *player)
  111. {
  112. /*
  113. It is a failure if already is a local player
  114. */
  115. FATAL_ERROR_IF(m_local_player != NULL,
  116. "Local player already allocated");
  117. m_local_player = player;
  118. }
  119. void ClientEnvironment::step(float dtime)
  120. {
  121. /* Step time of day */
  122. stepTimeOfDay(dtime);
  123. // Get some settings
  124. bool fly_allowed = m_client->checkLocalPrivilege("fly");
  125. bool free_move = fly_allowed && g_settings->getBool("free_move");
  126. // Get local player
  127. LocalPlayer *lplayer = getLocalPlayer();
  128. assert(lplayer);
  129. // collision info queue
  130. std::vector<CollisionInfo> player_collisions;
  131. /*
  132. Get the speed the player is going
  133. */
  134. bool is_climbing = lplayer->is_climbing;
  135. f32 player_speed = lplayer->getSpeed().getLength();
  136. /*
  137. Maximum position increment
  138. */
  139. //f32 position_max_increment = 0.05*BS;
  140. f32 position_max_increment = 0.1*BS;
  141. // Maximum time increment (for collision detection etc)
  142. // time = distance / speed
  143. f32 dtime_max_increment = 1;
  144. if(player_speed > 0.001)
  145. dtime_max_increment = position_max_increment / player_speed;
  146. // Maximum time increment is 10ms or lower
  147. if(dtime_max_increment > 0.01)
  148. dtime_max_increment = 0.01;
  149. // Don't allow overly huge dtime
  150. if(dtime > 0.5)
  151. dtime = 0.5;
  152. f32 dtime_downcount = dtime;
  153. /*
  154. Stuff that has a maximum time increment
  155. */
  156. u32 loopcount = 0;
  157. do
  158. {
  159. loopcount++;
  160. f32 dtime_part;
  161. if(dtime_downcount > dtime_max_increment)
  162. {
  163. dtime_part = dtime_max_increment;
  164. dtime_downcount -= dtime_part;
  165. }
  166. else
  167. {
  168. dtime_part = dtime_downcount;
  169. /*
  170. Setting this to 0 (no -=dtime_part) disables an infinite loop
  171. when dtime_part is so small that dtime_downcount -= dtime_part
  172. does nothing
  173. */
  174. dtime_downcount = 0;
  175. }
  176. /*
  177. Handle local player
  178. */
  179. {
  180. // Control local player
  181. lplayer->applyControl(dtime_part, this);
  182. // Apply physics
  183. if (!free_move && !is_climbing) {
  184. // Gravity
  185. v3f speed = lplayer->getSpeed();
  186. if (!lplayer->in_liquid)
  187. speed.Y -= lplayer->movement_gravity *
  188. lplayer->physics_override_gravity * dtime_part * 2.0f;
  189. // Liquid floating / sinking
  190. if (lplayer->in_liquid && !lplayer->swimming_vertical &&
  191. !lplayer->swimming_pitch)
  192. speed.Y -= lplayer->movement_liquid_sink * dtime_part * 2.0f;
  193. // Liquid resistance
  194. if (lplayer->in_liquid_stable || lplayer->in_liquid) {
  195. // How much the node's viscosity blocks movement, ranges
  196. // between 0 and 1. Should match the scale at which viscosity
  197. // increase affects other liquid attributes.
  198. static const f32 viscosity_factor = 0.3f;
  199. v3f d_wanted = -speed / lplayer->movement_liquid_fluidity;
  200. f32 dl = d_wanted.getLength();
  201. if (dl > lplayer->movement_liquid_fluidity_smooth)
  202. dl = lplayer->movement_liquid_fluidity_smooth;
  203. dl *= (lplayer->liquid_viscosity * viscosity_factor) +
  204. (1 - viscosity_factor);
  205. v3f d = d_wanted.normalize() * (dl * dtime_part * 100.0f);
  206. speed += d;
  207. }
  208. lplayer->setSpeed(speed);
  209. }
  210. /*
  211. Move the lplayer.
  212. This also does collision detection.
  213. */
  214. lplayer->move(dtime_part, this, position_max_increment,
  215. &player_collisions);
  216. }
  217. } while (dtime_downcount > 0.001);
  218. bool player_immortal = lplayer->getCAO() && lplayer->getCAO()->isImmortal();
  219. for (const CollisionInfo &info : player_collisions) {
  220. v3f speed_diff = info.new_speed - info.old_speed;;
  221. // Handle only fall damage
  222. // (because otherwise walking against something in fast_move kills you)
  223. if (speed_diff.Y < 0 || info.old_speed.Y >= 0)
  224. continue;
  225. // Get rid of other components
  226. speed_diff.X = 0;
  227. speed_diff.Z = 0;
  228. f32 pre_factor = 1; // 1 hp per node/s
  229. f32 tolerance = BS*14; // 5 without damage
  230. f32 post_factor = 1; // 1 hp per node/s
  231. if (info.type == COLLISION_NODE) {
  232. const ContentFeatures &f = m_client->ndef()->
  233. get(m_map->getNode(info.node_p));
  234. // Determine fall damage multiplier
  235. int addp = itemgroup_get(f.groups, "fall_damage_add_percent");
  236. pre_factor = 1.0f + (float)addp / 100.0f;
  237. }
  238. float speed = pre_factor * speed_diff.getLength();
  239. if (speed > tolerance && !player_immortal) {
  240. f32 damage_f = (speed - tolerance) / BS * post_factor;
  241. u16 damage = (u16)MYMIN(damage_f + 0.5, U16_MAX);
  242. if (damage != 0) {
  243. damageLocalPlayer(damage, true);
  244. m_client->getEventManager()->put(
  245. new SimpleTriggerEvent(MtEvent::PLAYER_FALLING_DAMAGE));
  246. }
  247. }
  248. }
  249. if (m_client->modsLoaded())
  250. m_script->environment_step(dtime);
  251. // Update lighting on local player (used for wield item)
  252. u32 day_night_ratio = getDayNightRatio();
  253. {
  254. // Get node at head
  255. // On InvalidPositionException, use this as default
  256. // (day: LIGHT_SUN, night: 0)
  257. MapNode node_at_lplayer(CONTENT_AIR, 0x0f, 0);
  258. v3s16 p = lplayer->getLightPosition();
  259. node_at_lplayer = m_map->getNode(p);
  260. u16 light = getInteriorLight(node_at_lplayer, 0, m_client->ndef());
  261. final_color_blend(&lplayer->light_color, light, day_night_ratio);
  262. }
  263. /*
  264. Step active objects and update lighting of them
  265. */
  266. bool update_lighting = m_active_object_light_update_interval.step(dtime, 0.21);
  267. auto cb_state = [this, dtime, update_lighting, day_night_ratio] (ClientActiveObject *cao) {
  268. // Step object
  269. cao->step(dtime, this);
  270. if (update_lighting)
  271. cao->updateLight(day_night_ratio);
  272. };
  273. m_ao_manager.step(dtime, cb_state);
  274. /*
  275. Step and handle simple objects
  276. */
  277. g_profiler->avg("ClientEnv: CSO count [#]", m_simple_objects.size());
  278. for (auto i = m_simple_objects.begin(); i != m_simple_objects.end();) {
  279. ClientSimpleObject *simple = *i;
  280. simple->step(dtime);
  281. if(simple->m_to_be_removed) {
  282. delete simple;
  283. i = m_simple_objects.erase(i);
  284. }
  285. else {
  286. ++i;
  287. }
  288. }
  289. }
  290. void ClientEnvironment::addSimpleObject(ClientSimpleObject *simple)
  291. {
  292. m_simple_objects.push_back(simple);
  293. }
  294. GenericCAO* ClientEnvironment::getGenericCAO(u16 id)
  295. {
  296. ClientActiveObject *obj = getActiveObject(id);
  297. if (obj && obj->getType() == ACTIVEOBJECT_TYPE_GENERIC)
  298. return (GenericCAO*) obj;
  299. return NULL;
  300. }
  301. bool isFreeClientActiveObjectId(const u16 id,
  302. ClientActiveObjectMap &objects)
  303. {
  304. return id != 0 && objects.find(id) == objects.end();
  305. }
  306. u16 getFreeClientActiveObjectId(ClientActiveObjectMap &objects)
  307. {
  308. // try to reuse id's as late as possible
  309. static u16 last_used_id = 0;
  310. u16 startid = last_used_id;
  311. for(;;) {
  312. last_used_id ++;
  313. if (isFreeClientActiveObjectId(last_used_id, objects))
  314. return last_used_id;
  315. if (last_used_id == startid)
  316. return 0;
  317. }
  318. }
  319. u16 ClientEnvironment::addActiveObject(ClientActiveObject *object)
  320. {
  321. // Register object. If failed return zero id
  322. if (!m_ao_manager.registerObject(object))
  323. return 0;
  324. object->addToScene(m_texturesource);
  325. // Update lighting immediately
  326. object->updateLight(getDayNightRatio());
  327. return object->getId();
  328. }
  329. void ClientEnvironment::addActiveObject(u16 id, u8 type,
  330. const std::string &init_data)
  331. {
  332. ClientActiveObject* obj =
  333. ClientActiveObject::create((ActiveObjectType) type, m_client, this);
  334. if(obj == NULL)
  335. {
  336. infostream<<"ClientEnvironment::addActiveObject(): "
  337. <<"id="<<id<<" type="<<type<<": Couldn't create object"
  338. <<std::endl;
  339. return;
  340. }
  341. obj->setId(id);
  342. try
  343. {
  344. obj->initialize(init_data);
  345. }
  346. catch(SerializationError &e)
  347. {
  348. errorstream<<"ClientEnvironment::addActiveObject():"
  349. <<" id="<<id<<" type="<<type
  350. <<": SerializationError in initialize(): "
  351. <<e.what()
  352. <<": init_data="<<serializeJsonString(init_data)
  353. <<std::endl;
  354. }
  355. u16 new_id = addActiveObject(obj);
  356. // Object initialized:
  357. if ((obj = getActiveObject(new_id))) {
  358. // Final step is to update all children which are already known
  359. // Data provided by AO_CMD_SPAWN_INFANT
  360. const auto &children = obj->getAttachmentChildIds();
  361. for (auto c_id : children) {
  362. if (auto *o = getActiveObject(c_id))
  363. o->updateAttachments();
  364. }
  365. }
  366. }
  367. void ClientEnvironment::removeActiveObject(u16 id)
  368. {
  369. // Get current attachment childs to detach them visually
  370. std::unordered_set<int> attachment_childs;
  371. if (auto *obj = getActiveObject(id))
  372. attachment_childs = obj->getAttachmentChildIds();
  373. m_ao_manager.removeObject(id);
  374. // Perform a proper detach in Irrlicht
  375. for (auto c_id : attachment_childs) {
  376. if (ClientActiveObject *child = getActiveObject(c_id))
  377. child->updateAttachments();
  378. }
  379. }
  380. void ClientEnvironment::processActiveObjectMessage(u16 id, const std::string &data)
  381. {
  382. ClientActiveObject *obj = getActiveObject(id);
  383. if (obj == NULL) {
  384. infostream << "ClientEnvironment::processActiveObjectMessage():"
  385. << " got message for id=" << id << ", which doesn't exist."
  386. << std::endl;
  387. return;
  388. }
  389. try {
  390. obj->processMessage(data);
  391. } catch (SerializationError &e) {
  392. errorstream<<"ClientEnvironment::processActiveObjectMessage():"
  393. << " id=" << id << " type=" << obj->getType()
  394. << " SerializationError in processMessage(): " << e.what()
  395. << std::endl;
  396. }
  397. }
  398. /*
  399. Callbacks for activeobjects
  400. */
  401. void ClientEnvironment::damageLocalPlayer(u16 damage, bool handle_hp)
  402. {
  403. LocalPlayer *lplayer = getLocalPlayer();
  404. assert(lplayer);
  405. if (handle_hp) {
  406. if (lplayer->hp > damage)
  407. lplayer->hp -= damage;
  408. else
  409. lplayer->hp = 0;
  410. }
  411. ClientEnvEvent event;
  412. event.type = CEE_PLAYER_DAMAGE;
  413. event.player_damage.amount = damage;
  414. event.player_damage.send_to_server = handle_hp;
  415. m_client_event_queue.push(event);
  416. }
  417. /*
  418. Client likes to call these
  419. */
  420. ClientEnvEvent ClientEnvironment::getClientEnvEvent()
  421. {
  422. FATAL_ERROR_IF(m_client_event_queue.empty(),
  423. "ClientEnvironment::getClientEnvEvent(): queue is empty");
  424. ClientEnvEvent event = m_client_event_queue.front();
  425. m_client_event_queue.pop();
  426. return event;
  427. }
  428. void ClientEnvironment::getSelectedActiveObjects(
  429. const core::line3d<f32> &shootline_on_map,
  430. std::vector<PointedThing> &objects)
  431. {
  432. std::vector<DistanceSortedActiveObject> allObjects;
  433. getActiveObjects(shootline_on_map.start,
  434. shootline_on_map.getLength() + 10.0f, allObjects);
  435. const v3f line_vector = shootline_on_map.getVector();
  436. for (const auto &allObject : allObjects) {
  437. ClientActiveObject *obj = allObject.obj;
  438. aabb3f selection_box;
  439. if (!obj->getSelectionBox(&selection_box))
  440. continue;
  441. const v3f &pos = obj->getPosition();
  442. aabb3f offsetted_box(selection_box.MinEdge + pos,
  443. selection_box.MaxEdge + pos);
  444. v3f current_intersection;
  445. v3s16 current_normal;
  446. if (boxLineCollision(offsetted_box, shootline_on_map.start, line_vector,
  447. &current_intersection, &current_normal)) {
  448. objects.emplace_back((s16) obj->getId(), current_intersection, current_normal,
  449. (current_intersection - shootline_on_map.start).getLengthSQ());
  450. }
  451. }
  452. }