#include "game.h"
#include <iomanip>
+#include <cmath>
+#include "client/renderingengine.h"
#include "camera.h"
#include "client.h"
+#include "client/inputhandler.h"
#include "client/tile.h" // For TextureSource
#include "client/keys.h"
#include "client/joystick_controller.h"
#include "clouds.h"
#include "config.h"
#include "content_cao.h"
-#include "drawscene.h"
#include "event_manager.h"
#include "fontengine.h"
#include "itemdef.h"
#include "guiVolumeChange.h"
#include "mainmenumanager.h"
#include "mapblock.h"
+#include "minimap.h"
#include "nodedef.h" // Needed for determining pointing to nodes
#include "nodemetadata.h"
#include "particles.h"
#include "profiler.h"
#include "quicktune_shortcutter.h"
+#include "raycast.h"
#include "server.h"
#include "settings.h"
-#include "shader.h" // For ShaderSource
+#include "shader.h"
#include "sky.h"
#include "subgame.h"
#include "tool.h"
+#include "util/basic_macros.h"
#include "util/directiontables.h"
#include "util/pointedthing.h"
#include "irrlicht_changes/static_text.h"
#include "version.h"
-#include "minimap.h"
-#include "mapblock_mesh.h"
-#include "script/clientscripting.h"
-
-#include "sound.h"
+#include "script/scripting_client.h"
#if USE_SOUND
#include "sound_openal.h"
#endif
-#ifdef HAVE_TOUCHSCREENGUI
- #include "touchscreengui.h"
-#endif
-
-extern Settings *g_settings;
-extern Profiler *g_profiler;
/*
Text input system
struct LocalFormspecHandler : public TextDest
{
- LocalFormspecHandler(const std::string &formname):
- m_client(NULL)
+ LocalFormspecHandler(const std::string &formname)
{
m_formname = formname;
}
if (fields.find("btn_exit_os") != fields.end()) {
g_gamecallback->exitToOS();
+#ifndef __ANDROID__
+ RenderingEngine::get_raw_device()->closeDevice();
+#endif
return;
}
}
// Don't disable this part when modding is disabled, it's used in builtin
- m_client->getScript()->on_formspec_input(m_formname, fields);
+ if (m_client && m_client->getScript())
+ m_client->getScript()->on_formspec_input(m_formname, fields);
}
- Client *m_client;
+ Client *m_client = nullptr;
};
/* Form update callback */
setStaticText(guitext_profiler, text.c_str());
guitext_profiler->setVisible(true);
- s32 w = fe->getTextWidth(text.c_str());
+ s32 w = fe->getTextWidth(text);
if (w < 400)
w = 400;
};
std::deque<Piece> m_log;
public:
- u32 m_log_max_size;
+ u32 m_log_max_size = 200;
- ProfilerGraph():
- m_log_max_size(200)
- {}
+ ProfilerGraph() = default;
void put(const Profiler::GraphValues &values)
{
// to be the same for each call to prevent flickering
std::map<std::string, Meta> m_meta;
- for (std::deque<Piece>::const_iterator k = m_log.begin();
- k != m_log.end(); ++k) {
- const Piece &piece = *k;
-
- for (Profiler::GraphValues::const_iterator i = piece.values.begin();
- i != piece.values.end(); ++i) {
- const std::string &id = i->first;
- const float &value = i->second;
+ for (const Piece &piece : m_log) {
+ for (const auto &i : piece.values) {
+ const std::string &id = i.first;
+ const float &value = i.second;
std::map<std::string, Meta>::iterator j = m_meta.find(id);
if (j == m_meta.end()) {
sizeof(usable_colors) / sizeof(*usable_colors);
u32 next_color_i = 0;
- for (std::map<std::string, Meta>::iterator i = m_meta.begin();
- i != m_meta.end(); ++i) {
- Meta &meta = i->second;
+ for (auto &i : m_meta) {
+ Meta &meta = i.second;
video::SColor color(255, 200, 200, 200);
if (next_color_i < usable_colors_count)
float lastscaledvalue = 0.0;
bool lastscaledvalue_exists = false;
- for (std::deque<Piece>::const_iterator j = m_log.begin();
- j != m_log.end(); ++j) {
- const Piece &piece = *j;
+ for (const Piece &piece : m_log) {
float value = 0;
bool value_exists = false;
Profiler::GraphValues::const_iterator k =
ISoundManager *m_sound;
INodeDefManager *m_ndef;
public:
+ bool makes_footstep_sound;
float m_player_step_timer;
SimpleSoundSpec m_player_step_sound;
SoundMaker(ISoundManager *sound, INodeDefManager *ndef):
m_sound(sound),
m_ndef(ndef),
+ makes_footstep_sound(true),
m_player_step_timer(0)
{
}
{
if (m_player_step_timer <= 0 && m_player_step_sound.exists()) {
m_player_step_timer = 0.03;
- m_sound->playSound(m_player_step_sound, false);
+ if (makes_footstep_sound)
+ m_sound->playSound(m_player_step_sound, false);
}
}
class GameOnDemandSoundFetcher: public OnDemandSoundFetcher
{
std::set<std::string> m_fetched;
+private:
+ void paths_insert(std::set<std::string> &dst_paths,
+ const std::string &base,
+ const std::string &name)
+ {
+ dst_paths.insert(base + DIR_DELIM + "sounds" + DIR_DELIM + name + ".ogg");
+ dst_paths.insert(base + DIR_DELIM + "sounds" + DIR_DELIM + name + ".0.ogg");
+ dst_paths.insert(base + DIR_DELIM + "sounds" + DIR_DELIM + name + ".1.ogg");
+ dst_paths.insert(base + DIR_DELIM + "sounds" + DIR_DELIM + name + ".2.ogg");
+ dst_paths.insert(base + DIR_DELIM + "sounds" + DIR_DELIM + name + ".3.ogg");
+ dst_paths.insert(base + DIR_DELIM + "sounds" + DIR_DELIM + name + ".4.ogg");
+ dst_paths.insert(base + DIR_DELIM + "sounds" + DIR_DELIM + name + ".5.ogg");
+ dst_paths.insert(base + DIR_DELIM + "sounds" + DIR_DELIM + name + ".6.ogg");
+ dst_paths.insert(base + DIR_DELIM + "sounds" + DIR_DELIM + name + ".7.ogg");
+ dst_paths.insert(base + DIR_DELIM + "sounds" + DIR_DELIM + name + ".8.ogg");
+ dst_paths.insert(base + DIR_DELIM + "sounds" + DIR_DELIM + name + ".9.ogg");
+ }
public:
void fetchSounds(const std::string &name,
- std::set<std::string> &dst_paths,
- std::set<std::string> &dst_datas)
+ std::set<std::string> &dst_paths,
+ std::set<std::string> &dst_datas)
{
if (m_fetched.count(name))
return;
m_fetched.insert(name);
- std::string base = porting::path_share + DIR_DELIM + "sounds";
- dst_paths.insert(base + DIR_DELIM + name + ".ogg");
- dst_paths.insert(base + DIR_DELIM + name + ".0.ogg");
- dst_paths.insert(base + DIR_DELIM + name + ".1.ogg");
- dst_paths.insert(base + DIR_DELIM + name + ".2.ogg");
- dst_paths.insert(base + DIR_DELIM + name + ".3.ogg");
- dst_paths.insert(base + DIR_DELIM + name + ".4.ogg");
- dst_paths.insert(base + DIR_DELIM + name + ".5.ogg");
- dst_paths.insert(base + DIR_DELIM + name + ".6.ogg");
- dst_paths.insert(base + DIR_DELIM + name + ".7.ogg");
- dst_paths.insert(base + DIR_DELIM + name + ".8.ogg");
- dst_paths.insert(base + DIR_DELIM + name + ".9.ogg");
+
+ paths_insert(dst_paths, porting::path_share, name);
+ paths_insert(dst_paths, porting::path_user, name);
}
};
m_eye_position_pixel.set(eye_position_array, services);
m_eye_position_vertex.set(eye_position_array, services);
- float minimap_yaw_array[3];
- v3f minimap_yaw = m_client->getMinimap()->getYawVec();
+ if (m_client->getMinimap()) {
+ float minimap_yaw_array[3];
+ v3f minimap_yaw = m_client->getMinimap()->getYawVec();
#if (IRRLICHT_VERSION_MAJOR == 1 && IRRLICHT_VERSION_MINOR < 8)
- minimap_yaw_array[0] = minimap_yaw.X;
- minimap_yaw_array[1] = minimap_yaw.Y;
- minimap_yaw_array[2] = minimap_yaw.Z;
+ minimap_yaw_array[0] = minimap_yaw.X;
+ minimap_yaw_array[1] = minimap_yaw.Y;
+ minimap_yaw_array[2] = minimap_yaw.Z;
#else
- minimap_yaw.getAs3Values(minimap_yaw_array);
+ minimap_yaw.getAs3Values(minimap_yaw_array);
#endif
- m_minimap_yaw.set(minimap_yaw_array, services);
+ m_minimap_yaw.set(minimap_yaw_array, services);
+ }
SamplerLayer_t base_tex = 0,
normal_tex = 1,
void setSky(Sky *sky) {
m_sky = sky;
- for (size_t i = 0; i < created_nosky.size(); ++i) {
- created_nosky[i]->setSky(m_sky);
+ for (GameGlobalShaderConstantSetter *ggscs : created_nosky) {
+ ggscs->setSky(m_sky);
}
created_nosky.clear();
}
};
-bool nodePlacementPrediction(Client &client,
- const ItemDefinition &playeritem_def, v3s16 nodepos, v3s16 neighbourpos)
+bool nodePlacementPrediction(Client &client, const ItemDefinition &playeritem_def,
+ const ItemStack &playeritem, v3s16 nodepos, v3s16 neighbourpos)
{
std::string prediction = playeritem_def.node_placement_prediction;
INodeDefManager *nodedef = client.ndef();
if (!is_valid_position)
return false;
- if (prediction != "" && !nodedef->get(node).rightclickable) {
+ if (!prediction.empty() && !nodedef->get(node).rightclickable) {
verbosestream << "Node placement prediction for "
<< playeritem_def.name << " is "
<< prediction << std::endl;
return false;
}
+ const ContentFeatures &predicted_f = nodedef->get(id);
+
// Predict param2 for facedir and wallmounted nodes
u8 param2 = 0;
- if (nodedef->get(id).param_type_2 == CPT2_WALLMOUNTED ||
- nodedef->get(id).param_type_2 == CPT2_COLORED_WALLMOUNTED) {
+ if (predicted_f.param_type_2 == CPT2_WALLMOUNTED ||
+ predicted_f.param_type_2 == CPT2_COLORED_WALLMOUNTED) {
v3s16 dir = nodepos - neighbourpos;
if (abs(dir.Y) > MYMAX(abs(dir.X), abs(dir.Z))) {
}
}
- if (nodedef->get(id).param_type_2 == CPT2_FACEDIR ||
- nodedef->get(id).param_type_2 == CPT2_COLORED_FACEDIR) {
+ if (predicted_f.param_type_2 == CPT2_FACEDIR ||
+ predicted_f.param_type_2 == CPT2_COLORED_FACEDIR) {
v3s16 dir = nodepos - floatToInt(client.getEnv().getLocalPlayer()->getPosition(), BS);
if (abs(dir.X) > abs(dir.Z)) {
assert(param2 <= 5);
//Check attachment if node is in group attached_node
- if (((ItemGroupList) nodedef->get(id).groups)["attached_node"] != 0) {
+ if (((ItemGroupList) predicted_f.groups)["attached_node"] != 0) {
static v3s16 wallmounted_dirs[8] = {
v3s16(0, 1, 0),
v3s16(0, -1, 0),
};
v3s16 pp;
- if (nodedef->get(id).param_type_2 == CPT2_WALLMOUNTED ||
- nodedef->get(id).param_type_2 == CPT2_COLORED_WALLMOUNTED)
+ if (predicted_f.param_type_2 == CPT2_WALLMOUNTED ||
+ predicted_f.param_type_2 == CPT2_COLORED_WALLMOUNTED)
pp = p + wallmounted_dirs[param2];
else
pp = p + v3s16(0, -1, 0);
return false;
}
+ // Apply color
+ if ((predicted_f.param_type_2 == CPT2_COLOR
+ || predicted_f.param_type_2 == CPT2_COLORED_FACEDIR
+ || predicted_f.param_type_2 == CPT2_COLORED_WALLMOUNTED)) {
+ const std::string &indexstr = playeritem.metadata.getString(
+ "palette_index", 0);
+ if (!indexstr.empty()) {
+ s32 index = mystoi(indexstr);
+ if (predicted_f.param_type_2 == CPT2_COLOR) {
+ param2 = index;
+ } else if (predicted_f.param_type_2
+ == CPT2_COLORED_WALLMOUNTED) {
+ // param2 = pure palette index + other
+ param2 = (index & 0xf8) | (param2 & 0x07);
+ } else if (predicted_f.param_type_2
+ == CPT2_COLORED_FACEDIR) {
+ // param2 = pure palette index + other
+ param2 = (index & 0xe0) | (param2 & 0x1f);
+ }
+ }
+ }
+
// Add node to client map
MapNode n(id, 0, param2);
}
static inline void create_formspec_menu(GUIFormSpecMenu **cur_formspec,
- Client *client, IrrlichtDevice *device, JoystickController *joystick,
+ Client *client, JoystickController *joystick,
IFormSource *fs_src, TextDest *txt_dest)
{
if (*cur_formspec == 0) {
- *cur_formspec = new GUIFormSpecMenu(device, joystick,
- guiroot, -1, &g_menumgr, client, client->getTextureSource(),
- fs_src, txt_dest);
+ *cur_formspec = new GUIFormSpecMenu(joystick, guiroot, -1, &g_menumgr,
+ client, client->getTextureSource(), fs_src, txt_dest);
(*cur_formspec)->doPause = false;
/*
// Get new messages from client
std::wstring message;
-
while (client.getChatMessage(message)) {
chat_backend.addUnparsedMessage(message);
}
s32 chat_y = 5;
if (show_debug)
- chat_y += 2 * line_height;
+ chat_y += 3 * line_height;
// first pass to calculate height of text to be set
+ const v2u32 &window_size = RenderingEngine::get_instance()->getWindowSize();
s32 width = std::min(g_fontengine->getTextWidth(recent_chat.c_str()) + 10,
- porting::getWindowSize().X - 20);
- core::rect<s32> rect(10, chat_y, width, chat_y + porting::getWindowSize().Y);
+ window_size.X - 20);
+ core::rect<s32> rect(10, chat_y, width, chat_y + window_size.Y);
guitext_chat->setRelativePosition(rect);
//now use real height of text and adjust rect according to this size
key[KeyType::SPECIAL1] = getKeySetting("keymap_special1");
key[KeyType::SNEAK] = getKeySetting("keymap_sneak");
- key[KeyType::AUTORUN] = getKeySetting("keymap_autorun");
+ key[KeyType::AUTOFORWARD] = getKeySetting("keymap_autoforward");
key[KeyType::DROP] = getKeySetting("keymap_drop");
key[KeyType::INVENTORY] = getKeySetting("keymap_inventory");
key[KeyType::FREEMOVE] = getKeySetting("keymap_freemove");
key[KeyType::FASTMOVE] = getKeySetting("keymap_fastmove");
key[KeyType::NOCLIP] = getKeySetting("keymap_noclip");
+ key[KeyType::HOTBAR_PREV] = getKeySetting("keymap_hotbar_previous");
+ key[KeyType::HOTBAR_NEXT] = getKeySetting("keymap_hotbar_next");
+ key[KeyType::MUTE] = getKeySetting("keymap_mute");
+ key[KeyType::INC_VOLUME] = getKeySetting("keymap_increase_volume");
+ key[KeyType::DEC_VOLUME] = getKeySetting("keymap_decrease_volume");
key[KeyType::CINEMATIC] = getKeySetting("keymap_cinematic");
key[KeyType::SCREENSHOT] = getKeySetting("keymap_screenshot");
key[KeyType::TOGGLE_HUD] = getKeySetting("keymap_toggle_hud");
key[KeyType::DEBUG_STACKS] = getKeySetting("keymap_print_debug_stacks");
+ for (int i = 0; i < 23; i++) {
+ std::string slot_key_name = "keymap_slot" + std::to_string(i + 1);
+ key[KeyType::SLOT_1 + i] = getKeySetting(slot_key_name.c_str());
+ }
+
if (handler) {
// First clear all keys, then re-add the ones we listen for
handler->dontListenForKeys();
- for (size_t i = 0; i < KeyType::INTERNAL_ENUM_COUNT; i++) {
- handler->listenForKey(key[i]);
+ for (const KeyPress &k : key) {
+ handler->listenForKey(k);
}
handler->listenForKey(EscapeKey);
handler->listenForKey(CancelKey);
- for (size_t i = 0; i < 10; i++) {
- handler->listenForKey(NumberKey[i]);
- }
}
}
PointedThing pointed_old;
bool digging;
bool ldown_for_dig;
+ bool dig_instantly;
+ bool digging_blocked;
bool left_punch;
bool update_wielded_item_trigger;
bool reset_jump_timer;
bool startup(bool *kill,
bool random_input,
InputHandler *input,
- IrrlichtDevice *device,
const std::string &map_dir,
const std::string &playername,
const std::string &password,
void toggleFast();
void toggleNoClip();
void toggleCinematic();
- void toggleAutorun();
+ void toggleAutoforward();
void toggleChat();
void toggleHud();
const core::line3d<f32> &shootline, bool liquids_pointable,
bool look_for_object, const v3s16 &camera_offset);
void handlePointingAtNothing(const ItemStack &playerItem);
- void handlePointingAtNode(const PointedThing &pointed, const ItemDefinition &playeritem_def,
- const ToolCapabilities &playeritem_toolcap, f32 dtime);
+ void handlePointingAtNode(const PointedThing &pointed,
+ const ItemDefinition &playeritem_def, const ItemStack &playeritem,
+ const ToolCapabilities &playeritem_toolcap, f32 dtime);
void handlePointingAtObject(const PointedThing &pointed, const ItemStack &playeritem,
const v3f &player_position, bool show_debug);
void handleDigging(const PointedThing &pointed, const v3s16 &nodepos,
// Misc
void limitFps(FpsControl *fps_timings, f32 *dtime);
- void showOverlayMessage(const wchar_t *msg, float dtime, int percent,
+ void showOverlayMessage(const char *msg, float dtime, int percent,
bool draw_clouds = true);
static void settingChangedCallback(const std::string &setting_name, void *data);
GameOnDemandSoundFetcher soundfetcher; // useful when testing
ISoundManager *sound;
- bool sound_is_dummy;
+ bool sound_is_dummy = false;
SoundMaker *soundmaker;
ChatBackend *chat_backend;
*/
gui::IGUIStaticText *guitext; // First line of debug text
gui::IGUIStaticText *guitext2; // Second line of debug text
+ gui::IGUIStaticText *guitext3; // Third line of debug text
gui::IGUIStaticText *guitext_info; // At the middle of the screen
gui::IGUIStaticText *guitext_status;
gui::IGUIStaticText *guitext_chat; // Chat text
f32 m_cache_cam_smoothing;
f32 m_cache_fog_start;
- bool m_invert_mouse;
- bool m_first_loop_after_window_activation;
- bool m_camera_offset_changed;
+ bool m_invert_mouse = false;
+ bool m_first_loop_after_window_activation = false;
+ bool m_camera_offset_changed = false;
#ifdef __ANDROID__
bool m_cache_hold_aux1;
itemdef_manager(NULL),
nodedef_manager(NULL),
sound(NULL),
- sound_is_dummy(false),
soundmaker(NULL),
chat_backend(NULL),
current_formspec(NULL),
sky(NULL),
local_inventory(NULL),
hud(NULL),
- mapper(NULL),
- m_invert_mouse(false),
- m_first_loop_after_window_activation(false),
- m_camera_offset_changed(false)
+ mapper(NULL)
{
g_settings->registerChangedCallback("doubletap_jump",
&settingChangedCallback, this);
bool Game::startup(bool *kill,
bool random_input,
InputHandler *input,
- IrrlichtDevice *device,
const std::string &map_dir,
const std::string &playername,
const std::string &password,
bool simple_singleplayer_mode)
{
// "cache"
- this->device = device;
+ this->device = RenderingEngine::get_raw_device();
this->kill = kill;
this->error_message = &error_message;
this->reconnect_requested = reconnect;
keycache.handler = input;
keycache.populate();
- driver = device->getVideoDriver();
- smgr = device->getSceneManager();
+ driver = device->getVideoDriver();
+ smgr = RenderingEngine::get_scene_manager();
- smgr->getParameters()->setAttribute(scene::OBJ_LOADER_IGNORE_MATERIAL_FILES, true);
+ RenderingEngine::get_scene_manager()->getParameters()->
+ setAttribute(scene::OBJ_LOADER_IGNORE_MATERIAL_FILES, true);
memset(&runData, 0, sizeof(runData));
runData.time_from_last_punch = 10.0;
Profiler::GraphValues dummyvalues;
g_profiler->graphGet(dummyvalues);
- draw_times.last_time = device->getTimer()->getTime();
+ draw_times.last_time = RenderingEngine::get_timer_time();
set_light_table(g_settings->getFloat("display_gamma"));
&& client->checkPrivilege("fast");
#endif
- while (device->run()
+ irr::core::dimension2d<u32> previous_screen_size(g_settings->getU16("screen_w"),
+ g_settings->getU16("screen_h"));
+
+ while (RenderingEngine::run()
&& !(*kill || g_gamecallback->shutdown_requested
|| (server && server->getShutdownRequested()))) {
+ const irr::core::dimension2d<u32> ¤t_screen_size =
+ RenderingEngine::get_video_driver()->getScreenSize();
+ // Verify if window size has changed and save it if it's the case
+ // Ensure evaluating settings->getBool after verifying screensize
+ // First condition is cheaper
+ if (previous_screen_size != current_screen_size &&
+ current_screen_size != irr::core::dimension2d<u32>(0,0) &&
+ g_settings->getBool("autosave_screensize")) {
+ g_settings->setU16("screen_w", current_screen_size.Width);
+ g_settings->setU16("screen_h", current_screen_size.Height);
+ previous_screen_size = current_screen_size;
+ }
+
/* Must be called immediately after a device->run() call because it
* uses device->getTimer()->getTime()
*/
driver->setRenderTarget(irr::video::ERT_STEREO_BOTH_BUFFERS);
}
#endif
+ if (current_formspec)
+ current_formspec->quitMenu();
- showOverlayMessage(wgettext("Shutting down..."), 0, 0, false);
+ showOverlayMessage("Shutting down...", 0, 0, false);
if (clouds)
clouds->drop();
u16 port,
const SubgameSpec &gamespec)
{
- texture_src = createTextureSource(device);
+ texture_src = createTextureSource();
- showOverlayMessage(wgettext("Loading..."), 0, 0);
+ showOverlayMessage("Loading...", 0, 0);
- shader_src = createShaderSource(device);
+ shader_src = createShaderSource();
itemdef_manager = createItemDefManager();
nodedef_manager = createNodeDefManager();
return false;
// Create a server if not connecting to an existing one
- if (*address == "") {
+ if (address->empty()) {
if (!createSingleplayerServer(map_dir, gamespec, port, address))
return false;
}
bool Game::createSingleplayerServer(const std::string &map_dir,
const SubgameSpec &gamespec, u16 port, std::string *address)
{
- showOverlayMessage(wgettext("Creating server..."), 0, 5);
+ showOverlayMessage("Creating server...", 0, 5);
std::string bind_str = g_settings->get("bind_address");
Address bind_addr(0, 0, 0, 0, port);
bool Game::createClient(const std::string &playername,
const std::string &password, std::string *address, u16 port)
{
- showOverlayMessage(wgettext("Creating client..."), 0, 10);
+ showOverlayMessage("Creating client...", 0, 10);
draw_control = new MapDrawControl;
if (!draw_control)
shader_src->addShaderConstantSetterFactory(scsf);
// Update cached textures, meshes and materials
- client->afterContentReceived(device);
+ client->afterContentReceived();
/* Camera
*/
- camera = new Camera(smgr, *draw_control, client);
+ camera = new Camera(*draw_control, client);
if (!camera || !camera->successfullyCreated(*error_message))
return false;
client->setCamera(camera);
/* Clouds
*/
if (m_cache_enable_clouds) {
- clouds = new Clouds(smgr->getRootSceneNode(), smgr, -1, time(0));
+ clouds = new Clouds(smgr, -1, time(0));
if (!clouds) {
*error_message = "Memory allocation error (clouds)";
errorstream << *error_message << std::endl;
/* Skybox
*/
- sky = new Sky(smgr->getRootSceneNode(), smgr, -1, texture_src);
+ sky = new Sky(-1, texture_src);
scsf->setSky(sky);
skybox = NULL; // This is used/set later on in the main run loop
player->hurt_tilt_timer = 0;
player->hurt_tilt_strength = 0;
- hud = new Hud(driver, smgr, guienv, client, player, local_inventory);
+ hud = new Hud(guienv, client, player, local_inventory);
if (!hud) {
*error_message = "Memory error: could not create HUD";
}
mapper = client->getMinimap();
- mapper->setMinimapMode(MINIMAP_MODE_OFF);
+ if (mapper)
+ mapper->setMinimapMode(MINIMAP_MODE_OFF);
return true;
}
core::rect<s32>(0, 0, 0, 0),
false, false, guiroot);
+ // Third line of debug text
+ guitext3 = addStaticText(guienv,
+ L"",
+ core::rect<s32>(0, 0, 0, 0),
+ false, false, guiroot);
+
// At the middle of the screen
// Object infos are shown in this
guitext_info = addStaticText(guienv,
*aborted = false;
bool local_server_mode = false;
- showOverlayMessage(wgettext("Resolving address..."), 0, 15);
+ showOverlayMessage("Resolving address...", 0, 15);
Address connect_address(0, 0, 0, 0, port);
return false;
}
- client = new Client(device,
- playername.c_str(), password,
+ client = new Client(playername.c_str(), password, *address,
*draw_control, texture_src, shader_src,
itemdef_manager, nodedef_manager, sound, eventmgr,
connect_address.isIPv6(), &flags);
connect_address.print(&infostream);
infostream << std::endl;
- client->connect(connect_address, *address,
+ client->connect(connect_address,
simple_singleplayer_mode || local_server_mode);
/*
f32 dtime;
f32 wait_time = 0; // in seconds
- fps_control.last_time = device->getTimer()->getTime();
+ fps_control.last_time = RenderingEngine::get_timer_time();
+ client->loadMods();
client->initMods();
- while (device->run()) {
+ while (RenderingEngine::run()) {
limitFps(&fps_control, &dtime);
wait_time += dtime;
// Only time out if we aren't waiting for the server we started
- if ((*address != "") && (wait_time > 10)) {
+ if ((!address->empty()) && (wait_time > 10)) {
bool sent_old_init = g_settings->getFlag("send_pre_v25_init");
// If no pre v25 init was sent, and no answer was received,
// but the low level connection could be established
}
// Update status
- showOverlayMessage(wgettext("Connecting to server..."), dtime, 20);
+ showOverlayMessage("Connecting to server...", dtime, 20);
}
} catch (con::PeerNotFoundException &e) {
// TODO: Should something be done here? At least an info/error
FpsControl fps_control = { 0 };
f32 dtime; // in seconds
- fps_control.last_time = device->getTimer()->getTime();
+ fps_control.last_time = RenderingEngine::get_timer_time();
- while (device->run()) {
+ while (RenderingEngine::run()) {
limitFps(&fps_control, &dtime);
if (!client->itemdefReceived()) {
const wchar_t *text = wgettext("Item definitions...");
progress = 25;
- draw_load_screen(text, device, guienv, texture_src,
+ RenderingEngine::draw_load_screen(text, guienv, texture_src,
dtime, progress);
delete[] text;
} else if (!client->nodedefReceived()) {
const wchar_t *text = wgettext("Node definitions...");
progress = 30;
- draw_load_screen(text, device, guienv, texture_src,
+ RenderingEngine::draw_load_screen(text, guienv, texture_src,
dtime, progress);
delete[] text;
} else {
}
progress = 30 + client->mediaReceiveProgress() * 35 + 0.5;
- draw_load_screen(utf8_to_wide(message.str()), device,
- guienv, texture_src, dtime, progress);
+ RenderingEngine::draw_load_screen(utf8_to_wide(message.str()), guienv,
+ texture_src, dtime, progress);
}
}
void Game::processUserInput(f32 dtime)
{
// Reset input if window not active or some menu is active
- if (!device->isWindowActive() || !noMenuActive() || guienv->hasFocus(gui_chat_console)) {
+ if (!device->isWindowActive() || isMenuActive() || guienv->hasFocus(gui_chat_console)) {
input->clear();
#ifdef HAVE_TOUCHSCREENGUI
g_touchscreengui->hide();
{
if (wasKeyDown(KeyType::DROP)) {
dropSelectedItem();
- } else if (wasKeyDown(KeyType::AUTORUN)) {
- toggleAutorun();
+ } else if (wasKeyDown(KeyType::AUTOFORWARD)) {
+ toggleAutoforward();
} else if (wasKeyDown(KeyType::INVENTORY)) {
openInventory();
} else if (wasKeyDown(KeyType::ESC) || input->wasKeyDown(CancelKey)) {
toggleFast();
} else if (wasKeyDown(KeyType::NOCLIP)) {
toggleNoClip();
+ } else if (wasKeyDown(KeyType::MUTE)) {
+ float volume = g_settings->getFloat("sound_volume");
+ if (volume < 0.001f) {
+ g_settings->setFloat("sound_volume", 1.0f);
+ m_statustext = narrow_to_wide(gettext("Volume changed to 100%"));
+ } else {
+ g_settings->setFloat("sound_volume", 0.0f);
+ m_statustext = narrow_to_wide(gettext("Volume changed to 0%"));
+ }
+ runData.statustext_time = 0;
+ } else if (wasKeyDown(KeyType::INC_VOLUME)) {
+ float new_volume = rangelim(g_settings->getFloat("sound_volume") + 0.1f, 0.0f, 1.0f);
+ char buf[100];
+ g_settings->setFloat("sound_volume", new_volume);
+ snprintf(buf, sizeof(buf), gettext("Volume changed to %d%%"), myround(new_volume * 100));
+ m_statustext = narrow_to_wide(buf);
+ runData.statustext_time = 0;
+ } else if (wasKeyDown(KeyType::DEC_VOLUME)) {
+ float new_volume = rangelim(g_settings->getFloat("sound_volume") - 0.1f, 0.0f, 1.0f);
+ char buf[100];
+ g_settings->setFloat("sound_volume", new_volume);
+ snprintf(buf, sizeof(buf), gettext("Volume changed to %d%%"), myround(new_volume * 100));
+ m_statustext = narrow_to_wide(buf);
+ runData.statustext_time = 0;
} else if (wasKeyDown(KeyType::CINEMATIC)) {
toggleCinematic();
} else if (wasKeyDown(KeyType::SCREENSHOT)) {
- client->makeScreenshot(device);
+ client->makeScreenshot();
} else if (wasKeyDown(KeyType::TOGGLE_HUD)) {
toggleHud();
} else if (wasKeyDown(KeyType::MINIMAP)) {
s32 dir = wheel;
- if (input->joystick.wasKeyDown(KeyType::SCROLL_DOWN)) {
+ if (input->joystick.wasKeyDown(KeyType::SCROLL_DOWN) ||
+ wasKeyDown(KeyType::HOTBAR_NEXT)) {
dir = -1;
}
- if (input->joystick.wasKeyDown(KeyType::SCROLL_UP)) {
+ if (input->joystick.wasKeyDown(KeyType::SCROLL_UP) ||
+ wasKeyDown(KeyType::HOTBAR_PREV)) {
dir = 1;
}
*new_playeritem = *new_playeritem > 0 ? *new_playeritem - 1 : max_item;
// else dir == 0
- /* Item selection using keyboard
+ /* Item selection using hotbar slot keys
*/
- for (u16 i = 0; i < 10; i++) {
- static const KeyPress *item_keys[10] = {
- NumberKey + 1, NumberKey + 2, NumberKey + 3, NumberKey + 4,
- NumberKey + 5, NumberKey + 6, NumberKey + 7, NumberKey + 8,
- NumberKey + 9, NumberKey + 0,
- };
-
- if (input->wasKeyDown(*item_keys[i])) {
+ for (u16 i = 0; i < 23; i++) {
+ if (wasKeyDown((GameKeyType) (KeyType::SLOT_1 + i))) {
if (i < PLAYER_INVENTORY_SIZE && i < player->hud_hotbar_itemcount) {
*new_playeritem = i;
infostream << "Selected item: " << new_playeritem << std::endl;
*/
LocalPlayer *player = client->getEnv().getLocalPlayer();
- if (player == NULL || player->getCAO() == NULL)
+ if (!player || !player->getCAO())
return;
infostream << "the_game: " << "Launching inventory" << std::endl;
PlayerInventoryFormSource *fs_src = new PlayerInventoryFormSource(client);
TextDest *txt_dst = new TextDestPlayerInventory(client);
- create_formspec_menu(¤t_formspec, client, device, &input->joystick, fs_src, txt_dst);
+ create_formspec_menu(¤t_formspec, client, &input->joystick, fs_src, txt_dst);
cur_formname = "";
InventoryLocation inventoryloc;
m_statustext = msg[cinematic];
}
-// Add WoW-style autorun by toggling continuous forward.
-void Game::toggleAutorun()
+// Autoforward by toggling continuous forward.
+void Game::toggleAutoforward()
{
- static const wchar_t *msg[] = { L"autorun disabled", L"autorun enabled" };
- bool autorun_enabled = !g_settings->getBool("continuous_forward");
- g_settings->set("continuous_forward", bool_to_cstr(autorun_enabled));
+ static const wchar_t *msg[] = { L"autoforward disabled", L"autoforward enabled" };
+ bool autoforward_enabled = !g_settings->getBool("continuous_forward");
+ g_settings->set("continuous_forward", bool_to_cstr(autoforward_enabled));
runData.statustext_time = 0;
- m_statustext = msg[autorun_enabled ? 1 : 0];
+ m_statustext = msg[autoforward_enabled ? 1 : 0];
}
void Game::toggleChat()
void Game::toggleMinimap(bool shift_pressed)
{
- if (!flags.show_hud || !g_settings->getBool("enable_minimap"))
+ if (!mapper || !flags.show_hud || !g_settings->getBool("enable_minimap"))
return;
if (shift_pressed) {
if (hud_flags & HUD_FLAG_MINIMAP_VISIBLE) {
mode = mapper->getMinimapMode();
mode = (MinimapMode)((int)mode + 1);
+ // If radar is disabled and in, or switching to, radar mode
+ if (!(hud_flags & HUD_FLAG_MINIMAP_RADAR_VISIBLE) && mode > 3)
+ mode = MINIMAP_MODE_OFF;
}
flags.show_minimap = true;
void Game::toggleFullViewRange()
{
static const wchar_t *msg[] = {
- L"Disabled full viewing range",
- L"Enabled full viewing range"
+ L"Normal view range",
+ L"Infinite view range"
};
draw_control->range_all = !draw_control->range_all;
void Game::updateCameraDirection(CameraOrientation *cam, float dtime)
{
- if ((device->isWindowActive() && noMenuActive()) || random_input) {
+ if ((device->isWindowActive() && device->isWindowFocused()
+ && !isMenuActive()) || random_input) {
#ifndef __ANDROID__
if (!random_input) {
device->getCursorControl()->setVisible(true);
#endif
- if (!m_first_loop_after_window_activation)
- m_first_loop_after_window_activation = true;
+ m_first_loop_after_window_activation = true;
}
}
void Game::processClientEvents(CameraOrientation *cam)
{
- ClientEvent event = client->getClientEvent();
-
LocalPlayer *player = client->getEnv().getLocalPlayer();
- for ( ; event.type != CE_NONE; event = client->getClientEvent()) {
+ while (client->hasClientEvents()) {
+ ClientEvent event = client->getClientEvent();
switch (event.type) {
case CE_PLAYER_DAMAGE:
break;
case CE_SHOW_FORMSPEC:
- if (*(event.show_formspec.formspec) == "") {
- if (current_formspec && ( *(event.show_formspec.formname) == "" || *(event.show_formspec.formname) == cur_formname) ){
+ if (event.show_formspec.formspec->empty()) {
+ if (current_formspec && (event.show_formspec.formname->empty()
+ || *(event.show_formspec.formname) == cur_formname)) {
current_formspec->quitMenu();
}
} else {
TextDestPlayerInventory *txt_dst =
new TextDestPlayerInventory(client, *(event.show_formspec.formname));
- create_formspec_menu(¤t_formspec, client, device, &input->joystick,
+ create_formspec_menu(¤t_formspec, client, &input->joystick,
fs_src, txt_dst);
cur_formname = *(event.show_formspec.formname);
}
{
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,
+ create_formspec_menu(¤t_formspec, client, &input->joystick,
fs_src, txt_dst);
}
delete event.show_formspec.formspec;
case CE_SPAWN_PARTICLE:
case CE_ADD_PARTICLESPAWNER:
case CE_DELETE_PARTICLESPAWNER:
- client->getParticleManager()->handleParticleEvent(&event, client,
- smgr, player);
+ client->getParticleManager()->handleParticleEvent(&event, client, player);
break;
case CE_HUDADD:
{
HudElement *e = player->removeHud(event.hudrm.id);
- if (e != NULL)
- delete e;
+ delete e;
}
break;
case CE_SET_SKY:
sky->setVisible(false);
+ // Whether clouds are visible in front of a custom skybox
+ sky->setCloudsEnabled(event.set_sky.clouds);
if (skybox) {
skybox->remove();
// Handle according to type
if (*event.set_sky.type == "regular") {
sky->setVisible(true);
+ sky->setCloudsEnabled(true);
} else if (*event.set_sky.type == "skybox" &&
event.set_sky.params->size() == 6) {
sky->setFallbackBgColor(*event.set_sky.bgcolor);
- skybox = smgr->addSkyBoxSceneNode(
+ skybox = RenderingEngine::get_scene_manager()->addSkyBoxSceneNode(
texture_src->getTextureForMesh((*event.set_sky.params)[0]),
texture_src->getTextureForMesh((*event.set_sky.params)[1]),
texture_src->getTextureForMesh((*event.set_sky.params)[2]),
event.override_day_night_ratio.ratio_f * 1000);
break;
+ case CE_CLOUD_PARAMS:
+ if (clouds) {
+ clouds->setDensity(event.cloud_params.density);
+ clouds->setColorBright(video::SColor(event.cloud_params.color_bright));
+ clouds->setColorAmbient(video::SColor(event.cloud_params.color_ambient));
+ clouds->setHeight(event.cloud_params.height);
+ clouds->setThickness(event.cloud_params.thickness);
+ clouds->setSpeed(v2f(
+ event.cloud_params.speed_x,
+ event.cloud_params.speed_y));
+ }
+ break;
+
default:
// unknown or unhandled type
break;
GenericCAO *playercao = player->getCAO();
// If playercao not loaded, don't change camera
- if (playercao == NULL)
+ if (!playercao)
return;
camera->toggleCameraMode();
float tool_reload_ratio = runData.time_from_last_punch / full_punch_interval;
tool_reload_ratio = MYMIN(tool_reload_ratio, 1.0);
- camera->update(player, dtime, busy_time / 1000.0f, tool_reload_ratio,
- client->getEnv());
+ camera->update(player, dtime, busy_time / 1000.0f, tool_reload_ratio);
camera->step(dtime);
v3f camera_position = camera->getPosition();
v3f(0, 0, 0), // velocity
camera->getDirection(),
camera->getCameraNode()->getUpVector());
- sound->setListenerGain(g_settings->getFloat("sound_volume"));
+ // Check if volume is in the proper range, else fix it.
+ float old_volume = g_settings->getFloat("sound_volume");
+ float new_volume = rangelim(old_volume, 0.0f, 1.0f);
+ sound->setListenerGain(new_volume);
- // Update sound maker
- soundmaker->step(dtime);
+ if (old_volume != new_volume) {
+ g_settings->setFloat("sound_volume", new_volume);
+ }
LocalPlayer *player = client->getEnv().getLocalPlayer();
+ // Tell the sound maker whether to make footstep sounds
+ soundmaker->makes_footstep_sound = player->makes_footstep_sound;
+
+ // Update sound maker
+ if (player->makes_footstep_sound)
+ soundmaker->step(dtime);
+
ClientMap &map = client->getEnv().getClientMap();
MapNode n = map.getNodeNoEx(player->getFootstepNodePos());
soundmaker->m_player_step_sound = nodedef_manager->get(n).sound_footstep;
hud->updateSelectionMesh(camera_offset);
}
+ if (runData.digging_blocked && !isLeftPressed()) {
+ // allow digging again if button is not pressed
+ runData.digging_blocked = false;
+ }
+
/*
Stop digging when
- releasing left mouse button
client->setCrack(-1, v3s16(0, 0, 0));
runData.dig_time = 0.0;
}
+ } else if (runData.dig_instantly && getLeftReleased()) {
+ // Remove e.g. torches faster when clicking instead of holding LMB
+ runData.nodig_delay_timer = 0;
+ runData.dig_instantly = false;
}
if (!runData.digging && runData.ldown_for_dig && !isLeftPressed()) {
soundmaker->m_player_leftpunch_sound.name = "";
- if (isRightPressed())
+ // Prepare for repeating, unless we're not supposed to
+ if (isRightPressed() && !g_settings->getBool("safe_dig_and_place"))
runData.repeat_rightclick_timer += dtime;
else
runData.repeat_rightclick_timer = 0;
if (playeritem_def.usable && isLeftPressed()) {
- if (getLeftClicked())
+ if (getLeftClicked() && (!client->moddingEnabled()
+ || !client->getScript()->on_item_use(playeritem, pointed)))
client->interact(4, pointed);
} else if (pointed.type == POINTEDTHING_NODE) {
ToolCapabilities playeritem_toolcap =
playeritem.getToolCapabilities(itemdef_manager);
- if (playeritem.name.empty()) {
+ if (playeritem.name.empty() && hand_def.tool_capabilities != NULL) {
playeritem_toolcap = *hand_def.tool_capabilities;
}
- handlePointingAtNode(pointed, playeritem_def, playeritem_toolcap, dtime);
+ handlePointingAtNode(pointed, playeritem_def, playeritem,
+ playeritem_toolcap, dtime);
} else if (pointed.type == POINTEDTHING_OBJECT) {
handlePointingAtObject(pointed, playeritem, player_position, show_debug);
} else if (isLeftPressed()) {
std::vector<aabb3f> *selectionboxes = hud->getSelectionBoxes();
selectionboxes->clear();
hud->setSelectedFaceNormal(v3f(0.0, 0.0, 0.0));
- static const bool show_entity_selectionbox = g_settings->getBool(
+ static thread_local const bool show_entity_selectionbox = g_settings->getBool(
"show_entity_selectionbox");
- ClientMap &map = client->getEnv().getClientMap();
- INodeDefManager *nodedef=client->getNodeDefManager();
+ ClientEnvironment &env = client->getEnv();
+ ClientMap &map = env.getClientMap();
+ INodeDefManager *nodedef = map.getNodeDefManager();
runData.selected_object = NULL;
- PointedThing result=client->getEnv().getPointedThing(
- shootline, liquids_pointable, look_for_object);
+ RaycastState s(shootline, look_for_object, liquids_pointable);
+ PointedThing result;
+ env.continueRaycast(&s, &result);
if (result.type == POINTEDTHING_OBJECT) {
runData.selected_object = client->getEnv().getActiveObject(result.object_id);
- if (show_entity_selectionbox && runData.selected_object->doShowSelectionBox()) {
- aabb3f *selection_box = runData.selected_object->getSelectionBox();
-
- // Box should exist because object was
- // returned in the first place
-
- assert(selection_box);
-
+ aabb3f selection_box;
+ if (show_entity_selectionbox && runData.selected_object->doShowSelectionBox() &&
+ runData.selected_object->getSelectionBox(&selection_box)) {
v3f pos = runData.selected_object->getPosition();
- selectionboxes->push_back(aabb3f(
- selection_box->MinEdge, selection_box->MaxEdge));
- selectionboxes->push_back(
- aabb3f(selection_box->MinEdge, selection_box->MaxEdge));
+ selectionboxes->push_back(aabb3f(selection_box));
hud->setSelectionPos(pos, camera_offset);
}
} else if (result.type == POINTEDTHING_NODE) {
}
// Update selection mesh light level and vertex colors
- if (selectionboxes->size() > 0) {
+ if (!selectionboxes->empty()) {
v3f pf = hud->getSelectionPos();
v3s16 p = floatToInt(pf, BS);
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]);
+ for (const v3s16 &dir : g_6dirs) {
+ n = map.getNodeNoEx(p + dir);
node_light = getInteriorLight(n, -1, nodedef);
if (node_light > light_level)
light_level = node_light;
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));
+ 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);
}
-void Game::handlePointingAtNode(const PointedThing &pointed, const ItemDefinition &playeritem_def,
- const ToolCapabilities &playeritem_toolcap, f32 dtime)
+void Game::handlePointingAtNode(const PointedThing &pointed,
+ const ItemDefinition &playeritem_def, const ItemStack &playeritem,
+ const ToolCapabilities &playeritem_toolcap, f32 dtime)
{
v3s16 nodepos = pointed.node_undersurface;
v3s16 neighbourpos = pointed.node_abovesurface;
*/
ClientMap &map = client->getEnv().getClientMap();
+
+ if (runData.nodig_delay_timer <= 0.0 && isLeftPressed()
+ && !runData.digging_blocked
+ && client->checkPrivilege("interact")) {
+ handleDigging(pointed, nodepos, playeritem_toolcap, dtime);
+ }
+
+ // This should be done after digging handling
NodeMetadata *meta = map.getNodeMetadata(nodepos);
if (meta) {
}
}
- if (runData.nodig_delay_timer <= 0.0 && isLeftPressed()
- && client->checkPrivilege("interact")) {
- handleDigging(pointed, nodepos, playeritem_toolcap, dtime);
- }
-
if ((getRightClicked() ||
runData.repeat_rightclick_timer >= m_repeat_right_click_time) &&
client->checkPrivilege("interact")) {
runData.repeat_rightclick_timer = 0;
infostream << "Ground right-clicked" << std::endl;
- if (meta && meta->getString("formspec") != "" && !random_input
+ if (meta && !meta->getString("formspec").empty() && !random_input
&& !isKeyDown(KeyType::SNEAK)) {
+ // Report right click to server
+ if (nodedef_manager->get(map.getNodeNoEx(nodepos)).rightclickable) {
+ client->interact(3, pointed);
+ }
+
infostream << "Launching custom inventory view" << std::endl;
InventoryLocation inventoryloc;
TextDest *txt_dst = new TextDestNodeMetadata(nodepos, client);
create_formspec_menu(¤t_formspec, client,
- device, &input->joystick, fs_src, txt_dst);
+ &input->joystick, fs_src, txt_dst);
cur_formname = "";
current_formspec->setFormSpec(meta->getString("formspec"), inventoryloc);
// If the wielded item has node placement prediction,
// make that happen
bool placed = nodePlacementPrediction(*client,
- playeritem_def,
+ playeritem_def, playeritem,
nodepos, neighbourpos);
if (placed) {
// Read the sound
soundmaker->m_player_rightpunch_sound =
playeritem_def.sound_place;
+
+ if (client->moddingEnabled())
+ client->getScript()->on_placenode(pointed, playeritem_def);
} else {
soundmaker->m_player_rightpunch_sound =
SimpleSoundSpec();
- if (playeritem_def.node_placement_prediction == "" ||
+ if (playeritem_def.node_placement_prediction.empty() ||
nodedef_manager->get(map.getNodeNoEx(nodepos)).rightclickable) {
client->interact(3, pointed); // Report to server
} else {
utf8_to_wide(runData.selected_object->infoText()));
if (show_debug) {
- if (infotext != L"") {
+ if (!infotext.empty()) {
infotext += L"\n";
}
infotext += unescape_enriched(utf8_to_wide(
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;
- }
-
// NOTE: Similar piece of code exists on the server side for
// cheat detection.
// Get digging parameters
runData.dig_time_complete = params.time;
if (m_cache_enable_particles) {
- const ContentFeatures &features =
- client->getNodeDefManager()->get(n);
- client->getParticleManager()->addPunchingParticles(client, smgr,
+ const ContentFeatures &features = client->getNodeDefManager()->get(n);
+ client->getParticleManager()->addPunchingParticles(client,
player, nodepos, n, features);
}
}
- if (runData.dig_time_complete >= 0.001) {
+ if (!runData.digging) {
+ infostream << "Started digging" << std::endl;
+ runData.dig_instantly = runData.dig_time_complete == 0;
+ if (client->moddingEnabled() && client->getScript()->on_punchnode(nodepos, n))
+ return;
+ client->interact(0, pointed);
+ runData.digging = true;
+ runData.ldown_for_dig = true;
+ }
+
+ if (!runData.dig_instantly) {
runData.dig_index = (float)crack_animation_length
* runData.dig_time
/ runData.dig_time_complete;
} else {
- // This is for torches
+ // This is for e.g. torches
runData.dig_index = crack_animation_length;
}
if (sound_dig.exists() && params.diggable) {
if (sound_dig.name == "__group") {
- if (params.main_group != "") {
+ if (!params.main_group.empty()) {
soundmaker->m_player_leftpunch_sound.gain = 0.5;
soundmaker->m_player_leftpunch_sound.name =
std::string("default_dig_") +
runData.dig_time = 0;
runData.digging = false;
+ // we successfully dug, now block it from repeating if we want to be safe
+ if (g_settings->getBool("safe_dig_and_place"))
+ runData.digging_blocked = true;
runData.nodig_delay_timer =
runData.dig_time_complete / (float)crack_animation_length;
- // We don't want a corresponding delay to
- // very time consuming nodes
+ // We don't want a corresponding delay to very time consuming nodes
+ // and nodes without digging time (e.g. torches) get a fixed delay.
if (runData.nodig_delay_timer > 0.3)
runData.nodig_delay_timer = 0.3;
+ else if (runData.dig_instantly)
+ runData.nodig_delay_timer = 0.15;
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;
- }
+ if (client->moddingEnabled() &&
+ client->getScript()->on_dignode(nodepos, wasnode)) {
+ return;
}
client->removeNode(nodepos);
}
if (m_cache_enable_particles) {
const ContentFeatures &features =
client->getNodeDefManager()->get(wasnode);
- client->getParticleManager()->addDiggingParticles(client, smgr,
+ client->getParticleManager()->addDiggingParticles(client,
player, nodepos, wasnode, features);
}
Update clouds
*/
if (clouds) {
- v3f player_position = player->getPosition();
if (sky->getCloudsVisible()) {
clouds->setVisible(true);
clouds->step(dtime);
- clouds->update(v2f(player_position.X, player_position.Z),
- sky->getCloudColor());
+ // camera->getPosition is not enough for 3rd person views
+ v3f camera_node_position = camera->getCameraNode()->getPosition();
+ v3s16 camera_offset = camera->getOffset();
+ camera_node_position.X = camera_node_position.X + camera_offset.X * BS;
+ camera_node_position.Y = camera_node_position.Y + camera_offset.Y * BS;
+ camera_node_position.Z = camera_node_position.Z + camera_offset.Z * BS;
+ clouds->update(camera_node_position,
+ sky->getCloudColor());
+ if (clouds->isCameraInsideCloud() && m_cache_enable_fog &&
+ !flags.force_fog_off) {
+ // if inside clouds, and fog enabled, use that as sky
+ // color(s)
+ video::SColor clouds_dark = clouds->getColor()
+ .getInterpolated(video::SColor(255, 0, 0, 0), 0.9);
+ sky->overrideColors(clouds_dark, clouds->getColor());
+ sky->setBodiesVisible(false);
+ runData.fog_range = std::fmin(runData.fog_range * 0.5f, 32.0f * BS);
+ // do not draw clouds after all
+ clouds->setVisible(false);
+ }
} else {
clouds->setVisible(false);
}
|| runData.update_draw_list_last_cam_dir.getDistanceFrom(camera_direction) > 0.2
|| m_camera_offset_changed) {
runData.update_draw_list_timer = 0;
- client->getEnv().getClientMap().updateDrawList(driver);
+ client->getEnv().getClientMap().updateDrawList();
runData.update_draw_list_last_cam_dir = camera_direction;
}
if (current_formspec->getReferenceCount() == 1) {
current_formspec->drop();
current_formspec = NULL;
- } else if (!noMenuActive()) {
+ } else if (isMenuActive()) {
guiroot->bringToFront(current_formspec);
}
}
/*
Drawing begins
*/
-
const video::SColor &skycolor = sky->getSkyColor();
TimeTaker tt_draw("mainloop: draw");
driver->beginScene(true, true, skycolor);
- draw_scene(driver, smgr, *camera, *client, player, *hud, *mapper,
+ RenderingEngine::draw_scene(camera, client, player, hud, mapper,
guienv, screensize, skycolor, flags.show_hud,
flags.show_minimap);
/*
Update minimap pos and rotation
*/
- if (flags.show_minimap && flags.show_hud) {
+ if (mapper && flags.show_minimap && flags.show_hud) {
mapper->setPos(floatToInt(player->getPosition(), BS));
mapper->setAngle(player->getYaw());
}
if (flags.show_debug) {
static float drawtime_avg = 0;
drawtime_avg = drawtime_avg * 0.95 + stats.drawtime * 0.05;
-
u16 fps = 1.0 / stats.dtime_jitter.avg;
std::ostringstream os(std::ios_base::binary);
os << std::fixed
<< PROJECT_NAME_C " " << g_version_hash
- << " FPS = " << fps
- << " (R: range_all=" << draw_control->range_all << ")"
+ << ", FPS = " << fps
+ << ", range_all = " << draw_control->range_all
<< std::setprecision(0)
- << " drawtime = " << drawtime_avg
+ << ", drawtime = " << drawtime_avg << " ms"
<< std::setprecision(1)
<< ", dtime_jitter = "
<< (stats.dtime_jitter.max_fraction * 100.0) << " %"
<< std::setprecision(1)
- << ", v_range = " << draw_control->wanted_range
+ << ", view_range = " << draw_control->wanted_range
<< std::setprecision(3)
- << ", RTT = " << client->getRTT();
+ << ", RTT = " << client->getRTT() << " s";
setStaticText(guitext, utf8_to_wide(os.str()).c_str());
guitext->setVisible(true);
} else {
if (flags.show_debug) {
std::ostringstream os(std::ios_base::binary);
os << std::setprecision(1) << std::fixed
- << "(" << (player_position.X / BS)
+ << "pos = (" << (player_position.X / BS)
<< ", " << (player_position.Y / BS)
<< ", " << (player_position.Z / BS)
- << ") (yaw=" << (wrapDegrees_0_360(cam.camera_yaw))
+ << "), yaw = " << (wrapDegrees_0_360(cam.camera_yaw)) << "°"
<< " " << yawToDirectionString(cam.camera_yaw)
- << ") (seed = " << ((u64)client->getMapSeed())
- << ")";
-
- if (runData.pointed_old.type == POINTEDTHING_NODE) {
- ClientMap &map = client->getEnv().getClientMap();
- const INodeDefManager *nodedef = client->getNodeDefManager();
- MapNode n = map.getNodeNoEx(runData.pointed_old.node_undersurface);
- if (n.getContent() != CONTENT_IGNORE && nodedef->get(n).name != "unknown") {
- const ContentFeatures &features = nodedef->get(n);
- os << " (pointing_at = " << nodedef->get(n).name
- << " - " << features.tiledef[0].name.c_str()
- << ")";
- }
- }
-
+ << ", seed = " << ((u64)client->getMapSeed());
setStaticText(guitext2, utf8_to_wide(os.str()).c_str());
guitext2->setVisible(true);
+ } else {
+ guitext2->setVisible(false);
+ }
+ if (guitext2->isVisible()) {
core::rect<s32> rect(
5, 5 + g_fontengine->getTextHeight(),
screensize.X, 5 + g_fontengine->getTextHeight() * 2
);
guitext2->setRelativePosition(rect);
+ }
+
+ if (flags.show_debug && runData.pointed_old.type == POINTEDTHING_NODE) {
+ ClientMap &map = client->getEnv().getClientMap();
+ const INodeDefManager *nodedef = client->getNodeDefManager();
+ MapNode n = map.getNodeNoEx(runData.pointed_old.node_undersurface);
+
+ if (n.getContent() != CONTENT_IGNORE && nodedef->get(n).name != "unknown") {
+ std::ostringstream os(std::ios_base::binary);
+ os << "pointing_at = (" << nodedef->get(n).name
+ << ", param2 = " << (u64) n.getParam2()
+ << ")";
+ setStaticText(guitext3, utf8_to_wide(os.str()).c_str());
+ guitext3->setVisible(true);
+ } else {
+ guitext3->setVisible(false);
+ }
} else {
- guitext2->setVisible(false);
+ guitext3->setVisible(false);
+ }
+
+ if (guitext3->isVisible()) {
+ core::rect<s32> rect(
+ 5, 5 + g_fontengine->getTextHeight() * 2,
+ screensize.X, 5 + g_fontengine->getTextHeight() * 3
+ );
+ guitext3->setRelativePosition(rect);
}
setStaticText(guitext_info, infotext.c_str());
fps_timings->last_time = time;
}
-// Note: This will free (using delete[])! \p msg. If you want to use it later,
-// pass a copy of it to this function
-// Note: \p msg must be allocated using new (not malloc())
-void Game::showOverlayMessage(const wchar_t *msg, float dtime,
- int percent, bool draw_clouds)
+void Game::showOverlayMessage(const char *msg, float dtime, int percent, bool draw_clouds)
{
- draw_load_screen(msg, device, guienv, texture_src, dtime, percent,
+ const wchar_t *wmsg = wgettext(msg);
+ RenderingEngine::draw_load_screen(wmsg, guienv, texture_src, dtime, percent,
draw_clouds);
- delete[] msg;
+ delete[] wmsg;
}
void Game::settingChangedCallback(const std::string &setting_name, void *data)
// Extended resource accounting
infostream << "Irrlicht resources after cleanup:" << std::endl;
infostream << "\tRemaining meshes : "
- << device->getSceneManager()->getMeshCache()->getMeshCount() << std::endl;
+ << RenderingEngine::get_mesh_cache()->getMeshCount() << std::endl;
infostream << "\tRemaining textures : "
<< driver->getTextureCount() << std::endl;
<< " (note: irrlicht doesn't support removing renderers)" << std::endl;
}
+#define GET_KEY_NAME(KEY) gettext(getKeySetting(#KEY).name())
void Game::showPauseMenu()
{
#ifdef __ANDROID__
" --> place single item to slot\n"
);
#else
- static const std::string control_text = strgettext("Default Controls:\n"
- "- WASD: move\n"
- "- Space: jump/climb\n"
- "- Shift: sneak/go down\n"
- "- Q: drop item\n"
- "- I: inventory\n"
+ static const std::string control_text_template = strgettext("Controls:\n"
+ "- %s: move forwards\n"
+ "- %s: move backwards\n"
+ "- %s: move left\n"
+ "- %s: move right\n"
+ "- %s: jump/climb\n"
+ "- %s: sneak/go down\n"
+ "- %s: drop item\n"
+ "- %s: inventory\n"
"- Mouse: turn/look\n"
"- Mouse left: dig/punch\n"
"- Mouse right: place/use\n"
"- Mouse wheel: select item\n"
- "- T: chat\n"
+ "- %s: chat\n"
);
+
+ char control_text_buf[600];
+
+ snprintf(control_text_buf, ARRLEN(control_text_buf), control_text_template.c_str(),
+ GET_KEY_NAME(keymap_forward),
+ GET_KEY_NAME(keymap_backward),
+ GET_KEY_NAME(keymap_left),
+ GET_KEY_NAME(keymap_right),
+ GET_KEY_NAME(keymap_jump),
+ GET_KEY_NAME(keymap_sneak),
+ GET_KEY_NAME(keymap_drop),
+ GET_KEY_NAME(keymap_inventory),
+ GET_KEY_NAME(keymap_chat)
+ );
+
+ std::string control_text = std::string(control_text_buf);
+ str_formspec_escape(control_text);
#endif
- float ypos = simple_singleplayer_mode ? 0.5 : 0.1;
+ float ypos = simple_singleplayer_mode ? 0.7f : 0.1f;
std::ostringstream os;
os << FORMSPEC_VERSION_STRING << SIZE_TAG
if (!simple_singleplayer_mode) {
os << "button_exit[4," << (ypos++) << ";3,0.5;btn_change_password;"
<< strgettext("Change Password") << "]";
+ } else {
+ os << "field[4.95,0;5,1.5;;" << strgettext("Game paused") << ";]";
}
#ifndef __ANDROID__
os << "button_exit[4," << (ypos++) << ";3,0.5;btn_exit_os;"
<< strgettext("Exit to OS") << "]"
<< "textarea[7.5,0.25;3.9,6.25;;" << control_text << ";]"
- << "textarea[0.4,0.25;3.5,6;;" << PROJECT_NAME_C "\n"
- << g_build_info << "\n"
- << "path_user = " << wrap_rows(porting::path_user, 20)
- << "\n;]";
+ << "textarea[0.4,0.25;3.9,6.25;;" << PROJECT_NAME_C " " VERSION_STRING "\n"
+ << "\n"
+ << strgettext("Game info:") << "\n";
+ const std::string &address = client->getAddressName();
+ static const std::string mode = strgettext("- Mode: ");
+ if (!simple_singleplayer_mode) {
+ Address serverAddress = client->getServerAddress();
+ if (!address.empty()) {
+ os << mode << strgettext("Remote server") << "\n"
+ << strgettext("- Address: ") << address;
+ } else {
+ os << mode << strgettext("Hosting server");
+ }
+ os << "\n" << strgettext("- Port: ") << serverAddress.getPort() << "\n";
+ } else {
+ os << mode << strgettext("Singleplayer") << "\n";
+ }
+ if (simple_singleplayer_mode || address.empty()) {
+ static const std::string on = strgettext("On");
+ static const std::string off = strgettext("Off");
+ const std::string &damage = g_settings->getBool("enable_damage") ? on : off;
+ const std::string &creative = g_settings->getBool("creative_mode") ? on : off;
+ const std::string &announced = g_settings->getBool("server_announce") ? on : off;
+ os << strgettext("- Damage: ") << damage << "\n"
+ << strgettext("- Creative Mode: ") << creative << "\n";
+ if (!simple_singleplayer_mode) {
+ const std::string &pvp = g_settings->getBool("enable_pvp") ? on : off;
+ os << strgettext("- PvP: ") << pvp << "\n"
+ << strgettext("- Public: ") << announced << "\n";
+ std::string server_name = g_settings->get("server_name");
+ str_formspec_escape(server_name);
+ if (announced == on && !server_name.empty())
+ os << strgettext("- Server Name: ") << server_name;
+
+ }
+ }
+ os << ";]";
/* Create menu */
/* Note: FormspecFormSource and LocalFormspecHandler *
FormspecFormSource *fs_src = new FormspecFormSource(os.str());
LocalFormspecHandler *txt_dst = new LocalFormspecHandler("MT_PAUSE_MENU");
- create_formspec_menu(¤t_formspec, client, device, &input->joystick, fs_src, txt_dst);
+ create_formspec_menu(¤t_formspec, client, &input->joystick, fs_src, txt_dst);
current_formspec->setFocus("btn_continue");
current_formspec->doPause = true;
}
void the_game(bool *kill,
bool random_input,
InputHandler *input,
- IrrlichtDevice *device,
-
const std::string &map_dir,
const std::string &playername,
const std::string &password,
try {
- if (game.startup(kill, random_input, input, device, map_dir,
+ if (game.startup(kill, random_input, input, map_dir,
playername, password, &server_address, port, error_message,
reconnect_requested, &chat_backend, gamespec,
simple_singleplayer_mode)) {