clientenvironment.cpp 14 KB

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