#include "util/serialize.h"
#include "util/pointedthing.h"
+#include "client.h"
#include "clientenvironment.h"
#include "clientsimpleobject.h"
#include "clientmap.h"
#include "mapblock_mesh.h"
#include "event.h"
#include "collision.h"
+#include "nodedef.h"
#include "profiler.h"
#include "raycast.h"
#include "voxelalgorithms.h"
#include "settings.h"
+#include "content_cao.h"
#include <algorithm>
+#include "client/renderingengine.h"
/*
ClientEnvironment
*/
-ClientEnvironment::ClientEnvironment(ClientMap *map, scene::ISceneManager *smgr,
- ITextureSource *texturesource, Client *client,
- IrrlichtDevice *irr):
+ClientEnvironment::ClientEnvironment(ClientMap *map,
+ ITextureSource *texturesource, Client *client):
Environment(client),
m_map(map),
- m_smgr(smgr),
m_texturesource(texturesource),
- m_client(client),
- m_irr(irr)
+ m_client(client)
{
char zero = 0;
memset(attachement_parent_ids, zero, sizeof(attachement_parent_ids));
ClientEnvironment::~ClientEnvironment()
{
// delete active objects
- for (ClientActiveObjectMap::iterator i = m_active_objects.begin();
- i != m_active_objects.end(); ++i) {
- delete i->second;
+ for (auto &active_object : m_active_objects) {
+ delete active_object.second;
}
- for(std::vector<ClientSimpleObject*>::iterator
- i = m_simple_objects.begin(); i != m_simple_objects.end(); ++i) {
- delete *i;
+ for (auto &simple_object : m_simple_objects) {
+ delete simple_object;
}
// Drop/delete map
void ClientEnvironment::setLocalPlayer(LocalPlayer *player)
{
- DSTACK(FUNCTION_NAME);
/*
It is a failure if already is a local player
*/
void ClientEnvironment::step(float dtime)
{
- DSTACK(FUNCTION_NAME);
-
/* Step time of day */
stepTimeOfDay(dtime);
//std::cout<<"Looped "<<loopcount<<" times."<<std::endl;
- for(std::vector<CollisionInfo>::iterator i = player_collisions.begin();
- i != player_collisions.end(); ++i) {
- CollisionInfo &info = *i;
+ bool player_immortal = lplayer->getCAO() && lplayer->getCAO()->isImmortal();
+
+ for (const CollisionInfo &info : player_collisions) {
v3f speed_diff = info.new_speed - info.old_speed;;
// Handle only fall damage
// (because otherwise walking against something in fast_move kills you)
- if(speed_diff.Y < 0 || info.old_speed.Y >= 0)
+ if (speed_diff.Y < 0 || info.old_speed.Y >= 0)
continue;
// Get rid of other components
speed_diff.X = 0;
f32 pre_factor = 1; // 1 hp per node/s
f32 tolerance = BS*14; // 5 without damage
f32 post_factor = 1; // 1 hp per node/s
- if(info.type == COLLISION_NODE)
- {
+ if (info.type == COLLISION_NODE) {
const ContentFeatures &f = m_client->ndef()->
get(m_map->getNodeNoEx(info.node_p));
// Determine fall damage multiplier
pre_factor = 1.0 + (float)addp/100.0;
}
float speed = pre_factor * speed_diff.getLength();
- if (speed > tolerance) {
+ if (speed > tolerance && !player_immortal) {
f32 damage_f = (speed - tolerance) / BS * post_factor;
u8 damage = (u8)MYMIN(damage_f + 0.5, 255);
if (damage != 0) {
m_script->environment_step(dtime);
}
- // Protocol v29 make this behaviour obsolete
- if (getGameDef()->getProtoVersion() < 29) {
- if (m_lava_hurt_interval.step(dtime, 1.0)) {
- v3f pf = lplayer->getPosition();
-
- // Feet, middle and head
- v3s16 p1 = floatToInt(pf + v3f(0, BS * 0.1, 0), BS);
- MapNode n1 = m_map->getNodeNoEx(p1);
- v3s16 p2 = floatToInt(pf + v3f(0, BS * 0.8, 0), BS);
- MapNode n2 = m_map->getNodeNoEx(p2);
- v3s16 p3 = floatToInt(pf + v3f(0, BS * 1.6, 0), BS);
- MapNode n3 = m_map->getNodeNoEx(p3);
-
- u32 damage_per_second = 0;
- damage_per_second = MYMAX(damage_per_second,
- m_client->ndef()->get(n1).damage_per_second);
- damage_per_second = MYMAX(damage_per_second,
- m_client->ndef()->get(n2).damage_per_second);
- damage_per_second = MYMAX(damage_per_second,
- m_client->ndef()->get(n3).damage_per_second);
-
- if (damage_per_second != 0)
- damageLocalPlayer(damage_per_second, true);
- }
-
- /*
- Drowning
- */
- if (m_drowning_interval.step(dtime, 2.0)) {
- v3f pf = lplayer->getPosition();
-
- // head
- v3s16 p = floatToInt(pf + v3f(0, BS * 1.6, 0), BS);
- MapNode n = m_map->getNodeNoEx(p);
- ContentFeatures c = m_client->ndef()->get(n);
- u8 drowning_damage = c.drowning;
- if (drowning_damage > 0 && lplayer->hp > 0) {
- u16 breath = lplayer->getBreath();
- if (breath > 10) {
- breath = 11;
- }
- if (breath > 0) {
- breath -= 1;
- }
- lplayer->setBreath(breath);
- updateLocalPlayerBreath(breath);
- }
-
- if (lplayer->getBreath() == 0 && drowning_damage > 0) {
- damageLocalPlayer(drowning_damage, true);
- }
- }
- if (m_breathing_interval.step(dtime, 0.5)) {
- v3f pf = lplayer->getPosition();
-
- // head
- v3s16 p = floatToInt(pf + v3f(0, BS * 1.6, 0), BS);
- MapNode n = m_map->getNodeNoEx(p);
- ContentFeatures c = m_client->ndef()->get(n);
- if (!lplayer->hp) {
- lplayer->setBreath(11);
- } else if (c.drowning == 0) {
- u16 breath = lplayer->getBreath();
- if (breath <= 10) {
- breath += 1;
- lplayer->setBreath(breath);
- updateLocalPlayerBreath(breath);
- }
- }
- }
- }
-
// Update lighting on local player (used for wield item)
u32 day_night_ratio = getDayNightRatio();
{
g_profiler->avg("CEnv: num of objects", m_active_objects.size());
bool update_lighting = m_active_object_light_update_interval.step(dtime, 0.21);
- for (ClientActiveObjectMap::iterator i = m_active_objects.begin();
- i != m_active_objects.end(); ++i) {
- ClientActiveObject* obj = i->second;
+ for (auto &ao_it : m_active_objects) {
+ ClientActiveObject* obj = ao_it.second;
// Step object
obj->step(dtime, this);
- if(update_lighting)
- {
+ if (update_lighting) {
// Update lighting
u8 light = 0;
bool pos_ok;
Step and handle simple objects
*/
g_profiler->avg("CEnv: num of simple objects", m_simple_objects.size());
- for(std::vector<ClientSimpleObject*>::iterator
- i = m_simple_objects.begin(); i != m_simple_objects.end();) {
- std::vector<ClientSimpleObject*>::iterator cur = i;
+ for (auto i = m_simple_objects.begin(); i != m_simple_objects.end();) {
+ auto cur = i;
ClientSimpleObject *simple = *cur;
simple->step(dtime);
ClientActiveObject *obj = getActiveObject(id);
if (obj && obj->getType() == ACTIVEOBJECT_TYPE_GENERIC)
return (GenericCAO*) obj;
- else
- return NULL;
+
+ return NULL;
}
ClientActiveObject* ClientEnvironment::getActiveObject(u16 id)
{
- ClientActiveObjectMap::iterator n = m_active_objects.find(id);
+ auto n = m_active_objects.find(id);
if (n == m_active_objects.end())
return NULL;
return n->second;
bool isFreeClientActiveObjectId(const u16 id,
ClientActiveObjectMap &objects)
{
- if(id == 0)
- return false;
+ return id != 0 && objects.find(id) == objects.end();
- return objects.find(id) == objects.end();
}
u16 getFreeClientActiveObjectId(ClientActiveObjectMap &objects)
infostream<<"ClientEnvironment::addActiveObject(): "
<<"added (id="<<object->getId()<<")"<<std::endl;
m_active_objects[object->getId()] = object;
- object->addToScene(m_smgr, m_texturesource, m_irr);
+ object->addToScene(m_texturesource);
{ // Update lighting immediately
u8 light = 0;
bool pos_ok;
void ClientEnvironment::getActiveObjects(v3f origin, f32 max_d,
std::vector<DistanceSortedActiveObject> &dest)
{
- for (ClientActiveObjectMap::iterator i = m_active_objects.begin();
- i != m_active_objects.end(); ++i) {
- ClientActiveObject* obj = i->second;
+ for (auto &ao_it : m_active_objects) {
+ ClientActiveObject* obj = ao_it.second;
f32 d = (obj->getPosition() - origin).getLength();
- if(d > max_d)
+ if (d > max_d)
continue;
- DistanceSortedActiveObject dso(obj, d);
-
- dest.push_back(dso);
+ dest.emplace_back(obj, d);
}
}
return event;
}
-ClientActiveObject * ClientEnvironment::getSelectedActiveObject(
- const core::line3d<f32> &shootline_on_map, v3f *intersection_point,
- v3s16 *intersection_normal)
+void ClientEnvironment::getSelectedActiveObjects(
+ const core::line3d<f32> &shootline_on_map,
+ std::vector<PointedThing> &objects)
{
- std::vector<DistanceSortedActiveObject> objects;
+ std::vector<DistanceSortedActiveObject> allObjects;
getActiveObjects(shootline_on_map.start,
- shootline_on_map.getLength() + 3, objects);
+ shootline_on_map.getLength() + 10.0f, allObjects);
const v3f line_vector = shootline_on_map.getVector();
- // Sort them.
- // After this, the closest object is the first in the array.
- std::sort(objects.begin(), objects.end());
-
- /* Because objects can have different nodebox sizes,
- * the object whose center is the nearest isn't necessarily
- * the closest one. If an object is found, don't stop
- * immediately. */
-
- f32 d_min = shootline_on_map.getLength();
- ClientActiveObject *nearest_obj = NULL;
- for (u32 i = 0; i < objects.size(); i++) {
- ClientActiveObject *obj = objects[i].obj;
-
- aabb3f *selection_box = obj->getSelectionBox();
- if (selection_box == NULL)
+ for (const auto &allObject : allObjects) {
+ ClientActiveObject *obj = allObject.obj;
+ aabb3f selection_box;
+ if (!obj->getSelectionBox(&selection_box))
continue;
- v3f pos = obj->getPosition();
-
- aabb3f offsetted_box(selection_box->MinEdge + pos,
- selection_box->MaxEdge + pos);
-
- if (offsetted_box.getCenter().getDistanceFrom(
- shootline_on_map.start) > d_min + 9.6f*BS) {
- // Probably there is no active object that has bigger nodebox than
- // (-5.5,-5.5,-5.5,5.5,5.5,5.5)
- // 9.6 > 5.5*sqrt(3)
- break;
- }
+ const v3f &pos = obj->getPosition();
+ aabb3f offsetted_box(selection_box.MinEdge + pos,
+ selection_box.MaxEdge + pos);
v3f current_intersection;
v3s16 current_normal;
if (boxLineCollision(offsetted_box, shootline_on_map.start, line_vector,
- ¤t_intersection, ¤t_normal)) {
- f32 d_current = current_intersection.getDistanceFrom(
- shootline_on_map.start);
- if (d_current <= d_min) {
- d_min = d_current;
- nearest_obj = obj;
- *intersection_point = current_intersection;
- *intersection_normal = current_normal;
- }
+ ¤t_intersection, ¤t_normal)) {
+ objects.emplace_back((s16) obj->getId(), current_intersection, current_normal,
+ (current_intersection - shootline_on_map.start).getLengthSQ());
}
}
-
- return nearest_obj;
-}
-
-/*
- Check if a node is pointable
-*/
-static inline bool isPointableNode(const MapNode &n,
- INodeDefManager *ndef, bool liquids_pointable)
-{
- const ContentFeatures &features = ndef->get(n);
- return features.pointable ||
- (liquids_pointable && features.isLiquid());
-}
-
-PointedThing ClientEnvironment::getPointedThing(
- core::line3d<f32> shootline,
- bool liquids_pointable,
- bool look_for_object)
-{
- PointedThing result;
-
- INodeDefManager *nodedef = m_map->getNodeDefManager();
-
- core::aabbox3d<s16> maximal_exceed = nodedef->getSelectionBoxIntUnion();
- // The code needs to search these nodes
- core::aabbox3d<s16> search_range(-maximal_exceed.MaxEdge,
- -maximal_exceed.MinEdge);
- // If a node is found, there might be a larger node behind.
- // To find it, we have to go further.
- s16 maximal_overcheck =
- std::max(abs(search_range.MinEdge.X), abs(search_range.MaxEdge.X))
- + std::max(abs(search_range.MinEdge.Y), abs(search_range.MaxEdge.Y))
- + std::max(abs(search_range.MinEdge.Z), abs(search_range.MaxEdge.Z));
-
- const v3f original_vector = shootline.getVector();
- const f32 original_length = original_vector.getLength();
-
- f32 min_distance = original_length;
-
- // First try to find an active object
- if (look_for_object) {
- ClientActiveObject *selected_object = getSelectedActiveObject(
- shootline, &result.intersection_point,
- &result.intersection_normal);
-
- if (selected_object != NULL) {
- min_distance =
- (result.intersection_point - shootline.start).getLength();
-
- result.type = POINTEDTHING_OBJECT;
- result.object_id = selected_object->getId();
- }
- }
-
- // Reduce shootline
- if (original_length > 0) {
- shootline.end = shootline.start
- + shootline.getVector() / original_length * min_distance;
- }
-
- // Try to find a node that is closer than the selected active
- // object (if it exists).
-
- voxalgo::VoxelLineIterator iterator(shootline.start / BS,
- shootline.getVector() / BS);
- v3s16 oldnode = iterator.m_current_node_pos;
- // Indicates that a node was found.
- bool is_node_found = false;
- // If a node is found, it is possible that there's a node
- // behind it with a large nodebox, so continue the search.
- u16 node_foundcounter = 0;
- // If a node is found, this is the center of the
- // first nodebox the shootline meets.
- v3f found_boxcenter(0, 0, 0);
- // The untested nodes are in this range.
- core::aabbox3d<s16> new_nodes;
- while (true) {
- // Test the nodes around the current node in search_range.
- new_nodes = search_range;
- new_nodes.MinEdge += iterator.m_current_node_pos;
- new_nodes.MaxEdge += iterator.m_current_node_pos;
-
- // Only check new nodes
- v3s16 delta = iterator.m_current_node_pos - oldnode;
- if (delta.X > 0)
- new_nodes.MinEdge.X = new_nodes.MaxEdge.X;
- else if (delta.X < 0)
- new_nodes.MaxEdge.X = new_nodes.MinEdge.X;
- else if (delta.Y > 0)
- new_nodes.MinEdge.Y = new_nodes.MaxEdge.Y;
- else if (delta.Y < 0)
- new_nodes.MaxEdge.Y = new_nodes.MinEdge.Y;
- else if (delta.Z > 0)
- new_nodes.MinEdge.Z = new_nodes.MaxEdge.Z;
- else if (delta.Z < 0)
- new_nodes.MaxEdge.Z = new_nodes.MinEdge.Z;
-
- // For each untested node
- for (s16 x = new_nodes.MinEdge.X; x <= new_nodes.MaxEdge.X; x++) {
- for (s16 y = new_nodes.MinEdge.Y; y <= new_nodes.MaxEdge.Y; y++) {
- for (s16 z = new_nodes.MinEdge.Z; z <= new_nodes.MaxEdge.Z; z++) {
- MapNode n;
- v3s16 np(x, y, z);
- bool is_valid_position;
-
- n = m_map->getNodeNoEx(np, &is_valid_position);
- if (!(is_valid_position &&
- isPointableNode(n, nodedef, liquids_pointable))) {
- continue;
- }
- std::vector<aabb3f> boxes;
- n.getSelectionBoxes(nodedef, &boxes,
- n.getNeighbors(np, m_map));
-
- v3f npf = intToFloat(np, BS);
- for (std::vector<aabb3f>::const_iterator i = boxes.begin();
- i != boxes.end(); ++i) {
- aabb3f box = *i;
- box.MinEdge += npf;
- box.MaxEdge += npf;
- v3f intersection_point;
- v3s16 intersection_normal;
- if (!boxLineCollision(box, shootline.start, shootline.getVector(),
- &intersection_point, &intersection_normal)) {
- continue;
- }
- f32 distance = (intersection_point - shootline.start).getLength();
- if (distance >= min_distance) {
- continue;
- }
- result.type = POINTEDTHING_NODE;
- result.node_undersurface = np;
- result.intersection_point = intersection_point;
- result.intersection_normal = intersection_normal;
- found_boxcenter = box.getCenter();
- min_distance = distance;
- is_node_found = true;
- }
- }
- }
- }
- if (is_node_found) {
- node_foundcounter++;
- if (node_foundcounter > maximal_overcheck) {
- break;
- }
- }
- // Next node
- if (iterator.hasNext()) {
- oldnode = iterator.m_current_node_pos;
- iterator.next();
- } else {
- break;
- }
- }
-
- if (is_node_found) {
- // Set undersurface and abovesurface nodes
- f32 d = 0.002 * BS;
- v3f fake_intersection = result.intersection_point;
- // Move intersection towards its source block.
- if (fake_intersection.X < found_boxcenter.X)
- fake_intersection.X += d;
- else
- fake_intersection.X -= d;
-
- if (fake_intersection.Y < found_boxcenter.Y)
- fake_intersection.Y += d;
- else
- fake_intersection.Y -= d;
-
- if (fake_intersection.Z < found_boxcenter.Z)
- fake_intersection.Z += d;
- else
- fake_intersection.Z -= d;
-
- result.node_real_undersurface = floatToInt(fake_intersection, BS);
- result.node_abovesurface = result.node_real_undersurface
- + result.intersection_normal;
- }
- return result;
}