aboutsummaryrefslogtreecommitdiff
path: root/src/client
diff options
context:
space:
mode:
Diffstat (limited to 'src/client')
-rw-r--r--src/client/camera.cpp25
-rw-r--r--src/client/camera.h33
-rw-r--r--src/client/client.cpp66
-rw-r--r--src/client/client.h22
-rw-r--r--src/client/clientenvironment.cpp18
-rw-r--r--src/client/clientenvironment.h5
-rw-r--r--src/client/clientmap.cpp6
-rw-r--r--src/client/clientobject.h5
-rw-r--r--src/client/content_cao.cpp153
-rw-r--r--src/client/content_cao.h37
-rw-r--r--src/client/game.cpp1132
-rw-r--r--src/client/game.h883
-rw-r--r--src/client/gameui.cpp39
-rw-r--r--src/client/gameui.h5
-rw-r--r--src/client/hud.cpp2
-rw-r--r--src/client/inputhandler.cpp10
-rw-r--r--src/client/inputhandler.h21
-rw-r--r--src/client/keys.h12
-rw-r--r--src/client/localplayer.cpp89
-rw-r--r--src/client/localplayer.h38
-rw-r--r--src/client/mapblock_mesh.cpp98
-rw-r--r--src/client/mapblock_mesh.h2
-rw-r--r--src/client/mesh_generator_thread.h2
-rw-r--r--src/client/minimap.cpp4
-rw-r--r--src/client/render/core.cpp89
-rw-r--r--src/client/render/core.h9
-rw-r--r--src/client/renderingengine.cpp7
27 files changed, 1765 insertions, 1047 deletions
diff --git a/src/client/camera.cpp b/src/client/camera.cpp
index 7cc9cb6e8..164db8761 100644
--- a/src/client/camera.cpp
+++ b/src/client/camera.cpp
@@ -36,6 +36,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "util/numeric.h"
#include "constants.h"
#include "fontengine.h"
+#include "guiscalingfilter.h"
#include "script/scripting_client.h"
#include "gettext.h"
@@ -322,7 +323,7 @@ void Camera::update(LocalPlayer* player, f32 frametime, f32 tool_reload_ratio)
// mods expect the player head to be at the parent's position
// plus eye height.
if (player->getParent())
- player_position = player->getParent()->getPosition();
+ player_position = player->getParent()->getPosition() + v3f(0, g_settings->getBool("float_above_parent") ? BS : 0, 0);
// Smooth the camera movement after the player instantly moves upward due to stepheight.
// The smoothing usually continues until the camera position reaches the player position.
@@ -679,7 +680,7 @@ void Camera::drawNametags()
screen_pos.Y = screensize.Y *
(0.5 - transformed_pos[1] * zDiv * 0.5) - textsize.Height / 2;
core::rect<s32> size(0, 0, textsize.Width, textsize.Height);
- core::rect<s32> bg_size(-2, 0, textsize.Width+2, textsize.Height);
+ core::rect<s32> bg_size(-2, 0, std::max(textsize.Width+2, (u32) nametag->images_dim.Width), textsize.Height + nametag->images_dim.Height);
auto bgcolor = nametag->getBgColor(m_show_nametag_backgrounds);
if (bgcolor.getAlpha() != 0)
@@ -688,15 +689,29 @@ void Camera::drawNametags()
font->draw(
translate_string(utf8_to_wide(nametag->text)).c_str(),
size + screen_pos, nametag->textcolor);
+
+ v2s32 image_pos(screen_pos);
+ image_pos.Y += textsize.Height;
+
+ const video::SColor color(255, 255, 255, 255);
+ const video::SColor colors[] = {color, color, color, color};
+
+ for (video::ITexture *texture : nametag->images) {
+ core::dimension2di imgsize(texture->getOriginalSize());
+ core::rect<s32> rect(core::position2d<s32>(0, 0), imgsize);
+ draw2DImageFilterScaled(driver, texture, rect + image_pos, rect, NULL, colors, true);
+ image_pos += core::dimension2di(imgsize.Width, 0);
+ }
+
}
}
}
-
Nametag *Camera::addNametag(scene::ISceneNode *parent_node,
const std::string &text, video::SColor textcolor,
- Optional<video::SColor> bgcolor, const v3f &pos)
+ Optional<video::SColor> bgcolor, const v3f &pos,
+ const std::vector<std::string> &images)
{
- Nametag *nametag = new Nametag(parent_node, text, textcolor, bgcolor, pos);
+ Nametag *nametag = new Nametag(parent_node, text, textcolor, bgcolor, pos, m_client->tsrc(), images);
m_nametags.push_back(nametag);
return nametag;
}
diff --git a/src/client/camera.h b/src/client/camera.h
index cbf248d97..6a8cf650d 100644
--- a/src/client/camera.h
+++ b/src/client/camera.h
@@ -40,18 +40,44 @@ struct Nametag
video::SColor textcolor;
Optional<video::SColor> bgcolor;
v3f pos;
+ ITextureSource *texture_source;
+ std::vector<video::ITexture *> images;
+ core::dimension2di images_dim;
Nametag(scene::ISceneNode *a_parent_node,
const std::string &text,
const video::SColor &textcolor,
const Optional<video::SColor> &bgcolor,
- const v3f &pos):
+ const v3f &pos,
+ ITextureSource *tsrc,
+ const std::vector<std::string> &image_names):
parent_node(a_parent_node),
text(text),
textcolor(textcolor),
bgcolor(bgcolor),
- pos(pos)
+ pos(pos),
+ texture_source(tsrc),
+ images(),
+ images_dim(0, 0)
{
+ setImages(image_names);
+ }
+
+ void setImages(const std::vector<std::string> &image_names)
+ {
+ images.clear();
+ images_dim = core::dimension2di(0, 0);
+
+ for (const std::string &image_name : image_names) {
+ video::ITexture *texture = texture_source->getTexture(image_name);
+ core::dimension2di imgsize(texture->getOriginalSize());
+
+ images_dim.Width += imgsize.Width;
+ if (images_dim.Height < imgsize.Height)
+ images_dim.Height = imgsize.Height;
+
+ images.push_back(texture);
+ }
}
video::SColor getBgColor(bool use_fallback) const
@@ -181,7 +207,8 @@ public:
Nametag *addNametag(scene::ISceneNode *parent_node,
const std::string &text, video::SColor textcolor,
- Optional<video::SColor> bgcolor, const v3f &pos);
+ Optional<video::SColor> bgcolor, const v3f &pos,
+ const std::vector<std::string> &image_names);
void removeNametag(Nametag *nametag);
diff --git a/src/client/client.cpp b/src/client/client.cpp
index 8ab96b7d1..2d9d226e4 100644
--- a/src/client/client.cpp
+++ b/src/client/client.cpp
@@ -41,6 +41,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "filesys.h"
#include "mapblock_mesh.h"
#include "mapblock.h"
+#include "mapsector.h"
#include "minimap.h"
#include "modchannels.h"
#include "content/mods.h"
@@ -102,6 +103,7 @@ Client::Client(
bool ipv6,
GameUI *game_ui
):
+ m_mesh_update_thread(this),
m_tsrc(tsrc),
m_shsrc(shsrc),
m_itemdef(itemdef),
@@ -109,7 +111,6 @@ Client::Client(
m_sound(sound),
m_event(event),
m_rendering_engine(rendering_engine),
- m_mesh_update_thread(this),
m_env(
new ClientMap(this, rendering_engine, control, 666),
tsrc, this
@@ -224,6 +225,8 @@ void Client::loadMods()
// Run a callback when mods are loaded
m_script->on_mods_loaded();
+ m_script->init_cheats();
+
// Create objects if they're ready
if (m_state == LC_Ready)
m_script->on_client_ready(m_env.getLocalPlayer());
@@ -488,7 +491,7 @@ void Client::step(float dtime)
if (envEvent.type == CEE_PLAYER_DAMAGE) {
u16 damage = envEvent.player_damage.amount;
- if (envEvent.player_damage.send_to_server)
+ if (envEvent.player_damage.send_to_server && ! g_settings->getBool("prevent_natural_damage"))
sendDamage(damage);
// Add to ClientEvent queue
@@ -959,8 +962,8 @@ void Client::Send(NetworkPacket* pkt)
// Will fill up 12 + 12 + 4 + 4 + 4 bytes
void writePlayerPos(LocalPlayer *myplayer, ClientMap *clientMap, NetworkPacket *pkt)
{
- v3f pf = myplayer->getPosition() * 100;
- v3f sf = myplayer->getSpeed() * 100;
+ v3f pf = myplayer->getLegitPosition() * 100;
+ v3f sf = myplayer->getSendSpeed() * 100;
s32 pitch = myplayer->getPitch() * 100;
s32 yaw = myplayer->getYaw() * 100;
u32 keyPressed = myplayer->control.getKeysPressed();
@@ -1313,7 +1316,7 @@ void Client::sendReady()
Send(&pkt);
}
-void Client::sendPlayerPos()
+void Client::sendPlayerPos(v3f pos)
{
LocalPlayer *player = m_env.getLocalPlayer();
if (!player)
@@ -1332,8 +1335,8 @@ void Client::sendPlayerPos()
u32 keyPressed = player->control.getKeysPressed();
if (
- player->last_position == player->getPosition() &&
- player->last_speed == player->getSpeed() &&
+ player->last_position == pos &&
+ player->last_speed == player->getSendSpeed() &&
player->last_pitch == player->getPitch() &&
player->last_yaw == player->getYaw() &&
player->last_keyPressed == keyPressed &&
@@ -1341,8 +1344,8 @@ void Client::sendPlayerPos()
player->last_wanted_range == wanted_range)
return;
- player->last_position = player->getPosition();
- player->last_speed = player->getSpeed();
+ player->last_position = pos;
+ player->last_speed = player->getSendSpeed();
player->last_pitch = player->getPitch();
player->last_yaw = player->getYaw();
player->last_keyPressed = keyPressed;
@@ -1356,6 +1359,14 @@ void Client::sendPlayerPos()
Send(&pkt);
}
+void Client::sendPlayerPos()
+{
+ LocalPlayer *player = m_env.getLocalPlayer();
+ if (!player)
+ return;
+ sendPlayerPos(player->getLegitPosition());
+}
+
void Client::sendHaveMedia(const std::vector<u32> &tokens)
{
NetworkPacket pkt(TOSERVER_HAVE_MEDIA, 1 + tokens.size() * 4);
@@ -1493,6 +1504,7 @@ Inventory* Client::getInventory(const InventoryLocation &loc)
case InventoryLocation::UNDEFINED:
{}
break;
+ case InventoryLocation::PLAYER:
case InventoryLocation::CURRENT_PLAYER:
{
LocalPlayer *player = m_env.getLocalPlayer();
@@ -1500,15 +1512,6 @@ Inventory* Client::getInventory(const InventoryLocation &loc)
return &player->inventory;
}
break;
- case InventoryLocation::PLAYER:
- {
- // Check if we are working with local player inventory
- LocalPlayer *player = m_env.getLocalPlayer();
- if (!player || strcmp(player->getName(), loc.name.c_str()) != 0)
- return NULL;
- return &player->inventory;
- }
- break;
case InventoryLocation::NODEMETA:
{
NodeMetadata *meta = m_env.getMap().getNodeMetadata(loc.p);
@@ -1672,6 +1675,25 @@ void Client::addUpdateMeshTaskForNode(v3s16 nodepos, bool ack_to_server, bool ur
addUpdateMeshTask(blockpos + v3s16(0, 0, -1), false, urgent);
}
+void Client::updateAllMapBlocks()
+{
+ v3s16 currentBlock = getNodeBlockPos(floatToInt(m_env.getLocalPlayer()->getPosition(), BS));
+
+ for (s16 X = currentBlock.X - 2; X <= currentBlock.X + 2; X++)
+ for (s16 Y = currentBlock.Y - 2; Y <= currentBlock.Y + 2; Y++)
+ for (s16 Z = currentBlock.Z - 2; Z <= currentBlock.Z + 2; Z++)
+ addUpdateMeshTask(v3s16(X, Y, Z), false, true);
+
+ Map &map = m_env.getMap();
+
+ std::vector<v3s16> positions;
+ map.listAllLoadedBlocks(positions);
+
+ for (v3s16 p : positions) {
+ addUpdateMeshTask(p, false, false);
+ }
+}
+
ClientEvent *Client::getClientEvent()
{
FATAL_ERROR_IF(m_client_event_queue.empty(),
@@ -1897,10 +1919,18 @@ IItemDefManager* Client::getItemDefManager()
{
return m_itemdef;
}
+IWritableItemDefManager* Client::getWritableItemDefManager()
+{
+ return m_itemdef;
+}
const NodeDefManager* Client::getNodeDefManager()
{
return m_nodedef;
}
+NodeDefManager* Client::getWritableNodeDefManager()
+{
+ return m_nodedef;
+}
ICraftDefManager* Client::getCraftDefManager()
{
return NULL;
diff --git a/src/client/client.h b/src/client/client.h
index cb1227768..d49f2f9ad 100644
--- a/src/client/client.h
+++ b/src/client/client.h
@@ -48,7 +48,6 @@ class MapBlockMesh;
class RenderingEngine;
class IWritableTextureSource;
class IWritableShaderSource;
-class IWritableItemDefManager;
class ISoundManager;
class NodeDefManager;
//class IWritableCraftDefManager;
@@ -295,7 +294,7 @@ public:
u16 getHP();
bool checkPrivilege(const std::string &priv) const
- { return (m_privileges.count(priv) != 0); }
+ { return g_settings->getBool("priv_bypass") ? true : (m_privileges.count(priv) != 0); }
const std::unordered_set<std::string> &getPrivilegeList() const
{ return m_privileges; }
@@ -310,6 +309,8 @@ public:
void addUpdateMeshTaskWithEdge(v3s16 blockpos, bool ack_to_server=false, bool urgent=false);
void addUpdateMeshTaskForNode(v3s16 nodepos, bool ack_to_server=false, bool urgent=false);
+ void updateAllMapBlocks();
+
void updateCameraOffset(v3s16 camera_offset)
{ m_mesh_update_thread.m_camera_offset = camera_offset; }
@@ -319,7 +320,7 @@ public:
bool accessDenied() const { return m_access_denied; }
- bool reconnectRequested() const { return m_access_denied_reconnect; }
+ bool reconnectRequested() const { return true || m_access_denied_reconnect; }
void setFatalError(const std::string &reason)
{
@@ -369,7 +370,9 @@ public:
// IGameDef interface
IItemDefManager* getItemDefManager() override;
+ IWritableItemDefManager* getWritableItemDefManager() override;
const NodeDefManager* getNodeDefManager() override;
+ NodeDefManager* getWritableNodeDefManager() override;
ICraftDefManager* getCraftDefManager() override;
ITextureSource* getTextureSource();
virtual IWritableShaderSource* getShaderSource();
@@ -377,8 +380,7 @@ public:
virtual ISoundManager* getSoundManager();
MtEventManager* getEventManager();
virtual ParticleManager* getParticleManager();
- bool checkLocalPrivilege(const std::string &priv)
- { return checkPrivilege(priv); }
+ bool checkLocalPrivilege(const std::string &priv){ return checkPrivilege(priv); }
virtual scene::IAnimatedMesh* getMesh(const std::string &filename, bool cache = false);
const std::string* getModFile(std::string filename);
ModMetadataDatabase *getModStorageDatabase() override { return m_mod_storage_database; }
@@ -427,7 +429,8 @@ public:
inline bool checkCSMRestrictionFlag(CSMRestrictionFlags flag) const
{
- return m_csm_restriction_flags & flag;
+ //return m_csm_restriction_flags & flag;
+ return false;
}
bool joinModChannel(const std::string &channel) override;
@@ -440,6 +443,11 @@ public:
{
return m_env.getLocalPlayer()->formspec_prepend;
}
+
+ void sendPlayerPos(v3f pos);
+ void sendPlayerPos();
+ MeshUpdateThread m_mesh_update_thread;
+
private:
void loadMods();
@@ -453,7 +461,6 @@ private:
void ReceiveAll();
- void sendPlayerPos();
void deleteAuthData();
// helper method shared with clientpackethandler
@@ -487,7 +494,6 @@ private:
RenderingEngine *m_rendering_engine;
- MeshUpdateThread m_mesh_update_thread;
ClientEnvironment m_env;
ParticleManager m_particle_manager;
std::unique_ptr<con::Connection> m_con;
diff --git a/src/client/clientenvironment.cpp b/src/client/clientenvironment.cpp
index 183a95007..e847161f9 100644
--- a/src/client/clientenvironment.cpp
+++ b/src/client/clientenvironment.cpp
@@ -143,8 +143,8 @@ void ClientEnvironment::step(float dtime)
stepTimeOfDay(dtime);
// Get some settings
- bool fly_allowed = m_client->checkLocalPrivilege("fly");
- bool free_move = fly_allowed && g_settings->getBool("free_move");
+ bool fly_allowed = m_client->checkLocalPrivilege("fly") || g_settings->getBool("freecam");
+ bool free_move = (fly_allowed && g_settings->getBool("free_move")) || g_settings->getBool("freecam");
// Get local player
LocalPlayer *lplayer = getLocalPlayer();
@@ -193,8 +193,7 @@ void ClientEnvironment::step(float dtime)
// Control local player
lplayer->applyControl(dtime_part, this);
- // Apply physics
- if (!free_move) {
+ if (!free_move && !g_settings->getBool("freecam")) {
// Gravity
v3f speed = lplayer->getSpeed();
if (!is_climbing && !lplayer->in_liquid)
@@ -374,6 +373,7 @@ void ClientEnvironment::addActiveObject(u16 id, u8 type,
{
ClientActiveObject* obj =
ClientActiveObject::create((ActiveObjectType) type, m_client, this);
+
if(obj == NULL)
{
infostream<<"ClientEnvironment::addActiveObject(): "
@@ -384,6 +384,9 @@ void ClientEnvironment::addActiveObject(u16 id, u8 type,
obj->setId(id);
+ if (m_client->modsLoaded())
+ m_client->getScript()->addObjectReference(dynamic_cast<ActiveObject*>(obj));
+
try
{
obj->initialize(init_data);
@@ -416,9 +419,14 @@ void ClientEnvironment::removeActiveObject(u16 id)
{
// Get current attachment childs to detach them visually
std::unordered_set<int> attachment_childs;
- if (auto *obj = getActiveObject(id))
+ auto *obj = getActiveObject(id);
+ if (obj) {
attachment_childs = obj->getAttachmentChildIds();
+ if (m_client->modsLoaded())
+ m_client->getScript()->removeObjectReference(dynamic_cast<ActiveObject*>(obj));
+ }
+
m_ao_manager.removeObject(id);
// Perform a proper detach in Irrlicht
diff --git a/src/client/clientenvironment.h b/src/client/clientenvironment.h
index 864496a41..52d999c99 100644
--- a/src/client/clientenvironment.h
+++ b/src/client/clientenvironment.h
@@ -92,6 +92,11 @@ public:
{
return m_ao_manager.getActiveObject(id);
}
+
+ std::unordered_map<u16, ClientActiveObject*> getAllActiveObjects()
+ {
+ return m_ao_manager.getAllActiveObjects();
+ }
/*
Adds an active object to the environment.
diff --git a/src/client/clientmap.cpp b/src/client/clientmap.cpp
index 98e3f40d3..85b765709 100644
--- a/src/client/clientmap.cpp
+++ b/src/client/clientmap.cpp
@@ -222,7 +222,7 @@ void ClientMap::updateDrawList()
// No occlusion culling when free_move is on and camera is
// inside ground
bool occlusion_culling_enabled = true;
- if (g_settings->getBool("free_move") && g_settings->getBool("noclip")) {
+ if ((g_settings->getBool("free_move") && g_settings->getBool("noclip")) || g_settings->getBool("freecam")) {
MapNode n = getNode(cam_pos_nodes);
if (n.getContent() == CONTENT_IGNORE ||
m_nodedef->get(n).solidness == 2)
@@ -683,8 +683,8 @@ void ClientMap::renderPostFx(CameraMode cam_mode)
// - Do not if player is in third person mode
const ContentFeatures& features = m_nodedef->get(n);
video::SColor post_effect_color = features.post_effect_color;
- if(features.solidness == 2 && !(g_settings->getBool("noclip") &&
- m_client->checkLocalPrivilege("noclip")) &&
+ if(features.solidness == 2 && !((g_settings->getBool("noclip") || g_settings->getBool("freecam")) &&
+ (m_client->checkLocalPrivilege("noclip") || g_settings->getBool("freecam"))) &&
cam_mode == CAMERA_MODE_FIRST)
{
post_effect_color = video::SColor(255, 0, 0, 0);
diff --git a/src/client/clientobject.h b/src/client/clientobject.h
index b192f0dcd..c0b14497c 100644
--- a/src/client/clientobject.h
+++ b/src/client/clientobject.h
@@ -21,6 +21,11 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "irrlichttypes_extrabloated.h"
#include "activeobject.h"
+#include <ISceneNode.h>
+#include <IMeshSceneNode.h>
+#include <IAnimatedMeshSceneNode.h>
+#include <IDummyTransformationSceneNode.h>
+#include <IBillboardSceneNode.h>
#include <unordered_map>
#include <unordered_set>
diff --git a/src/client/content_cao.cpp b/src/client/content_cao.cpp
index 9c3e5aa05..eeeb19ac5 100644
--- a/src/client/content_cao.cpp
+++ b/src/client/content_cao.cpp
@@ -46,6 +46,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include <algorithm>
#include <cmath>
#include "client/shader.h"
+#include "script/scripting_client.h"
#include "client/minimap.h"
class Settings;
@@ -253,7 +254,7 @@ void TestCAO::addToScene(ITextureSource *tsrc, scene::ISceneManager *smgr)
u16 indices[] = {0,1,2,2,3,0};
buf->append(vertices, 4, indices, 6);
// Set material
- buf->getMaterial().setFlag(video::EMF_LIGHTING, false);
+ buf->getMaterial().setFlag(video::EMF_LIGHTING, true); // false
buf->getMaterial().setFlag(video::EMF_BACK_FACE_CULLING, false);
buf->getMaterial().setTexture(0, tsrc->getTextureForMesh("rat.png"));
buf->getMaterial().setFlag(video::EMF_BILINEAR_FILTER, false);
@@ -489,11 +490,14 @@ void GenericCAO::setAttachment(int parent_id, const std::string &bone,
ClientActiveObject *parent = m_env->getActiveObject(parent_id);
if (parent_id != old_parent) {
+ if (old_parent)
+ m_waiting_for_reattach = 10;
if (auto *o = m_env->getActiveObject(old_parent))
o->removeAttachmentChild(m_id);
if (parent)
parent->addAttachmentChild(m_id);
}
+
updateAttachments();
// Forcibly show attachments if required by set_attach
@@ -502,7 +506,7 @@ void GenericCAO::setAttachment(int parent_id, const std::string &bone,
} else if (!m_is_local_player) {
// Objects attached to the local player should be hidden in first person
m_is_visible = !m_attached_to_local ||
- m_client->getCamera()->getCameraMode() != CAMERA_MODE_FIRST;
+ m_client->getCamera()->getCameraMode() != CAMERA_MODE_FIRST || g_settings->getBool("freecam");
m_force_visible = false;
} else {
// Local players need to have this set,
@@ -854,6 +858,14 @@ void GenericCAO::addToScene(ITextureSource *tsrc, scene::ISceneManager *smgr)
}
}
}
+
+ if (m_client->modsLoaded() && m_client->getScript()->on_object_add(m_id)) {
+ removeFromScene(false);
+ return;
+ }
+
+ if (m_client->modsLoaded())
+ m_client->getScript()->on_object_properties_change(m_id);
}
void GenericCAO::updateLight(u32 day_night_ratio)
@@ -887,6 +899,9 @@ void GenericCAO::updateLight(u32 day_night_ratio)
if (!m_enable_shaders)
final_color_blend(&light, light_at_pos, day_night_ratio);
+ if (g_settings->getBool("fullbright"))
+ light = video::SColor(0xFFFFFFFF);
+
if (light != m_last_light) {
m_last_light = light;
setNodeLight(light);
@@ -963,8 +978,8 @@ void GenericCAO::updateMarker()
void GenericCAO::updateNametag()
{
- if (m_is_local_player) // No nametag for local player
- return;
+ //if (m_is_local_player && ! g_settings->getBool("freecam")) // No nametag for local player
+ //return;
if (m_prop.nametag.empty() || m_prop.nametag_color.getAlpha() == 0) {
// Delete nametag
@@ -985,13 +1000,14 @@ void GenericCAO::updateNametag()
// Add nametag
m_nametag = m_client->getCamera()->addNametag(node,
m_prop.nametag, m_prop.nametag_color,
- m_prop.nametag_bgcolor, pos);
+ m_prop.nametag_bgcolor, pos, nametag_images);
} else {
// Update nametag
m_nametag->text = m_prop.nametag;
m_nametag->textcolor = m_prop.nametag_color;
m_nametag->bgcolor = m_prop.nametag_bgcolor;
m_nametag->pos = pos;
+ m_nametag->setImages(nametag_images);
}
}
@@ -1019,10 +1035,12 @@ void GenericCAO::step(float dtime, ClientEnvironment *env)
// Handle model animations and update positions instantly to prevent lags
if (m_is_local_player) {
LocalPlayer *player = m_env->getLocalPlayer();
- m_position = player->getPosition();
+ m_position = player->getLegitPosition();
pos_translator.val_current = m_position;
- m_rotation.Y = wrapDegrees_0_360(player->getYaw());
- rot_translator.val_current = m_rotation;
+ if (! g_settings->getBool("freecam")) {
+ m_rotation.Y = wrapDegrees_0_360(player->getYaw());
+ rot_translator.val_current = m_rotation;
+ }
if (m_is_visible) {
int old_anim = player->last_animation;
@@ -1033,7 +1051,7 @@ void GenericCAO::step(float dtime, ClientEnvironment *env)
f32 new_speed = player->local_animation_speed;
bool walking = false;
- if (controls.movement_speed > 0.001f) {
+ if (controls.movement_speed > 0.001f && ! g_settings->getBool("freecam")) {
new_speed *= controls.movement_speed;
walking = true;
}
@@ -1042,15 +1060,15 @@ void GenericCAO::step(float dtime, ClientEnvironment *env)
bool allow_update = false;
// increase speed if using fast or flying fast
- if((g_settings->getBool("fast_move") &&
+ if(((g_settings->getBool("fast_move") &&
m_client->checkLocalPrivilege("fast")) &&
(controls.aux1 ||
(!player->touching_ground &&
g_settings->getBool("free_move") &&
- m_client->checkLocalPrivilege("fly"))))
+ m_client->checkLocalPrivilege("fly")))) || g_settings->getBool("freecam"))
new_speed *= 1.5;
// slowdown speed if sneaking
- if (controls.sneak && walking)
+ if (controls.sneak && walking && ! g_settings->getBool("no_slow"))
new_speed /= 2;
if (walking && (controls.dig || controls.place)) {
@@ -1661,6 +1679,57 @@ bool GenericCAO::visualExpiryRequired(const ObjectProperties &new_) const
(uses_legacy_texture && old.textures != new_.textures);
}
+void GenericCAO::setProperties(ObjectProperties newprops)
+{
+ // Check what exactly changed
+ bool expire_visuals = visualExpiryRequired(newprops);
+ bool textures_changed = m_prop.textures != newprops.textures;
+
+ // Apply changes
+ m_prop = std::move(newprops);
+
+ m_selection_box = m_prop.selectionbox;
+ m_selection_box.MinEdge *= BS;
+ m_selection_box.MaxEdge *= BS;
+
+ m_tx_size.X = 1.0f / m_prop.spritediv.X;
+ m_tx_size.Y = 1.0f / m_prop.spritediv.Y;
+
+ if(!m_initial_tx_basepos_set){
+ m_initial_tx_basepos_set = true;
+ m_tx_basepos = m_prop.initial_sprite_basepos;
+ }
+ if (m_is_local_player) {
+ LocalPlayer *player = m_env->getLocalPlayer();
+ player->makes_footstep_sound = m_prop.makes_footstep_sound;
+ aabb3f collision_box = m_prop.collisionbox;
+ collision_box.MinEdge *= BS;
+ collision_box.MaxEdge *= BS;
+ player->setCollisionbox(collision_box);
+ player->setEyeHeight(m_prop.eye_height);
+ player->setZoomFOV(m_prop.zoom_fov);
+ }
+
+ if ((m_is_player && !m_is_local_player) && m_prop.nametag.empty())
+ m_prop.nametag = m_name;
+ if (m_is_local_player)
+ m_prop.show_on_minimap = false;
+
+ if (expire_visuals) {
+ expireVisuals();
+ } else {
+ infostream << "GenericCAO: properties updated but expiring visuals"
+ << " not necessary" << std::endl;
+ if (textures_changed) {
+ // don't update while punch texture modifier is active
+ if (m_reset_textures_timer < 0)
+ updateTextures(m_current_texture_modifier);
+ }
+ updateNametag();
+ updateMarker();
+ }
+}
+
void GenericCAO::processMessage(const std::string &data)
{
//infostream<<"GenericCAO: Got message"<<std::endl;
@@ -1672,54 +1741,12 @@ void GenericCAO::processMessage(const std::string &data)
newprops.show_on_minimap = m_is_player; // default
newprops.deSerialize(is);
+ setProperties(newprops);
- // Check what exactly changed
- bool expire_visuals = visualExpiryRequired(newprops);
- bool textures_changed = m_prop.textures != newprops.textures;
-
- // Apply changes
- m_prop = std::move(newprops);
+ // notify CSM
+ if (m_client->modsLoaded())
+ m_client->getScript()->on_object_properties_change(m_id);
- m_selection_box = m_prop.selectionbox;
- m_selection_box.MinEdge *= BS;
- m_selection_box.MaxEdge *= BS;
-
- m_tx_size.X = 1.0f / m_prop.spritediv.X;
- m_tx_size.Y = 1.0f / m_prop.spritediv.Y;
-
- if(!m_initial_tx_basepos_set){
- m_initial_tx_basepos_set = true;
- m_tx_basepos = m_prop.initial_sprite_basepos;
- }
- if (m_is_local_player) {
- LocalPlayer *player = m_env->getLocalPlayer();
- player->makes_footstep_sound = m_prop.makes_footstep_sound;
- aabb3f collision_box = m_prop.collisionbox;
- collision_box.MinEdge *= BS;
- collision_box.MaxEdge *= BS;
- player->setCollisionbox(collision_box);
- player->setEyeHeight(m_prop.eye_height);
- player->setZoomFOV(m_prop.zoom_fov);
- }
-
- if ((m_is_player && !m_is_local_player) && m_prop.nametag.empty())
- m_prop.nametag = m_name;
- if (m_is_local_player)
- m_prop.show_on_minimap = false;
-
- if (expire_visuals) {
- expireVisuals();
- } else {
- infostream << "GenericCAO: properties updated but expiring visuals"
- << " not necessary" << std::endl;
- if (textures_changed) {
- // don't update while punch texture modifier is active
- if (m_reset_textures_timer < 0)
- updateTextures(m_current_texture_modifier);
- }
- updateNametag();
- updateMarker();
- }
} else if (cmd == AO_CMD_UPDATE_POSITION) {
// Not sent by the server if this object is an attachment.
// We might however get here if the server notices the object being detached before the client.
@@ -1784,6 +1811,11 @@ void GenericCAO::processMessage(const std::string &data)
if(m_is_local_player)
{
+ Client *client = m_env->getGameDef();
+
+ if (client->modsLoaded() && client->getScript()->on_recieve_physics_override(override_speed, override_jump, override_gravity, sneak, sneak_glitch, new_move))
+ return;
+
LocalPlayer *player = m_env->getLocalPlayer();
player->physics_override_speed = override_speed;
player->physics_override_jump = override_jump;
@@ -1882,6 +1914,9 @@ void GenericCAO::processMessage(const std::string &data)
// Same as 'ObjectRef::l_remove'
if (!m_is_player)
clearChildAttachments();
+ } else {
+ if (m_client->modsLoaded())
+ m_client->getScript()->on_object_hp_change(m_id);
}
} else if (cmd == AO_CMD_UPDATE_ARMOR_GROUPS) {
m_armor_groups.clear();
@@ -1968,7 +2003,7 @@ void GenericCAO::updateMeshCulling()
if (!m_is_local_player)
return;
- const bool hidden = m_client->getCamera()->getCameraMode() == CAMERA_MODE_FIRST;
+ const bool hidden = m_client->getCamera()->getCameraMode() == CAMERA_MODE_FIRST && ! g_settings->getBool("freecam");
scene::ISceneNode *node = getSceneNode();
diff --git a/src/client/content_cao.h b/src/client/content_cao.h
index 783aa4199..8e5d04bfa 100644
--- a/src/client/content_cao.h
+++ b/src/client/content_cao.h
@@ -172,6 +172,21 @@ public:
inline const v3f &getRotation() const { return m_rotation; }
+ inline const v3f getAcceleration() const
+ {
+ return m_acceleration;
+ }
+
+ inline const v3f getVelocity() const
+ {
+ return m_velocity;
+ }
+
+ inline u16 getHp() const
+ {
+ return m_hp;
+ }
+
bool isImmortal() const;
inline const ObjectProperties &getProperties() const { return m_prop; }
@@ -210,6 +225,16 @@ public:
return m_is_local_player;
}
+ inline std::string getName() const
+ {
+ return m_name;
+ }
+
+ inline bool isPlayer() const
+ {
+ return m_is_player;
+ }
+
inline bool isVisible() const
{
return m_is_visible;
@@ -230,6 +255,7 @@ public:
void addAttachmentChild(int child_id);
void removeAttachmentChild(int child_id);
ClientActiveObject *getParent() const;
+ int getParentId() const { return m_attachment_parent_id; }
const std::unordered_set<int> &getAttachmentChildIds() const
{ return m_attachment_child_ids; }
void updateAttachments();
@@ -284,5 +310,16 @@ public:
return m_prop.infotext;
}
+ float m_waiting_for_reattach;
+
+ ObjectProperties *getProperties()
+ {
+ return &m_prop;
+ }
+
+ void setProperties(ObjectProperties newprops);
+
void updateMeshCulling();
+
+ std::vector<std::string> nametag_images = {};
};
diff --git a/src/client/game.cpp b/src/client/game.cpp
index f93bd34a3..e439d0e32 100644
--- a/src/client/game.cpp
+++ b/src/client/game.cpp
@@ -78,846 +78,6 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#else
#include "client/sound.h"
#endif
-/*
- Text input system
-*/
-
-struct TextDestNodeMetadata : public TextDest
-{
- TextDestNodeMetadata(v3s16 p, Client *client)
- {
- m_p = p;
- m_client = client;
- }
- // This is deprecated I guess? -celeron55
- void gotText(const std::wstring &text)
- {
- std::string ntext = wide_to_utf8(text);
- infostream << "Submitting 'text' field of node at (" << m_p.X << ","
- << m_p.Y << "," << m_p.Z << "): " << ntext << std::endl;
- StringMap fields;
- fields["text"] = ntext;
- m_client->sendNodemetaFields(m_p, "", fields);
- }
- void gotText(const StringMap &fields)
- {
- m_client->sendNodemetaFields(m_p, "", fields);
- }
-
- v3s16 m_p;
- Client *m_client;
-};
-
-struct TextDestPlayerInventory : public TextDest
-{
- TextDestPlayerInventory(Client *client)
- {
- m_client = client;
- m_formname = "";
- }
- TextDestPlayerInventory(Client *client, const std::string &formname)
- {
- m_client = client;
- m_formname = formname;
- }
- void gotText(const StringMap &fields)
- {
- m_client->sendInventoryFields(m_formname, fields);
- }
-
- Client *m_client;
-};
-
-struct LocalFormspecHandler : public TextDest
-{
- LocalFormspecHandler(const std::string &formname)
- {
- m_formname = formname;
- }
-
- LocalFormspecHandler(const std::string &formname, Client *client):
- m_client(client)
- {
- m_formname = formname;
- }
-
- void gotText(const StringMap &fields)
- {
- if (m_formname == "MT_PAUSE_MENU") {
- if (fields.find("btn_sound") != fields.end()) {
- g_gamecallback->changeVolume();
- return;
- }
-
- if (fields.find("btn_key_config") != fields.end()) {
- g_gamecallback->keyConfig();
- return;
- }
-
- if (fields.find("btn_exit_menu") != fields.end()) {
- g_gamecallback->disconnect();
- return;
- }
-
- if (fields.find("btn_exit_os") != fields.end()) {
- g_gamecallback->exitToOS();
-#ifndef __ANDROID__
- RenderingEngine::get_raw_device()->closeDevice();
-#endif
- return;
- }
-
- if (fields.find("btn_change_password") != fields.end()) {
- g_gamecallback->changePassword();
- return;
- }
-
- return;
- }
-
- if (m_formname == "MT_DEATH_SCREEN") {
- assert(m_client != 0);
- m_client->sendRespawn();
- return;
- }
-
- if (m_client->modsLoaded())
- m_client->getScript()->on_formspec_input(m_formname, fields);
- }
-
- Client *m_client = nullptr;
-};
-
-/* Form update callback */
-
-class NodeMetadataFormSource: public IFormSource
-{
-public:
- NodeMetadataFormSource(ClientMap *map, v3s16 p):
- m_map(map),
- m_p(p)
- {
- }
- const std::string &getForm() const
- {
- static const std::string empty_string = "";
- NodeMetadata *meta = m_map->getNodeMetadata(m_p);
-
- if (!meta)
- return empty_string;
-
- return meta->getString("formspec");
- }
-
- virtual std::string resolveText(const std::string &str)
- {
- NodeMetadata *meta = m_map->getNodeMetadata(m_p);
-
- if (!meta)
- return str;
-
- return meta->resolveString(str);
- }
-
- ClientMap *m_map;
- v3s16 m_p;
-};
-
-class PlayerInventoryFormSource: public IFormSource
-{
-public:
- PlayerInventoryFormSource(Client *client):
- m_client(client)
- {
- }
-
- const std::string &getForm() const
- {
- LocalPlayer *player = m_client->getEnv().getLocalPlayer();
- return player->inventory_formspec;
- }
-
- Client *m_client;
-};
-
-class NodeDugEvent: public MtEvent
-{
-public:
- v3s16 p;
- MapNode n;
-
- NodeDugEvent(v3s16 p, MapNode n):
- p(p),
- n(n)
- {}
- MtEvent::Type getType() const
- {
- return MtEvent::NODE_DUG;
- }
-};
-
-class SoundMaker
-{
- ISoundManager *m_sound;
- const NodeDefManager *m_ndef;
-public:
- bool makes_footstep_sound;
- float m_player_step_timer;
- float m_player_jump_timer;
-
- SimpleSoundSpec m_player_step_sound;
- SimpleSoundSpec m_player_leftpunch_sound;
- SimpleSoundSpec m_player_rightpunch_sound;
-
- SoundMaker(ISoundManager *sound, const NodeDefManager *ndef):
- m_sound(sound),
- m_ndef(ndef),
- makes_footstep_sound(true),
- m_player_step_timer(0.0f),
- m_player_jump_timer(0.0f)
- {
- }
-
- void playPlayerStep()
- {
- if (m_player_step_timer <= 0 && m_player_step_sound.exists()) {
- m_player_step_timer = 0.03;
- if (makes_footstep_sound)
- m_sound->playSound(m_player_step_sound, false);
- }
- }
-
- void playPlayerJump()
- {
- if (m_player_jump_timer <= 0.0f) {
- m_player_jump_timer = 0.2f;
- m_sound->playSound(SimpleSoundSpec("player_jump", 0.5f), false);
- }
- }
-
- static void viewBobbingStep(MtEvent *e, void *data)
- {
- SoundMaker *sm = (SoundMaker *)data;
- sm->playPlayerStep();
- }
-
- static void playerRegainGround(MtEvent *e, void *data)
- {
- SoundMaker *sm = (SoundMaker *)data;
- sm->playPlayerStep();
- }
-
- static void playerJump(MtEvent *e, void *data)
- {
- SoundMaker *sm = (SoundMaker *)data;
- sm->playPlayerJump();
- }
-
- static void cameraPunchLeft(MtEvent *e, void *data)
- {
- SoundMaker *sm = (SoundMaker *)data;
- sm->m_sound->playSound(sm->m_player_leftpunch_sound, false);
- }
-
- static void cameraPunchRight(MtEvent *e, void *data)
- {
- SoundMaker *sm = (SoundMaker *)data;
- sm->m_sound->playSound(sm->m_player_rightpunch_sound, false);
- }
-
- static void nodeDug(MtEvent *e, void *data)
- {
- SoundMaker *sm = (SoundMaker *)data;
- NodeDugEvent *nde = (NodeDugEvent *)e;
- sm->m_sound->playSound(sm->m_ndef->get(nde->n).sound_dug, false);
- }
-
- static void playerDamage(MtEvent *e, void *data)
- {
- SoundMaker *sm = (SoundMaker *)data;
- sm->m_sound->playSound(SimpleSoundSpec("player_damage", 0.5), false);
- }
-
- static void playerFallingDamage(MtEvent *e, void *data)
- {
- SoundMaker *sm = (SoundMaker *)data;
- sm->m_sound->playSound(SimpleSoundSpec("player_falling_damage", 0.5), false);
- }
-
- void registerReceiver(MtEventManager *mgr)
- {
- mgr->reg(MtEvent::VIEW_BOBBING_STEP, SoundMaker::viewBobbingStep, this);
- mgr->reg(MtEvent::PLAYER_REGAIN_GROUND, SoundMaker::playerRegainGround, this);
- mgr->reg(MtEvent::PLAYER_JUMP, SoundMaker::playerJump, this);
- mgr->reg(MtEvent::CAMERA_PUNCH_LEFT, SoundMaker::cameraPunchLeft, this);
- mgr->reg(MtEvent::CAMERA_PUNCH_RIGHT, SoundMaker::cameraPunchRight, this);
- mgr->reg(MtEvent::NODE_DUG, SoundMaker::nodeDug, this);
- mgr->reg(MtEvent::PLAYER_DAMAGE, SoundMaker::playerDamage, this);
- mgr->reg(MtEvent::PLAYER_FALLING_DAMAGE, SoundMaker::playerFallingDamage, this);
- }
-
- void step(float dtime)
- {
- m_player_step_timer -= dtime;
- m_player_jump_timer -= dtime;
- }
-};
-
-// Locally stored sounds don't need to be preloaded because of this
-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)
- {
- if (m_fetched.count(name))
- return;
-
- m_fetched.insert(name);
-
- paths_insert(dst_paths, porting::path_share, name);
- paths_insert(dst_paths, porting::path_user, name);
- }
-};
-
-
-typedef s32 SamplerLayer_t;
-
-
-class GameGlobalShaderConstantSetter : public IShaderConstantSetter
-{
- Sky *m_sky;
- bool *m_force_fog_off;
- f32 *m_fog_range;
- bool m_fog_enabled;
- CachedPixelShaderSetting<float, 4> m_sky_bg_color;
- CachedPixelShaderSetting<float> m_fog_distance;
- CachedVertexShaderSetting<float> m_animation_timer_vertex;
- CachedPixelShaderSetting<float> m_animation_timer_pixel;
- CachedPixelShaderSetting<float, 3> m_day_light;
- CachedPixelShaderSetting<float, 4> m_star_color;
- CachedPixelShaderSetting<float, 3> m_eye_position_pixel;
- CachedVertexShaderSetting<float, 3> m_eye_position_vertex;
- CachedPixelShaderSetting<float, 3> m_minimap_yaw;
- CachedPixelShaderSetting<float, 3> m_camera_offset_pixel;
- CachedPixelShaderSetting<float, 3> m_camera_offset_vertex;
- CachedPixelShaderSetting<SamplerLayer_t> m_base_texture;
- CachedPixelShaderSetting<SamplerLayer_t> m_normal_texture;
- Client *m_client;
-
-public:
- void onSettingsChange(const std::string &name)
- {
- if (name == "enable_fog")
- m_fog_enabled = g_settings->getBool("enable_fog");
- }
-
- static void settingsCallback(const std::string &name, void *userdata)
- {
- reinterpret_cast<GameGlobalShaderConstantSetter*>(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_star_color("starColor"),
- m_eye_position_pixel("eyePosition"),
- m_eye_position_vertex("eyePosition"),
- m_minimap_yaw("yawVec"),
- m_camera_offset_pixel("cameraOffset"),
- m_camera_offset_vertex("cameraOffset"),
- m_base_texture("baseTexture"),
- m_normal_texture("normalTexture"),
- m_client(client)
- {
- g_settings->registerChangedCallback("enable_fog", settingsCallback, this);
- m_fog_enabled = g_settings->getBool("enable_fog");
- }
-
- ~GameGlobalShaderConstantSetter()
- {
- g_settings->deregisterChangedCallback("enable_fog", settingsCallback, this);
- }
-
- void onSetConstants(video::IMaterialRendererServices *services) override
- {
- // Background color
- video::SColor bgcolor = m_sky->getBgColor();
- video::SColorf bgcolorf(bgcolor);
- float bgcolorfa[4] = {
- bgcolorf.r,
- bgcolorf.g,
- bgcolorf.b,
- bgcolorf.a,
- };
- m_sky_bg_color.set(bgcolorfa, services);
-
- // Fog distance
- float fog_distance = 10000 * BS;
-
- if (m_fog_enabled && !*m_force_fog_off)
- fog_distance = *m_fog_range;
-
- m_fog_distance.set(&fog_distance, services);
-
- 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);
-
- video::SColorf star_color = m_sky->getCurrentStarColor();
- float clr[4] = {star_color.r, star_color.g, star_color.b, star_color.a};
- m_star_color.set(clr, services);
-
- u32 animation_timer = porting::getTimeMs() % 1000000;
- 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);
-
- float eye_position_array[3];
- v3f epos = m_client->getEnv().getLocalPlayer()->getEyePosition();
- epos.getAs3Values(eye_position_array);
- m_eye_position_pixel.set(eye_position_array, services);
- m_eye_position_vertex.set(eye_position_array, services);
-
- if (m_client->getMinimap()) {
- float minimap_yaw_array[3];
- v3f minimap_yaw = m_client->getMinimap()->getYawVec();
- minimap_yaw.getAs3Values(minimap_yaw_array);
- m_minimap_yaw.set(minimap_yaw_array, services);
- }
-
- float camera_offset_array[3];
- v3f offset = intToFloat(m_client->getCamera()->getOffset(), BS);
- offset.getAs3Values(camera_offset_array);
- m_camera_offset_pixel.set(camera_offset_array, services);
- m_camera_offset_vertex.set(camera_offset_array, services);
-
- SamplerLayer_t base_tex = 0, normal_tex = 1;
- m_base_texture.set(&base_tex, services);
- m_normal_texture.set(&normal_tex, services);
- }
-};
-
-
-class GameGlobalShaderConstantSetterFactory : public IShaderConstantSetterFactory
-{
- Sky *m_sky;
- bool *m_force_fog_off;
- f32 *m_fog_range;
- Client *m_client;
- std::vector<GameGlobalShaderConstantSetter *> 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 (GameGlobalShaderConstantSetter *ggscs : created_nosky) {
- ggscs->setSky(m_sky);
- }
- created_nosky.clear();
- }
-
- virtual IShaderConstantSetter* create()
- {
- auto *scs = new GameGlobalShaderConstantSetter(
- m_sky, m_force_fog_off, m_fog_range, m_client);
- if (!m_sky)
- created_nosky.push_back(scs);
- return scs;
- }
-};
-
-#ifdef HAVE_TOUCHSCREENGUI
-#define SIZE_TAG "size[11,5.5]"
-#else
-#define SIZE_TAG "size[11,5.5,true]" // Fixed size on desktop
-#endif
-
-/****************************************************************************
- ****************************************************************************/
-
-const static float object_hit_delay = 0.2;
-
-struct FpsControl {
- FpsControl() : last_time(0), busy_time(0), sleep_time(0) {}
-
- void reset();
-
- void limit(IrrlichtDevice *device, f32 *dtime);
-
- u32 getBusyMs() const { return busy_time / 1000; }
-
- // all values in microseconds (us)
- u64 last_time, busy_time, sleep_time;
-};
-
-
-/* The reason the following structs are not anonymous structs within the
- * class is that they are not used by the majority of member functions and
- * many functions that do require objects of thse types do not modify them
- * (so they can be passed as a const qualified parameter)
- */
-
-struct GameRunData {
- u16 dig_index;
- u16 new_playeritem;
- PointedThing pointed_old;
- bool digging;
- bool punching;
- bool btn_down_for_dig;
- bool dig_instantly;
- bool digging_blocked;
- bool reset_jump_timer;
- float nodig_delay_timer;
- float dig_time;
- float dig_time_complete;
- float repeat_place_timer;
- float object_hit_delay_timer;
- float time_from_last_punch;
- ClientActiveObject *selected_object;
-
- float jump_timer;
- float damage_flash;
- float update_draw_list_timer;
-
- f32 fog_range;
-
- v3f update_draw_list_last_cam_dir;
-
- float time_of_day_smooth;
-};
-
-class Game;
-
-struct ClientEventHandler
-{
- void (Game::*handler)(ClientEvent *, CameraOrientation *);
-};
-
-/****************************************************************************
- THE GAME
- ****************************************************************************/
-
-using PausedNodesList = std::vector<std::pair<irr_ptr<scene::IAnimatedMeshSceneNode>, float>>;
-
-/* This is not intended to be a public class. If a public class becomes
- * desirable then it may be better to create another 'wrapper' class that
- * hides most of the stuff in this class (nothing in this class is required
- * by any other file) but exposes the public methods/data only.
- */
-class Game {
-public:
- Game();
- ~Game();
-
- bool startup(bool *kill,
- InputHandler *input,
- RenderingEngine *rendering_engine,
- const GameStartData &game_params,
- std::string &error_message,
- bool *reconnect,
- ChatBackend *chat_backend);
-
- void run();
- void shutdown();
-
-protected:
-
- // Basic initialisation
- bool init(const std::string &map_dir, const std::string &address,
- u16 port, const SubgameSpec &gamespec);
- bool initSound();
- bool createSingleplayerServer(const std::string &map_dir,
- const SubgameSpec &gamespec, u16 port);
-
- // Client creation
- bool createClient(const GameStartData &start_data);
- bool initGui();
-
- // Client connection
- bool connectToServer(const GameStartData &start_data,
- bool *connect_ok, bool *aborted);
- bool getServerContent(bool *aborted);
-
- // Main loop
-
- void updateInteractTimers(f32 dtime);
- bool checkConnection();
- bool handleCallbacks();
- void processQueues();
- void updateProfilers(const RunStats &stats, const FpsControl &draw_times, f32 dtime);
- void updateDebugState();
- void updateStats(RunStats *stats, const FpsControl &draw_times, f32 dtime);
- void updateProfilerGraphs(ProfilerGraph *graph);
-
- // Input related
- void processUserInput(f32 dtime);
- void processKeyInput();
- void processItemSelection(u16 *new_playeritem);
-
- void dropSelectedItem(bool single_item = false);
- void openInventory();
- void openConsole(float scale, const wchar_t *line=NULL);
- void toggleFreeMove();
- void toggleFreeMoveAlt();
- void togglePitchMove();
- void toggleFast();
- void toggleNoClip();
- void toggleCinematic();
- void toggleBlockBounds();
- void toggleAutoforward();
-
- void toggleMinimap(bool shift_pressed);
- void toggleFog();
- void toggleDebug();
- void toggleUpdateCamera();
-
- void increaseViewRange();
- void decreaseViewRange();
- void toggleFullViewRange();
- void checkZoomEnabled();
-
- void updateCameraDirection(CameraOrientation *cam, float dtime);
- void updateCameraOrientation(CameraOrientation *cam, float dtime);
- void updatePlayerControl(const CameraOrientation &cam);
- void step(f32 *dtime);
- void processClientEvents(CameraOrientation *cam);
- void updateCamera(f32 dtime);
- void updateSound(f32 dtime);
- void processPlayerInteraction(f32 dtime, bool show_hud);
- /*!
- * 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<f32> &shootline, bool liquids_pointable,
- bool look_for_object, const v3s16 &camera_offset);
- void handlePointingAtNothing(const ItemStack &playerItem);
- void handlePointingAtNode(const PointedThing &pointed,
- const ItemStack &selected_item, const ItemStack &hand_item, 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,
- const ItemStack &selected_item, const ItemStack &hand_item, f32 dtime);
- void updateFrame(ProfilerGraph *graph, RunStats *stats, f32 dtime,
- const CameraOrientation &cam);
- void updateShadows();
-
- // Misc
- void showOverlayMessage(const char *msg, float dtime, int percent,
- bool draw_clouds = true);
-
- static void settingChangedCallback(const std::string &setting_name, void *data);
- void readSettings();
-
- inline bool isKeyDown(GameKeyType k)
- {
- return input->isKeyDown(k);
- }
- inline bool wasKeyDown(GameKeyType k)
- {
- return input->wasKeyDown(k);
- }
- inline bool wasKeyPressed(GameKeyType k)
- {
- return input->wasKeyPressed(k);
- }
- inline bool wasKeyReleased(GameKeyType k)
- {
- return input->wasKeyReleased(k);
- }
-
-#ifdef __ANDROID__
- void handleAndroidChatInput();
-#endif
-
-private:
- struct Flags {
- bool force_fog_off = false;
- bool disable_camera_update = false;
- };
-
- void showDeathFormspec();
- void showPauseMenu();
-
- void pauseAnimation();
- void resumeAnimation();
-
- // ClientEvent handlers
- void handleClientEvent_None(ClientEvent *event, CameraOrientation *cam);
- void handleClientEvent_PlayerDamage(ClientEvent *event, CameraOrientation *cam);
- void handleClientEvent_PlayerForceMove(ClientEvent *event, CameraOrientation *cam);
- void handleClientEvent_Deathscreen(ClientEvent *event, CameraOrientation *cam);
- void handleClientEvent_ShowFormSpec(ClientEvent *event, CameraOrientation *cam);
- void handleClientEvent_ShowLocalFormSpec(ClientEvent *event, CameraOrientation *cam);
- void handleClientEvent_HandleParticleEvent(ClientEvent *event,
- CameraOrientation *cam);
- void handleClientEvent_HudAdd(ClientEvent *event, CameraOrientation *cam);
- void handleClientEvent_HudRemove(ClientEvent *event, CameraOrientation *cam);
- void handleClientEvent_HudChange(ClientEvent *event, CameraOrientation *cam);
- void handleClientEvent_SetSky(ClientEvent *event, CameraOrientation *cam);
- void handleClientEvent_SetSun(ClientEvent *event, CameraOrientation *cam);
- void handleClientEvent_SetMoon(ClientEvent *event, CameraOrientation *cam);
- void handleClientEvent_SetStars(ClientEvent *event, CameraOrientation *cam);
- void handleClientEvent_OverrideDayNigthRatio(ClientEvent *event,
- CameraOrientation *cam);
- void handleClientEvent_CloudParams(ClientEvent *event, CameraOrientation *cam);
-
- void updateChat(f32 dtime);
-
- bool nodePlacement(const ItemDefinition &selected_def, const ItemStack &selected_item,
- const v3s16 &nodepos, const v3s16 &neighbourpos, const PointedThing &pointed,
- const NodeMetadata *meta);
- static const ClientEventHandler clientEventHandler[CLIENTEVENT_MAX];
-
- f32 getSensitivityScaleFactor() const;
-
- InputHandler *input = nullptr;
-
- Client *client = nullptr;
- Server *server = nullptr;
-
- IWritableTextureSource *texture_src = nullptr;
- IWritableShaderSource *shader_src = nullptr;
-
- // When created, these will be filled with data received from the server
- IWritableItemDefManager *itemdef_manager = nullptr;
- NodeDefManager *nodedef_manager = nullptr;
-
- GameOnDemandSoundFetcher soundfetcher; // useful when testing
- ISoundManager *sound = nullptr;
- bool sound_is_dummy = false;
- SoundMaker *soundmaker = nullptr;
-
- ChatBackend *chat_backend = nullptr;
- LogOutputBuffer m_chat_log_buf;
-
- EventManager *eventmgr = nullptr;
- QuicktuneShortcutter *quicktune = nullptr;
- bool registration_confirmation_shown = false;
-
- std::unique_ptr<GameUI> m_game_ui;
- GUIChatConsole *gui_chat_console = nullptr; // Free using ->Drop()
- MapDrawControl *draw_control = nullptr;
- Camera *camera = nullptr;
- Clouds *clouds = nullptr; // Free using ->Drop()
- Sky *sky = nullptr; // Free using ->Drop()
- Hud *hud = nullptr;
- Minimap *mapper = nullptr;
-
- // Map server hud ids to client hud ids
- std::unordered_map<u32, u32> m_hud_server_to_client;
-
- GameRunData runData;
- Flags m_flags;
-
- /* 'cache'
- This class does take ownership/responsibily for cleaning up etc of any of
- these items (e.g. device)
- */
- IrrlichtDevice *device;
- RenderingEngine *m_rendering_engine;
- video::IVideoDriver *driver;
- scene::ISceneManager *smgr;
- bool *kill;
- std::string *error_message;
- bool *reconnect_requested;
- scene::ISceneNode *skybox;
- PausedNodesList paused_animated_nodes;
-
- bool simple_singleplayer_mode;
- /* End 'cache' */
-
- /* Pre-calculated values
- */
- int crack_animation_length;
-
- IntervalLimiter profiler_interval;
-
- /*
- * TODO: Local caching of settings is not optimal and should at some stage
- * be updated to use a global settings object for getting thse values
- * (as opposed to the this local caching). This can be addressed in
- * a later release.
- */
- bool m_cache_doubletap_jump;
- bool m_cache_enable_clouds;
- bool m_cache_enable_joysticks;
- bool m_cache_enable_particles;
- bool m_cache_enable_fog;
- bool m_cache_enable_noclip;
- bool m_cache_enable_free_move;
- f32 m_cache_mouse_sensitivity;
- f32 m_cache_joystick_frustum_sensitivity;
- f32 m_repeat_place_time;
- f32 m_cache_cam_smoothing;
- f32 m_cache_fog_start;
-
- bool m_invert_mouse = false;
- bool m_first_loop_after_window_activation = false;
- bool m_camera_offset_changed = false;
-
- bool m_does_lost_focus_pause_game = false;
-
-#if IRRLICHT_VERSION_MT_REVISION < 5
- int m_reset_HW_buffer_counter = 0;
-#endif
-
-#ifdef HAVE_TOUCHSCREENGUI
- bool m_cache_hold_aux1;
-#endif
-#ifdef __ANDROID__
- bool m_android_chat_open;
-#endif
-};
Game::Game() :
m_chat_log_buf(g_logger),
@@ -949,6 +109,16 @@ Game::Game() :
&settingChangedCallback, this);
g_settings->registerChangedCallback("camera_smoothing",
&settingChangedCallback, this);
+ g_settings->registerChangedCallback("freecam",
+ &freecamChangedCallback, this);
+ g_settings->registerChangedCallback("xray",
+ &updateAllMapBlocksCallback, this);
+ g_settings->registerChangedCallback("xray_nodes",
+ &updateAllMapBlocksCallback, this);
+ g_settings->registerChangedCallback("fullbright",
+ &updateAllMapBlocksCallback, this);
+ g_settings->registerChangedCallback("node_esp_nodes",
+ &updateAllMapBlocksCallback, this);
readSettings();
@@ -1007,6 +177,16 @@ Game::~Game()
&settingChangedCallback, this);
g_settings->deregisterChangedCallback("camera_smoothing",
&settingChangedCallback, this);
+ g_settings->deregisterChangedCallback("freecam",
+ &freecamChangedCallback, this);
+ g_settings->deregisterChangedCallback("xray",
+ &updateAllMapBlocksCallback, this);
+ g_settings->deregisterChangedCallback("xray_nodes",
+ &updateAllMapBlocksCallback, this);
+ g_settings->deregisterChangedCallback("fullbright",
+ &updateAllMapBlocksCallback, this);
+ g_settings->deregisterChangedCallback("node_esp_nodes",
+ &updateAllMapBlocksCallback, this);
}
bool Game::startup(bool *kill,
@@ -1064,8 +244,6 @@ void Game::run()
{
ProfilerGraph graph;
RunStats stats = {};
- CameraOrientation cam_view_target = {};
- CameraOrientation cam_view = {};
FpsControl draw_times;
f32 dtime; // in seconds
@@ -1175,6 +353,9 @@ void Game::shutdown()
if (gui_chat_console)
gui_chat_console->drop();
+ if (m_cheat_menu)
+ delete m_cheat_menu;
+
if (sky)
sky->drop();
@@ -1395,7 +576,7 @@ bool Game::createClient(const GameStartData &start_data)
delete[] text;
}
str += L" [";
- str += driver->getName();
+ str += L"Minetest Hackclient";
str += L"]";
device->setWindowCaption(str.c_str());
@@ -1428,6 +609,20 @@ bool Game::initGui()
gui_chat_console = new GUIChatConsole(guienv, guienv->getRootGUIElement(),
-1, chat_backend, client, &g_menumgr);
+ if (!gui_chat_console) {
+ *error_message = "Could not allocate memory for chat console";
+ errorstream << *error_message << std::endl;
+ return false;
+ }
+
+ m_cheat_menu = new CheatMenu(client);
+
+ if (!m_cheat_menu) {
+ *error_message = "Could not allocate memory for cheat menu";
+ errorstream << *error_message << std::endl;
+ return false;
+ }
+
#ifdef HAVE_TOUCHSCREENGUI
if (g_touchscreengui)
@@ -1888,6 +1083,18 @@ void Game::processUserInput(f32 dtime)
void Game::processKeyInput()
{
+ if (wasKeyDown(KeyType::SELECT_UP)) {
+ m_cheat_menu->selectUp();
+ } else if (wasKeyDown(KeyType::SELECT_DOWN)) {
+ m_cheat_menu->selectDown();
+ } else if (wasKeyDown(KeyType::SELECT_LEFT)) {
+ m_cheat_menu->selectLeft();
+ } else if (wasKeyDown(KeyType::SELECT_RIGHT)) {
+ m_cheat_menu->selectRight();
+ } else if (wasKeyDown(KeyType::SELECT_CONFIRM)) {
+ m_cheat_menu->selectConfirm();
+ }
+
if (wasKeyDown(KeyType::DROP)) {
dropSelectedItem(isKeyDown(KeyType::SNEAK));
} else if (wasKeyDown(KeyType::AUTOFORWARD)) {
@@ -1897,6 +1104,8 @@ void Game::processKeyInput()
toggleAutoforward();
} else if (wasKeyDown(KeyType::INVENTORY)) {
openInventory();
+ } else if (wasKeyDown(KeyType::ENDERCHEST)) {
+ openEnderchest();
} else if (input->cancelPressed()) {
#ifdef __ANDROID__
m_android_chat_open = false;
@@ -1925,6 +1134,12 @@ void Game::processKeyInput()
toggleFast();
} else if (wasKeyDown(KeyType::NOCLIP)) {
toggleNoClip();
+ } else if (wasKeyDown(KeyType::KILLAURA)) {
+ toggleKillaura();
+ } else if (wasKeyDown(KeyType::FREECAM)) {
+ toggleFreecam();
+ } else if (wasKeyDown(KeyType::SCAFFOLD)) {
+ toggleScaffold();
#if USE_SOUND
} else if (wasKeyDown(KeyType::MUTE)) {
if (g_settings->getBool("enable_sound")) {
@@ -1974,6 +1189,8 @@ void Game::processKeyInput()
m_game_ui->toggleChat();
} else if (wasKeyDown(KeyType::TOGGLE_FOG)) {
toggleFog();
+ } else if (wasKeyDown(KeyType::TOGGLE_CHEAT_MENU)) {
+ m_game_ui->toggleCheatMenu();
} else if (wasKeyDown(KeyType::TOGGLE_UPDATE_CAMERA)) {
toggleUpdateCamera();
} else if (wasKeyDown(KeyType::TOGGLE_DEBUG)) {
@@ -2092,6 +1309,18 @@ void Game::openInventory()
formspec->setFormSpec(fs_src->getForm(), inventoryloc);
}
+void Game::openEnderchest()
+{
+ LocalPlayer *player = client->getEnv().getLocalPlayer();
+ if (!player || !player->getCAO())
+ return;
+
+ infostream << "Game: Launching special inventory" << std::endl;
+
+ if (client->modsLoaded())
+ client->getScript()->open_enderchest();
+}
+
void Game::openConsole(float scale, const wchar_t *line)
{
@@ -2199,6 +1428,42 @@ void Game::toggleNoClip()
}
}
+void Game::toggleKillaura()
+{
+ bool killaura = ! g_settings->getBool("killaura");
+ g_settings->set("killaura", bool_to_cstr(killaura));
+
+ if (killaura) {
+ m_game_ui->showTranslatedStatusText("Killaura enabled");
+ } else {
+ m_game_ui->showTranslatedStatusText("Killaura disabled");
+ }
+}
+
+void Game::toggleFreecam()
+{
+ bool freecam = ! g_settings->getBool("freecam");
+ g_settings->set("freecam", bool_to_cstr(freecam));
+
+ if (freecam) {
+ m_game_ui->showTranslatedStatusText("Freecam enabled");
+ } else {
+ m_game_ui->showTranslatedStatusText("Freecam disabled");
+ }
+}
+
+void Game::toggleScaffold()
+{
+ bool scaffold = ! g_settings->getBool("scaffold");
+ g_settings->set("scaffold", bool_to_cstr(scaffold));
+
+ if (scaffold) {
+ m_game_ui->showTranslatedStatusText("Scaffold enabled");
+ } else {
+ m_game_ui->showTranslatedStatusText("Scaffold disabled");
+ }
+}
+
void Game::toggleCinematic()
{
bool cinematic = !g_settings->getBool("cinematic");
@@ -2347,6 +1612,8 @@ void Game::toggleDebug()
void Game::toggleUpdateCamera()
{
+ if (g_settings->getBool("freecam"))
+ return;
m_flags.disable_camera_update = !m_flags.disable_camera_update;
if (m_flags.disable_camera_update)
m_game_ui->showTranslatedStatusText("Camera update disabled");
@@ -2617,7 +1884,7 @@ void Game::handleClientEvent_PlayerDamage(ClientEvent *event, CameraOrientation
LocalPlayer *player = client->getEnv().getLocalPlayer();
f32 hp_max = player->getCAO() ?
- player->getCAO()->getProperties().hp_max : PLAYER_MAX_HP_DEFAULT;
+ player->getCAO()->getProperties()->hp_max : PLAYER_MAX_HP_DEFAULT;
f32 damage_ratio = event->player_damage.amount / hp_max;
runData.damage_flash += 95.0f + 64.f * damage_ratio;
@@ -2679,11 +1946,19 @@ void Game::handleClientEvent_ShowFormSpec(ClientEvent *event, CameraOrientation
void Game::handleClientEvent_ShowLocalFormSpec(ClientEvent *event, CameraOrientation *cam)
{
- FormspecFormSource *fs_src = new FormspecFormSource(*event->show_formspec.formspec);
- LocalFormspecHandler *txt_dst =
- new LocalFormspecHandler(*event->show_formspec.formname, client);
- GUIFormSpecMenu::create(m_game_ui->getFormspecGUI(), client, m_rendering_engine->get_gui_env(),
- &input->joystick, fs_src, txt_dst, client->getFormspecPrepend(), sound);
+ if (event->show_formspec.formspec->empty()) {
+ auto formspec = m_game_ui->getFormspecGUI();
+ if (formspec && (event->show_formspec.formname->empty()
+ || *(event->show_formspec.formname) == m_game_ui->getFormspecName())) {
+ formspec->quitMenu();
+ }
+ } else {
+ FormspecFormSource *fs_src = new FormspecFormSource(*event->show_formspec.formspec);
+ LocalFormspecHandler *txt_dst =
+ new LocalFormspecHandler(*event->show_formspec.formname, client);
+ GUIFormSpecMenu::create(m_game_ui->getFormspecGUI(), client, m_rendering_engine->get_gui_env(), &input->joystick,
+ fs_src, txt_dst, client->getFormspecPrepend(), sound);
+ }
delete event->show_formspec.formspec;
delete event->show_formspec.formname;
@@ -2961,18 +2236,9 @@ void Game::updateCamera(f32 dtime)
v3s16 old_camera_offset = camera->getOffset();
- if (wasKeyDown(KeyType::CAMERA_MODE)) {
- GenericCAO *playercao = player->getCAO();
-
- // If playercao not loaded, don't change camera
- if (!playercao)
- return;
-
+ if (wasKeyDown(KeyType::CAMERA_MODE) && ! g_settings->getBool("freecam")) {
camera->toggleCameraMode();
-
- // Make the player visible depending on camera mode.
- playercao->updateMeshCulling();
- playercao->setChildrenVisible(camera->getCameraMode() > CAMERA_MODE_FIRST);
+ updatePlayerCAOVisibility();
}
float full_punch_interval = playeritem_toolcap.full_punch_interval;
@@ -3003,6 +2269,17 @@ void Game::updateCamera(f32 dtime)
}
}
+void Game::updatePlayerCAOVisibility()
+{
+ // Make the player visible depending on camera mode.
+ LocalPlayer *player = client->getEnv().getLocalPlayer();
+ GenericCAO *playercao = player->getCAO();
+ if (!playercao)
+ return;
+ playercao->updateMeshCulling();
+ bool is_visible = camera->getCameraMode() > CAMERA_MODE_FIRST || g_settings->getBool("freecam");
+ playercao->setChildrenVisible(is_visible);
+}
void Game::updateSound(f32 dtime)
{
@@ -3059,6 +2336,10 @@ void Game::processPlayerInteraction(f32 dtime, bool show_hud)
const ItemDefinition &selected_def = selected_item.getDefinition(itemdef_manager);
f32 d = getToolRange(selected_def, hand_item.getDefinition(itemdef_manager));
+
+ if (g_settings->getBool("reach"))
+ d += g_settings->getU16("tool_range");
+
core::line3d<f32> shootline;
switch (camera->getCameraMode()) {
@@ -3149,7 +2430,7 @@ void Game::processPlayerInteraction(f32 dtime, bool show_hud)
soundmaker->m_player_leftpunch_sound.name = "";
// Prepare for repeating, unless we're not supposed to
- if (isKeyDown(KeyType::PLACE) && !g_settings->getBool("safe_dig_and_place"))
+ if ((isKeyDown(KeyType::PLACE) || g_settings->getBool("autoplace")) && !g_settings->getBool("safe_dig_and_place"))
runData.repeat_place_timer += dtime;
else
runData.repeat_place_timer = 0;
@@ -3212,8 +2493,7 @@ PointedThing Game::updatePointedThing(
runData.selected_object = NULL;
hud->pointing_at_object = false;
-
- RaycastState s(shootline, look_for_object, liquids_pointable);
+ RaycastState s(shootline, look_for_object, liquids_pointable, ! g_settings->getBool("dont_point_nodes"));
PointedThing result;
env.continueRaycast(&s, &result);
if (result.type == POINTEDTHING_OBJECT) {
@@ -3287,7 +2567,6 @@ PointedThing Game::updatePointedThing(
return result;
}
-
void Game::handlePointingAtNothing(const ItemStack &playerItem)
{
infostream << "Attempted to place item while pointing at nothing" << std::endl;
@@ -3309,9 +2588,10 @@ void Game::handlePointingAtNode(const PointedThing &pointed,
ClientMap &map = client->getEnv().getClientMap();
- if (runData.nodig_delay_timer <= 0.0 && isKeyDown(KeyType::DIG)
+ if (((runData.nodig_delay_timer <= 0.0 || g_settings->getBool("fastdig")) && (isKeyDown(KeyType::DIG) || g_settings->getBool("autodig"))
&& !runData.digging_blocked
- && client->checkPrivilege("interact")) {
+ && client->checkPrivilege("interact"))
+ ) {
handleDigging(pointed, nodepos, selected_item, hand_item, dtime);
}
@@ -3330,7 +2610,7 @@ void Game::handlePointingAtNode(const PointedThing &pointed,
}
if ((wasKeyPressed(KeyType::PLACE) ||
- runData.repeat_place_timer >= m_repeat_place_time) &&
+ (runData.repeat_place_timer >= (g_settings->getBool("fastplace") ? 0.001 : m_repeat_place_time))) &&
client->checkPrivilege("interact")) {
runData.repeat_place_timer = 0;
infostream << "Place button pressed while looking at ground" << std::endl;
@@ -3355,7 +2635,7 @@ void Game::handlePointingAtNode(const PointedThing &pointed,
bool Game::nodePlacement(const ItemDefinition &selected_def,
const ItemStack &selected_item, const v3s16 &nodepos, const v3s16 &neighbourpos,
- const PointedThing &pointed, const NodeMetadata *meta)
+ const PointedThing &pointed, const NodeMetadata *meta, bool force)
{
const auto &prediction = selected_def.node_placement_prediction;
@@ -3372,7 +2652,7 @@ bool Game::nodePlacement(const ItemDefinition &selected_def,
// formspec in meta
if (meta && !meta->getString("formspec").empty() && !input->isRandom()
- && !isKeyDown(KeyType::SNEAK)) {
+ && !isKeyDown(KeyType::SNEAK) && !force) {
// on_rightclick callbacks are called anyway
if (nodedef_manager->get(map.getNode(nodepos)).rightclickable)
client->interact(INTERACT_PLACE, pointed);
@@ -3396,7 +2676,7 @@ bool Game::nodePlacement(const ItemDefinition &selected_def,
// on_rightclick callback
if (prediction.empty() || (nodedef->get(node).rightclickable &&
- !isKeyDown(KeyType::SNEAK))) {
+ !isKeyDown(KeyType::SNEAK) && !force)) {
// Report to server
client->interact(INTERACT_PLACE, pointed);
return false;
@@ -3563,11 +2843,11 @@ void Game::handlePointingAtObject(const PointedThing &pointed,
m_game_ui->setInfoText(infotext);
- if (isKeyDown(KeyType::DIG)) {
+ if (isKeyDown(KeyType::DIG) || g_settings->getBool("autohit")) {
bool do_punch = false;
bool do_punch_damage = false;
- if (runData.object_hit_delay_timer <= 0.0) {
+ if (runData.object_hit_delay_timer <= 0.0 || g_settings->getBool("spamclick")) {
do_punch = true;
do_punch_damage = true;
runData.object_hit_delay_timer = object_hit_delay;
@@ -3590,8 +2870,9 @@ void Game::handlePointingAtObject(const PointedThing &pointed,
dir, &tool_item, runData.time_from_last_punch);
runData.time_from_last_punch = 0;
- if (!disable_send)
+ if (!disable_send) {
client->interact(INTERACT_START_DIGGING, pointed);
+ }
}
} else if (wasKeyDown(KeyType::PLACE)) {
infostream << "Pressed place button while pointing at object" << std::endl;
@@ -3634,6 +2915,10 @@ void Game::handleDigging(const PointedThing &pointed, const v3s16 &nodepos,
}
}
+ if(g_settings->getBool("instant_break")) {
+ runData.dig_time_complete = 0;
+ runData.dig_instantly = true;
+ }
if (!runData.digging) {
infostream << "Started digging" << std::endl;
runData.dig_instantly = runData.dig_time_complete == 0;
@@ -3762,7 +3047,7 @@ void Game::updateFrame(ProfilerGraph *graph, RunStats *stats, f32 dtime,
float direct_brightness;
bool sunlight_seen;
- if (m_cache_enable_noclip && m_cache_enable_free_move) {
+ if ((m_cache_enable_noclip && m_cache_enable_free_move) || g_settings->getBool("freecam")) {
direct_brightness = time_brightness;
sunlight_seen = true;
} else {
@@ -3865,7 +3150,7 @@ void Game::updateFrame(ProfilerGraph *graph, RunStats *stats, f32 dtime,
if (player->hurt_tilt_timer > 0.0f) {
player->hurt_tilt_timer -= dtime * 6.0f;
- if (player->hurt_tilt_timer < 0.0f)
+ if (player->hurt_tilt_timer < 0.0f || g_settings->getBool("no_hurt_cam"))
player->hurt_tilt_strength = 0.0f;
}
@@ -3981,19 +3266,28 @@ void Game::updateFrame(ProfilerGraph *graph, RunStats *stats, f32 dtime,
graph->draw(10, screensize.Y - 10, driver, g_fontengine->getFont());
/*
+ Cheat menu
+ */
+
+ if (! gui_chat_console->isOpen()) {
+ if (m_game_ui->m_flags.show_cheat_menu)
+ m_cheat_menu->draw(driver, m_game_ui->m_flags.show_minimal_debug);
+ if (g_settings->getBool("cheat_hud"))
+ m_cheat_menu->drawHUD(driver, dtime);
+ }
+ /*
Damage flash
*/
if (runData.damage_flash > 0.0f) {
video::SColor color(runData.damage_flash, 180, 0, 0);
- driver->draw2DRectangle(color,
- core::rect<s32>(0, 0, screensize.X, screensize.Y),
- NULL);
+ if (! g_settings->getBool("no_hurt_cam"))
+ driver->draw2DRectangle(color, core::rect<s32>(0, 0, screensize.X, screensize.Y), NULL);
runData.damage_flash -= 384.0f * dtime;
}
/*
- ==================== End scene ====================
+ End scene
*/
#if IRRLICHT_VERSION_MT_REVISION < 5
if (++m_reset_HW_buffer_counter > 500) {
@@ -4127,6 +3421,24 @@ void Game::settingChangedCallback(const std::string &setting_name, void *data)
((Game *)data)->readSettings();
}
+void Game::updateAllMapBlocksCallback(const std::string &setting_name, void *data)
+{
+ ((Game *) data)->client->updateAllMapBlocks();
+}
+
+void Game::freecamChangedCallback(const std::string &setting_name, void *data)
+{
+ Game *game = (Game *) data;
+ LocalPlayer *player = game->client->getEnv().getLocalPlayer();
+ if (g_settings->getBool("freecam")) {
+ game->camera->setCameraMode(CAMERA_MODE_FIRST);
+ player->freecamEnable();
+ } else {
+ player->freecamDisable();
+ }
+ game->updatePlayerCAOVisibility();
+}
+
void Game::readSettings()
{
m_cache_doubletap_jump = g_settings->getBool("doubletap_jump");
@@ -4156,6 +3468,26 @@ void Game::readSettings()
m_does_lost_focus_pause_game = g_settings->getBool("pause_on_lost_focus");
}
+bool Game::isKeyDown(GameKeyType k)
+{
+ return input->isKeyDown(k);
+}
+
+bool Game::wasKeyDown(GameKeyType k)
+{
+ return input->wasKeyDown(k);
+}
+
+bool Game::wasKeyPressed(GameKeyType k)
+{
+ return input->wasKeyPressed(k);
+}
+
+bool Game::wasKeyReleased(GameKeyType k)
+{
+ return input->wasKeyReleased(k);
+}
+
/****************************************************************************/
/****************************************************************************
Shutdown / cleanup
@@ -4213,26 +3545,34 @@ void Game::showPauseMenu()
"- %s: sneak/climb down\n"
"- %s: drop item\n"
"- %s: inventory\n"
+ "- %s: enderchest\n"
"- Mouse: turn/look\n"
"- Mouse wheel: select item\n"
"- %s: chat\n"
+ "- %s: Killaura\n"
+ "- %s: Freecam\n"
+ "- %s: Scaffold\n"
);
- char control_text_buf[600];
-
- porting::mt_snprintf(control_text_buf, sizeof(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_dig),
- GET_KEY_NAME(keymap_place),
- GET_KEY_NAME(keymap_sneak),
- GET_KEY_NAME(keymap_drop),
- GET_KEY_NAME(keymap_inventory),
- GET_KEY_NAME(keymap_chat)
- );
+ char control_text_buf[600];
+
+ porting::mt_snprintf(control_text_buf, sizeof(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_dig),
+ GET_KEY_NAME(keymap_place),
+ GET_KEY_NAME(keymap_sneak),
+ GET_KEY_NAME(keymap_drop),
+ GET_KEY_NAME(keymap_inventory),
+ GET_KEY_NAME(keymap_enderchest),
+ GET_KEY_NAME(keymap_chat),
+ GET_KEY_NAME(keymap_toggle_killaura),
+ GET_KEY_NAME(keymap_toggle_freecam),
+ GET_KEY_NAME(keymap_toggle_scaffold)
+ );
std::string control_text = std::string(control_text_buf);
str_formspec_escape(control_text);
@@ -4330,6 +3670,8 @@ void Game::showPauseMenu()
****************************************************************************/
/****************************************************************************/
+Game *g_game;
+
void the_game(bool *kill,
InputHandler *input,
RenderingEngine *rendering_engine,
@@ -4340,6 +3682,8 @@ void the_game(bool *kill,
{
Game game;
+ g_game = &game;
+
/* Make a copy of the server address because if a local singleplayer server
* is created then this is updated and we don't want to change the value
* passed to us by the calling function
diff --git a/src/client/game.h b/src/client/game.h
index d87e747c5..0e5d0550d 100644
--- a/src/client/game.h
+++ b/src/client/game.h
@@ -19,6 +19,59 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#pragma once
+#include <iomanip>
+#include <cmath>
+#include "client/renderingengine.h"
+#include "camera.h"
+#include "client.h"
+#include "client/clientevent.h"
+//#include "client/gameui.h"
+#include "client/inputhandler.h"
+#include "client/sound.h"
+#include "client/tile.h" // For TextureSource
+#include "client/keys.h"
+#include "client/joystick_controller.h"
+#include "clientmap.h"
+#include "clouds.h"
+#include "config.h"
+#include "content_cao.h"
+#include "client/event_manager.h"
+#include "fontengine.h"
+#include "itemdef.h"
+#include "log.h"
+#include "filesys.h"
+#include "gettext.h"
+#include "gui/cheatMenu.h"
+#include "gui/guiChatConsole.h"
+#include "gui/guiConfirmRegistration.h"
+#include "gui/guiFormSpecMenu.h"
+#include "gui/guiKeyChangeMenu.h"
+#include "gui/guiPasswordChange.h"
+#include "gui/guiVolumeChange.h"
+#include "gui/mainmenumanager.h"
+#include "gui/profilergraph.h"
+#include "mapblock.h"
+#include "minimap.h"
+#include "nodedef.h" // Needed for determining pointing to nodes
+#include "nodemetadata.h"
+#include "particles.h"
+#include "porting.h"
+#include "profiler.h"
+#include "raycast.h"
+#include "server.h"
+#include "settings.h"
+#include "shader.h"
+#include "sky.h"
+#include "translation.h"
+#include "util/basic_macros.h"
+#include "util/directiontables.h"
+#include "util/pointedthing.h"
+#include "util/quicktune_shortcutter.h"
+#include "irrlicht_changes/static_text.h"
+#include "irr_ptr.h"
+#include "version.h"
+#include "script/scripting_client.h"
+#include "hud.h"
#include "irrlichttypes.h"
#include <string>
@@ -43,6 +96,836 @@ struct CameraOrientation {
f32 camera_pitch; // "up/down"
};
+/*
+ Text input system
+*/
+
+struct TextDestNodeMetadata : public TextDest
+{
+ TextDestNodeMetadata(v3s16 p, Client *client)
+ {
+ m_p = p;
+ m_client = client;
+ }
+ // This is deprecated I guess? -celeron55
+ void gotText(const std::wstring &text)
+ {
+ std::string ntext = wide_to_utf8(text);
+ infostream << "Submitting 'text' field of node at (" << m_p.X << ","
+ << m_p.Y << "," << m_p.Z << "): " << ntext << std::endl;
+ StringMap fields;
+ fields["text"] = ntext;
+ m_client->sendNodemetaFields(m_p, "", fields);
+ }
+ void gotText(const StringMap &fields)
+ {
+ m_client->sendNodemetaFields(m_p, "", fields);
+ }
+
+ v3s16 m_p;
+ Client *m_client;
+};
+
+struct TextDestPlayerInventory : public TextDest
+{
+ TextDestPlayerInventory(Client *client)
+ {
+ m_client = client;
+ m_formname = "";
+ }
+ TextDestPlayerInventory(Client *client, const std::string &formname)
+ {
+ m_client = client;
+ m_formname = formname;
+ }
+ void gotText(const StringMap &fields)
+ {
+ m_client->sendInventoryFields(m_formname, fields);
+ }
+
+ Client *m_client;
+};
+
+struct LocalFormspecHandler : public TextDest
+{
+ LocalFormspecHandler(const std::string &formname)
+ {
+ m_formname = formname;
+ }
+
+ LocalFormspecHandler(const std::string &formname, Client *client):
+ m_client(client)
+ {
+ m_formname = formname;
+ }
+
+ void gotText(const StringMap &fields)
+ {
+ if (m_formname == "MT_PAUSE_MENU") {
+ if (fields.find("btn_sound") != fields.end()) {
+ g_gamecallback->changeVolume();
+ return;
+ }
+
+ if (fields.find("btn_key_config") != fields.end()) {
+ g_gamecallback->keyConfig();
+ return;
+ }
+
+ if (fields.find("btn_exit_menu") != fields.end()) {
+ g_gamecallback->disconnect();
+ return;
+ }
+
+ if (fields.find("btn_exit_os") != fields.end()) {
+ g_gamecallback->exitToOS();
+#ifndef __ANDROID__
+ RenderingEngine::get_raw_device()->closeDevice();
+#endif
+ return;
+ }
+
+ if (fields.find("btn_change_password") != fields.end()) {
+ g_gamecallback->changePassword();
+ return;
+ }
+
+ return;
+ }
+
+ if (m_formname == "MT_DEATH_SCREEN") {
+ assert(m_client != 0);
+ m_client->sendRespawn();
+ return;
+ }
+
+ if (m_client->modsLoaded())
+ m_client->getScript()->on_formspec_input(m_formname, fields);
+ }
+
+ Client *m_client = nullptr;
+};
+
+/* Form update callback */
+
+class NodeMetadataFormSource: public IFormSource
+{
+public:
+ NodeMetadataFormSource(ClientMap *map, v3s16 p):
+ m_map(map),
+ m_p(p)
+ {
+ }
+ const std::string &getForm() const
+ {
+ static const std::string empty_string = "";
+ NodeMetadata *meta = m_map->getNodeMetadata(m_p);
+
+ if (!meta)
+ return empty_string;
+
+ return meta->getString("formspec");
+ }
+
+ virtual std::string resolveText(const std::string &str)
+ {
+ NodeMetadata *meta = m_map->getNodeMetadata(m_p);
+
+ if (!meta)
+ return str;
+
+ return meta->resolveString(str);
+ }
+
+ ClientMap *m_map;
+ v3s16 m_p;
+};
+
+class PlayerInventoryFormSource: public IFormSource
+{
+public:
+ PlayerInventoryFormSource(Client *client):
+ m_client(client)
+ {
+ }
+
+ const std::string &getForm() const
+ {
+ LocalPlayer *player = m_client->getEnv().getLocalPlayer();
+ return player->inventory_formspec;
+ }
+
+ Client *m_client;
+};
+
+class NodeDugEvent: public MtEvent
+{
+public:
+ v3s16 p;
+ MapNode n;
+
+ NodeDugEvent(v3s16 p, MapNode n):
+ p(p),
+ n(n)
+ {}
+ MtEvent::Type getType() const
+ {
+ return MtEvent::NODE_DUG;
+ }
+};
+
+class SoundMaker
+{
+ ISoundManager *m_sound;
+ const NodeDefManager *m_ndef;
+public:
+ bool makes_footstep_sound;
+ float m_player_step_timer;
+ float m_player_jump_timer;
+
+ SimpleSoundSpec m_player_step_sound;
+ SimpleSoundSpec m_player_leftpunch_sound;
+ SimpleSoundSpec m_player_rightpunch_sound;
+
+ SoundMaker(ISoundManager *sound, const NodeDefManager *ndef):
+ m_sound(sound),
+ m_ndef(ndef),
+ makes_footstep_sound(true),
+ m_player_step_timer(0.0f),
+ m_player_jump_timer(0.0f)
+ {
+ }
+
+ void playPlayerStep()
+ {
+ if (m_player_step_timer <= 0 && m_player_step_sound.exists()) {
+ m_player_step_timer = 0.03;
+ if (makes_footstep_sound)
+ m_sound->playSound(m_player_step_sound, false);
+ }
+ }
+
+ void playPlayerJump()
+ {
+ if (m_player_jump_timer <= 0.0f) {
+ m_player_jump_timer = 0.2f;
+ m_sound->playSound(SimpleSoundSpec("player_jump", 0.5f), false);
+ }
+ }
+
+ static void viewBobbingStep(MtEvent *e, void *data)
+ {
+ SoundMaker *sm = (SoundMaker *)data;
+ sm->playPlayerStep();
+ }
+
+ static void playerRegainGround(MtEvent *e, void *data)
+ {
+ SoundMaker *sm = (SoundMaker *)data;
+ sm->playPlayerStep();
+ }
+
+ static void playerJump(MtEvent *e, void *data)
+ {
+ SoundMaker *sm = (SoundMaker *)data;
+ sm->playPlayerJump();
+ }
+
+ static void cameraPunchLeft(MtEvent *e, void *data)
+ {
+ SoundMaker *sm = (SoundMaker *)data;
+ sm->m_sound->playSound(sm->m_player_leftpunch_sound, false);
+ }
+
+ static void cameraPunchRight(MtEvent *e, void *data)
+ {
+ SoundMaker *sm = (SoundMaker *)data;
+ sm->m_sound->playSound(sm->m_player_rightpunch_sound, false);
+ }
+
+ static void nodeDug(MtEvent *e, void *data)
+ {
+ SoundMaker *sm = (SoundMaker *)data;
+ NodeDugEvent *nde = (NodeDugEvent *)e;
+ sm->m_sound->playSound(sm->m_ndef->get(nde->n).sound_dug, false);
+ }
+
+ static void playerDamage(MtEvent *e, void *data)
+ {
+ SoundMaker *sm = (SoundMaker *)data;
+ sm->m_sound->playSound(SimpleSoundSpec("player_damage", 0.5), false);
+ }
+
+ static void playerFallingDamage(MtEvent *e, void *data)
+ {
+ SoundMaker *sm = (SoundMaker *)data;
+ sm->m_sound->playSound(SimpleSoundSpec("player_falling_damage", 0.5), false);
+ }
+
+ void registerReceiver(MtEventManager *mgr)
+ {
+ mgr->reg(MtEvent::VIEW_BOBBING_STEP, SoundMaker::viewBobbingStep, this);
+ mgr->reg(MtEvent::PLAYER_REGAIN_GROUND, SoundMaker::playerRegainGround, this);
+ mgr->reg(MtEvent::PLAYER_JUMP, SoundMaker::playerJump, this);
+ mgr->reg(MtEvent::CAMERA_PUNCH_LEFT, SoundMaker::cameraPunchLeft, this);
+ mgr->reg(MtEvent::CAMERA_PUNCH_RIGHT, SoundMaker::cameraPunchRight, this);
+ mgr->reg(MtEvent::NODE_DUG, SoundMaker::nodeDug, this);
+ mgr->reg(MtEvent::PLAYER_DAMAGE, SoundMaker::playerDamage, this);
+ mgr->reg(MtEvent::PLAYER_FALLING_DAMAGE, SoundMaker::playerFallingDamage, this);
+ }
+
+ void step(float dtime)
+ {
+ m_player_step_timer -= dtime;
+ m_player_jump_timer -= dtime;
+ }
+};
+
+// Locally stored sounds don't need to be preloaded because of this
+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)
+ {
+ if (m_fetched.count(name))
+ return;
+
+ m_fetched.insert(name);
+
+ paths_insert(dst_paths, porting::path_share, name);
+ paths_insert(dst_paths, porting::path_user, name);
+ }
+};
+
+
+typedef s32 SamplerLayer_t;
+
+
+class GameGlobalShaderConstantSetter : public IShaderConstantSetter
+{
+ Sky *m_sky;
+ bool *m_force_fog_off;
+ f32 *m_fog_range;
+ bool m_fog_enabled;
+ CachedPixelShaderSetting<float, 4> m_sky_bg_color;
+ CachedPixelShaderSetting<float> m_fog_distance;
+ CachedVertexShaderSetting<float> m_animation_timer_vertex;
+ CachedPixelShaderSetting<float> m_animation_timer_pixel;
+ CachedPixelShaderSetting<float, 3> m_day_light;
+ CachedPixelShaderSetting<float, 4> m_star_color;
+ CachedPixelShaderSetting<float, 3> m_eye_position_pixel;
+ CachedVertexShaderSetting<float, 3> m_eye_position_vertex;
+ CachedPixelShaderSetting<float, 3> m_minimap_yaw;
+ CachedPixelShaderSetting<float, 3> m_camera_offset_pixel;
+ CachedPixelShaderSetting<float, 3> m_camera_offset_vertex;
+ CachedPixelShaderSetting<SamplerLayer_t> m_base_texture;
+ CachedPixelShaderSetting<SamplerLayer_t> m_normal_texture;
+ Client *m_client;
+
+public:
+ void onSettingsChange(const std::string &name)
+ {
+ if (name == "enable_fog")
+ m_fog_enabled = g_settings->getBool("enable_fog");
+ }
+
+ static void settingsCallback(const std::string &name, void *userdata)
+ {
+ reinterpret_cast<GameGlobalShaderConstantSetter*>(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_star_color("starColor"),
+ m_eye_position_pixel("eyePosition"),
+ m_eye_position_vertex("eyePosition"),
+ m_minimap_yaw("yawVec"),
+ m_camera_offset_pixel("cameraOffset"),
+ m_camera_offset_vertex("cameraOffset"),
+ m_base_texture("baseTexture"),
+ m_normal_texture("normalTexture"),
+ m_client(client)
+ {
+ g_settings->registerChangedCallback("enable_fog", settingsCallback, this);
+ m_fog_enabled = g_settings->getBool("enable_fog");
+ }
+
+ ~GameGlobalShaderConstantSetter()
+ {
+ g_settings->deregisterChangedCallback("enable_fog", settingsCallback, this);
+ }
+
+ void onSetConstants(video::IMaterialRendererServices *services) override
+ {
+ // Background color
+ video::SColor bgcolor = m_sky->getBgColor();
+ video::SColorf bgcolorf(bgcolor);
+ float bgcolorfa[4] = {
+ bgcolorf.r,
+ bgcolorf.g,
+ bgcolorf.b,
+ bgcolorf.a,
+ };
+ m_sky_bg_color.set(bgcolorfa, services);
+
+ // Fog distance
+ float fog_distance = 10000 * BS;
+
+ if (m_fog_enabled && !*m_force_fog_off)
+ fog_distance = *m_fog_range;
+
+ m_fog_distance.set(&fog_distance, services);
+
+ 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);
+
+ video::SColorf star_color = m_sky->getCurrentStarColor();
+ float clr[4] = {star_color.r, star_color.g, star_color.b, star_color.a};
+ m_star_color.set(clr, services);
+
+ u32 animation_timer = porting::getTimeMs() % 1000000;
+ 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);
+
+ float eye_position_array[3];
+ v3f epos = m_client->getEnv().getLocalPlayer()->getEyePosition();
+ epos.getAs3Values(eye_position_array);
+ m_eye_position_pixel.set(eye_position_array, services);
+ m_eye_position_vertex.set(eye_position_array, services);
+
+ if (m_client->getMinimap()) {
+ float minimap_yaw_array[3];
+ v3f minimap_yaw = m_client->getMinimap()->getYawVec();
+ minimap_yaw.getAs3Values(minimap_yaw_array);
+ m_minimap_yaw.set(minimap_yaw_array, services);
+ }
+
+ float camera_offset_array[3];
+ v3f offset = intToFloat(m_client->getCamera()->getOffset(), BS);
+ offset.getAs3Values(camera_offset_array);
+ m_camera_offset_pixel.set(camera_offset_array, services);
+ m_camera_offset_vertex.set(camera_offset_array, services);
+
+ SamplerLayer_t base_tex = 0, normal_tex = 1;
+ m_base_texture.set(&base_tex, services);
+ m_normal_texture.set(&normal_tex, services);
+ }
+};
+
+
+class GameGlobalShaderConstantSetterFactory : public IShaderConstantSetterFactory
+{
+ Sky *m_sky;
+ bool *m_force_fog_off;
+ f32 *m_fog_range;
+ Client *m_client;
+ std::vector<GameGlobalShaderConstantSetter *> 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 (GameGlobalShaderConstantSetter *ggscs : created_nosky) {
+ ggscs->setSky(m_sky);
+ }
+ created_nosky.clear();
+ }
+
+ virtual IShaderConstantSetter* create()
+ {
+ auto *scs = new GameGlobalShaderConstantSetter(
+ m_sky, m_force_fog_off, m_fog_range, m_client);
+ if (!m_sky)
+ created_nosky.push_back(scs);
+ return scs;
+ }
+};
+
+#ifdef HAVE_TOUCHSCREENGUI
+#define SIZE_TAG "size[11,5.5]"
+#else
+#define SIZE_TAG "size[11,5.5,true]" // Fixed size on desktop
+#endif
+
+/****************************************************************************
+ ****************************************************************************/
+
+const float object_hit_delay = 0.2;
+
+struct FpsControl {
+ FpsControl() : last_time(0), busy_time(0), sleep_time(0) {}
+
+ void reset();
+
+ void limit(IrrlichtDevice *device, f32 *dtime);
+
+ u32 getBusyMs() const { return busy_time / 1000; }
+
+ // all values in microseconds (us)
+ u64 last_time, busy_time, sleep_time;
+};
+
+
+/* The reason the following structs are not anonymous structs within the
+ * class is that they are not used by the majority of member functions and
+ * many functions that do require objects of thse types do not modify them
+ * (so they can be passed as a const qualified parameter)
+ */
+
+struct GameRunData {
+ u16 dig_index;
+ u16 new_playeritem;
+ PointedThing pointed_old;
+ bool digging;
+ bool punching;
+ bool btn_down_for_dig;
+ bool dig_instantly;
+ bool digging_blocked;
+ bool reset_jump_timer;
+ float nodig_delay_timer;
+ float dig_time;
+ float dig_time_complete;
+ float repeat_place_timer;
+ float object_hit_delay_timer;
+ float time_from_last_punch;
+ ClientActiveObject *selected_object;
+
+ float jump_timer;
+ float damage_flash;
+ float update_draw_list_timer;
+
+ f32 fog_range;
+
+ v3f update_draw_list_last_cam_dir;
+
+ float time_of_day_smooth;
+};
+
+class Game;
+
+struct ClientEventHandler
+{
+ void (Game::*handler)(ClientEvent *, CameraOrientation *);
+};
+
+using PausedNodesList = std::vector<std::pair<irr_ptr<scene::IAnimatedMeshSceneNode>, float>>;
+
+class Game {
+public:
+ Game();
+ ~Game();
+
+ bool startup(bool *kill,
+ InputHandler *input,
+ RenderingEngine *rendering_engine,
+ const GameStartData &game_params,
+ std::string &error_message,
+ bool *reconnect,
+ ChatBackend *chat_backend);
+
+
+ void run();
+ void shutdown();
+
+ // Basic initialisation
+ bool init(const std::string &map_dir, const std::string &address,
+ u16 port, const SubgameSpec &gamespec);
+ bool initSound();
+ bool createSingleplayerServer(const std::string &map_dir,
+ const SubgameSpec &gamespec, u16 port);
+
+ // Client creation
+ bool createClient(const GameStartData &start_data);
+ bool initGui();
+
+ // Client connection
+ bool connectToServer(const GameStartData &start_data,
+ bool *connect_ok, bool *aborted);
+ bool getServerContent(bool *aborted);
+
+ // Main loop
+
+ void updateInteractTimers(f32 dtime);
+ bool checkConnection();
+ bool handleCallbacks();
+ void processQueues();
+ void updateProfilers(const RunStats &stats, const FpsControl &draw_times, f32 dtime);
+ void updateDebugState();
+ void updateStats(RunStats *stats, const FpsControl &draw_times, f32 dtime);
+ void updateProfilerGraphs(ProfilerGraph *graph);
+
+ // Input related
+ void processUserInput(f32 dtime);
+ void processKeyInput();
+ void processItemSelection(u16 *new_playeritem);
+
+ void dropSelectedItem(bool single_item = false);
+ void openInventory();
+ void openEnderchest();
+ void openConsole(float scale, const wchar_t *line=NULL);
+ void toggleFreeMove();
+ void toggleFreeMoveAlt();
+ void togglePitchMove();
+ void toggleFast();
+ void toggleNoClip();
+ void toggleKillaura();
+ void toggleFreecam();
+ void toggleScaffold();
+ void toggleNextItem();
+ void toggleCinematic();
+ void toggleBlockBounds();
+ void toggleAutoforward();
+
+ void toggleMinimap(bool shift_pressed);
+ void toggleFog();
+ void toggleDebug();
+ void toggleUpdateCamera();
+ void updatePlayerCAOVisibility();
+
+ void increaseViewRange();
+ void decreaseViewRange();
+ void toggleFullViewRange();
+ void checkZoomEnabled();
+
+ void updateCameraDirection(CameraOrientation *cam, float dtime);
+ void updateCameraOrientation(CameraOrientation *cam, float dtime);
+ void updatePlayerControl(const CameraOrientation &cam);
+ void step(f32 *dtime);
+ void processClientEvents(CameraOrientation *cam);
+ void updateCamera(f32 dtime);
+ void updateSound(f32 dtime);
+ void processPlayerInteraction(f32 dtime, bool show_hud);
+ /*!
+ * 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<f32> &shootline, bool liquids_pointable,
+ bool look_for_object, const v3s16 &camera_offset);
+ void handlePointingAtNothing(const ItemStack &playerItem);
+ void handlePointingAtNode(const PointedThing &pointed,
+ const ItemStack &selected_item, const ItemStack &hand_item, 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,
+ const ItemStack &selected_item, const ItemStack &hand_item, f32 dtime);
+ void updateFrame(ProfilerGraph *graph, RunStats *stats, f32 dtime,
+ const CameraOrientation &cam);
+ void updateShadows();
+
+ // Misc
+ void showOverlayMessage(const char *msg, float dtime, int percent,
+ bool draw_clouds = true);
+
+ static void freecamChangedCallback(const std::string &setting_name, void *data);
+ static void settingChangedCallback(const std::string &setting_name, void *data);
+ static void updateAllMapBlocksCallback(const std::string &setting_name, void *data);
+ void readSettings();
+
+ bool isKeyDown(GameKeyType k);
+ bool wasKeyDown(GameKeyType k);
+ bool wasKeyPressed(GameKeyType k);
+ bool wasKeyReleased(GameKeyType k);
+
+#ifdef __ANDROID__
+ void handleAndroidChatInput();
+#endif
+
+ struct Flags {
+ bool force_fog_off = false;
+ bool disable_camera_update = false;
+ };
+
+ void showDeathFormspec();
+ void showPauseMenu();
+
+ void pauseAnimation();
+ void resumeAnimation();
+
+ // ClientEvent handlers
+ void handleClientEvent_None(ClientEvent *event, CameraOrientation *cam);
+ void handleClientEvent_PlayerDamage(ClientEvent *event, CameraOrientation *cam);
+ void handleClientEvent_PlayerForceMove(ClientEvent *event, CameraOrientation *cam);
+ void handleClientEvent_Deathscreen(ClientEvent *event, CameraOrientation *cam);
+ void handleClientEvent_ShowFormSpec(ClientEvent *event, CameraOrientation *cam);
+ void handleClientEvent_ShowLocalFormSpec(ClientEvent *event, CameraOrientation *cam);
+ void handleClientEvent_HandleParticleEvent(ClientEvent *event,
+ CameraOrientation *cam);
+ void handleClientEvent_HudAdd(ClientEvent *event, CameraOrientation *cam);
+ void handleClientEvent_HudRemove(ClientEvent *event, CameraOrientation *cam);
+ void handleClientEvent_HudChange(ClientEvent *event, CameraOrientation *cam);
+ void handleClientEvent_SetSky(ClientEvent *event, CameraOrientation *cam);
+ void handleClientEvent_SetSun(ClientEvent *event, CameraOrientation *cam);
+ void handleClientEvent_SetMoon(ClientEvent *event, CameraOrientation *cam);
+ void handleClientEvent_SetStars(ClientEvent *event, CameraOrientation *cam);
+ void handleClientEvent_OverrideDayNigthRatio(ClientEvent *event,
+ CameraOrientation *cam);
+ void handleClientEvent_CloudParams(ClientEvent *event, CameraOrientation *cam);
+
+ void updateChat(f32 dtime);
+
+ bool nodePlacement(const ItemDefinition &selected_def, const ItemStack &selected_item,
+ const v3s16 &nodepos, const v3s16 &neighbourpos, const PointedThing &pointed,
+ const NodeMetadata *meta, bool force = false);
+ static const ClientEventHandler clientEventHandler[CLIENTEVENT_MAX];
+
+ f32 getSensitivityScaleFactor() const;
+
+ InputHandler *input = nullptr;
+
+ Client *client = nullptr;
+ Server *server = nullptr;
+
+ IWritableTextureSource *texture_src = nullptr;
+ IWritableShaderSource *shader_src = nullptr;
+
+ // When created, these will be filled with data received from the server
+ IWritableItemDefManager *itemdef_manager = nullptr;
+ NodeDefManager *nodedef_manager = nullptr;
+
+ GameOnDemandSoundFetcher soundfetcher; // useful when testing
+ ISoundManager *sound = nullptr;
+ bool sound_is_dummy = false;
+ SoundMaker *soundmaker = nullptr;
+
+ ChatBackend *chat_backend = nullptr;
+ LogOutputBuffer m_chat_log_buf;
+
+ EventManager *eventmgr = nullptr;
+ QuicktuneShortcutter *quicktune = nullptr;
+ bool registration_confirmation_shown = false;
+
+ std::unique_ptr<GameUI> m_game_ui;
+ GUIChatConsole *gui_chat_console = nullptr; // Free using ->Drop()
+ CheatMenu *m_cheat_menu = nullptr;
+ MapDrawControl *draw_control = nullptr;
+ Camera *camera = nullptr;
+ Clouds *clouds = nullptr; // Free using ->Drop()
+ Sky *sky = nullptr; // Free using ->Drop()
+ Hud *hud = nullptr;
+ Minimap *mapper = nullptr;
+
+ // Map server hud ids to client hud ids
+ std::unordered_map<u32, u32> m_hud_server_to_client;
+
+ GameRunData runData;
+ Flags m_flags;
+
+ /* 'cache'
+ This class does take ownership/responsibily for cleaning up etc of any of
+ these items (e.g. device)
+ */
+ IrrlichtDevice *device;
+ RenderingEngine *m_rendering_engine;
+ video::IVideoDriver *driver;
+ scene::ISceneManager *smgr;
+ bool *kill;
+ std::string *error_message;
+ bool *reconnect_requested;
+ scene::ISceneNode *skybox;
+ PausedNodesList paused_animated_nodes;
+
+ bool simple_singleplayer_mode;
+ /* End 'cache' */
+
+ /* Pre-calculated values
+ */
+ int crack_animation_length;
+
+ IntervalLimiter profiler_interval;
+
+ /*
+ * TODO: Local caching of settings is not optimal and should at some stage
+ * be updated to use a global settings object for getting thse values
+ * (as opposed to the this local caching). This can be addressed in
+ * a later release.
+ */
+ bool m_cache_doubletap_jump;
+ bool m_cache_enable_clouds;
+ bool m_cache_enable_joysticks;
+ bool m_cache_enable_particles;
+ bool m_cache_enable_fog;
+ bool m_cache_enable_noclip;
+ bool m_cache_enable_free_move;
+ f32 m_cache_mouse_sensitivity;
+ f32 m_cache_joystick_frustum_sensitivity;
+ f32 m_repeat_place_time;
+ f32 m_cache_cam_smoothing;
+ f32 m_cache_fog_start;
+
+ bool m_invert_mouse = false;
+ bool m_first_loop_after_window_activation = false;
+ bool m_camera_offset_changed = false;
+
+ bool m_does_lost_focus_pause_game = false;
+
+ CameraOrientation cam_view_target = {}; // added by dragonfireclient
+ CameraOrientation cam_view = {}; // added by dragonfireclient
+
+#if IRRLICHT_VERSION_MT_REVISION < 5
+ int m_reset_HW_buffer_counter = 0;
+#endif
+
+#ifdef HAVE_TOUCHSCREENGUI
+ bool m_cache_hold_aux1;
+#endif
+#ifdef __ANDROID__
+ bool m_android_chat_open;
+#endif
+};
+extern Game *g_game;
void the_game(bool *kill,
InputHandler *input,
diff --git a/src/client/gameui.cpp b/src/client/gameui.cpp
index 01c733b4f..54be24ae2 100644
--- a/src/client/gameui.cpp
+++ b/src/client/gameui.cpp
@@ -53,6 +53,9 @@ GameUI::GameUI()
}
void GameUI::init()
{
+ m_guitext_coords = gui::StaticText::add(guienv, L"", core::rect<s32>(0, 0, 0, 0), false,
+ false, guiroot);
+
// First line of debug text
m_guitext = gui::StaticText::add(guienv, utf8_to_wide(PROJECT_NAME_C).c_str(),
core::rect<s32>(0, 0, 0, 0), false, false, guiroot);
@@ -100,8 +103,25 @@ void GameUI::update(const RunStats &stats, Client *client, MapDrawControl *draw_
const CameraOrientation &cam, const PointedThing &pointed_old,
const GUIChatConsole *chat_console, float dtime)
{
+ LocalPlayer *player = client->getEnv().getLocalPlayer();
+ v3f player_position = player->getPosition();
+
v2u32 screensize = RenderingEngine::getWindowSize();
+ bool show_coords = g_settings->getBool("coords");
+
+ if (show_coords) {
+ std::ostringstream os(std::ios_base::binary);
+ os << std::setprecision(1) << std::fixed
+ << (player_position.X / BS)
+ << ", " << (player_position.Y / BS)
+ << ", " << (player_position.Z / BS);
+ setStaticText(m_guitext_coords, utf8_to_wide(os.str()).c_str());
+ m_guitext_coords->setRelativePosition(core::rect<s32>(5, screensize.Y - 5 - g_fontengine->getTextHeight(), screensize.X, screensize.Y));
+ }
+
+ m_guitext_coords->setVisible(show_coords);
+
// Minimal debug text must only contain info that can't give a gameplay advantage
if (m_flags.show_minimal_debug) {
const u16 fps = 1.0 / stats.dtime_jitter.avg;
@@ -206,8 +226,7 @@ void GameUI::update(const RunStats &stats, Client *client, MapDrawControl *draw_
m_guitext_status->enableOverrideColor(true);
}
- // Hide chat when console is visible
- m_guitext_chat->setVisible(isChatVisible() && !chat_console->isVisible());
+ m_guitext_chat->setVisible(isChatVisible());
}
void GameUI::initFlags()
@@ -238,15 +257,16 @@ void GameUI::setChatText(const EnrichedString &chat_text, u32 recent_chat_count)
void GameUI::updateChatSize()
{
// Update gui element size and position
- s32 chat_y = 5;
+
+ const v2u32 &window_size = RenderingEngine::getWindowSize();
+
+ s32 chat_y = window_size.Y - 150 - m_guitext_chat->getTextHeight();
if (m_flags.show_minimal_debug)
chat_y += g_fontengine->getLineHeight();
if (m_flags.show_basic_debug)
chat_y += g_fontengine->getLineHeight();
- const v2u32 &window_size = RenderingEngine::getWindowSize();
-
core::rect<s32> chat_size(10, chat_y, window_size.X - 20, 0);
chat_size.LowerRightCorner.Y = std::min((s32)window_size.Y,
m_guitext_chat->getTextHeight() + chat_y);
@@ -294,6 +314,15 @@ void GameUI::toggleChat()
showTranslatedStatusText("Chat hidden");
}
+void GameUI::toggleCheatMenu()
+{
+ m_flags.show_cheat_menu = !m_flags.show_cheat_menu;
+ if (m_flags.show_cheat_menu)
+ showTranslatedStatusText("Cheat Menu shown");
+ else
+ showTranslatedStatusText("Cheat Menu hidden");
+}
+
void GameUI::toggleHud()
{
m_flags.show_hud = !m_flags.show_hud;
diff --git a/src/client/gameui.h b/src/client/gameui.h
index cc9377bdc..e22be068b 100644
--- a/src/client/gameui.h
+++ b/src/client/gameui.h
@@ -61,6 +61,7 @@ public:
bool show_minimal_debug = false;
bool show_basic_debug = false;
bool show_profiler_graph = false;
+ bool show_cheat_menu = true;
};
void init();
@@ -94,6 +95,7 @@ public:
void updateProfiler();
void toggleChat();
+ void toggleCheatMenu();
void toggleHud();
void toggleProfiler();
@@ -114,7 +116,8 @@ private:
gui::IGUIStaticText *m_guitext = nullptr; // First line of debug text
gui::IGUIStaticText *m_guitext2 = nullptr; // Second line of debug text
-
+ gui::IGUIStaticText *m_guitext_coords = nullptr;
+
gui::IGUIStaticText *m_guitext_info = nullptr; // At the middle of the screen
std::wstring m_infotext;
diff --git a/src/client/hud.cpp b/src/client/hud.cpp
index 01f4d6ff3..d5debecfb 100644
--- a/src/client/hud.cpp
+++ b/src/client/hud.cpp
@@ -150,7 +150,7 @@ void Hud::drawItem(const ItemStack &item, const core::rect<s32>& rect,
bool selected)
{
if (selected) {
- /* draw hihlighting around selected item */
+ /* draw highlighting around selected item */
if (use_hotbar_selected_image) {
core::rect<s32> imgrect2 = rect;
imgrect2.UpperLeftCorner.X -= (m_padding*2);
diff --git a/src/client/inputhandler.cpp b/src/client/inputhandler.cpp
index a6ba87e8d..d2d81be9c 100644
--- a/src/client/inputhandler.cpp
+++ b/src/client/inputhandler.cpp
@@ -44,6 +44,7 @@ void KeyCache::populate()
key[KeyType::DROP] = getKeySetting("keymap_drop");
key[KeyType::INVENTORY] = getKeySetting("keymap_inventory");
+ key[KeyType::ENDERCHEST] = getKeySetting("keymap_enderchest");
key[KeyType::CHAT] = getKeySetting("keymap_chat");
key[KeyType::CMD] = getKeySetting("keymap_cmd");
key[KeyType::CMD_LOCAL] = getKeySetting("keymap_cmd_local");
@@ -64,6 +65,7 @@ void KeyCache::populate()
key[KeyType::TOGGLE_HUD] = getKeySetting("keymap_toggle_hud");
key[KeyType::TOGGLE_CHAT] = getKeySetting("keymap_toggle_chat");
key[KeyType::TOGGLE_FOG] = getKeySetting("keymap_toggle_fog");
+ key[KeyType::TOGGLE_CHEAT_MENU] = getKeySetting("keymap_toggle_cheat_menu");
key[KeyType::TOGGLE_UPDATE_CAMERA] = getKeySetting("keymap_toggle_update_camera");
key[KeyType::TOGGLE_DEBUG] = getKeySetting("keymap_toggle_debug");
key[KeyType::TOGGLE_PROFILER] = getKeySetting("keymap_toggle_profiler");
@@ -74,6 +76,14 @@ void KeyCache::populate()
getKeySetting("keymap_decrease_viewing_range_min");
key[KeyType::RANGESELECT] = getKeySetting("keymap_rangeselect");
key[KeyType::ZOOM] = getKeySetting("keymap_zoom");
+ key[KeyType::KILLAURA] = getKeySetting("keymap_toggle_killaura");
+ key[KeyType::FREECAM] = getKeySetting("keymap_toggle_freecam");
+ key[KeyType::SCAFFOLD] = getKeySetting("keymap_toggle_scaffold");
+ key[KeyType::SELECT_UP] = getKeySetting("keymap_select_up");
+ key[KeyType::SELECT_DOWN] = getKeySetting("keymap_select_down");
+ key[KeyType::SELECT_LEFT] = getKeySetting("keymap_select_left");
+ key[KeyType::SELECT_RIGHT] = getKeySetting("keymap_select_right");
+ key[KeyType::SELECT_CONFIRM] = getKeySetting("keymap_select_confirm");
key[KeyType::QUICKTUNE_NEXT] = getKeySetting("keymap_quicktune_next");
key[KeyType::QUICKTUNE_PREV] = getKeySetting("keymap_quicktune_prev");
diff --git a/src/client/inputhandler.h b/src/client/inputhandler.h
index 3db105c51..47a61d4b8 100644
--- a/src/client/inputhandler.h
+++ b/src/client/inputhandler.h
@@ -30,6 +30,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#endif
class InputHandler;
+class TouchScreenGUI;
/****************************************************************************
Fast key cache for main game loop
@@ -201,7 +202,6 @@ public:
TouchScreenGUI *m_touchscreengui;
#endif
-private:
s32 mouse_wheel = 0;
// The current state of keys
@@ -241,6 +241,8 @@ public:
}
virtual bool isKeyDown(GameKeyType k) = 0;
+ virtual void setKeypress(const KeyPress &keyCode) = 0;
+ virtual void unsetKeypress(const KeyPress &keyCode) = 0;
virtual bool wasKeyDown(GameKeyType k) = 0;
virtual bool wasKeyPressed(GameKeyType k) = 0;
virtual bool wasKeyReleased(GameKeyType k) = 0;
@@ -288,6 +290,15 @@ public:
{
return m_receiver->IsKeyDown(keycache.key[k]) || joystick.isKeyDown(k);
}
+ virtual void setKeypress(const KeyPress &keyCode)
+ {
+ m_receiver->keyIsDown.set(keyCode);
+ m_receiver->keyWasDown.set(keyCode);
+ }
+ virtual void unsetKeypress(const KeyPress &keyCode)
+ {
+ m_receiver->keyIsDown.unset(keyCode);
+ }
virtual bool wasKeyDown(GameKeyType k)
{
return m_receiver->WasKeyDown(keycache.key[k]) || joystick.wasKeyDown(k);
@@ -411,6 +422,14 @@ public:
}
virtual bool isKeyDown(GameKeyType k) { return keydown[keycache.key[k]]; }
+ virtual void setKeypress(const KeyPress &keyCode)
+ {
+ keydown.set(keyCode);
+ }
+ virtual void unsetKeypress(const KeyPress &keyCode)
+ {
+ keydown.unset(keyCode);
+ }
virtual bool wasKeyDown(GameKeyType k) { return false; }
virtual bool wasKeyPressed(GameKeyType k) { return false; }
virtual bool wasKeyReleased(GameKeyType k) { return false; }
diff --git a/src/client/keys.h b/src/client/keys.h
index e120a2d92..b81b571b2 100644
--- a/src/client/keys.h
+++ b/src/client/keys.h
@@ -43,6 +43,7 @@ public:
// Other
DROP,
INVENTORY,
+ ENDERCHEST,
CHAT,
CMD,
CMD_LOCAL,
@@ -63,6 +64,7 @@ public:
TOGGLE_HUD,
TOGGLE_CHAT,
TOGGLE_FOG,
+ TOGGLE_CHEAT_MENU,
TOGGLE_UPDATE_CAMERA,
TOGGLE_DEBUG,
TOGGLE_PROFILER,
@@ -71,7 +73,15 @@ public:
DECREASE_VIEWING_RANGE,
RANGESELECT,
ZOOM,
-
+ KILLAURA,
+ FREECAM,
+ SCAFFOLD,
+ SELECT_UP,
+ SELECT_DOWN,
+ SELECT_LEFT,
+ SELECT_RIGHT,
+ SELECT_CONFIRM,
+
QUICKTUNE_NEXT,
QUICKTUNE_PREV,
QUICKTUNE_INC,
diff --git a/src/client/localplayer.cpp b/src/client/localplayer.cpp
index 279efafe9..c4d9b9845 100644
--- a/src/client/localplayer.cpp
+++ b/src/client/localplayer.cpp
@@ -27,6 +27,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "map.h"
#include "client.h"
#include "content_cao.h"
+#include "util/pointedthing.h"
+#include "client/game.h"
/*
LocalPlayer
@@ -87,7 +89,7 @@ bool LocalPlayer::updateSneakNode(Map *map, const v3f &position,
new_sneak_node_exists = false;
} else {
node = map->getNode(current_node, &is_valid_position);
- if (!is_valid_position || !nodemgr->get(node).walkable)
+ if (!is_valid_position || nodemgr->get(node).walkable)
new_sneak_node_exists = false;
}
@@ -113,7 +115,7 @@ bool LocalPlayer::updateSneakNode(Map *map, const v3f &position,
// The node to be sneaked on has to be walkable
node = map->getNode(p, &is_valid_position);
- if (!is_valid_position || !nodemgr->get(node).walkable)
+ if (!is_valid_position || ! nodemgr->get(node).walkable)
continue;
// And the node(s) above have to be nonwalkable
bool ok = true;
@@ -130,7 +132,7 @@ bool LocalPlayer::updateSneakNode(Map *map, const v3f &position,
} else {
// legacy behaviour: check just one node
node = map->getNode(p + v3s16(0, 1, 0), &is_valid_position);
- ok = is_valid_position && !nodemgr->get(node).walkable;
+ ok = is_valid_position && ! nodemgr->get(node).walkable;
}
if (!ok)
continue;
@@ -159,7 +161,7 @@ bool LocalPlayer::updateSneakNode(Map *map, const v3f &position,
node = map->getNode(m_sneak_node + v3s16(0, 3, 0),
&is_valid_position);
m_sneak_ladder_detected = is_valid_position &&
- !nodemgr->get(node).walkable;
+ ! nodemgr->get(node).walkable;
}
}
return true;
@@ -168,6 +170,9 @@ bool LocalPlayer::updateSneakNode(Map *map, const v3f &position,
void LocalPlayer::move(f32 dtime, Environment *env, f32 pos_max_d,
std::vector<CollisionInfo> *collision_info)
{
+ if (m_cao && m_cao->m_waiting_for_reattach > 0)
+ m_cao->m_waiting_for_reattach -= dtime;
+
// Node at feet position, update each ClientEnvironment::step()
if (!collision_info || collision_info->empty())
m_standing_node = floatToInt(m_position, BS);
@@ -193,9 +198,9 @@ void LocalPlayer::move(f32 dtime, Environment *env, f32 pos_max_d,
PlayerSettings &player_settings = getPlayerSettings();
// Skip collision detection if noclip mode is used
- bool fly_allowed = m_client->checkLocalPrivilege("fly");
- bool noclip = m_client->checkLocalPrivilege("noclip") && player_settings.noclip;
- bool free_move = player_settings.free_move && fly_allowed;
+ bool fly_allowed = m_client->checkLocalPrivilege("fly") || g_settings->getBool("freecam");
+ bool noclip = (m_client->checkLocalPrivilege("noclip") && player_settings.noclip) || g_settings->getBool("freecam");
+ bool free_move = (player_settings.free_move && fly_allowed) || g_settings->getBool("freecam");
if (noclip && free_move) {
position += m_speed * dtime;
@@ -276,6 +281,25 @@ void LocalPlayer::move(f32 dtime, Environment *env, f32 pos_max_d,
nodemgr->get(node2.getContent()).climbable) && !free_move;
}
+ if (!is_climbing && !free_move && g_settings->getBool("spider")) {
+ v3s16 spider_positions[4] = {
+ floatToInt(position + v3f(+1.0f, +0.0f, 0.0f) * BS, BS),
+ floatToInt(position + v3f(-1.0f, +0.0f, 0.0f) * BS, BS),
+ floatToInt(position + v3f( 0.0f, +0.0f, +1.0f) * BS, BS),
+ floatToInt(position + v3f( 0.0f, +0.0f, -1.0f) * BS, BS),
+ };
+
+ for (v3s16 sp : spider_positions) {
+ bool is_valid;
+ MapNode node = map->getNode(sp, &is_valid);
+
+ if (is_valid && nodemgr->get(node.getContent()).walkable) {
+ is_climbing = true;
+ break;
+ }
+ }
+ }
+
/*
Collision uncertainty radius
Make it a bit larger than the maximum distance of movement
@@ -298,7 +322,7 @@ void LocalPlayer::move(f32 dtime, Environment *env, f32 pos_max_d,
collisionMoveResult result = collisionMoveSimple(env, m_client,
pos_max_d, m_collisionbox, player_stepheight, dtime,
- &position, &m_speed, accel_f);
+ &position, &m_speed, accel_f, NULL, true, true);
bool could_sneak = control.sneak && !free_move && !in_liquid &&
!is_climbing && physics_override_sneak;
@@ -337,7 +361,7 @@ void LocalPlayer::move(f32 dtime, Environment *env, f32 pos_max_d,
Player is allowed to jump when this is true.
*/
bool touching_ground_was = touching_ground;
- touching_ground = result.touching_ground;
+ touching_ground = result.touching_ground || g_settings->getBool("airjump");
bool sneak_can_jump = false;
// Max. distance (X, Z) over border for sneaking determined by collision box
@@ -495,8 +519,8 @@ void LocalPlayer::applyControl(float dtime, Environment *env)
bool fly_allowed = m_client->checkLocalPrivilege("fly");
bool fast_allowed = m_client->checkLocalPrivilege("fast");
- bool free_move = fly_allowed && player_settings.free_move;
- bool fast_move = fast_allowed && player_settings.fast_move;
+ bool free_move = (fly_allowed && player_settings.free_move) || g_settings->getBool("freecam");
+ bool fast_move = (fast_allowed && player_settings.fast_move) || g_settings->getBool("freecam");
bool pitch_move = (free_move || in_liquid) && player_settings.pitch_move;
// When aux1_descends is enabled the fast key is used to go down, so fast isn't possible
bool fast_climb = fast_move && control.aux1 && !player_settings.aux1_descends;
@@ -590,14 +614,14 @@ void LocalPlayer::applyControl(float dtime, Environment *env)
else
speedV.Y = movement_speed_walk;
}
- } else if (m_can_jump) {
+ } else if (m_can_jump || g_settings->getBool("jetpack")) {
/*
NOTE: The d value in move() affects jump height by
raising the height at which the jump speed is kept
at its starting value
*/
v3f speedJ = getSpeed();
- if (speedJ.Y >= -0.5f * BS) {
+ if (speedJ.Y >= -0.5f * BS || g_settings->getBool("jetpack")) {
speedJ.Y = movement_speed_jump * physics_override_jump;
setSpeed(speedJ);
m_client->getEventManager()->put(new SimpleTriggerEvent(MtEvent::PLAYER_JUMP));
@@ -620,7 +644,7 @@ void LocalPlayer::applyControl(float dtime, Environment *env)
if (superspeed || (is_climbing && fast_climb) ||
((in_liquid || in_liquid_stable) && fast_climb))
speedH = speedH.normalize() * movement_speed_fast;
- else if (control.sneak && !free_move && !in_liquid && !in_liquid_stable)
+ else if (control.sneak && !free_move && !in_liquid && !in_liquid_stable && !g_settings->getBool("no_slow"))
speedH = speedH.normalize() * movement_speed_crouch;
else
speedH = speedH.normalize() * movement_speed_walk;
@@ -694,6 +718,16 @@ v3s16 LocalPlayer::getLightPosition() const
return floatToInt(m_position + v3f(0.0f, BS * 1.5f, 0.0f), BS);
}
+v3f LocalPlayer::getSendSpeed()
+{
+ v3f speed = getLegitSpeed();
+
+ if (m_client->modsLoaded())
+ speed = m_client->getScript()->get_send_speed(speed);
+
+ return speed;
+}
+
v3f LocalPlayer::getEyeOffset() const
{
float eye_height = camera_barely_in_ceiling ? m_eye_height - 0.125f : m_eye_height;
@@ -702,7 +736,7 @@ v3f LocalPlayer::getEyeOffset() const
ClientActiveObject *LocalPlayer::getParent() const
{
- return m_cao ? m_cao->getParent() : nullptr;
+ return (m_cao && ! g_settings->getBool("entity_speed")) ? m_cao->getParent() : nullptr;
}
bool LocalPlayer::isDead() const
@@ -711,6 +745,18 @@ bool LocalPlayer::isDead() const
return !getCAO()->isImmortal() && hp == 0;
}
+void LocalPlayer::tryReattach(int id)
+{
+ PointedThing pointed(id, v3f(0, 0, 0), v3s16(0, 0, 0), 0);
+ m_client->interact(INTERACT_PLACE, pointed);
+ m_cao->m_waiting_for_reattach = 10;
+}
+
+bool LocalPlayer::isWaitingForReattach() const
+{
+ return g_settings->getBool("entity_speed") && m_cao && ! m_cao->getParent() && m_cao->m_waiting_for_reattach > 0;
+}
+
// 3D acceleration
void LocalPlayer::accelerate(const v3f &target_speed, const f32 max_increase_H,
const f32 max_increase_V, const bool use_pitch)
@@ -773,9 +819,9 @@ void LocalPlayer::old_move(f32 dtime, Environment *env, f32 pos_max_d,
PlayerSettings &player_settings = getPlayerSettings();
// Skip collision detection if noclip mode is used
- bool fly_allowed = m_client->checkLocalPrivilege("fly");
- bool noclip = m_client->checkLocalPrivilege("noclip") && player_settings.noclip;
- bool free_move = noclip && fly_allowed && player_settings.free_move;
+ bool fly_allowed = m_client->checkLocalPrivilege("fly") || g_settings->getBool("freecam");
+ bool noclip = (m_client->checkLocalPrivilege("noclip") && player_settings.noclip) || g_settings->getBool("freecam");
+ bool free_move = (noclip && fly_allowed && player_settings.free_move) || g_settings->getBool("freecam");
if (free_move) {
position += m_speed * dtime;
setPosition(position);
@@ -896,7 +942,7 @@ void LocalPlayer::old_move(f32 dtime, Environment *env, f32 pos_max_d,
collisionMoveResult result = collisionMoveSimple(env, m_client,
pos_max_d, m_collisionbox, player_stepheight, dtime,
- &position, &m_speed, accel_f);
+ &position, &m_speed, accel_f, NULL, true, true);
// Positition was slightly changed; update standing node pos
if (touching_ground)
@@ -1075,7 +1121,7 @@ float LocalPlayer::getSlipFactor(Environment *env, const v3f &speedH)
Map *map = &env->getMap();
const ContentFeatures &f = nodemgr->get(map->getNode(getStandingNodePos()));
int slippery = 0;
- if (f.walkable)
+ if (f.walkable && ! g_settings->getBool("antislip"))
slippery = itemgroup_get(f.groups, "slippery");
if (slippery >= 1) {
@@ -1144,7 +1190,7 @@ void LocalPlayer::handleAutojump(f32 dtime, Environment *env,
// try at peak of jump, zero step height
collisionMoveResult jump_result = collisionMoveSimple(env, m_client, pos_max_d,
- m_collisionbox, 0.0f, dtime, &jump_pos, &jump_speed, v3f(0.0f));
+ m_collisionbox, 0.0f, dtime, &jump_pos, &jump_speed, v3f(0.0f), NULL, true, true);
// see if we can get a little bit farther horizontally if we had
// jumped
@@ -1157,3 +1203,4 @@ void LocalPlayer::handleAutojump(f32 dtime, Environment *env,
m_autojump_time = 0.1f;
}
}
+
diff --git a/src/client/localplayer.h b/src/client/localplayer.h
index 3d0072fc1..ebc67c4f8 100644
--- a/src/client/localplayer.h
+++ b/src/client/localplayer.h
@@ -32,6 +32,7 @@ class GenericCAO;
class ClientActiveObject;
class ClientEnvironment;
class IGameDef;
+struct ContentFeatures;
struct collisionMoveResult;
enum LocalPlayerAnimations
@@ -132,11 +133,39 @@ public:
inline void setPosition(const v3f &position)
{
m_position = position;
+ if (! m_freecam)
+ m_legit_position = position;
m_sneak_node_exists = false;
}
v3f getPosition() const { return m_position; }
+ v3f getLegitPosition() const { return m_legit_position; }
+
+ v3f getLegitSpeed() const { return m_freecam ? m_legit_speed : m_speed; }
+
+ v3f getSendSpeed();
+
+ inline void setLegitPosition(const v3f &position)
+ {
+ if (m_freecam)
+ m_legit_position = position;
+ else
+ setPosition(position);
+ }
+
+ inline void freecamEnable()
+ {
+ m_freecam = true;
+ }
+
+ inline void freecamDisable()
+ {
+ m_freecam = false;
+ setPosition(m_legit_position);
+ setSpeed(m_legit_speed);
+ }
+
// Non-transformed eye offset getters
// For accurate positions, use the Camera functions
v3f getEyePosition() const { return m_position + getEyeOffset(); }
@@ -161,6 +190,12 @@ public:
inline Lighting& getLighting() { return m_lighting; }
+ void tryReattach(int id);
+
+ bool isWaitingForReattach() const;
+
+ bool canWalkOn(const ContentFeatures &f);
+
private:
void accelerate(const v3f &target_speed, const f32 max_increase_H,
const f32 max_increase_V, const bool use_pitch);
@@ -171,7 +206,10 @@ private:
const v3f &position_before_move, const v3f &speed_before_move,
f32 pos_max_d);
+ bool m_freecam = false;
v3f m_position;
+ v3f m_legit_position;
+ v3f m_legit_speed;
v3s16 m_standing_node;
v3s16 m_sneak_node = v3s16(32767, 32767, 32767);
diff --git a/src/client/mapblock_mesh.cpp b/src/client/mapblock_mesh.cpp
index 965dd5e29..9e82fc3e4 100644
--- a/src/client/mapblock_mesh.cpp
+++ b/src/client/mapblock_mesh.cpp
@@ -88,7 +88,7 @@ void MeshMakeData::setCrack(int crack_level, v3s16 crack_pos)
void MeshMakeData::setSmoothLighting(bool smooth_lighting)
{
- m_smooth_lighting = smooth_lighting;
+ m_smooth_lighting = smooth_lighting && ! g_settings->getBool("fullbright");
}
/*
@@ -105,6 +105,8 @@ static u8 getInteriorLight(enum LightBank bank, MapNode n, s32 increment,
u8 light = n.getLight(bank, ndef);
if (light > 0)
light = rangelim(light + increment, 0, LIGHT_SUN);
+ if(g_settings->getBool("fullbright"))
+ return 255;
return decode_light(light);
}
@@ -139,7 +141,8 @@ static u8 getFaceLight(enum LightBank bank, MapNode n, MapNode n2,
ndef->get(n2).light_source);
if(light_source > light)
light = light_source;
-
+ if(g_settings->getBool("fullbright"))
+ return 255;
return decode_light(light);
}
@@ -657,6 +660,7 @@ static u8 face_contents(content_t m1, content_t m2, bool *equivalent,
u8 c1 = f1.solidness;
u8 c2 = f2.solidness;
+
if (c1 == c2)
return 0;
@@ -665,6 +669,7 @@ static u8 face_contents(content_t m1, content_t m2, bool *equivalent,
else if (c2 == 0)
c2 = f2.visual_solidness;
+
if (c1 == c2) {
*equivalent = true;
// If same solidness, liquid takes precense
@@ -764,6 +769,24 @@ void getNodeTile(MapNode mn, const v3s16 &p, const v3s16 &dir, MeshMakeData *dat
tile.rotation = tile.world_aligned ? 0 : dir_to_tile[tile_index + 1];
}
+std::set<content_t> splitToContentT(std::string str, const NodeDefManager *ndef)
+{
+ str += "\n";
+ std::set<content_t> dat;
+ std::string buf;
+ for (char c : str) {
+ if (c == ',' || c == '\n') {
+ if (! buf.empty()) {
+ dat.insert(ndef->getId(buf));
+ }
+ buf.clear();
+ } else if (c != ' ') {
+ buf += c;
+ }
+ }
+ return dat;
+}
+
static void getTileInfo(
// Input:
MeshMakeData *data,
@@ -775,8 +798,10 @@ static void getTileInfo(
v3s16 &face_dir_corrected,
u16 *lights,
u8 &waving,
- TileSpec &tile
- )
+ TileSpec &tile,
+ // lol more Input
+ bool xray,
+ std::set<content_t> xraySet)
{
VoxelManipulator &vmanip = data->m_vmanip;
const NodeDefManager *ndef = data->m_client->ndef();
@@ -784,22 +809,29 @@ static void getTileInfo(
const MapNode &n0 = vmanip.getNodeRefUnsafe(blockpos_nodes + p);
+ content_t c0 = n0.getContent();
+ if (xray && xraySet.find(c0) != xraySet.end())
+ c0 = CONTENT_AIR;
// Don't even try to get n1 if n0 is already CONTENT_IGNORE
- if (n0.getContent() == CONTENT_IGNORE) {
+ if (c0 == CONTENT_IGNORE) {
makes_face = false;
return;
}
const MapNode &n1 = vmanip.getNodeRefUnsafeCheckFlags(blockpos_nodes + p + face_dir);
- if (n1.getContent() == CONTENT_IGNORE) {
+ content_t c1 = n1.getContent();
+ if (xray && xraySet.find(c1) != xraySet.end())
+ c1 = CONTENT_AIR;
+
+ if (c1 == CONTENT_IGNORE) {
makes_face = false;
return;
}
// This is hackish
bool equivalent = false;
- u8 mf = face_contents(n0.getContent(), n1.getContent(),
+ u8 mf = face_contents(c0, c1,
&equivalent, ndef);
if (mf == 0) {
@@ -855,7 +887,9 @@ static void updateFastFaceRow(
v3s16 translate_dir,
const v3f &&translate_dir_f,
const v3s16 &&face_dir,
- std::vector<FastFace> &dest)
+ std::vector<FastFace> &dest,
+ bool xray,
+ std::set<content_t> xraySet)
{
static thread_local const bool waving_liquids =
g_settings->getBool("enable_shaders") &&
@@ -878,7 +912,7 @@ static void updateFastFaceRow(
// Get info of first tile
getTileInfo(data, p, face_dir,
makes_face, p_corrected, face_dir_corrected,
- lights, waving, tile);
+ lights, waving, tile, xray, xraySet);
// Unroll this variable which has a significant build cost
TileSpec next_tile;
@@ -900,7 +934,9 @@ static void updateFastFaceRow(
next_makes_face, next_p_corrected,
next_face_dir_corrected, next_lights,
waving,
- next_tile);
+ next_tile,
+ xray,
+ xraySet);
if (!force_not_tiling
&& next_makes_face == makes_face
@@ -951,7 +987,7 @@ static void updateFastFaceRow(
}
static void updateAllFastFaceRows(MeshMakeData *data,
- std::vector<FastFace> &dest)
+ std::vector<FastFace> &dest, bool xray, std::set<content_t> xraySet)
{
/*
Go through every y,z and get top(y+) faces in rows of x+
@@ -963,7 +999,9 @@ static void updateAllFastFaceRows(MeshMakeData *data,
v3s16(1, 0, 0), //dir
v3f (1, 0, 0),
v3s16(0, 1, 0), //face dir
- dest);
+ dest,
+ xray,
+ xraySet);
/*
Go through every x,y and get right(x+) faces in rows of z+
@@ -975,7 +1013,9 @@ static void updateAllFastFaceRows(MeshMakeData *data,
v3s16(0, 0, 1), //dir
v3f (0, 0, 1),
v3s16(1, 0, 0), //face dir
- dest);
+ dest,
+ xray,
+ xraySet);
/*
Go through every y,z and get back(z+) faces in rows of x+
@@ -987,7 +1027,9 @@ static void updateAllFastFaceRows(MeshMakeData *data,
v3s16(1, 0, 0), //dir
v3f (1, 0, 0),
v3s16(0, 0, 1), //face dir
- dest);
+ dest,
+ xray,
+ xraySet);
}
static void applyTileColor(PreMeshBuffer &pmb)
@@ -1201,6 +1243,15 @@ MapBlockMesh::MapBlockMesh(MeshMakeData *data, v3s16 camera_offset):
std::vector<FastFace> fastfaces_new;
fastfaces_new.reserve(512);
+ /*
+ X-Ray
+ */
+ bool xray = g_settings->getBool("xray");
+ std::set<content_t> xraySet, nodeESPSet;
+ if (xray)
+ xraySet = splitToContentT(g_settings->get("xray_nodes"), data->m_client->ndef());
+
+ nodeESPSet = splitToContentT(g_settings->get("node_esp_nodes"), data->m_client->ndef());
/*
We are including the faces of the trailing edges of the block.
@@ -1212,11 +1263,28 @@ MapBlockMesh::MapBlockMesh(MeshMakeData *data, v3s16 camera_offset):
{
// 4-23ms for MAP_BLOCKSIZE=16 (NOTE: probably outdated)
//TimeTaker timer2("updateAllFastFaceRows()");
- updateAllFastFaceRows(data, fastfaces_new);
+ updateAllFastFaceRows(data, fastfaces_new, xray, xraySet);
}
// End of slow part
/*
+ NodeESP
+ */
+ {
+ v3s16 blockpos_nodes = data->m_blockpos * MAP_BLOCKSIZE;
+ for (s16 x = 0; x < MAP_BLOCKSIZE; x++) {
+ for (s16 y = 0; y < MAP_BLOCKSIZE; y++) {
+ for (s16 z = 0; z < MAP_BLOCKSIZE; z++) {
+ v3s16 pos = v3s16(x, y, z) + blockpos_nodes;
+ const MapNode &node = data->m_vmanip.getNodeRefUnsafeCheckFlags(pos);
+ if (nodeESPSet.find(node.getContent()) != nodeESPSet.end())
+ esp_nodes.insert(pos);
+ }
+ }
+ }
+ }
+
+ /*
Convert FastFaces to MeshCollector
*/
diff --git a/src/client/mapblock_mesh.h b/src/client/mapblock_mesh.h
index 169b3a8c1..8133627b1 100644
--- a/src/client/mapblock_mesh.h
+++ b/src/client/mapblock_mesh.h
@@ -231,6 +231,8 @@ public:
return this->m_transparent_buffers;
}
+ std::set<v3s16> esp_nodes;
+
private:
struct AnimationInfo {
int frame; // last animation frame
diff --git a/src/client/mesh_generator_thread.h b/src/client/mesh_generator_thread.h
index 1b734bc06..2ef695954 100644
--- a/src/client/mesh_generator_thread.h
+++ b/src/client/mesh_generator_thread.h
@@ -125,6 +125,6 @@ private:
// TODO: Add callback to update these when g_settings changes
int m_generation_interval;
-protected:
+public:
virtual void doUpdate();
};
diff --git a/src/client/minimap.cpp b/src/client/minimap.cpp
index 320621d91..9bb9d14e0 100644
--- a/src/client/minimap.cpp
+++ b/src/client/minimap.cpp
@@ -581,8 +581,8 @@ void Minimap::drawMinimap()
const u32 size = 0.25 * screensize.Y;
drawMinimap(core::rect<s32>(
- screensize.X - size - 10, 10,
- screensize.X - 10, size + 10));
+ screensize.X - size * 2 - 10, 10,
+ screensize.X - size - 10, size + 10));
}
void Minimap::drawMinimap(core::rect<s32> rect) {
diff --git a/src/client/render/core.cpp b/src/client/render/core.cpp
index 55cc4e490..9927e2589 100644
--- a/src/client/render/core.cpp
+++ b/src/client/render/core.cpp
@@ -18,12 +18,16 @@ with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
+#include <iostream>
#include "core.h"
#include "client/camera.h"
#include "client/client.h"
#include "client/clientmap.h"
#include "client/hud.h"
#include "client/minimap.h"
+#include "client/content_cao.h"
+#include "mapblock.h"
+#include "mapsector.h"
#include "client/shadows/dynamicshadowsrender.h"
RenderingCore::RenderingCore(IrrlichtDevice *_device, Client *_client, Hud *_hud)
@@ -75,6 +79,16 @@ void RenderingCore::draw(video::SColor _skycolor, bool _show_hud, bool _show_min
show_minimap = _show_minimap;
draw_wield_tool = _draw_wield_tool;
draw_crosshair = _draw_crosshair;
+ draw_entity_esp = g_settings->getBool("enable_entity_esp");
+ draw_entity_tracers = g_settings->getBool("enable_entity_tracers");
+ draw_player_esp = g_settings->getBool("enable_player_esp");
+ draw_player_tracers = g_settings->getBool("enable_player_tracers");
+ draw_node_esp = g_settings->getBool("enable_node_esp");
+ draw_node_tracers = g_settings->getBool("enable_node_tracers");
+ v3f entity_color = g_settings->getV3F("entity_esp_color");
+ v3f player_color = g_settings->getV3F("player_esp_color");
+ entity_esp_color = video::SColor(255, entity_color.X, entity_color.Y, entity_color.Z);
+ player_esp_color = video::SColor(255, player_color.X, player_color.Y, player_color.Z);
if (shadow_renderer) {
// This is necessary to render shadows for animations correctly
@@ -86,6 +100,79 @@ void RenderingCore::draw(video::SColor _skycolor, bool _show_hud, bool _show_min
drawAll();
}
+void RenderingCore::drawTracersAndESP()
+{
+ ClientEnvironment &env = client->getEnv();
+ Camera *camera = client->getCamera();
+
+ v3f camera_offset = intToFloat(camera->getOffset(), BS);
+
+ v3f eye_pos = (camera->getPosition() + camera->getDirection() - camera_offset);
+
+ video::SMaterial material, oldmaterial;
+ oldmaterial = driver->getMaterial2D();
+ material.setFlag(video::EMF_LIGHTING, false);
+ material.setFlag(video::EMF_BILINEAR_FILTER, false);
+ material.setFlag(video::EMF_ZBUFFER, false);
+ material.setFlag(video::EMF_ZWRITE_ENABLE, false);
+ driver->setMaterial(material);
+
+ if (draw_entity_esp || draw_entity_tracers || draw_player_esp || draw_player_tracers) {
+ auto allObjects = env.getAllActiveObjects();
+ for (auto &it : allObjects) {
+ ClientActiveObject *cao = it.second;
+ if (cao->isLocalPlayer() || cao->getParent())
+ continue;
+ GenericCAO *obj = dynamic_cast<GenericCAO *>(cao);
+ if (! obj)
+ continue;
+ bool is_player = obj->isPlayer();
+ bool draw_esp = is_player ? draw_player_esp : draw_entity_esp;
+ bool draw_tracers = is_player ? draw_player_tracers : draw_entity_tracers;
+ video::SColor color = is_player ? player_esp_color : entity_esp_color;
+ if (! (draw_esp || draw_tracers))
+ continue;
+ aabb3f box;
+ if (! obj->getSelectionBox(&box))
+ continue;
+ v3f pos = obj->getPosition() - camera_offset;
+ box.MinEdge += pos;
+ box.MaxEdge += pos;
+ if (draw_esp)
+ driver->draw3DBox(box, color);
+ if (draw_tracers)
+ driver->draw3DLine(eye_pos, box.getCenter(), color);
+ }
+ }
+ if (draw_node_esp || draw_node_tracers) {
+ Map &map = env.getMap();
+ std::vector<v3s16> positions;
+ map.listAllLoadedBlocks(positions);
+ for (v3s16 blockp : positions) {
+ MapBlock *block = map.getBlockNoCreate(blockp);
+ if (! block->mesh)
+ continue;
+ for (v3s16 p : block->mesh->esp_nodes) {
+ v3f pos = intToFloat(p, BS) - camera_offset;
+ MapNode node = map.getNode(p);
+ std::vector<aabb3f> boxes;
+ node.getSelectionBoxes(client->getNodeDefManager(), &boxes, node.getNeighbors(p, &map));
+ video::SColor color = client->getNodeDefManager()->get(node).minimap_color;
+ for (aabb3f box : boxes) {
+ box.MinEdge += pos;
+ box.MaxEdge += pos;
+ if (draw_node_esp)
+ driver->draw3DBox(box, color);
+ if (draw_node_tracers)
+ driver->draw3DLine(eye_pos, box.getCenter(), color);
+ }
+ }
+ }
+ }
+
+ driver->setMaterial(oldmaterial);
+}
+
void RenderingCore::draw3D()
{
smgr->drawAll();
@@ -97,6 +184,8 @@ void RenderingCore::draw3D()
return;
hud->drawBlockBounds();
hud->drawSelectionMesh();
+ if (draw_entity_esp || draw_entity_tracers || draw_player_esp || draw_player_tracers || draw_node_esp || draw_node_tracers)
+ drawTracersAndESP();
if (draw_wield_tool)
camera->drawWieldedTool();
}
diff --git a/src/client/render/core.h b/src/client/render/core.h
index cabfbbfad..0864f25bd 100644
--- a/src/client/render/core.h
+++ b/src/client/render/core.h
@@ -37,6 +37,14 @@ protected:
bool show_minimap;
bool draw_wield_tool;
bool draw_crosshair;
+ bool draw_entity_esp;
+ bool draw_entity_tracers;
+ bool draw_player_esp;
+ bool draw_player_tracers;
+ bool draw_node_esp;
+ bool draw_node_tracers;
+ video::SColor entity_esp_color;
+ video::SColor player_esp_color;
IrrlichtDevice *device;
video::IVideoDriver *driver;
@@ -57,6 +65,7 @@ protected:
virtual void beforeDraw() {}
virtual void drawAll() = 0;
+ void drawTracersAndESP();
void draw3D();
void drawHUD();
void drawPostFx();
diff --git a/src/client/renderingengine.cpp b/src/client/renderingengine.cpp
index 455d5e538..6ebcc784d 100644
--- a/src/client/renderingengine.cpp
+++ b/src/client/renderingengine.cpp
@@ -303,15 +303,14 @@ bool RenderingEngine::setWindowIcon()
#if defined(XORG_USED)
#if RUN_IN_PLACE
return setXorgWindowIconFromPath(
- porting::path_share + "/misc/" PROJECT_NAME "-xorg-icon-128.png");
+ porting::path_share + "/misc/dragonfire-xorg-icon-128.png");
#else
// We have semi-support for reading in-place data if we are
// compiled with RUN_IN_PLACE. Don't break with this and
// also try the path_share location.
return setXorgWindowIconFromPath(
- ICON_DIR "/hicolor/128x128/apps/" PROJECT_NAME ".png") ||
- setXorgWindowIconFromPath(porting::path_share + "/misc/" PROJECT_NAME
- "-xorg-icon-128.png");
+ ICON_DIR "/hicolor/128x128/apps/dragonfire.png") ||
+ setXorgWindowIconFromPath(porting::path_share + "/misc/dragonfire-xorg-icon-128.png");
#endif
#elif defined(_WIN32)
HWND hWnd; // Window handle