]> git.lizzy.rs Git - dragonfireclient.git/blobdiff - src/client/clientenvironment.cpp
DevTest: Fix broken PNG textures
[dragonfireclient.git] / src / client / clientenvironment.cpp
index e1b20ec8498397969b3837a462d210bb63ef4f72..448af36c6596e982a144d16958db7eed0ed41a65 100644 (file)
@@ -25,17 +25,68 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #include "clientmap.h"
 #include "scripting_client.h"
 #include "mapblock_mesh.h"
-#include "event.h"
+#include "mtevent.h"
 #include "collision.h"
 #include "nodedef.h"
 #include "profiler.h"
 #include "raycast.h"
 #include "voxelalgorithms.h"
 #include "settings.h"
+#include "shader.h"
 #include "content_cao.h"
 #include <algorithm>
 #include "client/renderingengine.h"
 
+/*
+       CAOShaderConstantSetter
+*/
+
+//! Shader constant setter for passing material emissive color to the CAO object_shader
+class CAOShaderConstantSetter : public IShaderConstantSetter
+{
+public:
+       CAOShaderConstantSetter():
+                       m_emissive_color_setting("emissiveColor")
+       {}
+
+       ~CAOShaderConstantSetter() override = default;
+
+       void onSetConstants(video::IMaterialRendererServices *services) override
+       {
+               // Ambient color
+               video::SColorf emissive_color(m_emissive_color);
+
+               float as_array[4] = {
+                       emissive_color.r,
+                       emissive_color.g,
+                       emissive_color.b,
+                       emissive_color.a,
+               };
+               m_emissive_color_setting.set(as_array, services);
+       }
+
+       void onSetMaterial(const video::SMaterial& material) override
+       {
+               m_emissive_color = material.EmissiveColor;
+       }
+
+private:
+       video::SColor m_emissive_color;
+       CachedPixelShaderSetting<float, 4> m_emissive_color_setting;
+};
+
+class CAOShaderConstantSetterFactory : public IShaderConstantSetterFactory
+{
+public:
+       CAOShaderConstantSetterFactory()
+       {}
+
+       virtual IShaderConstantSetter* create()
+       {
+               return new CAOShaderConstantSetter();
+       }
+};
+
 /*
        ClientEnvironment
 */
@@ -47,6 +98,8 @@ ClientEnvironment::ClientEnvironment(ClientMap *map,
        m_texturesource(texturesource),
        m_client(client)
 {
+       auto *shdrsrc = m_client->getShaderSource();
+       shdrsrc->addShaderConstantSetterFactory(new CAOShaderConstantSetterFactory());
 }
 
 ClientEnvironment::~ClientEnvironment()
@@ -126,83 +179,81 @@ void ClientEnvironment::step(float dtime)
        if(dtime > 0.5)
                dtime = 0.5;
 
-       f32 dtime_downcount = dtime;
-
        /*
                Stuff that has a maximum time increment
        */
 
-       u32 loopcount = 0;
-       do
-       {
-               loopcount++;
-
-               f32 dtime_part;
-               if(dtime_downcount > dtime_max_increment)
-               {
-                       dtime_part = dtime_max_increment;
-                       dtime_downcount -= dtime_part;
-               }
-               else
-               {
-                       dtime_part = dtime_downcount;
-                       /*
-                               Setting this to 0 (no -=dtime_part) disables an infinite loop
-                               when dtime_part is so small that dtime_downcount -= dtime_part
-                               does nothing
-                       */
-                       dtime_downcount = 0;
-               }
-
+       u32 steps = ceil(dtime / dtime_max_increment);
+       f32 dtime_part = dtime / steps;
+       for (; steps > 0; --steps) {
                /*
-                       Handle local player
+                       Local player handling
                */
 
-               {
-                       // Apply physics
-                       if (!free_move && !is_climbing) {
-                               // Gravity
-                               v3f speed = lplayer->getSpeed();
-                               if (!lplayer->in_liquid)
-                                       speed.Y -= lplayer->movement_gravity *
-                                               lplayer->physics_override_gravity * dtime_part * 2.0f;
-
-                               // Liquid floating / sinking
-                               if (lplayer->in_liquid && !lplayer->swimming_vertical &&
-                                               !lplayer->swimming_pitch)
-                                       speed.Y -= lplayer->movement_liquid_sink * dtime_part * 2.0f;
-
-                               // Liquid resistance
-                               if (lplayer->in_liquid_stable || lplayer->in_liquid) {
-                                       // How much the node's viscosity blocks movement, ranges
-                                       // between 0 and 1. Should match the scale at which viscosity
-                                       // increase affects other liquid attributes.
-                                       static const f32 viscosity_factor = 0.3f;
-
-                                       v3f d_wanted = -speed / lplayer->movement_liquid_fluidity;
-                                       f32 dl = d_wanted.getLength();
+               // Control local player
+               lplayer->applyControl(dtime_part, this);
+
+               // Apply physics
+               if (!free_move) {
+                       // Gravity
+                       v3f speed = lplayer->getSpeed();
+                       if (!is_climbing && !lplayer->in_liquid)
+                               speed.Y -= lplayer->movement_gravity *
+                                       lplayer->physics_override_gravity * dtime_part * 2.0f;
+
+                       // Liquid floating / sinking
+                       if (!is_climbing && lplayer->in_liquid &&
+                                       !lplayer->swimming_vertical &&
+                                       !lplayer->swimming_pitch)
+                               speed.Y -= lplayer->movement_liquid_sink * dtime_part * 2.0f;
+
+                       // Movement resistance
+                       if (lplayer->move_resistance > 0) {
+                               // How much the node's move_resistance blocks movement, ranges
+                               // between 0 and 1. Should match the scale at which liquid_viscosity
+                               // increase affects other liquid attributes.
+                               static const f32 resistance_factor = 0.3f;
+
+                               v3f d_wanted;
+                               bool in_liquid_stable = lplayer->in_liquid_stable || lplayer->in_liquid;
+                               if (in_liquid_stable) {
+                                       d_wanted = -speed / lplayer->movement_liquid_fluidity;
+                               } else {
+                                       d_wanted = -speed / BS;
+                               }
+                               f32 dl = d_wanted.getLength();
+                               if (in_liquid_stable) {
                                        if (dl > lplayer->movement_liquid_fluidity_smooth)
                                                dl = lplayer->movement_liquid_fluidity_smooth;
-
-                                       dl *= (lplayer->liquid_viscosity * viscosity_factor) +
-                                               (1 - viscosity_factor);
-                                       v3f d = d_wanted.normalize() * (dl * dtime_part * 100.0f);
-                                       speed += d;
                                }
 
-                               lplayer->setSpeed(speed);
+                               dl *= (lplayer->move_resistance * resistance_factor) +
+                                       (1 - resistance_factor);
+                               v3f d = d_wanted.normalize() * (dl * dtime_part * 100.0f);
+                               speed += d;
                        }
 
-                       /*
-                               Move the lplayer.
-                               This also does collision detection.
-                       */
-                       lplayer->move(dtime_part, this, position_max_increment,
-                               &player_collisions);
+                       lplayer->setSpeed(speed);
                }
-       } while (dtime_downcount > 0.001);
 
-       bool player_immortal = lplayer->getCAO() && lplayer->getCAO()->isImmortal();
+               /*
+                       Move the lplayer.
+                       This also does collision detection.
+               */
+               lplayer->move(dtime_part, this, position_max_increment,
+                       &player_collisions);
+       }
+
+       bool player_immortal = false;
+       f32 player_fall_factor = 1.0f;
+       GenericCAO *playercao = lplayer->getCAO();
+       if (playercao) {
+               player_immortal = playercao->isImmortal();
+               int addp_p = itemgroup_get(playercao->getGroups(),
+                       "fall_damage_add_percent");
+               // convert armor group into an usable fall damage factor
+               player_fall_factor = 1.0f + (float)addp_p / 100.0f;
+       }
 
        for (const CollisionInfo &info : player_collisions) {
                v3f speed_diff = info.new_speed - info.old_speed;;
@@ -215,17 +266,20 @@ void ClientEnvironment::step(float dtime)
                speed_diff.Z = 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) {
                        const ContentFeatures &f = m_client->ndef()->
                                get(m_map->getNode(info.node_p));
-                       // Determine fall damage multiplier
-                       int addp = itemgroup_get(f.groups, "fall_damage_add_percent");
-                       pre_factor = 1.0f + (float)addp / 100.0f;
+                       // Determine fall damage modifier
+                       int addp_n = itemgroup_get(f.groups, "fall_damage_add_percent");
+                       // convert node group to an usable fall damage factor
+                       f32 node_fall_factor = 1.0f + (float)addp_n / 100.0f;
+                       // combine both player fall damage modifiers
+                       pre_factor = node_fall_factor * player_fall_factor;
                }
                float speed = pre_factor * speed_diff.getLength();
-               if (speed > tolerance && !player_immortal) {
-                       f32 damage_f = (speed - tolerance) / BS * post_factor;
+
+               if (speed > tolerance && !player_immortal && pre_factor > 0.0f) {
+                       f32 damage_f = (speed - tolerance) / BS;
                        u16 damage = (u16)MYMIN(damage_f + 0.5, U16_MAX);
                        if (damage != 0) {
                                damageLocalPlayer(damage, true);
@@ -263,21 +317,8 @@ void ClientEnvironment::step(float dtime)
                // Step object
                cao->step(dtime, this);
 
-               if (update_lighting) {
-                       // Update lighting
-                       u8 light = 0;
-                       bool pos_ok;
-
-                       // Get node at head
-                       v3s16 p = cao->getLightPosition();
-                       MapNode n = this->m_map->getNode(p, &pos_ok);
-                       if (pos_ok)
-                               light = n.getLightBlend(day_night_ratio, m_client->ndef());
-                       else
-                               light = blend_light(day_night_ratio, LIGHT_SUN, 0);
-
-                       cao->updateLight(light);
-               }
+               if (update_lighting)
+                       cao->updateLight(day_night_ratio);
        };
 
        m_ao_manager.step(dtime, cb_state);
@@ -314,49 +355,16 @@ GenericCAO* ClientEnvironment::getGenericCAO(u16 id)
        return NULL;
 }
 
-bool isFreeClientActiveObjectId(const u16 id,
-       ClientActiveObjectMap &objects)
-{
-       return id != 0 && objects.find(id) == objects.end();
-
-}
-
-u16 getFreeClientActiveObjectId(ClientActiveObjectMap &objects)
-{
-       // try to reuse id's as late as possible
-       static u16 last_used_id = 0;
-       u16 startid = last_used_id;
-       for(;;) {
-               last_used_id ++;
-               if (isFreeClientActiveObjectId(last_used_id, objects))
-                       return last_used_id;
-
-               if (last_used_id == startid)
-                       return 0;
-       }
-}
-
 u16 ClientEnvironment::addActiveObject(ClientActiveObject *object)
 {
        // Register object. If failed return zero id
        if (!m_ao_manager.registerObject(object))
                return 0;
 
-       object->addToScene(m_texturesource);
+       object->addToScene(m_texturesource, m_client->getSceneManager());
 
        // Update lighting immediately
-       u8 light = 0;
-       bool pos_ok;
-
-       // Get node at head
-       v3s16 p = object->getLightPosition();
-       MapNode n = m_map->getNode(p, &pos_ok);
-       if (pos_ok)
-               light = n.getLightBlend(getDayNightRatio(), m_client->ndef());
-       else
-               light = blend_light(getDayNightRatio(), LIGHT_SUN, 0);
-
-       object->updateLight(light);
+       object->updateLight(getDayNightRatio());
        return object->getId();
 }
 
@@ -393,7 +401,7 @@ void ClientEnvironment::addActiveObject(u16 id, u8 type,
        // Object initialized:
        if ((obj = getActiveObject(new_id))) {
                // Final step is to update all children which are already known
-               // Data provided by GENERIC_CMD_SPAWN_INFANT
+               // Data provided by AO_CMD_SPAWN_INFANT
                const auto &children = obj->getAttachmentChildIds();
                for (auto c_id : children) {
                        if (auto *o = getActiveObject(c_id))
@@ -402,6 +410,23 @@ void ClientEnvironment::addActiveObject(u16 id, u8 type,
        }
 }
 
+
+void ClientEnvironment::removeActiveObject(u16 id)
+{
+       // Get current attachment childs to detach them visually
+       std::unordered_set<int> attachment_childs;
+       if (auto *obj = getActiveObject(id))
+               attachment_childs = obj->getAttachmentChildIds();
+
+       m_ao_manager.removeObject(id);
+
+       // Perform a proper detach in Irrlicht
+       for (auto c_id : attachment_childs) {
+               if (ClientActiveObject *child = getActiveObject(c_id))
+                       child->updateAttachments();
+       }
+}
+
 void ClientEnvironment::processActiveObjectMessage(u16 id, const std::string &data)
 {
        ClientActiveObject *obj = getActiveObject(id);