aboutsummaryrefslogtreecommitdiff
path: root/src/client
diff options
context:
space:
mode:
Diffstat (limited to 'src/client')
-rw-r--r--src/client/activeobjectmgr.cpp13
-rw-r--r--src/client/camera.cpp26
-rw-r--r--src/client/client.cpp191
-rw-r--r--src/client/client.h32
-rw-r--r--src/client/clientenvironment.cpp46
-rw-r--r--src/client/clientenvironment.h7
-rw-r--r--src/client/clientmap.cpp155
-rw-r--r--src/client/clientmap.h2
-rw-r--r--src/client/clientmedia.cpp10
-rw-r--r--src/client/clientobject.h51
-rw-r--r--src/client/clouds.cpp2
-rw-r--r--src/client/content_cao.cpp242
-rw-r--r--src/client/content_cao.h39
-rw-r--r--src/client/content_cso.cpp2
-rw-r--r--src/client/fontengine.cpp323
-rw-r--r--src/client/fontengine.h9
-rw-r--r--src/client/game.cpp706
-rw-r--r--src/client/gameui.cpp74
-rw-r--r--src/client/gameui.h24
-rw-r--r--src/client/guiscalingfilter.cpp85
-rw-r--r--src/client/guiscalingfilter.h8
-rw-r--r--src/client/hud.cpp39
-rw-r--r--src/client/hud.h2
-rw-r--r--src/client/localplayer.cpp475
-rw-r--r--src/client/localplayer.h23
-rw-r--r--src/client/mapblock_mesh.cpp5
-rw-r--r--src/client/mesh.cpp193
-rw-r--r--src/client/mesh_generator_thread.cpp39
-rw-r--r--src/client/minimap.cpp2
-rw-r--r--src/client/particles.cpp95
-rw-r--r--src/client/particles.h3
-rw-r--r--src/client/render/core.cpp2
-rw-r--r--src/client/render/plain.cpp8
-rw-r--r--src/client/renderingengine.cpp73
-rw-r--r--src/client/shader.cpp10
-rw-r--r--src/client/sky.cpp286
-rw-r--r--src/client/sky.h10
-rw-r--r--src/client/tile.cpp93
-rw-r--r--src/client/tile.h16
39 files changed, 1700 insertions, 1721 deletions
diff --git a/src/client/activeobjectmgr.cpp b/src/client/activeobjectmgr.cpp
index 4ed98d79b..82f3cb944 100644
--- a/src/client/activeobjectmgr.cpp
+++ b/src/client/activeobjectmgr.cpp
@@ -29,14 +29,16 @@ void ActiveObjectMgr::clear()
// delete active objects
for (auto &active_object : m_active_objects) {
delete active_object.second;
+ // Object must be marked as gone when children try to detach
+ active_object.second = nullptr;
}
+ m_active_objects.clear();
}
void ActiveObjectMgr::step(
float dtime, const std::function<void(ClientActiveObject *)> &f)
{
- g_profiler->avg("Client::ActiveObjectMgr: num of objects",
- m_active_objects.size());
+ g_profiler->avg("ActiveObjectMgr: CAO count [#]", m_active_objects.size());
for (auto &ao_it : m_active_objects) {
f(ao_it.second);
}
@@ -91,15 +93,16 @@ void ActiveObjectMgr::removeObject(u16 id)
void ActiveObjectMgr::getActiveObjects(const v3f &origin, f32 max_d,
std::vector<DistanceSortedActiveObject> &dest)
{
+ f32 max_d2 = max_d * max_d;
for (auto &ao_it : m_active_objects) {
ClientActiveObject *obj = ao_it.second;
- f32 d = (obj->getPosition() - origin).getLength();
+ f32 d2 = (obj->getPosition() - origin).getLengthSQ();
- if (d > max_d)
+ if (d2 > max_d2)
continue;
- dest.emplace_back(obj, d);
+ dest.emplace_back(obj, d2);
}
}
diff --git a/src/client/camera.cpp b/src/client/camera.cpp
index 1bbdb56ea..d1e76026d 100644
--- a/src/client/camera.cpp
+++ b/src/client/camera.cpp
@@ -99,9 +99,9 @@ bool Camera::successfullyCreated(std::string &error_message)
error_message.clear();
}
- if (g_settings->getBool("enable_client_modding")) {
+ if (m_client->modsLoaded())
m_client->getScript()->on_camera_ready(this);
- }
+
return error_message.empty();
}
@@ -412,7 +412,7 @@ void Camera::update(LocalPlayer* player, f32 frametime, f32 busytime, f32 tool_r
// Prevent camera positioned inside nodes
const NodeDefManager *nodemgr = m_client->ndef();
MapNode n = m_client->getEnv().getClientMap()
- .getNodeNoEx(floatToInt(my_cp, BS));
+ .getNode(floatToInt(my_cp, BS));
const ContentFeatures& features = nodemgr->get(n);
if (features.walkable) {
@@ -448,12 +448,26 @@ void Camera::update(LocalPlayer* player, f32 frametime, f32 busytime, f32 tool_r
if (m_camera_mode != CAMERA_MODE_FIRST)
m_camera_position = my_cp;
- // Get FOV
+ /*
+ * Apply server-sent FOV. If server doesn't enforce FOV,
+ * check for zoom and set to zoom FOV.
+ * Otherwise, default to m_cache_fov
+ */
+
f32 fov_degrees;
- // Disable zoom with zoom FOV = 0
- if (player->getPlayerControl().zoom && player->getZoomFOV() > 0.001f) {
+ PlayerFovSpec fov_spec = player->getFov();
+ if (fov_spec.fov > 0.0f) {
+ // If server-sent FOV is a multiplier, multiply
+ // it with m_cache_fov instead of overriding
+ if (fov_spec.is_multiplier)
+ fov_degrees = m_cache_fov * fov_spec.fov;
+ else
+ fov_degrees = fov_spec.fov;
+ } else if (player->getPlayerControl().zoom && player->getZoomFOV() > 0.001f) {
+ // Player requests zoom, apply zoom FOV
fov_degrees = player->getZoomFOV();
} else {
+ // Set to client's selected FOV
fov_degrees = m_cache_fov;
}
fov_degrees = rangelim(fov_degrees, 1.0f, 160.0f);
diff --git a/src/client/client.cpp b/src/client/client.cpp
index a4a379a73..caa3cc78c 100644
--- a/src/client/client.cpp
+++ b/src/client/client.cpp
@@ -108,30 +108,15 @@ Client::Client(
m_minimap = new Minimap(this);
}
m_cache_save_interval = g_settings->getU16("server_map_save_interval");
-
- m_modding_enabled = g_settings->getBool("enable_client_modding");
- // Only create the client script environment if client scripting is enabled by the
- // client.
- if (m_modding_enabled) {
- m_script = new ClientScripting(this);
- m_env.setScript(m_script);
- m_script->setEnv(&m_env);
- }
}
void Client::loadMods()
{
- // Don't load mods twice
- if (m_mods_loaded) {
- return;
- }
-
+ // Don't load mods twice.
// If client scripting is disabled by the client, don't load builtin or
// client-provided mods.
- if (!m_modding_enabled) {
- warningstream << "Client side scripting is disabled by client." << std::endl;
+ if (m_mods_loaded || !g_settings->getBool("enable_client_modding"))
return;
- }
// If client scripting is disabled by the server, don't load builtin or
// client-provided mods.
@@ -140,11 +125,13 @@ void Client::loadMods()
if (checkCSMRestrictionFlag(CSMRestrictionFlags::CSM_RF_LOAD_CLIENT_MODS)) {
warningstream << "Client-provided mod loading is disabled by server." <<
std::endl;
- // This line is needed because builtin is not loaded
- m_modding_enabled = false;
return;
}
+ m_script = new ClientScripting(this);
+ m_env.setScript(m_script);
+ m_script->setEnv(&m_env);
+
// Load builtin
scanModIntoMemory(BUILTIN_MOD_NAME, getBuiltinLuaPath());
m_script->loadModFromMemory(BUILTIN_MOD_NAME);
@@ -190,9 +177,15 @@ void Client::loadMods()
for (const ModSpec &mod : m_mods)
m_script->loadModFromMemory(mod.name);
+ // Mods are done loading. Unlock callbacks
+ m_mods_loaded = true;
+
// Run a callback when mods are loaded
m_script->on_mods_loaded();
- m_mods_loaded = true;
+ if (m_state == LC_Ready)
+ m_script->on_client_ready(m_env.getLocalPlayer());
+ if (m_camera)
+ m_script->on_camera_ready(m_camera);
}
bool Client::checkBuiltinIntegrity()
@@ -244,7 +237,7 @@ const ModSpec* Client::getModSpec(const std::string &modname) const
void Client::Stop()
{
m_shutdown = true;
- if (m_modding_enabled)
+ if (m_mods_loaded)
m_script->on_shutdown();
//request all client managed threads to stop
m_mesh_update_thread.stop();
@@ -254,7 +247,7 @@ void Client::Stop()
m_localdb->endSave();
}
- if (m_modding_enabled)
+ if (m_mods_loaded)
delete m_script;
}
@@ -371,7 +364,6 @@ void Client::step(float dtime)
*/
const float map_timer_and_unload_dtime = 5.25;
if(m_map_timer_and_unload_interval.step(dtime, map_timer_and_unload_dtime)) {
- ScopeProfiler sp(g_profiler, "Client: map timer and unload");
std::vector<v3s16> deleted_blocks;
m_env.getMap().timerUpdate(map_timer_and_unload_dtime,
g_settings->getFloat("client_unload_unused_data_timeout"),
@@ -480,6 +472,7 @@ void Client::step(float dtime)
*/
{
int num_processed_meshes = 0;
+ std::vector<v3s16> blocks_to_ack;
while (!m_mesh_update_thread.m_queue_out.empty())
{
num_processed_meshes++;
@@ -518,14 +511,18 @@ void Client::step(float dtime)
m_minimap->addBlock(r.p, minimap_mapblock);
if (r.ack_block_to_server) {
- /*
- Acknowledge block
- [0] u8 count
- [1] v3s16 pos_0
- */
- sendGotBlocks(r.p);
+ if (blocks_to_ack.size() == 255) {
+ sendGotBlocks(blocks_to_ack);
+ blocks_to_ack.clear();
+ }
+
+ blocks_to_ack.emplace_back(r.p);
}
}
+ if (blocks_to_ack.size() > 0) {
+ // Acknowledge block(s)
+ sendGotBlocks(blocks_to_ack);
+ }
if (num_processed_meshes > 0)
g_profiler->graphAdd("num_processed_meshes", num_processed_meshes);
@@ -558,8 +555,8 @@ void Client::step(float dtime)
if (count_after != count_before) {
// Do this every <interval> seconds after TOCLIENT_INVENTORY
// Reset the locally changed inventory to the authoritative inventory
- m_env.getLocalPlayer()->inventory = *m_inventory_from_server;
- m_inventory_updated = true;
+ player->inventory = *m_inventory_from_server;
+ m_update_wielded_item = true;
}
}
@@ -908,7 +905,7 @@ void writePlayerPos(LocalPlayer *myplayer, ClientMap *clientMap, NetworkPacket *
*pkt << fov << wanted_range;
}
-void Client::interact(u8 action, const PointedThing& pointed)
+void Client::interact(InteractAction action, const PointedThing& pointed)
{
if(m_state != LC_Ready) {
errorstream << "Client::interact() "
@@ -928,19 +925,12 @@ void Client::interact(u8 action, const PointedThing& pointed)
[5] u32 length of the next item (plen)
[9] serialized PointedThing
[9 + plen] player position information
- actions:
- 0: start digging (from undersurface) or use
- 1: stop digging (all parameters ignored)
- 2: digging completed
- 3: place block or item (to abovesurface)
- 4: use item
- 5: perform secondary action of item
*/
NetworkPacket pkt(TOSERVER_INTERACT, 1 + 2 + 0);
- pkt << action;
- pkt << (u16)getPlayerItem();
+ pkt << (u8)action;
+ pkt << myplayer->getWieldIndex();
std::ostringstream tmp_os(std::ios::binary);
pointed.serialize(tmp_os);
@@ -1074,10 +1064,13 @@ void Client::sendDeletedBlocks(std::vector<v3s16> &blocks)
Send(&pkt);
}
-void Client::sendGotBlocks(v3s16 block)
+void Client::sendGotBlocks(const std::vector<v3s16> &blocks)
{
- NetworkPacket pkt(TOSERVER_GOTBLOCKS, 1 + 6);
- pkt << (u8) 1 << block;
+ NetworkPacket pkt(TOSERVER_GOTBLOCKS, 1 + 6 * blocks.size());
+ pkt << (u8) blocks.size();
+ for (const v3s16 &block : blocks)
+ pkt << block;
+
Send(&pkt);
}
@@ -1200,7 +1193,7 @@ void Client::clearOutChatQueue()
}
void Client::sendChangePassword(const std::string &oldpassword,
- const std::string &newpassword)
+ const std::string &newpassword)
{
LocalPlayer *player = m_env.getLocalPlayer();
if (player == NULL)
@@ -1229,60 +1222,54 @@ void Client::sendRespawn()
void Client::sendReady()
{
NetworkPacket pkt(TOSERVER_CLIENT_READY,
- 1 + 1 + 1 + 1 + 2 + sizeof(char) * strlen(g_version_hash));
+ 1 + 1 + 1 + 1 + 2 + sizeof(char) * strlen(g_version_hash) + 2);
pkt << (u8) VERSION_MAJOR << (u8) VERSION_MINOR << (u8) VERSION_PATCH
<< (u8) 0 << (u16) strlen(g_version_hash);
pkt.putRawString(g_version_hash, (u16) strlen(g_version_hash));
+ pkt << (u16)FORMSPEC_API_VERSION;
Send(&pkt);
}
void Client::sendPlayerPos()
{
- LocalPlayer *myplayer = m_env.getLocalPlayer();
- if (!myplayer)
+ LocalPlayer *player = m_env.getLocalPlayer();
+ if (!player)
return;
ClientMap &map = m_env.getClientMap();
-
- u8 camera_fov = map.getCameraFov();
- u8 wanted_range = map.getControl().wanted_range;
-
- // Save bandwidth by only updating position when something changed
- if(myplayer->last_position == myplayer->getPosition() &&
- myplayer->last_speed == myplayer->getSpeed() &&
- myplayer->last_pitch == myplayer->getPitch() &&
- myplayer->last_yaw == myplayer->getYaw() &&
- myplayer->last_keyPressed == myplayer->keyPressed &&
- myplayer->last_camera_fov == camera_fov &&
- myplayer->last_wanted_range == wanted_range)
+ u8 camera_fov = map.getCameraFov();
+ u8 wanted_range = map.getControl().wanted_range;
+
+ // Save bandwidth by only updating position when
+ // player is not dead and something changed
+
+ // FIXME: This part causes breakages in mods like 3d_armor, and has been commented for now
+ // if (m_activeobjects_received && player->isDead())
+ // return;
+
+ if (
+ player->last_position == player->getPosition() &&
+ player->last_speed == player->getSpeed() &&
+ player->last_pitch == player->getPitch() &&
+ player->last_yaw == player->getYaw() &&
+ player->last_keyPressed == player->keyPressed &&
+ player->last_camera_fov == camera_fov &&
+ player->last_wanted_range == wanted_range)
return;
- myplayer->last_position = myplayer->getPosition();
- myplayer->last_speed = myplayer->getSpeed();
- myplayer->last_pitch = myplayer->getPitch();
- myplayer->last_yaw = myplayer->getYaw();
- myplayer->last_keyPressed = myplayer->keyPressed;
- myplayer->last_camera_fov = camera_fov;
- myplayer->last_wanted_range = wanted_range;
+ player->last_position = player->getPosition();
+ player->last_speed = player->getSpeed();
+ player->last_pitch = player->getPitch();
+ player->last_yaw = player->getYaw();
+ player->last_keyPressed = player->keyPressed;
+ player->last_camera_fov = camera_fov;
+ player->last_wanted_range = wanted_range;
NetworkPacket pkt(TOSERVER_PLAYERPOS, 12 + 12 + 4 + 4 + 4 + 1 + 1);
- writePlayerPos(myplayer, &map, &pkt);
-
- Send(&pkt);
-}
-
-void Client::sendPlayerItem(u16 item)
-{
- LocalPlayer *myplayer = m_env.getLocalPlayer();
- if (!myplayer)
- return;
-
- NetworkPacket pkt(TOSERVER_PLAYERITEM, 2);
-
- pkt << item;
+ writePlayerPos(player, &map, &pkt);
Send(&pkt);
}
@@ -1318,7 +1305,7 @@ MapNode Client::getNode(v3s16 p, bool *is_valid_position)
return {};
}
}
- return m_env.getMap().getNodeNoEx(p, is_valid_position);
+ return m_env.getMap().getNode(p, is_valid_position);
}
void Client::addNode(v3s16 p, MapNode n, bool remove_metadata)
@@ -1346,28 +1333,33 @@ void Client::setPlayerControl(PlayerControl &control)
player->control = control;
}
-void Client::selectPlayerItem(u16 item)
+void Client::setPlayerItem(u16 item)
{
- m_playeritem = item;
- m_inventory_updated = true;
- sendPlayerItem(item);
-}
+ m_env.getLocalPlayer()->setWieldIndex(item);
+ m_update_wielded_item = true;
-// Returns true if the inventory of the local player has been
-// updated from the server. If it is true, it is set to false.
-bool Client::getLocalInventoryUpdated()
-{
- bool updated = m_inventory_updated;
- m_inventory_updated = false;
- return updated;
+ NetworkPacket pkt(TOSERVER_PLAYERITEM, 2);
+ pkt << item;
+ Send(&pkt);
}
-// Copies the inventory of the local player to parameter
-void Client::getLocalInventory(Inventory &dst)
+// Returns true once after the inventory of the local player
+// has been updated from the server.
+bool Client::updateWieldedItem()
{
+ if (!m_update_wielded_item)
+ return false;
+
+ m_update_wielded_item = false;
+
LocalPlayer *player = m_env.getLocalPlayer();
assert(player);
- dst = player->inventory;
+ if (auto *list = player->inventory.getList("main"))
+ list->setModified(false);
+ if (auto *list = player->inventory.getList("hand"))
+ list->setModified(false);
+
+ return true;
}
Inventory* Client::getInventory(const InventoryLocation &loc)
@@ -1510,7 +1502,7 @@ void Client::typeChatMessage(const std::wstring &message)
return;
// If message was consumed by script API, don't send it to server
- if (m_modding_enabled && m_script->on_sending_message(wide_to_utf8(message)))
+ if (m_mods_loaded && m_script->on_sending_message(wide_to_utf8(message)))
return;
// Send to others
@@ -1706,9 +1698,8 @@ void Client::afterContentReceived()
m_state = LC_Ready;
sendReady();
- if (g_settings->getBool("enable_client_modding")) {
+ if (m_mods_loaded)
m_script->on_client_ready(m_env.getLocalPlayer());
- }
text = wgettext("Done!");
RenderingEngine::draw_load_screen(text, guienv, m_tsrc, 0, 100);
diff --git a/src/client/client.h b/src/client/client.h
index 312b8c87f..e3c931837 100644
--- a/src/client/client.h
+++ b/src/client/client.h
@@ -193,6 +193,7 @@ public:
void handleCommand_ActiveObjectRemoveAdd(NetworkPacket* pkt);
void handleCommand_ActiveObjectMessages(NetworkPacket* pkt);
void handleCommand_Movement(NetworkPacket* pkt);
+ void handleCommand_Fov(NetworkPacket *pkt);
void handleCommand_HP(NetworkPacket* pkt);
void handleCommand_Breath(NetworkPacket* pkt);
void handleCommand_MovePlayer(NetworkPacket* pkt);
@@ -227,12 +228,13 @@ public:
void handleCommand_SrpBytesSandB(NetworkPacket *pkt);
void handleCommand_FormspecPrepend(NetworkPacket *pkt);
void handleCommand_CSMRestrictionFlags(NetworkPacket *pkt);
+ void handleCommand_PlayerSpeed(NetworkPacket *pkt);
void ProcessData(NetworkPacket *pkt);
void Send(NetworkPacket* pkt);
- void interact(u8 action, const PointedThing& pointed);
+ void interact(InteractAction action, const PointedThing &pointed);
void sendNodemetaFields(v3s16 p, const std::string &formname,
const StringMap &fields);
@@ -271,20 +273,17 @@ public:
void setPlayerControl(PlayerControl &control);
- void selectPlayerItem(u16 item);
- u16 getPlayerItem() const
- { return m_playeritem; }
-
// Returns true if the inventory of the local player has been
// updated from the server. If it is true, it is set to false.
- bool getLocalInventoryUpdated();
- // Copies the inventory of the local player to parameter
- void getLocalInventory(Inventory &dst);
+ bool updateWieldedItem();
/* InventoryManager interface */
Inventory* getInventory(const InventoryLocation &loc) override;
void inventoryAction(InventoryAction *a) override;
+ // Send the item number 'item' as player item to the server
+ void setPlayerItem(u16 item);
+
const std::list<std::string> &getConnectedPlayerNames()
{
return m_env.getPlayerNames();
@@ -335,12 +334,14 @@ public:
// disconnect client when CSM failed.
const std::string &accessDeniedReason() const { return m_access_denied_reason; }
- bool itemdefReceived()
+ const bool itemdefReceived() const
{ return m_itemdef_received; }
- bool nodedefReceived()
+ const bool nodedefReceived() const
{ return m_nodedef_received; }
- bool mediaReceived()
+ const bool mediaReceived() const
{ return !m_media_downloader; }
+ const bool activeObjectsReceived() const
+ { return m_activeobjects_received; }
u16 getProtoVersion()
{ return m_proto_ver; }
@@ -399,7 +400,6 @@ public:
}
ClientScripting *getScript() { return m_script; }
- const bool moddingEnabled() const { return m_modding_enabled; }
const bool modsLoaded() const { return m_mods_loaded; }
void pushToEventQueue(ClientEvent *event);
@@ -454,8 +454,6 @@ private:
void Receive();
void sendPlayerPos();
- // Send the item number 'item' as player item to the server
- void sendPlayerItem(u16 item);
void deleteAuthData();
// helper method shared with clientpackethandler
@@ -465,7 +463,7 @@ private:
void promptConfirmRegistration(AuthMechanism chosen_auth_mechanism);
void startAuth(AuthMechanism chosen_auth_mechanism);
void sendDeletedBlocks(std::vector<v3s16> &blocks);
- void sendGotBlocks(v3s16 block);
+ void sendGotBlocks(const std::vector<v3s16> &blocks);
void sendRemovedSounds(std::vector<s32> &soundList);
// Helper function
@@ -506,8 +504,7 @@ private:
// If 0, server init hasn't been received yet.
u16 m_proto_ver = 0;
- u16 m_playeritem = 0;
- bool m_inventory_updated = false;
+ bool m_update_wielded_item = false;
Inventory *m_inventory_from_server = nullptr;
float m_inventory_from_server_age = 0.0f;
PacketCounter m_packetcounter;
@@ -545,6 +542,7 @@ private:
std::queue<ClientEvent *> m_client_event_queue;
bool m_itemdef_received = false;
bool m_nodedef_received = false;
+ bool m_activeobjects_received = false;
bool m_mods_loaded = false;
ClientMediaDownloader *m_media_downloader;
diff --git a/src/client/clientenvironment.cpp b/src/client/clientenvironment.cpp
index a788c93c2..5eb033302 100644
--- a/src/client/clientenvironment.cpp
+++ b/src/client/clientenvironment.cpp
@@ -47,8 +47,6 @@ ClientEnvironment::ClientEnvironment(ClientMap *map,
m_texturesource(texturesource),
m_client(client)
{
- char zero = 0;
- memset(attachement_parent_ids, zero, sizeof(attachement_parent_ids));
}
ClientEnvironment::~ClientEnvironment()
@@ -220,7 +218,7 @@ void ClientEnvironment::step(float dtime)
f32 post_factor = 1; // 1 hp per node/s
if (info.type == COLLISION_NODE) {
const ContentFeatures &f = m_client->ndef()->
- get(m_map->getNodeNoEx(info.node_p));
+ get(m_map->getNode(info.node_p));
// Determine fall damage multiplier
int addp = itemgroup_get(f.groups, "fall_damage_add_percent");
pre_factor = 1.0f + (float)addp / 100.0f;
@@ -250,7 +248,7 @@ void ClientEnvironment::step(float dtime)
MapNode node_at_lplayer(CONTENT_AIR, 0x0f, 0);
v3s16 p = lplayer->getLightPosition();
- node_at_lplayer = m_map->getNodeNoEx(p);
+ node_at_lplayer = m_map->getNode(p);
u16 light = getInteriorLight(node_at_lplayer, 0, m_client->ndef());
final_color_blend(&lplayer->light_color, light, day_night_ratio);
@@ -272,7 +270,7 @@ void ClientEnvironment::step(float dtime)
// Get node at head
v3s16 p = cao->getLightPosition();
- MapNode n = this->m_map->getNodeNoEx(p, &pos_ok);
+ MapNode n = this->m_map->getNode(p, &pos_ok);
if (pos_ok)
light = n.getLightBlend(day_night_ratio, m_client->ndef());
else
@@ -287,15 +285,14 @@ void ClientEnvironment::step(float dtime)
/*
Step and handle simple objects
*/
- g_profiler->avg("CEnv: num of simple objects", m_simple_objects.size());
+ g_profiler->avg("ClientEnv: CSO count [#]", m_simple_objects.size());
for (auto i = m_simple_objects.begin(); i != m_simple_objects.end();) {
- auto cur = i;
- ClientSimpleObject *simple = *cur;
+ ClientSimpleObject *simple = *i;
simple->step(dtime);
if(simple->m_to_be_removed) {
delete simple;
- i = m_simple_objects.erase(cur);
+ i = m_simple_objects.erase(i);
}
else {
++i;
@@ -353,7 +350,7 @@ u16 ClientEnvironment::addActiveObject(ClientActiveObject *object)
// Get node at head
v3s16 p = object->getLightPosition();
- MapNode n = m_map->getNodeNoEx(p, &pos_ok);
+ MapNode n = m_map->getNode(p, &pos_ok);
if (pos_ok)
light = n.getLightBlend(getDayNightRatio(), m_client->ndef());
else
@@ -392,7 +389,34 @@ void ClientEnvironment::addActiveObject(u16 id, u8 type,
<<std::endl;
}
- addActiveObject(obj);
+ u16 new_id = addActiveObject(obj);
+ // Object initialized:
+ if ((obj = getActiveObject(new_id))) {
+ // Final step is to update all children which are already known
+ // Data provided by GENERIC_CMD_SPAWN_INFANT
+ const auto &children = obj->getAttachmentChildIds();
+ for (auto c_id : children) {
+ if (auto *o = getActiveObject(c_id))
+ o->updateAttachments();
+ }
+ }
+}
+
+
+void ClientEnvironment::removeActiveObject(u16 id)
+{
+ // Get current attachment childs to detach them visually
+ std::unordered_set<int> attachment_childs;
+ if (auto *obj = getActiveObject(id))
+ attachment_childs = obj->getAttachmentChildIds();
+
+ m_ao_manager.removeObject(id);
+
+ // Perform a proper detach in Irrlicht
+ for (auto c_id : attachment_childs) {
+ if (ClientActiveObject *child = getActiveObject(c_id))
+ child->updateAttachments();
+ }
}
void ClientEnvironment::processActiveObjectMessage(u16 id, const std::string &data)
diff --git a/src/client/clientenvironment.h b/src/client/clientenvironment.h
index 4fa3f4848..864496a41 100644
--- a/src/client/clientenvironment.h
+++ b/src/client/clientenvironment.h
@@ -104,10 +104,7 @@ public:
u16 addActiveObject(ClientActiveObject *object);
void addActiveObject(u16 id, u8 type, const std::string &init_data);
- void removeActiveObject(u16 id)
- {
- m_ao_manager.removeObject(id);
- }
+ void removeActiveObject(u16 id);
void processActiveObjectMessage(u16 id, const std::string &data);
@@ -138,8 +135,6 @@ public:
std::vector<PointedThing> &objects
);
- u16 attachement_parent_ids[USHRT_MAX + 1];
-
const std::list<std::string> &getPlayerNames() { return m_player_names; }
void addPlayerName(const std::string &name) { m_player_names.push_back(name); }
void removePlayerName(const std::string &name) { m_player_names.remove(name); }
diff --git a/src/client/clientmap.cpp b/src/client/clientmap.cpp
index 969c55539..3e4ab2e94 100644
--- a/src/client/clientmap.cpp
+++ b/src/client/clientmap.cpp
@@ -63,14 +63,13 @@ ClientMap::ClientMap(
MapSector * ClientMap::emergeSector(v2s16 p2d)
{
// Check that it doesn't exist already
- try {
- return getSectorNoGenerate(p2d);
- } catch(InvalidPositionException &e) {
- }
+ MapSector *sector = getSectorNoGenerate(p2d);
- // Create a sector
- MapSector *sector = new MapSector(this, p2d, m_gamedef);
- m_sectors[p2d] = sector;
+ // Create it if it does not exist yet
+ if (!sector) {
+ sector = new MapSector(this, p2d, m_gamedef);
+ m_sectors[p2d] = sector;
+ }
return sector;
}
@@ -116,7 +115,6 @@ void ClientMap::getBlocksInViewRange(v3s16 cam_pos_nodes,
void ClientMap::updateDrawList()
{
ScopeProfiler sp(g_profiler, "CM::updateDrawList()", SPT_AVG);
- g_profiler->add("CM::updateDrawList() count", 1);
for (auto &i : m_drawlist) {
MapBlock *block = i.second;
@@ -138,34 +136,26 @@ void ClientMap::updateDrawList()
v3s16 p_blocks_max;
getBlocksInViewRange(cam_pos_nodes, &p_blocks_min, &p_blocks_max);
- // Number of blocks in rendering range
- u32 blocks_in_range = 0;
+ // Number of blocks with mesh in rendering range
+ u32 blocks_in_range_with_mesh = 0;
// Number of blocks occlusion culled
u32 blocks_occlusion_culled = 0;
- // Number of blocks in rendering range but don't have a mesh
- u32 blocks_in_range_without_mesh = 0;
- // Blocks that had mesh that would have been drawn according to
- // rendering range (if max blocks limit didn't kick in)
- u32 blocks_would_have_drawn = 0;
- // Blocks that were drawn and had a mesh
- u32 blocks_drawn = 0;
- // Blocks which had a corresponding meshbuffer for this pass
- //u32 blocks_had_pass_meshbuf = 0;
- // Blocks from which stuff was actually drawn
- //u32 blocks_without_stuff = 0;
- // Distance to farthest drawn block
- float farthest_drawn = 0;
// No occlusion culling when free_move is on and camera is
// inside ground
bool occlusion_culling_enabled = true;
- if (g_settings->getBool("free_move")) {
- MapNode n = getNodeNoEx(cam_pos_nodes);
+ if (g_settings->getBool("free_move") && g_settings->getBool("noclip")) {
+ MapNode n = getNode(cam_pos_nodes);
if (n.getContent() == CONTENT_IGNORE ||
m_nodedef->get(n).solidness == 2)
occlusion_culling_enabled = false;
}
+ // Uncomment to debug occluded blocks in the wireframe mode
+ // TODO: Include this as a flag for an extended debugging setting
+ //if (occlusion_culling_enabled && m_control.show_wireframe)
+ // occlusion_culling_enabled = porting::getTimeS() & 1;
+
for (const auto &sector_it : m_sectors) {
MapSector *sector = sector_it.second;
v2s16 sp = sector->getPos();
@@ -185,11 +175,11 @@ void ClientMap::updateDrawList()
u32 sector_blocks_drawn = 0;
- for (auto block : sectorblocks) {
+ for (MapBlock *block : sectorblocks) {
/*
- Compare block position to camera position, skip
- if not seen on display
- */
+ Compare block position to camera position, skip
+ if not seen on display
+ */
if (block->mesh)
block->mesh->updateCameraOffset(m_camera_offset);
@@ -203,20 +193,20 @@ void ClientMap::updateDrawList()
camera_direction, camera_fov, range, &d))
continue;
- blocks_in_range++;
/*
Ignore if mesh doesn't exist
*/
- if (!block->mesh) {
- blocks_in_range_without_mesh++;
+ if (!block->mesh)
continue;
- }
+
+ blocks_in_range_with_mesh++;
/*
Occlusion culling
*/
- if (occlusion_culling_enabled && isBlockOccluded(block, cam_pos_nodes)) {
+ if ((!m_control.range_all && d > m_control.wanted_range * BS) ||
+ (occlusion_culling_enabled && isBlockOccluded(block, cam_pos_nodes))) {
blocks_occlusion_culled++;
continue;
}
@@ -224,36 +214,20 @@ void ClientMap::updateDrawList()
// This block is in range. Reset usage timer.
block->resetUsageTimer();
- // Limit block count in case of a sudden increase
- blocks_would_have_drawn++;
- if (blocks_drawn >= m_control.wanted_max_blocks &&
- !m_control.range_all &&
- d > m_control.wanted_range * BS)
- continue;
-
// Add to set
block->refGrab();
m_drawlist[block->getPos()] = block;
sector_blocks_drawn++;
- blocks_drawn++;
- if (d / BS > farthest_drawn)
- farthest_drawn = d / BS;
-
} // foreach sectorblocks
if (sector_blocks_drawn != 0)
m_last_drawn_sectors.insert(sp);
}
- g_profiler->avg("CM: blocks in range", blocks_in_range);
- g_profiler->avg("CM: blocks occlusion culled", blocks_occlusion_culled);
- if (blocks_in_range != 0)
- g_profiler->avg("CM: blocks in range without mesh (frac)",
- (float)blocks_in_range_without_mesh / blocks_in_range);
- g_profiler->avg("CM: blocks drawn", blocks_drawn);
- g_profiler->avg("CM: farthest drawn", farthest_drawn);
- g_profiler->avg("CM: wanted max blocks", m_control.wanted_max_blocks);
+ g_profiler->avg("MapBlock meshes in range [#]", blocks_in_range_with_mesh);
+ g_profiler->avg("MapBlocks occlusion culled [#]", blocks_occlusion_culled);
+ g_profiler->avg("MapBlocks drawn [#]", m_drawlist.size());
}
struct MeshBufList
@@ -306,9 +280,9 @@ void ClientMap::renderMap(video::IVideoDriver* driver, s32 pass)
std::string prefix;
if (pass == scene::ESNRP_SOLID)
- prefix = "CM: solid: ";
+ prefix = "renderMap(SOLID): ";
else
- prefix = "CM: transparent: ";
+ prefix = "renderMap(TRANSPARENT): ";
/*
This is called two times per frame, reset on the non-transparent one
@@ -317,14 +291,6 @@ void ClientMap::renderMap(video::IVideoDriver* driver, s32 pass)
m_last_drawn_sectors.clear();
/*
- Get time for measuring timeout.
-
- Measuring time is very useful for long delays when the
- machine is swapping a lot.
- */
- std::time_t time1 = time(0);
-
- /*
Get animation parameters
*/
float animation_time = m_client->getAnimationTime();
@@ -340,26 +306,15 @@ void ClientMap::renderMap(video::IVideoDriver* driver, s32 pass)
*/
u32 vertex_count = 0;
- u32 meshbuffer_count = 0;
// For limiting number of mesh animations per frame
u32 mesh_animate_count = 0;
- u32 mesh_animate_count_far = 0;
-
- // Blocks that were drawn and had a mesh
- u32 blocks_drawn = 0;
- // Blocks which had a corresponding meshbuffer for this pass
- u32 blocks_had_pass_meshbuf = 0;
- // Blocks from which stuff was actually drawn
- u32 blocks_without_stuff = 0;
+ //u32 mesh_animate_count_far = 0;
/*
Draw the selected MapBlocks
*/
- {
- ScopeProfiler sp(g_profiler, prefix + "drawing blocks", SPT_AVG);
-
MeshBufListList drawbufs;
for (auto &i : m_drawlist) {
@@ -381,15 +336,13 @@ void ClientMap::renderMap(video::IVideoDriver* driver, s32 pass)
assert(mapBlockMesh);
// Pretty random but this should work somewhat nicely
bool faraway = d >= BS * 50;
- //bool faraway = d >= m_control.wanted_range * BS;
if (mapBlockMesh->isAnimationForced() || !faraway ||
- mesh_animate_count_far < (m_control.range_all ? 200 : 50)) {
+ mesh_animate_count < (m_control.range_all ? 200 : 50)) {
+
bool animated = mapBlockMesh->animate(faraway, animation_time,
crack, daynight_ratio);
if (animated)
mesh_animate_count++;
- if (animated && faraway)
- mesh_animate_count_far++;
} else {
mapBlockMesh->decreaseAnimationForceTimer();
}
@@ -437,46 +390,33 @@ void ClientMap::renderMap(video::IVideoDriver* driver, s32 pass)
}
}
+ TimeTaker draw("Drawing mesh buffers");
+
// Render all layers in order
for (auto &lists : drawbufs.lists) {
- int timecheck_counter = 0;
for (MeshBufList &list : lists) {
- timecheck_counter++;
- if (timecheck_counter > 50) {
- timecheck_counter = 0;
- std::time_t time2 = time(0);
- if (time2 > time1 + 4) {
- infostream << "ClientMap::renderMap(): "
- "Rendering takes ages, returning."
- << std::endl;
- return;
- }
+ // Check and abort if the machine is swapping a lot
+ if (draw.getTimerTime() > 2000) {
+ infostream << "ClientMap::renderMap(): Rendering took >2s, " <<
+ "returning." << std::endl;
+ return;
}
-
driver->setMaterial(list.m);
for (scene::IMeshBuffer *buf : list.bufs) {
driver->drawMeshBuffer(buf);
vertex_count += buf->getVertexCount();
- meshbuffer_count++;
}
}
}
- } // ScopeProfiler
+ g_profiler->avg(prefix + "draw meshes [ms]", draw.stop(true));
// Log only on solid pass because values are the same
if (pass == scene::ESNRP_SOLID) {
- g_profiler->avg("CM: animated meshes", mesh_animate_count);
- g_profiler->avg("CM: animated meshes (far)", mesh_animate_count_far);
+ g_profiler->avg("renderMap(): animated meshes [#]", mesh_animate_count);
}
- g_profiler->avg(prefix + "vertices drawn", vertex_count);
- if (blocks_had_pass_meshbuf != 0)
- g_profiler->avg(prefix + "meshbuffers per block",
- (float)meshbuffer_count / (float)blocks_had_pass_meshbuf);
- if (blocks_drawn != 0)
- g_profiler->avg(prefix + "empty blocks (frac)",
- (float)blocks_without_stuff / blocks_drawn);
+ g_profiler->avg(prefix + "vertices drawn [#]", vertex_count);
}
static bool getVisibleBrightness(Map *map, const v3f &p0, v3f dir, float step,
@@ -497,7 +437,7 @@ static bool getVisibleBrightness(Map *map, const v3f &p0, v3f dir, float step,
// Check content nearly at camera position
{
v3s16 p = floatToInt(p0 /*+ dir * 3*BS*/, BS);
- MapNode n = map->getNodeNoEx(p);
+ MapNode n = map->getNode(p);
if(ndef->get(n).param_type == CPT_LIGHT &&
!ndef->get(n).sunlight_propagates)
allow_allowing_non_sunlight_propagates = true;
@@ -505,7 +445,7 @@ static bool getVisibleBrightness(Map *map, const v3f &p0, v3f dir, float step,
// If would start at CONTENT_IGNORE, start closer
{
v3s16 p = floatToInt(pf, BS);
- MapNode n = map->getNodeNoEx(p);
+ MapNode n = map->getNode(p);
if(n.getContent() == CONTENT_IGNORE){
float newd = 2*BS;
pf = p0 + dir * 2*newd;
@@ -519,7 +459,7 @@ static bool getVisibleBrightness(Map *map, const v3f &p0, v3f dir, float step,
step *= step_multiplier;
v3s16 p = floatToInt(pf, BS);
- MapNode n = map->getNodeNoEx(p);
+ MapNode n = map->getNode(p);
if (allow_allowing_non_sunlight_propagates && i == 0 &&
ndef->get(n).param_type == CPT_LIGHT &&
!ndef->get(n).sunlight_propagates) {
@@ -555,6 +495,7 @@ static bool getVisibleBrightness(Map *map, const v3f &p0, v3f dir, float step,
int ClientMap::getBackgroundBrightness(float max_d, u32 daylight_factor,
int oldvalue, bool *sunlight_seen_result)
{
+ ScopeProfiler sp(g_profiler, "CM::getBackgroundBrightness", SPT_AVG);
static v3f z_directions[50] = {
v3f(-100, 0, 0)
};
@@ -621,7 +562,7 @@ int ClientMap::getBackgroundBrightness(float max_d, u32 daylight_factor,
int ret = 0;
if(brightness_count == 0){
- MapNode n = getNodeNoEx(floatToInt(m_camera_position, BS));
+ MapNode n = getNode(floatToInt(m_camera_position, BS));
if(m_nodedef->get(n).param_type == CPT_LIGHT){
ret = decode_light(n.getLightBlend(daylight_factor, m_nodedef));
} else {
@@ -640,7 +581,7 @@ void ClientMap::renderPostFx(CameraMode cam_mode)
// Sadly ISceneManager has no "post effects" render pass, in that case we
// could just register for that and handle it in renderMap().
- MapNode n = getNodeNoEx(floatToInt(m_camera_position, BS));
+ MapNode n = getNode(floatToInt(m_camera_position, BS));
// - If the player is in a solid node, make everything black.
// - If the player is in liquid, draw a semi-transparent overlay.
diff --git a/src/client/clientmap.h b/src/client/clientmap.h
index 8402bb00d..172e3a1d6 100644
--- a/src/client/clientmap.h
+++ b/src/client/clientmap.h
@@ -31,8 +31,6 @@ struct MapDrawControl
bool range_all = false;
// Wanted drawing range
float wanted_range = 0.0f;
- // Maximum number of blocks to draw
- u32 wanted_max_blocks = 0;
// show a wire frame for debugging
bool show_wireframe = false;
};
diff --git a/src/client/clientmedia.cpp b/src/client/clientmedia.cpp
index e3ad92dbc..6da99bbbf 100644
--- a/src/client/clientmedia.cpp
+++ b/src/client/clientmedia.cpp
@@ -254,6 +254,16 @@ void ClientMediaDownloader::initialStep(Client *client)
fetch_request.post_data = required_hash_set;
fetch_request.extra_headers.emplace_back(
"Content-Type: application/octet-stream");
+
+ // Encapsulate possible IPv6 plain address in []
+ std::string addr = client->getAddressName();
+ if (addr.find(':', 0) != std::string::npos)
+ addr = '[' + addr + ']';
+ fetch_request.extra_headers.emplace_back(
+ std::string("Referer: minetest://") +
+ addr + ":" +
+ std::to_string(client->getServerAddress().getPort()));
+
httpfetch_async(fetch_request);
m_httpfetch_active++;
diff --git a/src/client/clientobject.h b/src/client/clientobject.h
index 9377d1e67..c673fff9a 100644
--- a/src/client/clientobject.h
+++ b/src/client/clientobject.h
@@ -22,6 +22,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "irrlichttypes_extrabloated.h"
#include "activeobject.h"
#include <unordered_map>
+#include <unordered_set>
+
class ClientEnvironment;
class ITextureSource;
@@ -37,51 +39,53 @@ public:
ClientActiveObject(u16 id, Client *client, ClientEnvironment *env);
virtual ~ClientActiveObject();
- virtual void addToScene(ITextureSource *tsrc) {};
+ virtual void addToScene(ITextureSource *tsrc) {}
virtual void removeFromScene(bool permanent) {}
// 0 <= light_at_pos <= LIGHT_SUN
- virtual void updateLight(u8 light_at_pos){}
- virtual void updateLightNoCheck(u8 light_at_pos){}
- virtual v3s16 getLightPosition(){return v3s16(0,0,0);}
+ virtual void updateLight(u8 light_at_pos) {}
+ virtual void updateLightNoCheck(u8 light_at_pos) {}
+ virtual v3s16 getLightPosition() { return v3s16(0, 0, 0); }
virtual bool getCollisionBox(aabb3f *toset) const { return false; }
virtual bool getSelectionBox(aabb3f *toset) const { return false; }
virtual bool collideWithObjects() const { return false; }
- virtual v3f getPosition(){ return v3f(0,0,0); }
- virtual float getYaw() const { return 0; }
+ virtual const v3f getPosition() const { return v3f(0.0f); }
virtual scene::ISceneNode *getSceneNode() { return NULL; }
virtual scene::IAnimatedMeshSceneNode *getAnimatedMeshSceneNode() { return NULL; }
- virtual bool isLocalPlayer() const {return false;}
+ virtual bool isLocalPlayer() const { return false; }
+
virtual ClientActiveObject *getParent() const { return nullptr; };
- virtual void setAttachments() {}
- virtual bool doShowSelectionBox(){return true;}
+ virtual const std::unordered_set<int> &getAttachmentChildIds() const
+ { static std::unordered_set<int> rv; return rv; }
+ virtual void updateAttachments() {};
+
+ virtual bool doShowSelectionBox() { return true; }
// Step object in time
- virtual void step(float dtime, ClientEnvironment *env){}
+ virtual void step(float dtime, ClientEnvironment *env) {}
// Process a message sent by the server side object
- virtual void processMessage(const std::string &data){}
+ virtual void processMessage(const std::string &data) {}
- virtual std::string infoText() {return "";}
- virtual std::string debugInfoText() {return "";}
+ virtual std::string infoText() { return ""; }
+ virtual std::string debugInfoText() { return ""; }
/*
This takes the return value of
ServerActiveObject::getClientInitializationData
*/
- virtual void initialize(const std::string &data){}
+ virtual void initialize(const std::string &data) {}
// Create a certain type of ClientActiveObject
- static ClientActiveObject* create(ActiveObjectType type, Client *client,
- ClientEnvironment *env);
+ static ClientActiveObject *create(ActiveObjectType type, Client *client,
+ ClientEnvironment *env);
// If returns true, punch will not be sent to the server
- virtual bool directReportPunch(v3f dir, const ItemStack *punchitem=NULL,
- float time_from_last_punch=1000000)
- { return false; }
+ virtual bool directReportPunch(v3f dir, const ItemStack *punchitem = nullptr,
+ float time_from_last_punch = 1000000) { return false; }
protected:
// Used for creating objects based on type
- typedef ClientActiveObject* (*Factory)(Client *client, ClientEnvironment *env);
+ typedef ClientActiveObject *(*Factory)(Client *client, ClientEnvironment *env);
static void registerType(u16 type, Factory f);
Client *m_client;
ClientEnvironment *m_env;
@@ -90,10 +94,10 @@ private:
static std::unordered_map<u16, Factory> m_types;
};
-struct DistanceSortedActiveObject
+class DistanceSortedActiveObject
{
+public:
ClientActiveObject *obj;
- f32 d;
DistanceSortedActiveObject(ClientActiveObject *a_obj, f32 a_d)
{
@@ -105,4 +109,7 @@ struct DistanceSortedActiveObject
{
return d < other.d;
}
+
+private:
+ f32 d;
};
diff --git a/src/client/clouds.cpp b/src/client/clouds.cpp
index 13051f32c..887a62f25 100644
--- a/src/client/clouds.cpp
+++ b/src/client/clouds.cpp
@@ -99,7 +99,7 @@ void Clouds::render()
//if(SceneManager->getSceneNodeRenderPass() != scene::ESNRP_SOLID)
return;
- ScopeProfiler sp(g_profiler, "Rendering of clouds, avg", SPT_AVG);
+ ScopeProfiler sp(g_profiler, "Clouds::render()", SPT_AVG);
int num_faces_to_draw = m_enable_3d ? 6 : 1;
diff --git a/src/client/content_cao.cpp b/src/client/content_cao.cpp
index 8643b5824..a15c1cc0b 100644
--- a/src/client/content_cao.cpp
+++ b/src/client/content_cao.cpp
@@ -17,36 +17,35 @@ with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
+#include "content_cao.h"
+#include <IBillboardSceneNode.h>
#include <ICameraSceneNode.h>
#include <ITextSceneNode.h>
-#include <IBillboardSceneNode.h>
#include <IMeshManipulator.h>
#include <IAnimatedMeshSceneNode.h>
-#include "content_cao.h"
-#include "util/numeric.h" // For IntervalLimiter & setPitchYawRoll
-#include "util/serialize.h"
-#include "util/basic_macros.h"
+#include "client/client.h"
+#include "client/renderingengine.h"
#include "client/sound.h"
#include "client/tile.h"
-#include "environment.h"
+#include "util/basic_macros.h"
+#include "util/numeric.h" // For IntervalLimiter & setPitchYawRoll
+#include "util/serialize.h"
+#include "camera.h" // CameraModes
#include "collision.h"
-#include "settings.h"
-#include "serialization.h" // For decompressZlib
-#include "clientobject.h"
-#include "mesh.h"
-#include "itemdef.h"
-#include "tool.h"
#include "content_cso.h"
-#include "sound.h"
-#include "nodedef.h"
+#include "environment.h"
+#include "itemdef.h"
#include "localplayer.h"
#include "map.h"
-#include "camera.h" // CameraModes
-#include "client.h"
+#include "mesh.h"
+#include "nodedef.h"
+#include "serialization.h" // For decompressZlib
+#include "settings.h"
+#include "sound.h"
+#include "tool.h"
#include "wieldmesh.h"
#include <algorithm>
#include <cmath>
-#include "client/renderingengine.h"
class Settings;
struct ToolCapabilities;
@@ -305,6 +304,7 @@ void TestCAO::processMessage(const std::string &data)
*/
#include "genericobject.h"
+#include "clientobject.h"
GenericCAO::GenericCAO(Client *client, ClientEnvironment *env):
ClientActiveObject(0, client, env)
@@ -372,6 +372,7 @@ void GenericCAO::processInitData(const std::string &data)
m_position = readV3F32(is);
m_rotation = readV3F32(is);
m_hp = readU16(is);
+
const u8 num_messages = readU8(is);
for (int i = 0; i < num_messages; i++) {
@@ -400,7 +401,7 @@ bool GenericCAO::getSelectionBox(aabb3f *toset) const
return true;
}
-v3f GenericCAO::getPosition()
+const v3f GenericCAO::getPosition() const
{
if (getParent() != nullptr) {
if (m_matrixnode)
@@ -443,7 +444,7 @@ scene::IAnimatedMeshSceneNode* GenericCAO::getAnimatedMeshSceneNode()
void GenericCAO::setChildrenVisible(bool toset)
{
- for (u16 cao_id : m_children) {
+ for (u16 cao_id : m_attachment_child_ids) {
GenericCAO *obj = m_env->getGenericCAO(cao_id);
if (obj) {
obj->setVisible(toset);
@@ -451,43 +452,81 @@ void GenericCAO::setChildrenVisible(bool toset)
}
}
-void GenericCAO::setAttachments()
+void GenericCAO::setAttachment(int parent_id, const std::string &bone, v3f position, v3f rotation)
{
+ int old_parent = m_attachment_parent_id;
+ m_attachment_parent_id = parent_id;
+ m_attachment_bone = bone;
+ m_attachment_position = position;
+ m_attachment_rotation = rotation;
+
+ ClientActiveObject *parent = m_env->getActiveObject(parent_id);
+
+ if (parent_id != old_parent) {
+ if (auto *o = m_env->getActiveObject(old_parent))
+ o->removeAttachmentChild(m_id);
+ if (parent)
+ parent->addAttachmentChild(m_id);
+ }
+
updateAttachments();
}
-ClientActiveObject* GenericCAO::getParent() const
+void GenericCAO::getAttachment(int *parent_id, std::string *bone, v3f *position,
+ v3f *rotation) const
+{
+ *parent_id = m_attachment_parent_id;
+ *bone = m_attachment_bone;
+ *position = m_attachment_position;
+ *rotation = m_attachment_rotation;
+}
+
+void GenericCAO::clearChildAttachments()
{
- ClientActiveObject *obj = NULL;
+ // Cannot use for-loop here: setAttachment() modifies 'm_attachment_child_ids'!
+ while (!m_attachment_child_ids.empty()) {
+ int child_id = *m_attachment_child_ids.begin();
- u16 attached_id = m_env->attachement_parent_ids[getId()];
+ if (ClientActiveObject *child = m_env->getActiveObject(child_id))
+ child->setAttachment(0, "", v3f(), v3f());
- if ((attached_id != 0) &&
- (attached_id != getId())) {
- obj = m_env->getActiveObject(attached_id);
+ removeAttachmentChild(child_id);
}
- return obj;
}
-void GenericCAO::removeFromScene(bool permanent)
+void GenericCAO::clearParentAttachment()
{
- // Should be true when removing the object permanently and false when refreshing (eg: updating visuals)
- if((m_env != NULL) && (permanent))
- {
- for (u16 ci : m_children) {
- if (m_env->attachement_parent_ids[ci] == getId()) {
- m_env->attachement_parent_ids[ci] = 0;
- }
- }
- m_children.clear();
+ if (m_attachment_parent_id)
+ setAttachment(0, "", m_attachment_position, m_attachment_rotation);
+ else
+ setAttachment(0, "", v3f(), v3f());
+}
- m_env->attachement_parent_ids[getId()] = 0;
+void GenericCAO::addAttachmentChild(int child_id)
+{
+ m_attachment_child_ids.insert(child_id);
+}
- LocalPlayer* player = m_env->getLocalPlayer();
- if (this == player->parent) {
- player->parent = nullptr;
- player->isAttached = false;
- }
+void GenericCAO::removeAttachmentChild(int child_id)
+{
+ m_attachment_child_ids.erase(child_id);
+}
+
+ClientActiveObject* GenericCAO::getParent() const
+{
+ return m_attachment_parent_id ? m_env->getActiveObject(m_attachment_parent_id) :
+ nullptr;
+}
+
+void GenericCAO::removeFromScene(bool permanent)
+{
+ // Should be true when removing the object permanently
+ // and false when refreshing (eg: updating visuals)
+ if (m_env && permanent) {
+ // The client does not know whether this object does re-appear to
+ // a later time, thus do not clear child attachments.
+
+ clearParentAttachment();
}
if (m_meshnode) {
@@ -711,6 +750,7 @@ void GenericCAO::addToScene(ITextureSource *tsrc)
updateTextures(m_current_texture_modifier);
scene::ISceneNode *node = getSceneNode();
+
if (node && !m_prop.nametag.empty() && !m_is_local_player) {
// Add nametag
v3f pos;
@@ -736,7 +776,7 @@ void GenericCAO::updateLight(u8 light_at_pos)
updateLightNoCheck(light_at_pos);
// Update light of all children
- for (u16 i : m_children) {
+ for (u16 i : m_attachment_child_ids) {
ClientActiveObject *obj = m_env->getActiveObject(i);
if (obj) {
obj->updateLightNoCheck(light_at_pos);
@@ -871,12 +911,8 @@ void GenericCAO::step(float dtime, ClientEnvironment *env)
// Attachments, part 1: All attached objects must be unparented first,
// or Irrlicht causes a segmentation fault
- for (auto ci = m_children.begin(); ci != m_children.end();) {
- if (m_env->attachement_parent_ids[*ci] != getId()) {
- ci = m_children.erase(ci);
- continue;
- }
- ClientActiveObject *obj = m_env->getActiveObject(*ci);
+ for (u16 cao_id : m_attachment_child_ids) {
+ ClientActiveObject *obj = m_env->getActiveObject(cao_id);
if (obj) {
scene::ISceneNode *child_node = obj->getSceneNode();
// The node's parent is always an IDummyTraformationSceneNode,
@@ -884,18 +920,16 @@ void GenericCAO::step(float dtime, ClientEnvironment *env)
if (child_node)
child_node->getParent()->setParent(m_smgr->getRootSceneNode());
}
- ++ci;
}
removeFromScene(false);
addToScene(m_client->tsrc());
// Attachments, part 2: Now that the parent has been refreshed, put its attachments back
- for (u16 cao_id : m_children) {
- // Get the object of the child
+ for (u16 cao_id : m_attachment_child_ids) {
ClientActiveObject *obj = m_env->getActiveObject(cao_id);
if (obj)
- obj->setAttachments();
+ obj->updateAttachments();
}
}
@@ -916,7 +950,6 @@ void GenericCAO::step(float dtime, ClientEnvironment *env)
{
LocalPlayer *player = m_env->getLocalPlayer();
player->overridePosition = getParent()->getPosition();
- m_env->getLocalPlayer()->parent = getParent();
}
} else {
rot_translator.translate(dtime);
@@ -960,7 +993,7 @@ void GenericCAO::step(float dtime, ClientEnvironment *env)
const NodeDefManager *ndef = m_client->ndef();
v3s16 p = floatToInt(getPosition() +
v3f(0.0f, (m_prop.collisionbox.MinEdge.Y - 0.5f) * BS, 0.0f), BS);
- MapNode n = m_env->getMap().getNodeNoEx(p);
+ MapNode n = m_env->getMap().getNode(p);
SimpleSoundSpec spec = ndef->get(n).sound_footstep;
// Reduce footstep gain, as non-local-player footsteps are
// somehow louder.
@@ -997,15 +1030,20 @@ void GenericCAO::step(float dtime, ClientEnvironment *env)
if (!getParent() && m_prop.automatic_face_movement_dir &&
(fabs(m_velocity.Z) > 0.001 || fabs(m_velocity.X) > 0.001)) {
-
float target_yaw = atan2(m_velocity.Z, m_velocity.X) * 180 / M_PI
+ m_prop.automatic_face_movement_dir_offset;
- float max_rotation_delta =
- dtime * m_prop.automatic_face_movement_max_rotation_per_sec;
+ float max_rotation_per_sec =
+ m_prop.automatic_face_movement_max_rotation_per_sec;
- wrappedApproachShortest(m_rotation.Y, target_yaw, max_rotation_delta, 360.f);
- rot_translator.val_current = m_rotation;
+ if (max_rotation_per_sec > 0) {
+ wrappedApproachShortest(m_rotation.Y, target_yaw,
+ dtime * max_rotation_per_sec, 360.f);
+ } else {
+ // Negative values of max_rotation_per_sec mean disabled.
+ m_rotation.Y = target_yaw;
+ }
+ rot_translator.val_current = m_rotation;
updateNodePos();
}
}
@@ -1057,6 +1095,7 @@ void GenericCAO::updateTexturePos()
}
}
+// Do not pass by reference, see header.
void GenericCAO::updateTextures(std::string mod)
{
ITextureSource *tsrc = m_client->tsrc();
@@ -1225,18 +1264,19 @@ void GenericCAO::updateTextures(std::string mod)
buf->getMaterial().AmbientColor = m_prop.colors[1];
buf->getMaterial().DiffuseColor = m_prop.colors[1];
buf->getMaterial().SpecularColor = m_prop.colors[1];
- setMeshColor(mesh, m_prop.colors[1]);
} else if (!m_prop.colors.empty()) {
buf->getMaterial().AmbientColor = m_prop.colors[0];
buf->getMaterial().DiffuseColor = m_prop.colors[0];
buf->getMaterial().SpecularColor = m_prop.colors[0];
- setMeshColor(mesh, m_prop.colors[0]);
}
buf->getMaterial().setFlag(video::EMF_TRILINEAR_FILTER, use_trilinear_filter);
buf->getMaterial().setFlag(video::EMF_BILINEAR_FILTER, use_bilinear_filter);
buf->getMaterial().setFlag(video::EMF_ANISOTROPIC_FILTER, use_anisotropic_filter);
}
+ // Set mesh color (only if lighting is disabled)
+ if (!m_prop.colors.empty() && m_glow < 0)
+ setMeshColor(mesh, m_prop.colors[0]);
}
}
}
@@ -1290,6 +1330,21 @@ void GenericCAO::updateBonePosition()
void GenericCAO::updateAttachments()
{
ClientActiveObject *parent = getParent();
+
+ m_attached_to_local = parent && parent->isLocalPlayer();
+
+ /*
+ Following cases exist:
+ m_attachment_parent_id == 0 && !parent
+ This object is not attached
+ m_attachment_parent_id != 0 && parent
+ This object is attached
+ m_attachment_parent_id != 0 && !parent
+ This object will be attached as soon the parent is known
+ m_attachment_parent_id == 0 && parent
+ Impossible case
+ */
+
if (!parent) { // Detach or don't attach
if (m_matrixnode) {
v3f old_pos = m_matrixnode->getAbsolutePosition();
@@ -1297,10 +1352,6 @@ void GenericCAO::updateAttachments()
getPosRotMatrix().setTranslation(old_pos);
m_matrixnode->updateAbsolutePosition();
}
- if (m_is_local_player) {
- LocalPlayer *player = m_env->getLocalPlayer();
- player->isAttached = false;
- }
}
else // Attach
{
@@ -1319,10 +1370,11 @@ void GenericCAO::updateAttachments()
getPosRotMatrix().setRotationDegrees(m_attachment_rotation);
m_matrixnode->updateAbsolutePosition();
}
- if (m_is_local_player) {
- LocalPlayer *player = m_env->getLocalPlayer();
- player->isAttached = true;
- }
+ }
+ if (m_is_local_player) {
+ LocalPlayer *player = m_env->getLocalPlayer();
+ player->isAttached = parent;
+ player->parent = parent;
}
}
@@ -1482,31 +1534,15 @@ void GenericCAO::processMessage(const std::string &data)
updateBonePosition();
} else if (cmd == GENERIC_CMD_ATTACH_TO) {
u16 parent_id = readS16(is);
- u16 &old_parent_id = m_env->attachement_parent_ids[getId()];
- if (parent_id != old_parent_id) {
- if (GenericCAO *old_parent = m_env->getGenericCAO(old_parent_id)) {
- old_parent->m_children.erase(std::remove(
- m_children.begin(), m_children.end(),
- getId()), m_children.end());
- }
- if (GenericCAO *new_parent = m_env->getGenericCAO(parent_id))
- new_parent->m_children.push_back(getId());
-
- old_parent_id = parent_id;
- }
+ std::string bone = deSerializeString(is);
+ v3f position = readV3F32(is);
+ v3f rotation = readV3F32(is);
- m_attachment_bone = deSerializeString(is);
- m_attachment_position = readV3F32(is);
- m_attachment_rotation = readV3F32(is);
+ setAttachment(parent_id, bone, position, rotation);
// localplayer itself can't be attached to localplayer
- if (!m_is_local_player) {
- m_attached_to_local = getParent() != NULL && getParent()->isLocalPlayer();
- // Objects attached to the local player should be hidden by default
+ if (!m_is_local_player)
m_is_visible = !m_attached_to_local;
- }
-
- updateAttachments();
} else if (cmd == GENERIC_CMD_PUNCHED) {
u16 result_hp = readU16(is);
@@ -1515,9 +1551,12 @@ void GenericCAO::processMessage(const std::string &data)
m_hp = result_hp;
+ if (m_is_local_player)
+ m_env->getLocalPlayer()->hp = m_hp;
+
if (damage > 0)
{
- if (m_hp <= 0)
+ if (m_hp == 0)
{
// TODO: Execute defined fast response
// As there is no definition, make a smoke puff
@@ -1534,6 +1573,14 @@ void GenericCAO::processMessage(const std::string &data)
updateTextures(m_current_texture_modifier + "^[brighten");
}
}
+
+ if (m_hp == 0) {
+ // Same as 'Server::DiePlayer'
+ clearParentAttachment();
+ // Same as 'ObjectRef::l_remove'
+ if (!m_is_player)
+ clearChildAttachments();
+ }
} else if (cmd == GENERIC_CMD_UPDATE_ARMOR_GROUPS) {
m_armor_groups.clear();
int armor_groups_size = readU16(is);
@@ -1555,13 +1602,10 @@ void GenericCAO::processMessage(const std::string &data)
}
} else if (cmd == GENERIC_CMD_SPAWN_INFANT) {
u16 child_id = readU16(is);
- u8 type = readU8(is);
+ u8 type = readU8(is); // maybe this will be useful later
+ (void)type;
- if (GenericCAO *childobj = m_env->getGenericCAO(child_id)) {
- childobj->processInitData(deSerializeLongString(is));
- } else {
- m_env->addActiveObject(child_id, type, deSerializeLongString(is));
- }
+ addAttachmentChild(child_id);
} else {
warningstream << FUNCTION_NAME
<< ": unknown command or outdated client \""
diff --git a/src/client/content_cao.h b/src/client/content_cao.h
index 3ce628d30..2c2d11077 100644
--- a/src/client/content_cao.h
+++ b/src/client/content_cao.h
@@ -102,10 +102,14 @@ private:
bool m_animation_loop = true;
// stores position and rotation for each bone name
std::unordered_map<std::string, core::vector2d<v3f>> m_bone_position;
+
+ int m_attachment_parent_id = 0;
+ std::unordered_set<int> m_attachment_child_ids;
std::string m_attachment_bone = "";
v3f m_attachment_position;
v3f m_attachment_rotation;
bool m_attached_to_local = false;
+
int m_anim_frame = 0;
int m_anim_num_frames = 1;
float m_anim_framelength = 0.2f;
@@ -122,8 +126,6 @@ private:
bool m_is_visible = false;
s8 m_glow = 0;
- std::vector<u16> m_children;
-
public:
GenericCAO(Client *client, ClientEnvironment *env);
@@ -152,13 +154,15 @@ public:
virtual bool getSelectionBox(aabb3f *toset) const;
- v3f getPosition();
+ const v3f getPosition() const;
- inline const v3f &getRotation()
+ void setPosition(const v3f &pos)
{
- return m_rotation;
+ pos_translator.val_current = pos;
}
+ inline const v3f &getRotation() const { return m_rotation; }
+
const bool isImmortal();
scene::ISceneNode *getSceneNode();
@@ -178,6 +182,12 @@ public:
return m_matrixnode->getRelativeTransformationMatrix();
}
+ inline const core::matrix4 &getAbsolutePosRotMatrix() const
+ {
+ assert(m_matrixnode);
+ return m_matrixnode->getAbsoluteTransformation();
+ }
+
inline f32 getStepHeight() const
{
return m_prop.stepheight;
@@ -199,10 +209,17 @@ public:
}
void setChildrenVisible(bool toset);
-
+ void setAttachment(int parent_id, const std::string &bone, v3f position, v3f rotation);
+ void getAttachment(int *parent_id, std::string *bone, v3f *position,
+ v3f *rotation) const;
+ void clearChildAttachments();
+ void clearParentAttachment();
+ void addAttachmentChild(int child_id);
+ void removeAttachmentChild(int child_id);
ClientActiveObject *getParent() const;
-
- void setAttachments();
+ const std::unordered_set<int> &getAttachmentChildIds() const
+ { return m_attachment_child_ids; }
+ void updateAttachments();
void removeFromScene(bool permanent);
@@ -225,8 +242,8 @@ public:
void updateTexturePos();
- // std::string copy is mandatory as mod can be a class member and there is a swap
- // on those class members... do NOT pass by reference
+ // ffs this HAS TO BE a string copy! See #5739 if you think otherwise
+ // Reason: updateTextures(m_previous_texture_modifier);
void updateTextures(std::string mod);
void updateAnimation();
@@ -235,8 +252,6 @@ public:
void updateBonePosition();
- void updateAttachments();
-
void processMessage(const std::string &data);
bool directReportPunch(v3f dir, const ItemStack *punchitem=NULL,
diff --git a/src/client/content_cso.cpp b/src/client/content_cso.cpp
index 04c503f44..f9641afbe 100644
--- a/src/client/content_cso.cpp
+++ b/src/client/content_cso.cpp
@@ -48,7 +48,7 @@ public:
/* Update brightness */
u8 light;
bool pos_ok;
- MapNode n = env->getMap().getNodeNoEx(floatToInt(pos, BS), &pos_ok);
+ MapNode n = env->getMap().getNode(floatToInt(pos, BS), &pos_ok);
light = pos_ok ? decode_light(n.getLightBlend(env->getDayNightRatio(),
env->getGameDef()->ndef()))
: 64;
diff --git a/src/client/fontengine.cpp b/src/client/fontengine.cpp
index 59e5bedee..858d6780e 100644
--- a/src/client/fontengine.cpp
+++ b/src/client/fontengine.cpp
@@ -23,9 +23,9 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "config.h"
#include "porting.h"
#include "filesys.h"
+#include "gettext.h"
#if USE_FREETYPE
-#include "gettext.h"
#include "irrlicht_changes/CGUITTFont.h"
#endif
@@ -55,36 +55,7 @@ FontEngine::FontEngine(Settings* main_settings, gui::IGUIEnvironment* env) :
assert(m_env != NULL); // pre-condition
assert(m_env->getSkin() != NULL); // pre-condition
- m_currentMode = FM_Simple;
-
-#if USE_FREETYPE
- if (g_settings->getBool("freetype")) {
- m_default_size[FM_Standard] = m_settings->getU16("font_size");
- m_default_size[FM_Fallback] = m_settings->getU16("fallback_font_size");
- m_default_size[FM_Mono] = m_settings->getU16("mono_font_size");
-
- if (is_yes(gettext("needs_fallback_font"))) {
- m_currentMode = FM_Fallback;
- }
- else {
- m_currentMode = FM_Standard;
- }
- }
-
- // having freetype but not using it is quite a strange case so we need to do
- // special handling for it
- if (m_currentMode == FM_Simple) {
- std::stringstream fontsize;
- fontsize << DEFAULT_FONT_SIZE;
- m_settings->setDefault("font_size", fontsize.str());
- m_settings->setDefault("mono_font_size", fontsize.str());
- }
-#endif
-
- m_default_size[FM_Simple] = m_settings->getU16("font_size");
- m_default_size[FM_SimpleMono] = m_settings->getU16("mono_font_size");
-
- updateSkin();
+ readSettings();
if (m_currentMode == FM_Standard) {
m_settings->registerChangedCallback("font_size", font_setting_changed, NULL);
@@ -129,32 +100,26 @@ irr::gui::IGUIFont* FontEngine::getFont(unsigned int font_size, FontMode mode)
{
if (mode == FM_Unspecified) {
mode = m_currentMode;
- }
- else if ((mode == FM_Mono) && (m_currentMode == FM_Simple)) {
- mode = FM_SimpleMono;
+ } else if (m_currentMode == FM_Simple) {
+ // Freetype disabled -> Force simple mode
+ mode = (mode == FM_Mono || mode == FM_SimpleMono) ?
+ FM_SimpleMono : FM_Simple;
}
- if (font_size == FONT_SIZE_UNSPECIFIED) {
+ // Fallback to default size
+ if (font_size == FONT_SIZE_UNSPECIFIED)
font_size = m_default_size[mode];
- }
-
- if ((font_size == m_lastSize) && (mode == m_lastMode)) {
- return m_lastFont;
- }
-
- if (m_font_cache[mode].find(font_size) == m_font_cache[mode].end()) {
- initFont(font_size, mode);
- }
- if (m_font_cache[mode].find(font_size) == m_font_cache[mode].end()) {
- return NULL;
+ const auto &cache = m_font_cache[mode];
+ if (cache.find(font_size) == cache.end()) {
+ if (mode == FM_Simple || mode == FM_SimpleMono)
+ initSimpleFont(font_size, mode);
+ else
+ initFont(font_size, mode);
}
- m_lastSize = font_size;
- m_lastMode = mode;
- m_lastFont = m_font_cache[mode][font_size];
-
- return m_font_cache[mode][font_size];
+ const auto &font = cache.find(font_size);
+ return font != cache.end() ? font->second : nullptr;
}
/******************************************************************************/
@@ -211,20 +176,17 @@ unsigned int FontEngine::getDefaultFontSize()
/******************************************************************************/
void FontEngine::readSettings()
{
-#if USE_FREETYPE
- if (g_settings->getBool("freetype")) {
+ if (USE_FREETYPE && g_settings->getBool("freetype")) {
m_default_size[FM_Standard] = m_settings->getU16("font_size");
m_default_size[FM_Fallback] = m_settings->getU16("fallback_font_size");
m_default_size[FM_Mono] = m_settings->getU16("mono_font_size");
- if (is_yes(gettext("needs_fallback_font"))) {
- m_currentMode = FM_Fallback;
- }
- else {
- m_currentMode = FM_Standard;
- }
+ m_currentMode = is_yes(gettext("needs_fallback_font")) ?
+ FM_Fallback : FM_Standard;
+ } else {
+ m_currentMode = FM_Simple;
}
-#endif
+
m_default_size[FM_Simple] = m_settings->getU16("font_size");
m_default_size[FM_SimpleMono] = m_settings->getU16("mono_font_size");
@@ -260,81 +222,55 @@ void FontEngine::updateFontCache()
{
/* the only font to be initialized is default one,
* all others are re-initialized on demand */
- initFont(m_default_size[m_currentMode], m_currentMode);
-
- /* reset font quick access */
- m_lastMode = FM_Unspecified;
- m_lastSize = 0;
- m_lastFont = NULL;
+ getFont(FONT_SIZE_UNSPECIFIED, FM_Unspecified);
}
/******************************************************************************/
void FontEngine::initFont(unsigned int basesize, FontMode mode)
{
+ assert(mode != FM_Unspecified);
+ assert(basesize != FONT_SIZE_UNSPECIFIED);
- std::string font_config_prefix;
-
- if (mode == FM_Unspecified) {
- mode = m_currentMode;
- }
+ if (m_font_cache[mode].find(basesize) != m_font_cache[mode].end())
+ return;
- switch (mode) {
- case FM_Standard:
- font_config_prefix = "";
- break;
+ std::string setting_prefix = "";
+ switch (mode) {
case FM_Fallback:
- font_config_prefix = "fallback_";
+ setting_prefix = "fallback_";
break;
-
case FM_Mono:
- font_config_prefix = "mono_";
- if (m_currentMode == FM_Simple)
- mode = FM_SimpleMono;
+ case FM_SimpleMono:
+ setting_prefix = "mono_";
break;
-
- case FM_Simple: /* Fallthrough */
- case FM_SimpleMono: /* Fallthrough */
default:
- font_config_prefix = "";
-
+ break;
}
- if (m_font_cache[mode].find(basesize) != m_font_cache[mode].end())
- return;
-
- if ((mode == FM_Simple) || (mode == FM_SimpleMono)) {
- initSimpleFont(basesize, mode);
- return;
+ u32 size = std::floor(RenderingEngine::getDisplayDensity() *
+ m_settings->getFloat("gui_scaling") * basesize);
+ if (size == 0) {
+ errorstream << "FontEngine: attempt to use font size 0" << std::endl;
+ errorstream << " display density: " << RenderingEngine::getDisplayDensity() << std::endl;
+ abort();
}
-#if USE_FREETYPE
- else {
- if (!is_yes(m_settings->get("freetype"))) {
- return;
- }
- u32 size = std::floor(RenderingEngine::getDisplayDensity() *
- m_settings->getFloat("gui_scaling") * basesize);
- if (size == 0) {
- errorstream << "FontEngine: attempt to use font size 0" << std::endl;
- errorstream << " display density: " << RenderingEngine::getDisplayDensity() << std::endl;
- abort();
- }
- u32 font_shadow = 0;
- u32 font_shadow_alpha = 0;
- try {
- font_shadow =
- g_settings->getU16(font_config_prefix + "font_shadow");
- } catch (SettingNotFoundException&) {}
- try {
- font_shadow_alpha =
- g_settings->getU16(font_config_prefix + "font_shadow_alpha");
- } catch (SettingNotFoundException&) {}
+ u16 font_shadow = 0;
+ u16 font_shadow_alpha = 0;
+ g_settings->getU16NoEx(setting_prefix + "font_shadow", font_shadow);
+ g_settings->getU16NoEx(setting_prefix + "font_shadow_alpha", font_shadow_alpha);
- std::string font_path = g_settings->get(font_config_prefix + "font_path");
+ std::string fallback_settings[] = {
+ m_settings->get(setting_prefix + "font_path"),
+ m_settings->get("fallback_font_path"),
+ m_settings->getDefault(setting_prefix + "font_path")
+ };
- irr::gui::IGUIFont* font = gui::CGUITTFont::createTTFont(m_env,
+#if USE_FREETYPE
+ for (const std::string &font_path : fallback_settings) {
+ irr::gui::IGUIFont *font = gui::CGUITTFont::createTTFont(m_env,
font_path.c_str(), size, true, true, font_shadow,
font_shadow_alpha);
@@ -343,93 +279,42 @@ void FontEngine::initFont(unsigned int basesize, FontMode mode)
return;
}
- if (font_config_prefix == "mono_") {
- const std::string &mono_font_path = m_settings->getDefault("mono_font_path");
-
- if (font_path != mono_font_path) {
- // try original mono font
- errorstream << "FontEngine: failed to load custom mono "
- "font: " << font_path << ", trying to fall back to "
- "original mono font" << std::endl;
-
- font = gui::CGUITTFont::createTTFont(m_env,
- mono_font_path.c_str(), size, true, true,
- font_shadow, font_shadow_alpha);
-
- if (font) {
- m_font_cache[mode][basesize] = font;
- return;
- }
- }
- } else {
- // try fallback font
- errorstream << "FontEngine: failed to load: " << font_path <<
- ", trying to fall back to fallback font" << std::endl;
-
- font_path = g_settings->get(font_config_prefix + "fallback_font_path");
-
- font = gui::CGUITTFont::createTTFont(m_env,
- font_path.c_str(), size, true, true, font_shadow,
- font_shadow_alpha);
-
- if (font) {
- m_font_cache[mode][basesize] = font;
- return;
- }
-
- const std::string &fallback_font_path = m_settings->getDefault("fallback_font_path");
-
- if (font_path != fallback_font_path) {
- // try original fallback font
- errorstream << "FontEngine: failed to load custom fallback "
- "font: " << font_path << ", trying to fall back to "
- "original fallback font" << std::endl;
-
- font = gui::CGUITTFont::createTTFont(m_env,
- fallback_font_path.c_str(), size, true, true,
- font_shadow, font_shadow_alpha);
+ errorstream << "FontEngine: Cannot load '" << font_path <<
+ "'. Trying to fall back to another path." << std::endl;
+ }
- if (font) {
- m_font_cache[mode][basesize] = font;
- return;
- }
- }
- }
- // give up
- errorstream << "FontEngine: failed to load freetype font: "
- << font_path << std::endl;
- errorstream << "minetest can not continue without a valid font. "
- "Please correct the 'font_path' setting or install the font "
- "file in the proper location" << std::endl;
- abort();
- }
+ // give up
+ errorstream << "minetest can not continue without a valid font. "
+ "Please correct the 'font_path' setting or install the font "
+ "file in the proper location" << std::endl;
+#else
+ errorstream << "FontEngine: Tried to load freetype fonts but Minetest was"
+ " not compiled with that library." << std::endl;
#endif
+ abort();
}
/** initialize a font without freetype */
void FontEngine::initSimpleFont(unsigned int basesize, FontMode mode)
{
- assert(mode == FM_Simple || mode == FM_SimpleMono); // pre-condition
+ assert(mode == FM_Simple || mode == FM_SimpleMono);
- std::string font_path;
- if (mode == FM_Simple) {
- font_path = m_settings->get("font_path");
- } else {
- font_path = m_settings->get("mono_font_path");
- }
+ const std::string &font_path = m_settings->get(
+ (mode == FM_SimpleMono) ? "mono_font_path" : "font_path");
+
+ size_t pos_dot = font_path.find_last_of('.');
std::string basename = font_path;
- std::string ending = font_path.substr(font_path.length() -4);
+ std::string ending = lowercase(font_path.substr(pos_dot));
if (ending == ".ttf") {
- errorstream << "FontEngine: Not trying to open \"" << font_path
- << "\" which seems to be a truetype font." << std::endl;
+ errorstream << "FontEngine: Found font \"" << font_path
+ << "\" but freetype is not available." << std::endl;
return;
}
- if ((ending == ".xml") || (ending == ".png")) {
- basename = font_path.substr(0,font_path.length()-4);
- }
+ if (ending == ".xml" || ending == ".png")
+ basename = font_path.substr(0, pos_dot);
if (basesize == FONT_SIZE_UNSPECIFIED)
basesize = DEFAULT_FONT_SIZE;
@@ -439,59 +324,35 @@ void FontEngine::initSimpleFont(unsigned int basesize, FontMode mode)
m_settings->getFloat("gui_scaling") *
basesize);
- irr::gui::IGUIFont* font = NULL;
+ irr::gui::IGUIFont *font = nullptr;
+ std::string font_extensions[] = { ".png", ".xml" };
- for(unsigned int offset = 0; offset < MAX_FONT_SIZE_OFFSET; offset++) {
+ // Find nearest matching font scale
+ // Does a "zig-zag motion" (positibe/negative), from 0 to MAX_FONT_SIZE_OFFSET
+ for (s32 zoffset = 0; zoffset < MAX_FONT_SIZE_OFFSET * 2; zoffset++) {
+ std::stringstream path;
- // try opening positive offset
- std::stringstream fontsize_plus_png;
- fontsize_plus_png << basename << "_" << (size + offset) << ".png";
+ // LSB to sign
+ s32 sign = (zoffset & 1) ? -1 : 1;
+ s32 offset = zoffset >> 1;
- if (fs::PathExists(fontsize_plus_png.str())) {
- font = m_env->getFont(fontsize_plus_png.str().c_str());
+ for (const std::string &ext : font_extensions) {
+ path.str(""); // Clear
+ path << basename << "_" << (size + offset * sign) << ext;
- if (font) {
- verbosestream << "FontEngine: found font: " << fontsize_plus_png.str() << std::endl;
- break;
- }
- }
-
- std::stringstream fontsize_plus_xml;
- fontsize_plus_xml << basename << "_" << (size + offset) << ".xml";
+ if (!fs::PathExists(path.str()))
+ continue;
- if (fs::PathExists(fontsize_plus_xml.str())) {
- font = m_env->getFont(fontsize_plus_xml.str().c_str());
+ font = m_env->getFont(path.str().c_str());
if (font) {
- verbosestream << "FontEngine: found font: " << fontsize_plus_xml.str() << std::endl;
+ verbosestream << "FontEngine: found font: " << path.str() << std::endl;
break;
}
}
- // try negative offset
- std::stringstream fontsize_minus_png;
- fontsize_minus_png << basename << "_" << (size - offset) << ".png";
-
- if (fs::PathExists(fontsize_minus_png.str())) {
- font = m_env->getFont(fontsize_minus_png.str().c_str());
-
- if (font) {
- verbosestream << "FontEngine: found font: " << fontsize_minus_png.str() << std::endl;
- break;
- }
- }
-
- std::stringstream fontsize_minus_xml;
- fontsize_minus_xml << basename << "_" << (size - offset) << ".xml";
-
- if (fs::PathExists(fontsize_minus_xml.str())) {
- font = m_env->getFont(fontsize_minus_xml.str().c_str());
-
- if (font) {
- verbosestream << "FontEngine: found font: " << fontsize_minus_xml.str() << std::endl;
- break;
- }
- }
+ if (font)
+ break;
}
// try name direct
@@ -503,8 +364,6 @@ void FontEngine::initSimpleFont(unsigned int basesize, FontMode mode)
}
}
- if (font) {
- font->grab();
+ if (font)
m_font_cache[mode][basesize] = font;
- }
}
diff --git a/src/client/fontengine.h b/src/client/fontengine.h
index a75618f86..62aa71897 100644
--- a/src/client/fontengine.h
+++ b/src/client/fontengine.h
@@ -112,15 +112,6 @@ private:
/** current font engine mode */
FontMode m_currentMode = FM_Standard;
- /** font mode of last request */
- FontMode m_lastMode;
-
- /** size of last request */
- unsigned int m_lastSize = 0;
-
- /** last font returned */
- irr::gui::IGUIFont* m_lastFont = nullptr;
-
DISABLE_CLASS_COPY(FontEngine);
};
diff --git a/src/client/game.cpp b/src/client/game.cpp
index 37680dda3..450eb4e32 100644
--- a/src/client/game.cpp
+++ b/src/client/game.cpp
@@ -55,7 +55,6 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "particles.h"
#include "porting.h"
#include "profiler.h"
-#include "quicktune_shortcutter.h"
#include "raycast.h"
#include "server.h"
#include "settings.h"
@@ -65,6 +64,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#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 "version.h"
#include "script/scripting_client.h"
@@ -184,7 +184,7 @@ struct LocalFormspecHandler : public TextDest
return;
}
- if (m_client && m_client->moddingEnabled())
+ if (m_client && m_client->modsLoaded())
m_client->getScript()->on_formspec_input(m_formname, fields);
}
@@ -413,6 +413,8 @@ class GameGlobalShaderConstantSetter : public IShaderConstantSetter
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;
CachedPixelShaderSetting<SamplerLayer_t> m_texture_flags;
@@ -445,6 +447,8 @@ public:
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_texture_flags("textureFlags"),
@@ -493,7 +497,7 @@ public:
sunlight.b };
m_day_light.set(dnc, services);
- u32 animation_timer = porting::getTimeMs() % 100000;
+ 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);
@@ -523,6 +527,18 @@ public:
m_minimap_yaw.set(minimap_yaw_array, services);
}
+ float camera_offset_array[3];
+ v3f offset = intToFloat(m_client->getCamera()->getOffset(), BS);
+#if (IRRLICHT_VERSION_MAJOR == 1 && IRRLICHT_VERSION_MINOR < 8)
+ camera_offset_array[0] = offset.X;
+ camera_offset_array[1] = offset.Y;
+ camera_offset_array[2] = offset.Z;
+#else
+ offset.getAs3Values(camera_offset_array);
+#endif
+ 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,
flags_tex = 2;
@@ -599,7 +615,6 @@ struct GameRunData {
bool dig_instantly;
bool digging_blocked;
bool left_punch;
- bool update_wielded_item_trigger;
bool reset_jump_timer;
float nodig_delay_timer;
float dig_time;
@@ -689,8 +704,8 @@ protected:
bool handleCallbacks();
void processQueues();
void updateProfilers(const RunStats &stats, const FpsControl &draw_times, f32 dtime);
- void addProfilerGraphs(const RunStats &stats, const FpsControl &draw_times, f32 dtime);
void updateStats(RunStats *stats, const FpsControl &draw_times, f32 dtime);
+ void updateProfilerGraphs(ProfilerGraph *graph);
// Input related
void processUserInput(f32 dtime);
@@ -744,15 +759,13 @@ protected:
bool look_for_object, const v3s16 &camera_offset);
void handlePointingAtNothing(const ItemStack &playerItem);
void handlePointingAtNode(const PointedThing &pointed,
- const ItemDefinition &playeritem_def, const ItemStack &playeritem,
- const ToolCapabilities &playeritem_toolcap, f32 dtime);
+ 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 ToolCapabilities &playeritem_toolcap, f32 dtime);
+ const ItemStack &selected_item, const ItemStack &hand_item, f32 dtime);
void updateFrame(ProfilerGraph *graph, RunStats *stats, f32 dtime,
const CameraOrientation &cam);
- void updateProfilerGraphs(ProfilerGraph *graph);
// Misc
void limitFps(FpsControl *fps_timings, f32 *dtime);
@@ -804,8 +817,9 @@ private:
void updateChat(f32 dtime, const v2u32 &screensize);
- bool nodePlacementPrediction(const ItemDefinition &playeritem_def,
- const ItemStack &playeritem, const v3s16 &nodepos, const v3s16 &neighbourpos);
+ 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];
InputHandler *input = nullptr;
@@ -827,10 +841,6 @@ private:
ChatBackend *chat_backend = nullptr;
- GUIFormSpecMenu *current_formspec = nullptr;
- //default: "". If other than "", empty show_formspec packets will only close the formspec when the formname matches
- std::string cur_formname;
-
EventManager *eventmgr = nullptr;
QuicktuneShortcutter *quicktune = nullptr;
bool registration_confirmation_shown = false;
@@ -841,7 +851,6 @@ private:
Camera *camera = nullptr;
Clouds *clouds = nullptr; // Free using ->Drop()
Sky *sky = nullptr; // Free using ->Drop()
- Inventory *local_inventory = nullptr;
Hud *hud = nullptr;
Minimap *mapper = nullptr;
@@ -955,7 +964,6 @@ Game::~Game()
delete server; // deleted first to stop all server threads
delete hud;
- delete local_inventory;
delete camera;
delete quicktune;
delete eventmgr;
@@ -1026,7 +1034,6 @@ bool Game::startup(bool *kill,
// Reinit runData
runData = GameRunData();
runData.time_from_last_punch = 10.0;
- runData.update_wielded_item_trigger = true;
m_game_ui->initFlags();
@@ -1089,11 +1096,13 @@ void Game::run()
previous_screen_size = current_screen_size;
}
- /* Must be called immediately after a device->run() call because it
- * uses device->getTimer()->getTime()
- */
+ // Calculate dtime =
+ // RenderingEngine::run() from this iteration
+ // + Sleep time until the wanted FPS are reached
limitFps(&draw_times, &dtime);
+ // Prepare render data for next iteration
+
updateStats(&stats, draw_times, dtime);
updateInteractTimers(dtime);
@@ -1143,8 +1152,9 @@ void Game::shutdown()
driver->setRenderTarget(irr::video::ERT_STEREO_BOTH_BUFFERS);
}
#endif
- if (current_formspec)
- current_formspec->quitMenu();
+ auto formspec = m_game_ui->getFormspecGUI();
+ if (formspec)
+ formspec->quitMenu();
showOverlayMessage(N_("Shutting down..."), 0, 0, false);
@@ -1163,10 +1173,7 @@ void Game::shutdown()
g_menumgr.deletingMenu(g_menumgr.m_stack.front());
}
- if (current_formspec) {
- current_formspec->drop();
- current_formspec = NULL;
- }
+ m_game_ui->deleteFormspec();
chat_backend->addMessage(L"", L"# Disconnected.");
chat_backend->addMessage(L"", L"");
@@ -1355,10 +1362,8 @@ bool Game::createClient(const std::string &playername,
scsf->setSky(sky);
skybox = NULL; // This is used/set later on in the main run loop
- local_inventory = new Inventory(itemdef_manager);
-
- if (!(sky && local_inventory)) {
- *error_message = "Memory allocation error (sky or local inventory)";
+ if (!sky) {
+ *error_message = "Memory allocation error sky";
errorstream << *error_message << std::endl;
return false;
}
@@ -1390,7 +1395,7 @@ bool Game::createClient(const std::string &playername,
player->hurt_tilt_timer = 0;
player->hurt_tilt_strength = 0;
- hud = new Hud(guienv, client, player, local_inventory);
+ hud = new Hud(guienv, client, player, &player->inventory);
if (!hud) {
*error_message = "Memory error: could not create HUD";
@@ -1545,7 +1550,7 @@ bool Game::connectToServer(const std::string &playername,
} else {
registration_confirmation_shown = true;
(new GUIConfirmRegistration(guienv, guienv->getRootGUIElement(), -1,
- &g_menumgr, client, playername, password, *address, connection_aborted))->drop();
+ &g_menumgr, client, playername, password, connection_aborted))->drop();
}
} else {
wait_time += dtime;
@@ -1733,7 +1738,8 @@ void Game::processQueues()
}
-void Game::updateProfilers(const RunStats &stats, const FpsControl &draw_times, f32 dtime)
+void Game::updateProfilers(const RunStats &stats, const FpsControl &draw_times,
+ f32 dtime)
{
float profiler_print_interval =
g_settings->getFloat("profiler_print_interval");
@@ -1741,7 +1747,7 @@ void Game::updateProfilers(const RunStats &stats, const FpsControl &draw_times,
if (profiler_print_interval == 0) {
print_to_log = false;
- profiler_print_interval = 5;
+ profiler_print_interval = 3;
}
if (profiler_interval.step(dtime, profiler_print_interval)) {
@@ -1754,25 +1760,14 @@ void Game::updateProfilers(const RunStats &stats, const FpsControl &draw_times,
g_profiler->clear();
}
- addProfilerGraphs(stats, draw_times, dtime);
-}
-
-
-void Game::addProfilerGraphs(const RunStats &stats,
- const FpsControl &draw_times, f32 dtime)
-{
- g_profiler->graphAdd("mainloop_other",
- draw_times.busy_time / 1000.0f - stats.drawtime / 1000.0f);
-
- if (draw_times.sleep_time != 0)
- g_profiler->graphAdd("mainloop_sleep", draw_times.sleep_time / 1000.0f);
- g_profiler->graphAdd("mainloop_dtime", dtime);
+ // Update update graphs
+ g_profiler->graphAdd("Time non-rendering [ms]",
+ draw_times.busy_time - stats.drawtime);
- g_profiler->add("Elapsed time", dtime);
- g_profiler->avg("FPS", 1. / dtime);
+ g_profiler->graphAdd("Sleep [ms]", draw_times.sleep_time);
+ g_profiler->graphAdd("FPS", 1.0f / dtime);
}
-
void Game::updateStats(RunStats *stats, const FpsControl &draw_times,
f32 dtime)
{
@@ -1853,8 +1848,9 @@ void Game::processUserInput(f32 dtime)
input->step(dtime);
#ifdef __ANDROID__
- if (current_formspec != NULL)
- current_formspec->getAndroidUIInput();
+ auto formspec = m_game_ui->getFormspecGUI();
+ if (formspec)
+ formspec->getAndroidUIInput();
else
handleAndroidChatInput();
#endif
@@ -1880,6 +1876,9 @@ void Game::processKeyInput()
} else if (wasKeyDown(KeyType::INVENTORY)) {
openInventory();
} else if (input->cancelPressed()) {
+#ifdef __ANDROID__
+ m_android_chat_open = false;
+#endif
if (!gui_chat_console->isOpenInhibited()) {
showPauseMenu();
}
@@ -1888,7 +1887,7 @@ void Game::processKeyInput()
} else if (wasKeyDown(KeyType::CMD)) {
openConsole(0.2, L"/");
} else if (wasKeyDown(KeyType::CMD_LOCAL)) {
- if (client->moddingEnabled())
+ if (client->modsLoaded())
openConsole(0.2, L".");
else
m_game_ui->showStatusText(wgettext("Client side scripting is disabled"));
@@ -1979,7 +1978,7 @@ void Game::processItemSelection(u16 *new_playeritem)
/* Item selection using mouse wheel
*/
- *new_playeritem = client->getPlayerItem();
+ *new_playeritem = player->getWieldIndex();
s32 wheel = input->getMouseWheel();
u16 max_item = MYMIN(PLAYER_INVENTORY_SIZE - 1,
@@ -2021,7 +2020,7 @@ void Game::dropSelectedItem(bool single_item)
a->count = single_item ? 1 : 0;
a->from_inv.setCurrentPlayer();
a->from_list = "main";
- a->from_i = client->getPlayerItem();
+ a->from_i = client->getEnv().getLocalPlayer()->getWieldIndex();
client->inventoryAction(a);
}
@@ -2044,13 +2043,14 @@ void Game::openInventory()
InventoryLocation inventoryloc;
inventoryloc.setCurrentPlayer();
- if (!client->moddingEnabled()
+ if (!client->modsLoaded()
|| !client->getScript()->on_inventory_open(fs_src->m_client->getInventory(inventoryloc))) {
TextDest *txt_dst = new TextDestPlayerInventory(client);
- GUIFormSpecMenu::create(current_formspec, client, &input->joystick, fs_src,
+ auto *&formspec = m_game_ui->updateFormspec("");
+ GUIFormSpecMenu::create(formspec, client, &input->joystick, fs_src,
txt_dst, client->getFormspecPrepend());
- cur_formname = "";
- current_formspec->setFormSpec(fs_src->getForm(), inventoryloc);
+
+ formspec->setFormSpec(fs_src->getForm(), inventoryloc);
}
}
@@ -2079,6 +2079,7 @@ void Game::handleAndroidChatInput()
if (m_android_chat_open && porting::getInputDialogState() == 0) {
std::string text = porting::getInputDialogValue();
client->typeChatMessage(utf8_to_wide(text));
+ m_android_chat_open = false;
}
}
#endif
@@ -2348,7 +2349,7 @@ void Game::toggleFullViewRange()
void Game::checkZoomEnabled()
{
LocalPlayer *player = client->getEnv().getLocalPlayer();
- if (player->getZoomFOV() < 0.001f)
+ if (player->getZoomFOV() < 0.001f || player->getFov().fov > 0.0f)
m_game_ui->showTranslatedStatusText("Zoom currently disabled by game or mod");
}
@@ -2479,6 +2480,13 @@ void Game::updatePlayerControl(const CameraOrientation &cam)
keypress_bits |= 1U << 4;
}
+ // autoforward if set: simulate "up" key
+ if (player->getPlayerSettings().continuous_forward &&
+ client->activeObjectsReceived() && !player->isDead()) {
+ control.up = true;
+ keypress_bits |= 1U << 0;
+ }
+
client->setPlayerControl(control);
player->keyPressed = keypress_bits;
@@ -2491,7 +2499,7 @@ inline void Game::step(f32 *dtime)
bool can_be_and_is_paused =
(simple_singleplayer_mode && g_menumgr.pausesGame());
- if (can_be_and_is_paused) { // This is for a singleplayer server
+ if (can_be_and_is_paused) { // This is for a singleplayer server
*dtime = 0; // No time passes
} else {
if (server)
@@ -2526,9 +2534,8 @@ void Game::handleClientEvent_None(ClientEvent *event, CameraOrientation *cam)
void Game::handleClientEvent_PlayerDamage(ClientEvent *event, CameraOrientation *cam)
{
- if (client->moddingEnabled()) {
+ if (client->modsLoaded())
client->getScript()->on_damage_taken(event->player_damage.amount);
- }
// Damage flash and hurt tilt are not used at death
if (client->getHP() > 0) {
@@ -2556,7 +2563,7 @@ void Game::handleClientEvent_Deathscreen(ClientEvent *event, CameraOrientation *
{
// If client scripting is enabled, deathscreen is handled by CSM code in
// builtin/client/init.lua
- if (client->moddingEnabled())
+ if (client->modsLoaded())
client->getScript()->on_death();
else
showDeathFormspec();
@@ -2571,9 +2578,10 @@ void Game::handleClientEvent_Deathscreen(ClientEvent *event, CameraOrientation *
void Game::handleClientEvent_ShowFormSpec(ClientEvent *event, CameraOrientation *cam)
{
if (event->show_formspec.formspec->empty()) {
- if (current_formspec && (event->show_formspec.formname->empty()
- || *(event->show_formspec.formname) == cur_formname)) {
- current_formspec->quitMenu();
+ 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 =
@@ -2581,9 +2589,9 @@ void Game::handleClientEvent_ShowFormSpec(ClientEvent *event, CameraOrientation
TextDestPlayerInventory *txt_dst =
new TextDestPlayerInventory(client, *(event->show_formspec.formname));
- GUIFormSpecMenu::create(current_formspec, client, &input->joystick,
+ auto *&formspec = m_game_ui->updateFormspec(*(event->show_formspec.formname));
+ GUIFormSpecMenu::create(formspec, client, &input->joystick,
fs_src, txt_dst, client->getFormspecPrepend());
- cur_formname = *(event->show_formspec.formname);
}
delete event->show_formspec.formspec;
@@ -2595,7 +2603,7 @@ void Game::handleClientEvent_ShowLocalFormSpec(ClientEvent *event, CameraOrienta
FormspecFormSource *fs_src = new FormspecFormSource(*event->show_formspec.formspec);
LocalFormspecHandler *txt_dst =
new LocalFormspecHandler(*event->show_formspec.formname, client);
- GUIFormSpecMenu::create(current_formspec, client, &input->joystick,
+ GUIFormSpecMenu::create(m_game_ui->getFormspecGUI(), client, &input->joystick,
fs_src, txt_dst, client->getFormspecPrepend());
delete event->show_formspec.formspec;
@@ -2840,19 +2848,10 @@ void Game::updateCamera(u32 busy_time, f32 dtime)
*/
ItemStack playeritem;
{
- InventoryList *mlist = local_inventory->getList("main");
-
- if (mlist && client->getPlayerItem() < mlist->getSize())
- playeritem = mlist->getItem(client->getPlayerItem());
- }
-
- if (playeritem.getDefinition(itemdef_manager).name.empty()) { // override the hand
- InventoryList *hlist = local_inventory->getList("hand");
- if (hlist)
- playeritem = hlist->getItem(0);
+ ItemStack selected, hand;
+ playeritem = player->getWieldedItem(&selected, &hand);
}
-
ToolCapabilities playeritem_toolcap =
playeritem.getToolCapabilities(itemdef_manager);
@@ -2933,7 +2932,7 @@ void Game::updateSound(f32 dtime)
soundmaker->step(dtime);
ClientMap &map = client->getEnv().getClientMap();
- MapNode n = map.getNodeNoEx(player->getFootstepNodePos());
+ MapNode n = map.getNode(player->getFootstepNodePos());
soundmaker->m_player_step_sound = nodedef_manager->get(n).sound_footstep;
}
@@ -2942,46 +2941,35 @@ void Game::processPlayerInteraction(f32 dtime, bool show_hud, bool show_debug)
{
LocalPlayer *player = client->getEnv().getLocalPlayer();
- ItemStack playeritem;
- {
- InventoryList *mlist = local_inventory->getList("main");
-
- if (mlist && client->getPlayerItem() < mlist->getSize())
- playeritem = mlist->getItem(client->getPlayerItem());
- }
-
- const ItemDefinition &playeritem_def =
- playeritem.getDefinition(itemdef_manager);
- InventoryList *hlist = local_inventory->getList("hand");
- const ItemDefinition &hand_def =
- hlist ? hlist->getItem(0).getDefinition(itemdef_manager) : itemdef_manager->get("");
-
v3f player_position = player->getPosition();
+ v3f player_eye_position = player->getEyePosition();
v3f camera_position = camera->getPosition();
v3f camera_direction = camera->getDirection();
v3s16 camera_offset = camera->getOffset();
+ if (camera->getCameraMode() == CAMERA_MODE_FIRST)
+ player_eye_position += player->eye_offset_first;
+ else
+ player_eye_position += player->eye_offset_third;
/*
Calculate what block is the crosshair pointing to
*/
- f32 d = playeritem_def.range; // max. distance
- f32 d_hand = hand_def.range;
+ ItemStack selected_item, hand_item;
+ const ItemStack &tool_item = player->getWieldedItem(&selected_item, &hand_item);
- if (d < 0 && d_hand >= 0)
- d = d_hand;
- else if (d < 0)
- d = 4.0;
+ const ItemDefinition &selected_def = selected_item.getDefinition(itemdef_manager);
+ f32 d = getToolRange(selected_def, hand_item.getDefinition(itemdef_manager));
core::line3d<f32> shootline;
if (camera->getCameraMode() != CAMERA_MODE_THIRD_FRONT) {
- shootline = core::line3d<f32>(camera_position,
- camera_position + camera_direction * BS * d);
+ shootline = core::line3d<f32>(player_eye_position,
+ player_eye_position + camera_direction * BS * d);
} else {
- // prevent player pointing anything in front-view
- shootline = core::line3d<f32>(camera_position,camera_position);
+ // prevent player pointing anything in front-view
+ shootline = core::line3d<f32>(camera_position, camera_position);
}
#ifdef HAVE_TOUCHSCREENGUI
@@ -2998,7 +2986,7 @@ void Game::processPlayerInteraction(f32 dtime, bool show_hud, bool show_debug)
#endif
PointedThing pointed = updatePointedThing(shootline,
- playeritem_def.liquids_pointable,
+ selected_def.liquids_pointable,
!runData.ldown_for_dig,
camera_offset);
@@ -3020,7 +3008,7 @@ void Game::processPlayerInteraction(f32 dtime, bool show_hud, bool show_debug)
if (runData.digging) {
if (input->getLeftReleased()) {
infostream << "Left button released"
- << " (stopped digging)" << std::endl;
+ << " (stopped digging)" << std::endl;
runData.digging = false;
} else if (pointed != runData.pointed_old) {
if (pointed.type == POINTEDTHING_NODE
@@ -3031,14 +3019,14 @@ void Game::processPlayerInteraction(f32 dtime, bool show_hud, bool show_debug)
// Don't reset.
} else {
infostream << "Pointing away from node"
- << " (stopped digging)" << std::endl;
+ << " (stopped digging)" << std::endl;
runData.digging = false;
hud->updateSelectionMesh(camera_offset);
}
}
if (!runData.digging) {
- client->interact(1, runData.pointed_old);
+ client->interact(INTERACT_STOP_DIGGING, runData.pointed_old);
client->setCrack(-1, v3s16(0, 0, 0));
runData.dig_time = 0.0;
}
@@ -3062,30 +3050,19 @@ void Game::processPlayerInteraction(f32 dtime, bool show_hud, bool show_debug)
else
runData.repeat_rightclick_timer = 0;
- if (playeritem_def.usable && input->getLeftState()) {
- if (input->getLeftClicked() && (!client->moddingEnabled()
- || !client->getScript()->on_item_use(playeritem, pointed)))
- client->interact(4, pointed);
+ if (selected_def.usable && input->getLeftState()) {
+ if (input->getLeftClicked() && (!client->modsLoaded()
+ || !client->getScript()->on_item_use(selected_item, pointed)))
+ client->interact(INTERACT_USE, pointed);
} else if (pointed.type == POINTEDTHING_NODE) {
- ToolCapabilities playeritem_toolcap =
- playeritem.getToolCapabilities(itemdef_manager);
- if (playeritem.name.empty()) {
- const ToolCapabilities *handToolcap = hlist
- ? &hlist->getItem(0).getToolCapabilities(itemdef_manager)
- : itemdef_manager->get("").tool_capabilities;
-
- if (handToolcap != nullptr)
- playeritem_toolcap = *handToolcap;
- }
- handlePointingAtNode(pointed, playeritem_def, playeritem,
- playeritem_toolcap, dtime);
+ handlePointingAtNode(pointed, selected_item, hand_item, dtime);
} else if (pointed.type == POINTEDTHING_OBJECT) {
- handlePointingAtObject(pointed, playeritem, player_position, show_debug);
+ handlePointingAtObject(pointed, tool_item, player_position, show_debug);
} else if (input->getLeftState()) {
// When button is held down in air, show continuous animation
runData.left_punch = true;
} else if (input->getRightClicked()) {
- handlePointingAtNothing(playeritem);
+ handlePointingAtNothing(selected_item);
}
runData.pointed_old = pointed;
@@ -3133,7 +3110,7 @@ PointedThing Game::updatePointedThing(
}
} else if (result.type == POINTEDTHING_NODE) {
// Update selection boxes
- MapNode n = map.getNodeNoEx(result.node_undersurface);
+ MapNode n = map.getNode(result.node_undersurface);
std::vector<aabb3f> boxes;
n.getSelectionBoxes(nodedef, &boxes,
n.getNeighbors(result.node_undersurface, &map));
@@ -3160,12 +3137,12 @@ PointedThing Game::updatePointedThing(
v3s16 p = floatToInt(pf, BS);
// Get selection mesh light level
- MapNode n = map.getNodeNoEx(p);
+ MapNode n = map.getNode(p);
u16 node_light = getInteriorLight(n, -1, nodedef);
u16 light_level = node_light;
for (const v3s16 &dir : g_6dirs) {
- n = map.getNodeNoEx(p + dir);
+ n = map.getNode(p + dir);
node_light = getInteriorLight(n, -1, nodedef);
if (node_light > light_level)
light_level = node_light;
@@ -3197,13 +3174,12 @@ void Game::handlePointingAtNothing(const ItemStack &playerItem)
infostream << "Right Clicked in Air" << std::endl;
PointedThing fauxPointed;
fauxPointed.type = POINTEDTHING_NOTHING;
- client->interact(5, fauxPointed);
+ client->interact(INTERACT_ACTIVATE, fauxPointed);
}
void Game::handlePointingAtNode(const PointedThing &pointed,
- const ItemDefinition &playeritem_def, const ItemStack &playeritem,
- const ToolCapabilities &playeritem_toolcap, f32 dtime)
+ const ItemStack &selected_item, const ItemStack &hand_item, f32 dtime)
{
v3s16 nodepos = pointed.node_undersurface;
v3s16 neighbourpos = pointed.node_abovesurface;
@@ -3217,7 +3193,7 @@ void Game::handlePointingAtNode(const PointedThing &pointed,
if (runData.nodig_delay_timer <= 0.0 && input->getLeftState()
&& !runData.digging_blocked
&& client->checkPrivilege("interact")) {
- handleDigging(pointed, nodepos, playeritem_toolcap, dtime);
+ handleDigging(pointed, nodepos, selected_item, hand_item, dtime);
}
// This should be done after digging handling
@@ -3227,7 +3203,7 @@ void Game::handlePointingAtNode(const PointedThing &pointed,
m_game_ui->setInfoText(unescape_translate(utf8_to_wide(
meta->getString("infotext"))));
} else {
- MapNode n = map.getNodeNoEx(nodepos);
+ MapNode n = map.getNode(nodepos);
if (nodedef_manager->get(n).tiledef[0].name == "unknown_node.png") {
m_game_ui->setInfoText(L"Unknown node: " +
@@ -3241,213 +3217,219 @@ void Game::handlePointingAtNode(const PointedThing &pointed,
runData.repeat_rightclick_timer = 0;
infostream << "Ground right-clicked" << std::endl;
- if (meta && !meta->getString("formspec").empty() && !random_input
- && !isKeyDown(KeyType::SNEAK)) {
- // Report right click to server
- if (nodedef_manager->get(map.getNodeNoEx(nodepos)).rightclickable) {
- client->interact(3, pointed);
- }
-
- infostream << "Launching custom inventory view" << std::endl;
-
- InventoryLocation inventoryloc;
- inventoryloc.setNodeMeta(nodepos);
+ camera->setDigging(1); // right click animation (always shown for feedback)
- NodeMetadataFormSource *fs_src = new NodeMetadataFormSource(
- &client->getEnv().getClientMap(), nodepos);
- TextDest *txt_dst = new TextDestNodeMetadata(nodepos, client);
+ soundmaker->m_player_rightpunch_sound = SimpleSoundSpec();
- GUIFormSpecMenu::create(current_formspec, client, &input->joystick, fs_src,
- txt_dst, client->getFormspecPrepend());
- cur_formname.clear();
+ // If the wielded item has node placement prediction,
+ // make that happen
+ // And also set the sound and send the interact
+ // But first check for meta formspec and rightclickable
+ auto &def = selected_item.getDefinition(itemdef_manager);
+ bool placed = nodePlacement(def, selected_item, nodepos, neighbourpos,
+ pointed, meta);
- current_formspec->setFormSpec(meta->getString("formspec"), inventoryloc);
- } else {
- // Report right click to server
-
- camera->setDigging(1); // right click animation (always shown for feedback)
-
- // If the wielded item has node placement prediction,
- // make that happen
- bool placed = nodePlacementPrediction(playeritem_def, playeritem, nodepos,
- neighbourpos);
-
- if (placed) {
- // Report to server
- client->interact(3, pointed);
- // Read the sound
- soundmaker->m_player_rightpunch_sound =
- playeritem_def.sound_place;
-
- if (client->moddingEnabled())
- client->getScript()->on_placenode(pointed, playeritem_def);
- } else {
- soundmaker->m_player_rightpunch_sound =
- SimpleSoundSpec();
-
- if (playeritem_def.node_placement_prediction.empty() ||
- nodedef_manager->get(map.getNodeNoEx(nodepos)).rightclickable) {
- client->interact(3, pointed); // Report to server
- } else {
- soundmaker->m_player_rightpunch_sound =
- playeritem_def.sound_place_failed;
- }
- }
- }
+ if (placed && client->modsLoaded())
+ client->getScript()->on_placenode(pointed, def);
}
}
-bool Game::nodePlacementPrediction(const ItemDefinition &playeritem_def,
- const ItemStack &playeritem, const v3s16 &nodepos, const v3s16 &neighbourpos)
+bool Game::nodePlacement(const ItemDefinition &selected_def,
+ const ItemStack &selected_item, const v3s16 &nodepos, const v3s16 &neighbourpos,
+ const PointedThing &pointed, const NodeMetadata *meta)
{
- std::string prediction = playeritem_def.node_placement_prediction;
+ std::string prediction = selected_def.node_placement_prediction;
const NodeDefManager *nodedef = client->ndef();
ClientMap &map = client->getEnv().getClientMap();
MapNode node;
bool is_valid_position;
- node = map.getNodeNoEx(nodepos, &is_valid_position);
- if (!is_valid_position)
+ node = map.getNode(nodepos, &is_valid_position);
+ if (!is_valid_position) {
+ soundmaker->m_player_rightpunch_sound = selected_def.sound_place_failed;
+ return false;
+ }
+
+ // formspec in meta
+ if (meta && !meta->getString("formspec").empty() && !random_input
+ && !isKeyDown(KeyType::SNEAK)) {
+ // on_rightclick callbacks are called anyway
+ if (nodedef_manager->get(map.getNode(nodepos)).rightclickable)
+ client->interact(INTERACT_PLACE, pointed);
+
+ infostream << "Launching custom inventory view" << std::endl;
+
+ InventoryLocation inventoryloc;
+ inventoryloc.setNodeMeta(nodepos);
+
+ NodeMetadataFormSource *fs_src = new NodeMetadataFormSource(
+ &client->getEnv().getClientMap(), nodepos);
+ TextDest *txt_dst = new TextDestNodeMetadata(nodepos, client);
+
+ auto *&formspec = m_game_ui->updateFormspec("");
+ GUIFormSpecMenu::create(formspec, client, &input->joystick, fs_src,
+ txt_dst, client->getFormspecPrepend());
+
+ formspec->setFormSpec(meta->getString("formspec"), inventoryloc);
return false;
+ }
+
+ // on_rightclick callback
+ if (prediction.empty() || (nodedef->get(node).rightclickable &&
+ !isKeyDown(KeyType::SNEAK))) {
+ // Report to server
+ client->interact(INTERACT_PLACE, pointed);
+ return false;
+ }
- if (!prediction.empty() && !nodedef->get(node).rightclickable) {
- verbosestream << "Node placement prediction for "
- << playeritem_def.name << " is "
- << prediction << std::endl;
- v3s16 p = neighbourpos;
-
- // Place inside node itself if buildable_to
- MapNode n_under = map.getNodeNoEx(nodepos, &is_valid_position);
- if (is_valid_position)
- {
- if (nodedef->get(n_under).buildable_to)
- p = nodepos;
- else {
- node = map.getNodeNoEx(p, &is_valid_position);
- if (is_valid_position &&!nodedef->get(node).buildable_to)
- return false;
+ verbosestream << "Node placement prediction for "
+ << selected_def.name << " is "
+ << prediction << std::endl;
+ v3s16 p = neighbourpos;
+
+ // Place inside node itself if buildable_to
+ MapNode n_under = map.getNode(nodepos, &is_valid_position);
+ if (is_valid_position) {
+ if (nodedef->get(n_under).buildable_to) {
+ p = nodepos;
+ } else {
+ node = map.getNode(p, &is_valid_position);
+ if (is_valid_position && !nodedef->get(node).buildable_to) {
+ // Report to server
+ client->interact(INTERACT_PLACE, pointed);
+ return false;
}
}
+ }
- // Find id of predicted node
- content_t id;
- bool found = nodedef->getId(prediction, id);
+ // Find id of predicted node
+ content_t id;
+ bool found = nodedef->getId(prediction, id);
- if (!found) {
- errorstream << "Node placement prediction failed for "
- << playeritem_def.name << " (places "
- << prediction
- << ") - Name not known" << std::endl;
- return false;
- }
+ if (!found) {
+ errorstream << "Node placement prediction failed for "
+ << selected_def.name << " (places "
+ << prediction
+ << ") - Name not known" << std::endl;
+ // Handle this as if prediction was empty
+ // Report to server
+ client->interact(INTERACT_PLACE, pointed);
+ return false;
+ }
- const ContentFeatures &predicted_f = nodedef->get(id);
+ const ContentFeatures &predicted_f = nodedef->get(id);
- // Predict param2 for facedir and wallmounted nodes
- u8 param2 = 0;
+ // Predict param2 for facedir and wallmounted nodes
+ u8 param2 = 0;
- if (predicted_f.param_type_2 == CPT2_WALLMOUNTED ||
+ if (predicted_f.param_type_2 == CPT2_WALLMOUNTED ||
predicted_f.param_type_2 == CPT2_COLORED_WALLMOUNTED) {
- v3s16 dir = nodepos - neighbourpos;
+ v3s16 dir = nodepos - neighbourpos;
- if (abs(dir.Y) > MYMAX(abs(dir.X), abs(dir.Z))) {
- param2 = dir.Y < 0 ? 1 : 0;
- } else if (abs(dir.X) > abs(dir.Z)) {
- param2 = dir.X < 0 ? 3 : 2;
- } else {
- param2 = dir.Z < 0 ? 5 : 4;
- }
+ if (abs(dir.Y) > MYMAX(abs(dir.X), abs(dir.Z))) {
+ param2 = dir.Y < 0 ? 1 : 0;
+ } else if (abs(dir.X) > abs(dir.Z)) {
+ param2 = dir.X < 0 ? 3 : 2;
+ } else {
+ param2 = dir.Z < 0 ? 5 : 4;
}
+ }
- if (predicted_f.param_type_2 == CPT2_FACEDIR ||
+ if (predicted_f.param_type_2 == CPT2_FACEDIR ||
predicted_f.param_type_2 == CPT2_COLORED_FACEDIR) {
- v3s16 dir = nodepos - floatToInt(client->getEnv().getLocalPlayer()->getPosition(), BS);
+ v3s16 dir = nodepos - floatToInt(client->getEnv().getLocalPlayer()->getPosition(), BS);
- if (abs(dir.X) > abs(dir.Z)) {
- param2 = dir.X < 0 ? 3 : 1;
- } else {
- param2 = dir.Z < 0 ? 2 : 0;
- }
+ if (abs(dir.X) > abs(dir.Z)) {
+ param2 = dir.X < 0 ? 3 : 1;
+ } else {
+ param2 = dir.Z < 0 ? 2 : 0;
}
+ }
+
+ assert(param2 <= 5);
- assert(param2 <= 5);
-
- //Check attachment if node is in group attached_node
- if (((ItemGroupList) predicted_f.groups)["attached_node"] != 0) {
- static v3s16 wallmounted_dirs[8] = {
- v3s16(0, 1, 0),
- v3s16(0, -1, 0),
- v3s16(1, 0, 0),
- v3s16(-1, 0, 0),
- v3s16(0, 0, 1),
- v3s16(0, 0, -1),
- };
- v3s16 pp;
-
- if (predicted_f.param_type_2 == CPT2_WALLMOUNTED ||
+ //Check attachment if node is in group attached_node
+ if (((ItemGroupList) predicted_f.groups)["attached_node"] != 0) {
+ static v3s16 wallmounted_dirs[8] = {
+ v3s16(0, 1, 0),
+ v3s16(0, -1, 0),
+ v3s16(1, 0, 0),
+ v3s16(-1, 0, 0),
+ v3s16(0, 0, 1),
+ v3s16(0, 0, -1),
+ };
+ v3s16 pp;
+
+ if (predicted_f.param_type_2 == CPT2_WALLMOUNTED ||
predicted_f.param_type_2 == CPT2_COLORED_WALLMOUNTED)
- pp = p + wallmounted_dirs[param2];
- else
- pp = p + v3s16(0, -1, 0);
+ pp = p + wallmounted_dirs[param2];
+ else
+ pp = p + v3s16(0, -1, 0);
- if (!nodedef->get(map.getNodeNoEx(pp)).walkable)
- return false;
+ if (!nodedef->get(map.getNode(pp)).walkable) {
+ // Report to server
+ client->interact(INTERACT_PLACE, pointed);
+ return false;
}
+ }
- // Apply color
- if ((predicted_f.param_type_2 == CPT2_COLOR
+ // Apply color
+ if ((predicted_f.param_type_2 == CPT2_COLOR
|| predicted_f.param_type_2 == CPT2_COLORED_FACEDIR
|| predicted_f.param_type_2 == CPT2_COLORED_WALLMOUNTED)) {
- const std::string &indexstr = playeritem.metadata.getString(
- "palette_index", 0);
- if (!indexstr.empty()) {
- s32 index = mystoi(indexstr);
- if (predicted_f.param_type_2 == CPT2_COLOR) {
- param2 = index;
- } else if (predicted_f.param_type_2
- == CPT2_COLORED_WALLMOUNTED) {
- // param2 = pure palette index + other
- param2 = (index & 0xf8) | (param2 & 0x07);
- } else if (predicted_f.param_type_2
- == CPT2_COLORED_FACEDIR) {
- // param2 = pure palette index + other
- param2 = (index & 0xe0) | (param2 & 0x1f);
- }
+ const std::string &indexstr = selected_item.metadata.getString(
+ "palette_index", 0);
+ if (!indexstr.empty()) {
+ s32 index = mystoi(indexstr);
+ if (predicted_f.param_type_2 == CPT2_COLOR) {
+ param2 = index;
+ } else if (predicted_f.param_type_2 == CPT2_COLORED_WALLMOUNTED) {
+ // param2 = pure palette index + other
+ param2 = (index & 0xf8) | (param2 & 0x07);
+ } else if (predicted_f.param_type_2 == CPT2_COLORED_FACEDIR) {
+ // param2 = pure palette index + other
+ param2 = (index & 0xe0) | (param2 & 0x1f);
}
}
+ }
- // Add node to client map
- MapNode n(id, 0, param2);
+ // Add node to client map
+ MapNode n(id, 0, param2);
- try {
- LocalPlayer *player = client->getEnv().getLocalPlayer();
+ try {
+ LocalPlayer *player = client->getEnv().getLocalPlayer();
- // Dont place node when player would be inside new node
- // NOTE: This is to be eventually implemented by a mod as client-side Lua
- if (!nodedef->get(n).walkable ||
+ // Dont place node when player would be inside new node
+ // NOTE: This is to be eventually implemented by a mod as client-side Lua
+ if (!nodedef->get(n).walkable ||
g_settings->getBool("enable_build_where_you_stand") ||
(client->checkPrivilege("noclip") && g_settings->getBool("noclip")) ||
(nodedef->get(n).walkable &&
neighbourpos != player->getStandingNodePos() + v3s16(0, 1, 0) &&
neighbourpos != player->getStandingNodePos() + v3s16(0, 2, 0))) {
-
- // This triggers the required mesh update too
- client->addNode(p, n);
- return true;
- }
- } catch (InvalidPositionException &e) {
- errorstream << "Node placement prediction failed for "
- << playeritem_def.name << " (places "
- << prediction
- << ") - Position not loaded" << std::endl;
+ // This triggers the required mesh update too
+ client->addNode(p, n);
+ // Report to server
+ client->interact(INTERACT_PLACE, pointed);
+ // A node is predicted, also play a sound
+ soundmaker->m_player_rightpunch_sound = selected_def.sound_place;
+ return true;
+ } else {
+ soundmaker->m_player_rightpunch_sound = selected_def.sound_place_failed;
+ return false;
}
+ } catch (InvalidPositionException &e) {
+ errorstream << "Node placement prediction failed for "
+ << selected_def.name << " (places "
+ << prediction
+ << ") - Position not loaded" << std::endl;
+ soundmaker->m_player_rightpunch_sound = selected_def.sound_place_failed;
+ return false;
}
-
- return false;
}
-void Game::handlePointingAtObject(const PointedThing &pointed, const ItemStack &playeritem,
- const v3f &player_position, bool show_debug)
+void Game::handlePointingAtObject(const PointedThing &pointed,
+ const ItemStack &tool_item, const v3f &player_position, bool show_debug)
{
std::wstring infotext = unescape_translate(
utf8_to_wide(runData.selected_object->infoText()));
@@ -3483,50 +3465,39 @@ void Game::handlePointingAtObject(const PointedThing &pointed, const ItemStack &
// Report direct punch
v3f objpos = runData.selected_object->getPosition();
v3f dir = (objpos - player_position).normalize();
- ItemStack item = playeritem;
- if (playeritem.name.empty()) {
- InventoryList *hlist = local_inventory->getList("hand");
- if (hlist) {
- item = hlist->getItem(0);
- }
- }
bool disable_send = runData.selected_object->directReportPunch(
- dir, &item, runData.time_from_last_punch);
+ dir, &tool_item, runData.time_from_last_punch);
runData.time_from_last_punch = 0;
if (!disable_send)
- client->interact(0, pointed);
+ client->interact(INTERACT_START_DIGGING, pointed);
}
} else if (input->getRightClicked()) {
infostream << "Right-clicked object" << std::endl;
- client->interact(3, pointed); // place
+ client->interact(INTERACT_PLACE, pointed); // place
}
}
void Game::handleDigging(const PointedThing &pointed, const v3s16 &nodepos,
- const ToolCapabilities &playeritem_toolcap, f32 dtime)
+ const ItemStack &selected_item, const ItemStack &hand_item, f32 dtime)
{
+ // See also: serverpackethandle.cpp, action == 2
LocalPlayer *player = client->getEnv().getLocalPlayer();
ClientMap &map = client->getEnv().getClientMap();
- MapNode n = client->getEnv().getClientMap().getNodeNoEx(nodepos);
+ MapNode n = client->getEnv().getClientMap().getNode(nodepos);
// NOTE: Similar piece of code exists on the server side for
// cheat detection.
// Get digging parameters
DigParams params = getDigParams(nodedef_manager->get(n).groups,
- &playeritem_toolcap);
+ &selected_item.getToolCapabilities(itemdef_manager));
// If can't dig, try hand
if (!params.diggable) {
- InventoryList *hlist = local_inventory->getList("hand");
- const ToolCapabilities *tp = hlist
- ? &hlist->getItem(0).getToolCapabilities(itemdef_manager)
- : itemdef_manager->get("").tool_capabilities;
-
- if (tp)
- params = getDigParams(nodedef_manager->get(n).groups, tp);
+ params = getDigParams(nodedef_manager->get(n).groups,
+ &hand_item.getToolCapabilities(itemdef_manager));
}
if (!params.diggable) {
@@ -3545,9 +3516,9 @@ void Game::handleDigging(const PointedThing &pointed, const v3s16 &nodepos,
if (!runData.digging) {
infostream << "Started digging" << std::endl;
runData.dig_instantly = runData.dig_time_complete == 0;
- if (client->moddingEnabled() && client->getScript()->on_punchnode(nodepos, n))
+ if (client->modsLoaded() && client->getScript()->on_punchnode(nodepos, n))
return;
- client->interact(0, pointed);
+ client->interact(INTERACT_START_DIGGING, pointed);
runData.digging = true;
runData.ldown_for_dig = true;
}
@@ -3603,10 +3574,10 @@ void Game::handleDigging(const PointedThing &pointed, const v3s16 &nodepos,
runData.nodig_delay_timer = 0.15;
bool is_valid_position;
- MapNode wasnode = map.getNodeNoEx(nodepos, &is_valid_position);
+ MapNode wasnode = map.getNode(nodepos, &is_valid_position);
if (is_valid_position) {
- if (client->moddingEnabled() &&
- client->getScript()->on_dignode(nodepos, wasnode)) {
+ if (client->modsLoaded() &&
+ client->getScript()->on_dignode(nodepos, wasnode)) {
return;
}
@@ -3622,7 +3593,7 @@ void Game::handleDigging(const PointedThing &pointed, const v3s16 &nodepos,
// implicit else: no prediction
}
- client->interact(2, pointed);
+ client->interact(INTERACT_DIGGING_COMPLETED, pointed);
if (m_cache_enable_particles) {
const ContentFeatures &features =
@@ -3650,6 +3621,7 @@ void Game::handleDigging(const PointedThing &pointed, const v3s16 &nodepos,
void Game::updateFrame(ProfilerGraph *graph, RunStats *stats, f32 dtime,
const CameraOrientation &cam)
{
+ TimeTaker tt_update("Game::updateFrame()");
LocalPlayer *player = client->getEnv().getLocalPlayer();
/*
@@ -3674,7 +3646,6 @@ void Game::updateFrame(ProfilerGraph *graph, RunStats *stats, f32 dtime,
direct_brightness = time_brightness;
sunlight_seen = true;
} else {
- ScopeProfiler sp(g_profiler, "Detecting background light", SPT_AVG);
float old_brightness = sky->getBrightness();
direct_brightness = client->getEnv().getClientMap()
.getBackgroundBrightness(MYMIN(runData.fog_range * 1.2, 60 * BS),
@@ -3780,31 +3751,14 @@ void Game::updateFrame(ProfilerGraph *graph, RunStats *stats, f32 dtime,
Inventory
*/
- if (client->getPlayerItem() != runData.new_playeritem)
- client->selectPlayerItem(runData.new_playeritem);
+ if (player->getWieldIndex() != runData.new_playeritem)
+ client->setPlayerItem(runData.new_playeritem);
- // Update local inventory if it has changed
- if (client->getLocalInventoryUpdated()) {
- //infostream<<"Updating local inventory"<<std::endl;
- client->getLocalInventory(*local_inventory);
- runData.update_wielded_item_trigger = true;
- }
-
- if (runData.update_wielded_item_trigger) {
+ if (client->updateWieldedItem()) {
// Update wielded tool
- InventoryList *mlist = local_inventory->getList("main");
-
- if (mlist && (client->getPlayerItem() < mlist->getSize())) {
- ItemStack item = mlist->getItem(client->getPlayerItem());
- if (item.getDefinition(itemdef_manager).name.empty()) { // override the hand
- InventoryList *hlist = local_inventory->getList("hand");
- if (hlist)
- item = hlist->getItem(0);
- }
- camera->wield(item);
- }
-
- runData.update_wielded_item_trigger = false;
+ ItemStack selected_item, hand_item;
+ ItemStack &tool_item = player->getWieldedItem(&selected_item, &hand_item);
+ camera->wield(tool_item);
}
/*
@@ -3822,28 +3776,42 @@ void Game::updateFrame(ProfilerGraph *graph, RunStats *stats, f32 dtime,
runData.update_draw_list_last_cam_dir = camera_direction;
}
- m_game_ui->update(*stats, client, draw_control, cam, runData.pointed_old, dtime);
+ m_game_ui->update(*stats, client, draw_control, cam, runData.pointed_old, gui_chat_console, dtime);
/*
make sure menu is on top
1. Delete formspec menu reference if menu was removed
2. Else, make sure formspec menu is on top
*/
- if (current_formspec) {
- if (current_formspec->getReferenceCount() == 1) {
- current_formspec->drop();
- current_formspec = NULL;
- } else if (isMenuActive()) {
- guiroot->bringToFront(current_formspec);
+ auto formspec = m_game_ui->getFormspecGUI();
+ do { // breakable. only runs for one iteration
+ if (!formspec)
+ break;
+
+ if (formspec->getReferenceCount() == 1) {
+ m_game_ui->deleteFormspec();
+ break;
}
- }
+
+ auto &loc = formspec->getFormspecLocation();
+ if (loc.type == InventoryLocation::NODEMETA) {
+ NodeMetadata *meta = client->getEnv().getClientMap().getNodeMetadata(loc.p);
+ if (!meta || meta->getString("formspec").empty()) {
+ formspec->quitMenu();
+ break;
+ }
+ }
+
+ if (isMenuActive())
+ guiroot->bringToFront(formspec);
+ } while (false);
/*
Drawing begins
*/
const video::SColor &skycolor = sky->getSkyColor();
- TimeTaker tt_draw("mainloop: draw");
+ TimeTaker tt_draw("Draw scene");
driver->beginScene(true, true, skycolor);
bool draw_wield_tool = (m_game_ui->m_flags.show_hud &&
@@ -3903,7 +3871,8 @@ void Game::updateFrame(ProfilerGraph *graph, RunStats *stats, f32 dtime,
driver->endScene();
stats->drawtime = tt_draw.stop(true);
- g_profiler->graphAdd("mainloop_draw", stats->drawtime / 1000.0f);
+ g_profiler->avg("Game::updateFrame(): draw scene [ms]", stats->drawtime);
+ g_profiler->graphAdd("Update frame [ms]", tt_update.stop(true));
}
/* Log times and stuff for visualization */
@@ -4033,8 +4002,8 @@ void Game::extendedResourceCleanup()
void Game::showDeathFormspec()
{
- static std::string formspec =
- std::string(FORMSPEC_VERSION_STRING) +
+ static std::string formspec_str =
+ std::string("formspec_version[1]") +
SIZE_TAG
"bgcolor[#320000b4;true]"
"label[4.85,1.35;" + gettext("You died") + "]"
@@ -4044,12 +4013,13 @@ void Game::showDeathFormspec()
/* Create menu */
/* Note: FormspecFormSource and LocalFormspecHandler *
* are deleted by guiFormSpecMenu */
- FormspecFormSource *fs_src = new FormspecFormSource(formspec);
+ FormspecFormSource *fs_src = new FormspecFormSource(formspec_str);
LocalFormspecHandler *txt_dst = new LocalFormspecHandler("MT_DEATH_SCREEN", client);
- GUIFormSpecMenu::create(current_formspec, client, &input->joystick, fs_src,
- txt_dst, client->getFormspecPrepend());
- current_formspec->setFocus("btn_respawn");
+ auto *&formspec = m_game_ui->getFormspecGUI();
+ GUIFormSpecMenu::create(formspec, client, &input->joystick,
+ fs_src, txt_dst, client->getFormspecPrepend());
+ formspec->setFocus("btn_respawn");
}
#define GET_KEY_NAME(KEY) gettext(getKeySetting(#KEY).name())
@@ -4107,7 +4077,7 @@ void Game::showPauseMenu()
float ypos = simple_singleplayer_mode ? 0.7f : 0.1f;
std::ostringstream os;
- os << FORMSPEC_VERSION_STRING << SIZE_TAG
+ os << "formspec_version[1]" << SIZE_TAG
<< "button_exit[4," << (ypos++) << ";3,0.5;btn_continue;"
<< strgettext("Continue") << "]";
@@ -4173,10 +4143,11 @@ void Game::showPauseMenu()
FormspecFormSource *fs_src = new FormspecFormSource(os.str());
LocalFormspecHandler *txt_dst = new LocalFormspecHandler("MT_PAUSE_MENU");
- GUIFormSpecMenu::create(current_formspec, client, &input->joystick,
+ auto *&formspec = m_game_ui->getFormspecGUI();
+ GUIFormSpecMenu::create(formspec, client, &input->joystick,
fs_src, txt_dst, client->getFormspecPrepend());
- current_formspec->setFocus("btn_continue");
- current_formspec->doPause = true;
+ formspec->setFocus("btn_continue");
+ formspec->doPause = true;
}
/****************************************************************************/
@@ -4227,7 +4198,8 @@ void the_game(bool *kill,
error_message = e.what();
errorstream << "ServerError: " << error_message << std::endl;
} catch (ModError &e) {
- error_message = e.what() + strgettext("\nCheck debug.txt for details.");
- errorstream << "ModError: " << error_message << std::endl;
+ error_message = std::string("ModError: ") + e.what() +
+ strgettext("\nCheck debug.txt for details.");
+ errorstream << error_message << std::endl;
}
}
diff --git a/src/client/gameui.cpp b/src/client/gameui.cpp
index 1f433e49a..674d07fa6 100644
--- a/src/client/gameui.cpp
+++ b/src/client/gameui.cpp
@@ -22,6 +22,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include <irrlicht_changes/static_text.h>
#include <gettext.h>
#include "gui/mainmenumanager.h"
+#include "gui/guiChatConsole.h"
#include "util/pointedthing.h"
#include "client.h"
#include "clientmap.h"
@@ -79,13 +80,15 @@ void GameUI::init()
// Profiler text (size is updated when text is updated)
m_guitext_profiler = gui::StaticText::add(guienv, L"<Profiler>",
core::rect<s32>(0, 0, 0, 0), false, false, guiroot);
+ m_guitext_profiler->setOverrideFont(g_fontengine->getFont(
+ g_fontengine->getDefaultFontSize() * 0.9f, FM_Mono));
m_guitext_profiler->setBackgroundColor(video::SColor(120, 0, 0, 0));
m_guitext_profiler->setVisible(false);
- m_guitext_profiler->setWordWrap(true);
}
void GameUI::update(const RunStats &stats, Client *client, MapDrawControl *draw_control,
- const CameraOrientation &cam, const PointedThing &pointed_old, float dtime)
+ const CameraOrientation &cam, const PointedThing &pointed_old,
+ const GUIChatConsole *chat_console, float dtime)
{
v2u32 screensize = RenderingEngine::get_instance()->getWindowSize();
@@ -97,17 +100,17 @@ void GameUI::update(const RunStats &stats, Client *client, MapDrawControl *draw_
std::ostringstream os(std::ios_base::binary);
os << std::fixed
<< PROJECT_NAME_C " " << g_version_hash
- << ", FPS: " << fps
+ << " | FPS: " << fps
<< std::setprecision(0)
- << ", drawtime: " << drawtime_avg << "ms"
+ << " | drawtime: " << drawtime_avg << "ms"
<< std::setprecision(1)
- << ", dtime jitter: "
+ << " | dtime jitter: "
<< (stats.dtime_jitter.max_fraction * 100.0) << "%"
<< std::setprecision(1)
- << ", view range: "
+ << " | view range: "
<< (draw_control->range_all ? "All" : itos(draw_control->wanted_range))
<< std::setprecision(3)
- << ", RTT: " << client->getRTT() << "s";
+ << " | RTT: " << client->getRTT() << "s";
setStaticText(m_guitext, utf8_to_wide(os.str()).c_str());
m_guitext->setRelativePosition(core::rect<s32>(5, 5, screensize.X,
@@ -126,14 +129,15 @@ void GameUI::update(const RunStats &stats, Client *client, MapDrawControl *draw_
<< "pos: (" << (player_position.X / BS)
<< ", " << (player_position.Y / BS)
<< ", " << (player_position.Z / BS)
- << "), yaw: " << (wrapDegrees_0_360(cam.camera_yaw)) << "° "
+ << ") | yaw: " << (wrapDegrees_0_360(cam.camera_yaw)) << "° "
<< yawToDirectionString(cam.camera_yaw)
- << ", seed: " << ((u64)client->getMapSeed());
+ << " | pitch: " << (-wrapDegrees_180(cam.camera_pitch)) << "°"
+ << " | seed: " << ((u64)client->getMapSeed());
if (pointed_old.type == POINTEDTHING_NODE) {
ClientMap &map = client->getEnv().getClientMap();
const NodeDefManager *nodedef = client->getNodeDefManager();
- MapNode n = map.getNodeNoEx(pointed_old.node_undersurface);
+ MapNode n = map.getNode(pointed_old.node_undersurface);
if (n.getContent() != CONTENT_IGNORE && nodedef->get(n).name != "unknown") {
os << ", pointed: " << nodedef->get(n).name
@@ -185,6 +189,9 @@ void GameUI::update(const RunStats &stats, Client *client, MapDrawControl *draw_
m_guitext_status->setOverrideColor(fade_color);
m_guitext_status->enableOverrideColor(true);
}
+
+ // Hide chat when console is visible
+ m_guitext_chat->setVisible(isChatVisible() && !chat_console->isVisible());
}
void GameUI::initFlags()
@@ -226,38 +233,28 @@ void GameUI::setChatText(const EnrichedString &chat_text, u32 recent_chat_count)
m_guitext_chat->setRelativePosition(core::rect<s32>(10, chat_y, width,
chat_y + m_guitext_chat->getTextHeight()));
- // Don't show chat if disabled or empty or profiler is enabled
- m_guitext_chat->setVisible(m_flags.show_chat &&
- recent_chat_count != 0 && m_profiler_current_page == 0);
+ m_recent_chat_count = recent_chat_count;
}
void GameUI::updateProfiler()
{
if (m_profiler_current_page != 0) {
std::ostringstream os(std::ios_base::binary);
- g_profiler->printPage(os, m_profiler_current_page, m_profiler_max_page);
-
- std::wstring text = translate_string(utf8_to_wide(os.str()));
- setStaticText(m_guitext_profiler, text.c_str());
-
- s32 w = g_fontengine->getTextWidth(text);
-
- if (w < 400)
- w = 400;
-
- u32 text_height = g_fontengine->getTextHeight();
-
- core::position2di upper_left, lower_right;
+ os << " Profiler page " << (int)m_profiler_current_page <<
+ ", elapsed: " << g_profiler->getElapsedMs() << " ms)" << std::endl;
- upper_left.X = 6;
- upper_left.Y = (text_height + 5) * 2;
- lower_right.X = 12 + w;
- lower_right.Y = upper_left.Y + (text_height + 1) * MAX_PROFILER_TEXT_ROWS;
+ int lines = g_profiler->print(os, m_profiler_current_page, m_profiler_max_page);
+ ++lines;
- s32 screen_height = RenderingEngine::get_video_driver()->getScreenSize().Height;
+ std::wstring text = utf8_to_wide(os.str());
+ setStaticText(m_guitext_profiler, text.c_str());
- if (lower_right.Y > screen_height * 2 / 3)
- lower_right.Y = screen_height * 2 / 3;
+ core::dimension2d<u32> size = m_guitext_profiler->getOverrideFont()->
+ getDimension(text.c_str());
+ core::position2di upper_left(6, 50);
+ core::position2di lower_right = upper_left;
+ lower_right.X += size.Width + 10;
+ lower_right.Y += size.Height;
m_guitext_profiler->setRelativePosition(core::rect<s32>(upper_left, lower_right));
}
@@ -301,3 +298,14 @@ void GameUI::toggleProfiler()
showTranslatedStatusText("Profiler hidden");
}
}
+
+
+void GameUI::deleteFormspec()
+{
+ if (m_formspec) {
+ m_formspec->drop();
+ m_formspec = nullptr;
+ }
+
+ m_formname.clear();
+}
diff --git a/src/client/gameui.h b/src/client/gameui.h
index b6b54562a..67c6a9921 100644
--- a/src/client/gameui.h
+++ b/src/client/gameui.h
@@ -21,12 +21,14 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#pragma once
#include <IGUIEnvironment.h>
+#include "gui/guiFormSpecMenu.h"
#include "util/enriched_string.h"
#include "util/pointedthing.h"
#include "game.h"
using namespace irr;
class Client;
+class GUIChatConsole;
struct MapDrawControl;
/*
@@ -62,7 +64,7 @@ public:
void init();
void update(const RunStats &stats, Client *client, MapDrawControl *draw_control,
const CameraOrientation &cam, const PointedThing &pointed_old,
- float dtime);
+ const GUIChatConsole *chat_console, float dtime);
void initFlags();
const Flags &getFlags() const { return m_flags; }
@@ -80,6 +82,10 @@ public:
void showTranslatedStatusText(const char *str);
inline void clearStatusText() { m_statustext.clear(); }
+ const bool isChatVisible()
+ {
+ return m_flags.show_chat && m_recent_chat_count != 0 && m_profiler_current_page == 0;
+ }
void setChatText(const EnrichedString &chat_text, u32 recent_chat_count);
void updateProfiler();
@@ -88,6 +94,16 @@ public:
void toggleHud();
void toggleProfiler();
+ GUIFormSpecMenu *&updateFormspec(const std::string &formname)
+ {
+ m_formname = formname;
+ return m_formspec;
+ }
+
+ const std::string &getFormspecName() { return m_formname; }
+ GUIFormSpecMenu *&getFormspecGUI() { return m_formspec; }
+ void deleteFormspec();
+
private:
Flags m_flags;
@@ -103,8 +119,14 @@ private:
video::SColor m_statustext_initial_color;
gui::IGUIStaticText *m_guitext_chat = nullptr; // Chat text
+ u32 m_recent_chat_count = 0;
gui::IGUIStaticText *m_guitext_profiler = nullptr; // Profiler text
u8 m_profiler_current_page = 0;
const u8 m_profiler_max_page = 3;
+
+ // Default: "". If other than "": Empty show_formspec packets will only
+ // close the formspec when the formname matches
+ std::string m_formname;
+ GUIFormSpecMenu *m_formspec = nullptr;
};
diff --git a/src/client/guiscalingfilter.cpp b/src/client/guiscalingfilter.cpp
index 3b4377da5..2ff57ab74 100644
--- a/src/client/guiscalingfilter.cpp
+++ b/src/client/guiscalingfilter.cpp
@@ -23,6 +23,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "util/numeric.h"
#include <cstdio>
#include "client/renderingengine.h"
+#include "client/tile.h" // hasNPotSupport()
/* Maintain a static cache to store the images that correspond to textures
* in a format that's manipulable by code. Some platforms exhibit issues
@@ -39,7 +40,7 @@ std::map<io::path, video::ITexture *> g_txrCache;
/* Manually insert an image into the cache, useful to avoid texture-to-image
* conversion whenever we can intercept it.
*/
-void guiScalingCache(io::path key, video::IVideoDriver *driver, video::IImage *value)
+void guiScalingCache(const io::path &key, video::IVideoDriver *driver, video::IImage *value)
{
if (!g_settings->getBool("gui_scaling_filter"))
return;
@@ -113,17 +114,18 @@ video::ITexture *guiScalingResizeCached(video::IVideoDriver *driver,
(u32)destrect.getHeight()));
imageScaleNNAA(srcimg, srcrect, destimg);
-#ifdef __ANDROID__
- // Android is very picky about textures being powers of 2, so expand
- // the image dimensions to the next power of 2, if necessary, for
- // that platform.
- video::IImage *po2img = driver->createImage(src->getColorFormat(),
- core::dimension2d<u32>(npot2((u32)destrect.getWidth()),
- npot2((u32)destrect.getHeight())));
- po2img->fill(video::SColor(0, 0, 0, 0));
- destimg->copyTo(po2img);
- destimg->drop();
- destimg = po2img;
+#if ENABLE_GLES
+ // Some platforms are picky about textures being powers of 2, so expand
+ // the image dimensions to the next power of 2, if necessary.
+ if (!hasNPotSupport()) {
+ video::IImage *po2img = driver->createImage(src->getColorFormat(),
+ core::dimension2d<u32>(npot2((u32)destrect.getWidth()),
+ npot2((u32)destrect.getHeight())));
+ po2img->fill(video::SColor(0, 0, 0, 0));
+ destimg->copyTo(po2img);
+ destimg->drop();
+ destimg = po2img;
+ }
#endif
// Convert the scaled image back into a texture.
@@ -167,3 +169,62 @@ void draw2DImageFilterScaled(video::IVideoDriver *driver, video::ITexture *txr,
driver->draw2DImage(scaled, destrect, mysrcrect, cliprect, colors, usealpha);
}
+
+void draw2DImage9Slice(video::IVideoDriver *driver, video::ITexture *texture,
+ const core::rect<s32> &rect, const core::rect<s32> &middle)
+{
+ const video::SColor color(255,255,255,255);
+ const video::SColor colors[] = {color,color,color,color};
+
+ auto originalSize = texture->getOriginalSize();
+ core::vector2di lowerRightOffset = core::vector2di(originalSize.Width, originalSize.Height) - middle.LowerRightCorner;
+
+ for (int y = 0; y < 3; ++y) {
+ for (int x = 0; x < 3; ++x) {
+ core::rect<s32> src({0, 0}, originalSize);
+ core::rect<s32> dest = rect;
+
+ switch (x) {
+ case 0:
+ dest.LowerRightCorner.X = rect.UpperLeftCorner.X + middle.UpperLeftCorner.X;
+ src.LowerRightCorner.X = middle.UpperLeftCorner.X;
+ break;
+
+ case 1:
+ dest.UpperLeftCorner.X += middle.UpperLeftCorner.X;
+ dest.LowerRightCorner.X -= lowerRightOffset.X;
+ src.UpperLeftCorner.X = middle.UpperLeftCorner.X;
+ src.LowerRightCorner.X = middle.LowerRightCorner.X;
+ break;
+
+ case 2:
+ dest.UpperLeftCorner.X = rect.LowerRightCorner.X - lowerRightOffset.X;
+ src.UpperLeftCorner.X = middle.LowerRightCorner.X;
+ break;
+ }
+
+ switch (y) {
+ case 0:
+ dest.LowerRightCorner.Y = rect.UpperLeftCorner.Y + middle.UpperLeftCorner.Y;
+ src.LowerRightCorner.Y = middle.UpperLeftCorner.Y;
+ break;
+
+ case 1:
+ dest.UpperLeftCorner.Y += middle.UpperLeftCorner.Y;
+ dest.LowerRightCorner.Y -= lowerRightOffset.Y;
+ src.UpperLeftCorner.Y = middle.UpperLeftCorner.Y;
+ src.LowerRightCorner.Y = middle.LowerRightCorner.Y;
+ break;
+
+ case 2:
+ dest.UpperLeftCorner.Y = rect.LowerRightCorner.Y - lowerRightOffset.Y;
+ src.UpperLeftCorner.Y = middle.LowerRightCorner.Y;
+ break;
+ }
+
+ draw2DImageFilterScaled(driver, texture, dest,
+ src,
+ NULL/*&AbsoluteClippingRect*/, colors, true);
+ }
+ }
+}
diff --git a/src/client/guiscalingfilter.h b/src/client/guiscalingfilter.h
index 4661bf8da..181009551 100644
--- a/src/client/guiscalingfilter.h
+++ b/src/client/guiscalingfilter.h
@@ -23,7 +23,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
/* Manually insert an image into the cache, useful to avoid texture-to-image
* conversion whenever we can intercept it.
*/
-void guiScalingCache(io::path key, video::IVideoDriver *driver, video::IImage *value);
+void guiScalingCache(const io::path &key, video::IVideoDriver *driver, video::IImage *value);
// Manually clear the cache, e.g. when switching to different worlds.
void guiScalingCacheClear();
@@ -48,3 +48,9 @@ void draw2DImageFilterScaled(video::IVideoDriver *driver, video::ITexture *txr,
const core::rect<s32> &destrect, const core::rect<s32> &srcrect,
const core::rect<s32> *cliprect = 0, const video::SColor *const colors = 0,
bool usealpha = false);
+
+/*
+ * 9-slice / segment drawing
+ */
+void draw2DImage9Slice(video::IVideoDriver *driver, video::ITexture *texture,
+ const core::rect<s32> &rect, const core::rect<s32> &middle);
diff --git a/src/client/hud.cpp b/src/client/hud.cpp
index 1a2287a13..291d03816 100644
--- a/src/client/hud.cpp
+++ b/src/client/hud.cpp
@@ -372,7 +372,7 @@ void Hud::drawLuaElements(const v3s16 &camera_offset)
}
-void Hud::drawStatbar(v2s32 pos, u16 corner, u16 drawdir, std::string texture,
+void Hud::drawStatbar(v2s32 pos, u16 corner, u16 drawdir, const std::string &texture,
s32 count, v2s32 offset, v2s32 size)
{
const video::SColor color(255, 255, 255, 255);
@@ -649,10 +649,31 @@ void drawItemStack(video::IVideoDriver *driver,
core::rect<s32> oldViewPort = driver->getViewPort();
core::matrix4 oldProjMat = driver->getTransform(video::ETS_PROJECTION);
core::matrix4 oldViewMat = driver->getTransform(video::ETS_VIEW);
+ core::rect<s32> viewrect = rect;
+ if (clip)
+ viewrect.clipAgainst(*clip);
+
core::matrix4 ProjMatrix;
- ProjMatrix.buildProjectionMatrixOrthoLH(2, 2, -1, 100);
+ ProjMatrix.buildProjectionMatrixOrthoLH(2.0f, 2.0f, -1.0f, 100.0f);
+
+ core::matrix4 ViewMatrix;
+ ViewMatrix.buildProjectionMatrixOrthoLH(
+ 2.0f * viewrect.getWidth() / rect.getWidth(),
+ 2.0f * viewrect.getHeight() / rect.getHeight(),
+ -1.0f,
+ 100.0f);
+ ViewMatrix.setTranslation(core::vector3df(
+ 1.0f * (rect.LowerRightCorner.X + rect.UpperLeftCorner.X -
+ viewrect.LowerRightCorner.X - viewrect.UpperLeftCorner.X) /
+ viewrect.getWidth(),
+ 1.0f * (viewrect.LowerRightCorner.Y + viewrect.UpperLeftCorner.Y -
+ rect.LowerRightCorner.Y - rect.UpperLeftCorner.Y) /
+ viewrect.getHeight(),
+ 0.0f));
+
driver->setTransform(video::ETS_PROJECTION, ProjMatrix);
- driver->setTransform(video::ETS_VIEW, ProjMatrix);
+ driver->setTransform(video::ETS_VIEW, ViewMatrix);
+
core::matrix4 matrix;
matrix.makeIdentity();
@@ -662,7 +683,7 @@ void drawItemStack(video::IVideoDriver *driver,
}
driver->setTransform(video::ETS_WORLD, matrix);
- driver->setViewPort(rect);
+ driver->setViewPort(viewrect);
video::SColor basecolor =
client->idef()->getItemstackColor(item, client);
@@ -693,6 +714,16 @@ void drawItemStack(video::IVideoDriver *driver,
driver->setTransform(video::ETS_VIEW, oldViewMat);
driver->setTransform(video::ETS_PROJECTION, oldProjMat);
driver->setViewPort(oldViewPort);
+
+ // draw the inventory_overlay
+ if (def.type == ITEM_NODE && def.inventory_image.empty() &&
+ !def.inventory_overlay.empty()) {
+ ITextureSource *tsrc = client->getTextureSource();
+ video::ITexture *overlay_texture = tsrc->getTexture(def.inventory_overlay);
+ core::dimension2d<u32> dimens = overlay_texture->getOriginalSize();
+ core::rect<s32> srcrect(0, 0, dimens.Width, dimens.Height);
+ draw2DImageFilterScaled(driver, overlay_texture, rect, srcrect, clip, 0, true);
+ }
}
if(def.type == ITEM_TOOL && item.wear != 0)
diff --git a/src/client/hud.h b/src/client/hud.h
index e9bcdf4e2..693d2adee 100644
--- a/src/client/hud.h
+++ b/src/client/hud.h
@@ -81,7 +81,7 @@ public:
void drawLuaElements(const v3s16 &camera_offset);
private:
- void drawStatbar(v2s32 pos, u16 corner, u16 drawdir, std::string texture,
+ void drawStatbar(v2s32 pos, u16 corner, u16 drawdir, const std::string &texture,
s32 count, v2s32 offset, v2s32 size = v2s32());
void drawItems(v2s32 upperleftpos, v2s32 screen_offset, s32 itemcount,
diff --git a/src/client/localplayer.cpp b/src/client/localplayer.cpp
index 7e7b1a867..c086d860a 100644
--- a/src/client/localplayer.cpp
+++ b/src/client/localplayer.cpp
@@ -41,7 +41,7 @@ LocalPlayer::LocalPlayer(Client *client, const char *name):
static aabb3f getNodeBoundingBox(const std::vector<aabb3f> &nodeboxes)
{
if (nodeboxes.empty())
- return aabb3f(0, 0, 0, 0, 0, 0);
+ return aabb3f(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f);
aabb3f b_max;
@@ -56,7 +56,7 @@ static aabb3f getNodeBoundingBox(const std::vector<aabb3f> &nodeboxes)
}
bool LocalPlayer::updateSneakNode(Map *map, const v3f &position,
- const v3f &sneak_max)
+ const v3f &sneak_max)
{
static const v3s16 dir9_center[9] = {
v3s16( 0, 0, 0),
@@ -76,17 +76,17 @@ bool LocalPlayer::updateSneakNode(Map *map, const v3f &position,
bool new_sneak_node_exists = m_sneak_node_exists;
// We want the top of the sneak node to be below the players feet
- f32 position_y_mod = 0.05 * BS;
+ f32 position_y_mod = 0.05f * BS;
if (m_sneak_node_exists)
position_y_mod = m_sneak_node_bb_top.MaxEdge.Y - position_y_mod;
// Get position of current standing node
- const v3s16 current_node = floatToInt(position - v3f(0, position_y_mod, 0), BS);
+ const v3s16 current_node = floatToInt(position - v3f(0.0f, position_y_mod, 0.0f), BS);
if (current_node != m_sneak_node) {
new_sneak_node_exists = false;
} else {
- node = map->getNodeNoEx(current_node, &is_valid_position);
+ node = map->getNode(current_node, &is_valid_position);
if (!is_valid_position || !nodemgr->get(node).walkable)
new_sneak_node_exists = false;
}
@@ -97,7 +97,7 @@ bool LocalPlayer::updateSneakNode(Map *map, const v3f &position,
// Get new sneak node
m_sneak_ladder_detected = false;
- f32 min_distance_f = 100000.0 * BS;
+ f32 min_distance_f = 100000.0f * BS;
for (const auto &d : dir9_center) {
const v3s16 p = current_node + d;
@@ -106,23 +106,22 @@ bool LocalPlayer::updateSneakNode(Map *map, const v3f &position,
f32 distance_f = diff.getLength();
if (distance_f > min_distance_f ||
- fabs(diff.X) > (.5 + .1) * BS + sneak_max.X ||
- fabs(diff.Y) > (.5 + .1) * BS + sneak_max.Z)
+ fabs(diff.X) > (0.5f + 0.1f) * BS + sneak_max.X ||
+ fabs(diff.Y) > (0.5f + 0.1f) * BS + sneak_max.Z)
continue;
// The node to be sneaked on has to be walkable
- node = map->getNodeNoEx(p, &is_valid_position);
+ node = map->getNode(p, &is_valid_position);
if (!is_valid_position || !nodemgr->get(node).walkable)
continue;
// And the node(s) above have to be nonwalkable
bool ok = true;
if (!physics_override_sneak_glitch) {
- u16 height = ceilf(
- (m_collisionbox.MaxEdge.Y - m_collisionbox.MinEdge.Y) / BS
- );
+ u16 height =
+ ceilf((m_collisionbox.MaxEdge.Y - m_collisionbox.MinEdge.Y) / BS);
for (u16 y = 1; y <= height; y++) {
- node = map->getNodeNoEx(p + v3s16(0, y, 0), &is_valid_position);
+ node = map->getNode(p + v3s16(0, y, 0), &is_valid_position);
if (!is_valid_position || nodemgr->get(node).walkable) {
ok = false;
break;
@@ -130,7 +129,7 @@ bool LocalPlayer::updateSneakNode(Map *map, const v3f &position,
}
} else {
// legacy behaviour: check just one node
- node = map->getNodeNoEx(p + v3s16(0, 1, 0), &is_valid_position);
+ node = map->getNode(p + v3s16(0, 1, 0), &is_valid_position);
ok = is_valid_position && !nodemgr->get(node).walkable;
}
if (!ok)
@@ -145,7 +144,7 @@ bool LocalPlayer::updateSneakNode(Map *map, const v3f &position,
return false;
// Update saved top bounding box of sneak node
- node = map->getNodeNoEx(m_sneak_node);
+ node = map->getNode(m_sneak_node);
std::vector<aabb3f> nodeboxes;
node.getCollisionBoxes(nodemgr, &nodeboxes);
m_sneak_node_bb_top = getNodeBoundingBox(nodeboxes);
@@ -153,11 +152,11 @@ bool LocalPlayer::updateSneakNode(Map *map, const v3f &position,
if (physics_override_sneak_glitch) {
// Detect sneak ladder:
// Node two meters above sneak node must be solid
- node = map->getNodeNoEx(m_sneak_node + v3s16(0, 2, 0),
+ node = map->getNode(m_sneak_node + v3s16(0, 2, 0),
&is_valid_position);
if (is_valid_position && nodemgr->get(node).walkable) {
// Node three meters above: must be non-solid
- node = map->getNodeNoEx(m_sneak_node + v3s16(0, 3, 0),
+ node = map->getNode(m_sneak_node + v3s16(0, 3, 0),
&is_valid_position);
m_sneak_ladder_detected = is_valid_position &&
!nodemgr->get(node).walkable;
@@ -169,10 +168,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 (!collision_info || collision_info->empty()) {
- // Node below the feet, update each ClientEnvironment::step()
- m_standing_node = floatToInt(m_position, BS) - v3s16(0, 1, 0);
- }
+ // Node at feet position, update each ClientEnvironment::step()
+ if (!collision_info || collision_info->empty())
+ m_standing_node = floatToInt(m_position, BS);
// Temporary option for old move code
if (!physics_override_new_move) {
@@ -188,6 +186,7 @@ void LocalPlayer::move(f32 dtime, Environment *env, f32 pos_max_d,
// Copy parent position if local player is attached
if (isAttached) {
setPosition(overridePosition);
+ added_velocity = v3f(0.0f); // ignored
return;
}
@@ -201,9 +200,13 @@ void LocalPlayer::move(f32 dtime, Environment *env, f32 pos_max_d,
if (noclip && free_move) {
position += m_speed * dtime;
setPosition(position);
+ added_velocity = v3f(0.0f); // ignored
return;
}
+ m_speed += added_velocity;
+ added_velocity = v3f(0.0f);
+
/*
Collision detection
*/
@@ -219,20 +222,19 @@ void LocalPlayer::move(f32 dtime, Environment *env, f32 pos_max_d,
// If in liquid, the threshold of coming out is at higher y
if (in_liquid)
{
- pp = floatToInt(position + v3f(0,BS*0.1,0), BS);
- node = map->getNodeNoEx(pp, &is_valid_position);
+ pp = floatToInt(position + v3f(0.0f, BS * 0.1f, 0.0f), BS);
+ node = map->getNode(pp, &is_valid_position);
if (is_valid_position) {
in_liquid = nodemgr->get(node.getContent()).isLiquid();
liquid_viscosity = nodemgr->get(node.getContent()).liquid_viscosity;
} else {
in_liquid = false;
}
- }
- // If not in liquid, the threshold of going in is at lower y
- else
- {
- pp = floatToInt(position + v3f(0,BS*0.5,0), BS);
- node = map->getNodeNoEx(pp, &is_valid_position);
+ } else {
+ // If not in liquid, the threshold of going in is at lower y
+
+ pp = floatToInt(position + v3f(0.0f, BS * 0.5f, 0.0f), BS);
+ node = map->getNode(pp, &is_valid_position);
if (is_valid_position) {
in_liquid = nodemgr->get(node.getContent()).isLiquid();
liquid_viscosity = nodemgr->get(node.getContent()).liquid_viscosity;
@@ -245,8 +247,8 @@ void LocalPlayer::move(f32 dtime, Environment *env, f32 pos_max_d,
/*
Check if player is in liquid (the stable value)
*/
- pp = floatToInt(position + v3f(0,0,0), BS);
- node = map->getNodeNoEx(pp, &is_valid_position);
+ pp = floatToInt(position + v3f(0.0f), BS);
+ node = map->getNode(pp, &is_valid_position);
if (is_valid_position) {
in_liquid_stable = nodemgr->get(node.getContent()).isLiquid();
} else {
@@ -254,21 +256,20 @@ void LocalPlayer::move(f32 dtime, Environment *env, f32 pos_max_d,
}
/*
- Check if player is climbing
+ Check if player is climbing
*/
-
- pp = floatToInt(position + v3f(0,0.5*BS,0), BS);
- v3s16 pp2 = floatToInt(position + v3f(0,-0.2*BS,0), BS);
- node = map->getNodeNoEx(pp, &is_valid_position);
+ pp = floatToInt(position + v3f(0.0f, 0.5f * BS, 0.0f), BS);
+ v3s16 pp2 = floatToInt(position + v3f(0.0f, -0.2f * BS, 0.0f), BS);
+ node = map->getNode(pp, &is_valid_position);
bool is_valid_position2;
- MapNode node2 = map->getNodeNoEx(pp2, &is_valid_position2);
+ MapNode node2 = map->getNode(pp2, &is_valid_position2);
if (!(is_valid_position && is_valid_position2)) {
is_climbing = false;
} else {
- is_climbing = (nodemgr->get(node.getContent()).climbable
- || nodemgr->get(node2.getContent()).climbable) && !free_move;
+ is_climbing = (nodemgr->get(node.getContent()).climbable ||
+ nodemgr->get(node2.getContent()).climbable) && !free_move;
}
/*
@@ -277,7 +278,7 @@ void LocalPlayer::move(f32 dtime, Environment *env, f32 pos_max_d,
*/
//f32 d = pos_max_d * 1.1;
// A fairly large value in here makes moving smoother
- f32 d = 0.15*BS;
+ f32 d = 0.15f * BS;
// This should always apply, otherwise there are glitches
sanity_check(d > pos_max_d);
@@ -287,7 +288,7 @@ void LocalPlayer::move(f32 dtime, Environment *env, f32 pos_max_d,
float player_stepheight = (m_cao == nullptr) ? 0.0f :
(touching_ground ? m_cao->getStepHeight() : (0.2f * BS));
- v3f accel_f = v3f(0,0,0);
+ v3f accel_f;
const v3f initial_position = position;
const v3f initial_speed = m_speed;
@@ -309,7 +310,7 @@ void LocalPlayer::move(f32 dtime, Environment *env, f32 pos_max_d,
collision_info->push_back(colinfo);
if (colinfo.type != COLLISION_NODE ||
- colinfo.new_speed.Y != 0 ||
+ colinfo.axis != COLLISION_AXIS_Y ||
(could_sneak && m_sneak_node_exists))
continue;
@@ -320,6 +321,7 @@ void LocalPlayer::move(f32 dtime, Environment *env, f32 pos_max_d,
if (is_first || len < distance) {
m_standing_node = colinfo.node_p;
distance = len;
+ is_first = false;
}
}
}
@@ -340,7 +342,7 @@ void LocalPlayer::move(f32 dtime, Environment *env, f32 pos_max_d,
if (m_sneak_ladder_detected) {
// restore legacy behaviour (this makes the m_speed.Y hack necessary)
- sneak_max = v3f(0.4 * BS, 0, 0.4 * BS);
+ sneak_max = v3f(0.4f * BS, 0.0f, 0.4f * BS);
}
/*
@@ -364,12 +366,12 @@ void LocalPlayer::move(f32 dtime, Environment *env, f32 pos_max_d,
bmin.Z - sneak_max.Z, bmax.Z + sneak_max.Z);
if (position.X != old_pos.X)
- m_speed.X = 0;
+ m_speed.X = 0.0f;
if (position.Z != old_pos.Z)
- m_speed.Z = 0;
+ m_speed.Z = 0.0f;
}
- if (y_diff > 0 && m_speed.Y <= 0 &&
+ if (y_diff > 0 && m_speed.Y <= 0.0f &&
(physics_override_sneak_glitch || y_diff < BS * 0.6f)) {
// Move player to the maximal height when falling or when
// the ledge is climbed on the next step.
@@ -377,11 +379,11 @@ void LocalPlayer::move(f32 dtime, Environment *env, f32 pos_max_d,
// Smoothen the movement (based on 'position.Y = bmax.Y')
position.Y += y_diff * dtime * 22.0f + BS * 0.01f;
position.Y = std::min(position.Y, bmax.Y);
- m_speed.Y = 0;
+ m_speed.Y = 0.0f;
}
// Allow jumping on node edges while sneaking
- if (m_speed.Y == 0 || m_sneak_ladder_detected)
+ if (m_speed.Y == 0.0f || m_sneak_ladder_detected)
sneak_can_jump = true;
if (collision_info &&
@@ -413,7 +415,7 @@ void LocalPlayer::move(f32 dtime, Environment *env, f32 pos_max_d,
Report collisions
*/
- if(!result.standing_on_object && !touching_ground_was && touching_ground) {
+ if (!result.standing_on_object && !touching_ground_was && touching_ground) {
m_client->getEventManager()->put(new SimpleTriggerEvent(MtEvent::PLAYER_REGAIN_GROUND));
// Set camera impact value to be used for view bobbing
@@ -423,31 +425,29 @@ void LocalPlayer::move(f32 dtime, Environment *env, f32 pos_max_d,
{
camera_barely_in_ceiling = false;
v3s16 camera_np = floatToInt(getEyePosition(), BS);
- MapNode n = map->getNodeNoEx(camera_np);
- if(n.getContent() != CONTENT_IGNORE){
- if(nodemgr->get(n).walkable && nodemgr->get(n).solidness == 2){
+ MapNode n = map->getNode(camera_np);
+ if (n.getContent() != CONTENT_IGNORE) {
+ if (nodemgr->get(n).walkable && nodemgr->get(n).solidness == 2)
camera_barely_in_ceiling = true;
- }
}
}
/*
Check properties of the node on which the player is standing
*/
- const ContentFeatures &f = nodemgr->get(map->getNodeNoEx(m_standing_node));
+ const ContentFeatures &f = nodemgr->get(map->getNode(m_standing_node));
+
// Determine if jumping is possible
- m_can_jump = (touching_ground && !in_liquid && !is_climbing)
- || sneak_can_jump;
- if (itemgroup_get(f.groups, "disable_jump"))
- m_can_jump = false;
+ m_disable_jump = itemgroup_get(f.groups, "disable_jump");
+ m_can_jump = ((touching_ground && !is_climbing) || sneak_can_jump) && !m_disable_jump;
// Jump key pressed while jumping off from a bouncy block
if (m_can_jump && control.jump && itemgroup_get(f.groups, "bouncy") &&
- m_speed.Y >= -0.5 * BS) {
+ m_speed.Y >= -0.5f * BS) {
float jumpspeed = movement_speed_jump * physics_override_jump;
- if (m_speed.Y > 1) {
+ if (m_speed.Y > 1.0f) {
// Reduce boost when speed already is high
- m_speed.Y += jumpspeed / (1 + (m_speed.Y / 16 ));
+ m_speed.Y += jumpspeed / (1.0f + (m_speed.Y / 16.0f));
} else {
m_speed.Y += jumpspeed;
}
@@ -474,19 +474,17 @@ void LocalPlayer::applyControl(float dtime, Environment *env)
setYaw(control.yaw);
// Nullify speed and don't run positioning code if the player is attached
- if(isAttached)
- {
- setSpeed(v3f(0,0,0));
+ if (isAttached) {
+ setSpeed(v3f(0.0f));
return;
}
PlayerSettings &player_settings = getPlayerSettings();
// All vectors are relative to the player's yaw,
- // (and pitch if pitch fly mode enabled),
+ // (and pitch if pitch move mode enabled),
// and will be rotated at the end
- v3f speedH = v3f(0,0,0); // Horizontal (X, Z)
- v3f speedV = v3f(0,0,0); // Vertical (Y)
+ v3f speedH, speedV; // Horizontal (X, Z) and Vertical (Y)
bool fly_allowed = m_client->checkLocalPrivilege("fly");
bool fast_allowed = m_client->checkLocalPrivilege("fast");
@@ -496,7 +494,6 @@ void LocalPlayer::applyControl(float dtime, Environment *env)
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;
- bool continuous_forward = player_settings.continuous_forward;
bool always_fly_fast = player_settings.always_fly_fast;
// Whether superspeed mode is used or not
@@ -506,76 +503,58 @@ void LocalPlayer::applyControl(float dtime, Environment *env)
superspeed = true;
// Old descend control
- if (player_settings.aux1_descends)
- {
+ if (player_settings.aux1_descends) {
// If free movement and fast movement, always move fast
- if(free_move && fast_move)
+ if (free_move && fast_move)
superspeed = true;
// Auxiliary button 1 (E)
- if(control.aux1)
- {
- if(free_move)
- {
+ if (control.aux1) {
+ if (free_move) {
// In free movement mode, aux1 descends
- if(fast_move)
+ if (fast_move)
speedV.Y = -movement_speed_fast;
else
speedV.Y = -movement_speed_walk;
- }
- else if(in_liquid || in_liquid_stable)
- {
+ } else if (in_liquid || in_liquid_stable) {
speedV.Y = -movement_speed_walk;
swimming_vertical = true;
- }
- else if(is_climbing)
- {
+ } else if (is_climbing) {
speedV.Y = -movement_speed_climb;
- }
- else
- {
+ } else {
// If not free movement but fast is allowed, aux1 is
// "Turbo button"
- if(fast_move)
+ if (fast_move)
superspeed = true;
}
}
- }
- // New minecraft-like descend control
- else
- {
+ } else {
+ // New minecraft-like descend control
+
// Auxiliary button 1 (E)
- if(control.aux1)
- {
- if(!is_climbing)
- {
+ if (control.aux1) {
+ if (!is_climbing) {
// aux1 is "Turbo button"
- if(fast_move)
+ if (fast_move)
superspeed = true;
}
}
- if(control.sneak)
- {
- if(free_move)
- {
+ if (control.sneak) {
+ if (free_move) {
// In free movement mode, sneak descends
if (fast_move && (control.aux1 || always_fly_fast))
speedV.Y = -movement_speed_fast;
else
speedV.Y = -movement_speed_walk;
- }
- else if(in_liquid || in_liquid_stable)
- {
- if(fast_climb)
+ } else if (in_liquid || in_liquid_stable) {
+ if (fast_climb)
speedV.Y = -movement_speed_fast;
else
speedV.Y = -movement_speed_walk;
swimming_vertical = true;
- }
- else if(is_climbing)
- {
- if(fast_climb)
+ } else if (is_climbing) {
+ if (fast_climb)
speedV.Y = -movement_speed_fast;
else
speedV.Y = -movement_speed_climb;
@@ -583,42 +562,32 @@ void LocalPlayer::applyControl(float dtime, Environment *env)
}
}
- if (continuous_forward)
- speedH += v3f(0,0,1);
+ if (control.up)
+ speedH += v3f(0.0f, 0.0f, 1.0f);
+
+ if (control.down)
+ speedH -= v3f(0.0f, 0.0f, 1.0f);
+
+ if (!control.up && !control.down)
+ speedH -= v3f(0.0f, 0.0f, 1.0f) * (control.forw_move_joystick_axis / 32767.f);
+
+ if (control.left)
+ speedH += v3f(-1.0f, 0.0f, 0.0f);
+
+ if (control.right)
+ speedH += v3f(1.0f, 0.0f, 0.0f);
+
+ if (!control.left && !control.right)
+ speedH += v3f(1.0f, 0.0f, 0.0f) * (control.sidew_move_joystick_axis / 32767.f);
- if (control.up) {
- if (continuous_forward) {
- if (fast_move)
- superspeed = true;
- } else {
- speedH += v3f(0,0,1);
- }
- }
- if (control.down) {
- speedH -= v3f(0,0,1);
- }
- if (!control.up && !control.down) {
- speedH -= v3f(0,0,1) *
- (control.forw_move_joystick_axis / 32767.f);
- }
- if (control.left) {
- speedH += v3f(-1,0,0);
- }
- if (control.right) {
- speedH += v3f(1,0,0);
- }
- if (!control.left && !control.right) {
- speedH += v3f(1,0,0) *
- (control.sidew_move_joystick_axis / 32767.f);
- }
if (m_autojump) {
// release autojump after a given time
m_autojump_time -= dtime;
if (m_autojump_time <= 0.0f)
m_autojump = false;
}
- if(control.jump)
- {
+
+ if (control.jump) {
if (free_move) {
if (player_settings.aux1_descends || always_fly_fast) {
if (fast_move)
@@ -626,37 +595,31 @@ void LocalPlayer::applyControl(float dtime, Environment *env)
else
speedV.Y = movement_speed_walk;
} else {
- if(fast_move && control.aux1)
+ if (fast_move && control.aux1)
speedV.Y = movement_speed_fast;
else
speedV.Y = movement_speed_walk;
}
- }
- else if(m_can_jump)
- {
+ } else if (m_can_jump) {
/*
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.5 * BS) {
+ if (speedJ.Y >= -0.5f * BS) {
speedJ.Y = movement_speed_jump * physics_override_jump;
setSpeed(speedJ);
m_client->getEventManager()->put(new SimpleTriggerEvent(MtEvent::PLAYER_JUMP));
}
- }
- else if(in_liquid)
- {
- if(fast_climb)
+ } else if (in_liquid && !m_disable_jump) {
+ if (fast_climb)
speedV.Y = movement_speed_fast;
else
speedV.Y = movement_speed_walk;
swimming_vertical = true;
- }
- else if(is_climbing)
- {
- if(fast_climb)
+ } else if (is_climbing && !m_disable_jump) {
+ if (fast_climb)
speedV.Y = movement_speed_fast;
else
speedV.Y = movement_speed_climb;
@@ -664,29 +627,31 @@ void LocalPlayer::applyControl(float dtime, Environment *env)
}
// The speed of the player (Y is ignored)
- if(superspeed || (is_climbing && fast_climb) || ((in_liquid || in_liquid_stable) && fast_climb))
+ 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)
speedH = speedH.normalize() * movement_speed_crouch;
else
speedH = speedH.normalize() * movement_speed_walk;
// Acceleration increase
- f32 incH = 0; // Horizontal (X, Z)
- f32 incV = 0; // Vertical (Y)
- if((!touching_ground && !free_move && !is_climbing && !in_liquid) || (!free_move && m_can_jump && control.jump))
- {
+ f32 incH = 0.0f; // Horizontal (X, Z)
+ f32 incV = 0.0f; // Vertical (Y)
+ if ((!touching_ground && !free_move && !is_climbing && !in_liquid) ||
+ (!free_move && m_can_jump && control.jump)) {
// Jumping and falling
- if(superspeed || (fast_move && control.aux1))
+ if (superspeed || (fast_move && control.aux1))
incH = movement_acceleration_fast * BS * dtime;
else
incH = movement_acceleration_air * BS * dtime;
- incV = 0; // No vertical acceleration in air
- }
- else if (superspeed || (is_climbing && fast_climb) || ((in_liquid || in_liquid_stable) && fast_climb))
+ incV = 0.0f; // No vertical acceleration in air
+ } else if (superspeed || (is_climbing && fast_climb) ||
+ ((in_liquid || in_liquid_stable) && fast_climb)) {
incH = incV = movement_acceleration_fast * BS * dtime;
- else
+ } else {
incH = incV = movement_acceleration_default * BS * dtime;
+ }
float slip_factor = 1.0f;
if (!free_move && !in_liquid && !in_liquid_stable)
@@ -701,47 +666,55 @@ void LocalPlayer::applyControl(float dtime, Environment *env)
// Accelerate to target speed with maximum increment
accelerate((speedH + speedV) * physics_override_speed,
- incH * physics_override_speed * slip_factor, incV * physics_override_speed,
- pitch_move);
+ incH * physics_override_speed * slip_factor, incV * physics_override_speed,
+ pitch_move);
}
v3s16 LocalPlayer::getStandingNodePos()
{
- if(m_sneak_node_exists)
+ if (m_sneak_node_exists)
return m_sneak_node;
+
return m_standing_node;
}
v3s16 LocalPlayer::getFootstepNodePos()
{
+ // Emit swimming sound if the player is in liquid
if (in_liquid_stable)
- // Emit swimming sound if the player is in liquid
return floatToInt(getPosition(), BS);
+
+ // BS * 0.05 below the player's feet ensures a 1/16th height
+ // nodebox is detected instead of the node below it.
if (touching_ground)
- // BS * 0.05 below the player's feet ensures a 1/16th height
- // nodebox is detected instead of the node below it.
- return floatToInt(getPosition() - v3f(0, BS * 0.05f, 0), BS);
+ return floatToInt(getPosition() - v3f(0.0f, BS * 0.05f, 0.0f), BS);
+
// A larger distance below is necessary for a footstep sound
// when landing after a jump or fall. BS * 0.5 ensures water
// sounds when swimming in 1 node deep water.
- return floatToInt(getPosition() - v3f(0, BS * 0.5f, 0), BS);
+ return floatToInt(getPosition() - v3f(0.0f, BS * 0.5f, 0.0f), BS);
}
v3s16 LocalPlayer::getLightPosition() const
{
- return floatToInt(m_position + v3f(0,BS+BS/2,0), BS);
+ return floatToInt(m_position + v3f(0.0f, BS * 1.5f, 0.0f), BS);
}
v3f LocalPlayer::getEyeOffset() const
{
- float eye_height = camera_barely_in_ceiling ?
- m_eye_height - 0.125f : m_eye_height;
- return v3f(0, BS * eye_height, 0);
+ float eye_height = camera_barely_in_ceiling ? m_eye_height - 0.125f : m_eye_height;
+ return v3f(0.0f, BS * eye_height, 0.0f);
+}
+
+bool LocalPlayer::isDead() const
+{
+ FATAL_ERROR_IF(!getCAO(), "LocalPlayer's CAO isn't initialized");
+ return !getCAO()->isImmortal() && hp == 0;
}
// 3D acceleration
void LocalPlayer::accelerate(const v3f &target_speed, const f32 max_increase_H,
- const f32 max_increase_V, const bool use_pitch)
+ const f32 max_increase_V, const bool use_pitch)
{
const f32 yaw = getYaw();
const f32 pitch = getPitch();
@@ -752,18 +725,18 @@ void LocalPlayer::accelerate(const v3f &target_speed, const f32 max_increase_H,
flat_speed.rotateYZBy(-pitch);
v3f d_wanted = target_speed - flat_speed;
- v3f d = v3f(0,0,0);
+ v3f d;
// Then compare the horizontal and vertical components with the wanted speed
- if (max_increase_H > 0) {
- v3f d_wanted_H = d_wanted * v3f(1,0,1);
+ if (max_increase_H > 0.0f) {
+ v3f d_wanted_H = d_wanted * v3f(1.0f, 0.0f, 1.0f);
if (d_wanted_H.getLength() > max_increase_H)
d += d_wanted_H.normalize() * max_increase_H;
else
d += d_wanted_H;
}
- if (max_increase_V > 0) {
+ if (max_increase_V > 0.0f) {
f32 d_wanted_V = d_wanted.Y;
if (d_wanted_V > max_increase_V)
d.Y += max_increase_V;
@@ -783,7 +756,7 @@ void LocalPlayer::accelerate(const v3f &target_speed, const f32 max_increase_H,
// Temporary option for old move code
void LocalPlayer::old_move(f32 dtime, Environment *env, f32 pos_max_d,
- std::vector<CollisionInfo> *collision_info)
+ std::vector<CollisionInfo> *collision_info)
{
Map *map = &env->getMap();
const NodeDefManager *nodemgr = m_client->ndef();
@@ -794,6 +767,7 @@ void LocalPlayer::old_move(f32 dtime, Environment *env, f32 pos_max_d,
if (isAttached) {
setPosition(overridePosition);
m_sneak_node_exists = false;
+ added_velocity = v3f(0.0f);
return;
}
@@ -807,9 +781,13 @@ void LocalPlayer::old_move(f32 dtime, Environment *env, f32 pos_max_d,
position += m_speed * dtime;
setPosition(position);
m_sneak_node_exists = false;
+ added_velocity = v3f(0.0f);
return;
}
+ m_speed += added_velocity;
+ added_velocity = v3f(0.0f);
+
/*
Collision detection
*/
@@ -822,8 +800,8 @@ void LocalPlayer::old_move(f32 dtime, Environment *env, f32 pos_max_d,
*/
if (in_liquid) {
// If in liquid, the threshold of coming out is at higher y
- pp = floatToInt(position + v3f(0, BS * 0.1, 0), BS);
- node = map->getNodeNoEx(pp, &is_valid_position);
+ pp = floatToInt(position + v3f(0.0f, BS * 0.1f, 0.0f), BS);
+ node = map->getNode(pp, &is_valid_position);
if (is_valid_position) {
in_liquid = nodemgr->get(node.getContent()).isLiquid();
liquid_viscosity = nodemgr->get(node.getContent()).liquid_viscosity;
@@ -832,8 +810,8 @@ void LocalPlayer::old_move(f32 dtime, Environment *env, f32 pos_max_d,
}
} else {
// If not in liquid, the threshold of going in is at lower y
- pp = floatToInt(position + v3f(0, BS * 0.5, 0), BS);
- node = map->getNodeNoEx(pp, &is_valid_position);
+ pp = floatToInt(position + v3f(0.0f, BS * 0.5f, 0.0f), BS);
+ node = map->getNode(pp, &is_valid_position);
if (is_valid_position) {
in_liquid = nodemgr->get(node.getContent()).isLiquid();
liquid_viscosity = nodemgr->get(node.getContent()).liquid_viscosity;
@@ -845,8 +823,8 @@ void LocalPlayer::old_move(f32 dtime, Environment *env, f32 pos_max_d,
/*
Check if player is in liquid (the stable value)
*/
- pp = floatToInt(position + v3f(0, 0, 0), BS);
- node = map->getNodeNoEx(pp, &is_valid_position);
+ pp = floatToInt(position + v3f(0.0f), BS);
+ node = map->getNode(pp, &is_valid_position);
if (is_valid_position)
in_liquid_stable = nodemgr->get(node.getContent()).isLiquid();
else
@@ -855,17 +833,17 @@ void LocalPlayer::old_move(f32 dtime, Environment *env, f32 pos_max_d,
/*
Check if player is climbing
*/
- pp = floatToInt(position + v3f(0, 0.5 * BS, 0), BS);
- v3s16 pp2 = floatToInt(position + v3f(0, -0.2 * BS, 0), BS);
- node = map->getNodeNoEx(pp, &is_valid_position);
+ pp = floatToInt(position + v3f(0.0f, 0.5f * BS, 0.0f), BS);
+ v3s16 pp2 = floatToInt(position + v3f(0.0f, -0.2f * BS, 0.0f), BS);
+ node = map->getNode(pp, &is_valid_position);
bool is_valid_position2;
- MapNode node2 = map->getNodeNoEx(pp2, &is_valid_position2);
+ MapNode node2 = map->getNode(pp2, &is_valid_position2);
if (!(is_valid_position && is_valid_position2))
is_climbing = false;
else
is_climbing = (nodemgr->get(node.getContent()).climbable ||
- nodemgr->get(node2.getContent()).climbable) && !free_move;
+ nodemgr->get(node2.getContent()).climbable) && !free_move;
/*
Collision uncertainty radius
@@ -873,11 +851,11 @@ void LocalPlayer::old_move(f32 dtime, Environment *env, f32 pos_max_d,
*/
//f32 d = pos_max_d * 1.1;
// A fairly large value in here makes moving smoother
- f32 d = 0.15 * BS;
+ f32 d = 0.15f * BS;
// This should always apply, otherwise there are glitches
sanity_check(d > pos_max_d);
// Maximum distance over border for sneaking
- f32 sneak_max = BS * 0.4;
+ f32 sneak_max = BS * 0.4f;
/*
If sneaking, keep in range from the last walked node and don't
@@ -886,14 +864,14 @@ void LocalPlayer::old_move(f32 dtime, Environment *env, f32 pos_max_d,
if (control.sneak && m_sneak_node_exists &&
!(fly_allowed && player_settings.free_move) && !in_liquid &&
physics_override_sneak) {
- f32 maxd = 0.5 * BS + sneak_max;
+ f32 maxd = 0.5f * BS + sneak_max;
v3f lwn_f = intToFloat(m_sneak_node, BS);
position.X = rangelim(position.X, lwn_f.X - maxd, lwn_f.X + maxd);
position.Z = rangelim(position.Z, lwn_f.Z - maxd, lwn_f.Z + maxd);
if (!is_climbing) {
// Move up if necessary
- f32 new_y = (lwn_f.Y - 0.5 * BS) + m_sneak_node_bb_ymax;
+ f32 new_y = (lwn_f.Y - 0.5f * BS) + m_sneak_node_bb_ymax;
if (position.Y < new_y)
position.Y = new_y;
/*
@@ -901,15 +879,15 @@ void LocalPlayer::old_move(f32 dtime, Environment *env, f32 pos_max_d,
sneaking over the edges of current sneaking_node.
TODO (when fixed): Set Y-speed only to 0 when position.Y < new_y.
*/
- if (m_speed.Y < 0)
- m_speed.Y = 0;
+ if (m_speed.Y < 0.0f)
+ m_speed.Y = 0.0f;
}
}
- // this shouldn't be hardcoded but transmitted from server
- float player_stepheight = touching_ground ? (BS * 0.6) : (BS * 0.2);
+ // TODO: This shouldn't be hardcoded but decided by the server
+ float player_stepheight = touching_ground ? (BS * 0.6f) : (BS * 0.2f);
- v3f accel_f = v3f(0, 0, 0);
+ v3f accel_f;
const v3f initial_position = position;
const v3f initial_speed = m_speed;
@@ -917,6 +895,12 @@ void LocalPlayer::old_move(f32 dtime, Environment *env, f32 pos_max_d,
pos_max_d, m_collisionbox, player_stepheight, dtime,
&position, &m_speed, accel_f);
+ // Positition was slightly changed; update standing node pos
+ if (touching_ground)
+ m_standing_node = floatToInt(m_position - v3f(0.0f, 0.1f * BS, 0.0f), BS);
+ else
+ m_standing_node = floatToInt(m_position, BS);
+
/*
If the player's feet touch the topside of any node, this is
set to true.
@@ -926,35 +910,35 @@ void LocalPlayer::old_move(f32 dtime, Environment *env, f32 pos_max_d,
bool touching_ground_was = touching_ground;
touching_ground = result.touching_ground;
- //bool standing_on_unloaded = result.standing_on_unloaded;
+ //bool standing_on_unloaded = result.standing_on_unloaded;
/*
Check the nodes under the player to see from which node the
- player is sneaking from, if any. If the node from under
+ player is sneaking from, if any. If the node from under
the player has been removed, the player falls.
*/
- f32 position_y_mod = 0.05 * BS;
- if (m_sneak_node_bb_ymax > 0)
+ f32 position_y_mod = 0.05f * BS;
+ if (m_sneak_node_bb_ymax > 0.0f)
position_y_mod = m_sneak_node_bb_ymax - position_y_mod;
- v3s16 current_node = floatToInt(position - v3f(0, position_y_mod, 0), BS);
+ v3s16 current_node = floatToInt(position - v3f(0.0f, position_y_mod, 0.0f), BS);
if (m_sneak_node_exists &&
- nodemgr->get(map->getNodeNoEx(m_old_node_below)).name == "air" &&
+ nodemgr->get(map->getNode(m_old_node_below)).name == "air" &&
m_old_node_below_type != "air") {
// Old node appears to have been removed; that is,
// it wasn't air before but now it is
m_need_to_get_new_sneak_node = false;
m_sneak_node_exists = false;
- } else if (nodemgr->get(map->getNodeNoEx(current_node)).name != "air") {
+ } else if (nodemgr->get(map->getNode(current_node)).name != "air") {
// We are on something, so make sure to recalculate the sneak
// node.
m_need_to_get_new_sneak_node = true;
}
if (m_need_to_get_new_sneak_node && physics_override_sneak) {
- m_sneak_node_bb_ymax = 0;
- v3s16 pos_i_bottom = floatToInt(position - v3f(0, position_y_mod, 0), BS);
+ m_sneak_node_bb_ymax = 0.0f;
+ v3s16 pos_i_bottom = floatToInt(position - v3f(0.0f, position_y_mod, 0.0f), BS);
v2f player_p2df(position.X, position.Z);
- f32 min_distance_f = 100000.0 * BS;
+ f32 min_distance_f = 100000.0f * BS;
// If already seeking from some node, compare to it.
v3s16 new_sneak_node = m_sneak_node;
for (s16 x= -1; x <= 1; x++)
@@ -964,24 +948,24 @@ void LocalPlayer::old_move(f32 dtime, Environment *env, f32 pos_max_d,
v2f node_p2df(pf.X, pf.Z);
f32 distance_f = player_p2df.getDistanceFrom(node_p2df);
f32 max_axis_distance_f = MYMAX(
- std::fabs(player_p2df.X - node_p2df.X),
- std::fabs(player_p2df.Y - node_p2df.Y));
+ std::fabs(player_p2df.X - node_p2df.X),
+ std::fabs(player_p2df.Y - node_p2df.Y));
if (distance_f > min_distance_f ||
- max_axis_distance_f > 0.5 * BS + sneak_max + 0.1 * BS)
+ max_axis_distance_f > 0.5f * BS + sneak_max + 0.1f * BS)
continue;
// The node to be sneaked on has to be walkable
- node = map->getNodeNoEx(p, &is_valid_position);
+ node = map->getNode(p, &is_valid_position);
if (!is_valid_position || !nodemgr->get(node).walkable)
continue;
// And the node above it has to be nonwalkable
- node = map->getNodeNoEx(p + v3s16(0, 1, 0), &is_valid_position);
+ node = map->getNode(p + v3s16(0, 1, 0), &is_valid_position);
if (!is_valid_position || nodemgr->get(node).walkable)
continue;
// If not 'sneak_glitch' the node 2 nodes above it has to be nonwalkable
if (!physics_override_sneak_glitch) {
- node =map->getNodeNoEx(p + v3s16(0, 2, 0), &is_valid_position);
+ node = map->getNode(p + v3s16(0, 2, 0), &is_valid_position);
if (!is_valid_position || nodemgr->get(node).walkable)
continue;
}
@@ -990,14 +974,14 @@ void LocalPlayer::old_move(f32 dtime, Environment *env, f32 pos_max_d,
new_sneak_node = p;
}
- bool sneak_node_found = (min_distance_f < 100000.0 * BS * 0.9);
+ bool sneak_node_found = (min_distance_f < 100000.0f * BS * 0.9f);
m_sneak_node = new_sneak_node;
m_sneak_node_exists = sneak_node_found;
if (sneak_node_found) {
- f32 cb_max = 0;
- MapNode n = map->getNodeNoEx(m_sneak_node);
+ f32 cb_max = 0.0f;
+ MapNode n = map->getNode(m_sneak_node);
std::vector<aabb3f> nodeboxes;
n.getCollisionBoxes(nodemgr, &nodeboxes);
for (const auto &box : nodeboxes) {
@@ -1025,7 +1009,7 @@ void LocalPlayer::old_move(f32 dtime, Environment *env, f32 pos_max_d,
/*
Report collisions
*/
- // Dont report if flying
+ // Don't report if flying
if (collision_info && !(player_settings.free_move && fly_allowed)) {
for (const auto &info : result.collisions) {
collision_info->push_back(info);
@@ -1035,13 +1019,13 @@ void LocalPlayer::old_move(f32 dtime, Environment *env, f32 pos_max_d,
if (!result.standing_on_object && !touching_ground_was && touching_ground) {
m_client->getEventManager()->put(new SimpleTriggerEvent(MtEvent::PLAYER_REGAIN_GROUND));
// Set camera impact value to be used for view bobbing
- camera_impact = getSpeed().Y * -1;
+ camera_impact = getSpeed().Y * -1.0f;
}
{
camera_barely_in_ceiling = false;
v3s16 camera_np = floatToInt(getEyePosition(), BS);
- MapNode n = map->getNodeNoEx(camera_np);
+ MapNode n = map->getNode(camera_np);
if (n.getContent() != CONTENT_IGNORE) {
if (nodemgr->get(n).walkable && nodemgr->get(n).solidness == 2)
camera_barely_in_ceiling = true;
@@ -1051,24 +1035,25 @@ void LocalPlayer::old_move(f32 dtime, Environment *env, f32 pos_max_d,
/*
Update the node last under the player
*/
- m_old_node_below = floatToInt(position - v3f(0, BS / 2, 0), BS);
- m_old_node_below_type = nodemgr->get(map->getNodeNoEx(m_old_node_below)).name;
+ m_old_node_below = floatToInt(position - v3f(0.0f, BS / 2.0f, 0.0f), BS);
+ m_old_node_below_type = nodemgr->get(map->getNode(m_old_node_below)).name;
/*
Check properties of the node on which the player is standing
*/
- const ContentFeatures &f = nodemgr->get(map->getNodeNoEx(getStandingNodePos()));
+ const ContentFeatures &f = nodemgr->get(map->getNode(getStandingNodePos()));
+
// Determine if jumping is possible
- m_can_jump = touching_ground && !in_liquid;
- if (itemgroup_get(f.groups, "disable_jump"))
- m_can_jump = false;
+ m_disable_jump = itemgroup_get(f.groups, "disable_jump");
+ m_can_jump = touching_ground && !m_disable_jump;
+
// Jump key pressed while jumping off from a bouncy block
if (m_can_jump && control.jump && itemgroup_get(f.groups, "bouncy") &&
- m_speed.Y >= -0.5 * BS) {
+ m_speed.Y >= -0.5f * BS) {
float jumpspeed = movement_speed_jump * physics_override_jump;
- if (m_speed.Y > 1) {
+ if (m_speed.Y > 1.0f) {
// Reduce boost when speed already is high
- m_speed.Y += jumpspeed / (1 + (m_speed.Y / 16 ));
+ m_speed.Y += jumpspeed / (1.0f + (m_speed.Y / 16.0f));
} else {
m_speed.Y += jumpspeed;
}
@@ -1085,24 +1070,23 @@ float LocalPlayer::getSlipFactor(Environment *env, const v3f &speedH)
// Slip on slippery nodes
const NodeDefManager *nodemgr = env->getGameDef()->ndef();
Map *map = &env->getMap();
- const ContentFeatures &f = nodemgr->get(map->getNodeNoEx(
- getStandingNodePos()));
+ const ContentFeatures &f = nodemgr->get(map->getNode(getStandingNodePos()));
int slippery = 0;
if (f.walkable)
slippery = itemgroup_get(f.groups, "slippery");
if (slippery >= 1) {
- if (speedH == v3f(0.0f)) {
- slippery = slippery * 2;
- }
+ if (speedH == v3f(0.0f))
+ slippery *= 2;
+
return core::clamp(1.0f / (slippery + 1), 0.001f, 1.0f);
}
return 1.0f;
}
void LocalPlayer::handleAutojump(f32 dtime, Environment *env,
- const collisionMoveResult &result, const v3f &initial_position,
- const v3f &initial_speed, f32 pos_max_d)
+ const collisionMoveResult &result, const v3f &initial_position,
+ const v3f &initial_speed, f32 pos_max_d)
{
PlayerSettings &player_settings = getPlayerSettings();
if (!player_settings.autojump)
@@ -1111,11 +1095,13 @@ void LocalPlayer::handleAutojump(f32 dtime, Environment *env,
if (m_autojump)
return;
- bool control_forward = control.up || player_settings.continuous_forward ||
- (!control.up && !control.down &&
- control.forw_move_joystick_axis < -0.05);
+ bool control_forward = control.up ||
+ (!control.up && !control.down &&
+ control.forw_move_joystick_axis < -0.05f);
+
bool could_autojump =
- m_can_jump && !control.jump && !control.sneak && control_forward;
+ m_can_jump && !control.jump && !control.sneak && control_forward;
+
if (!could_autojump)
return;
@@ -1139,9 +1125,9 @@ void LocalPlayer::handleAutojump(f32 dtime, Environment *env,
v3s16 ceilpos_max = floatToInt(headpos_max, BS) + v3s16(0, 1, 0);
const NodeDefManager *ndef = env->getGameDef()->ndef();
bool is_position_valid;
- for (s16 z = ceilpos_min.Z; z <= ceilpos_max.Z; z++) {
- for (s16 x = ceilpos_min.X; x <= ceilpos_max.X; x++) {
- MapNode n = env->getMap().getNodeNoEx(v3s16(x, ceilpos_max.Y, z), &is_position_valid);
+ for (s16 z = ceilpos_min.Z; z <= ceilpos_max.Z; ++z) {
+ for (s16 x = ceilpos_min.X; x <= ceilpos_max.X; ++x) {
+ MapNode n = env->getMap().getNode(v3s16(x, ceilpos_max.Y, z), &is_position_valid);
if (!is_position_valid)
break; // won't collide with the void outside
@@ -1159,8 +1145,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, 0, 0));
+ m_collisionbox, 0.0f, dtime, &jump_pos, &jump_speed, v3f(0.0f));
// see if we can get a little bit farther horizontally if we had
// jumped
diff --git a/src/client/localplayer.h b/src/client/localplayer.h
index b1fc1fbc8..45dc6776e 100644
--- a/src/client/localplayer.h
+++ b/src/client/localplayer.h
@@ -100,7 +100,7 @@ public:
bool makes_footstep_sound = true;
int last_animation = NO_ANIM;
- float last_animation_speed;
+ float last_animation_speed = 0.0f;
std::string hotbar_image = "";
std::string hotbar_selected_image = "";
@@ -149,15 +149,22 @@ public:
bool getAutojump() const { return m_autojump; }
+ bool isDead() const;
+
+ inline void addVelocity(const v3f &vel)
+ {
+ added_velocity += vel;
+ }
+
private:
void accelerate(const v3f &target_speed, const f32 max_increase_H,
- const f32 max_increase_V, const bool use_pitch);
+ const f32 max_increase_V, const bool use_pitch);
bool updateSneakNode(Map *map, const v3f &position, const v3f &sneak_max);
float getSlipFactor(Environment *env, const v3f &speedH);
void handleAutojump(f32 dtime, Environment *env,
- const collisionMoveResult &result,
- const v3f &position_before_move, const v3f &speed_before_move,
- f32 pos_max_d);
+ const collisionMoveResult &result,
+ const v3f &position_before_move, const v3f &speed_before_move,
+ f32 pos_max_d);
v3f m_position;
v3s16 m_standing_node;
@@ -183,17 +190,21 @@ private:
// ***** End of variables for temporary option *****
bool m_can_jump = false;
+ bool m_disable_jump = false;
u16 m_breath = PLAYER_MAX_BREATH_DEFAULT;
f32 m_yaw = 0.0f;
f32 m_pitch = 0.0f;
bool camera_barely_in_ceiling = false;
aabb3f m_collisionbox = aabb3f(-BS * 0.30f, 0.0f, -BS * 0.30f, BS * 0.30f,
- BS * 1.75f, BS * 0.30f);
+ BS * 1.75f, BS * 0.30f);
float m_eye_height = 1.625f;
float m_zoom_fov = 0.0f;
bool m_autojump = false;
float m_autojump_time = 0.0f;
+ v3f added_velocity = v3f(0.0f); // cleared on each move()
+ // TODO: Rename to adhere to convention: added_velocity --> m_added_velocity
+
GenericCAO *m_cao = nullptr;
Client *m_client;
};
diff --git a/src/client/mapblock_mesh.cpp b/src/client/mapblock_mesh.cpp
index 6b5ba9f9d..2bfaa7a4f 100644
--- a/src/client/mapblock_mesh.cpp
+++ b/src/client/mapblock_mesh.cpp
@@ -942,10 +942,7 @@ static void updateFastFaceRow(
makeFastFace(tile, lights[0], lights[1], lights[2], lights[3],
pf, sp, face_dir_corrected, scale, dest);
-
- g_profiler->avg("Meshgen: faces drawn by tiling", 0);
- for (int i = 1; i < continuous_tiles_count; i++)
- g_profiler->avg("Meshgen: faces drawn by tiling", 1);
+ g_profiler->avg("Meshgen: Tiles per face [#]", continuous_tiles_count);
}
continuous_tiles_count = 1;
diff --git a/src/client/mesh.cpp b/src/client/mesh.cpp
index 7fc7531f2..4d73ead8a 100644
--- a/src/client/mesh.cpp
+++ b/src/client/mesh.cpp
@@ -21,6 +21,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "debug.h"
#include "log.h"
#include "irrMap.h"
+#include <cmath>
#include <iostream>
#include <IAnimatedMesh.h>
#include <SAnimatedMesh.h>
@@ -202,6 +203,20 @@ void setMeshColor(scene::IMesh *mesh, const video::SColor &color)
setMeshBufferColor(mesh->getMeshBuffer(j), color);
}
+template <typename F>
+static void applyToMesh(scene::IMesh *mesh, const F &fn)
+{
+ u16 mc = mesh->getMeshBufferCount();
+ for (u16 j = 0; j < mc; j++) {
+ scene::IMeshBuffer *buf = mesh->getMeshBuffer(j);
+ const u32 stride = getVertexPitchFromType(buf->getVertexType());
+ u32 vertex_count = buf->getVertexCount();
+ char *vertices = reinterpret_cast<char *>(buf->getVertices());
+ for (u32 i = 0; i < vertex_count; i++)
+ fn(reinterpret_cast<video::S3DVertex *>(vertices + i * stride));
+ }
+}
+
void colorizeMeshBuffer(scene::IMeshBuffer *buf, const video::SColor *buffercolor)
{
const u32 stride = getVertexPitchFromType(buf->getVertexType());
@@ -222,28 +237,20 @@ void setMeshColorByNormalXYZ(scene::IMesh *mesh,
const video::SColor &colorY,
const video::SColor &colorZ)
{
- if (mesh == NULL)
+ if (!mesh)
return;
-
- u16 mc = mesh->getMeshBufferCount();
- for (u16 j = 0; j < mc; j++) {
- scene::IMeshBuffer *buf = mesh->getMeshBuffer(j);
- const u32 stride = getVertexPitchFromType(buf->getVertexType());
- u32 vertex_count = buf->getVertexCount();
- u8 *vertices = (u8 *)buf->getVertices();
- for (u32 i = 0; i < vertex_count; i++) {
- video::S3DVertex *vertex = (video::S3DVertex *)(vertices + i * stride);
- f32 x = fabs(vertex->Normal.X);
- f32 y = fabs(vertex->Normal.Y);
- f32 z = fabs(vertex->Normal.Z);
- if (x >= y && x >= z)
- vertex->Color = colorX;
- else if (y >= z)
- vertex->Color = colorY;
- else
- vertex->Color = colorZ;
- }
- }
+ auto colorizator = [=] (video::S3DVertex *vertex) {
+ f32 x = fabs(vertex->Normal.X);
+ f32 y = fabs(vertex->Normal.Y);
+ f32 z = fabs(vertex->Normal.Z);
+ if (x >= y && x >= z)
+ vertex->Color = colorX;
+ else if (y >= z)
+ vertex->Color = colorY;
+ else
+ vertex->Color = colorZ;
+ };
+ applyToMesh(mesh, colorizator);
}
void setMeshColorByNormal(scene::IMesh *mesh, const v3f &normal,
@@ -251,132 +258,58 @@ void setMeshColorByNormal(scene::IMesh *mesh, const v3f &normal,
{
if (!mesh)
return;
+ auto colorizator = [normal, color] (video::S3DVertex *vertex) {
+ if (vertex->Normal == normal)
+ vertex->Color = color;
+ };
+ applyToMesh(mesh, colorizator);
+}
- u16 mc = mesh->getMeshBufferCount();
- for (u16 j = 0; j < mc; j++) {
- scene::IMeshBuffer *buf = mesh->getMeshBuffer(j);
- const u32 stride = getVertexPitchFromType(buf->getVertexType());
- u32 vertex_count = buf->getVertexCount();
- u8 *vertices = (u8 *)buf->getVertices();
- for (u32 i = 0; i < vertex_count; i++) {
- video::S3DVertex *vertex = (video::S3DVertex *)(vertices + i * stride);
- if (normal == vertex->Normal) {
- vertex->Color = color;
- }
- }
- }
+template <float v3f::*U, float v3f::*V>
+static void rotateMesh(scene::IMesh *mesh, float degrees)
+{
+ degrees *= M_PI / 180.0f;
+ float c = std::cos(degrees);
+ float s = std::sin(degrees);
+ auto rotator = [c, s] (video::S3DVertex *vertex) {
+ float u = vertex->Pos.*U;
+ float v = vertex->Pos.*V;
+ vertex->Pos.*U = c * u - s * v;
+ vertex->Pos.*V = s * u + c * v;
+ };
+ applyToMesh(mesh, rotator);
}
void rotateMeshXYby(scene::IMesh *mesh, f64 degrees)
{
- u16 mc = mesh->getMeshBufferCount();
- for (u16 j = 0; j < mc; j++) {
- scene::IMeshBuffer *buf = mesh->getMeshBuffer(j);
- const u32 stride = getVertexPitchFromType(buf->getVertexType());
- u32 vertex_count = buf->getVertexCount();
- u8 *vertices = (u8 *)buf->getVertices();
- for (u32 i = 0; i < vertex_count; i++)
- ((video::S3DVertex *)(vertices + i * stride))->Pos.rotateXYBy(degrees);
- }
+ rotateMesh<&v3f::X, &v3f::Y>(mesh, degrees);
}
void rotateMeshXZby(scene::IMesh *mesh, f64 degrees)
{
- u16 mc = mesh->getMeshBufferCount();
- for (u16 j = 0; j < mc; j++) {
- scene::IMeshBuffer *buf = mesh->getMeshBuffer(j);
- const u32 stride = getVertexPitchFromType(buf->getVertexType());
- u32 vertex_count = buf->getVertexCount();
- u8 *vertices = (u8 *)buf->getVertices();
- for (u32 i = 0; i < vertex_count; i++)
- ((video::S3DVertex *)(vertices + i * stride))->Pos.rotateXZBy(degrees);
- }
+ rotateMesh<&v3f::X, &v3f::Z>(mesh, degrees);
}
void rotateMeshYZby(scene::IMesh *mesh, f64 degrees)
{
- u16 mc = mesh->getMeshBufferCount();
- for (u16 j = 0; j < mc; j++) {
- scene::IMeshBuffer *buf = mesh->getMeshBuffer(j);
- const u32 stride = getVertexPitchFromType(buf->getVertexType());
- u32 vertex_count = buf->getVertexCount();
- u8 *vertices = (u8 *)buf->getVertices();
- for (u32 i = 0; i < vertex_count; i++)
- ((video::S3DVertex *)(vertices + i * stride))->Pos.rotateYZBy(degrees);
- }
+ rotateMesh<&v3f::Y, &v3f::Z>(mesh, degrees);
}
void rotateMeshBy6dFacedir(scene::IMesh *mesh, int facedir)
{
int axisdir = facedir >> 2;
facedir &= 0x03;
-
- u16 mc = mesh->getMeshBufferCount();
- for (u16 j = 0; j < mc; j++) {
- scene::IMeshBuffer *buf = mesh->getMeshBuffer(j);
- const u32 stride = getVertexPitchFromType(buf->getVertexType());
- u32 vertex_count = buf->getVertexCount();
- u8 *vertices = (u8 *)buf->getVertices();
- for (u32 i = 0; i < vertex_count; i++) {
- video::S3DVertex *vertex = (video::S3DVertex *)(vertices + i * stride);
- switch (axisdir) {
- case 0:
- if (facedir == 1)
- vertex->Pos.rotateXZBy(-90);
- else if (facedir == 2)
- vertex->Pos.rotateXZBy(180);
- else if (facedir == 3)
- vertex->Pos.rotateXZBy(90);
- break;
- case 1: // z+
- vertex->Pos.rotateYZBy(90);
- if (facedir == 1)
- vertex->Pos.rotateXYBy(90);
- else if (facedir == 2)
- vertex->Pos.rotateXYBy(180);
- else if (facedir == 3)
- vertex->Pos.rotateXYBy(-90);
- break;
- case 2: //z-
- vertex->Pos.rotateYZBy(-90);
- if (facedir == 1)
- vertex->Pos.rotateXYBy(-90);
- else if (facedir == 2)
- vertex->Pos.rotateXYBy(180);
- else if (facedir == 3)
- vertex->Pos.rotateXYBy(90);
- break;
- case 3: //x+
- vertex->Pos.rotateXYBy(-90);
- if (facedir == 1)
- vertex->Pos.rotateYZBy(90);
- else if (facedir == 2)
- vertex->Pos.rotateYZBy(180);
- else if (facedir == 3)
- vertex->Pos.rotateYZBy(-90);
- break;
- case 4: //x-
- vertex->Pos.rotateXYBy(90);
- if (facedir == 1)
- vertex->Pos.rotateYZBy(-90);
- else if (facedir == 2)
- vertex->Pos.rotateYZBy(180);
- else if (facedir == 3)
- vertex->Pos.rotateYZBy(90);
- break;
- case 5:
- vertex->Pos.rotateXYBy(-180);
- if (facedir == 1)
- vertex->Pos.rotateXZBy(90);
- else if (facedir == 2)
- vertex->Pos.rotateXZBy(180);
- else if (facedir == 3)
- vertex->Pos.rotateXZBy(-90);
- break;
- default:
- break;
- }
- }
+ switch (facedir) {
+ case 1: rotateMeshXZby(mesh, -90); break;
+ case 2: rotateMeshXZby(mesh, 180); break;
+ case 3: rotateMeshXZby(mesh, 90); break;
+ }
+ switch (axisdir) {
+ case 1: rotateMeshYZby(mesh, 90); break; // z+
+ case 2: rotateMeshYZby(mesh, -90); break; // z-
+ case 3: rotateMeshXYby(mesh, -90); break; // x+
+ case 4: rotateMeshXYby(mesh, 90); break; // x-
+ case 5: rotateMeshXYby(mesh, -180); break;
}
}
@@ -410,8 +343,8 @@ scene::IMeshBuffer* cloneMeshBuffer(scene::IMeshBuffer *mesh_buffer)
video::S3DVertex2TCoords *v =
(video::S3DVertex2TCoords *) mesh_buffer->getVertices();
u16 *indices = mesh_buffer->getIndices();
- scene::SMeshBufferTangents *cloned_buffer =
- new scene::SMeshBufferTangents();
+ scene::SMeshBufferLightMap *cloned_buffer =
+ new scene::SMeshBufferLightMap();
cloned_buffer->append(v, mesh_buffer->getVertexCount(), indices,
mesh_buffer->getIndexCount());
return cloned_buffer;
diff --git a/src/client/mesh_generator_thread.cpp b/src/client/mesh_generator_thread.cpp
index be4bcc1f4..53b980eeb 100644
--- a/src/client/mesh_generator_thread.cpp
+++ b/src/client/mesh_generator_thread.cpp
@@ -98,7 +98,7 @@ void MeshUpdateQueue::addBlock(Map *map, v3s16 p, bool ack_block_to_server, bool
&cache_hit_counter);
cached_blocks.push_back(cached_block);
}
- g_profiler->avg("MeshUpdateQueue MapBlock cache hit %",
+ g_profiler->avg("MeshUpdateQueue: MapBlocks from cache [%]",
100.0f * cache_hit_counter / cached_blocks.size());
/*
@@ -162,39 +162,36 @@ QueuedMeshUpdate *MeshUpdateQueue::pop()
CachedMapBlockData* MeshUpdateQueue::cacheBlock(Map *map, v3s16 p, UpdateMode mode,
size_t *cache_hit_counter)
{
+ CachedMapBlockData *cached_block = nullptr;
std::map<v3s16, CachedMapBlockData*>::iterator it =
m_cache.find(p);
+
if (it != m_cache.end()) {
- // Already in cache
- CachedMapBlockData *cached_block = it->second;
+ cached_block = it->second;
+
if (mode == SKIP_UPDATE_IF_ALREADY_CACHED) {
if (cache_hit_counter)
(*cache_hit_counter)++;
return cached_block;
}
- MapBlock *b = map->getBlockNoCreateNoEx(p);
- if (b) {
- if (cached_block->data == NULL)
- cached_block->data =
- new MapNode[MAP_BLOCKSIZE * MAP_BLOCKSIZE * MAP_BLOCKSIZE];
- memcpy(cached_block->data, b->getData(),
- MAP_BLOCKSIZE * MAP_BLOCKSIZE * MAP_BLOCKSIZE * sizeof(MapNode));
- } else {
- delete[] cached_block->data;
- cached_block->data = NULL;
- }
- return cached_block;
}
- // Not yet in cache
- CachedMapBlockData *cached_block = new CachedMapBlockData();
- m_cache[p] = cached_block;
+ if (!cached_block) {
+ // Not yet in cache
+ cached_block = new CachedMapBlockData();
+ m_cache[p] = cached_block;
+ }
+
MapBlock *b = map->getBlockNoCreateNoEx(p);
if (b) {
- cached_block->data =
- new MapNode[MAP_BLOCKSIZE * MAP_BLOCKSIZE * MAP_BLOCKSIZE];
+ if (!cached_block->data)
+ cached_block->data =
+ new MapNode[MAP_BLOCKSIZE * MAP_BLOCKSIZE * MAP_BLOCKSIZE];
memcpy(cached_block->data, b->getData(),
MAP_BLOCKSIZE * MAP_BLOCKSIZE * MAP_BLOCKSIZE * sizeof(MapNode));
+ } else {
+ delete[] cached_block->data;
+ cached_block->data = nullptr;
}
return cached_block;
}
@@ -292,7 +289,7 @@ void MeshUpdateThread::doUpdate()
while ((q = m_queue_in.pop())) {
if (m_generation_interval)
sleep_ms(m_generation_interval);
- ScopeProfiler sp(g_profiler, "Client: Mesh making");
+ ScopeProfiler sp(g_profiler, "Client: Mesh making (sum)");
MapBlockMesh *mesh_new = new MapBlockMesh(q->data, m_camera_offset);
diff --git a/src/client/minimap.cpp b/src/client/minimap.cpp
index 4d83c088a..68770ec19 100644
--- a/src/client/minimap.cpp
+++ b/src/client/minimap.cpp
@@ -569,7 +569,7 @@ void Minimap::updateActiveMarkers()
m_active_markers.clear();
for (Nametag *nametag : nametags) {
- v3s16 pos = floatToInt(nametag->parent_node->getPosition() +
+ v3s16 pos = floatToInt(nametag->parent_node->getAbsolutePosition() +
intToFloat(client->getCamera()->getOffset(), BS), BS);
pos -= data->pos - v3s16(data->map_size / 2,
data->scan_height / 2,
diff --git a/src/client/particles.cpp b/src/client/particles.cpp
index ebd52f0f0..a0e4e54eb 100644
--- a/src/client/particles.cpp
+++ b/src/client/particles.cpp
@@ -21,6 +21,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include <cmath>
#include "client.h"
#include "collision.h"
+#include "client/content_cao.h"
#include "client/clientevent.h"
#include "client/renderingengine.h"
#include "util/numeric.h"
@@ -38,9 +39,10 @@ with this program; if not, write to the Free Software Foundation, Inc.,
v3f random_v3f(v3f min, v3f max)
{
- return v3f( rand()/(float)RAND_MAX*(max.X-min.X)+min.X,
- rand()/(float)RAND_MAX*(max.Y-min.Y)+min.Y,
- rand()/(float)RAND_MAX*(max.Z-min.Z)+min.Z);
+ return v3f(
+ rand() / (float)RAND_MAX * (max.X - min.X) + min.X,
+ rand() / (float)RAND_MAX * (max.Y - min.Y) + min.Y,
+ rand() / (float)RAND_MAX * (max.Z - min.Z) + min.Z);
}
Particle::Particle(
@@ -99,8 +101,13 @@ Particle::Particle(
m_glow = glow;
// Irrlicht stuff
- m_collisionbox = aabb3f
- (-size/2,-size/2,-size/2,size/2,size/2,size/2);
+ m_collisionbox = aabb3f(
+ -size / 2,
+ -size / 2,
+ -size / 2,
+ size / 2,
+ size / 2,
+ size / 2);
this->setAutomaticCulling(scene::EAC_OFF);
// Init lighting
@@ -120,7 +127,7 @@ void Particle::OnRegisterSceneNode()
void Particle::render()
{
- video::IVideoDriver* driver = SceneManager->getVideoDriver();
+ video::IVideoDriver *driver = SceneManager->getVideoDriver();
driver->setMaterial(m_material);
driver->setTransform(video::ETS_WORLD, AbsoluteTransformation);
@@ -181,7 +188,7 @@ void Particle::updateLight()
floor(m_pos.Y+0.5),
floor(m_pos.Z+0.5)
);
- MapNode n = m_env->getClientMap().getNodeNoEx(p, &pos_ok);
+ MapNode n = m_env->getClientMap().getNode(p, &pos_ok);
if (pos_ok)
light = n.getLightBlend(m_env->getDayNightRatio(), m_gamedef->ndef());
else
@@ -291,24 +298,29 @@ ParticleSpawner::ParticleSpawner(
m_animation = anim;
m_glow = glow;
- for (u16 i = 0; i<=m_amount; i++)
+ for (u16 i = 0; i <= m_amount; i++)
{
- float spawntime = (float)rand()/(float)RAND_MAX*m_spawntime;
+ float spawntime = (float)rand() / (float)RAND_MAX * m_spawntime;
m_spawntimes.push_back(spawntime);
}
}
void ParticleSpawner::spawnParticle(ClientEnvironment *env, float radius,
- bool is_attached, const v3f &attached_pos, float attached_yaw)
+ const core::matrix4 *attached_absolute_pos_rot_matrix)
{
v3f ppos = m_player->getPosition() / BS;
v3f pos = random_v3f(m_minpos, m_maxpos);
// Need to apply this first or the following check
// will be wrong for attached spawners
- if (is_attached) {
- pos.rotateXZBy(attached_yaw);
- pos += attached_pos;
+ if (attached_absolute_pos_rot_matrix) {
+ pos *= BS;
+ attached_absolute_pos_rot_matrix->transformVect(pos);
+ pos /= BS;
+ v3s16 camera_offset = m_particlemanager->m_env->getCameraOffset();
+ pos.X += camera_offset.X;
+ pos.Y += camera_offset.Y;
+ pos.Z += camera_offset.Z;
}
if (pos.getDistanceFrom(ppos) > radius)
@@ -317,18 +329,19 @@ void ParticleSpawner::spawnParticle(ClientEnvironment *env, float radius,
v3f vel = random_v3f(m_minvel, m_maxvel);
v3f acc = random_v3f(m_minacc, m_maxacc);
- if (is_attached) {
- // Apply attachment yaw
- vel.rotateXZBy(attached_yaw);
- acc.rotateXZBy(attached_yaw);
+ if (attached_absolute_pos_rot_matrix) {
+ // Apply attachment rotation
+ attached_absolute_pos_rot_matrix->rotateVect(vel);
+ attached_absolute_pos_rot_matrix->rotateVect(acc);
}
float exptime = rand() / (float)RAND_MAX
- * (m_maxexptime - m_minexptime)
- + m_minexptime;
+ * (m_maxexptime - m_minexptime)
+ + m_minexptime;
+
float size = rand() / (float)RAND_MAX
- * (m_maxsize - m_minsize)
- + m_minsize;
+ * (m_maxsize - m_minsize)
+ + m_minsize;
m_particlemanager->addParticle(new Particle(
m_gamedef,
@@ -351,7 +364,7 @@ void ParticleSpawner::spawnParticle(ClientEnvironment *env, float radius,
));
}
-void ParticleSpawner::step(float dtime, ClientEnvironment* env)
+void ParticleSpawner::step(float dtime, ClientEnvironment *env)
{
m_time += dtime;
@@ -359,14 +372,10 @@ void ParticleSpawner::step(float dtime, ClientEnvironment* env)
g_settings->getS16("max_block_send_distance") * MAP_BLOCKSIZE;
bool unloaded = false;
- bool is_attached = false;
- v3f attached_pos = v3f(0,0,0);
- float attached_yaw = 0;
- if (m_attached_id != 0) {
- if (ClientActiveObject *attached = env->getActiveObject(m_attached_id)) {
- attached_pos = attached->getPosition() / BS;
- attached_yaw = attached->getYaw();
- is_attached = true;
+ const core::matrix4 *attached_absolute_pos_rot_matrix = nullptr;
+ if (m_attached_id) {
+ if (GenericCAO *attached = dynamic_cast<GenericCAO *>(env->getActiveObject(m_attached_id))) {
+ attached_absolute_pos_rot_matrix = &attached->getAbsolutePosRotMatrix();
} else {
unloaded = true;
}
@@ -377,12 +386,12 @@ void ParticleSpawner::step(float dtime, ClientEnvironment* env)
for (std::vector<float>::iterator i = m_spawntimes.begin();
i != m_spawntimes.end();) {
if ((*i) <= m_time && m_amount > 0) {
- m_amount--;
+ --m_amount;
// Pretend to, but don't actually spawn a particle if it is
// attached to an unloaded object or distant from player.
if (!unloaded)
- spawnParticle(env, radius, is_attached, attached_pos, attached_yaw);
+ spawnParticle(env, radius, attached_absolute_pos_rot_matrix);
i = m_spawntimes.erase(i);
} else {
@@ -398,13 +407,13 @@ void ParticleSpawner::step(float dtime, ClientEnvironment* env)
for (int i = 0; i <= m_amount; i++) {
if (rand() / (float)RAND_MAX < dtime)
- spawnParticle(env, radius, is_attached, attached_pos, attached_yaw);
+ spawnParticle(env, radius, attached_absolute_pos_rot_matrix);
}
}
}
-ParticleManager::ParticleManager(ClientEnvironment* env) :
+ParticleManager::ParticleManager(ClientEnvironment *env) :
m_env(env)
{}
@@ -419,7 +428,7 @@ void ParticleManager::step(float dtime)
stepSpawners (dtime);
}
-void ParticleManager::stepSpawners (float dtime)
+void ParticleManager::stepSpawners(float dtime)
{
MutexAutoLock lock(m_spawner_list_lock);
for (auto i = m_particle_spawners.begin(); i != m_particle_spawners.end();) {
@@ -433,7 +442,7 @@ void ParticleManager::stepSpawners (float dtime)
}
}
-void ParticleManager::stepParticles (float dtime)
+void ParticleManager::stepParticles(float dtime)
{
MutexAutoLock lock(m_particle_list_lock);
for (auto i = m_particles.begin(); i != m_particles.end();) {
@@ -448,7 +457,7 @@ void ParticleManager::stepParticles (float dtime)
}
}
-void ParticleManager::clearAll ()
+void ParticleManager::clearAll()
{
MutexAutoLock lock(m_spawner_list_lock);
MutexAutoLock lock2(m_particle_list_lock);
@@ -457,9 +466,7 @@ void ParticleManager::clearAll ()
m_particle_spawners.erase(i++);
}
- for(std::vector<Particle*>::iterator i =
- m_particles.begin();
- i != m_particles.end();)
+ for(auto i = m_particles.begin(); i != m_particles.end();)
{
(*i)->remove();
delete *i;
@@ -568,7 +575,7 @@ void ParticleManager::handleParticleEvent(ClientEvent *event, Client *client,
// The final burst of particles when a node is finally dug, *not* particles
// spawned during the digging of a node.
-void ParticleManager::addDiggingParticles(IGameDef* gamedef,
+void ParticleManager::addDiggingParticles(IGameDef *gamedef,
LocalPlayer *player, v3s16 pos, const MapNode &n, const ContentFeatures &f)
{
// No particles for "airlike" nodes
@@ -583,7 +590,7 @@ void ParticleManager::addDiggingParticles(IGameDef* gamedef,
// During the digging of a node particles are spawned individually by this
// function, called from Game::handleDigging() in game.cpp.
-void ParticleManager::addNodeParticle(IGameDef* gamedef,
+void ParticleManager::addNodeParticle(IGameDef *gamedef,
LocalPlayer *player, v3s16 pos, const MapNode &n, const ContentFeatures &f)
{
// No particles for "airlike" nodes
@@ -635,7 +642,7 @@ void ParticleManager::addNodeParticle(IGameDef* gamedef,
else
n.getColor(f, &color);
- Particle* toadd = new Particle(
+ Particle *toadd = new Particle(
gamedef,
player,
m_env,
@@ -658,7 +665,7 @@ void ParticleManager::addNodeParticle(IGameDef* gamedef,
addParticle(toadd);
}
-void ParticleManager::addParticle(Particle* toadd)
+void ParticleManager::addParticle(Particle *toadd)
{
MutexAutoLock lock(m_particle_list_lock);
m_particles.push_back(toadd);
diff --git a/src/client/particles.h b/src/client/particles.h
index 353743372..e7b8cbe24 100644
--- a/src/client/particles.h
+++ b/src/client/particles.h
@@ -144,8 +144,7 @@ public:
private:
void spawnParticle(ClientEnvironment *env, float radius,
- bool is_attached, const v3f &attached_pos,
- float attached_yaw);
+ const core::matrix4 *attached_absolute_pos_rot_matrix);
ParticleManager *m_particlemanager;
float m_time;
diff --git a/src/client/render/core.cpp b/src/client/render/core.cpp
index 8c70b36c6..bf5aa6c2c 100644
--- a/src/client/render/core.cpp
+++ b/src/client/render/core.cpp
@@ -86,7 +86,7 @@ void RenderingCore::drawHUD()
if (show_hud) {
if (draw_crosshair)
hud->drawCrosshair();
- hud->drawHotbar(client->getPlayerItem());
+ hud->drawHotbar(client->getEnv().getLocalPlayer()->getWieldIndex());
hud->drawLuaElements(camera->getOffset());
camera->drawNametags();
if (mapper && show_minimap)
diff --git a/src/client/render/plain.cpp b/src/client/render/plain.cpp
index cc17c98c3..a130a14eb 100644
--- a/src/client/render/plain.cpp
+++ b/src/client/render/plain.cpp
@@ -35,7 +35,7 @@ RenderingCorePlain::RenderingCorePlain(
void RenderingCorePlain::initTextures()
{
- if (!scale)
+ if (scale <= 1)
return;
v2u32 size{scaledown(scale, screensize.X), scaledown(scale, screensize.Y)};
lowres = driver->addRenderTargetTexture(
@@ -44,21 +44,21 @@ void RenderingCorePlain::initTextures()
void RenderingCorePlain::clearTextures()
{
- if (!scale)
+ if (scale <= 1)
return;
driver->removeTexture(lowres);
}
void RenderingCorePlain::beforeDraw()
{
- if (!scale)
+ if (scale <= 1)
return;
driver->setRenderTarget(lowres, true, true, skycolor);
}
void RenderingCorePlain::upscale()
{
- if (!scale)
+ if (scale <= 1)
return;
driver->setRenderTarget(0, true, true);
v2u32 size{scaledown(scale, screensize.X), scaledown(scale, screensize.Y)};
diff --git a/src/client/renderingengine.cpp b/src/client/renderingengine.cpp
index b18e91f6e..6e6509eeb 100644
--- a/src/client/renderingengine.cpp
+++ b/src/client/renderingengine.cpp
@@ -35,6 +35,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "render/factory.h"
#include "inputhandler.h"
#include "gettext.h"
+#include "../gui/guiSkin.h"
#if !defined(_WIN32) && !defined(__APPLE__) && !defined(__ANDROID__) && \
!defined(SERVER) && !defined(__HAIKU__)
@@ -44,14 +45,38 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/Xatom.h>
+
#endif
-#ifdef __ANDROID__
+#if ENABLE_GLES
#include "filesys.h"
#endif
RenderingEngine *RenderingEngine::s_singleton = nullptr;
+
+static gui::GUISkin *createSkin(gui::IGUIEnvironment *environment,
+ gui::EGUI_SKIN_TYPE type, video::IVideoDriver *driver)
+{
+ gui::GUISkin *skin = new gui::GUISkin(type, driver);
+
+ gui::IGUIFont *builtinfont = environment->getBuiltInFont();
+ gui::IGUIFontBitmap *bitfont = nullptr;
+ if (builtinfont && builtinfont->getType() == gui::EGFT_BITMAP)
+ bitfont = (gui::IGUIFontBitmap*)builtinfont;
+
+ gui::IGUISpriteBank *bank = 0;
+ skin->setFont(builtinfont);
+
+ if (bitfont)
+ bank = bitfont->getSpriteBank();
+
+ skin->setSpriteBank(bank);
+
+ return skin;
+}
+
+
RenderingEngine::RenderingEngine(IEventReceiver *receiver)
{
sanity_check(!s_singleton);
@@ -77,7 +102,7 @@ RenderingEngine::RenderingEngine(IEventReceiver *receiver)
u32 i;
for (i = 0; i != drivers.size(); i++) {
if (!strcasecmp(driverstring.c_str(),
- RenderingEngine::getVideoDriverName(drivers[i]))) {
+ RenderingEngine::getVideoDriverName(drivers[i]))) {
driverType = drivers[i];
break;
}
@@ -106,12 +131,22 @@ RenderingEngine::RenderingEngine(IEventReceiver *receiver)
params.OGLES2ShaderPath = std::string(porting::path_user + DIR_DELIM + "media" +
DIR_DELIM + "Shaders" + DIR_DELIM).c_str();
// clang-format on
+#elif ENABLE_GLES
+ // there is no standardized path for these on desktop
+ std::string rel_path = std::string("client") + DIR_DELIM
+ + "shaders" + DIR_DELIM + "Irrlicht";
+ params.OGLES2ShaderPath = (porting::path_share + DIR_DELIM + rel_path + DIR_DELIM).c_str();
#endif
m_device = createDeviceEx(params);
driver = m_device->getVideoDriver();
s_singleton = this;
+
+ auto skin = createSkin(m_device->getGUIEnvironment(),
+ gui::EGST_WINDOWS_METALLIC, driver);
+ m_device->getGUIEnvironment()->setSkin(skin);
+ skin->drop();
}
RenderingEngine::~RenderingEngine()
@@ -193,7 +228,7 @@ bool RenderingEngine::setupTopLevelWindow(const std::string &name)
// sort here that would call the correct toplevel setup methods for
// the environment Minetest is running in but for now not deviating
// from the original pattern.
-
+
/* Setting Xorg properties for the top level window */
setupTopLevelXorgWindow(name);
/* Done with Xorg properties */
@@ -211,7 +246,7 @@ bool RenderingEngine::setupTopLevelWindow(const std::string &name)
/* Done with general properties */
// FIXME: setWindowIcon returns a bool result but it is unused.
- // For now continue to return this result.
+ // For now continue to return this result.
return result;
}
@@ -223,7 +258,7 @@ void RenderingEngine::setupTopLevelXorgWindow(const std::string &name)
Display *x11_dpl = reinterpret_cast<Display *>(exposedData.OpenGLLinux.X11Display);
if (x11_dpl == NULL) {
warningstream << "Client: Could not find X11 Display in ExposedVideoData"
- << std::endl;
+ << std::endl;
return;
}
@@ -244,30 +279,30 @@ void RenderingEngine::setupTopLevelXorgWindow(const std::string &name)
// FIXME: In the future WMNormalHints should be set ... e.g see the
// gtk/gdk code (gdk/x11/gdksurface-x11.c) for the setup_top_level
- // method. But for now (as it would require some significant changes)
- // leave the code as is.
-
+ // method. But for now (as it would require some significant changes)
+ // leave the code as is.
+
// The following is borrowed from the above gdk source for setting top
// level windows. The source indicates and the Xlib docs suggest that
- // this will set the WM_CLIENT_MACHINE and WM_LOCAL_NAME. This will not
- // set the WM_CLIENT_MACHINE to a Fully Qualified Domain Name (FQDN) which is
+ // this will set the WM_CLIENT_MACHINE and WM_LOCAL_NAME. This will not
+ // set the WM_CLIENT_MACHINE to a Fully Qualified Domain Name (FQDN) which is
// required by the Extended Window Manager Hints (EWMH) spec when setting
// the _NET_WM_PID (see further down) but running Minetest in an env
// where the window manager is on another machine from Minetest (therefore
// making the PID useless) is not expected to be a problem. Further
// more, using gtk/gdk as the model it would seem that not using a FQDN is
// not an issue for modern Xorg window managers.
-
+
verbosestream << "Client: Setting Xorg window manager Properties"
<< std::endl;
XSetWMProperties (x11_dpl, x11_win, NULL, NULL, NULL, 0, NULL, NULL, NULL);
- // Set the _NET_WM_PID window property according to the EWMH spec. _NET_WM_PID
- // (in conjunction with WM_CLIENT_MACHINE) can be used by window managers to
- // force a shutdown of an application if it doesn't respond to the destroy
- // window message.
-
+ // Set the _NET_WM_PID window property according to the EWMH spec. _NET_WM_PID
+ // (in conjunction with WM_CLIENT_MACHINE) can be used by window managers to
+ // force a shutdown of an application if it doesn't respond to the destroy
+ // window message.
+
verbosestream << "Client: Setting Xorg _NET_WM_PID extened window manager property"
<< std::endl;
@@ -277,12 +312,12 @@ void RenderingEngine::setupTopLevelXorgWindow(const std::string &name)
infostream << "Client: PID is '" << static_cast<long>(pid) << "'"
<< std::endl;
- XChangeProperty(x11_dpl, x11_win, NET_WM_PID,
- XA_CARDINAL, 32, PropModeReplace,
+ XChangeProperty(x11_dpl, x11_win, NET_WM_PID,
+ XA_CARDINAL, 32, PropModeReplace,
reinterpret_cast<unsigned char *>(&pid),1);
// Set the WM_CLIENT_LEADER window property here. Minetest has only one
- // window and that window will always be the leader.
+ // window and that window will always be the leader.
verbosestream << "Client: Setting Xorg WM_CLIENT_LEADER property"
<< std::endl;
diff --git a/src/client/shader.cpp b/src/client/shader.cpp
index 3b49a36ba..f36ff3d85 100644
--- a/src/client/shader.cpp
+++ b/src/client/shader.cpp
@@ -527,15 +527,18 @@ ShaderInfo generate_shader(const std::string &name, u8 material_type, u8 drawtyp
switch (material_type) {
case TILE_MATERIAL_OPAQUE:
case TILE_MATERIAL_LIQUID_OPAQUE:
+ case TILE_MATERIAL_WAVING_LIQUID_OPAQUE:
shaderinfo.base_material = video::EMT_SOLID;
break;
case TILE_MATERIAL_ALPHA:
case TILE_MATERIAL_LIQUID_TRANSPARENT:
+ case TILE_MATERIAL_WAVING_LIQUID_TRANSPARENT:
shaderinfo.base_material = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
break;
case TILE_MATERIAL_BASIC:
case TILE_MATERIAL_WAVING_LEAVES:
case TILE_MATERIAL_WAVING_PLANTS:
+ case TILE_MATERIAL_WAVING_LIQUID_BASIC:
shaderinfo.base_material = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
break;
}
@@ -631,10 +634,13 @@ ShaderInfo generate_shader(const std::string &name, u8 material_type, u8 drawtyp
"TILE_MATERIAL_LIQUID_OPAQUE",
"TILE_MATERIAL_WAVING_LEAVES",
"TILE_MATERIAL_WAVING_PLANTS",
- "TILE_MATERIAL_OPAQUE"
+ "TILE_MATERIAL_OPAQUE",
+ "TILE_MATERIAL_WAVING_LIQUID_BASIC",
+ "TILE_MATERIAL_WAVING_LIQUID_TRANSPARENT",
+ "TILE_MATERIAL_WAVING_LIQUID_OPAQUE",
};
- for (int i = 0; i < 7; i++){
+ for (int i = 0; i < 10; i++){
shaders_header += "#define ";
shaders_header += materialTypes[i];
shaders_header += " ";
diff --git a/src/client/sky.cpp b/src/client/sky.cpp
index ff968444d..346cd0642 100644
--- a/src/client/sky.cpp
+++ b/src/client/sky.cpp
@@ -30,6 +30,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "client/renderingengine.h"
#include "settings.h"
#include "camera.h" // CameraModes
+#include "config.h"
Sky::Sky(s32 id, ITextureSource *tsrc):
@@ -44,7 +45,7 @@ Sky::Sky(s32 id, ITextureSource *tsrc):
video::SMaterial mat;
mat.Lighting = false;
-#ifdef __ANDROID__
+#if ENABLE_GLES
mat.ZBuffer = video::ECFN_DISABLED;
#else
mat.ZBuffer = video::ECFN_NEVER;
@@ -118,8 +119,8 @@ void Sky::render()
if (!m_visible)
return;
- video::IVideoDriver* driver = SceneManager->getVideoDriver();
- scene::ICameraSceneNode* camera = SceneManager->getActiveCamera();
+ video::IVideoDriver *driver = SceneManager->getVideoDriver();
+ scene::ICameraSceneNode *camera = SceneManager->getActiveCamera();
if (!camera || !driver)
return;
@@ -273,7 +274,7 @@ void Sky::render()
// Stars are only drawn when brighter than skycolor
if (starcolor.getBlue() < m_skycolor.getBlue())
break;
-#ifdef __ANDROID__
+#if ENABLE_GLES
u16 indices[SKY_STAR_COUNT * 3];
video::S3DVertex vertices[SKY_STAR_COUNT * 3];
for (u32 i = 0; i < SKY_STAR_COUNT; i++) {
@@ -337,7 +338,7 @@ void Sky::render()
indices, SKY_STAR_COUNT, video::EVT_STANDARD,
scene::EPT_QUADS, video::EIT_16BIT);
#endif
- } while(false);
+ } while (false);
// Draw sunrise/sunset horizon glow texture (textures/base/pack/sunrisebg.png)
{
@@ -366,154 +367,12 @@ void Sky::render()
// Draw sun
if (wicked_time_of_day > 0.15 && wicked_time_of_day < 0.85) {
- if (!m_sun_texture) {
- driver->setMaterial(m_materials[1]);
- float d = sunsize * 1.7;
- video::SColor c = suncolor;
- c.setAlpha(0.05 * 255);
- vertices[0] = video::S3DVertex(-d, -d, -1, 0, 0, 1, c, t, t);
- vertices[1] = video::S3DVertex( d, -d, -1, 0, 0, 1, c, o, t);
- vertices[2] = video::S3DVertex( d, d, -1, 0, 0, 1, c, o, o);
- vertices[3] = video::S3DVertex(-d, d, -1, 0, 0, 1, c, t, o);
- for (video::S3DVertex &vertex : vertices) {
- // Switch from -Z (south) to +X (east)
- vertex.Pos.rotateXZBy(90);
- vertex.Pos.rotateXYBy(wicked_time_of_day * 360 - 90);
- }
- driver->drawIndexedTriangleFan(&vertices[0], 4, indices, 2);
-
- d = sunsize * 1.2;
- c = suncolor;
- c.setAlpha(0.15 * 255);
- vertices[0] = video::S3DVertex(-d, -d, -1, 0, 0, 1, c, t, t);
- vertices[1] = video::S3DVertex( d, -d, -1, 0, 0, 1, c, o, t);
- vertices[2] = video::S3DVertex( d, d, -1, 0, 0, 1, c, o, o);
- vertices[3] = video::S3DVertex(-d, d, -1, 0, 0, 1, c, t, o);
- for (video::S3DVertex &vertex : vertices) {
- // Switch from -Z (south) to +X (east)
- vertex.Pos.rotateXZBy(90);
- vertex.Pos.rotateXYBy(wicked_time_of_day * 360 - 90);
- }
- driver->drawIndexedTriangleFan(&vertices[0], 4, indices, 2);
-
- d = sunsize;
- vertices[0] = video::S3DVertex(-d, -d, -1, 0, 0, 1, suncolor, t, t);
- vertices[1] = video::S3DVertex( d, -d, -1, 0, 0, 1, suncolor, o, t);
- vertices[2] = video::S3DVertex( d, d, -1, 0, 0, 1, suncolor, o, o);
- vertices[3] = video::S3DVertex(-d, d, -1, 0, 0, 1, suncolor, t, o);
- for (video::S3DVertex &vertex : vertices) {
- // Switch from -Z (south) to +X (east)
- vertex.Pos.rotateXZBy(90);
- vertex.Pos.rotateXYBy(wicked_time_of_day * 360 - 90);
- }
- driver->drawIndexedTriangleFan(&vertices[0], 4, indices, 2);
-
- d = sunsize * 0.7;
- vertices[0] = video::S3DVertex(-d, -d, -1, 0, 0, 1, suncolor2, t, t);
- vertices[1] = video::S3DVertex( d, -d, -1, 0, 0, 1, suncolor2, o, t);
- vertices[2] = video::S3DVertex( d, d, -1, 0, 0, 1, suncolor2, o, o);
- vertices[3] = video::S3DVertex(-d, d, -1, 0, 0, 1, suncolor2, t, o);
- for (video::S3DVertex &vertex : vertices) {
- // Switch from -Z (south) to +X (east)
- vertex.Pos.rotateXZBy(90);
- vertex.Pos.rotateXYBy(wicked_time_of_day * 360 - 90);
- }
- driver->drawIndexedTriangleFan(&vertices[0], 4, indices, 2);
- } else {
- driver->setMaterial(m_materials[3]);
- float d = sunsize * 1.7;
- video::SColor c;
- if (m_sun_tonemap)
- c = video::SColor (0, 0, 0, 0);
- else
- c = video::SColor (255, 255, 255, 255);
- vertices[0] = video::S3DVertex(-d, -d, -1, 0, 0, 1, c, t, t);
- vertices[1] = video::S3DVertex( d, -d, -1, 0, 0, 1, c, o, t);
- vertices[2] = video::S3DVertex( d, d, -1, 0, 0, 1, c, o, o);
- vertices[3] = video::S3DVertex(-d, d, -1, 0, 0, 1, c, t, o);
- for (video::S3DVertex &vertex : vertices) {
- // Switch from -Z (south) to +X (east)
- vertex.Pos.rotateXZBy(90);
- vertex.Pos.rotateXYBy(wicked_time_of_day * 360 - 90);
- }
- driver->drawIndexedTriangleFan(&vertices[0], 4, indices, 2);
- }
+ draw_sun(driver, sunsize, suncolor, suncolor2, wicked_time_of_day);
}
// Draw moon
if (wicked_time_of_day < 0.3 || wicked_time_of_day > 0.7) {
- if (!m_moon_texture) {
- driver->setMaterial(m_materials[1]);
- float d = moonsize * 1.9;
- video::SColor c = mooncolor;
- c.setAlpha(0.05 * 255);
- vertices[0] = video::S3DVertex(-d, -d, -1, 0, 0, 1, c, t, t);
- vertices[1] = video::S3DVertex( d, -d, -1, 0, 0, 1, c, o, t);
- vertices[2] = video::S3DVertex( d, d, -1, 0, 0, 1, c, o, o);
- vertices[3] = video::S3DVertex(-d, d, -1, 0, 0, 1, c, t, o);
- for (video::S3DVertex &vertex : vertices) {
- // Switch from -Z (south) to -X (west)
- vertex.Pos.rotateXZBy(-90);
- vertex.Pos.rotateXYBy(wicked_time_of_day * 360 - 90);
- }
- driver->drawIndexedTriangleFan(&vertices[0], 4, indices, 2);
-
- d = moonsize * 1.3;
- c = mooncolor;
- c.setAlpha(0.15 * 255);
- vertices[0] = video::S3DVertex(-d, -d, -1, 0, 0, 1, c, t, t);
- vertices[1] = video::S3DVertex( d, -d, -1, 0, 0, 1, c, o, t);
- vertices[2] = video::S3DVertex( d, d, -1, 0, 0, 1, c, o, o);
- vertices[3] = video::S3DVertex(-d, d, -1, 0, 0, 1, c, t, o);
- for (video::S3DVertex &vertex : vertices) {
- // Switch from -Z (south) to -X (west)
- vertex.Pos.rotateXZBy(-90);
- vertex.Pos.rotateXYBy(wicked_time_of_day * 360 - 90);
- }
- driver->drawIndexedTriangleFan(&vertices[0], 4, indices, 2);
-
- d = moonsize;
- vertices[0] = video::S3DVertex(-d, -d, -1, 0, 0, 1, mooncolor, t, t);
- vertices[1] = video::S3DVertex( d, -d, -1, 0, 0, 1, mooncolor, o, t);
- vertices[2] = video::S3DVertex( d, d, -1, 0, 0, 1, mooncolor, o, o);
- vertices[3] = video::S3DVertex(-d, d, -1, 0, 0, 1, mooncolor, t, o);
- for (video::S3DVertex &vertex : vertices) {
- // Switch from -Z (south) to -X (west)
- vertex.Pos.rotateXZBy(-90);
- vertex.Pos.rotateXYBy(wicked_time_of_day * 360 - 90);
- }
- driver->drawIndexedTriangleFan(&vertices[0], 4, indices, 2);
-
- float d2 = moonsize * 0.6;
- vertices[0] = video::S3DVertex(-d, -d, -1, 0, 0, 1, mooncolor2, t, t);
- vertices[1] = video::S3DVertex( d2,-d, -1, 0, 0, 1, mooncolor2, o, t);
- vertices[2] = video::S3DVertex( d2, d2, -1, 0, 0, 1, mooncolor2, o, o);
- vertices[3] = video::S3DVertex(-d, d2, -1, 0, 0, 1, mooncolor2, t, o);
- for (video::S3DVertex &vertex : vertices) {
- // Switch from -Z (south) to -X (west)
- vertex.Pos.rotateXZBy(-90);
- vertex.Pos.rotateXYBy(wicked_time_of_day * 360 - 90);
- }
- driver->drawIndexedTriangleFan(&vertices[0], 4, indices, 2);
- } else {
- driver->setMaterial(m_materials[4]);
- float d = moonsize * 1.9;
- video::SColor c;
- if (m_moon_tonemap)
- c = video::SColor (0, 0, 0, 0);
- else
- c = video::SColor (255, 255, 255, 255);
- vertices[0] = video::S3DVertex(-d, -d, -1, 0, 0, 1, c, t, t);
- vertices[1] = video::S3DVertex( d, -d, -1, 0, 0, 1, c, o, t);
- vertices[2] = video::S3DVertex( d, d, -1, 0, 0, 1, c, o, o);
- vertices[3] = video::S3DVertex(-d, d, -1, 0, 0, 1, c, t, o);
- for (video::S3DVertex &vertex : vertices) {
- // Switch from -Z (south) to -X (west)
- vertex.Pos.rotateXZBy(-90);
- vertex.Pos.rotateXYBy(wicked_time_of_day * 360 - 90);
- }
- driver->drawIndexedTriangleFan(&vertices[0], 4, indices, 2);
- }
+ draw_moon(driver, moonsize, mooncolor, mooncolor2, wicked_time_of_day);
}
// Draw far cloudy fog thing below all horizons in front of sun, moon
@@ -555,8 +414,8 @@ void Sky::render()
void Sky::update(float time_of_day, float time_brightness,
- float direct_brightness, bool sunlight_seen,
- CameraMode cam_mode, float yaw, float pitch)
+ float direct_brightness, bool sunlight_seen,
+ CameraMode cam_mode, float yaw, float pitch)
{
// Stabilize initial brightness and color values by flooding updates
if (m_first_update) {
@@ -766,3 +625,128 @@ void Sky::update(float time_of_day, float time_brightness,
video::SColorf(pointcolor), m_horizon_blend() * 0.25);
}
}
+
+void Sky::draw_sun(video::IVideoDriver *driver, float sunsize, const video::SColor &suncolor,
+ const video::SColor &suncolor2, float wicked_time_of_day)
+ /* Draw sun in the sky.
+ * driver: Video driver object used to draw
+ * sunsize: the default size of the sun
+ * suncolor: main sun color
+ * suncolor2: second sun color
+ * wicked_time_of_day: current time of day, to know where should be the sun in the sky
+ */
+{
+ static const u16 indices[4] = {0, 1, 2, 3};
+ std::array<video::S3DVertex, 4> vertices;
+ if (!m_sun_texture) {
+ driver->setMaterial(m_materials[1]);
+ const float sunsizes[4] = {sunsize * 1.7f, sunsize * 1.2f, sunsize, sunsize * 0.7f};
+ video::SColor c1 = suncolor;
+ video::SColor c2 = suncolor;
+ c1.setAlpha(0.05 * 255);
+ c2.setAlpha(0.15 * 255);
+ const video::SColor colors[4] = {c1, c2, suncolor, suncolor2};
+ for (int i = 0; i < 4; i++) {
+ draw_sky_body(vertices, -sunsizes[i], sunsizes[i], colors[i]);
+ place_sky_body(vertices, 90, wicked_time_of_day * 360 - 90);
+ driver->drawIndexedTriangleFan(&vertices[0], 4, indices, 2);
+ }
+ } else {
+ driver->setMaterial(m_materials[3]);
+ float d = sunsize * 1.7;
+ video::SColor c;
+ if (m_sun_tonemap)
+ c = video::SColor(0, 0, 0, 0);
+ else
+ c = video::SColor(255, 255, 255, 255);
+ draw_sky_body(vertices, -d, d, c);
+ place_sky_body(vertices, 90, wicked_time_of_day * 360 - 90);
+ driver->drawIndexedTriangleFan(&vertices[0], 4, indices, 2);
+ }
+}
+
+
+void Sky::draw_moon(video::IVideoDriver *driver, float moonsize, const video::SColor &mooncolor,
+ const video::SColor &mooncolor2, float wicked_time_of_day)
+ /*
+ * Draw moon in the sky.
+ * driver: Video driver object used to draw
+ * moonsize: the default size of the moon
+ * mooncolor: main moon color
+ * mooncolor2: second moon color
+ * wicked_time_of_day: current time of day, to know where should be the moon in the sky
+ */
+{
+ static const u16 indices[4] = {0, 1, 2, 3};
+ std::array<video::S3DVertex, 4> vertices;
+ if (!m_moon_texture) {
+ driver->setMaterial(m_materials[1]);
+ const float moonsizes_1[4] = {
+ -moonsize * 1.9f,
+ -moonsize * 1.3f,
+ -moonsize,
+ -moonsize
+ };
+ const float moonsizes_2[4] = {
+ moonsize * 1.9f,
+ moonsize * 1.3f,
+ moonsize,
+ moonsize * 0.6f
+ };
+ video::SColor c1 = mooncolor;
+ video::SColor c2 = mooncolor;
+ c1.setAlpha(0.05 * 255);
+ c2.setAlpha(0.15 * 255);
+ const video::SColor colors[4] = {c1, c2, mooncolor, mooncolor2};
+ for (int i = 0; i < 4; i++) {
+ draw_sky_body(vertices, moonsizes_1[i], moonsizes_2[i], colors[i]);
+ place_sky_body(vertices, -90, wicked_time_of_day * 360 - 90);
+ driver->drawIndexedTriangleFan(&vertices[0], 4, indices, 2);
+ }
+ } else {
+ driver->setMaterial(m_materials[4]);
+ float d = moonsize * 1.9;
+ video::SColor c;
+ if (m_moon_tonemap)
+ c = video::SColor(0, 0, 0, 0);
+ else
+ c = video::SColor(255, 255, 255, 255);
+ draw_sky_body(vertices, -d, d, c);
+ place_sky_body(vertices, -90, wicked_time_of_day * 360 - 90);
+ driver->drawIndexedTriangleFan(&vertices[0], 4, indices, 2);
+ }
+}
+
+
+void Sky::draw_sky_body(std::array<video::S3DVertex, 4> &vertices, float pos_1, float pos_2, const video::SColor &c)
+{
+ /*
+ * Create an array of vertices with the dimensions specified.
+ * pos_1, pos_2: position of the body's vertices
+ * c: color of the body
+ */
+
+ const f32 t = 1.0f;
+ const f32 o = 0.0f;
+ vertices[0] = video::S3DVertex(pos_1, pos_1, -1, 0, 0, 1, c, t, t);
+ vertices[1] = video::S3DVertex(pos_2, pos_1, -1, 0, 0, 1, c, o, t);
+ vertices[2] = video::S3DVertex(pos_2, pos_2, -1, 0, 0, 1, c, o, o);
+ vertices[3] = video::S3DVertex(pos_1, pos_2, -1, 0, 0, 1, c, t, o);
+}
+
+
+void Sky::place_sky_body(
+ std::array<video::S3DVertex, 4> &vertices, float horizon_position, float day_position)
+ /*
+ * Place body in the sky.
+ * vertices: The body as a rectangle of 4 vertices
+ * horizon_position: turn the body around the Y axis
+ * day_position: turn the body around the Z axis, to place it depending of the time of the day
+ */
+{
+ for (video::S3DVertex &vertex : vertices) {
+ // Body is directed to -Z (south) by default
+ vertex.Pos.rotateXZBy(horizon_position);
+ vertex.Pos.rotateXYBy(day_position);
+ }
+}
diff --git a/src/client/sky.h b/src/client/sky.h
index b66a4990f..9cff20e08 100644
--- a/src/client/sky.h
+++ b/src/client/sky.h
@@ -18,6 +18,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
*/
#include <ISceneNode.h>
+#include <array>
#include "camera.h"
#include "irrlichttypes_extrabloated.h"
@@ -145,4 +146,13 @@ private:
video::ITexture *m_moon_texture;
video::ITexture *m_sun_tonemap;
video::ITexture *m_moon_tonemap;
+ void draw_sun(video::IVideoDriver *driver, float sunsize, const video::SColor &suncolor,
+ const video::SColor &suncolor2, float wicked_time_of_day);
+ void draw_moon(video::IVideoDriver *driver, float moonsize, const video::SColor &mooncolor,
+ const video::SColor &mooncolor2, float wicked_time_of_day);
+ void draw_sky_body(std::array<video::S3DVertex, 4> &vertices,
+ float pos_1, float pos_2, const video::SColor &c);
+ void place_sky_body(
+ std::array<video::S3DVertex, 4> &vertices, float horizon_position,
+ float day_position);
};
diff --git a/src/client/tile.cpp b/src/client/tile.cpp
index 4911013ae..3d9e2470a 100644
--- a/src/client/tile.cpp
+++ b/src/client/tile.cpp
@@ -21,6 +21,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include <algorithm>
#include <ICameraSceneNode.h>
+#include <IrrCompileConfig.h>
#include "util/string.h"
#include "util/container.h"
#include "util/thread.h"
@@ -34,8 +35,12 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "renderingengine.h"
-#ifdef __ANDROID__
+#if ENABLE_GLES
+#ifdef _IRR_COMPILE_WITH_OGLES1_
#include <GLES/gl.h>
+#else
+#include <GLES2/gl2.h>
+#endif
#endif
/*
@@ -117,9 +122,14 @@ std::string getImagePath(std::string path)
Utilizes a thread-safe cache.
*/
-std::string getTexturePath(const std::string &filename)
+std::string getTexturePath(const std::string &filename, bool *is_base_pack)
{
std::string fullpath;
+
+ // This can set a wrong value on cached textures, but is irrelevant because
+ // is_base_pack is only passed when initializing the textures the first time
+ if (is_base_pack)
+ *is_base_pack = false;
/*
Check from cache
*/
@@ -131,7 +141,8 @@ std::string getTexturePath(const std::string &filename)
Check from texture_path
*/
for (const auto &path : getTextureDirs()) {
- std::string testpath = path + DIR_DELIM + filename;
+ std::string testpath = path + DIR_DELIM;
+ testpath.append(filename);
// Check all filename extensions. Returns "" if not found.
fullpath = getImagePath(testpath);
if (!fullpath.empty())
@@ -148,6 +159,8 @@ std::string getTexturePath(const std::string &filename)
std::string testpath = base_path + DIR_DELIM + filename;
// Check all filename extensions. Returns "" if not found.
fullpath = getImagePath(testpath);
+ if (is_base_pack && !fullpath.empty())
+ *is_base_pack = true;
}
// Add to cache (also an empty result is cached)
@@ -209,9 +222,11 @@ public:
bool need_to_grab = true;
// Try to use local texture instead if asked to
- if (prefer_local){
- std::string path = getTexturePath(name);
- if (!path.empty()) {
+ if (prefer_local) {
+ bool is_base_pack;
+ std::string path = getTexturePath(name, &is_base_pack);
+ // Ignore base pack
+ if (!path.empty() && !is_base_pack) {
video::IImage *img2 = RenderingEngine::get_video_driver()->
createImageFromFile(path.c_str());
if (img2){
@@ -594,7 +609,7 @@ u32 TextureSource::generateTexture(const std::string &name)
video::ITexture *tex = NULL;
if (img != NULL) {
-#ifdef __ANDROID__
+#if ENABLE_GLES
img = Align2Npot2(img, driver);
#endif
// Create texture from resulting image
@@ -751,7 +766,7 @@ void TextureSource::rebuildImagesAndTextures()
// Recreate textures
for (TextureInfo &ti : m_textureinfo_cache) {
video::IImage *img = generateImage(ti.name);
-#ifdef __ANDROID__
+#if ENABLE_GLES
img = Align2Npot2(img, driver);
#endif
// Create texture from resulting image
@@ -988,8 +1003,30 @@ video::IImage* TextureSource::generateImage(const std::string &name)
return baseimg;
}
-#ifdef __ANDROID__
-#include <GLES/gl.h>
+#if ENABLE_GLES
+
+
+static inline u16 get_GL_major_version()
+{
+ const GLubyte *gl_version = glGetString(GL_VERSION);
+ return (u16) (gl_version[0] - '0');
+}
+
+/**
+ * Check if hardware requires npot2 aligned textures
+ * @return true if alignment NOT(!) requires, false otherwise
+ */
+
+bool hasNPotSupport()
+{
+ // Only GLES2 is trusted to correctly report npot support
+ // Note: we cache the boolean result, the GL context will never change.
+ static const bool supported = get_GL_major_version() > 1 &&
+ glGetString(GL_EXTENSIONS) &&
+ strstr((char *)glGetString(GL_EXTENSIONS), "GL_OES_texture_npot");
+ return supported;
+}
+
/**
* Check and align image to npot2 if required by hardware
* @param image image to check for npot2 alignment
@@ -997,53 +1034,33 @@ video::IImage* TextureSource::generateImage(const std::string &name)
* @return image or copy of image aligned to npot2
*/
-inline u16 get_GL_major_version()
-{
- const GLubyte *gl_version = glGetString(GL_VERSION);
- return (u16) (gl_version[0] - '0');
-}
-
video::IImage * Align2Npot2(video::IImage * image,
video::IVideoDriver* driver)
{
- if (image == NULL) {
+ if (image == NULL)
return image;
- }
- core::dimension2d<u32> dim = image->getDimension();
-
- // Only GLES2 is trusted to correctly report npot support
- // Note: we cache the boolean result. GL context will never change on Android.
- static const bool hasNPotSupport = get_GL_major_version() > 1 &&
- glGetString(GL_EXTENSIONS) &&
- strstr((char *)glGetString(GL_EXTENSIONS), "GL_OES_texture_npot");
-
- if (hasNPotSupport)
+ if (hasNPotSupport())
return image;
+ core::dimension2d<u32> dim = image->getDimension();
unsigned int height = npot2(dim.Height);
unsigned int width = npot2(dim.Width);
- if ((dim.Height == height) &&
- (dim.Width == width)) {
+ if (dim.Height == height && dim.Width == width)
return image;
- }
- if (dim.Height > height) {
+ if (dim.Height > height)
height *= 2;
- }
-
- if (dim.Width > width) {
+ if (dim.Width > width)
width *= 2;
- }
video::IImage *targetimage =
driver->createImage(video::ECF_A8R8G8B8,
core::dimension2d<u32>(width, height));
- if (targetimage != NULL) {
+ if (targetimage != NULL)
image->copyToScaling(targetimage);
- }
image->drop();
return targetimage;
}
@@ -1077,7 +1094,7 @@ bool TextureSource::generateImagePart(std::string part_of_name,
// Stuff starting with [ are special commands
if (part_of_name.empty() || part_of_name[0] != '[') {
video::IImage *image = m_sourcecache.getOrLoad(part_of_name);
-#ifdef __ANDROID__
+#if ENABLE_GLES
image = Align2Npot2(image, driver);
#endif
if (image == NULL) {
diff --git a/src/client/tile.h b/src/client/tile.h
index 2a33dd160..533df676e 100644
--- a/src/client/tile.h
+++ b/src/client/tile.h
@@ -27,8 +27,9 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include <SMaterial.h>
#include <memory>
#include "util/numeric.h"
+#include "config.h"
-#if __ANDROID__
+#if ENABLE_GLES
#include <IVideoDriver.h>
#endif
@@ -63,7 +64,7 @@ std::string getImagePath(std::string path);
Utilizes a thread-safe cache.
*/
-std::string getTexturePath(const std::string &filename);
+std::string getTexturePath(const std::string &filename, bool *is_base_pack = nullptr);
void clearTextureNameCache();
@@ -133,7 +134,8 @@ public:
IWritableTextureSource *createTextureSource();
-#ifdef __ANDROID__
+#if ENABLE_GLES
+bool hasNPotSupport();
video::IImage * Align2Npot2(video::IImage * image, irr::video::IVideoDriver* driver);
#endif
@@ -144,7 +146,10 @@ enum MaterialType{
TILE_MATERIAL_LIQUID_OPAQUE,
TILE_MATERIAL_WAVING_LEAVES,
TILE_MATERIAL_WAVING_PLANTS,
- TILE_MATERIAL_OPAQUE
+ TILE_MATERIAL_OPAQUE,
+ TILE_MATERIAL_WAVING_LIQUID_BASIC,
+ TILE_MATERIAL_WAVING_LIQUID_TRANSPARENT,
+ TILE_MATERIAL_WAVING_LIQUID_OPAQUE,
};
// Material flags
@@ -208,16 +213,19 @@ struct TileLayer
switch (material_type) {
case TILE_MATERIAL_OPAQUE:
case TILE_MATERIAL_LIQUID_OPAQUE:
+ case TILE_MATERIAL_WAVING_LIQUID_OPAQUE:
material.MaterialType = video::EMT_SOLID;
break;
case TILE_MATERIAL_BASIC:
case TILE_MATERIAL_WAVING_LEAVES:
case TILE_MATERIAL_WAVING_PLANTS:
+ case TILE_MATERIAL_WAVING_LIQUID_BASIC:
material.MaterialTypeParam = 0.5;
material.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
break;
case TILE_MATERIAL_ALPHA:
case TILE_MATERIAL_LIQUID_TRANSPARENT:
+ case TILE_MATERIAL_WAVING_LIQUID_TRANSPARENT:
material.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
break;
default: