X-Git-Url: https://git.lizzy.rs/?a=blobdiff_plain;ds=sidebyside;f=src%2Fgame.cpp;h=4a3acf493cbaca4d769880f5c71b757b50c57f9c;hb=7b74f04a611ddaf36d79c0c9ebbf7f2b89c12a64;hp=af0476a0b74dd8f79749a505a5936f80e41f8529;hpb=f8fd432dca9f84a489cb7033afc4e4eef7cff49d;p=dragonfireclient.git diff --git a/src/game.cpp b/src/game.cpp index af0476a0b..4a3acf493 100644 --- a/src/game.cpp +++ b/src/game.cpp @@ -41,7 +41,6 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "guiKeyChangeMenu.h" #include "guiPasswordChange.h" #include "guiVolumeChange.h" -#include "hud.h" #include "mainmenumanager.h" #include "mapblock.h" #include "nodedef.h" // Needed for determining pointing to nodes @@ -61,6 +60,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "version.h" #include "minimap.h" #include "mapblock_mesh.h" +#include "script/clientscripting.h" #include "sound.h" @@ -125,6 +125,7 @@ struct TextDestPlayerInventory : public TextDest { struct LocalFormspecHandler : public TextDest { LocalFormspecHandler(); + LocalFormspecHandler(std::string formname) : m_client(0) { @@ -179,38 +180,8 @@ struct LocalFormspecHandler : public TextDest { } } - if (m_formname == "MT_DEATH_SCREEN") { - assert(m_client != 0); - - if ((fields.find("btn_respawn") != fields.end())) { - m_client->sendRespawn(); - return; - } - - if (fields.find("quit") != fields.end()) { - m_client->sendRespawn(); - return; - } - } - - // don't show error message for unhandled cursor keys - if ((fields.find("key_up") != fields.end()) || - (fields.find("key_down") != fields.end()) || - (fields.find("key_left") != fields.end()) || - (fields.find("key_right") != fields.end())) { - return; - } - - errorstream << "LocalFormspecHandler::gotText unhandled >" - << m_formname << "< event" << std::endl; - - int i = 0; - StringMap::const_iterator it; - for (it = fields.begin(); it != fields.end(); ++it) { - errorstream << "\t" << i << ": " << it->first - << "=" << it->second << std::endl; - i++; - } + // Don't disable this part when modding is disabled, it's used in builtin + m_client->getScript()->on_formspec_input(m_formname, fields); } Client *m_client; @@ -265,269 +236,6 @@ class PlayerInventoryFormSource: public IFormSource Client *m_client; }; -/* - Check if a node is pointable -*/ -inline bool isPointableNode(const MapNode &n, - Client *client, bool liquids_pointable) -{ - const ContentFeatures &features = client->getNodeDefManager()->get(n); - return features.pointable || - (liquids_pointable && features.isLiquid()); -} - -static inline void getNeighborConnectingFace(v3s16 p, INodeDefManager *nodedef, - ClientMap *map, MapNode n, u8 bitmask, u8 *neighbors) -{ - MapNode n2 = map->getNodeNoEx(p); - if (nodedef->nodeboxConnects(n, n2, bitmask)) - *neighbors |= bitmask; -} - -static inline u8 getNeighbors(v3s16 p, INodeDefManager *nodedef, ClientMap *map, MapNode n) -{ - u8 neighbors = 0; - const ContentFeatures &f = nodedef->get(n); - // locate possible neighboring nodes to connect to - if (f.drawtype == NDT_NODEBOX && f.node_box.type == NODEBOX_CONNECTED) { - v3s16 p2 = p; - - p2.Y++; - getNeighborConnectingFace(p2, nodedef, map, n, 1, &neighbors); - - p2 = p; - p2.Y--; - getNeighborConnectingFace(p2, nodedef, map, n, 2, &neighbors); - - p2 = p; - p2.Z--; - getNeighborConnectingFace(p2, nodedef, map, n, 4, &neighbors); - - p2 = p; - p2.X--; - getNeighborConnectingFace(p2, nodedef, map, n, 8, &neighbors); - - p2 = p; - p2.Z++; - getNeighborConnectingFace(p2, nodedef, map, n, 16, &neighbors); - - p2 = p; - p2.X++; - getNeighborConnectingFace(p2, nodedef, map, n, 32, &neighbors); - } - - return neighbors; -} - -/* - Find what the player is pointing at -*/ -PointedThing getPointedThing(Client *client, Hud *hud, const v3f &player_position, - const v3f &camera_direction, const v3f &camera_position, - core::line3d shootline, f32 d, bool liquids_pointable, - bool look_for_object, const v3s16 &camera_offset, - ClientActiveObject *&selected_object) -{ - PointedThing result; - - std::vector *selectionboxes = hud->getSelectionBoxes(); - selectionboxes->clear(); - static const bool show_entity_selectionbox = g_settings->getBool("show_entity_selectionbox"); - - selected_object = NULL; - - INodeDefManager *nodedef = client->getNodeDefManager(); - ClientMap &map = client->getEnv().getClientMap(); - - f32 min_distance = BS * 1001; - - // First try to find a pointed at active object - if (look_for_object) { - selected_object = client->getSelectedActiveObject(d * BS, - camera_position, shootline); - - if (selected_object != NULL) { - if (show_entity_selectionbox && - selected_object->doShowSelectionBox()) { - aabb3f *selection_box = selected_object->getSelectionBox(); - // Box should exist because object was - // returned in the first place - assert(selection_box); - - v3f pos = selected_object->getPosition(); - selectionboxes->push_back(aabb3f( - selection_box->MinEdge, selection_box->MaxEdge)); - hud->setSelectionPos(pos, camera_offset); - } - - min_distance = (selected_object->getPosition() - camera_position).getLength(); - - result.type = POINTEDTHING_OBJECT; - result.object_id = selected_object->getId(); - } - } - - // That didn't work, try to find a pointed at node - - v3s16 pos_i = floatToInt(player_position, BS); - - /*infostream<<"pos_i=("< 0 ? a : 1); - s16 zend = pos_i.Z + (camera_direction.Z > 0 ? a : 1); - s16 xend = pos_i.X + (camera_direction.X > 0 ? a : 1); - - // Prevent signed number overflow - if (yend == 32767) - yend = 32766; - - if (zend == 32767) - zend = 32766; - - if (xend == 32767) - xend = 32766; - - v3s16 pointed_pos(0, 0, 0); - - for (s16 y = ystart; y <= yend; y++) { - for (s16 z = zstart; z <= zend; z++) { - for (s16 x = xstart; x <= xend; x++) { - MapNode n; - bool is_valid_position; - v3s16 p(x, y, z); - - n = map.getNodeNoEx(p, &is_valid_position); - if (!is_valid_position) { - continue; - } - if (!isPointableNode(n, client, liquids_pointable)) { - continue; - } - - std::vector boxes; - n.getSelectionBoxes(nodedef, &boxes, getNeighbors(p, nodedef, &map, n)); - - v3s16 np(x, y, z); - v3f npf = intToFloat(np, BS); - for (std::vector::const_iterator - i = boxes.begin(); - i != boxes.end(); ++i) { - aabb3f box = *i; - box.MinEdge += npf; - box.MaxEdge += npf; - - v3f centerpoint = box.getCenter(); - f32 distance = (centerpoint - camera_position).getLength(); - if (distance >= min_distance) { - continue; - } - if (!box.intersectsWithLine(shootline)) { - continue; - } - result.type = POINTEDTHING_NODE; - min_distance = distance; - pointed_pos = np; - } - } - } - } - - if (result.type == POINTEDTHING_NODE) { - f32 d = 0.001 * BS; - MapNode n = map.getNodeNoEx(pointed_pos); - v3f npf = intToFloat(pointed_pos, BS); - std::vector boxes; - n.getSelectionBoxes(nodedef, &boxes, getNeighbors(pointed_pos, nodedef, &map, n)); - f32 face_min_distance = 1000 * BS; - for (std::vector::const_iterator - i = boxes.begin(); - i != boxes.end(); ++i) { - aabb3f box = *i; - box.MinEdge += npf; - box.MaxEdge += npf; - for (u16 j = 0; j < 6; j++) { - v3s16 facedir = g_6dirs[j]; - aabb3f facebox = box; - if (facedir.X > 0) { - facebox.MinEdge.X = facebox.MaxEdge.X - d; - } else if (facedir.X < 0) { - facebox.MaxEdge.X = facebox.MinEdge.X + d; - } else if (facedir.Y > 0) { - facebox.MinEdge.Y = facebox.MaxEdge.Y - d; - } else if (facedir.Y < 0) { - facebox.MaxEdge.Y = facebox.MinEdge.Y + d; - } else if (facedir.Z > 0) { - facebox.MinEdge.Z = facebox.MaxEdge.Z - d; - } else if (facedir.Z < 0) { - facebox.MaxEdge.Z = facebox.MinEdge.Z + d; - } - v3f centerpoint = facebox.getCenter(); - f32 distance = (centerpoint - camera_position).getLength(); - if (distance >= face_min_distance) - continue; - if (!facebox.intersectsWithLine(shootline)) - continue; - result.node_abovesurface = pointed_pos + facedir; - face_min_distance = distance; - } - } - selectionboxes->clear(); - for (std::vector::const_iterator - i = boxes.begin(); - i != boxes.end(); ++i) { - aabb3f box = *i; - box.MinEdge += v3f(-d, -d, -d); - box.MaxEdge += v3f(d, d, d); - selectionboxes->push_back(box); - } - hud->setSelectionPos(intToFloat(pointed_pos, BS), camera_offset); - result.node_undersurface = pointed_pos; - } - - // Update selection mesh light level and vertex colors - if (selectionboxes->size() > 0) { - v3f pf = hud->getSelectionPos(); - v3s16 p = floatToInt(pf, BS); - - // Get selection mesh light level - MapNode n = map.getNodeNoEx(p); - u16 node_light = getInteriorLight(n, -1, nodedef); - u16 light_level = node_light; - - for (u8 i = 0; i < 6; i++) { - n = map.getNodeNoEx(p + g_6dirs[i]); - node_light = getInteriorLight(n, -1, nodedef); - if (node_light > light_level) - light_level = node_light; - } - - video::SColor c = MapBlock_LightColor(255, light_level, 0); - u8 day = c.getRed(); - u8 night = c.getGreen(); - u32 daynight_ratio = client->getEnv().getDayNightRatio(); - finalColorBlend(c, day, night, daynight_ratio); - - // Modify final color a bit with time - u32 timer = porting::getTimeMs() % 5000; - float timerf = (float)(irr::core::PI * ((timer / 2500.0) - 0.5)); - float sin_r = 0.08 * sin(timerf); - float sin_g = 0.08 * sin(timerf + irr::core::PI * 0.5); - float sin_b = 0.08 * sin(timerf + irr::core::PI); - c.setRed(core::clamp(core::round32(c.getRed() * (0.8 + sin_r)), 0, 255)); - c.setGreen(core::clamp(core::round32(c.getGreen() * (0.8 + sin_g)), 0, 255)); - c.setBlue(core::clamp(core::round32(c.getBlue() * (0.8 + sin_b)), 0, 255)); - - // Set mesh final color - hud->setSelectionMeshColor(c); - } - return result; -} - /* Profiler display */ void update_profiler_gui(gui::IGUIStaticText *guitext_profiler, FontEngine *fe, @@ -886,40 +594,73 @@ class GameOnDemandSoundFetcher: public OnDemandSoundFetcher } }; + +// before 1.8 there isn't a "integer interface", only float +#if (IRRLICHT_VERSION_MAJOR == 1 && IRRLICHT_VERSION_MINOR < 8) +typedef f32 SamplerLayer_t; +#else +typedef s32 SamplerLayer_t; +#endif + + class GameGlobalShaderConstantSetter : public IShaderConstantSetter { Sky *m_sky; bool *m_force_fog_off; f32 *m_fog_range; + bool m_fog_enabled; + CachedPixelShaderSetting m_sky_bg_color; + CachedPixelShaderSetting m_fog_distance; + CachedVertexShaderSetting m_animation_timer_vertex; + CachedPixelShaderSetting m_animation_timer_pixel; + CachedPixelShaderSetting m_day_light; + CachedPixelShaderSetting m_eye_position_pixel; + CachedVertexShaderSetting m_eye_position_vertex; + CachedPixelShaderSetting m_minimap_yaw; + CachedPixelShaderSetting m_base_texture; + CachedPixelShaderSetting m_normal_texture; + CachedPixelShaderSetting m_texture_flags; Client *m_client; - bool m_fogEnabled; public: void onSettingsChange(const std::string &name) { if (name == "enable_fog") - m_fogEnabled = g_settings->getBool("enable_fog"); + m_fog_enabled = g_settings->getBool("enable_fog"); } - static void SettingsCallback(const std::string &name, void *userdata) + static void settingsCallback(const std::string &name, void *userdata) { reinterpret_cast(userdata)->onSettingsChange(name); } + void setSky(Sky *sky) { m_sky = sky; } + GameGlobalShaderConstantSetter(Sky *sky, bool *force_fog_off, f32 *fog_range, Client *client) : m_sky(sky), m_force_fog_off(force_fog_off), m_fog_range(fog_range), + m_sky_bg_color("skyBgColor"), + m_fog_distance("fogDistance"), + m_animation_timer_vertex("animationTimer"), + m_animation_timer_pixel("animationTimer"), + m_day_light("dayLight"), + m_eye_position_pixel("eyePosition"), + m_eye_position_vertex("eyePosition"), + m_minimap_yaw("yawVec"), + m_base_texture("baseTexture"), + m_normal_texture("normalTexture"), + m_texture_flags("textureFlags"), m_client(client) { - g_settings->registerChangedCallback("enable_fog", SettingsCallback, this); - m_fogEnabled = g_settings->getBool("enable_fog"); + g_settings->registerChangedCallback("enable_fog", settingsCallback, this); + m_fog_enabled = g_settings->getBool("enable_fog"); } ~GameGlobalShaderConstantSetter() { - g_settings->deregisterChangedCallback("enable_fog", SettingsCallback, this); + g_settings->deregisterChangedCallback("enable_fog", settingsCallback, this); } virtual void onSetConstants(video::IMaterialRendererServices *services, @@ -937,54 +678,98 @@ class GameGlobalShaderConstantSetter : public IShaderConstantSetter bgcolorf.b, bgcolorf.a, }; - services->setPixelShaderConstant("skyBgColor", bgcolorfa, 4); + m_sky_bg_color.set(bgcolorfa, services); // Fog distance float fog_distance = 10000 * BS; - if (m_fogEnabled && !*m_force_fog_off) + if (m_fog_enabled && !*m_force_fog_off) fog_distance = *m_fog_range; - services->setPixelShaderConstant("fogDistance", &fog_distance, 1); + m_fog_distance.set(&fog_distance, services); - // Day-night ratio - u32 daynight_ratio = m_client->getEnv().getDayNightRatio(); - float daynight_ratio_f = (float)daynight_ratio / 1000.0; - services->setPixelShaderConstant("dayNightRatio", &daynight_ratio_f, 1); + u32 daynight_ratio = (float)m_client->getEnv().getDayNightRatio(); + video::SColorf sunlight; + get_sunlight_color(&sunlight, daynight_ratio); + float dnc[3] = { + sunlight.r, + sunlight.g, + sunlight.b }; + m_day_light.set(dnc, services); u32 animation_timer = porting::getTimeMs() % 100000; - float animation_timer_f = (float)animation_timer / 100000.0; - services->setPixelShaderConstant("animationTimer", &animation_timer_f, 1); - services->setVertexShaderConstant("animationTimer", &animation_timer_f, 1); + float animation_timer_f = (float)animation_timer / 100000.f; + m_animation_timer_vertex.set(&animation_timer_f, services); + m_animation_timer_pixel.set(&animation_timer_f, services); - LocalPlayer *player = m_client->getEnv().getLocalPlayer(); - v3f eye_position = player->getEyePosition(); - services->setPixelShaderConstant("eyePosition", (irr::f32 *)&eye_position, 3); - services->setVertexShaderConstant("eyePosition", (irr::f32 *)&eye_position, 3); - - v3f minimap_yaw_vec = m_client->getMapper()->getYawVec(); - services->setPixelShaderConstant("yawVec", (irr::f32 *)&minimap_yaw_vec, 3); + float eye_position_array[3]; + v3f epos = m_client->getEnv().getLocalPlayer()->getEyePosition(); +#if (IRRLICHT_VERSION_MAJOR == 1 && IRRLICHT_VERSION_MINOR < 8) + eye_position_array[0] = epos.X; + eye_position_array[1] = epos.Y; + eye_position_array[2] = epos.Z; +#else + epos.getAs3Values(eye_position_array); +#endif + m_eye_position_pixel.set(eye_position_array, services); + m_eye_position_vertex.set(eye_position_array, services); - // Uniform sampler layers - // before 1.8 there isn't a "integer interface", only float + float minimap_yaw_array[3]; + v3f minimap_yaw = m_client->getMinimap()->getYawVec(); #if (IRRLICHT_VERSION_MAJOR == 1 && IRRLICHT_VERSION_MINOR < 8) - f32 layer0 = 0; - f32 layer1 = 1; - f32 layer2 = 2; - services->setPixelShaderConstant("baseTexture" , (irr::f32 *)&layer0, 1); - services->setPixelShaderConstant("normalTexture" , (irr::f32 *)&layer1, 1); - services->setPixelShaderConstant("textureFlags" , (irr::f32 *)&layer2, 1); + minimap_yaw_array[0] = minimap_yaw.X; + minimap_yaw_array[1] = minimap_yaw.Y; + minimap_yaw_array[2] = minimap_yaw.Z; #else - s32 layer0 = 0; - s32 layer1 = 1; - s32 layer2 = 2; - services->setPixelShaderConstant("baseTexture" , (irr::s32 *)&layer0, 1); - services->setPixelShaderConstant("normalTexture" , (irr::s32 *)&layer1, 1); - services->setPixelShaderConstant("textureFlags" , (irr::s32 *)&layer2, 1); + minimap_yaw.getAs3Values(minimap_yaw_array); #endif + m_minimap_yaw.set(minimap_yaw_array, services); + + SamplerLayer_t base_tex = 0, + normal_tex = 1, + flags_tex = 2; + m_base_texture.set(&base_tex, services); + m_normal_texture.set(&normal_tex, services); + m_texture_flags.set(&flags_tex, services); + } +}; + + +class GameGlobalShaderConstantSetterFactory : public IShaderConstantSetterFactory +{ + Sky *m_sky; + bool *m_force_fog_off; + f32 *m_fog_range; + Client *m_client; + std::vector created_nosky; +public: + GameGlobalShaderConstantSetterFactory(bool *force_fog_off, + f32 *fog_range, Client *client) : + m_sky(NULL), + m_force_fog_off(force_fog_off), + m_fog_range(fog_range), + m_client(client) + {} + + void setSky(Sky *sky) { + m_sky = sky; + for (size_t i = 0; i < created_nosky.size(); ++i) { + created_nosky[i]->setSky(m_sky); + } + created_nosky.clear(); + } + + virtual IShaderConstantSetter* create() + { + GameGlobalShaderConstantSetter *scs = new GameGlobalShaderConstantSetter( + m_sky, m_force_fog_off, m_fog_range, m_client); + if (!m_sky) + created_nosky.push_back(scs); + return scs; } }; + bool nodePlacementPrediction(Client &client, const ItemDefinition &playeritem_def, v3s16 nodepos, v3s16 neighbourpos) { @@ -1032,7 +817,8 @@ bool nodePlacementPrediction(Client &client, // Predict param2 for facedir and wallmounted nodes u8 param2 = 0; - if (nodedef->get(id).param_type_2 == CPT2_WALLMOUNTED) { + if (nodedef->get(id).param_type_2 == CPT2_WALLMOUNTED || + nodedef->get(id).param_type_2 == CPT2_COLORED_WALLMOUNTED) { v3s16 dir = nodepos - neighbourpos; if (abs(dir.Y) > MYMAX(abs(dir.X), abs(dir.Z))) { @@ -1044,7 +830,8 @@ bool nodePlacementPrediction(Client &client, } } - if (nodedef->get(id).param_type_2 == CPT2_FACEDIR) { + if (nodedef->get(id).param_type_2 == CPT2_FACEDIR || + nodedef->get(id).param_type_2 == CPT2_COLORED_FACEDIR) { v3s16 dir = nodepos - floatToInt(client.getEnv().getLocalPlayer()->getPosition(), BS); if (abs(dir.X) > abs(dir.Z)) { @@ -1068,7 +855,8 @@ bool nodePlacementPrediction(Client &client, }; v3s16 pp; - if (nodedef->get(id).param_type_2 == CPT2_WALLMOUNTED) + if (nodedef->get(id).param_type_2 == CPT2_WALLMOUNTED || + nodedef->get(id).param_type_2 == CPT2_COLORED_WALLMOUNTED) pp = p + wallmounted_dirs[param2]; else pp = p + v3s16(0, -1, 0); @@ -1108,16 +896,14 @@ bool nodePlacementPrediction(Client &client, } static inline void create_formspec_menu(GUIFormSpecMenu **cur_formspec, - InventoryManager *invmgr, IGameDef *gamedef, - IWritableTextureSource *tsrc, IrrlichtDevice *device, - JoystickController *joystick, - IFormSource *fs_src, TextDest *txt_dest, Client *client) + Client *client, IrrlichtDevice *device, JoystickController *joystick, + IFormSource *fs_src, TextDest *txt_dest) { if (*cur_formspec == 0) { *cur_formspec = new GUIFormSpecMenu(device, joystick, - guiroot, -1, &g_menumgr, invmgr, gamedef, tsrc, - fs_src, txt_dest, client); + guiroot, -1, &g_menumgr, client, client->getTextureSource(), + fs_src, txt_dest); (*cur_formspec)->doPause = false; /* @@ -1132,6 +918,7 @@ static inline void create_formspec_menu(GUIFormSpecMenu **cur_formspec, (*cur_formspec)->setFormSource(fs_src); (*cur_formspec)->setTextDest(txt_dest); } + } #ifdef __ANDROID__ @@ -1140,32 +927,9 @@ static inline void create_formspec_menu(GUIFormSpecMenu **cur_formspec, #define SIZE_TAG "size[11,5.5,true]" // Fixed size on desktop #endif -static void show_deathscreen(GUIFormSpecMenu **cur_formspec, - InventoryManager *invmgr, IGameDef *gamedef, - IWritableTextureSource *tsrc, IrrlichtDevice *device, - JoystickController *joystick, Client *client) -{ - std::string formspec = - std::string(FORMSPEC_VERSION_STRING) + - SIZE_TAG - "bgcolor[#320000b4;true]" - "label[4.85,1.35;" + gettext("You died.") + "]" - "button_exit[4,3;3,0.5;btn_respawn;" + gettext("Respawn") + "]" - ; - - /* Create menu */ - /* Note: FormspecFormSource and LocalFormspecHandler - * are deleted by guiFormSpecMenu */ - FormspecFormSource *fs_src = new FormspecFormSource(formspec); - LocalFormspecHandler *txt_dst = new LocalFormspecHandler("MT_DEATH_SCREEN", client); - - create_formspec_menu(cur_formspec, invmgr, gamedef, tsrc, device, - joystick, fs_src, txt_dst, NULL); -} - /******************************************************************************/ static void show_pause_menu(GUIFormSpecMenu **cur_formspec, - InventoryManager *invmgr, IGameDef *gamedef, + Client *client, IWritableTextureSource *tsrc, IrrlichtDevice *device, JoystickController *joystick, bool singleplayermode) { @@ -1232,8 +996,7 @@ static void show_pause_menu(GUIFormSpecMenu **cur_formspec, FormspecFormSource *fs_src = new FormspecFormSource(os.str()); LocalFormspecHandler *txt_dst = new LocalFormspecHandler("MT_PAUSE_MENU"); - create_formspec_menu(cur_formspec, invmgr, gamedef, tsrc, device, - joystick, fs_src, txt_dst, NULL); + create_formspec_menu(cur_formspec, client, device, joystick, fs_src, txt_dst); std::string con("btn_continue"); (*cur_formspec)->setFocus(con); (*cur_formspec)->doPause = true; @@ -1559,7 +1322,7 @@ class Game { void dropSelectedItem(); void openInventory(); - void openConsole(float height, const wchar_t *line=NULL); + void openConsole(float scale, const wchar_t *line=NULL); void toggleFreeMove(float *statustext_time); void toggleFreeMoveAlt(float *statustext_time, float *jump_timer); void toggleFast(float *statustext_time); @@ -1594,6 +1357,23 @@ class Game { void updateSound(f32 dtime); void processPlayerInteraction(GameRunData *runData, f32 dtime, bool show_hud, bool show_debug); + /*! + * Returns the object or node the player is pointing at. + * Also updates the selected thing in the Hud. + * + * @param[in] shootline the shootline, starting from + * the camera position. This also gives the maximal distance + * of the search. + * @param[in] liquids_pointable if false, liquids are ignored + * @param[in] look_for_object if false, objects are ignored + * @param[in] camera_offset offset of the camera + * @param[out] selected_object the selected object or + * NULL if not found + */ + PointedThing updatePointedThing( + const core::line3d &shootline, bool liquids_pointable, + bool look_for_object, const v3s16 &camera_offset, + ClientActiveObject *&selected_object); void handlePointingAtNothing(GameRunData *runData, const ItemStack &playerItem); void handlePointingAtNode(GameRunData *runData, const PointedThing &pointed, const ItemDefinition &playeritem_def, @@ -1680,6 +1460,8 @@ class Game { ChatBackend *chat_backend; GUIFormSpecMenu *current_formspec; + //default: "". If other than "", empty show_formspec packets will only close the formspec when the formname matches + std::string cur_formname; EventManager *eventmgr; QuicktuneShortcutter *quicktune; @@ -1691,7 +1473,10 @@ class Game { Sky *sky; // Free using ->Drop() Inventory *local_inventory; Hud *hud; - Mapper *mapper; + Minimap *mapper; + + GameRunData runData; + VolatileRunFlags flags; /* 'cache' This class does take ownership/responsibily for cleaning up etc of any of @@ -1703,7 +1488,6 @@ class Game { bool *kill; std::string *error_message; bool *reconnect_requested; - IGameDef *gamedef; // Convenience (same as *client) scene::ISceneNode *skybox; bool random_input; @@ -1746,6 +1530,8 @@ class Game { f32 m_cache_mouse_sensitivity; f32 m_cache_joystick_frustum_sensitivity; f32 m_repeat_right_click_time; + f32 m_cache_cam_smoothing; + f32 m_cache_fog_start; #ifdef __ANDROID__ bool m_cache_hold_aux1; @@ -1765,6 +1551,7 @@ Game::Game() : soundmaker(NULL), chat_backend(NULL), current_formspec(NULL), + cur_formname(""), eventmgr(NULL), quicktune(NULL), gui_chat_console(NULL), @@ -1796,6 +1583,12 @@ Game::Game() : &settingChangedCallback, this); g_settings->registerChangedCallback("free_move", &settingChangedCallback, this); + g_settings->registerChangedCallback("cinematic", + &settingChangedCallback, this); + g_settings->registerChangedCallback("cinematic_camera_smoothing", + &settingChangedCallback, this); + g_settings->registerChangedCallback("camera_smoothing", + &settingChangedCallback, this); readSettings(); @@ -1849,6 +1642,12 @@ Game::~Game() &settingChangedCallback, this); g_settings->deregisterChangedCallback("free_move", &settingChangedCallback, this); + g_settings->deregisterChangedCallback("cinematic", + &settingChangedCallback, this); + g_settings->deregisterChangedCallback("cinematic_camera_smoothing", + &settingChangedCallback, this); + g_settings->deregisterChangedCallback("camera_smoothing", + &settingChangedCallback, this); } bool Game::startup(bool *kill, @@ -1884,6 +1683,18 @@ bool Game::startup(bool *kill, smgr->getParameters()->setAttribute(scene::OBJ_LOADER_IGNORE_MATERIAL_FILES, true); + memset(&runData, 0, sizeof(runData)); + runData.time_from_last_punch = 10.0; + runData.profiler_max_page = 3; + runData.update_wielded_item_trigger = true; + + memset(&flags, 0, sizeof(flags)); + flags.show_chat = true; + flags.show_hud = true; + flags.show_debug = g_settings->getBool("show_debug"); + flags.invert_mouse = g_settings->getBool("invert_mouse"); + flags.first_loop_after_window_activation = true; + if (!init(map_dir, address, port, gamespec)) return false; @@ -1900,34 +1711,15 @@ void Game::run() RunStats stats = { 0 }; CameraOrientation cam_view_target = { 0 }; CameraOrientation cam_view = { 0 }; - GameRunData runData = { 0 }; FpsControl draw_times = { 0 }; - VolatileRunFlags flags = { 0 }; f32 dtime; // in seconds - runData.time_from_last_punch = 10.0; - runData.profiler_max_page = 3; - runData.update_wielded_item_trigger = true; - - flags.show_chat = true; - flags.show_hud = true; - flags.show_minimap = g_settings->getBool("enable_minimap"); - flags.show_debug = g_settings->getBool("show_debug"); - flags.invert_mouse = g_settings->getBool("invert_mouse"); - flags.first_loop_after_window_activation = true; - /* Clear the profiler */ Profiler::GraphValues dummyvalues; g_profiler->graphGet(dummyvalues); draw_times.last_time = device->getTimer()->getTime(); - shader_src->addGlobalConstantSetter(new GameGlobalShaderConstantSetter( - sky, - &flags.force_fog_off, - &runData.fog_range, - client)); - set_light_table(g_settings->getFloat("display_gamma")); #ifdef __ANDROID__ @@ -1961,16 +1753,10 @@ void Game::run() processUserInput(&flags, &runData, dtime); // Update camera before player movement to avoid camera lag of one frame updateCameraDirection(&cam_view_target, &flags, dtime); - float cam_smoothing = 0; - if (g_settings->getBool("cinematic")) - cam_smoothing = 1 - g_settings->getFloat("cinematic_camera_smoothing"); - else - cam_smoothing = 1 - g_settings->getFloat("camera_smoothing"); - cam_smoothing = rangelim(cam_smoothing, 0.01f, 1.0f); cam_view.camera_yaw += (cam_view_target.camera_yaw - - cam_view.camera_yaw) * cam_smoothing; + cam_view.camera_yaw) * m_cache_cam_smoothing; cam_view.camera_pitch += (cam_view_target.camera_pitch - - cam_view.camera_pitch) * cam_smoothing; + cam_view.camera_pitch) * m_cache_cam_smoothing; updatePlayerControl(cam_view); step(&dtime); processClientEvents(&cam_view_target, &runData.damage_flash); @@ -1983,16 +1769,18 @@ void Game::run() updateProfilerGraphs(&graph); // Update if minimap has been disabled by the server - flags.show_minimap &= !client->isMinimapDisabledByServer(); + flags.show_minimap &= client->shouldShowMinimap(); } } void Game::shutdown() { +#if IRRLICHT_VERSION_MAJOR == 1 && IRRLICHT_VERSION_MINOR <= 8 if (g_settings->get("3d_mode") == "pageflip") { driver->setRenderTarget(irr::video::ERT_STEREO_BOTH_BUFFERS); } +#endif showOverlayMessage(wgettext("Shutting down..."), 0, 0, false); @@ -2167,12 +1955,16 @@ bool Game::createClient(const std::string &playername, return false; } + GameGlobalShaderConstantSetterFactory *scsf = new GameGlobalShaderConstantSetterFactory( + &flags.force_fog_off, &runData.fog_range, client); + shader_src->addShaderConstantSetterFactory(scsf); + // Update cached textures, meshes and materials client->afterContentReceived(device); /* Camera */ - camera = new Camera(smgr, *draw_control, gamedef); + camera = new Camera(smgr, *draw_control, client); if (!camera || !camera->successfullyCreated(*error_message)) return false; client->setCamera(camera); @@ -2191,6 +1983,7 @@ bool Game::createClient(const std::string &playername, /* Skybox */ sky = new Sky(smgr->getRootSceneNode(), smgr, -1, texture_src); + scsf->setSky(sky); skybox = NULL; // This is used/set later on in the main run loop local_inventory = new Inventory(itemdef_manager); @@ -2228,7 +2021,7 @@ bool Game::createClient(const std::string &playername, player->hurt_tilt_timer = 0; player->hurt_tilt_strength = 0; - hud = new Hud(driver, smgr, guienv, gamedef, player, local_inventory); + hud = new Hud(driver, smgr, guienv, client, player, local_inventory); if (!hud) { *error_message = "Memory error: could not create HUD"; @@ -2236,7 +2029,7 @@ bool Game::createClient(const std::string &playername, return false; } - mapper = client->getMapper(); + mapper = client->getMinimap(); mapper->setMinimapMode(MINIMAP_MODE_OFF); return true; @@ -2358,8 +2151,6 @@ bool Game::connectToServer(const std::string &playername, if (!client) return false; - gamedef = client; // Client acts as our GameDef - infostream << "Connecting to server at "; connect_address.print(&infostream); infostream << std::endl; @@ -2380,6 +2171,8 @@ bool Game::connectToServer(const std::string &playername, fps_control.last_time = device->getTimer()->getTime(); + client->initMods(); + while (device->run()) { limitFps(&fps_control, &dtime); @@ -2605,7 +2398,7 @@ inline bool Game::handleCallbacks() void Game::processQueues() { texture_src->processQueue(); - itemdef_manager->processQueue(gamedef); + itemdef_manager->processQueue(client); shader_src->processQueue(); } @@ -2777,7 +2570,7 @@ void Game::processKeyInput(VolatileRunFlags *flags, openInventory(); } else if (wasKeyDown(KeyType::ESC) || input->wasKeyDown(CancelKey)) { if (!gui_chat_console->isOpenInhibited()) { - show_pause_menu(¤t_formspec, client, gamedef, + show_pause_menu(¤t_formspec, client, texture_src, device, &input->joystick, simple_singleplayer_mode); } @@ -2786,7 +2579,8 @@ void Game::processKeyInput(VolatileRunFlags *flags, } else if (wasKeyDown(KeyType::CMD)) { openConsole(0.2, L"/"); } else if (wasKeyDown(KeyType::CONSOLE)) { - openConsole(1); + openConsole(core::clamp( + g_settings->getFloat("console_height"), 0.1f, 1.0f)); } else if (wasKeyDown(KeyType::FREEMOVE)) { toggleFreeMove(statustext_time); } else if (wasKeyDown(KeyType::JUMP)) { @@ -2929,8 +2723,8 @@ void Game::openInventory() PlayerInventoryFormSource *fs_src = new PlayerInventoryFormSource(client); TextDest *txt_dst = new TextDestPlayerInventory(client); - create_formspec_menu(¤t_formspec, client, gamedef, texture_src, - device, &input->joystick, fs_src, txt_dst, client); + create_formspec_menu(¤t_formspec, client, device, &input->joystick, fs_src, txt_dst); + cur_formname = ""; InventoryLocation inventoryloc; inventoryloc.setCurrentPlayer(); @@ -2938,15 +2732,17 @@ void Game::openInventory() } -void Game::openConsole(float height, const wchar_t *line) +void Game::openConsole(float scale, const wchar_t *line) { + assert(scale > 0.0f && scale <= 1.0f); + #ifdef __ANDROID__ porting::showInputDialog(gettext("ok"), "", "", 2); m_android_chat_open = true; #else if (gui_chat_console->isOpenInhibited()) return; - gui_chat_console->openConsole(height); + gui_chat_console->openConsole(scale); if (line) { gui_chat_console->setCloseOnEnter(true); gui_chat_console->replaceAndAddToHistory(line); @@ -3131,7 +2927,7 @@ void Game::toggleDebug(float *statustext_time, bool *show_debug, *show_profiler_graph = false; *show_wireframe = false; statustext = L"Debug info shown"; - } else if (!*show_profiler_graph) { + } else if (!*show_profiler_graph && !*show_wireframe) { *show_profiler_graph = true; statustext = L"Profiler graph shown"; } else if (!*show_wireframe && client->checkPrivilege("debug")) { @@ -3190,9 +2986,16 @@ void Game::increaseViewRange(float *statustext_time) { s16 range = g_settings->getS16("viewing_range"); s16 range_new = range + 10; + + if (range_new > 4000) { + range_new = 4000; + statustext = utf8_to_wide("Viewing range is at maximum: " + + itos(range_new)); + } else { + statustext = utf8_to_wide("Viewing range changed to " + + itos(range_new)); + } g_settings->set("viewing_range", itos(range_new)); - statustext = utf8_to_wide("Viewing range changed to " - + itos(range_new)); *statustext_time = 0; } @@ -3202,12 +3005,15 @@ void Game::decreaseViewRange(float *statustext_time) s16 range = g_settings->getS16("viewing_range"); s16 range_new = range - 10; - if (range_new < 20) + if (range_new < 20) { range_new = 20; - + statustext = utf8_to_wide("Viewing range is at minimum: " + + itos(range_new)); + } else { + statustext = utf8_to_wide("Viewing range changed to " + + itos(range_new)); + } g_settings->set("viewing_range", itos(range_new)); - statustext = utf8_to_wide("Viewing range changed to " - + itos(range_new)); *statustext_time = 0; } @@ -3265,8 +3071,8 @@ void Game::updateCameraOrientation(CameraOrientation *cam, { #ifdef HAVE_TOUCHSCREENGUI if (g_touchscreengui) { - cam->camera_yaw = g_touchscreengui->getYaw(); - cam->camera_pitch = g_touchscreengui->getPitch(); + cam->camera_yaw += g_touchscreengui->getYawChange(); + cam->camera_pitch = g_touchscreengui->getPitch(); } else { #endif @@ -3381,10 +3187,10 @@ void Game::processClientEvents(CameraOrientation *cam, float *damage_flash) for ( ; event.type != CE_NONE; event = client->getClientEvent()) { - if (event.type == CE_PLAYER_DAMAGE && - client->getHP() != 0) { - //u16 damage = event.player_damage.amount; - //infostream<<"Player damage: "<getHP() != 0) { + if (client->moddingEnabled()) { + client->getScript()->on_damage_taken(event.player_damage.amount); + } *damage_flash += 95.0 + 3.2 * event.player_damage.amount; *damage_flash = MYMIN(*damage_flash, 127.0); @@ -3394,15 +3200,13 @@ void Game::processClientEvents(CameraOrientation *cam, float *damage_flash) rangelim(event.player_damage.amount / 4, 1.0, 4.0); MtEvent *e = new SimpleTriggerEvent("PlayerDamage"); - gamedef->event()->put(e); + client->event()->put(e); } else if (event.type == CE_PLAYER_FORCE_MOVE) { cam->camera_yaw = event.player_force_move.yaw; cam->camera_pitch = event.player_force_move.pitch; } else if (event.type == CE_DEATHSCREEN) { - show_deathscreen(¤t_formspec, client, gamedef, texture_src, - device, &input->joystick, client); - - chat_backend->addMessage(L"", L"You died."); + // This should be enabled for death formspec in builtin + client->getScript()->on_death(); /* Handle visualization */ *damage_flash = 0; @@ -3410,21 +3214,34 @@ void Game::processClientEvents(CameraOrientation *cam, float *damage_flash) player->hurt_tilt_strength = 0; } else if (event.type == CE_SHOW_FORMSPEC) { - FormspecFormSource *fs_src = - new FormspecFormSource(*(event.show_formspec.formspec)); - TextDestPlayerInventory *txt_dst = - new TextDestPlayerInventory(client, *(event.show_formspec.formname)); - - create_formspec_menu(¤t_formspec, client, gamedef, - texture_src, device, &input->joystick, - fs_src, txt_dst, client); + if (*(event.show_formspec.formspec) == "") { + if (current_formspec && ( *(event.show_formspec.formname) == "" || *(event.show_formspec.formname) == cur_formname) ){ + current_formspec->quitMenu(); + } + } else { + FormspecFormSource *fs_src = + new FormspecFormSource(*(event.show_formspec.formspec)); + TextDestPlayerInventory *txt_dst = + new TextDestPlayerInventory(client, *(event.show_formspec.formname)); + + create_formspec_menu(¤t_formspec, client, device, &input->joystick, + fs_src, txt_dst); + cur_formname = *(event.show_formspec.formname); + } delete(event.show_formspec.formspec); delete(event.show_formspec.formname); + } else if (event.type == CE_SHOW_LOCAL_FORMSPEC) { + FormspecFormSource *fs_src = new FormspecFormSource(*event.show_formspec.formspec); + LocalFormspecHandler *txt_dst = new LocalFormspecHandler(*event.show_formspec.formname, client); + create_formspec_menu(¤t_formspec, client, device, &input->joystick, + fs_src, txt_dst); + delete event.show_formspec.formspec; + delete event.show_formspec.formname; } else if ((event.type == CE_SPAWN_PARTICLE) || (event.type == CE_ADD_PARTICLESPAWNER) || (event.type == CE_DELETE_PARTICLESPAWNER)) { - client->getParticleManager()->handleParticleEvent(&event, gamedef, + client->getParticleManager()->handleParticleEvent(&event, client, smgr, player); } else if (event.type == CE_HUDADD) { u32 id = event.hudadd.id; @@ -3598,6 +3415,12 @@ void Game::updateCamera(VolatileRunFlags *flags, u32 busy_time, if (mlist && client->getPlayerItem() < mlist->getSize()) playeritem = mlist->getItem(client->getPlayerItem()); } + if (playeritem.getDefinition(itemdef_manager).name.empty()) { // override the hand + InventoryList *hlist = local_inventory->getList("hand"); + if (hlist) + playeritem = hlist->getItem(0); + } + ToolCapabilities playeritem_toolcap = playeritem.getToolCapabilities(itemdef_manager); @@ -3664,7 +3487,7 @@ void Game::updateSound(f32 dtime) LocalPlayer *player = client->getEnv().getLocalPlayer(); ClientMap &map = client->getEnv().getClientMap(); - MapNode n = map.getNodeNoEx(player->getStandingNodePos()); + MapNode n = map.getNodeNoEx(player->getFootstepNodePos()); soundmaker->m_player_step_sound = nodedef_manager->get(n).sound_footstep; } @@ -3682,6 +3505,11 @@ void Game::processPlayerInteraction(GameRunData *runData, playeritem = mlist->getItem(client->getPlayerItem()); } + if (playeritem.getDefinition(itemdef_manager).name.empty()) { // override the hand + InventoryList *hlist = local_inventory->getList("hand"); + if (hlist) + playeritem = hlist->getItem(0); + } const ItemDefinition &playeritem_def = playeritem.getDefinition(itemdef_manager); @@ -3706,14 +3534,11 @@ void Game::processPlayerInteraction(GameRunData *runData, core::line3d shootline; if (camera->getCameraMode() != CAMERA_MODE_THIRD_FRONT) { - shootline = core::line3d(camera_position, - camera_position + camera_direction * BS * (d + 1)); - + camera_position + camera_direction * BS * d); } else { // prevent player pointing anything in front-view - if (camera->getCameraMode() == CAMERA_MODE_THIRD_FRONT) - shootline = core::line3d(0, 0, 0, 0, 0, 0); + shootline = core::line3d(camera_position,camera_position); } #ifdef HAVE_TOUCHSCREENGUI @@ -3726,10 +3551,7 @@ void Game::processPlayerInteraction(GameRunData *runData, #endif - PointedThing pointed = getPointedThing( - // input - client, hud, player_position, camera_direction, - camera_position, shootline, d, + PointedThing pointed = updatePointedThing(shootline, playeritem_def.liquids_pointable, !runData->ldown_for_dig, camera_offset, @@ -3823,6 +3645,107 @@ void Game::processPlayerInteraction(GameRunData *runData, } +PointedThing Game::updatePointedThing( + const core::line3d &shootline, + bool liquids_pointable, + bool look_for_object, + const v3s16 &camera_offset, + ClientActiveObject *&selected_object) +{ + std::vector *selectionboxes = hud->getSelectionBoxes(); + selectionboxes->clear(); + hud->setSelectedFaceNormal(v3f(0.0, 0.0, 0.0)); + static const bool show_entity_selectionbox = g_settings->getBool( + "show_entity_selectionbox"); + + ClientMap &map = client->getEnv().getClientMap(); + INodeDefManager *nodedef=client->getNodeDefManager(); + + selected_object = NULL; + + PointedThing result=client->getEnv().getPointedThing( + shootline, liquids_pointable, look_for_object); + if (result.type == POINTEDTHING_OBJECT) { + selected_object = client->getEnv().getActiveObject(result.object_id); + if (show_entity_selectionbox && selected_object->doShowSelectionBox()) { + aabb3f *selection_box = selected_object->getSelectionBox(); + + // Box should exist because object was + // returned in the first place + + assert(selection_box); + + v3f pos = selected_object->getPosition(); + selectionboxes->push_back(aabb3f( + selection_box->MinEdge, selection_box->MaxEdge)); + selectionboxes->push_back( + aabb3f(selection_box->MinEdge, selection_box->MaxEdge)); + hud->setSelectionPos(pos, camera_offset); + } + } else if (result.type == POINTEDTHING_NODE) { + // Update selection boxes + MapNode n = map.getNodeNoEx(result.node_undersurface); + std::vector boxes; + n.getSelectionBoxes(nodedef, &boxes, + n.getNeighbors(result.node_undersurface, &map)); + + f32 d = 0.002 * BS; + for (std::vector::const_iterator i = boxes.begin(); + i != boxes.end(); ++i) { + aabb3f box = *i; + box.MinEdge -= v3f(d, d, d); + box.MaxEdge += v3f(d, d, d); + selectionboxes->push_back(box); + } + hud->setSelectionPos(intToFloat(result.node_undersurface, BS), + camera_offset); + hud->setSelectedFaceNormal(v3f( + result.intersection_normal.X, + result.intersection_normal.Y, + result.intersection_normal.Z)); + } + + // Update selection mesh light level and vertex colors + if (selectionboxes->size() > 0) { + v3f pf = hud->getSelectionPos(); + v3s16 p = floatToInt(pf, BS); + + // Get selection mesh light level + MapNode n = map.getNodeNoEx(p); + u16 node_light = getInteriorLight(n, -1, nodedef); + u16 light_level = node_light; + + for (u8 i = 0; i < 6; i++) { + n = map.getNodeNoEx(p + g_6dirs[i]); + node_light = getInteriorLight(n, -1, nodedef); + if (node_light > light_level) + light_level = node_light; + } + + u32 daynight_ratio = client->getEnv().getDayNightRatio(); + video::SColor c; + final_color_blend(&c, light_level, daynight_ratio); + + // Modify final color a bit with time + u32 timer = porting::getTimeMs() % 5000; + float timerf = (float) (irr::core::PI * ((timer / 2500.0) - 0.5)); + float sin_r = 0.08 * sin(timerf); + float sin_g = 0.08 * sin(timerf + irr::core::PI * 0.5); + float sin_b = 0.08 * sin(timerf + irr::core::PI); + c.setRed( + core::clamp(core::round32(c.getRed() * (0.8 + sin_r)), 0, 255)); + c.setGreen( + core::clamp(core::round32(c.getGreen() * (0.8 + sin_g)), 0, 255)); + c.setBlue( + core::clamp(core::round32(c.getBlue() * (0.8 + sin_b)), 0, 255)); + + // Set mesh final color + hud->setSelectionMeshColor(c); + } + return result; +} + + void Game::handlePointingAtNothing(GameRunData *runData, const ItemStack &playerItem) { infostream << "Right Clicked in Air" << std::endl; @@ -3879,8 +3802,9 @@ void Game::handlePointingAtNode(GameRunData *runData, &client->getEnv().getClientMap(), nodepos); TextDest *txt_dst = new TextDestNodeMetadata(nodepos, client); - create_formspec_menu(¤t_formspec, client, gamedef, - texture_src, device, &input->joystick, fs_src, txt_dst, client); + create_formspec_menu(¤t_formspec, client, + device, &input->joystick, fs_src, txt_dst); + cur_formname = ""; current_formspec->setFormSpec(meta->getString("formspec"), inventoryloc); } else { @@ -3975,17 +3899,20 @@ void Game::handleDigging(GameRunData *runData, const PointedThing &pointed, const v3s16 &nodepos, const ToolCapabilities &playeritem_toolcap, f32 dtime) { + + LocalPlayer *player = client->getEnv().getLocalPlayer(); + ClientMap &map = client->getEnv().getClientMap(); + MapNode n = client->getEnv().getClientMap().getNodeNoEx(nodepos); + if (!runData->digging) { infostream << "Started digging" << std::endl; + if (client->moddingEnabled() && client->getScript()->on_punchnode(nodepos, n)) + return; client->interact(0, pointed); runData->digging = true; runData->ldown_for_dig = true; } - LocalPlayer *player = client->getEnv().getLocalPlayer(); - ClientMap &map = client->getEnv().getClientMap(); - MapNode n = client->getEnv().getClientMap().getNodeNoEx(nodepos); - // NOTE: Similar piece of code exists on the server side for // cheat detection. // Get digging parameters @@ -4010,8 +3937,8 @@ void Game::handleDigging(GameRunData *runData, if (m_cache_enable_particles) { const ContentFeatures &features = client->getNodeDefManager()->get(n); - client->getParticleManager()->addPunchingParticles(gamedef, smgr, - player, nodepos, features.tiles); + client->getParticleManager()->addPunchingParticles(client, smgr, + player, nodepos, n, features); } } @@ -4047,19 +3974,7 @@ void Game::handleDigging(GameRunData *runData, client->setCrack(runData->dig_index, nodepos); } else { infostream << "Digging completed" << std::endl; - client->interact(2, pointed); client->setCrack(-1, v3s16(0, 0, 0)); - bool is_valid_position; - MapNode wasnode = map.getNodeNoEx(nodepos, &is_valid_position); - if (is_valid_position) - client->removeNode(nodepos); - - if (m_cache_enable_particles) { - const ContentFeatures &features = - client->getNodeDefManager()->get(wasnode); - client->getParticleManager()->addDiggingParticles(gamedef, smgr, - player, nodepos, features.tiles); - } runData->dig_time = 0; runData->digging = false; @@ -4079,9 +3994,30 @@ void Game::handleDigging(GameRunData *runData, if (runData->nodig_delay_timer < mindelay) runData->nodig_delay_timer = mindelay; + bool is_valid_position; + MapNode wasnode = map.getNodeNoEx(nodepos, &is_valid_position); + if (is_valid_position) { + if (client->moddingEnabled()) { + if (client->getScript()->on_dignode(nodepos, wasnode)) { + return; + } + } + client->removeNode(nodepos); + } + + client->interact(2, pointed); + + if (m_cache_enable_particles) { + const ContentFeatures &features = + client->getNodeDefManager()->get(wasnode); + client->getParticleManager()->addDiggingParticles(client, smgr, + player, nodepos, wasnode, features); + } + + // Send event to trigger sound MtEvent *e = new NodeDugEvent(nodepos, wasnode); - gamedef->event()->put(e); + client->event()->put(e); } if (runData->dig_time_complete < 100000.0) { @@ -4108,7 +4044,7 @@ void Game::updateFrame(ProfilerGraph *graph, RunStats *stats, if (draw_control->range_all) { runData->fog_range = 100000 * BS; } else { - runData->fog_range = 0.9 * draw_control->wanted_range * BS; + runData->fog_range = draw_control->wanted_range * BS; } /* @@ -4186,7 +4122,7 @@ void Game::updateFrame(ProfilerGraph *graph, RunStats *stats, driver->setFog( sky->getBgColor(), video::EFT_FOG_LINEAR, - runData->fog_range * 0.4, + runData->fog_range * m_cache_fog_start, runData->fog_range * 1.0, 0.01, false, // pixel fog @@ -4234,8 +4170,14 @@ void Game::updateFrame(ProfilerGraph *graph, RunStats *stats, if (mlist && (client->getPlayerItem() < mlist->getSize())) { ItemStack item = mlist->getItem(client->getPlayerItem()); + if (item.getDefinition(itemdef_manager).name.empty()) { // override the hand + InventoryList *hlist = local_inventory->getList("hand"); + if (hlist) + item = hlist->getItem(0); + } camera->wield(item); } + runData->update_wielded_item_trigger = false; } @@ -4556,7 +4498,18 @@ void Game::readSettings() m_cache_enable_noclip = g_settings->getBool("noclip"); m_cache_enable_free_move = g_settings->getBool("free_move"); + m_cache_fog_start = g_settings->getFloat("fog_start"); + + m_cache_cam_smoothing = 0; + if (g_settings->getBool("cinematic")) + m_cache_cam_smoothing = 1 - g_settings->getFloat("cinematic_camera_smoothing"); + else + m_cache_cam_smoothing = 1 - g_settings->getFloat("camera_smoothing"); + + m_cache_fog_start = rangelim(m_cache_fog_start, 0.0f, 0.99f); + m_cache_cam_smoothing = rangelim(m_cache_cam_smoothing, 0.01f, 1.0f); m_cache_mouse_sensitivity = rangelim(m_cache_mouse_sensitivity, 0.001, 100.0); + } /****************************************************************************/