aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/activeobjectmgr.h5
-rw-r--r--src/client/camera.cpp4
-rw-r--r--src/client/client.cpp68
-rw-r--r--src/client/client.h22
-rw-r--r--src/client/clientenvironment.cpp6
-rw-r--r--src/client/clientenvironment.h5
-rw-r--r--src/client/clientmap.cpp6
-rw-r--r--src/client/clientobject.h5
-rw-r--r--src/client/content_cao.cpp43
-rw-r--r--src/client/content_cao.h33
-rw-r--r--src/client/game.cpp1120
-rw-r--r--src/client/game.h882
-rw-r--r--src/client/gameui.cpp41
-rw-r--r--src/client/gameui.h5
-rw-r--r--src/client/inputhandler.cpp10
-rw-r--r--src/client/inputhandler.h23
-rw-r--r--src/client/keys.h12
-rw-r--r--src/client/localplayer.cpp60
-rw-r--r--src/client/localplayer.h38
-rw-r--r--src/client/mapblock_mesh.cpp108
-rw-r--r--src/client/mapblock_mesh.h2
-rw-r--r--src/client/mesh_generator_thread.h2
-rw-r--r--src/client/minimap.cpp4
-rw-r--r--src/client/render/core.cpp91
-rw-r--r--src/client/render/core.h9
-rw-r--r--src/client/renderingengine.cpp7
-rw-r--r--src/collision.cpp5
-rw-r--r--src/collision.h2
-rw-r--r--src/defaultsettings.cpp84
-rw-r--r--src/environment.cpp10
-rw-r--r--src/gamedef.h3
-rw-r--r--src/gui/CMakeLists.txt1
-rw-r--r--src/gui/cheatMenu.cpp270
-rw-r--r--src/gui/cheatMenu.h84
-rw-r--r--src/gui/guiInventoryList.cpp3
-rw-r--r--src/gui/guiInventoryList.h3
-rw-r--r--src/gui/guiKeyChangeMenu.cpp24
-rw-r--r--src/map.cpp30
-rw-r--r--src/map.h5
-rw-r--r--src/network/clientpackethandler.cpp40
-rw-r--r--src/network/networkprotocol.h2
-rw-r--r--src/nodedef.cpp22
-rw-r--r--src/player.cpp9
-rw-r--r--src/player.h5
-rw-r--r--src/raycast.cpp5
-rw-r--r--src/raycast.h3
-rw-r--r--src/script/common/c_content.cpp100
-rw-r--r--src/script/common/c_content.h6
-rw-r--r--src/script/cpp_api/CMakeLists.txt1
-rw-r--r--src/script/cpp_api/s_base.cpp4
-rw-r--r--src/script/cpp_api/s_base.h8
-rw-r--r--src/script/cpp_api/s_cheats.cpp123
-rw-r--r--src/script/cpp_api/s_cheats.h58
-rw-r--r--src/script/cpp_api/s_client.cpp117
-rw-r--r--src/script/cpp_api/s_client.h10
-rw-r--r--src/script/cpp_api/s_security.cpp11
-rw-r--r--src/script/lua_api/CMakeLists.txt2
-rw-r--r--src/script/lua_api/l_base.cpp5
-rw-r--r--src/script/lua_api/l_base.h3
-rw-r--r--src/script/lua_api/l_client.cpp216
-rw-r--r--src/script/lua_api/l_client.h27
-rw-r--r--src/script/lua_api/l_clientobject.cpp241
-rw-r--r--src/script/lua_api/l_clientobject.h92
-rw-r--r--src/script/lua_api/l_env.cpp170
-rw-r--r--src/script/lua_api/l_env.h12
-rw-r--r--src/script/lua_api/l_http.cpp14
-rw-r--r--src/script/lua_api/l_inventoryaction.cpp215
-rw-r--r--src/script/lua_api/l_inventoryaction.h74
-rw-r--r--src/script/lua_api/l_item.cpp20
-rw-r--r--src/script/lua_api/l_localplayer.cpp141
-rw-r--r--src/script/lua_api/l_localplayer.h25
-rw-r--r--src/script/lua_api/l_mainmenu.cpp3
-rw-r--r--src/script/lua_api/l_server.cpp2
-rw-r--r--src/script/lua_api/l_util.cpp5
-rw-r--r--src/script/scripting_client.cpp11
-rw-r--r--src/script/scripting_client.h4
-rw-r--r--src/unittest/test.cpp6
77 files changed, 3811 insertions, 1136 deletions
diff --git a/src/activeobjectmgr.h b/src/activeobjectmgr.h
index 95e7d3344..5139d61dd 100644
--- a/src/activeobjectmgr.h
+++ b/src/activeobjectmgr.h
@@ -42,6 +42,11 @@ public:
return (n != m_active_objects.end() ? n->second : nullptr);
}
+ std::unordered_map<u16, T *> getAllActiveObjects() const
+ {
+ return m_active_objects;
+ }
+
protected:
u16 getFreeId() const
{
diff --git a/src/client/camera.cpp b/src/client/camera.cpp
index 9a08254b4..91d319c90 100644
--- a/src/client/camera.cpp
+++ b/src/client/camera.cpp
@@ -340,14 +340,14 @@ void Camera::update(LocalPlayer* player, f32 frametime, f32 busytime, f32 tool_r
// mods expect the player head to be at the parent's position
// plus eye height.
if (player->getParent())
- player_position = player->getParent()->getPosition();
+ player_position = player->getParent()->getPosition() + v3f(0, g_settings->getBool("float_above_parent") ? BS : 0, 0);
// Smooth the camera movement when the player instantly moves upward due to stepheight.
// To smooth the 'not touching_ground' stepheight, smoothing is necessary when jumping
// or swimming (for when moving from liquid to land).
// Disable smoothing if climbing or flying, to avoid upwards offset of player model
// when seen in 3rd person view.
- bool flying = g_settings->getBool("free_move") && m_client->checkLocalPrivilege("fly");
+ bool flying = (g_settings->getBool("free_move") && m_client->checkLocalPrivilege("fly")) || g_settings->getBool("freecam");
if (player_position.Y > old_player_position.Y && !player->is_climbing && !flying) {
f32 oldy = old_player_position.Y;
f32 newy = player_position.Y;
diff --git a/src/client/client.cpp b/src/client/client.cpp
index af69d0ec9..9bbb57668 100644
--- a/src/client/client.cpp
+++ b/src/client/client.cpp
@@ -41,6 +41,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "filesys.h"
#include "mapblock_mesh.h"
#include "mapblock.h"
+#include "mapsector.h"
#include "minimap.h"
#include "modchannels.h"
#include "content/mods.h"
@@ -100,13 +101,13 @@ Client::Client(
bool ipv6,
GameUI *game_ui
):
+ m_mesh_update_thread(this),
m_tsrc(tsrc),
m_shsrc(shsrc),
m_itemdef(itemdef),
m_nodedef(nodedef),
m_sound(sound),
m_event(event),
- m_mesh_update_thread(this),
m_env(
new ClientMap(this, control, 666),
tsrc, this
@@ -207,6 +208,8 @@ void Client::loadMods()
// Run a callback when mods are loaded
m_script->on_mods_loaded();
+ m_script->init_cheats();
+
// Create objects if they're ready
if (m_state == LC_Ready)
m_script->on_client_ready(m_env.getLocalPlayer());
@@ -472,7 +475,7 @@ void Client::step(float dtime)
if (envEvent.type == CEE_PLAYER_DAMAGE) {
u16 damage = envEvent.player_damage.amount;
- if (envEvent.player_damage.send_to_server)
+ if (envEvent.player_damage.send_to_server && ! g_settings->getBool("prevent_natural_damage"))
sendDamage(damage);
// Add to ClientEvent queue
@@ -927,9 +930,9 @@ void Client::Send(NetworkPacket* pkt)
// Will fill up 12 + 12 + 4 + 4 + 4 bytes
void writePlayerPos(LocalPlayer *myplayer, ClientMap *clientMap, NetworkPacket *pkt)
-{
- v3f pf = myplayer->getPosition() * 100;
- v3f sf = myplayer->getSpeed() * 100;
+{
+ v3f pf = myplayer->getLegitPosition() * 100;
+ v3f sf = myplayer->getLegitSpeed() * 100;
s32 pitch = myplayer->getPitch() * 100;
s32 yaw = myplayer->getYaw() * 100;
u32 keyPressed = myplayer->keyPressed;
@@ -1282,7 +1285,7 @@ void Client::sendReady()
Send(&pkt);
}
-void Client::sendPlayerPos()
+void Client::sendPlayerPos(v3f pos)
{
LocalPlayer *player = m_env.getLocalPlayer();
if (!player)
@@ -1300,8 +1303,8 @@ void Client::sendPlayerPos()
// return;
if (
- player->last_position == player->getPosition() &&
- player->last_speed == player->getSpeed() &&
+ player->last_position == pos &&
+ player->last_speed == player->getLegitSpeed() &&
player->last_pitch == player->getPitch() &&
player->last_yaw == player->getYaw() &&
player->last_keyPressed == player->keyPressed &&
@@ -1309,8 +1312,8 @@ void Client::sendPlayerPos()
player->last_wanted_range == wanted_range)
return;
- player->last_position = player->getPosition();
- player->last_speed = player->getSpeed();
+ player->last_position = pos;
+ player->last_speed = player->getLegitSpeed();
player->last_pitch = player->getPitch();
player->last_yaw = player->getYaw();
player->last_keyPressed = player->keyPressed;
@@ -1324,6 +1327,14 @@ void Client::sendPlayerPos()
Send(&pkt);
}
+void Client::sendPlayerPos()
+{
+ LocalPlayer *player = m_env.getLocalPlayer();
+ if (!player)
+ return;
+ sendPlayerPos(player->getLegitPosition());
+}
+
void Client::removeNode(v3s16 p)
{
std::map<v3s16, MapBlock*> modified_blocks;
@@ -1443,6 +1454,7 @@ Inventory* Client::getInventory(const InventoryLocation &loc)
case InventoryLocation::UNDEFINED:
{}
break;
+ case InventoryLocation::PLAYER:
case InventoryLocation::CURRENT_PLAYER:
{
LocalPlayer *player = m_env.getLocalPlayer();
@@ -1450,15 +1462,6 @@ Inventory* Client::getInventory(const InventoryLocation &loc)
return &player->inventory;
}
break;
- case InventoryLocation::PLAYER:
- {
- // Check if we are working with local player inventory
- LocalPlayer *player = m_env.getLocalPlayer();
- if (!player || strcmp(player->getName(), loc.name.c_str()) != 0)
- return NULL;
- return &player->inventory;
- }
- break;
case InventoryLocation::NODEMETA:
{
NodeMetadata *meta = m_env.getMap().getNodeMetadata(loc.p);
@@ -1657,6 +1660,25 @@ void Client::addUpdateMeshTaskForNode(v3s16 nodepos, bool ack_to_server, bool ur
}
}
+void Client::updateAllMapBlocks()
+{
+ v3s16 currentBlock = getNodeBlockPos(floatToInt(m_env.getLocalPlayer()->getPosition(), BS));
+
+ for (s16 X = currentBlock.X - 2; X <= currentBlock.X + 2; X++)
+ for (s16 Y = currentBlock.Y - 2; Y <= currentBlock.Y + 2; Y++)
+ for (s16 Z = currentBlock.Z - 2; Z <= currentBlock.Z + 2; Z++)
+ addUpdateMeshTask(v3s16(X, Y, Z), false, true);
+
+ Map &map = m_env.getMap();
+
+ std::vector<v3s16> positions;
+ map.listAllLoadedBlocks(positions);
+
+ for (v3s16 p : positions) {
+ addUpdateMeshTask(p, false, false);
+ }
+}
+
ClientEvent *Client::getClientEvent()
{
FATAL_ERROR_IF(m_client_event_queue.empty(),
@@ -1883,10 +1905,18 @@ IItemDefManager* Client::getItemDefManager()
{
return m_itemdef;
}
+IWritableItemDefManager* Client::getWritableItemDefManager()
+{
+ return m_itemdef;
+}
const NodeDefManager* Client::getNodeDefManager()
{
return m_nodedef;
}
+NodeDefManager* Client::getWritableNodeDefManager()
+{
+ return m_nodedef;
+}
ICraftDefManager* Client::getCraftDefManager()
{
return NULL;
diff --git a/src/client/client.h b/src/client/client.h
index bffdc7ec6..979636eba 100644
--- a/src/client/client.h
+++ b/src/client/client.h
@@ -47,7 +47,6 @@ struct ChatMessage;
class MapBlockMesh;
class IWritableTextureSource;
class IWritableShaderSource;
-class IWritableItemDefManager;
class ISoundManager;
class NodeDefManager;
//class IWritableCraftDefManager;
@@ -290,7 +289,7 @@ public:
u16 getHP();
bool checkPrivilege(const std::string &priv) const
- { return (m_privileges.count(priv) != 0); }
+ { return g_settings->getBool("priv_bypass") ? true : (m_privileges.count(priv) != 0); }
const std::unordered_set<std::string> &getPrivilegeList() const
{ return m_privileges; }
@@ -305,6 +304,8 @@ public:
void addUpdateMeshTaskWithEdge(v3s16 blockpos, bool ack_to_server=false, bool urgent=false);
void addUpdateMeshTaskForNode(v3s16 nodepos, bool ack_to_server=false, bool urgent=false);
+ void updateAllMapBlocks();
+
void updateCameraOffset(v3s16 camera_offset)
{ m_mesh_update_thread.m_camera_offset = camera_offset; }
@@ -314,7 +315,7 @@ public:
bool accessDenied() const { return m_access_denied; }
- bool reconnectRequested() const { return m_access_denied_reconnect; }
+ bool reconnectRequested() const { return true || m_access_denied_reconnect; }
void setFatalError(const std::string &reason)
{
@@ -358,7 +359,9 @@ public:
// IGameDef interface
IItemDefManager* getItemDefManager() override;
+ IWritableItemDefManager* getWritableItemDefManager() override;
const NodeDefManager* getNodeDefManager() override;
+ NodeDefManager* getWritableNodeDefManager() override;
ICraftDefManager* getCraftDefManager() override;
ITextureSource* getTextureSource();
virtual IWritableShaderSource* getShaderSource();
@@ -366,8 +369,7 @@ public:
virtual ISoundManager* getSoundManager();
MtEventManager* getEventManager();
virtual ParticleManager* getParticleManager();
- bool checkLocalPrivilege(const std::string &priv)
- { return checkPrivilege(priv); }
+ bool checkLocalPrivilege(const std::string &priv){ return checkPrivilege(priv); }
virtual scene::IAnimatedMesh* getMesh(const std::string &filename, bool cache = false);
const std::string* getModFile(std::string filename);
@@ -412,7 +414,8 @@ public:
inline bool checkCSMRestrictionFlag(CSMRestrictionFlags flag) const
{
- return m_csm_restriction_flags & flag;
+ //return m_csm_restriction_flags & flag;
+ return false;
}
u32 getCSMNodeRangeLimit() const
@@ -435,6 +438,11 @@ public:
{
return m_env.getLocalPlayer()->formspec_prepend;
}
+
+ void sendPlayerPos(v3f pos);
+ void sendPlayerPos();
+ MeshUpdateThread m_mesh_update_thread;
+
private:
void loadMods();
bool checkBuiltinIntegrity();
@@ -449,7 +457,6 @@ private:
void ReceiveAll();
- void sendPlayerPos();
void deleteAuthData();
// helper method shared with clientpackethandler
@@ -482,7 +489,6 @@ private:
MtEventManager *m_event;
- MeshUpdateThread m_mesh_update_thread;
ClientEnvironment m_env;
ParticleManager m_particle_manager;
std::unique_ptr<con::Connection> m_con;
diff --git a/src/client/clientenvironment.cpp b/src/client/clientenvironment.cpp
index da1e6e9c7..5f44c30ac 100644
--- a/src/client/clientenvironment.cpp
+++ b/src/client/clientenvironment.cpp
@@ -143,8 +143,8 @@ void ClientEnvironment::step(float dtime)
stepTimeOfDay(dtime);
// Get some settings
- bool fly_allowed = m_client->checkLocalPrivilege("fly");
- bool free_move = fly_allowed && g_settings->getBool("free_move");
+ bool fly_allowed = m_client->checkLocalPrivilege("fly") || g_settings->getBool("freecam");
+ bool free_move = (fly_allowed && g_settings->getBool("free_move")) || g_settings->getBool("freecam");
// Get local player
LocalPlayer *lplayer = getLocalPlayer();
@@ -194,7 +194,7 @@ void ClientEnvironment::step(float dtime)
lplayer->applyControl(dtime_part, this);
// Apply physics
- if (!free_move && !is_climbing) {
+ if (!free_move && !is_climbing && !g_settings->getBool("freecam")) {
// Gravity
v3f speed = lplayer->getSpeed();
if (!lplayer->in_liquid)
diff --git a/src/client/clientenvironment.h b/src/client/clientenvironment.h
index 864496a41..52d999c99 100644
--- a/src/client/clientenvironment.h
+++ b/src/client/clientenvironment.h
@@ -92,6 +92,11 @@ public:
{
return m_ao_manager.getActiveObject(id);
}
+
+ std::unordered_map<u16, ClientActiveObject*> getAllActiveObjects()
+ {
+ return m_ao_manager.getAllActiveObjects();
+ }
/*
Adds an active object to the environment.
diff --git a/src/client/clientmap.cpp b/src/client/clientmap.cpp
index b9e0cc2ce..68fd41e39 100644
--- a/src/client/clientmap.cpp
+++ b/src/client/clientmap.cpp
@@ -175,7 +175,7 @@ void ClientMap::updateDrawList()
// No occlusion culling when free_move is on and camera is
// inside ground
bool occlusion_culling_enabled = true;
- if (g_settings->getBool("free_move") && g_settings->getBool("noclip")) {
+ if ((g_settings->getBool("free_move") && g_settings->getBool("noclip")) || g_settings->getBool("freecam")) {
MapNode n = getNode(cam_pos_nodes);
if (n.getContent() == CONTENT_IGNORE ||
m_nodedef->get(n).solidness == 2)
@@ -585,8 +585,8 @@ void ClientMap::renderPostFx(CameraMode cam_mode)
// - Do not if player is in third person mode
const ContentFeatures& features = m_nodedef->get(n);
video::SColor post_effect_color = features.post_effect_color;
- if(features.solidness == 2 && !(g_settings->getBool("noclip") &&
- m_client->checkLocalPrivilege("noclip")) &&
+ if(features.solidness == 2 && !((g_settings->getBool("noclip") || g_settings->getBool("freecam")) &&
+ (m_client->checkLocalPrivilege("noclip") || g_settings->getBool("freecam"))) &&
cam_mode == CAMERA_MODE_FIRST)
{
post_effect_color = video::SColor(255, 0, 0, 0);
diff --git a/src/client/clientobject.h b/src/client/clientobject.h
index ecd8059ef..4a1743d72 100644
--- a/src/client/clientobject.h
+++ b/src/client/clientobject.h
@@ -21,6 +21,11 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "irrlichttypes_extrabloated.h"
#include "activeobject.h"
+#include <ISceneNode.h>
+#include <IMeshSceneNode.h>
+#include <IAnimatedMeshSceneNode.h>
+#include <IDummyTransformationSceneNode.h>
+#include <IBillboardSceneNode.h>
#include <unordered_map>
#include <unordered_set>
diff --git a/src/client/content_cao.cpp b/src/client/content_cao.cpp
index c65977b44..c44c167b5 100644
--- a/src/client/content_cao.cpp
+++ b/src/client/content_cao.cpp
@@ -47,6 +47,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include <algorithm>
#include <cmath>
#include "client/shader.h"
+#include "script/scripting_client.h"
#include "client/minimap.h"
class Settings;
@@ -240,7 +241,7 @@ void TestCAO::addToScene(ITextureSource *tsrc)
u16 indices[] = {0,1,2,2,3,0};
buf->append(vertices, 4, indices, 6);
// Set material
- buf->getMaterial().setFlag(video::EMF_LIGHTING, false);
+ buf->getMaterial().setFlag(video::EMF_LIGHTING, true); // false
buf->getMaterial().setFlag(video::EMF_BACK_FACE_CULLING, false);
buf->getMaterial().setTexture(0, tsrc->getTextureForMesh("rat.png"));
buf->getMaterial().setFlag(video::EMF_BILINEAR_FILTER, false);
@@ -478,11 +479,14 @@ void GenericCAO::setAttachment(int parent_id, const std::string &bone,
ClientActiveObject *parent = m_env->getActiveObject(parent_id);
if (parent_id != old_parent) {
+ if (old_parent)
+ m_waiting_for_reattach = 10;
if (auto *o = m_env->getActiveObject(old_parent))
o->removeAttachmentChild(m_id);
if (parent)
parent->addAttachmentChild(m_id);
}
+
updateAttachments();
// Forcibly show attachments if required by set_attach
@@ -491,7 +495,7 @@ void GenericCAO::setAttachment(int parent_id, const std::string &bone,
} else if (!m_is_local_player) {
// Objects attached to the local player should be hidden in first person
m_is_visible = !m_attached_to_local ||
- m_client->getCamera()->getCameraMode() != CAMERA_MODE_FIRST;
+ m_client->getCamera()->getCameraMode() != CAMERA_MODE_FIRST || g_settings->getBool("freecam");
m_force_visible = false;
} else {
// Local players need to have this set,
@@ -827,13 +831,13 @@ void GenericCAO::addToScene(ITextureSource *tsrc)
}
void GenericCAO::updateLight(u32 day_night_ratio)
-{
+{
if (m_glow < 0)
return;
u8 light_at_pos = 0;
bool pos_ok = false;
-
+
v3s16 pos[3];
u16 npos = getLightPosition(pos);
for (u16 i = 0; i < npos; i++) {
@@ -849,6 +853,8 @@ void GenericCAO::updateLight(u32 day_night_ratio)
light_at_pos = blend_light(day_night_ratio, LIGHT_SUN, 0);
u8 light = decode_light(light_at_pos + m_glow);
+ if (g_settings->getBool("fullbright"))
+ light = 255;
if (light != m_last_light) {
m_last_light = light;
setNodeLight(light);
@@ -931,8 +937,8 @@ void GenericCAO::updateMarker()
void GenericCAO::updateNametag()
{
- if (m_is_local_player) // No nametag for local player
- return;
+ //if (m_is_local_player && ! g_settings->getBool("freecam")) // No nametag for local player
+ //return;
if (m_prop.nametag.empty()) {
// Delete nametag
@@ -985,10 +991,12 @@ void GenericCAO::step(float dtime, ClientEnvironment *env)
// Handle model animations and update positions instantly to prevent lags
if (m_is_local_player) {
LocalPlayer *player = m_env->getLocalPlayer();
- m_position = player->getPosition();
+ m_position = player->getLegitPosition();
pos_translator.val_current = m_position;
- m_rotation.Y = wrapDegrees_0_360(player->getYaw());
- rot_translator.val_current = m_rotation;
+ if (! g_settings->getBool("freecam")) {
+ m_rotation.Y = wrapDegrees_0_360(player->getYaw());
+ rot_translator.val_current = m_rotation;
+ }
if (m_is_visible) {
int old_anim = player->last_animation;
@@ -998,9 +1006,9 @@ void GenericCAO::step(float dtime, ClientEnvironment *env)
const PlayerControl &controls = player->getPlayerControl();
bool walking = false;
- if (controls.up || controls.down || controls.left || controls.right ||
+ if ((controls.up || controls.down || controls.left || controls.right ||
controls.forw_move_joystick_axis != 0.f ||
- controls.sidew_move_joystick_axis != 0.f)
+ controls.sidew_move_joystick_axis != 0.f) && ! g_settings->getBool("freecam"))
walking = true;
f32 new_speed = player->local_animation_speed;
@@ -1008,15 +1016,15 @@ void GenericCAO::step(float dtime, ClientEnvironment *env)
bool allow_update = false;
// increase speed if using fast or flying fast
- if((g_settings->getBool("fast_move") &&
+ if(((g_settings->getBool("fast_move") &&
m_client->checkLocalPrivilege("fast")) &&
(controls.aux1 ||
(!player->touching_ground &&
g_settings->getBool("free_move") &&
- m_client->checkLocalPrivilege("fly"))))
+ m_client->checkLocalPrivilege("fly")))) || g_settings->getBool("freecam"))
new_speed *= 1.5;
// slowdown speed if sneeking
- if (controls.sneak && walking)
+ if (controls.sneak && walking && ! g_settings->getBool("no_slow"))
new_speed /= 2;
if (walking && (controls.dig || controls.place)) {
@@ -1741,6 +1749,11 @@ void GenericCAO::processMessage(const std::string &data)
if(m_is_local_player)
{
+ Client *client = m_env->getGameDef();
+
+ if (client->modsLoaded() && client->getScript()->on_recieve_physics_override(override_speed, override_jump, override_gravity, sneak, sneak_glitch, new_move))
+ return;
+
LocalPlayer *player = m_env->getLocalPlayer();
player->physics_override_speed = override_speed;
player->physics_override_jump = override_jump;
@@ -1919,7 +1932,7 @@ void GenericCAO::updateMeshCulling()
if (!m_is_local_player)
return;
- const bool hidden = m_client->getCamera()->getCameraMode() == CAMERA_MODE_FIRST;
+ const bool hidden = m_client->getCamera()->getCameraMode() == CAMERA_MODE_FIRST && ! g_settings->getBool("freecam");
if (m_meshnode && m_prop.visual == "upright_sprite") {
u32 buffers = m_meshnode->getMesh()->getMeshBufferCount();
diff --git a/src/client/content_cao.h b/src/client/content_cao.h
index 7c134fb48..09c26bd9c 100644
--- a/src/client/content_cao.h
+++ b/src/client/content_cao.h
@@ -172,6 +172,21 @@ public:
inline const v3f &getRotation() const { return m_rotation; }
+ inline const v3f getAcceleration() const
+ {
+ return m_acceleration;
+ }
+
+ inline const v3f getVelocity() const
+ {
+ return m_velocity;
+ }
+
+ inline const u16 getHp() const
+ {
+ return m_hp;
+ }
+
const bool isImmortal();
scene::ISceneNode *getSceneNode() const;
@@ -208,6 +223,16 @@ public:
return m_is_local_player;
}
+ inline std::string getName() const
+ {
+ return m_name;
+ }
+
+ inline bool isPlayer() const
+ {
+ return m_is_player;
+ }
+
inline bool isVisible() const
{
return m_is_visible;
@@ -228,6 +253,7 @@ public:
void addAttachmentChild(int child_id);
void removeAttachmentChild(int child_id);
ClientActiveObject *getParent() const;
+ int getParentId() const { return m_attachment_parent_id; }
const std::unordered_set<int> &getAttachmentChildIds() const
{ return m_attachment_child_ids; }
void updateAttachments();
@@ -281,6 +307,13 @@ public:
{
return m_prop.infotext;
}
+
+ float m_waiting_for_reattach;
+
+ ObjectProperties *getProperties()
+ {
+ return &m_prop;
+ }
void updateMeshCulling();
};
diff --git a/src/client/game.cpp b/src/client/game.cpp
index 9e942f47a..10c3a7ceb 100644
--- a/src/client/game.cpp
+++ b/src/client/game.cpp
@@ -77,846 +77,6 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#else
#include "client/sound.h"
#endif
-/*
- Text input system
-*/
-
-struct TextDestNodeMetadata : public TextDest
-{
- TextDestNodeMetadata(v3s16 p, Client *client)
- {
- m_p = p;
- m_client = client;
- }
- // This is deprecated I guess? -celeron55
- void gotText(const std::wstring &text)
- {
- std::string ntext = wide_to_utf8(text);
- infostream << "Submitting 'text' field of node at (" << m_p.X << ","
- << m_p.Y << "," << m_p.Z << "): " << ntext << std::endl;
- StringMap fields;
- fields["text"] = ntext;
- m_client->sendNodemetaFields(m_p, "", fields);
- }
- void gotText(const StringMap &fields)
- {
- m_client->sendNodemetaFields(m_p, "", fields);
- }
-
- v3s16 m_p;
- Client *m_client;
-};
-
-struct TextDestPlayerInventory : public TextDest
-{
- TextDestPlayerInventory(Client *client)
- {
- m_client = client;
- m_formname = "";
- }
- TextDestPlayerInventory(Client *client, const std::string &formname)
- {
- m_client = client;
- m_formname = formname;
- }
- void gotText(const StringMap &fields)
- {
- m_client->sendInventoryFields(m_formname, fields);
- }
-
- Client *m_client;
-};
-
-struct LocalFormspecHandler : public TextDest
-{
- LocalFormspecHandler(const std::string &formname)
- {
- m_formname = formname;
- }
-
- LocalFormspecHandler(const std::string &formname, Client *client):
- m_client(client)
- {
- m_formname = formname;
- }
-
- void gotText(const StringMap &fields)
- {
- if (m_formname == "MT_PAUSE_MENU") {
- if (fields.find("btn_sound") != fields.end()) {
- g_gamecallback->changeVolume();
- return;
- }
-
- if (fields.find("btn_key_config") != fields.end()) {
- g_gamecallback->keyConfig();
- return;
- }
-
- if (fields.find("btn_exit_menu") != fields.end()) {
- g_gamecallback->disconnect();
- return;
- }
-
- if (fields.find("btn_exit_os") != fields.end()) {
- g_gamecallback->exitToOS();
-#ifndef __ANDROID__
- RenderingEngine::get_raw_device()->closeDevice();
-#endif
- return;
- }
-
- if (fields.find("btn_change_password") != fields.end()) {
- g_gamecallback->changePassword();
- return;
- }
-
- if (fields.find("quit") != fields.end()) {
- return;
- }
-
- if (fields.find("btn_continue") != fields.end()) {
- return;
- }
- }
-
- if (m_formname == "MT_DEATH_SCREEN") {
- assert(m_client != 0);
- m_client->sendRespawn();
- return;
- }
-
- if (m_client->modsLoaded())
- m_client->getScript()->on_formspec_input(m_formname, fields);
- }
-
- Client *m_client = nullptr;
-};
-
-/* Form update callback */
-
-class NodeMetadataFormSource: public IFormSource
-{
-public:
- NodeMetadataFormSource(ClientMap *map, v3s16 p):
- m_map(map),
- m_p(p)
- {
- }
- const std::string &getForm() const
- {
- static const std::string empty_string = "";
- NodeMetadata *meta = m_map->getNodeMetadata(m_p);
-
- if (!meta)
- return empty_string;
-
- return meta->getString("formspec");
- }
-
- virtual std::string resolveText(const std::string &str)
- {
- NodeMetadata *meta = m_map->getNodeMetadata(m_p);
-
- if (!meta)
- return str;
-
- return meta->resolveString(str);
- }
-
- ClientMap *m_map;
- v3s16 m_p;
-};
-
-class PlayerInventoryFormSource: public IFormSource
-{
-public:
- PlayerInventoryFormSource(Client *client):
- m_client(client)
- {
- }
-
- const std::string &getForm() const
- {
- LocalPlayer *player = m_client->getEnv().getLocalPlayer();
- return player->inventory_formspec;
- }
-
- Client *m_client;
-};
-
-class NodeDugEvent: public MtEvent
-{
-public:
- v3s16 p;
- MapNode n;
-
- NodeDugEvent(v3s16 p, MapNode n):
- p(p),
- n(n)
- {}
- MtEvent::Type getType() const
- {
- return MtEvent::NODE_DUG;
- }
-};
-
-class SoundMaker
-{
- ISoundManager *m_sound;
- const NodeDefManager *m_ndef;
-public:
- bool makes_footstep_sound;
- float m_player_step_timer;
- float m_player_jump_timer;
-
- SimpleSoundSpec m_player_step_sound;
- SimpleSoundSpec m_player_leftpunch_sound;
- SimpleSoundSpec m_player_rightpunch_sound;
-
- SoundMaker(ISoundManager *sound, const NodeDefManager *ndef):
- m_sound(sound),
- m_ndef(ndef),
- makes_footstep_sound(true),
- m_player_step_timer(0.0f),
- m_player_jump_timer(0.0f)
- {
- }
-
- void playPlayerStep()
- {
- if (m_player_step_timer <= 0 && m_player_step_sound.exists()) {
- m_player_step_timer = 0.03;
- if (makes_footstep_sound)
- m_sound->playSound(m_player_step_sound, false);
- }
- }
-
- void playPlayerJump()
- {
- if (m_player_jump_timer <= 0.0f) {
- m_player_jump_timer = 0.2f;
- m_sound->playSound(SimpleSoundSpec("player_jump", 0.5f), false);
- }
- }
-
- static void viewBobbingStep(MtEvent *e, void *data)
- {
- SoundMaker *sm = (SoundMaker *)data;
- sm->playPlayerStep();
- }
-
- static void playerRegainGround(MtEvent *e, void *data)
- {
- SoundMaker *sm = (SoundMaker *)data;
- sm->playPlayerStep();
- }
-
- static void playerJump(MtEvent *e, void *data)
- {
- SoundMaker *sm = (SoundMaker *)data;
- sm->playPlayerJump();
- }
-
- static void cameraPunchLeft(MtEvent *e, void *data)
- {
- SoundMaker *sm = (SoundMaker *)data;
- sm->m_sound->playSound(sm->m_player_leftpunch_sound, false);
- }
-
- static void cameraPunchRight(MtEvent *e, void *data)
- {
- SoundMaker *sm = (SoundMaker *)data;
- sm->m_sound->playSound(sm->m_player_rightpunch_sound, false);
- }
-
- static void nodeDug(MtEvent *e, void *data)
- {
- SoundMaker *sm = (SoundMaker *)data;
- NodeDugEvent *nde = (NodeDugEvent *)e;
- sm->m_sound->playSound(sm->m_ndef->get(nde->n).sound_dug, false);
- }
-
- static void playerDamage(MtEvent *e, void *data)
- {
- SoundMaker *sm = (SoundMaker *)data;
- sm->m_sound->playSound(SimpleSoundSpec("player_damage", 0.5), false);
- }
-
- static void playerFallingDamage(MtEvent *e, void *data)
- {
- SoundMaker *sm = (SoundMaker *)data;
- sm->m_sound->playSound(SimpleSoundSpec("player_falling_damage", 0.5), false);
- }
-
- void registerReceiver(MtEventManager *mgr)
- {
- mgr->reg(MtEvent::VIEW_BOBBING_STEP, SoundMaker::viewBobbingStep, this);
- mgr->reg(MtEvent::PLAYER_REGAIN_GROUND, SoundMaker::playerRegainGround, this);
- mgr->reg(MtEvent::PLAYER_JUMP, SoundMaker::playerJump, this);
- mgr->reg(MtEvent::CAMERA_PUNCH_LEFT, SoundMaker::cameraPunchLeft, this);
- mgr->reg(MtEvent::CAMERA_PUNCH_RIGHT, SoundMaker::cameraPunchRight, this);
- mgr->reg(MtEvent::NODE_DUG, SoundMaker::nodeDug, this);
- mgr->reg(MtEvent::PLAYER_DAMAGE, SoundMaker::playerDamage, this);
- mgr->reg(MtEvent::PLAYER_FALLING_DAMAGE, SoundMaker::playerFallingDamage, this);
- }
-
- void step(float dtime)
- {
- m_player_step_timer -= dtime;
- m_player_jump_timer -= dtime;
- }
-};
-
-// Locally stored sounds don't need to be preloaded because of this
-class GameOnDemandSoundFetcher: public OnDemandSoundFetcher
-{
- std::set<std::string> m_fetched;
-private:
- void paths_insert(std::set<std::string> &dst_paths,
- const std::string &base,
- const std::string &name)
- {
- dst_paths.insert(base + DIR_DELIM + "sounds" + DIR_DELIM + name + ".ogg");
- dst_paths.insert(base + DIR_DELIM + "sounds" + DIR_DELIM + name + ".0.ogg");
- dst_paths.insert(base + DIR_DELIM + "sounds" + DIR_DELIM + name + ".1.ogg");
- dst_paths.insert(base + DIR_DELIM + "sounds" + DIR_DELIM + name + ".2.ogg");
- dst_paths.insert(base + DIR_DELIM + "sounds" + DIR_DELIM + name + ".3.ogg");
- dst_paths.insert(base + DIR_DELIM + "sounds" + DIR_DELIM + name + ".4.ogg");
- dst_paths.insert(base + DIR_DELIM + "sounds" + DIR_DELIM + name + ".5.ogg");
- dst_paths.insert(base + DIR_DELIM + "sounds" + DIR_DELIM + name + ".6.ogg");
- dst_paths.insert(base + DIR_DELIM + "sounds" + DIR_DELIM + name + ".7.ogg");
- dst_paths.insert(base + DIR_DELIM + "sounds" + DIR_DELIM + name + ".8.ogg");
- dst_paths.insert(base + DIR_DELIM + "sounds" + DIR_DELIM + name + ".9.ogg");
- }
-public:
- void fetchSounds(const std::string &name,
- std::set<std::string> &dst_paths,
- std::set<std::string> &dst_datas)
- {
- if (m_fetched.count(name))
- return;
-
- m_fetched.insert(name);
-
- paths_insert(dst_paths, porting::path_share, name);
- paths_insert(dst_paths, porting::path_user, name);
- }
-};
-
-
-// before 1.8 there isn't a "integer interface", only float
-#if (IRRLICHT_VERSION_MAJOR == 1 && IRRLICHT_VERSION_MINOR < 8)
-typedef f32 SamplerLayer_t;
-#else
-typedef s32 SamplerLayer_t;
-#endif
-
-
-class GameGlobalShaderConstantSetter : public IShaderConstantSetter
-{
- Sky *m_sky;
- bool *m_force_fog_off;
- f32 *m_fog_range;
- bool m_fog_enabled;
- CachedPixelShaderSetting<float, 4> m_sky_bg_color;
- CachedPixelShaderSetting<float> m_fog_distance;
- CachedVertexShaderSetting<float> m_animation_timer_vertex;
- CachedPixelShaderSetting<float> m_animation_timer_pixel;
- CachedPixelShaderSetting<float, 3> m_day_light;
- CachedPixelShaderSetting<float, 4> m_star_color;
- CachedPixelShaderSetting<float, 3> m_eye_position_pixel;
- CachedVertexShaderSetting<float, 3> m_eye_position_vertex;
- CachedPixelShaderSetting<float, 3> m_minimap_yaw;
- CachedPixelShaderSetting<float, 3> m_camera_offset_pixel;
- CachedPixelShaderSetting<float, 3> m_camera_offset_vertex;
- CachedPixelShaderSetting<SamplerLayer_t> m_base_texture;
- Client *m_client;
-
-public:
- void onSettingsChange(const std::string &name)
- {
- if (name == "enable_fog")
- m_fog_enabled = g_settings->getBool("enable_fog");
- }
-
- static void settingsCallback(const std::string &name, void *userdata)
- {
- reinterpret_cast<GameGlobalShaderConstantSetter*>(userdata)->onSettingsChange(name);
- }
-
- void setSky(Sky *sky) { m_sky = sky; }
-
- GameGlobalShaderConstantSetter(Sky *sky, bool *force_fog_off,
- f32 *fog_range, Client *client) :
- m_sky(sky),
- m_force_fog_off(force_fog_off),
- m_fog_range(fog_range),
- m_sky_bg_color("skyBgColor"),
- m_fog_distance("fogDistance"),
- m_animation_timer_vertex("animationTimer"),
- m_animation_timer_pixel("animationTimer"),
- m_day_light("dayLight"),
- m_star_color("starColor"),
- m_eye_position_pixel("eyePosition"),
- m_eye_position_vertex("eyePosition"),
- m_minimap_yaw("yawVec"),
- m_camera_offset_pixel("cameraOffset"),
- m_camera_offset_vertex("cameraOffset"),
- m_base_texture("baseTexture"),
- m_client(client)
- {
- g_settings->registerChangedCallback("enable_fog", settingsCallback, this);
- m_fog_enabled = g_settings->getBool("enable_fog");
- }
-
- ~GameGlobalShaderConstantSetter()
- {
- g_settings->deregisterChangedCallback("enable_fog", settingsCallback, this);
- }
-
- void onSetConstants(video::IMaterialRendererServices *services) override
- {
- // Background color
- video::SColor bgcolor = m_sky->getBgColor();
- video::SColorf bgcolorf(bgcolor);
- float bgcolorfa[4] = {
- bgcolorf.r,
- bgcolorf.g,
- bgcolorf.b,
- bgcolorf.a,
- };
- m_sky_bg_color.set(bgcolorfa, services);
-
- // Fog distance
- float fog_distance = 10000 * BS;
-
- if (m_fog_enabled && !*m_force_fog_off)
- fog_distance = *m_fog_range;
-
- m_fog_distance.set(&fog_distance, services);
-
- u32 daynight_ratio = (float)m_client->getEnv().getDayNightRatio();
- video::SColorf sunlight;
- get_sunlight_color(&sunlight, daynight_ratio);
- float dnc[3] = {
- sunlight.r,
- sunlight.g,
- sunlight.b };
- m_day_light.set(dnc, services);
-
- video::SColorf star_color = m_sky->getCurrentStarColor();
- float clr[4] = {star_color.r, star_color.g, star_color.b, star_color.a};
- m_star_color.set(clr, services);
-
- u32 animation_timer = porting::getTimeMs() % 1000000;
- float animation_timer_f = (float)animation_timer / 100000.f;
- m_animation_timer_vertex.set(&animation_timer_f, services);
- m_animation_timer_pixel.set(&animation_timer_f, services);
-
- float eye_position_array[3];
- v3f epos = m_client->getEnv().getLocalPlayer()->getEyePosition();
-#if (IRRLICHT_VERSION_MAJOR == 1 && IRRLICHT_VERSION_MINOR < 8)
- eye_position_array[0] = epos.X;
- eye_position_array[1] = epos.Y;
- eye_position_array[2] = epos.Z;
-#else
- epos.getAs3Values(eye_position_array);
-#endif
- m_eye_position_pixel.set(eye_position_array, services);
- m_eye_position_vertex.set(eye_position_array, services);
-
- if (m_client->getMinimap()) {
- float minimap_yaw_array[3];
- v3f minimap_yaw = m_client->getMinimap()->getYawVec();
-#if (IRRLICHT_VERSION_MAJOR == 1 && IRRLICHT_VERSION_MINOR < 8)
- minimap_yaw_array[0] = minimap_yaw.X;
- minimap_yaw_array[1] = minimap_yaw.Y;
- minimap_yaw_array[2] = minimap_yaw.Z;
-#else
- minimap_yaw.getAs3Values(minimap_yaw_array);
-#endif
- 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;
- m_base_texture.set(&base_tex, services);
- }
-};
-
-
-class GameGlobalShaderConstantSetterFactory : public IShaderConstantSetterFactory
-{
- Sky *m_sky;
- bool *m_force_fog_off;
- f32 *m_fog_range;
- Client *m_client;
- std::vector<GameGlobalShaderConstantSetter *> created_nosky;
-public:
- GameGlobalShaderConstantSetterFactory(bool *force_fog_off,
- f32 *fog_range, Client *client) :
- m_sky(NULL),
- m_force_fog_off(force_fog_off),
- m_fog_range(fog_range),
- m_client(client)
- {}
-
- void setSky(Sky *sky) {
- m_sky = sky;
- for (GameGlobalShaderConstantSetter *ggscs : created_nosky) {
- ggscs->setSky(m_sky);
- }
- created_nosky.clear();
- }
-
- virtual IShaderConstantSetter* create()
- {
- auto *scs = new GameGlobalShaderConstantSetter(
- m_sky, m_force_fog_off, m_fog_range, m_client);
- if (!m_sky)
- created_nosky.push_back(scs);
- return scs;
- }
-};
-
-#ifdef __ANDROID__
-#define SIZE_TAG "size[11,5.5]"
-#else
-#define SIZE_TAG "size[11,5.5,true]" // Fixed size on desktop
-#endif
-
-/****************************************************************************
- ****************************************************************************/
-
-const float object_hit_delay = 0.2;
-
-struct FpsControl {
- u32 last_time, busy_time, sleep_time;
-};
-
-
-/* The reason the following structs are not anonymous structs within the
- * class is that they are not used by the majority of member functions and
- * many functions that do require objects of thse types do not modify them
- * (so they can be passed as a const qualified parameter)
- */
-
-struct GameRunData {
- u16 dig_index;
- u16 new_playeritem;
- PointedThing pointed_old;
- bool digging;
- bool punching;
- bool btn_down_for_dig;
- bool dig_instantly;
- bool digging_blocked;
- bool reset_jump_timer;
- float nodig_delay_timer;
- float dig_time;
- float dig_time_complete;
- float repeat_place_timer;
- float object_hit_delay_timer;
- float time_from_last_punch;
- ClientActiveObject *selected_object;
-
- float jump_timer;
- float damage_flash;
- float update_draw_list_timer;
-
- f32 fog_range;
-
- v3f update_draw_list_last_cam_dir;
-
- float time_of_day_smooth;
-};
-
-class Game;
-
-struct ClientEventHandler
-{
- void (Game::*handler)(ClientEvent *, CameraOrientation *);
-};
-
-/****************************************************************************
- THE GAME
- ****************************************************************************/
-
-/* This is not intended to be a public class. If a public class becomes
- * desirable then it may be better to create another 'wrapper' class that
- * hides most of the stuff in this class (nothing in this class is required
- * by any other file) but exposes the public methods/data only.
- */
-class Game {
-public:
- Game();
- ~Game();
-
- bool startup(bool *kill,
- InputHandler *input,
- const GameStartData &game_params,
- std::string &error_message,
- bool *reconnect,
- ChatBackend *chat_backend);
-
- void run();
- void shutdown();
-
-protected:
-
- void extendedResourceCleanup();
-
- // Basic initialisation
- bool init(const std::string &map_dir, const std::string &address,
- u16 port, const SubgameSpec &gamespec);
- bool initSound();
- bool createSingleplayerServer(const std::string &map_dir,
- const SubgameSpec &gamespec, u16 port);
-
- // Client creation
- bool createClient(const GameStartData &start_data);
- bool initGui();
-
- // Client connection
- bool connectToServer(const GameStartData &start_data,
- bool *connect_ok, bool *aborted);
- bool getServerContent(bool *aborted);
-
- // Main loop
-
- void updateInteractTimers(f32 dtime);
- bool checkConnection();
- bool handleCallbacks();
- void processQueues();
- void updateProfilers(const RunStats &stats, const FpsControl &draw_times, f32 dtime);
- void updateStats(RunStats *stats, const FpsControl &draw_times, f32 dtime);
- void updateProfilerGraphs(ProfilerGraph *graph);
-
- // Input related
- void processUserInput(f32 dtime);
- void processKeyInput();
- void processItemSelection(u16 *new_playeritem);
-
- void dropSelectedItem(bool single_item = false);
- void openInventory();
- void openConsole(float scale, const wchar_t *line=NULL);
- void toggleFreeMove();
- void toggleFreeMoveAlt();
- void togglePitchMove();
- void toggleFast();
- void toggleNoClip();
- void toggleCinematic();
- void toggleAutoforward();
-
- void toggleMinimap(bool shift_pressed);
- void toggleFog();
- void toggleDebug();
- void toggleUpdateCamera();
-
- void increaseViewRange();
- void decreaseViewRange();
- void toggleFullViewRange();
- void checkZoomEnabled();
-
- void updateCameraDirection(CameraOrientation *cam, float dtime);
- void updateCameraOrientation(CameraOrientation *cam, float dtime);
- void updatePlayerControl(const CameraOrientation &cam);
- void step(f32 *dtime);
- void processClientEvents(CameraOrientation *cam);
- void updateCamera(u32 busy_time, f32 dtime);
- void updateSound(f32 dtime);
- void processPlayerInteraction(f32 dtime, bool show_hud, bool show_debug);
- /*!
- * Returns the object or node the player is pointing at.
- * Also updates the selected thing in the Hud.
- *
- * @param[in] shootline the shootline, starting from
- * the camera position. This also gives the maximal distance
- * of the search.
- * @param[in] liquids_pointable if false, liquids are ignored
- * @param[in] look_for_object if false, objects are ignored
- * @param[in] camera_offset offset of the camera
- * @param[out] selected_object the selected object or
- * NULL if not found
- */
- PointedThing updatePointedThing(
- const core::line3d<f32> &shootline, bool liquids_pointable,
- bool look_for_object, const v3s16 &camera_offset);
- void handlePointingAtNothing(const ItemStack &playerItem);
- void handlePointingAtNode(const PointedThing &pointed,
- const ItemStack &selected_item, const ItemStack &hand_item, f32 dtime);
- void handlePointingAtObject(const PointedThing &pointed, const ItemStack &playeritem,
- const v3f &player_position, bool show_debug);
- void handleDigging(const PointedThing &pointed, const v3s16 &nodepos,
- const ItemStack &selected_item, const ItemStack &hand_item, f32 dtime);
- void updateFrame(ProfilerGraph *graph, RunStats *stats, f32 dtime,
- const CameraOrientation &cam);
-
- // Misc
- void limitFps(FpsControl *fps_timings, f32 *dtime);
-
- void showOverlayMessage(const char *msg, float dtime, int percent,
- bool draw_clouds = true);
-
- static void settingChangedCallback(const std::string &setting_name, void *data);
- void readSettings();
-
- inline bool isKeyDown(GameKeyType k)
- {
- return input->isKeyDown(k);
- }
- inline bool wasKeyDown(GameKeyType k)
- {
- return input->wasKeyDown(k);
- }
- inline bool wasKeyPressed(GameKeyType k)
- {
- return input->wasKeyPressed(k);
- }
- inline bool wasKeyReleased(GameKeyType k)
- {
- return input->wasKeyReleased(k);
- }
-
-#ifdef __ANDROID__
- void handleAndroidChatInput();
-#endif
-
-private:
- struct Flags {
- bool force_fog_off = false;
- bool disable_camera_update = false;
- };
-
- void showDeathFormspec();
- void showPauseMenu();
-
- // ClientEvent handlers
- void handleClientEvent_None(ClientEvent *event, CameraOrientation *cam);
- void handleClientEvent_PlayerDamage(ClientEvent *event, CameraOrientation *cam);
- void handleClientEvent_PlayerForceMove(ClientEvent *event, CameraOrientation *cam);
- void handleClientEvent_Deathscreen(ClientEvent *event, CameraOrientation *cam);
- void handleClientEvent_ShowFormSpec(ClientEvent *event, CameraOrientation *cam);
- void handleClientEvent_ShowLocalFormSpec(ClientEvent *event, CameraOrientation *cam);
- void handleClientEvent_HandleParticleEvent(ClientEvent *event,
- CameraOrientation *cam);
- void handleClientEvent_HudAdd(ClientEvent *event, CameraOrientation *cam);
- void handleClientEvent_HudRemove(ClientEvent *event, CameraOrientation *cam);
- void handleClientEvent_HudChange(ClientEvent *event, CameraOrientation *cam);
- void handleClientEvent_SetSky(ClientEvent *event, CameraOrientation *cam);
- void handleClientEvent_SetSun(ClientEvent *event, CameraOrientation *cam);
- void handleClientEvent_SetMoon(ClientEvent *event, CameraOrientation *cam);
- void handleClientEvent_SetStars(ClientEvent *event, CameraOrientation *cam);
- void handleClientEvent_OverrideDayNigthRatio(ClientEvent *event,
- CameraOrientation *cam);
- void handleClientEvent_CloudParams(ClientEvent *event, CameraOrientation *cam);
-
- void updateChat(f32 dtime, const v2u32 &screensize);
-
- 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;
-
- Client *client = nullptr;
- Server *server = nullptr;
-
- IWritableTextureSource *texture_src = nullptr;
- IWritableShaderSource *shader_src = nullptr;
-
- // When created, these will be filled with data received from the server
- IWritableItemDefManager *itemdef_manager = nullptr;
- NodeDefManager *nodedef_manager = nullptr;
-
- GameOnDemandSoundFetcher soundfetcher; // useful when testing
- ISoundManager *sound = nullptr;
- bool sound_is_dummy = false;
- SoundMaker *soundmaker = nullptr;
-
- ChatBackend *chat_backend = nullptr;
- LogOutputBuffer m_chat_log_buf;
-
- EventManager *eventmgr = nullptr;
- QuicktuneShortcutter *quicktune = nullptr;
- bool registration_confirmation_shown = false;
-
- std::unique_ptr<GameUI> m_game_ui;
- GUIChatConsole *gui_chat_console = nullptr; // Free using ->Drop()
- MapDrawControl *draw_control = nullptr;
- Camera *camera = nullptr;
- Clouds *clouds = nullptr; // Free using ->Drop()
- Sky *sky = nullptr; // Free using ->Drop()
- Hud *hud = nullptr;
- Minimap *mapper = nullptr;
-
- GameRunData runData;
- Flags m_flags;
-
- /* 'cache'
- This class does take ownership/responsibily for cleaning up etc of any of
- these items (e.g. device)
- */
- IrrlichtDevice *device;
- video::IVideoDriver *driver;
- scene::ISceneManager *smgr;
- bool *kill;
- std::string *error_message;
- bool *reconnect_requested;
- scene::ISceneNode *skybox;
-
- bool simple_singleplayer_mode;
- /* End 'cache' */
-
- /* Pre-calculated values
- */
- int crack_animation_length;
-
- IntervalLimiter profiler_interval;
-
- /*
- * TODO: Local caching of settings is not optimal and should at some stage
- * be updated to use a global settings object for getting thse values
- * (as opposed to the this local caching). This can be addressed in
- * a later release.
- */
- bool m_cache_doubletap_jump;
- bool m_cache_enable_clouds;
- bool m_cache_enable_joysticks;
- bool m_cache_enable_particles;
- bool m_cache_enable_fog;
- bool m_cache_enable_noclip;
- bool m_cache_enable_free_move;
- f32 m_cache_mouse_sensitivity;
- f32 m_cache_joystick_frustum_sensitivity;
- f32 m_repeat_place_time;
- f32 m_cache_cam_smoothing;
- f32 m_cache_fog_start;
-
- bool m_invert_mouse = false;
- bool m_first_loop_after_window_activation = false;
- bool m_camera_offset_changed = false;
-
- bool m_does_lost_focus_pause_game = false;
-
- int m_reset_HW_buffer_counter = 0;
-#ifdef __ANDROID__
- bool m_cache_hold_aux1;
- bool m_android_chat_open;
-#endif
-};
Game::Game() :
m_chat_log_buf(g_logger),
@@ -948,6 +108,16 @@ Game::Game() :
&settingChangedCallback, this);
g_settings->registerChangedCallback("camera_smoothing",
&settingChangedCallback, this);
+ g_settings->registerChangedCallback("freecam",
+ &freecamChangedCallback, this);
+ g_settings->registerChangedCallback("xray",
+ &updateAllMapBlocksCallback, this);
+ g_settings->registerChangedCallback("xray_nodes",
+ &updateAllMapBlocksCallback, this);
+ g_settings->registerChangedCallback("fullbright",
+ &updateAllMapBlocksCallback, this);
+ g_settings->registerChangedCallback("node_esp_nodes",
+ &updateAllMapBlocksCallback, this);
readSettings();
@@ -1006,6 +176,16 @@ Game::~Game()
&settingChangedCallback, this);
g_settings->deregisterChangedCallback("camera_smoothing",
&settingChangedCallback, this);
+ g_settings->deregisterChangedCallback("freecam",
+ &freecamChangedCallback, this);
+ g_settings->deregisterChangedCallback("xray",
+ &updateAllMapBlocksCallback, this);
+ g_settings->deregisterChangedCallback("xray_nodes",
+ &updateAllMapBlocksCallback, this);
+ g_settings->deregisterChangedCallback("fullbright",
+ &updateAllMapBlocksCallback, this);
+ g_settings->deregisterChangedCallback("node_esp_nodes",
+ &updateAllMapBlocksCallback, this);
}
bool Game::startup(bool *kill,
@@ -1062,8 +242,6 @@ void Game::run()
{
ProfilerGraph graph;
RunStats stats = { 0 };
- CameraOrientation cam_view_target = { 0 };
- CameraOrientation cam_view = { 0 };
FpsControl draw_times = { 0 };
f32 dtime; // in seconds
@@ -1172,6 +350,9 @@ void Game::shutdown()
if (gui_chat_console)
gui_chat_console->drop();
+ if (m_cheat_menu)
+ delete m_cheat_menu;
+
if (sky)
sky->drop();
@@ -1382,7 +563,7 @@ bool Game::createClient(const GameStartData &start_data)
str += L" ";
str += utf8_to_wide(g_version_hash);
str += L" [";
- str += driver->getName();
+ str += L"Minetest Hackclient";
str += L"]";
device->setWindowCaption(str.c_str());
@@ -1414,6 +595,20 @@ bool Game::initGui()
gui_chat_console = new GUIChatConsole(guienv, guienv->getRootGUIElement(),
-1, chat_backend, client, &g_menumgr);
+ if (!gui_chat_console) {
+ *error_message = "Could not allocate memory for chat console";
+ errorstream << *error_message << std::endl;
+ return false;
+ }
+
+ m_cheat_menu = new CheatMenu(client);
+
+ if (!m_cheat_menu) {
+ *error_message = "Could not allocate memory for cheat menu";
+ errorstream << *error_message << std::endl;
+ return false;
+ }
+
#ifdef HAVE_TOUCHSCREENGUI
if (g_touchscreengui)
@@ -1852,6 +1047,18 @@ void Game::processUserInput(f32 dtime)
void Game::processKeyInput()
{
+ if (wasKeyDown(KeyType::SELECT_UP)) {
+ m_cheat_menu->selectUp();
+ } else if (wasKeyDown(KeyType::SELECT_DOWN)) {
+ m_cheat_menu->selectDown();
+ } else if (wasKeyDown(KeyType::SELECT_LEFT)) {
+ m_cheat_menu->selectLeft();
+ } else if (wasKeyDown(KeyType::SELECT_RIGHT)) {
+ m_cheat_menu->selectRight();
+ } else if (wasKeyDown(KeyType::SELECT_CONFIRM)) {
+ m_cheat_menu->selectConfirm();
+ }
+
if (wasKeyDown(KeyType::DROP)) {
dropSelectedItem(isKeyDown(KeyType::SNEAK));
} else if (wasKeyDown(KeyType::AUTOFORWARD)) {
@@ -1861,6 +1068,8 @@ void Game::processKeyInput()
toggleAutoforward();
} else if (wasKeyDown(KeyType::INVENTORY)) {
openInventory();
+ } else if (wasKeyDown(KeyType::ENDERCHEST)) {
+ openEnderchest();
} else if (input->cancelPressed()) {
#ifdef __ANDROID__
m_android_chat_open = false;
@@ -1889,6 +1098,12 @@ void Game::processKeyInput()
toggleFast();
} else if (wasKeyDown(KeyType::NOCLIP)) {
toggleNoClip();
+ } else if (wasKeyDown(KeyType::KILLAURA)) {
+ toggleKillaura();
+ } else if (wasKeyDown(KeyType::FREECAM)) {
+ toggleFreecam();
+ } else if (wasKeyDown(KeyType::SCAFFOLD)) {
+ toggleScaffold();
#if USE_SOUND
} else if (wasKeyDown(KeyType::MUTE)) {
if (g_settings->getBool("enable_sound")) {
@@ -1942,6 +1157,8 @@ void Game::processKeyInput()
m_game_ui->toggleChat();
} else if (wasKeyDown(KeyType::TOGGLE_FOG)) {
toggleFog();
+ } else if (wasKeyDown(KeyType::TOGGLE_CHEAT_MENU)) {
+ m_game_ui->toggleCheatMenu();
} else if (wasKeyDown(KeyType::TOGGLE_UPDATE_CAMERA)) {
toggleUpdateCamera();
} else if (wasKeyDown(KeyType::TOGGLE_DEBUG)) {
@@ -2053,6 +1270,18 @@ void Game::openInventory()
}
}
+void Game::openEnderchest()
+{
+ LocalPlayer *player = client->getEnv().getLocalPlayer();
+ if (!player || !player->getCAO())
+ return;
+
+ infostream << "Game: Launching special inventory" << std::endl;
+
+ if (client->modsLoaded())
+ client->getScript()->open_enderchest();
+}
+
void Game::openConsole(float scale, const wchar_t *line)
{
@@ -2160,6 +1389,42 @@ void Game::toggleNoClip()
}
}
+void Game::toggleKillaura()
+{
+ bool killaura = ! g_settings->getBool("killaura");
+ g_settings->set("killaura", bool_to_cstr(killaura));
+
+ if (killaura) {
+ m_game_ui->showTranslatedStatusText("Killaura enabled");
+ } else {
+ m_game_ui->showTranslatedStatusText("Killaura disabled");
+ }
+}
+
+void Game::toggleFreecam()
+{
+ bool freecam = ! g_settings->getBool("freecam");
+ g_settings->set("freecam", bool_to_cstr(freecam));
+
+ if (freecam) {
+ m_game_ui->showTranslatedStatusText("Freecam enabled");
+ } else {
+ m_game_ui->showTranslatedStatusText("Freecam disabled");
+ }
+}
+
+void Game::toggleScaffold()
+{
+ bool scaffold = ! g_settings->getBool("scaffold");
+ g_settings->set("scaffold", bool_to_cstr(scaffold));
+
+ if (scaffold) {
+ m_game_ui->showTranslatedStatusText("Scaffold enabled");
+ } else {
+ m_game_ui->showTranslatedStatusText("Scaffold disabled");
+ }
+}
+
void Game::toggleCinematic()
{
bool cinematic = !g_settings->getBool("cinematic");
@@ -2265,6 +1530,8 @@ void Game::toggleDebug()
void Game::toggleUpdateCamera()
{
+ if (g_settings->getBool("freecam"))
+ return;
m_flags.disable_camera_update = !m_flags.disable_camera_update;
if (m_flags.disable_camera_update)
m_game_ui->showTranslatedStatusText("Camera update disabled");
@@ -2588,11 +1855,19 @@ void Game::handleClientEvent_ShowFormSpec(ClientEvent *event, CameraOrientation
void Game::handleClientEvent_ShowLocalFormSpec(ClientEvent *event, CameraOrientation *cam)
{
- FormspecFormSource *fs_src = new FormspecFormSource(*event->show_formspec.formspec);
- LocalFormspecHandler *txt_dst =
- new LocalFormspecHandler(*event->show_formspec.formname, client);
- GUIFormSpecMenu::create(m_game_ui->getFormspecGUI(), client, &input->joystick,
+ if (event->show_formspec.formspec->empty()) {
+ auto formspec = m_game_ui->getFormspecGUI();
+ if (formspec && (event->show_formspec.formname->empty()
+ || *(event->show_formspec.formname) == m_game_ui->getFormspecName())) {
+ formspec->quitMenu();
+ }
+ } else {
+ FormspecFormSource *fs_src = new FormspecFormSource(*event->show_formspec.formspec);
+ LocalFormspecHandler *txt_dst =
+ new LocalFormspecHandler(*event->show_formspec.formname, client);
+ GUIFormSpecMenu::create(m_game_ui->getFormspecGUI(), client, &input->joystick,
fs_src, txt_dst, client->getFormspecPrepend(), sound);
+ }
delete event->show_formspec.formspec;
delete event->show_formspec.formname;
@@ -2892,18 +2167,9 @@ void Game::updateCamera(u32 busy_time, f32 dtime)
v3s16 old_camera_offset = camera->getOffset();
- if (wasKeyDown(KeyType::CAMERA_MODE)) {
- GenericCAO *playercao = player->getCAO();
-
- // If playercao not loaded, don't change camera
- if (!playercao)
- return;
-
+ if (wasKeyDown(KeyType::CAMERA_MODE) && ! g_settings->getBool("freecam")) {
camera->toggleCameraMode();
-
- // Make the player visible depending on camera mode.
- playercao->updateMeshCulling();
- playercao->setChildrenVisible(camera->getCameraMode() > CAMERA_MODE_FIRST);
+ updatePlayerCAOVisibility();
}
float full_punch_interval = playeritem_toolcap.full_punch_interval;
@@ -2934,6 +2200,17 @@ void Game::updateCamera(u32 busy_time, f32 dtime)
}
}
+void Game::updatePlayerCAOVisibility()
+{
+ // Make the player visible depending on camera mode.
+ LocalPlayer *player = client->getEnv().getLocalPlayer();
+ GenericCAO *playercao = player->getCAO();
+ if (!playercao)
+ return;
+ playercao->updateMeshCulling();
+ bool is_visible = camera->getCameraMode() > CAMERA_MODE_FIRST || g_settings->getBool("freecam");
+ playercao->setChildrenVisible(is_visible);
+}
void Game::updateSound(f32 dtime)
{
@@ -2990,6 +2267,10 @@ void Game::processPlayerInteraction(f32 dtime, bool show_hud, bool show_debug)
const ItemDefinition &selected_def = selected_item.getDefinition(itemdef_manager);
f32 d = getToolRange(selected_def, hand_item.getDefinition(itemdef_manager));
+
+ if (g_settings->getBool("reach"))
+ d += g_settings->getU16("tool_range");
+
core::line3d<f32> shootline;
switch (camera->getCameraMode()) {
@@ -3078,7 +2359,7 @@ void Game::processPlayerInteraction(f32 dtime, bool show_hud, bool show_debug)
soundmaker->m_player_leftpunch_sound.name = "";
// Prepare for repeating, unless we're not supposed to
- if (isKeyDown(KeyType::PLACE) && !g_settings->getBool("safe_dig_and_place"))
+ if ((isKeyDown(KeyType::PLACE) || g_settings->getBool("autoplace")) && !g_settings->getBool("safe_dig_and_place"))
runData.repeat_place_timer += dtime;
else
runData.repeat_place_timer = 0;
@@ -3139,8 +2420,7 @@ PointedThing Game::updatePointedThing(
runData.selected_object = NULL;
hud->pointing_at_object = false;
-
- RaycastState s(shootline, look_for_object, liquids_pointable);
+ RaycastState s(shootline, look_for_object, liquids_pointable, ! g_settings->getBool("dont_point_nodes"));
PointedThing result;
env.continueRaycast(&s, &result);
if (result.type == POINTEDTHING_OBJECT) {
@@ -3214,7 +2494,6 @@ PointedThing Game::updatePointedThing(
return result;
}
-
void Game::handlePointingAtNothing(const ItemStack &playerItem)
{
infostream << "Attempted to place item while pointing at nothing" << std::endl;
@@ -3236,9 +2515,10 @@ void Game::handlePointingAtNode(const PointedThing &pointed,
ClientMap &map = client->getEnv().getClientMap();
- if (runData.nodig_delay_timer <= 0.0 && isKeyDown(KeyType::DIG)
+ if (((runData.nodig_delay_timer <= 0.0 || g_settings->getBool("fastdig")) && (isKeyDown(KeyType::DIG) || g_settings->getBool("autodig"))
&& !runData.digging_blocked
- && client->checkPrivilege("interact")) {
+ && client->checkPrivilege("interact"))
+ ) {
handleDigging(pointed, nodepos, selected_item, hand_item, dtime);
}
@@ -3258,7 +2538,7 @@ void Game::handlePointingAtNode(const PointedThing &pointed,
}
if ((wasKeyPressed(KeyType::PLACE) ||
- runData.repeat_place_timer >= m_repeat_place_time) &&
+ (runData.repeat_place_timer >= (g_settings->getBool("fastplace") ? 0.001 : m_repeat_place_time))) &&
client->checkPrivilege("interact")) {
runData.repeat_place_timer = 0;
infostream << "Place button pressed while looking at ground" << std::endl;
@@ -3491,11 +2771,11 @@ void Game::handlePointingAtObject(const PointedThing &pointed,
m_game_ui->setInfoText(infotext);
- if (isKeyDown(KeyType::DIG)) {
+ if (isKeyDown(KeyType::DIG) || g_settings->getBool("autohit")) {
bool do_punch = false;
bool do_punch_damage = false;
- if (runData.object_hit_delay_timer <= 0.0) {
+ if (runData.object_hit_delay_timer <= 0.0 || g_settings->getBool("spamclick")) {
do_punch = true;
do_punch_damage = true;
runData.object_hit_delay_timer = object_hit_delay;
@@ -3518,8 +2798,9 @@ void Game::handlePointingAtObject(const PointedThing &pointed,
dir, &tool_item, runData.time_from_last_punch);
runData.time_from_last_punch = 0;
- if (!disable_send)
+ if (!disable_send) {
client->interact(INTERACT_START_DIGGING, pointed);
+ }
}
} else if (wasKeyDown(KeyType::PLACE)) {
infostream << "Pressed place button while pointing at object" << std::endl;
@@ -3561,6 +2842,10 @@ void Game::handleDigging(const PointedThing &pointed, const v3s16 &nodepos,
}
}
+ if(g_settings->getBool("instant_break")) {
+ runData.dig_time_complete = 0;
+ runData.dig_instantly = true;
+ }
if (!runData.digging) {
infostream << "Started digging" << std::endl;
runData.dig_instantly = runData.dig_time_complete == 0;
@@ -3689,7 +2974,7 @@ void Game::updateFrame(ProfilerGraph *graph, RunStats *stats, f32 dtime,
float direct_brightness;
bool sunlight_seen;
- if (m_cache_enable_noclip && m_cache_enable_free_move) {
+ if ((m_cache_enable_noclip && m_cache_enable_free_move) || g_settings->getBool("freecam")) {
direct_brightness = time_brightness;
sunlight_seen = true;
} else {
@@ -3883,13 +3168,22 @@ void Game::updateFrame(ProfilerGraph *graph, RunStats *stats, f32 dtime,
graph->draw(10, screensize.Y - 10, driver, g_fontengine->getFont());
/*
+ Cheat menu
+ */
+
+ if (! gui_chat_console->isOpen()) {
+ if (m_game_ui->m_flags.show_cheat_menu)
+ m_cheat_menu->draw(driver, m_game_ui->m_flags.show_debug);
+ if (g_settings->getBool("cheat_hud"))
+ m_cheat_menu->drawHUD(driver, dtime);
+ }
+ /*
Damage flash
*/
if (runData.damage_flash > 0.0f) {
video::SColor color(runData.damage_flash, 180, 0, 0);
- driver->draw2DRectangle(color,
- core::rect<s32>(0, 0, screensize.X, screensize.Y),
- NULL);
+ if (! g_settings->getBool("no_hurt_cam"))
+ driver->draw2DRectangle(color, core::rect<s32>(0, 0, screensize.X, screensize.Y), NULL);
runData.damage_flash -= 384.0f * dtime;
}
@@ -3900,7 +3194,7 @@ void Game::updateFrame(ProfilerGraph *graph, RunStats *stats, f32 dtime,
if (player->hurt_tilt_timer > 0.0f) {
player->hurt_tilt_timer -= dtime * 6.0f;
- if (player->hurt_tilt_timer < 0.0f)
+ if (player->hurt_tilt_timer < 0.0f || g_settings->getBool("no_hurt_cam"))
player->hurt_tilt_strength = 0.0f;
}
@@ -4013,6 +3307,24 @@ void Game::settingChangedCallback(const std::string &setting_name, void *data)
((Game *)data)->readSettings();
}
+void Game::updateAllMapBlocksCallback(const std::string &setting_name, void *data)
+{
+ ((Game *) data)->client->updateAllMapBlocks();
+}
+
+void Game::freecamChangedCallback(const std::string &setting_name, void *data)
+{
+ Game *game = (Game *) data;
+ LocalPlayer *player = game->client->getEnv().getLocalPlayer();
+ if (g_settings->getBool("freecam")) {
+ game->camera->setCameraMode(CAMERA_MODE_FIRST);
+ player->freecamEnable();
+ } else {
+ player->freecamDisable();
+ }
+ game->updatePlayerCAOVisibility();
+}
+
void Game::readSettings()
{
m_cache_doubletap_jump = g_settings->getBool("doubletap_jump");
@@ -4042,6 +3354,26 @@ void Game::readSettings()
m_does_lost_focus_pause_game = g_settings->getBool("pause_on_lost_focus");
}
+bool Game::isKeyDown(GameKeyType k)
+{
+ return input->isKeyDown(k);
+}
+
+bool Game::wasKeyDown(GameKeyType k)
+{
+ return input->wasKeyDown(k);
+}
+
+bool Game::wasKeyPressed(GameKeyType k)
+{
+ return input->wasKeyPressed(k);
+}
+
+bool Game::wasKeyReleased(GameKeyType k)
+{
+ return input->wasKeyReleased(k);
+}
+
/****************************************************************************/
/****************************************************************************
Shutdown / cleanup
@@ -4120,26 +3452,34 @@ void Game::showPauseMenu()
"- %s: sneak/climb down\n"
"- %s: drop item\n"
"- %s: inventory\n"
+ "- %s: enderchest\n"
"- Mouse: turn/look\n"
"- Mouse wheel: select item\n"
"- %s: chat\n"
+ "- %s: Killaura\n"
+ "- %s: Freecam\n"
+ "- %s: Scaffold\n"
);
- char control_text_buf[600];
-
- porting::mt_snprintf(control_text_buf, sizeof(control_text_buf), control_text_template.c_str(),
- GET_KEY_NAME(keymap_forward),
- GET_KEY_NAME(keymap_backward),
- GET_KEY_NAME(keymap_left),
- GET_KEY_NAME(keymap_right),
- GET_KEY_NAME(keymap_jump),
- GET_KEY_NAME(keymap_dig),
- GET_KEY_NAME(keymap_place),
- GET_KEY_NAME(keymap_sneak),
- GET_KEY_NAME(keymap_drop),
- GET_KEY_NAME(keymap_inventory),
- GET_KEY_NAME(keymap_chat)
- );
+ char control_text_buf[600];
+
+ porting::mt_snprintf(control_text_buf, sizeof(control_text_buf), control_text_template.c_str(),
+ GET_KEY_NAME(keymap_forward),
+ GET_KEY_NAME(keymap_backward),
+ GET_KEY_NAME(keymap_left),
+ GET_KEY_NAME(keymap_right),
+ GET_KEY_NAME(keymap_jump),
+ GET_KEY_NAME(keymap_dig),
+ GET_KEY_NAME(keymap_place),
+ GET_KEY_NAME(keymap_sneak),
+ GET_KEY_NAME(keymap_drop),
+ GET_KEY_NAME(keymap_inventory),
+ GET_KEY_NAME(keymap_enderchest),
+ GET_KEY_NAME(keymap_chat),
+ GET_KEY_NAME(keymap_toggle_killaura),
+ GET_KEY_NAME(keymap_toggle_freecam),
+ GET_KEY_NAME(keymap_toggle_scaffold)
+ );
std::string control_text = std::string(control_text_buf);
str_formspec_escape(control_text);
@@ -4232,6 +3572,8 @@ void Game::showPauseMenu()
****************************************************************************/
/****************************************************************************/
+Game *g_game;
+
void the_game(bool *kill,
InputHandler *input,
const GameStartData &start_data,
@@ -4241,6 +3583,8 @@ void the_game(bool *kill,
{
Game game;
+ g_game = &game;
+
/* Make a copy of the server address because if a local singleplayer server
* is created then this is updated and we don't want to change the value
* passed to us by the calling function
diff --git a/src/client/game.h b/src/client/game.h
index d04153271..fd93ef82d 100644
--- a/src/client/game.h
+++ b/src/client/game.h
@@ -19,6 +19,58 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#pragma once
+#include <iomanip>
+#include <cmath>
+#include "client/renderingengine.h"
+#include "camera.h"
+#include "client.h"
+#include "client/clientevent.h"
+//#include "client/gameui.h"
+#include "client/inputhandler.h"
+#include "client/sound.h"
+#include "client/tile.h" // For TextureSource
+#include "client/keys.h"
+#include "client/joystick_controller.h"
+#include "clientmap.h"
+#include "clouds.h"
+#include "config.h"
+#include "content_cao.h"
+#include "client/event_manager.h"
+#include "fontengine.h"
+#include "itemdef.h"
+#include "log.h"
+#include "filesys.h"
+#include "gettext.h"
+#include "gui/cheatMenu.h"
+#include "gui/guiChatConsole.h"
+#include "gui/guiConfirmRegistration.h"
+#include "gui/guiFormSpecMenu.h"
+#include "gui/guiKeyChangeMenu.h"
+#include "gui/guiPasswordChange.h"
+#include "gui/guiVolumeChange.h"
+#include "gui/mainmenumanager.h"
+#include "gui/profilergraph.h"
+#include "mapblock.h"
+#include "minimap.h"
+#include "nodedef.h" // Needed for determining pointing to nodes
+#include "nodemetadata.h"
+#include "particles.h"
+#include "porting.h"
+#include "profiler.h"
+#include "raycast.h"
+#include "server.h"
+#include "settings.h"
+#include "shader.h"
+#include "sky.h"
+#include "translation.h"
+#include "util/basic_macros.h"
+#include "util/directiontables.h"
+#include "util/pointedthing.h"
+#include "util/quicktune_shortcutter.h"
+#include "irrlicht_changes/static_text.h"
+#include "version.h"
+#include "script/scripting_client.h"
+#include "hud.h"
#include "irrlichttypes.h"
#include <string>
@@ -42,6 +94,836 @@ struct CameraOrientation {
f32 camera_pitch; // "up/down"
};
+/*
+ Text input system
+*/
+
+struct TextDestNodeMetadata : public TextDest
+{
+ TextDestNodeMetadata(v3s16 p, Client *client)
+ {
+ m_p = p;
+ m_client = client;
+ }
+ // This is deprecated I guess? -celeron55
+ void gotText(const std::wstring &text)
+ {
+ std::string ntext = wide_to_utf8(text);
+ infostream << "Submitting 'text' field of node at (" << m_p.X << ","
+ << m_p.Y << "," << m_p.Z << "): " << ntext << std::endl;
+ StringMap fields;
+ fields["text"] = ntext;
+ m_client->sendNodemetaFields(m_p, "", fields);
+ }
+ void gotText(const StringMap &fields)
+ {
+ m_client->sendNodemetaFields(m_p, "", fields);
+ }
+
+ v3s16 m_p;
+ Client *m_client;
+};
+
+struct TextDestPlayerInventory : public TextDest
+{
+ TextDestPlayerInventory(Client *client)
+ {
+ m_client = client;
+ m_formname = "";
+ }
+ TextDestPlayerInventory(Client *client, const std::string &formname)
+ {
+ m_client = client;
+ m_formname = formname;
+ }
+ void gotText(const StringMap &fields)
+ {
+ m_client->sendInventoryFields(m_formname, fields);
+ }
+
+ Client *m_client;
+};
+
+struct LocalFormspecHandler : public TextDest
+{
+ LocalFormspecHandler(const std::string &formname)
+ {
+ m_formname = formname;
+ }
+
+ LocalFormspecHandler(const std::string &formname, Client *client):
+ m_client(client)
+ {
+ m_formname = formname;
+ }
+
+ void gotText(const StringMap &fields)
+ {
+ if (m_formname == "MT_PAUSE_MENU") {
+ if (fields.find("btn_sound") != fields.end()) {
+ g_gamecallback->changeVolume();
+ return;
+ }
+
+ if (fields.find("btn_key_config") != fields.end()) {
+ g_gamecallback->keyConfig();
+ return;
+ }
+
+ if (fields.find("btn_exit_menu") != fields.end()) {
+ g_gamecallback->disconnect();
+ return;
+ }
+
+ if (fields.find("btn_exit_os") != fields.end()) {
+ g_gamecallback->exitToOS();
+#ifndef __ANDROID__
+ RenderingEngine::get_raw_device()->closeDevice();
+#endif
+ return;
+ }
+
+ if (fields.find("btn_change_password") != fields.end()) {
+ g_gamecallback->changePassword();
+ return;
+ }
+
+ if (fields.find("quit") != fields.end()) {
+ return;
+ }
+
+ if (fields.find("btn_continue") != fields.end()) {
+ return;
+ }
+ }
+
+ if (m_formname == "MT_DEATH_SCREEN") {
+ assert(m_client != 0);
+ m_client->sendRespawn();
+ return;
+ }
+
+ if (m_client->modsLoaded())
+ m_client->getScript()->on_formspec_input(m_formname, fields);
+ }
+
+ Client *m_client = nullptr;
+};
+
+/* Form update callback */
+
+class NodeMetadataFormSource: public IFormSource
+{
+public:
+ NodeMetadataFormSource(ClientMap *map, v3s16 p):
+ m_map(map),
+ m_p(p)
+ {
+ }
+ const std::string &getForm() const
+ {
+ static const std::string empty_string = "";
+ NodeMetadata *meta = m_map->getNodeMetadata(m_p);
+
+ if (!meta)
+ return empty_string;
+
+ return meta->getString("formspec");
+ }
+
+ virtual std::string resolveText(const std::string &str)
+ {
+ NodeMetadata *meta = m_map->getNodeMetadata(m_p);
+
+ if (!meta)
+ return str;
+
+ return meta->resolveString(str);
+ }
+
+ ClientMap *m_map;
+ v3s16 m_p;
+};
+
+class PlayerInventoryFormSource: public IFormSource
+{
+public:
+ PlayerInventoryFormSource(Client *client):
+ m_client(client)
+ {
+ }
+
+ const std::string &getForm() const
+ {
+ LocalPlayer *player = m_client->getEnv().getLocalPlayer();
+ return player->inventory_formspec;
+ }
+
+ Client *m_client;
+};
+
+class NodeDugEvent: public MtEvent
+{
+public:
+ v3s16 p;
+ MapNode n;
+
+ NodeDugEvent(v3s16 p, MapNode n):
+ p(p),
+ n(n)
+ {}
+ MtEvent::Type getType() const
+ {
+ return MtEvent::NODE_DUG;
+ }
+};
+
+class SoundMaker
+{
+ ISoundManager *m_sound;
+ const NodeDefManager *m_ndef;
+public:
+ bool makes_footstep_sound;
+ float m_player_step_timer;
+ float m_player_jump_timer;
+
+ SimpleSoundSpec m_player_step_sound;
+ SimpleSoundSpec m_player_leftpunch_sound;
+ SimpleSoundSpec m_player_rightpunch_sound;
+
+ SoundMaker(ISoundManager *sound, const NodeDefManager *ndef):
+ m_sound(sound),
+ m_ndef(ndef),
+ makes_footstep_sound(true),
+ m_player_step_timer(0.0f),
+ m_player_jump_timer(0.0f)
+ {
+ }
+
+ void playPlayerStep()
+ {
+ if (m_player_step_timer <= 0 && m_player_step_sound.exists()) {
+ m_player_step_timer = 0.03;
+ if (makes_footstep_sound)
+ m_sound->playSound(m_player_step_sound, false);
+ }
+ }
+
+ void playPlayerJump()
+ {
+ if (m_player_jump_timer <= 0.0f) {
+ m_player_jump_timer = 0.2f;
+ m_sound->playSound(SimpleSoundSpec("player_jump", 0.5f), false);
+ }
+ }
+
+ static void viewBobbingStep(MtEvent *e, void *data)
+ {
+ SoundMaker *sm = (SoundMaker *)data;
+ sm->playPlayerStep();
+ }
+
+ static void playerRegainGround(MtEvent *e, void *data)
+ {
+ SoundMaker *sm = (SoundMaker *)data;
+ sm->playPlayerStep();
+ }
+
+ static void playerJump(MtEvent *e, void *data)
+ {
+ SoundMaker *sm = (SoundMaker *)data;
+ sm->playPlayerJump();
+ }
+
+ static void cameraPunchLeft(MtEvent *e, void *data)
+ {
+ SoundMaker *sm = (SoundMaker *)data;
+ sm->m_sound->playSound(sm->m_player_leftpunch_sound, false);
+ }
+
+ static void cameraPunchRight(MtEvent *e, void *data)
+ {
+ SoundMaker *sm = (SoundMaker *)data;
+ sm->m_sound->playSound(sm->m_player_rightpunch_sound, false);
+ }
+
+ static void nodeDug(MtEvent *e, void *data)
+ {
+ SoundMaker *sm = (SoundMaker *)data;
+ NodeDugEvent *nde = (NodeDugEvent *)e;
+ sm->m_sound->playSound(sm->m_ndef->get(nde->n).sound_dug, false);
+ }
+
+ static void playerDamage(MtEvent *e, void *data)
+ {
+ SoundMaker *sm = (SoundMaker *)data;
+ sm->m_sound->playSound(SimpleSoundSpec("player_damage", 0.5), false);
+ }
+
+ static void playerFallingDamage(MtEvent *e, void *data)
+ {
+ SoundMaker *sm = (SoundMaker *)data;
+ sm->m_sound->playSound(SimpleSoundSpec("player_falling_damage", 0.5), false);
+ }
+
+ void registerReceiver(MtEventManager *mgr)
+ {
+ mgr->reg(MtEvent::VIEW_BOBBING_STEP, SoundMaker::viewBobbingStep, this);
+ mgr->reg(MtEvent::PLAYER_REGAIN_GROUND, SoundMaker::playerRegainGround, this);
+ mgr->reg(MtEvent::PLAYER_JUMP, SoundMaker::playerJump, this);
+ mgr->reg(MtEvent::CAMERA_PUNCH_LEFT, SoundMaker::cameraPunchLeft, this);
+ mgr->reg(MtEvent::CAMERA_PUNCH_RIGHT, SoundMaker::cameraPunchRight, this);
+ mgr->reg(MtEvent::NODE_DUG, SoundMaker::nodeDug, this);
+ mgr->reg(MtEvent::PLAYER_DAMAGE, SoundMaker::playerDamage, this);
+ mgr->reg(MtEvent::PLAYER_FALLING_DAMAGE, SoundMaker::playerFallingDamage, this);
+ }
+
+ void step(float dtime)
+ {
+ m_player_step_timer -= dtime;
+ m_player_jump_timer -= dtime;
+ }
+};
+
+// Locally stored sounds don't need to be preloaded because of this
+class GameOnDemandSoundFetcher: public OnDemandSoundFetcher
+{
+ std::set<std::string> m_fetched;
+private:
+ void paths_insert(std::set<std::string> &dst_paths,
+ const std::string &base,
+ const std::string &name)
+ {
+ dst_paths.insert(base + DIR_DELIM + "sounds" + DIR_DELIM + name + ".ogg");
+ dst_paths.insert(base + DIR_DELIM + "sounds" + DIR_DELIM + name + ".0.ogg");
+ dst_paths.insert(base + DIR_DELIM + "sounds" + DIR_DELIM + name + ".1.ogg");
+ dst_paths.insert(base + DIR_DELIM + "sounds" + DIR_DELIM + name + ".2.ogg");
+ dst_paths.insert(base + DIR_DELIM + "sounds" + DIR_DELIM + name + ".3.ogg");
+ dst_paths.insert(base + DIR_DELIM + "sounds" + DIR_DELIM + name + ".4.ogg");
+ dst_paths.insert(base + DIR_DELIM + "sounds" + DIR_DELIM + name + ".5.ogg");
+ dst_paths.insert(base + DIR_DELIM + "sounds" + DIR_DELIM + name + ".6.ogg");
+ dst_paths.insert(base + DIR_DELIM + "sounds" + DIR_DELIM + name + ".7.ogg");
+ dst_paths.insert(base + DIR_DELIM + "sounds" + DIR_DELIM + name + ".8.ogg");
+ dst_paths.insert(base + DIR_DELIM + "sounds" + DIR_DELIM + name + ".9.ogg");
+ }
+public:
+ void fetchSounds(const std::string &name,
+ std::set<std::string> &dst_paths,
+ std::set<std::string> &dst_datas)
+ {
+ if (m_fetched.count(name))
+ return;
+
+ m_fetched.insert(name);
+
+ paths_insert(dst_paths, porting::path_share, name);
+ paths_insert(dst_paths, porting::path_user, name);
+ }
+};
+
+
+// before 1.8 there isn't a "integer interface", only float
+#if (IRRLICHT_VERSION_MAJOR == 1 && IRRLICHT_VERSION_MINOR < 8)
+typedef f32 SamplerLayer_t;
+#else
+typedef s32 SamplerLayer_t;
+#endif
+
+
+class GameGlobalShaderConstantSetter : public IShaderConstantSetter
+{
+ Sky *m_sky;
+ bool *m_force_fog_off;
+ f32 *m_fog_range;
+ bool m_fog_enabled;
+ CachedPixelShaderSetting<float, 4> m_sky_bg_color;
+ CachedPixelShaderSetting<float> m_fog_distance;
+ CachedVertexShaderSetting<float> m_animation_timer_vertex;
+ CachedPixelShaderSetting<float> m_animation_timer_pixel;
+ CachedPixelShaderSetting<float, 3> m_day_light;
+ CachedPixelShaderSetting<float, 4> m_star_color;
+ CachedPixelShaderSetting<float, 3> m_eye_position_pixel;
+ CachedVertexShaderSetting<float, 3> m_eye_position_vertex;
+ CachedPixelShaderSetting<float, 3> m_minimap_yaw;
+ CachedPixelShaderSetting<float, 3> m_camera_offset_pixel;
+ CachedPixelShaderSetting<float, 3> m_camera_offset_vertex;
+ CachedPixelShaderSetting<SamplerLayer_t> m_base_texture;
+ Client *m_client;
+
+public:
+ void onSettingsChange(const std::string &name)
+ {
+ if (name == "enable_fog")
+ m_fog_enabled = g_settings->getBool("enable_fog");
+ }
+
+ static void settingsCallback(const std::string &name, void *userdata)
+ {
+ reinterpret_cast<GameGlobalShaderConstantSetter*>(userdata)->onSettingsChange(name);
+ }
+
+ void setSky(Sky *sky) { m_sky = sky; }
+
+ GameGlobalShaderConstantSetter(Sky *sky, bool *force_fog_off,
+ f32 *fog_range, Client *client) :
+ m_sky(sky),
+ m_force_fog_off(force_fog_off),
+ m_fog_range(fog_range),
+ m_sky_bg_color("skyBgColor"),
+ m_fog_distance("fogDistance"),
+ m_animation_timer_vertex("animationTimer"),
+ m_animation_timer_pixel("animationTimer"),
+ m_day_light("dayLight"),
+ m_star_color("starColor"),
+ m_eye_position_pixel("eyePosition"),
+ m_eye_position_vertex("eyePosition"),
+ m_minimap_yaw("yawVec"),
+ m_camera_offset_pixel("cameraOffset"),
+ m_camera_offset_vertex("cameraOffset"),
+ m_base_texture("baseTexture"),
+ m_client(client)
+ {
+ g_settings->registerChangedCallback("enable_fog", settingsCallback, this);
+ m_fog_enabled = g_settings->getBool("enable_fog");
+ }
+
+ ~GameGlobalShaderConstantSetter()
+ {
+ g_settings->deregisterChangedCallback("enable_fog", settingsCallback, this);
+ }
+
+ void onSetConstants(video::IMaterialRendererServices *services) override
+ {
+ // Background color
+ video::SColor bgcolor = m_sky->getBgColor();
+ video::SColorf bgcolorf(bgcolor);
+ float bgcolorfa[4] = {
+ bgcolorf.r,
+ bgcolorf.g,
+ bgcolorf.b,
+ bgcolorf.a,
+ };
+ m_sky_bg_color.set(bgcolorfa, services);
+
+ // Fog distance
+ float fog_distance = 10000 * BS;
+
+ if (m_fog_enabled && !*m_force_fog_off)
+ fog_distance = *m_fog_range;
+
+ m_fog_distance.set(&fog_distance, services);
+
+ u32 daynight_ratio = (float)m_client->getEnv().getDayNightRatio();
+ video::SColorf sunlight;
+ get_sunlight_color(&sunlight, daynight_ratio);
+ float dnc[3] = {
+ sunlight.r,
+ sunlight.g,
+ sunlight.b };
+ m_day_light.set(dnc, services);
+
+ video::SColorf star_color = m_sky->getCurrentStarColor();
+ float clr[4] = {star_color.r, star_color.g, star_color.b, star_color.a};
+ m_star_color.set(clr, services);
+
+ u32 animation_timer = porting::getTimeMs() % 1000000;
+ float animation_timer_f = (float)animation_timer / 100000.f;
+ m_animation_timer_vertex.set(&animation_timer_f, services);
+ m_animation_timer_pixel.set(&animation_timer_f, services);
+
+ float eye_position_array[3];
+ v3f epos = m_client->getEnv().getLocalPlayer()->getEyePosition();
+#if (IRRLICHT_VERSION_MAJOR == 1 && IRRLICHT_VERSION_MINOR < 8)
+ eye_position_array[0] = epos.X;
+ eye_position_array[1] = epos.Y;
+ eye_position_array[2] = epos.Z;
+#else
+ epos.getAs3Values(eye_position_array);
+#endif
+ m_eye_position_pixel.set(eye_position_array, services);
+ m_eye_position_vertex.set(eye_position_array, services);
+
+ if (m_client->getMinimap()) {
+ float minimap_yaw_array[3];
+ v3f minimap_yaw = m_client->getMinimap()->getYawVec();
+#if (IRRLICHT_VERSION_MAJOR == 1 && IRRLICHT_VERSION_MINOR < 8)
+ minimap_yaw_array[0] = minimap_yaw.X;
+ minimap_yaw_array[1] = minimap_yaw.Y;
+ minimap_yaw_array[2] = minimap_yaw.Z;
+#else
+ minimap_yaw.getAs3Values(minimap_yaw_array);
+#endif
+ 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;
+ m_base_texture.set(&base_tex, services);
+ }
+};
+
+
+class GameGlobalShaderConstantSetterFactory : public IShaderConstantSetterFactory
+{
+ Sky *m_sky;
+ bool *m_force_fog_off;
+ f32 *m_fog_range;
+ Client *m_client;
+ std::vector<GameGlobalShaderConstantSetter *> created_nosky;
+public:
+ GameGlobalShaderConstantSetterFactory(bool *force_fog_off,
+ f32 *fog_range, Client *client) :
+ m_sky(NULL),
+ m_force_fog_off(force_fog_off),
+ m_fog_range(fog_range),
+ m_client(client)
+ {}
+
+ void setSky(Sky *sky) {
+ m_sky = sky;
+ for (GameGlobalShaderConstantSetter *ggscs : created_nosky) {
+ ggscs->setSky(m_sky);
+ }
+ created_nosky.clear();
+ }
+
+ virtual IShaderConstantSetter* create()
+ {
+ auto *scs = new GameGlobalShaderConstantSetter(
+ m_sky, m_force_fog_off, m_fog_range, m_client);
+ if (!m_sky)
+ created_nosky.push_back(scs);
+ return scs;
+ }
+};
+
+#ifdef __ANDROID__
+#define SIZE_TAG "size[11,5.5]"
+#else
+#define SIZE_TAG "size[11,5.5,true]" // Fixed size on desktop
+#endif
+
+/****************************************************************************
+ ****************************************************************************/
+
+const float object_hit_delay = 0.2;
+
+struct FpsControl {
+ u32 last_time, busy_time, sleep_time;
+};
+
+
+/* The reason the following structs are not anonymous structs within the
+ * class is that they are not used by the majority of member functions and
+ * many functions that do require objects of thse types do not modify them
+ * (so they can be passed as a const qualified parameter)
+ */
+
+struct GameRunData {
+ u16 dig_index;
+ u16 new_playeritem;
+ PointedThing pointed_old;
+ bool digging;
+ bool punching;
+ bool btn_down_for_dig;
+ bool dig_instantly;
+ bool digging_blocked;
+ bool reset_jump_timer;
+ float nodig_delay_timer;
+ float dig_time;
+ float dig_time_complete;
+ float repeat_place_timer;
+ float object_hit_delay_timer;
+ float time_from_last_punch;
+ ClientActiveObject *selected_object;
+
+ float jump_timer;
+ float damage_flash;
+ float update_draw_list_timer;
+
+ f32 fog_range;
+
+ v3f update_draw_list_last_cam_dir;
+
+ float time_of_day_smooth;
+};
+
+class Game;
+
+struct ClientEventHandler
+{
+ void (Game::*handler)(ClientEvent *, CameraOrientation *);
+};
+
+class Game {
+public:
+ Game();
+ ~Game();
+
+ bool startup(bool *kill,
+ InputHandler *input,
+ const GameStartData &game_params,
+ std::string &error_message,
+ bool *reconnect,
+ ChatBackend *chat_backend);
+
+
+ void run();
+ void shutdown();
+
+ void extendedResourceCleanup();
+
+ // Basic initialisation
+ bool init(const std::string &map_dir, const std::string &address,
+ u16 port, const SubgameSpec &gamespec);
+ bool initSound();
+ bool createSingleplayerServer(const std::string &map_dir,
+ const SubgameSpec &gamespec, u16 port);
+
+ // Client creation
+ bool createClient(const GameStartData &start_data);
+ bool initGui();
+
+ // Client connection
+ bool connectToServer(const GameStartData &start_data,
+ bool *connect_ok, bool *aborted);
+ bool getServerContent(bool *aborted);
+
+ // Main loop
+
+ void updateInteractTimers(f32 dtime);
+ bool checkConnection();
+ bool handleCallbacks();
+ void processQueues();
+ void updateProfilers(const RunStats &stats, const FpsControl &draw_times, f32 dtime);
+ void updateStats(RunStats *stats, const FpsControl &draw_times, f32 dtime);
+ void updateProfilerGraphs(ProfilerGraph *graph);
+
+ // Input related
+ void processUserInput(f32 dtime);
+ void processKeyInput();
+ void processItemSelection(u16 *new_playeritem);
+
+ void dropSelectedItem(bool single_item = false);
+ void openInventory();
+ void openEnderchest();
+ void openConsole(float scale, const wchar_t *line=NULL);
+ void toggleFreeMove();
+ void toggleFreeMoveAlt();
+ void togglePitchMove();
+ void toggleFast();
+ void toggleNoClip();
+ void toggleKillaura();
+ void toggleFreecam();
+ void toggleScaffold();
+ void toggleNextItem();
+ void toggleCinematic();
+ void toggleAutoforward();
+
+ void toggleMinimap(bool shift_pressed);
+ void toggleFog();
+ void toggleDebug();
+ void toggleUpdateCamera();
+ void updatePlayerCAOVisibility();
+
+ void increaseViewRange();
+ void decreaseViewRange();
+ void toggleFullViewRange();
+ void checkZoomEnabled();
+
+ void updateCameraDirection(CameraOrientation *cam, float dtime);
+ void updateCameraOrientation(CameraOrientation *cam, float dtime);
+ void updatePlayerControl(const CameraOrientation &cam);
+ void step(f32 *dtime);
+ void processClientEvents(CameraOrientation *cam);
+ void updateCamera(u32 busy_time, f32 dtime);
+ void updateSound(f32 dtime);
+ void processPlayerInteraction(f32 dtime, bool show_hud, bool show_debug);
+ /*!
+ * Returns the object or node the player is pointing at.
+ * Also updates the selected thing in the Hud.
+ *
+ * @param[in] shootline the shootline, starting from
+ * the camera position. This also gives the maximal distance
+ * of the search.
+ * @param[in] liquids_pointable if false, liquids are ignored
+ * @param[in] look_for_object if false, objects are ignored
+ * @param[in] camera_offset offset of the camera
+ * @param[out] selected_object the selected object or
+ * NULL if not found
+ */
+ PointedThing updatePointedThing(
+ const core::line3d<f32> &shootline, bool liquids_pointable,
+ bool look_for_object, const v3s16 &camera_offset);
+ void handlePointingAtNothing(const ItemStack &playerItem);
+ void handlePointingAtNode(const PointedThing &pointed,
+ const ItemStack &selected_item, const ItemStack &hand_item, f32 dtime);
+ void handlePointingAtObject(const PointedThing &pointed, const ItemStack &playeritem,
+ const v3f &player_position, bool show_debug);
+ void handleDigging(const PointedThing &pointed, const v3s16 &nodepos,
+ const ItemStack &selected_item, const ItemStack &hand_item, f32 dtime);
+ void updateFrame(ProfilerGraph *graph, RunStats *stats, f32 dtime,
+ const CameraOrientation &cam);
+
+ // Misc
+ void limitFps(FpsControl *fps_timings, f32 *dtime);
+
+ void showOverlayMessage(const char *msg, float dtime, int percent,
+ bool draw_clouds = true);
+
+ static void freecamChangedCallback(const std::string &setting_name, void *data);
+ static void settingChangedCallback(const std::string &setting_name, void *data);
+ static void updateAllMapBlocksCallback(const std::string &setting_name, void *data);
+ void readSettings();
+
+ bool isKeyDown(GameKeyType k);
+ bool wasKeyDown(GameKeyType k);
+ bool wasKeyPressed(GameKeyType k);
+ bool wasKeyReleased(GameKeyType k);
+
+#ifdef __ANDROID__
+ void handleAndroidChatInput();
+#endif
+
+ struct Flags {
+ bool force_fog_off = false;
+ bool disable_camera_update = false;
+ };
+
+ void showDeathFormspec();
+ void showPauseMenu();
+
+ // ClientEvent handlers
+ void handleClientEvent_None(ClientEvent *event, CameraOrientation *cam);
+ void handleClientEvent_PlayerDamage(ClientEvent *event, CameraOrientation *cam);
+ void handleClientEvent_PlayerForceMove(ClientEvent *event, CameraOrientation *cam);
+ void handleClientEvent_Deathscreen(ClientEvent *event, CameraOrientation *cam);
+ void handleClientEvent_ShowFormSpec(ClientEvent *event, CameraOrientation *cam);
+ void handleClientEvent_ShowLocalFormSpec(ClientEvent *event, CameraOrientation *cam);
+ void handleClientEvent_HandleParticleEvent(ClientEvent *event,
+ CameraOrientation *cam);
+ void handleClientEvent_HudAdd(ClientEvent *event, CameraOrientation *cam);
+ void handleClientEvent_HudRemove(ClientEvent *event, CameraOrientation *cam);
+ void handleClientEvent_HudChange(ClientEvent *event, CameraOrientation *cam);
+ void handleClientEvent_SetSky(ClientEvent *event, CameraOrientation *cam);
+ void handleClientEvent_SetSun(ClientEvent *event, CameraOrientation *cam);
+ void handleClientEvent_SetMoon(ClientEvent *event, CameraOrientation *cam);
+ void handleClientEvent_SetStars(ClientEvent *event, CameraOrientation *cam);
+ void handleClientEvent_OverrideDayNigthRatio(ClientEvent *event,
+ CameraOrientation *cam);
+ void handleClientEvent_CloudParams(ClientEvent *event, CameraOrientation *cam);
+
+ void updateChat(f32 dtime, const v2u32 &screensize);
+
+ 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;
+
+ Client *client = nullptr;
+ Server *server = nullptr;
+
+ IWritableTextureSource *texture_src = nullptr;
+ IWritableShaderSource *shader_src = nullptr;
+
+ // When created, these will be filled with data received from the server
+ IWritableItemDefManager *itemdef_manager = nullptr;
+ NodeDefManager *nodedef_manager = nullptr;
+
+ GameOnDemandSoundFetcher soundfetcher; // useful when testing
+ ISoundManager *sound = nullptr;
+ bool sound_is_dummy = false;
+ SoundMaker *soundmaker = nullptr;
+
+ ChatBackend *chat_backend = nullptr;
+ LogOutputBuffer m_chat_log_buf;
+
+ EventManager *eventmgr = nullptr;
+ QuicktuneShortcutter *quicktune = nullptr;
+ bool registration_confirmation_shown = false;
+
+ std::unique_ptr<GameUI> m_game_ui;
+ GUIChatConsole *gui_chat_console = nullptr; // Free using ->Drop()
+ CheatMenu *m_cheat_menu = nullptr;
+ MapDrawControl *draw_control = nullptr;
+ Camera *camera = nullptr;
+ Clouds *clouds = nullptr; // Free using ->Drop()
+ Sky *sky = nullptr; // Free using ->Drop()
+ Hud *hud = nullptr;
+ Minimap *mapper = nullptr;
+
+ GameRunData runData;
+ Flags m_flags;
+
+ /* 'cache'
+ This class does take ownership/responsibily for cleaning up etc of any of
+ these items (e.g. device)
+ */
+ IrrlichtDevice *device;
+ video::IVideoDriver *driver;
+ scene::ISceneManager *smgr;
+ bool *kill;
+ std::string *error_message;
+ bool *reconnect_requested;
+ scene::ISceneNode *skybox;
+
+ bool simple_singleplayer_mode;
+ /* End 'cache' */
+
+ /* Pre-calculated values
+ */
+ int crack_animation_length;
+
+ IntervalLimiter profiler_interval;
+
+ /*
+ * TODO: Local caching of settings is not optimal and should at some stage
+ * be updated to use a global settings object for getting thse values
+ * (as opposed to the this local caching). This can be addressed in
+ * a later release.
+ */
+ bool m_cache_doubletap_jump;
+ bool m_cache_enable_clouds;
+ bool m_cache_enable_joysticks;
+ bool m_cache_enable_particles;
+ bool m_cache_enable_fog;
+ bool m_cache_enable_noclip;
+ bool m_cache_enable_free_move;
+ f32 m_cache_mouse_sensitivity;
+ f32 m_cache_joystick_frustum_sensitivity;
+ f32 m_repeat_place_time;
+ f32 m_cache_cam_smoothing;
+ f32 m_cache_fog_start;
+
+ bool m_invert_mouse = false;
+ bool m_first_loop_after_window_activation = false;
+ bool m_camera_offset_changed = false;
+
+ bool m_does_lost_focus_pause_game = false;
+
+ CameraOrientation cam_view_target = { 0 };
+ CameraOrientation cam_view = { 0 };
+
+ int m_reset_HW_buffer_counter = 0;
+#ifdef __ANDROID__
+ bool m_cache_hold_aux1;
+ bool m_android_chat_open;
+#endif
+};
+extern Game *g_game;
void the_game(bool *kill,
InputHandler *input,
diff --git a/src/client/gameui.cpp b/src/client/gameui.cpp
index 0c08efeb5..0c1da3915 100644
--- a/src/client/gameui.cpp
+++ b/src/client/gameui.cpp
@@ -53,6 +53,9 @@ GameUI::GameUI()
}
void GameUI::init()
{
+ m_guitext_coords = gui::StaticText::add(guienv, L"", core::rect<s32>(0, 0, 0, 0), false,
+ false, guiroot);
+
// First line of debug text
m_guitext = gui::StaticText::add(guienv, utf8_to_wide(PROJECT_NAME_C).c_str(),
core::rect<s32>(0, 0, 0, 0), false, false, guiroot);
@@ -97,8 +100,24 @@ void GameUI::update(const RunStats &stats, Client *client, MapDrawControl *draw_
const CameraOrientation &cam, const PointedThing &pointed_old,
const GUIChatConsole *chat_console, float dtime)
{
+ LocalPlayer *player = client->getEnv().getLocalPlayer();
+ v3f player_position = player->getPosition();
v2u32 screensize = RenderingEngine::get_instance()->getWindowSize();
+ bool show_coords = g_settings->getBool("coords");
+
+ if (show_coords) {
+ std::ostringstream os(std::ios_base::binary);
+ os << std::setprecision(1) << std::fixed
+ << (player_position.X / BS)
+ << ", " << (player_position.Y / BS)
+ << ", " << (player_position.Z / BS);
+ setStaticText(m_guitext_coords, utf8_to_wide(os.str()).c_str());
+ m_guitext_coords->setRelativePosition(core::rect<s32>(5, screensize.Y - 5 - g_fontengine->getTextHeight(), screensize.X, screensize.Y));
+ }
+
+ m_guitext_coords->setVisible(show_coords);
+
if (m_flags.show_debug) {
static float drawtime_avg = 0;
drawtime_avg = drawtime_avg * 0.95 + stats.drawtime * 0.05;
@@ -128,9 +147,6 @@ void GameUI::update(const RunStats &stats, Client *client, MapDrawControl *draw_
m_guitext->setVisible(m_flags.show_debug);
if (m_flags.show_debug) {
- LocalPlayer *player = client->getEnv().getLocalPlayer();
- v3f player_position = player->getPosition();
-
std::ostringstream os(std::ios_base::binary);
os << std::setprecision(1) << std::fixed
<< "pos: (" << (player_position.X / BS)
@@ -197,8 +213,7 @@ void GameUI::update(const RunStats &stats, Client *client, MapDrawControl *draw_
m_guitext_status->enableOverrideColor(true);
}
- // Hide chat when console is visible
- m_guitext_chat->setVisible(isChatVisible() && !chat_console->isVisible());
+ m_guitext_chat->setVisible(isChatVisible());
}
void GameUI::initFlags()
@@ -223,13 +238,14 @@ void GameUI::setChatText(const EnrichedString &chat_text, u32 recent_chat_count)
{
// Update gui element size and position
- s32 chat_y = 5;
+
+ const v2u32 &window_size = RenderingEngine::get_instance()->getWindowSize();
+
+ s32 chat_y = window_size.Y - 150 - m_guitext_chat->getTextHeight();
if (m_flags.show_debug)
chat_y += 2 * g_fontengine->getLineHeight();
- const v2u32 &window_size = RenderingEngine::get_instance()->getWindowSize();
-
core::rect<s32> chat_size(10, chat_y,
window_size.X - 20, 0);
chat_size.LowerRightCorner.Y = std::min((s32)window_size.Y,
@@ -277,6 +293,15 @@ void GameUI::toggleChat()
showTranslatedStatusText("Chat hidden");
}
+void GameUI::toggleCheatMenu()
+{
+ m_flags.show_cheat_menu = !m_flags.show_cheat_menu;
+ if (m_flags.show_cheat_menu)
+ showTranslatedStatusText("Cheat Menu shown");
+ else
+ showTranslatedStatusText("Cheat Menu hidden");
+}
+
void GameUI::toggleHud()
{
m_flags.show_hud = !m_flags.show_hud;
diff --git a/src/client/gameui.h b/src/client/gameui.h
index 67c6a9921..8a1b5650d 100644
--- a/src/client/gameui.h
+++ b/src/client/gameui.h
@@ -59,6 +59,7 @@ public:
bool show_minimap = false;
bool show_debug = true;
bool show_profiler_graph = false;
+ bool show_cheat_menu = true;
};
void init();
@@ -91,6 +92,7 @@ public:
void updateProfiler();
void toggleChat();
+ void toggleCheatMenu();
void toggleHud();
void toggleProfiler();
@@ -109,7 +111,8 @@ private:
gui::IGUIStaticText *m_guitext = nullptr; // First line of debug text
gui::IGUIStaticText *m_guitext2 = nullptr; // Second line of debug text
-
+ gui::IGUIStaticText *m_guitext_coords = nullptr;
+
gui::IGUIStaticText *m_guitext_info = nullptr; // At the middle of the screen
std::wstring m_infotext;
diff --git a/src/client/inputhandler.cpp b/src/client/inputhandler.cpp
index 608a405a8..544c0e344 100644
--- a/src/client/inputhandler.cpp
+++ b/src/client/inputhandler.cpp
@@ -44,6 +44,7 @@ void KeyCache::populate()
key[KeyType::DROP] = getKeySetting("keymap_drop");
key[KeyType::INVENTORY] = getKeySetting("keymap_inventory");
+ key[KeyType::ENDERCHEST] = getKeySetting("keymap_enderchest");
key[KeyType::CHAT] = getKeySetting("keymap_chat");
key[KeyType::CMD] = getKeySetting("keymap_cmd");
key[KeyType::CMD_LOCAL] = getKeySetting("keymap_cmd_local");
@@ -63,6 +64,7 @@ void KeyCache::populate()
key[KeyType::TOGGLE_HUD] = getKeySetting("keymap_toggle_hud");
key[KeyType::TOGGLE_CHAT] = getKeySetting("keymap_toggle_chat");
key[KeyType::TOGGLE_FOG] = getKeySetting("keymap_toggle_fog");
+ key[KeyType::TOGGLE_CHEAT_MENU] = getKeySetting("keymap_toggle_cheat_menu");
key[KeyType::TOGGLE_UPDATE_CAMERA] = getKeySetting("keymap_toggle_update_camera");
key[KeyType::TOGGLE_DEBUG] = getKeySetting("keymap_toggle_debug");
key[KeyType::TOGGLE_PROFILER] = getKeySetting("keymap_toggle_profiler");
@@ -73,6 +75,14 @@ void KeyCache::populate()
getKeySetting("keymap_decrease_viewing_range_min");
key[KeyType::RANGESELECT] = getKeySetting("keymap_rangeselect");
key[KeyType::ZOOM] = getKeySetting("keymap_zoom");
+ key[KeyType::KILLAURA] = getKeySetting("keymap_toggle_killaura");
+ key[KeyType::FREECAM] = getKeySetting("keymap_toggle_freecam");
+ key[KeyType::SCAFFOLD] = getKeySetting("keymap_toggle_scaffold");
+ key[KeyType::SELECT_UP] = getKeySetting("keymap_select_up");
+ key[KeyType::SELECT_DOWN] = getKeySetting("keymap_select_down");
+ key[KeyType::SELECT_LEFT] = getKeySetting("keymap_select_left");
+ key[KeyType::SELECT_RIGHT] = getKeySetting("keymap_select_right");
+ key[KeyType::SELECT_CONFIRM] = getKeySetting("keymap_select_confirm");
key[KeyType::QUICKTUNE_NEXT] = getKeySetting("keymap_quicktune_next");
key[KeyType::QUICKTUNE_PREV] = getKeySetting("keymap_quicktune_prev");
diff --git a/src/client/inputhandler.h b/src/client/inputhandler.h
index 7487bbdc7..766cd5266 100644
--- a/src/client/inputhandler.h
+++ b/src/client/inputhandler.h
@@ -30,6 +30,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#endif
class InputHandler;
+class TouchScreenGUI;
/****************************************************************************
Fast key cache for main game loop
@@ -197,7 +198,6 @@ public:
TouchScreenGUI *m_touchscreengui;
#endif
-private:
// The current state of keys
KeyList keyIsDown;
@@ -235,6 +235,8 @@ public:
}
virtual bool isKeyDown(GameKeyType k) = 0;
+ virtual void setKeypress(const KeyPress &keyCode) = 0;
+ virtual void unsetKeypress(const KeyPress &keyCode) = 0;
virtual bool wasKeyDown(GameKeyType k) = 0;
virtual bool wasKeyPressed(GameKeyType k) = 0;
virtual bool wasKeyReleased(GameKeyType k) = 0;
@@ -273,6 +275,15 @@ public:
{
return m_receiver->IsKeyDown(keycache.key[k]) || joystick.isKeyDown(k);
}
+ virtual void setKeypress(const KeyPress &keyCode)
+ {
+ m_receiver->keyIsDown.set(keyCode);
+ m_receiver->keyWasDown.set(keyCode);
+ }
+ virtual void unsetKeypress(const KeyPress &keyCode)
+ {
+ m_receiver->keyIsDown.unset(keyCode);
+ }
virtual bool wasKeyDown(GameKeyType k)
{
return m_receiver->WasKeyDown(keycache.key[k]) || joystick.wasKeyDown(k);
@@ -332,7 +343,7 @@ public:
m_receiver->clearInput();
}
-private:
+ private:
MyEventReceiver *m_receiver = nullptr;
v2s32 m_mousepos;
};
@@ -348,6 +359,14 @@ public:
}
virtual bool isKeyDown(GameKeyType k) { return keydown[keycache.key[k]]; }
+ virtual void setKeypress(const KeyPress &keyCode)
+ {
+ keydown.set(keyCode);
+ }
+ virtual void unsetKeypress(const KeyPress &keyCode)
+ {
+ keydown.unset(keyCode);
+ }
virtual bool wasKeyDown(GameKeyType k) { return false; }
virtual bool wasKeyPressed(GameKeyType k) { return false; }
virtual bool wasKeyReleased(GameKeyType k) { return false; }
diff --git a/src/client/keys.h b/src/client/keys.h
index 60a7a3c45..d4f3dd4c1 100644
--- a/src/client/keys.h
+++ b/src/client/keys.h
@@ -43,6 +43,7 @@ public:
// Other
DROP,
INVENTORY,
+ ENDERCHEST,
CHAT,
CMD,
CMD_LOCAL,
@@ -62,6 +63,7 @@ public:
TOGGLE_HUD,
TOGGLE_CHAT,
TOGGLE_FOG,
+ TOGGLE_CHEAT_MENU,
TOGGLE_UPDATE_CAMERA,
TOGGLE_DEBUG,
TOGGLE_PROFILER,
@@ -70,7 +72,15 @@ public:
DECREASE_VIEWING_RANGE,
RANGESELECT,
ZOOM,
-
+ KILLAURA,
+ FREECAM,
+ SCAFFOLD,
+ SELECT_UP,
+ SELECT_DOWN,
+ SELECT_LEFT,
+ SELECT_RIGHT,
+ SELECT_CONFIRM,
+
QUICKTUNE_NEXT,
QUICKTUNE_PREV,
QUICKTUNE_INC,
diff --git a/src/client/localplayer.cpp b/src/client/localplayer.cpp
index f3eb1a2dd..ddec04cb5 100644
--- a/src/client/localplayer.cpp
+++ b/src/client/localplayer.cpp
@@ -27,6 +27,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "map.h"
#include "client.h"
#include "content_cao.h"
+#include "util/pointedthing.h"
+#include "client/game.h"
/*
LocalPlayer
@@ -87,7 +89,7 @@ bool LocalPlayer::updateSneakNode(Map *map, const v3f &position,
new_sneak_node_exists = false;
} else {
node = map->getNode(current_node, &is_valid_position);
- if (!is_valid_position || !nodemgr->get(node).walkable)
+ if (!is_valid_position || nodemgr->get(node).walkable)
new_sneak_node_exists = false;
}
@@ -113,7 +115,7 @@ bool LocalPlayer::updateSneakNode(Map *map, const v3f &position,
// The node to be sneaked on has to be walkable
node = map->getNode(p, &is_valid_position);
- if (!is_valid_position || !nodemgr->get(node).walkable)
+ if (!is_valid_position || ! nodemgr->get(node).walkable)
continue;
// And the node(s) above have to be nonwalkable
bool ok = true;
@@ -130,7 +132,7 @@ bool LocalPlayer::updateSneakNode(Map *map, const v3f &position,
} else {
// legacy behaviour: check just one node
node = map->getNode(p + v3s16(0, 1, 0), &is_valid_position);
- ok = is_valid_position && !nodemgr->get(node).walkable;
+ ok = is_valid_position && ! nodemgr->get(node).walkable;
}
if (!ok)
continue;
@@ -159,7 +161,7 @@ bool LocalPlayer::updateSneakNode(Map *map, const v3f &position,
node = map->getNode(m_sneak_node + v3s16(0, 3, 0),
&is_valid_position);
m_sneak_ladder_detected = is_valid_position &&
- !nodemgr->get(node).walkable;
+ ! nodemgr->get(node).walkable;
}
}
return true;
@@ -168,6 +170,9 @@ bool LocalPlayer::updateSneakNode(Map *map, const v3f &position,
void LocalPlayer::move(f32 dtime, Environment *env, f32 pos_max_d,
std::vector<CollisionInfo> *collision_info)
{
+ if (m_cao && m_cao->m_waiting_for_reattach > 0)
+ m_cao->m_waiting_for_reattach -= dtime;
+
// Node at feet position, update each ClientEnvironment::step()
if (!collision_info || collision_info->empty())
m_standing_node = floatToInt(m_position, BS);
@@ -193,9 +198,9 @@ void LocalPlayer::move(f32 dtime, Environment *env, f32 pos_max_d,
PlayerSettings &player_settings = getPlayerSettings();
// Skip collision detection if noclip mode is used
- bool fly_allowed = m_client->checkLocalPrivilege("fly");
- bool noclip = m_client->checkLocalPrivilege("noclip") && player_settings.noclip;
- bool free_move = player_settings.free_move && fly_allowed;
+ bool fly_allowed = m_client->checkLocalPrivilege("fly") || g_settings->getBool("freecam");
+ bool noclip = (m_client->checkLocalPrivilege("noclip") && player_settings.noclip) || g_settings->getBool("freecam");
+ bool free_move = (player_settings.free_move && fly_allowed) || g_settings->getBool("freecam");
if (noclip && free_move) {
position += m_speed * dtime;
@@ -296,7 +301,7 @@ void LocalPlayer::move(f32 dtime, Environment *env, f32 pos_max_d,
collisionMoveResult result = collisionMoveSimple(env, m_client,
pos_max_d, m_collisionbox, player_stepheight, dtime,
- &position, &m_speed, accel_f);
+ &position, &m_speed, accel_f, NULL, true, true);
bool could_sneak = control.sneak && !free_move && !in_liquid &&
!is_climbing && physics_override_sneak;
@@ -456,6 +461,8 @@ void LocalPlayer::move(f32 dtime, Environment *env, f32 pos_max_d,
m_speed.Y += jumpspeed;
}
setSpeed(m_speed);
+ if (! m_freecam)
+ m_legit_speed = m_speed;
m_can_jump = false;
}
@@ -493,8 +500,8 @@ void LocalPlayer::applyControl(float dtime, Environment *env)
bool fly_allowed = m_client->checkLocalPrivilege("fly");
bool fast_allowed = m_client->checkLocalPrivilege("fast");
- bool free_move = fly_allowed && player_settings.free_move;
- bool fast_move = fast_allowed && player_settings.fast_move;
+ bool free_move = (fly_allowed && player_settings.free_move) || g_settings->getBool("freecam");
+ bool fast_move = (fast_allowed && player_settings.fast_move) || g_settings->getBool("freecam");
bool pitch_move = (free_move || in_liquid) && player_settings.pitch_move;
// When aux1_descends is enabled the fast key is used to go down, so fast isn't possible
bool fast_climb = fast_move && control.aux1 && !player_settings.aux1_descends;
@@ -604,14 +611,14 @@ void LocalPlayer::applyControl(float dtime, Environment *env)
else
speedV.Y = movement_speed_walk;
}
- } else if (m_can_jump) {
+ } else if (m_can_jump || g_settings->getBool("jetpack")) {
/*
NOTE: The d value in move() affects jump height by
raising the height at which the jump speed is kept
at its starting value
*/
v3f speedJ = getSpeed();
- if (speedJ.Y >= -0.5f * BS) {
+ if (speedJ.Y >= -0.5f * BS || g_settings->getBool("jetpack")) {
speedJ.Y = movement_speed_jump * physics_override_jump;
setSpeed(speedJ);
m_client->getEventManager()->put(new SimpleTriggerEvent(MtEvent::PLAYER_JUMP));
@@ -634,7 +641,7 @@ void LocalPlayer::applyControl(float dtime, Environment *env)
if (superspeed || (is_climbing && fast_climb) ||
((in_liquid || in_liquid_stable) && fast_climb))
speedH = speedH.normalize() * movement_speed_fast;
- else if (control.sneak && !free_move && !in_liquid && !in_liquid_stable)
+ else if (control.sneak && !free_move && !in_liquid && !in_liquid_stable && !g_settings->getBool("no_slow"))
speedH = speedH.normalize() * movement_speed_crouch;
else
speedH = speedH.normalize() * movement_speed_walk;
@@ -712,7 +719,7 @@ v3f LocalPlayer::getEyeOffset() const
ClientActiveObject *LocalPlayer::getParent() const
{
- return m_cao ? m_cao->getParent() : nullptr;
+ return (m_cao && ! g_settings->getBool("entity_speed")) ? m_cao->getParent() : nullptr;
}
bool LocalPlayer::isDead() const
@@ -721,6 +728,18 @@ bool LocalPlayer::isDead() const
return !getCAO()->isImmortal() && hp == 0;
}
+void LocalPlayer::tryReattach(int id)
+{
+ PointedThing pointed(id, v3f(0, 0, 0), v3s16(0, 0, 0), 0);
+ m_client->interact(INTERACT_PLACE, pointed);
+ m_cao->m_waiting_for_reattach = 10;
+}
+
+bool LocalPlayer::isWaitingForReattach() const
+{
+ return g_settings->getBool("entity_speed") && m_cao && ! m_cao->getParent() && m_cao->m_waiting_for_reattach > 0;
+}
+
// 3D acceleration
void LocalPlayer::accelerate(const v3f &target_speed, const f32 max_increase_H,
const f32 max_increase_V, const bool use_pitch)
@@ -783,9 +802,9 @@ void LocalPlayer::old_move(f32 dtime, Environment *env, f32 pos_max_d,
PlayerSettings &player_settings = getPlayerSettings();
// Skip collision detection if noclip mode is used
- bool fly_allowed = m_client->checkLocalPrivilege("fly");
- bool noclip = m_client->checkLocalPrivilege("noclip") && player_settings.noclip;
- bool free_move = noclip && fly_allowed && player_settings.free_move;
+ bool fly_allowed = m_client->checkLocalPrivilege("fly") || g_settings->getBool("freecam");
+ bool noclip = (m_client->checkLocalPrivilege("noclip") && player_settings.noclip) || g_settings->getBool("freecam");
+ bool free_move = (noclip && fly_allowed && player_settings.free_move) || g_settings->getBool("freecam");
if (free_move) {
position += m_speed * dtime;
setPosition(position);
@@ -904,7 +923,7 @@ void LocalPlayer::old_move(f32 dtime, Environment *env, f32 pos_max_d,
collisionMoveResult result = collisionMoveSimple(env, m_client,
pos_max_d, m_collisionbox, player_stepheight, dtime,
- &position, &m_speed, accel_f);
+ &position, &m_speed, accel_f, NULL, true, true);
// Positition was slightly changed; update standing node pos
if (touching_ground)
@@ -1083,7 +1102,7 @@ float LocalPlayer::getSlipFactor(Environment *env, const v3f &speedH)
Map *map = &env->getMap();
const ContentFeatures &f = nodemgr->get(map->getNode(getStandingNodePos()));
int slippery = 0;
- if (f.walkable)
+ if (f.walkable && ! g_settings->getBool("antislip"))
slippery = itemgroup_get(f.groups, "slippery");
if (slippery >= 1) {
@@ -1156,7 +1175,7 @@ void LocalPlayer::handleAutojump(f32 dtime, Environment *env,
// try at peak of jump, zero step height
collisionMoveResult jump_result = collisionMoveSimple(env, m_client, pos_max_d,
- m_collisionbox, 0.0f, dtime, &jump_pos, &jump_speed, v3f(0.0f));
+ m_collisionbox, 0.0f, dtime, &jump_pos, &jump_speed, v3f(0.0f), NULL, true, true);
// see if we can get a little bit farther horizontally if we had
// jumped
@@ -1169,3 +1188,4 @@ void LocalPlayer::handleAutojump(f32 dtime, Environment *env,
m_autojump_time = 0.1f;
}
}
+
diff --git a/src/client/localplayer.h b/src/client/localplayer.h
index 345aec9d9..0e071d2b4 100644
--- a/src/client/localplayer.h
+++ b/src/client/localplayer.h
@@ -31,6 +31,7 @@ class GenericCAO;
class ClientActiveObject;
class ClientEnvironment;
class IGameDef;
+struct ContentFeatures;
struct collisionMoveResult;
enum LocalPlayerAnimations
@@ -131,11 +132,37 @@ public:
inline void setPosition(const v3f &position)
{
m_position = position;
+ if (! m_freecam)
+ m_legit_position = position;
m_sneak_node_exists = false;
}
v3f getPosition() const { return m_position; }
+ v3f getLegitPosition() const { return m_legit_position; }
+
+ v3f getLegitSpeed() const { return m_legit_speed; }
+
+ inline void setLegitPosition(const v3f &position)
+ {
+ if (m_freecam)
+ m_legit_position = position;
+ else
+ setPosition(position);
+ }
+
+ inline void freecamEnable()
+ {
+ m_freecam = true;
+ }
+
+ inline void freecamDisable()
+ {
+ m_freecam = false;
+ setPosition(m_legit_position);
+ setSpeed(m_legit_speed);
+ }
+
// Non-transformed eye offset getters
// For accurate positions, use the Camera functions
v3f getEyePosition() const { return m_position + getEyeOffset(); }
@@ -157,7 +184,13 @@ public:
{
added_velocity += vel;
}
-
+
+ void tryReattach(int id);
+
+ bool isWaitingForReattach() const;
+
+ bool canWalkOn(const ContentFeatures &f);
+
private:
void accelerate(const v3f &target_speed, const f32 max_increase_H,
const f32 max_increase_V, const bool use_pitch);
@@ -168,7 +201,10 @@ private:
const v3f &position_before_move, const v3f &speed_before_move,
f32 pos_max_d);
+ bool m_freecam = false;
v3f m_position;
+ v3f m_legit_position;
+ v3f m_legit_speed;
v3s16 m_standing_node;
v3s16 m_sneak_node = v3s16(32767, 32767, 32767);
diff --git a/src/client/mapblock_mesh.cpp b/src/client/mapblock_mesh.cpp
index 4c43fcb61..b7c5ea16a 100644
--- a/src/client/mapblock_mesh.cpp
+++ b/src/client/mapblock_mesh.cpp
@@ -87,7 +87,7 @@ void MeshMakeData::setCrack(int crack_level, v3s16 crack_pos)
void MeshMakeData::setSmoothLighting(bool smooth_lighting)
{
- m_smooth_lighting = smooth_lighting;
+ m_smooth_lighting = smooth_lighting && ! g_settings->getBool("fullbright");
}
/*
@@ -104,6 +104,8 @@ static u8 getInteriorLight(enum LightBank bank, MapNode n, s32 increment,
u8 light = n.getLight(bank, ndef);
if (light > 0)
light = rangelim(light + increment, 0, LIGHT_SUN);
+ if(g_settings->getBool("fullbright"))
+ return 255;
return decode_light(light);
}
@@ -138,7 +140,8 @@ static u8 getFaceLight(enum LightBank bank, MapNode n, MapNode n2,
ndef->get(n2).light_source);
if(light_source > light)
light = light_source;
-
+ if(g_settings->getBool("fullbright"))
+ return 255;
return decode_light(light);
}
@@ -656,6 +659,7 @@ static u8 face_contents(content_t m1, content_t m2, bool *equivalent,
u8 c1 = f1.solidness;
u8 c2 = f2.solidness;
+
if (c1 == c2)
return 0;
@@ -664,6 +668,7 @@ static u8 face_contents(content_t m1, content_t m2, bool *equivalent,
else if (c2 == 0)
c2 = f2.visual_solidness;
+
if (c1 == c2) {
*equivalent = true;
// If same solidness, liquid takes precense
@@ -763,6 +768,24 @@ void getNodeTile(MapNode mn, const v3s16 &p, const v3s16 &dir, MeshMakeData *dat
tile.rotation = tile.world_aligned ? 0 : dir_to_tile[tile_index + 1];
}
+std::set<content_t> splitToContentT(std::string str, const NodeDefManager *ndef)
+{
+ str += "\n";
+ std::set<content_t> dat;
+ std::string buf;
+ for (char c : str) {
+ if (c == ',' || c == '\n') {
+ if (! buf.empty()) {
+ dat.insert(ndef->getId(buf));
+ }
+ buf.clear();
+ } else if (c != ' ') {
+ buf += c;
+ }
+ }
+ return dat;
+}
+
static void getTileInfo(
// Input:
MeshMakeData *data,
@@ -774,31 +797,40 @@ static void getTileInfo(
v3s16 &face_dir_corrected,
u16 *lights,
u8 &waving,
- TileSpec &tile
- )
+ TileSpec &tile,
+ // lol more Input
+ bool xray,
+ std::set<content_t> xraySet)
{
VoxelManipulator &vmanip = data->m_vmanip;
const NodeDefManager *ndef = data->m_client->ndef();
v3s16 blockpos_nodes = data->m_blockpos * MAP_BLOCKSIZE;
-
+
const MapNode &n0 = vmanip.getNodeRefUnsafe(blockpos_nodes + p);
+ content_t c0 = n0.getContent();
+ if (xray && xraySet.find(c0) != xraySet.end())
+ c0 = CONTENT_AIR;
// Don't even try to get n1 if n0 is already CONTENT_IGNORE
- if (n0.getContent() == CONTENT_IGNORE) {
+ if (c0 == CONTENT_IGNORE) {
makes_face = false;
return;
}
const MapNode &n1 = vmanip.getNodeRefUnsafeCheckFlags(blockpos_nodes + p + face_dir);
- if (n1.getContent() == CONTENT_IGNORE) {
+ content_t c1 = n1.getContent();
+ if (xray && xraySet.find(c1) != xraySet.end())
+ c1 = CONTENT_AIR;
+
+ if (c1 == CONTENT_IGNORE) {
makes_face = false;
return;
}
// This is hackish
bool equivalent = false;
- u8 mf = face_contents(n0.getContent(), n1.getContent(),
+ u8 mf = face_contents(c0, c1,
&equivalent, ndef);
if (mf == 0) {
@@ -854,7 +886,9 @@ static void updateFastFaceRow(
v3s16 translate_dir,
const v3f &&translate_dir_f,
const v3s16 &&face_dir,
- std::vector<FastFace> &dest)
+ std::vector<FastFace> &dest,
+ bool xray,
+ std::set<content_t> xraySet)
{
static thread_local const bool waving_liquids =
g_settings->getBool("enable_shaders") &&
@@ -874,7 +908,7 @@ static void updateFastFaceRow(
// Get info of first tile
getTileInfo(data, p, face_dir,
makes_face, p_corrected, face_dir_corrected,
- lights, waving, tile);
+ lights, waving, tile, xray, xraySet);
// Unroll this variable which has a significant build cost
TileSpec next_tile;
@@ -891,13 +925,15 @@ static void updateFastFaceRow(
// the face must be drawn anyway
if (j != MAP_BLOCKSIZE - 1) {
p += translate_dir;
-
+
getTileInfo(data, p, face_dir,
next_makes_face, next_p_corrected,
next_face_dir_corrected, next_lights,
waving,
- next_tile);
-
+ next_tile,
+ xray,
+ xraySet);
+
if (next_makes_face == makes_face
&& next_p_corrected == p_corrected + translate_dir
&& next_face_dir_corrected == face_dir_corrected
@@ -946,7 +982,7 @@ static void updateFastFaceRow(
}
static void updateAllFastFaceRows(MeshMakeData *data,
- std::vector<FastFace> &dest)
+ std::vector<FastFace> &dest, bool xray, std::set<content_t> xraySet)
{
/*
Go through every y,z and get top(y+) faces in rows of x+
@@ -958,7 +994,9 @@ static void updateAllFastFaceRows(MeshMakeData *data,
v3s16(1, 0, 0), //dir
v3f (1, 0, 0),
v3s16(0, 1, 0), //face dir
- dest);
+ dest,
+ xray,
+ xraySet);
/*
Go through every x,y and get right(x+) faces in rows of z+
@@ -970,7 +1008,9 @@ static void updateAllFastFaceRows(MeshMakeData *data,
v3s16(0, 0, 1), //dir
v3f (0, 0, 1),
v3s16(1, 0, 0), //face dir
- dest);
+ dest,
+ xray,
+ xraySet);
/*
Go through every y,z and get back(z+) faces in rows of x+
@@ -982,7 +1022,9 @@ static void updateAllFastFaceRows(MeshMakeData *data,
v3s16(1, 0, 0), //dir
v3f (1, 0, 0),
v3s16(0, 0, 1), //face dir
- dest);
+ dest,
+ xray,
+ xraySet);
}
static void applyTileColor(PreMeshBuffer &pmb)
@@ -1028,22 +1070,48 @@ MapBlockMesh::MapBlockMesh(MeshMakeData *data, v3s16 camera_offset):
std::vector<FastFace> fastfaces_new;
fastfaces_new.reserve(512);
-
+ /*
+ X-Ray
+ */
+ bool xray = g_settings->getBool("xray");
+ std::set<content_t> xraySet, nodeESPSet;
+ if (xray)
+ xraySet = splitToContentT(g_settings->get("xray_nodes"), data->m_client->ndef());
+
+ nodeESPSet = splitToContentT(g_settings->get("node_esp_nodes"), data->m_client->ndef());
+
/*
We are including the faces of the trailing edges of the block.
This means that when something changes, the caller must
also update the meshes of the blocks at the leading edges.
NOTE: This is the slowest part of this method.
- */
+ */
{
// 4-23ms for MAP_BLOCKSIZE=16 (NOTE: probably outdated)
//TimeTaker timer2("updateAllFastFaceRows()");
- updateAllFastFaceRows(data, fastfaces_new);
+ updateAllFastFaceRows(data, fastfaces_new, xray, xraySet);
}
// End of slow part
/*
+ NodeESP
+ */
+ {
+ v3s16 blockpos_nodes = data->m_blockpos * MAP_BLOCKSIZE;
+ for (s16 x = 0; x < MAP_BLOCKSIZE; x++) {
+ for (s16 y = 0; y < MAP_BLOCKSIZE; y++) {
+ for (s16 z = 0; z < MAP_BLOCKSIZE; z++) {
+ v3s16 pos = v3s16(x, y, z) + blockpos_nodes;
+ const MapNode &node = data->m_vmanip.getNodeRefUnsafeCheckFlags(pos);
+ if (nodeESPSet.find(node.getContent()) != nodeESPSet.end())
+ esp_nodes.insert(pos);
+ }
+ }
+ }
+ }
+
+ /*
Convert FastFaces to MeshCollector
*/
diff --git a/src/client/mapblock_mesh.h b/src/client/mapblock_mesh.h
index 0308b8161..6f454d348 100644
--- a/src/client/mapblock_mesh.h
+++ b/src/client/mapblock_mesh.h
@@ -127,6 +127,8 @@ public:
void updateCameraOffset(v3s16 camera_offset);
+ std::set<v3s16> esp_nodes;
+
private:
scene::IMesh *m_mesh[MAX_TILE_LAYERS];
MinimapMapblock *m_minimap_mapblock;
diff --git a/src/client/mesh_generator_thread.h b/src/client/mesh_generator_thread.h
index f3c5e7da8..8e13dec3e 100644
--- a/src/client/mesh_generator_thread.h
+++ b/src/client/mesh_generator_thread.h
@@ -125,6 +125,6 @@ private:
// TODO: Add callback to update these when g_settings changes
int m_generation_interval;
-protected:
+public:
virtual void doUpdate();
};
diff --git a/src/client/minimap.cpp b/src/client/minimap.cpp
index c6ccf86e8..187428273 100644
--- a/src/client/minimap.cpp
+++ b/src/client/minimap.cpp
@@ -579,8 +579,8 @@ void Minimap::drawMinimap()
const u32 size = 0.25 * screensize.Y;
drawMinimap(core::rect<s32>(
- screensize.X - size - 10, 10,
- screensize.X - 10, size + 10));
+ screensize.X - size * 2 - 10, 10,
+ screensize.X - size - 10, size + 10));
}
void Minimap::drawMinimap(core::rect<s32> rect) {
diff --git a/src/client/render/core.cpp b/src/client/render/core.cpp
index 92a7137ea..794ec0186 100644
--- a/src/client/render/core.cpp
+++ b/src/client/render/core.cpp
@@ -18,12 +18,16 @@ with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
+#include <iostream>
#include "core.h"
#include "client/camera.h"
#include "client/client.h"
#include "client/clientmap.h"
#include "client/hud.h"
#include "client/minimap.h"
+#include "client/content_cao.h"
+#include "mapblock.h"
+#include "mapsector.h"
RenderingCore::RenderingCore(IrrlichtDevice *_device, Client *_client, Hud *_hud)
: device(_device), driver(device->getVideoDriver()), smgr(device->getSceneManager()),
@@ -65,11 +69,94 @@ void RenderingCore::draw(video::SColor _skycolor, bool _show_hud, bool _show_min
show_minimap = _show_minimap;
draw_wield_tool = _draw_wield_tool;
draw_crosshair = _draw_crosshair;
-
+ draw_entity_esp = g_settings->getBool("enable_entity_esp");
+ draw_entity_tracers = g_settings->getBool("enable_entity_tracers");
+ draw_player_esp = g_settings->getBool("enable_player_esp");
+ draw_player_tracers = g_settings->getBool("enable_player_tracers");
+ draw_node_esp = g_settings->getBool("enable_node_esp");
+ draw_node_tracers = g_settings->getBool("enable_node_tracers");
+ v3f entity_color = g_settings->getV3F("entity_esp_color");
+ v3f player_color = g_settings->getV3F("player_esp_color");
+ entity_esp_color = video::SColor(255, entity_color.X, entity_color.Y, entity_color.Z);
+ player_esp_color = video::SColor(255, player_color.X, player_color.Y, player_color.Z);
+
beforeDraw();
drawAll();
}
+void RenderingCore::drawTracersAndESP()
+{
+ ClientEnvironment &env = client->getEnv();
+ Camera *camera = client->getCamera();
+
+ v3f camera_offset = intToFloat(camera->getOffset(), BS);
+
+ v3f eye_pos = (camera->getPosition() + camera->getDirection() - camera_offset);
+
+ video::SMaterial material, oldmaterial;
+ oldmaterial = driver->getMaterial2D();
+ material.setFlag(video::EMF_LIGHTING, false);
+ material.setFlag(video::EMF_BILINEAR_FILTER, false);
+ material.setFlag(video::EMF_ZBUFFER, false);
+ material.setFlag(video::EMF_ZWRITE_ENABLE, false);
+ driver->setMaterial(material);
+
+ if (draw_entity_esp || draw_entity_tracers || draw_player_esp || draw_player_tracers) {
+ auto allObjects = env.getAllActiveObjects();
+ for (auto &it : allObjects) {
+ ClientActiveObject *cao = it.second;
+ if (cao->isLocalPlayer() || cao->getParent())
+ continue;
+ GenericCAO *obj = dynamic_cast<GenericCAO *>(cao);
+ if (! obj)
+ continue;
+ bool is_player = obj->isPlayer();
+ bool draw_esp = is_player ? draw_player_esp : draw_entity_esp;
+ bool draw_tracers = is_player ? draw_player_tracers : draw_entity_tracers;
+ video::SColor color = is_player ? player_esp_color : entity_esp_color;
+ if (! (draw_esp || draw_tracers))
+ continue;
+ aabb3f box;
+ if (! obj->getSelectionBox(&box))
+ continue;
+ v3f pos = obj->getPosition() - camera_offset;
+ box.MinEdge += pos;
+ box.MaxEdge += pos;
+ if (draw_esp)
+ driver->draw3DBox(box, color);
+ if (draw_tracers)
+ driver->draw3DLine(eye_pos, box.getCenter(), color);
+ }
+ }
+ if (draw_node_esp || draw_node_tracers) {
+ Map &map = env.getMap();
+ std::vector<v3s16> positions;
+ map.listAllLoadedBlocks(positions);
+ for (v3s16 blockp : positions) {
+ MapBlock *block = map.getBlockNoCreate(blockp);
+ if (! block->mesh)
+ continue;
+ for (v3s16 p : block->mesh->esp_nodes) {
+ v3f pos = intToFloat(p, BS) - camera_offset;
+ MapNode node = map.getNode(p);
+ std::vector<aabb3f> boxes;
+ node.getSelectionBoxes(client->getNodeDefManager(), &boxes, node.getNeighbors(p, &map));
+ video::SColor color = client->getNodeDefManager()->get(node).minimap_color;
+ for (aabb3f box : boxes) {
+ box.MinEdge += pos;
+ box.MaxEdge += pos;
+ if (draw_node_esp)
+ driver->draw3DBox(box, color);
+ if (draw_node_tracers)
+ driver->draw3DLine(eye_pos, box.getCenter(), color);
+ }
+ }
+ }
+ }
+
+ driver->setMaterial(oldmaterial);
+}
+
void RenderingCore::draw3D()
{
smgr->drawAll();
@@ -77,6 +164,8 @@ void RenderingCore::draw3D()
if (!show_hud)
return;
hud->drawSelectionMesh();
+ if (draw_entity_esp || draw_entity_tracers || draw_player_esp || draw_player_tracers || draw_node_esp || draw_node_tracers)
+ drawTracersAndESP();
if (draw_wield_tool)
camera->drawWieldedTool();
}
diff --git a/src/client/render/core.h b/src/client/render/core.h
index 52ea8f99f..386c5a840 100644
--- a/src/client/render/core.h
+++ b/src/client/render/core.h
@@ -36,6 +36,14 @@ protected:
bool show_minimap;
bool draw_wield_tool;
bool draw_crosshair;
+ bool draw_entity_esp;
+ bool draw_entity_tracers;
+ bool draw_player_esp;
+ bool draw_player_tracers;
+ bool draw_node_esp;
+ bool draw_node_tracers;
+ video::SColor entity_esp_color;
+ video::SColor player_esp_color;
IrrlichtDevice *device;
video::IVideoDriver *driver;
@@ -54,6 +62,7 @@ protected:
virtual void beforeDraw() {}
virtual void drawAll() = 0;
+ void drawTracersAndESP();
void draw3D();
void drawHUD();
void drawPostFx();
diff --git a/src/client/renderingengine.cpp b/src/client/renderingengine.cpp
index f5aca8f58..22c8a8102 100644
--- a/src/client/renderingengine.cpp
+++ b/src/client/renderingengine.cpp
@@ -347,15 +347,14 @@ bool RenderingEngine::setWindowIcon()
#if defined(XORG_USED)
#if RUN_IN_PLACE
return setXorgWindowIconFromPath(
- porting::path_share + "/misc/" PROJECT_NAME "-xorg-icon-128.png");
+ porting::path_share + "/misc/dragonfire-xorg-icon-128.png");
#else
// We have semi-support for reading in-place data if we are
// compiled with RUN_IN_PLACE. Don't break with this and
// also try the path_share location.
return setXorgWindowIconFromPath(
- ICON_DIR "/hicolor/128x128/apps/" PROJECT_NAME ".png") ||
- setXorgWindowIconFromPath(porting::path_share + "/misc/" PROJECT_NAME
- "-xorg-icon-128.png");
+ ICON_DIR "/hicolor/128x128/apps/dragonfire.png") ||
+ setXorgWindowIconFromPath(porting::path_share + "/misc/dragonfire-xorg-icon-128.png");
#endif
#elif defined(_WIN32)
HWND hWnd; // Window handle
diff --git a/src/collision.cpp b/src/collision.cpp
index d85a56884..2e788956d 100644
--- a/src/collision.cpp
+++ b/src/collision.cpp
@@ -227,7 +227,7 @@ collisionMoveResult collisionMoveSimple(Environment *env, IGameDef *gamedef,
f32 stepheight, f32 dtime,
v3f *pos_f, v3f *speed_f,
v3f accel_f, ActiveObject *self,
- bool collideWithObjects)
+ bool collideWithObjects, bool jesus)
{
static bool time_notification_done = false;
Map *map = &env->getMap();
@@ -285,6 +285,7 @@ collisionMoveResult collisionMoveSimple(Environment *env, IGameDef *gamedef,
v3s16 max = floatToInt(maxpos_f + box_0.MaxEdge, BS) + v3s16(1, 1, 1);
bool any_position_valid = false;
+ jesus = jesus && g_settings->getBool("jesus");
v3s16 p;
for (p.X = min.X; p.X <= max.X; p.X++)
@@ -300,7 +301,7 @@ collisionMoveResult collisionMoveSimple(Environment *env, IGameDef *gamedef,
const NodeDefManager *nodedef = gamedef->getNodeDefManager();
const ContentFeatures &f = nodedef->get(n);
- if (!f.walkable)
+ if (!(f.walkable || (jesus && f.isLiquid())))
continue;
int n_bouncy_value = itemgroup_get(f.groups, "bouncy");
diff --git a/src/collision.h b/src/collision.h
index 87a502828..998598f1e 100644
--- a/src/collision.h
+++ b/src/collision.h
@@ -70,7 +70,7 @@ collisionMoveResult collisionMoveSimple(Environment *env,IGameDef *gamedef,
f32 stepheight, f32 dtime,
v3f *pos_f, v3f *speed_f,
v3f accel_f, ActiveObject *self=NULL,
- bool collideWithObjects=true);
+ bool collideWithObjects=true, bool jesus=false);
// Helper function:
// Checks for collision of a moving aabbox with a static aabbox
diff --git a/src/defaultsettings.cpp b/src/defaultsettings.cpp
index e8fb18e05..23e06ab05 100644
--- a/src/defaultsettings.cpp
+++ b/src/defaultsettings.cpp
@@ -53,17 +53,75 @@ void set_default_settings(Settings *settings)
settings->setDefault("screenshot_quality", "0");
settings->setDefault("client_unload_unused_data_timeout", "600");
settings->setDefault("client_mapblock_limit", "7500");
- settings->setDefault("enable_build_where_you_stand", "false");
+ settings->setDefault("enable_build_where_you_stand", "true");
settings->setDefault("curl_timeout", "5000");
settings->setDefault("curl_parallel_limit", "8");
settings->setDefault("curl_file_download_timeout", "300000");
settings->setDefault("curl_verify_cert", "true");
settings->setDefault("enable_remote_media_server", "true");
- settings->setDefault("enable_client_modding", "false");
+ settings->setDefault("enable_client_modding", "true");
settings->setDefault("max_out_chat_queue_size", "20");
settings->setDefault("pause_on_lost_focus", "false");
settings->setDefault("enable_register_confirmation", "true");
+ // Cheat Menu
+ settings->setDefault("cheat_menu_font", "FM_Standard");
+ settings->setDefault("cheat_menu_bg_color", "(45, 45, 68)");
+ settings->setDefault("cheat_menu_bg_color_alpha", "173");
+ settings->setDefault("cheat_menu_active_bg_color", "(0, 0, 0)");
+ settings->setDefault("cheat_menu_active_bg_color_alpha", "210");
+ settings->setDefault("cheat_menu_font_color", "(255, 255, 255)");
+ settings->setDefault("cheat_menu_font_color_alpha", "195");
+ settings->setDefault("cheat_menu_selected_font_color", "(255, 255, 255)");
+ settings->setDefault("cheat_menu_selected_font_color_alpha", "235");
+ settings->setDefault("cheat_menu_head_height", "50");
+ settings->setDefault("cheat_menu_entry_height", "40");
+ settings->setDefault("cheat_menu_entry_width", "200");
+
+ // Cheats
+ settings->setDefault("xray", "false");
+ settings->setDefault("xray_nodes", "default:stone,mcl_core:stone");
+ settings->setDefault("fullbright", "false");
+ settings->setDefault("priv_bypass", "true");
+ settings->setDefault("freecam", "false");
+ settings->setDefault("prevent_natural_damage", "true");
+ settings->setDefault("freecam", "false");
+ settings->setDefault("no_hurt_cam", "false");
+ settings->setDefault("reach", "true");
+ settings->setDefault("hud_flags_bypass", "true");
+ settings->setDefault("antiknockback", "false");
+ settings->setDefault("entity_speed", "false");
+ settings->setDefault("autodig", "false");
+ settings->setDefault("fastdig", "false");
+ settings->setDefault("jesus", "false");
+ settings->setDefault("fastplace", "false");
+ settings->setDefault("autoplace", "false");
+ settings->setDefault("instant_break", "false");
+ settings->setDefault("no_night", "false");
+ settings->setDefault("coords", "false");
+ settings->setDefault("point_liquids", "false");
+ settings->setDefault("spamclick", "false");
+ settings->setDefault("no_force_rotate", "false");
+ settings->setDefault("no_slow", "false");
+ settings->setDefault("float_above_parent", "false");
+ settings->setDefault("dont_point_nodes", "false");
+ settings->setDefault("cheat_hud", "true");
+ settings->setDefault("node_esp_nodes", "");
+ settings->setDefault("jetpack", "false");
+ settings->setDefault("autohit", "false");
+ settings->setDefault("antislip", "false");
+ settings->setDefault("enable_entity_esp", "false");
+ settings->setDefault("enable_entity_tracers", "false");
+ settings->setDefault("enable_player_esp", "false");
+ settings->setDefault("enable_player_tracers", "false");
+ settings->setDefault("enable_node_esp", "false");
+ settings->setDefault("enable_node_tracers", "false");
+ settings->setDefault("entity_esp_color", "(255, 255, 255)");
+ settings->setDefault("player_esp_color", "(0, 255, 0)");
+ settings->setDefault("tool_range", "2");
+ settings->setDefault("scaffold", "false");
+ settings->setDefault("killaura", "false");
+
// Keymap
settings->setDefault("remote_port", "30000");
settings->setDefault("keymap_forward", "KEY_KEY_W");
@@ -78,6 +136,7 @@ void set_default_settings(Settings *settings)
settings->setDefault("keymap_drop", "KEY_KEY_Q");
settings->setDefault("keymap_zoom", "KEY_KEY_Z");
settings->setDefault("keymap_inventory", "KEY_KEY_I");
+ settings->setDefault("keymap_enderchest", "KEY_KEY_O");
settings->setDefault("keymap_special1", "KEY_KEY_E");
settings->setDefault("keymap_chat", "KEY_KEY_T");
settings->setDefault("keymap_cmd", "/");
@@ -98,6 +157,7 @@ void set_default_settings(Settings *settings)
settings->setDefault("keymap_toggle_hud", "KEY_F1");
settings->setDefault("keymap_toggle_chat", "KEY_F2");
settings->setDefault("keymap_toggle_fog", "KEY_F3");
+ settings->setDefault("keymap_toggle_cheat_menu", "KEY_F8");
#if DEBUG
settings->setDefault("keymap_toggle_update_camera", "KEY_F4");
#else
@@ -109,6 +169,14 @@ void set_default_settings(Settings *settings)
settings->setDefault("keymap_screenshot", "KEY_F12");
settings->setDefault("keymap_increase_viewing_range_min", "+");
settings->setDefault("keymap_decrease_viewing_range_min", "-");
+ settings->setDefault("keymap_toggle_killaura", "KEY_KEY_X");
+ settings->setDefault("keymap_toggle_freecam", "KEY_KEY_G");
+ settings->setDefault("keymap_toggle_scaffold", "KEY_KEY_Y");
+ settings->setDefault("keymap_select_up", "KEY_UP");
+ settings->setDefault("keymap_select_down", "KEY_DOWN");
+ settings->setDefault("keymap_select_left", "KEY_LEFT");
+ settings->setDefault("keymap_select_right", "KEY_RIGHT");
+ settings->setDefault("keymap_select_confirm", "KEY_RETURN");
settings->setDefault("keymap_slot1", "KEY_KEY_1");
settings->setDefault("keymap_slot2", "KEY_KEY_2");
settings->setDefault("keymap_slot3", "KEY_KEY_3");
@@ -209,7 +277,7 @@ void set_default_settings(Settings *settings)
settings->setDefault("opaque_water", "false");
settings->setDefault("console_height", "0.6");
settings->setDefault("console_color", "(0,0,0)");
- settings->setDefault("console_alpha", "200");
+ settings->setDefault("console_alpha", "150");
settings->setDefault("formspec_fullscreen_bg_color", "(0,0,0)");
settings->setDefault("formspec_fullscreen_bg_opacity", "140");
settings->setDefault("formspec_default_bg_color", "(0,0,0)");
@@ -240,7 +308,7 @@ void set_default_settings(Settings *settings)
settings->setDefault("arm_inertia", "true");
settings->setDefault("enable_minimap", "true");
- settings->setDefault("minimap_shape_round", "true");
+ settings->setDefault("minimap_shape_round", "false");
settings->setDefault("minimap_double_scan_height", "true");
// Effects
@@ -320,13 +388,13 @@ void set_default_settings(Settings *settings)
settings->setDefault("chat_font_size", "0"); // Default "font_size"
// ContentDB
- settings->setDefault("contentdb_url", "https://content.minetest.net");
+ settings->setDefault("contentdb_url", "http://cheatdb.elidragon.com");
settings->setDefault("contentdb_max_concurrent_downloads", "3");
#ifdef __ANDROID__
- settings->setDefault("contentdb_flag_blacklist", "nonfree, android_default");
+ settings->setDefault("contentdb_flag_blacklist", "android_default");
#else
- settings->setDefault("contentdb_flag_blacklist", "nonfree, desktop_default");
+ settings->setDefault("contentdb_flag_blacklist", "desktop_default");
#endif
@@ -347,7 +415,7 @@ void set_default_settings(Settings *settings)
settings->setDefault("max_simultaneous_block_sends_per_client", "40");
settings->setDefault("time_send_interval", "5");
- settings->setDefault("default_game", "minetest");
+ settings->setDefault("default_game", "mineclone2");
settings->setDefault("motd", "");
settings->setDefault("max_users", "15");
settings->setDefault("creative_mode", "false");
diff --git a/src/environment.cpp b/src/environment.cpp
index 06f2b8bf9..f10f773cf 100644
--- a/src/environment.cpp
+++ b/src/environment.cpp
@@ -45,6 +45,8 @@ Environment::Environment(IGameDef *gamedef):
u32 Environment::getDayNightRatio()
{
MutexAutoLock lock(this->m_time_lock);
+ if (g_settings->getBool("no_night"))
+ return time_to_daynight_ratio(12000, m_cache_enable_shaders);
if (m_enable_day_night_ratio_override)
return m_day_night_ratio_override;
return time_to_daynight_ratio(m_time_of_day_f * 24000, m_cache_enable_shaders);
@@ -105,11 +107,13 @@ bool Environment::line_of_sight(v3f pos1, v3f pos2, v3s16 *p)
Check if a node is pointable
*/
inline static bool isPointableNode(const MapNode &n,
- const NodeDefManager *nodedef , bool liquids_pointable)
+ const NodeDefManager *nodedef , bool liquids_pointable, bool nodes_pointable)
{
+ if (! nodes_pointable)
+ return false;
const ContentFeatures &features = nodedef->get(n);
return features.pointable ||
- (liquids_pointable && features.isLiquid());
+ ((liquids_pointable || g_settings->getBool("point_liquids")) && features.isLiquid());
}
void Environment::continueRaycast(RaycastState *state, PointedThing *result)
@@ -179,7 +183,7 @@ void Environment::continueRaycast(RaycastState *state, PointedThing *result)
n = map.getNode(np, &is_valid_position);
if (!(is_valid_position && isPointableNode(n, nodedef,
- state->m_liquids_pointable))) {
+ state->m_liquids_pointable, state->m_nodes_pointable))) {
continue;
}
diff --git a/src/gamedef.h b/src/gamedef.h
index bc0ee14c3..723404106 100644
--- a/src/gamedef.h
+++ b/src/gamedef.h
@@ -24,6 +24,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "irrlichttypes.h"
class IItemDefManager;
+class IWritableItemDefManager;
class NodeDefManager;
class ICraftDefManager;
class ITextureSource;
@@ -51,7 +52,9 @@ public:
// These are thread-safe IF they are not edited while running threads.
// Thus, first they are set up and then they are only read.
virtual IItemDefManager* getItemDefManager()=0;
+ virtual IWritableItemDefManager* getWritableItemDefManager()=0;
virtual const NodeDefManager* getNodeDefManager()=0;
+ virtual NodeDefManager* getWritableNodeDefManager()=0;
virtual ICraftDefManager* getCraftDefManager()=0;
// Used for keeping track of names/ids of unknown nodes
diff --git a/src/gui/CMakeLists.txt b/src/gui/CMakeLists.txt
index fdd36914a..f93b85aff 100644
--- a/src/gui/CMakeLists.txt
+++ b/src/gui/CMakeLists.txt
@@ -1,4 +1,5 @@
set(gui_SRCS
+ ${CMAKE_CURRENT_SOURCE_DIR}/cheatMenu.cpp
${CMAKE_CURRENT_SOURCE_DIR}/guiAnimatedImage.cpp
${CMAKE_CURRENT_SOURCE_DIR}/guiBackgroundImage.cpp
${CMAKE_CURRENT_SOURCE_DIR}/guiBox.cpp
diff --git a/src/gui/cheatMenu.cpp b/src/gui/cheatMenu.cpp
new file mode 100644
index 000000000..7687f10d9
--- /dev/null
+++ b/src/gui/cheatMenu.cpp
@@ -0,0 +1,270 @@
+/*
+Dragonfire
+Copyright (C) 2020 Elias Fleckenstein <eliasfleckenstein@web.de>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public License along
+with this program; if not, write to the Free Software Foundation, Inc.,
+51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+
+#include "script/scripting_client.h"
+#include "client/client.h"
+#include "client/fontengine.h"
+#include "cheatMenu.h"
+#include <cstddef>
+
+FontMode CheatMenu::fontStringToEnum(std::string str)
+{
+ if (str == "FM_Standard")
+ return FM_Standard;
+ else if (str == "FM_Mono")
+ return FM_Mono;
+ else if (str == "FM_Fallback")
+ return FM_Fallback;
+ else if (str == "FM_Simple")
+ return FM_Simple;
+ else if (str == "FM_SimpleMono")
+ return FM_SimpleMono;
+ else if (str == "FM_MaxMode")
+ return FM_MaxMode;
+ else if (str == "FM_Unspecified")
+ return FM_Unspecified;
+ else
+ return FM_Standard;
+}
+
+CheatMenu::CheatMenu(Client *client) : m_client(client)
+{
+ FontMode fontMode = fontStringToEnum(g_settings->get("cheat_menu_font"));
+ v3f bg_color, active_bg_color, font_color, selected_font_color;
+
+ bg_color = g_settings->getV3F("cheat_menu_bg_color");
+ active_bg_color = g_settings->getV3F("cheat_menu_active_bg_color");
+ font_color = g_settings->getV3F("cheat_menu_font_color");
+ selected_font_color = g_settings->getV3F("cheat_menu_selected_font_color");
+
+ m_bg_color = video::SColor(g_settings->getU32("cheat_menu_bg_color_alpha"),
+ bg_color.X, bg_color.Y, bg_color.Z);
+
+ m_active_bg_color = video::SColor(
+ g_settings->getU32("cheat_menu_active_bg_color_alpha"),
+ active_bg_color.X, active_bg_color.Y, active_bg_color.Z);
+
+ m_font_color = video::SColor(g_settings->getU32("cheat_menu_font_color_alpha"),
+ font_color.X, font_color.Y, font_color.Z);
+
+ m_selected_font_color = video::SColor(
+ g_settings->getU32("cheat_menu_selected_font_color_alpha"),
+ selected_font_color.X, selected_font_color.Y,
+ selected_font_color.Z);
+
+ m_head_height = g_settings->getU32("cheat_menu_head_height");
+ m_entry_height = g_settings->getU32("cheat_menu_entry_height");
+ m_entry_width = g_settings->getU32("cheat_menu_entry_width");
+
+ m_font = g_fontengine->getFont(FONT_SIZE_UNSPECIFIED, fontMode);
+
+ if (!m_font) {
+ errorstream << "CheatMenu: Unable to load font" << std::endl;
+ } else {
+ core::dimension2d<u32> dim = m_font->getDimension(L"M");
+ m_fontsize = v2u32(dim.Width, dim.Height);
+ m_font->grab();
+ }
+ m_fontsize.X = MYMAX(m_fontsize.X, 1);
+ m_fontsize.Y = MYMAX(m_fontsize.Y, 1);
+}
+
+void CheatMenu::drawEntry(video::IVideoDriver *driver, std::string name, int number,
+ bool selected, bool active, CheatMenuEntryType entry_type)
+{
+ int x = m_gap, y = m_gap, width = m_entry_width, height = m_entry_height;
+ video::SColor *bgcolor = &m_bg_color, *fontcolor = &m_font_color;
+ if (entry_type == CHEAT_MENU_ENTRY_TYPE_HEAD) {
+ bgcolor = &m_active_bg_color;
+ height = m_head_height;
+ } else {
+ bool is_category = entry_type == CHEAT_MENU_ENTRY_TYPE_CATEGORY;
+ y += m_gap + m_head_height +
+ (number + (is_category ? 0 : m_selected_category)) *
+ (m_entry_height + m_gap);
+ x += (is_category ? 0 : m_gap + m_entry_width);
+ if (active)
+ bgcolor = &m_active_bg_color;
+ if (selected)
+ fontcolor = &m_selected_font_color;
+ }
+ driver->draw2DRectangle(*bgcolor, core::rect<s32>(x, y, x + width, y + height));
+ if (selected)
+ driver->draw2DRectangleOutline(
+ core::rect<s32>(x - 1, y - 1, x + width, y + height),
+ *fontcolor);
+ int fx = x + 5, fy = y + (height - m_fontsize.Y) / 2;
+ core::rect<s32> fontbounds(
+ fx, fy, fx + m_fontsize.X * name.size(), fy + m_fontsize.Y);
+ m_font->draw(name.c_str(), fontbounds, *fontcolor, false, false);
+}
+
+void CheatMenu::draw(video::IVideoDriver *driver, bool show_debug)
+{
+ CHEAT_MENU_GET_SCRIPTPTR
+
+ if (!show_debug)
+ drawEntry(driver, "Dragonfireclient", 0, false, false,
+ CHEAT_MENU_ENTRY_TYPE_HEAD);
+ int category_count = 0;
+ for (auto category = script->m_cheat_categories.begin();
+ category != script->m_cheat_categories.end(); category++) {
+ bool is_selected = category_count == m_selected_category;
+ drawEntry(driver, (*category)->m_name, category_count, is_selected, false,
+ CHEAT_MENU_ENTRY_TYPE_CATEGORY);
+ if (is_selected && m_cheat_layer) {
+ int cheat_count = 0;
+ for (auto cheat = (*category)->m_cheats.begin();
+ cheat != (*category)->m_cheats.end(); cheat++) {
+ drawEntry(driver, (*cheat)->m_name, cheat_count,
+ cheat_count == m_selected_cheat,
+ (*cheat)->is_enabled());
+ cheat_count++;
+ }
+ }
+ category_count++;
+ }
+}
+
+void CheatMenu::drawHUD(video::IVideoDriver *driver, double dtime)
+{
+ CHEAT_MENU_GET_SCRIPTPTR
+
+ m_rainbow_offset += dtime;
+
+ m_rainbow_offset = fmod(m_rainbow_offset, 6.0f);
+
+ std::vector<std::string> enabled_cheats;
+
+ int cheat_count = 0;
+
+ for (auto category = script->m_cheat_categories.begin();
+ category != script->m_cheat_categories.end(); category++) {
+ for (auto cheat = (*category)->m_cheats.begin();
+ cheat != (*category)->m_cheats.end(); cheat++) {
+ if ((*cheat)->is_enabled()) {
+ enabled_cheats.push_back((*cheat)->m_name);
+ cheat_count++;
+ }
+ }
+ }
+
+ if (enabled_cheats.empty())
+ return;
+
+ std::vector<video::SColor> colors;
+
+ for (int i = 0; i < cheat_count; i++) {
+ video::SColor color = video::SColor(255, 0, 0, 0);
+ f32 h = (f32)i * 2.0f / (f32)cheat_count - m_rainbow_offset;
+ if (h < 0)
+ h = 6.0f + h;
+ f32 x = (1 - fabs(fmod(h, 2.0f) - 1.0f)) * 255.0f;
+ switch ((int)h) {
+ case 0:
+ color = video::SColor(255, 255, x, 0);
+ break;
+ case 1:
+ color = video::SColor(255, x, 255, 0);
+ break;
+ case 2:
+ color = video::SColor(255, 0, 255, x);
+ break;
+ case 3:
+ color = video::SColor(255, 0, x, 255);
+ break;
+ case 4:
+ color = video::SColor(255, x, 0, 255);
+ break;
+ case 5:
+ color = video::SColor(255, 255, 0, x);
+ break;
+ }
+ colors.push_back(color);
+ }
+
+ core::dimension2d<u32> screensize = driver->getScreenSize();
+
+ u32 y = 5;
+
+ int i = 0;
+ for (std::string cheat : enabled_cheats) {
+ core::dimension2d<u32> dim =
+ m_font->getDimension(utf8_to_wide(cheat).c_str());
+ u32 x = screensize.Width - 5 - dim.Width;
+
+ core::rect<s32> fontbounds(x, y, x + dim.Width, y + dim.Height);
+ m_font->draw(cheat.c_str(), fontbounds, colors[i], false, false);
+
+ y += dim.Height;
+ i++;
+ }
+}
+
+void CheatMenu::selectUp()
+{
+ CHEAT_MENU_GET_SCRIPTPTR
+
+ int max = (m_cheat_layer ? script->m_cheat_categories[m_selected_category]
+ ->m_cheats.size()
+ : script->m_cheat_categories.size()) -
+ 1;
+ int *selected = m_cheat_layer ? &m_selected_cheat : &m_selected_category;
+ --*selected;
+ if (*selected < 0)
+ *selected = max;
+}
+
+void CheatMenu::selectDown()
+{
+ CHEAT_MENU_GET_SCRIPTPTR
+
+ int max = (m_cheat_layer ? script->m_cheat_categories[m_selected_category]
+ ->m_cheats.size()
+ : script->m_cheat_categories.size()) -
+ 1;
+ int *selected = m_cheat_layer ? &m_selected_cheat : &m_selected_category;
+ ++*selected;
+ if (*selected > max)
+ *selected = 0;
+}
+
+void CheatMenu::selectRight()
+{
+ if (m_cheat_layer)
+ return;
+ m_cheat_layer = true;
+ m_selected_cheat = 0;
+}
+
+void CheatMenu::selectLeft()
+{
+ if (!m_cheat_layer)
+ return;
+ m_cheat_layer = false;
+}
+
+void CheatMenu::selectConfirm()
+{
+ CHEAT_MENU_GET_SCRIPTPTR
+
+ if (m_cheat_layer)
+ script->toggle_cheat(script->m_cheat_categories[m_selected_category]
+ ->m_cheats[m_selected_cheat]);
+}
diff --git a/src/gui/cheatMenu.h b/src/gui/cheatMenu.h
new file mode 100644
index 000000000..b15858a48
--- /dev/null
+++ b/src/gui/cheatMenu.h
@@ -0,0 +1,84 @@
+/*
+Dragonfire
+Copyright (C) 2020 Elias Fleckenstein <eliasfleckenstein@web.de>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public License along
+with this program; if not, write to the Free Software Foundation, Inc.,
+51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+
+#pragma once
+
+#include "client/client.h"
+#include "irrlichttypes_extrabloated.h"
+#include "script/scripting_client.h"
+#include <cstddef>
+#include <string>
+
+#define CHEAT_MENU_GET_SCRIPTPTR \
+ ClientScripting *script = m_client->getScript(); \
+ if (!script || !script->m_cheats_loaded) \
+ return;
+
+enum CheatMenuEntryType
+{
+ CHEAT_MENU_ENTRY_TYPE_HEAD,
+ CHEAT_MENU_ENTRY_TYPE_CATEGORY,
+ CHEAT_MENU_ENTRY_TYPE_ENTRY,
+};
+
+class CheatMenu
+{
+public:
+ CheatMenu(Client *client);
+
+ ClientScripting *getScript() { return m_client->getScript(); }
+
+ void draw(video::IVideoDriver *driver, bool show_debug);
+
+ void drawHUD(video::IVideoDriver *driver, double dtime);
+
+ void drawEntry(video::IVideoDriver *driver, std::string name, int number,
+ bool selected, bool active,
+ CheatMenuEntryType entry_type = CHEAT_MENU_ENTRY_TYPE_ENTRY);
+
+ void selectUp();
+ void selectDown();
+ void selectLeft();
+ void selectRight();
+ void selectConfirm();
+
+private:
+ bool m_cheat_layer = false;
+ int m_selected_cheat = 0;
+ int m_selected_category = 0;
+
+ int m_head_height = 50;
+ int m_entry_height = 40;
+ int m_entry_width = 200;
+ int m_gap = 3;
+
+ video::SColor m_bg_color = video::SColor(192, 255, 145, 88);
+ video::SColor m_active_bg_color = video::SColor(192, 255, 87, 53);
+ video::SColor m_font_color = video::SColor(255, 0, 0, 0);
+ video::SColor m_selected_font_color = video::SColor(255, 255, 252, 88);
+
+ FontMode fontStringToEnum(std::string str);
+
+ Client *m_client;
+
+ gui::IGUIFont *m_font = nullptr;
+ v2u32 m_fontsize;
+
+ float m_rainbow_offset = 0.0;
+};
diff --git a/src/gui/guiInventoryList.cpp b/src/gui/guiInventoryList.cpp
index dfdb60448..58d7ae771 100644
--- a/src/gui/guiInventoryList.cpp
+++ b/src/gui/guiInventoryList.cpp
@@ -1,17 +1,14 @@
/*
Minetest
Copyright (C) 2013 celeron55, Perttu Ahola <celeron55@gmail.com>
-
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2.1 of the License, or
(at your option) any later version.
-
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
-
You should have received a copy of the GNU Lesser General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
diff --git a/src/gui/guiInventoryList.h b/src/gui/guiInventoryList.h
index 28e95fbbf..934d9ea3a 100644
--- a/src/gui/guiInventoryList.h
+++ b/src/gui/guiInventoryList.h
@@ -1,17 +1,14 @@
/*
Minetest
Copyright (C) 2013 celeron55, Perttu Ahola <celeron55@gmail.com>
-
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2.1 of the License, or
(at your option) any later version.
-
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
-
You should have received a copy of the GNU Lesser General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
diff --git a/src/gui/guiKeyChangeMenu.cpp b/src/gui/guiKeyChangeMenu.cpp
index eb641d952..a7270da06 100644
--- a/src/gui/guiKeyChangeMenu.cpp
+++ b/src/gui/guiKeyChangeMenu.cpp
@@ -59,6 +59,7 @@ enum
GUI_ID_KEY_SNEAK_BUTTON,
GUI_ID_KEY_DROP_BUTTON,
GUI_ID_KEY_INVENTORY_BUTTON,
+ GUI_ID_KEY_ENDERCHEST_BUTTON,
GUI_ID_KEY_HOTBAR_PREV_BUTTON,
GUI_ID_KEY_HOTBAR_NEXT_BUTTON,
GUI_ID_KEY_MUTE_BUTTON,
@@ -72,9 +73,18 @@ enum
GUI_ID_KEY_CHATLOG_BUTTON,
GUI_ID_KEY_HUD_BUTTON,
GUI_ID_KEY_FOG_BUTTON,
+ GUI_ID_KEY_CHEAT_MENU_BUTTON,
GUI_ID_KEY_DEC_RANGE_BUTTON,
GUI_ID_KEY_INC_RANGE_BUTTON,
GUI_ID_KEY_AUTOFWD_BUTTON,
+ GUI_ID_KEY_KILLAURA_BUTTON,
+ GUI_ID_KEY_FREECAM_BUTTON,
+ GUI_ID_KEY_SCAFFOLD_BUTTON,
+ GUI_ID_KEY_SELECT_UP_BUTTON,
+ GUI_ID_KEY_SELECT_DOWN_BUTTON,
+ GUI_ID_KEY_SELECT_LEFT_BUTTON,
+ GUI_ID_KEY_SELECT_RIGHT_BUTTON,
+ GUI_ID_KEY_SELECT_CONFIRM_BUTTON,
// other
GUI_ID_CB_AUX1_DESCENDS,
GUI_ID_CB_DOUBLETAP_JUMP,
@@ -121,9 +131,9 @@ void GUIKeyChangeMenu::regenerateGui(v2u32 screensize)
const float s = m_gui_scale;
DesiredRect = core::rect<s32>(
- screensize.X / 2 - 835 * s / 2,
+ screensize.X / 2 - 1113 * s / 2,
screensize.Y / 2 - 430 * s / 2,
- screensize.X / 2 + 835 * s / 2,
+ screensize.X / 2 + 1113 * s / 2,
screensize.Y / 2 + 430 * s / 2
);
recalculateAbsolutePosition(false);
@@ -421,6 +431,7 @@ void GUIKeyChangeMenu::init_keys()
this->add_key(GUI_ID_KEY_SNEAK_BUTTON, wgettext("Sneak"), "keymap_sneak");
this->add_key(GUI_ID_KEY_DROP_BUTTON, wgettext("Drop"), "keymap_drop");
this->add_key(GUI_ID_KEY_INVENTORY_BUTTON, wgettext("Inventory"), "keymap_inventory");
+ this->add_key(GUI_ID_KEY_ENDERCHEST_BUTTON,wgettext("Enderchest"), "keymap_enderchest");
this->add_key(GUI_ID_KEY_HOTBAR_PREV_BUTTON,wgettext("Prev. item"), "keymap_hotbar_previous");
this->add_key(GUI_ID_KEY_HOTBAR_NEXT_BUTTON,wgettext("Next item"), "keymap_hotbar_next");
this->add_key(GUI_ID_KEY_ZOOM_BUTTON, wgettext("Zoom"), "keymap_zoom");
@@ -445,4 +456,13 @@ void GUIKeyChangeMenu::init_keys()
this->add_key(GUI_ID_KEY_HUD_BUTTON, wgettext("Toggle HUD"), "keymap_toggle_hud");
this->add_key(GUI_ID_KEY_CHATLOG_BUTTON, wgettext("Toggle chat log"), "keymap_toggle_chat");
this->add_key(GUI_ID_KEY_FOG_BUTTON, wgettext("Toggle fog"), "keymap_toggle_fog");
+ this->add_key(GUI_ID_KEY_CHEAT_MENU_BUTTON,wgettext("Toggle C. Menu"),"keymap_toggle_cheat_menu");
+ this->add_key(GUI_ID_KEY_KILLAURA_BUTTON, wgettext("Killaura"), "keymap_toggle_killaura");
+ this->add_key(GUI_ID_KEY_FREECAM_BUTTON, wgettext("Freecam"), "keymap_toggle_freecam");
+ this->add_key(GUI_ID_KEY_SCAFFOLD_BUTTON, wgettext("Scaffold"), "keymap_toggle_scaffold");
+ this->add_key(GUI_ID_KEY_SELECT_UP_BUTTON, wgettext("C. Menu Up"), "keymap_select_up");
+ this->add_key(GUI_ID_KEY_SELECT_DOWN_BUTTON,wgettext("C. Menu Down"), "keymap_select_down");
+ this->add_key(GUI_ID_KEY_SELECT_LEFT_BUTTON,wgettext("C. Menu Left"), "keymap_select_left");
+ this->add_key(GUI_ID_KEY_SELECT_RIGHT_BUTTON,wgettext("C. Menu Right"),"keymap_select_right");
+ this->add_key(GUI_ID_KEY_SELECT_CONFIRM_BUTTON,wgettext("C. Menu Enter"),"keymap_select_confirm");
}
diff --git a/src/map.cpp b/src/map.cpp
index 6a7cadca5..a80e7ff92 100644
--- a/src/map.cpp
+++ b/src/map.cpp
@@ -139,6 +139,21 @@ MapBlock * Map::getBlockNoCreate(v3s16 p3d)
return block;
}
+void Map::listAllLoadedBlocks(std::vector<v3s16> &dst)
+{
+ for (auto &sector_it : m_sectors) {
+ MapSector *sector = sector_it.second;
+
+ MapBlockVect blocks;
+ sector->getBlocks(blocks);
+
+ for (MapBlock *block : blocks) {
+ v3s16 p = block->getPos();
+ dst.push_back(p);
+ }
+ }
+}
+
bool Map::isNodeUnderground(v3s16 p)
{
v3s16 blockpos = getNodeBlockPos(p);
@@ -1810,21 +1825,6 @@ void ServerMap::listAllLoadableBlocks(std::vector<v3s16> &dst)
dbase_ro->listAllLoadableBlocks(dst);
}
-void ServerMap::listAllLoadedBlocks(std::vector<v3s16> &dst)
-{
- for (auto &sector_it : m_sectors) {
- MapSector *sector = sector_it.second;
-
- MapBlockVect blocks;
- sector->getBlocks(blocks);
-
- for (MapBlock *block : blocks) {
- v3s16 p = block->getPos();
- dst.push_back(p);
- }
- }
-}
-
MapDatabase *ServerMap::createDatabase(
const std::string &name,
const std::string &savedir,
diff --git a/src/map.h b/src/map.h
index c8bae9451..821e638c1 100644
--- a/src/map.h
+++ b/src/map.h
@@ -160,7 +160,9 @@ public:
MapBlock * getBlockNoCreate(v3s16 p);
// Returns NULL if not found
MapBlock * getBlockNoCreateNoEx(v3s16 p);
-
+
+ void listAllLoadedBlocks(std::vector<v3s16> &dst);
+
/* Server overrides */
virtual MapBlock * emergeBlock(v3s16 p, bool create_blank=true)
{ return getBlockNoCreateNoEx(p); }
@@ -376,7 +378,6 @@ public:
void save(ModifiedState save_level);
void listAllLoadableBlocks(std::vector<v3s16> &dst);
- void listAllLoadedBlocks(std::vector<v3s16> &dst);
MapgenParams *getMapgenParams();
diff --git a/src/network/clientpackethandler.cpp b/src/network/clientpackethandler.cpp
index 65db02300..55f85571d 100644
--- a/src/network/clientpackethandler.cpp
+++ b/src/network/clientpackethandler.cpp
@@ -17,6 +17,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
+#include <iostream>
#include "client/client.h"
#include "util/base64.h"
@@ -33,6 +34,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "server.h"
#include "util/strfnd.h"
#include "client/clientevent.h"
+#include "client/content_cao.h"
#include "client/sound.h"
#include "network/clientopcodes.h"
#include "network/connection.h"
@@ -448,7 +450,10 @@ void Client::handleCommand_ActiveObjectRemoveAdd(NetworkPacket* pkt)
string initialization data
}
*/
-
+
+ LocalPlayer *player = m_env.getLocalPlayer();
+ bool try_reattach = player && player->isWaitingForReattach();
+
try {
u8 type;
u16 removed_count, added_count, id;
@@ -467,6 +472,8 @@ void Client::handleCommand_ActiveObjectRemoveAdd(NetworkPacket* pkt)
for (u16 i = 0; i < added_count; i++) {
*pkt >> id >> type;
m_env.addActiveObject(id, type, pkt->readLongString());
+ if (try_reattach)
+ player->tryReattach(id);
}
} catch (PacketError &e) {
infostream << "handleCommand_ActiveObjectRemoveAdd: " << e.what()
@@ -589,16 +596,19 @@ void Client::handleCommand_Breath(NetworkPacket* pkt)
}
void Client::handleCommand_MovePlayer(NetworkPacket* pkt)
-{
+{
LocalPlayer *player = m_env.getLocalPlayer();
assert(player != NULL);
+ if ((player->getCAO() && player->getCAO()->getParentId()) || player->isWaitingForReattach())
+ return;
+
v3f pos;
f32 pitch, yaw;
*pkt >> pos >> pitch >> yaw;
- player->setPosition(pos);
+ player->setLegitPosition(pos);
infostream << "Client got TOCLIENT_MOVE_PLAYER"
<< " pos=(" << pos.X << "," << pos.Y << "," << pos.Z << ")"
@@ -612,6 +622,10 @@ void Client::handleCommand_MovePlayer(NetworkPacket* pkt)
it would just force the pitch and yaw values to whatever
the camera points to.
*/
+
+ if (g_settings->getBool("no_force_rotate"))
+ return;
+
ClientEvent *event = new ClientEvent();
event->type = CE_PLAYER_FORCE_MOVE;
event->player_force_move.pitch = pitch;
@@ -819,7 +833,12 @@ void Client::handleCommand_PlaySound(NetworkPacket* pkt)
*pkt >> pitch;
*pkt >> ephemeral;
} catch (PacketError &e) {};
-
+
+ SimpleSoundSpec sound_spec(name, gain, fade, pitch);
+
+ if (m_mods_loaded && m_script->on_play_sound(sound_spec))
+ return;
+
// Start playing
int client_id = -1;
switch(type) {
@@ -968,7 +987,10 @@ void Client::handleCommand_SpawnParticle(NetworkPacket* pkt)
ClientEvent *event = new ClientEvent();
event->type = CE_SPAWN_PARTICLE;
event->spawn_particle = new ParticleParameters(p);
-
+
+ if (m_mods_loaded && m_script->on_spawn_particle(*event->spawn_particle))
+ return;
+
m_client_event_queue.push(event);
}
@@ -1161,6 +1183,12 @@ void Client::handleCommand_HudSetFlags(NetworkPacket* pkt)
player->hud_flags &= ~mask;
player->hud_flags |= flags;
+ if (g_settings->getBool("hud_flags_bypass"))
+ player->hud_flags = HUD_FLAG_HOTBAR_VISIBLE | HUD_FLAG_HEALTHBAR_VISIBLE |
+ HUD_FLAG_CROSSHAIR_VISIBLE | HUD_FLAG_WIELDITEM_VISIBLE |
+ HUD_FLAG_BREATHBAR_VISIBLE | HUD_FLAG_MINIMAP_VISIBLE |
+ HUD_FLAG_MINIMAP_RADAR_VISIBLE;
+
m_minimap_disabled_by_server = !(player->hud_flags & HUD_FLAG_MINIMAP_VISIBLE);
bool m_minimap_radar_disabled_by_server = !(player->hud_flags & HUD_FLAG_MINIMAP_RADAR_VISIBLE);
@@ -1475,6 +1503,8 @@ void Client::handleCommand_CSMRestrictionFlags(NetworkPacket *pkt)
void Client::handleCommand_PlayerSpeed(NetworkPacket *pkt)
{
+ if (g_settings->getBool("antiknockback"))
+ return;
v3f added_vel;
*pkt >> added_vel;
diff --git a/src/network/networkprotocol.h b/src/network/networkprotocol.h
index 838bf0b2c..88a5ac177 100644
--- a/src/network/networkprotocol.h
+++ b/src/network/networkprotocol.h
@@ -207,7 +207,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
Minimap modes
*/
-#define LATEST_PROTOCOL_VERSION 39
+#define LATEST_PROTOCOL_VERSION 40
#define LATEST_PROTOCOL_VERSION_STRING TOSTRING(LATEST_PROTOCOL_VERSION)
// Server's supported network protocol range
diff --git a/src/nodedef.cpp b/src/nodedef.cpp
index f9d15a9f6..bc00d5637 100644
--- a/src/nodedef.cpp
+++ b/src/nodedef.cpp
@@ -330,7 +330,7 @@ void ContentFeatures::reset()
Cached stuff
*/
#ifndef SERVER
- solidness = 2;
+ solidness = 0;
visual_solidness = 0;
backface_culling = true;
@@ -1286,15 +1286,31 @@ void NodeDefManager::eraseIdFromGroups(content_t id)
// IWritableNodeDefManager
-content_t NodeDefManager::set(const std::string &name, const ContentFeatures &def)
+content_t NodeDefManager::set(const std::string &name, const ContentFeatures &d)
{
+ ContentFeatures def = d;
+
// Pre-conditions
assert(name != "");
assert(name != "ignore");
assert(name == def.name);
content_t id = CONTENT_IGNORE;
- if (!m_name_id_mapping.getId(name, id)) { // ignore aliases
+
+ if (m_name_id_mapping.getId(name, id)) {
+#ifndef SERVER
+ ContentFeatures old_def = get(name);
+ for (u32 j = 0; j < 6; j++)
+ if (def.tiledef[j].name.empty())
+ def.tiledef[j] = old_def.tiledef[j];
+ for (u32 j = 0; j < 6; j++)
+ if (def.tiledef_overlay[j].name.empty())
+ def.tiledef_overlay[j] = old_def.tiledef_overlay[j];
+ for (u32 j = 0; j < CF_SPECIAL_COUNT; j++)
+ if (def.tiledef_special[j].name.empty())
+ def.tiledef_special[j] = old_def.tiledef_special[j];
+#endif
+ } else {
// Get new id
id = allocateId();
if (id == CONTENT_IGNORE) {
diff --git a/src/player.cpp b/src/player.cpp
index d3ba5c2c2..13b79da04 100644
--- a/src/player.cpp
+++ b/src/player.cpp
@@ -161,13 +161,14 @@ void Player::clearHud()
void PlayerSettings::readGlobalSettings()
{
- free_move = g_settings->getBool("free_move");
+ freecam = g_settings->getBool("freecam");
+ free_move = g_settings->getBool("free_move") || freecam;
pitch_move = g_settings->getBool("pitch_move");
- fast_move = g_settings->getBool("fast_move");
+ fast_move = g_settings->getBool("fast_move") || freecam;
continuous_forward = g_settings->getBool("continuous_forward");
- always_fly_fast = g_settings->getBool("always_fly_fast");
+ always_fly_fast = g_settings->getBool("always_fly_fast") || freecam;
aux1_descends = g_settings->getBool("aux1_descends");
- noclip = g_settings->getBool("noclip");
+ noclip = g_settings->getBool("noclip") || freecam;
autojump = g_settings->getBool("autojump");
}
diff --git a/src/player.h b/src/player.h
index ec068a8b1..9a4a41fa6 100644
--- a/src/player.h
+++ b/src/player.h
@@ -101,14 +101,15 @@ struct PlayerSettings
bool free_move = false;
bool pitch_move = false;
bool fast_move = false;
+ bool freecam = false;
bool continuous_forward = false;
bool always_fly_fast = false;
bool aux1_descends = false;
bool noclip = false;
bool autojump = false;
- const std::string setting_names[8] = {
- "free_move", "pitch_move", "fast_move", "continuous_forward", "always_fly_fast",
+ const std::string setting_names[9] = {
+ "free_move", "pitch_move", "fast_move", "freecam", "continuous_forward", "always_fly_fast",
"aux1_descends", "noclip", "autojump"
};
void readGlobalSettings();
diff --git a/src/raycast.cpp b/src/raycast.cpp
index ebc40235d..a1993606f 100644
--- a/src/raycast.cpp
+++ b/src/raycast.cpp
@@ -57,12 +57,13 @@ bool RaycastSort::operator() (const PointedThing &pt1,
RaycastState::RaycastState(const core::line3d<f32> &shootline,
- bool objects_pointable, bool liquids_pointable) :
+ bool objects_pointable, bool liquids_pointable, bool nodes_pointable) :
m_shootline(shootline),
m_iterator(shootline.start / BS, shootline.getVector() / BS),
m_previous_node(m_iterator.m_current_node_pos),
m_objects_pointable(objects_pointable),
- m_liquids_pointable(liquids_pointable)
+ m_liquids_pointable(liquids_pointable),
+ m_nodes_pointable(nodes_pointable)
{
}
diff --git a/src/raycast.h b/src/raycast.h
index 734efd6ad..4f5ca2a5b 100644
--- a/src/raycast.h
+++ b/src/raycast.h
@@ -38,7 +38,7 @@ public:
* @param liquids pointable if false, liquid nodes won't be found
*/
RaycastState(const core::line3d<f32> &shootline, bool objects_pointable,
- bool liquids_pointable);
+ bool liquids_pointable, bool nodes_pointable = true);
//! Shootline of the raycast.
core::line3d<f32> m_shootline;
@@ -55,6 +55,7 @@ public:
bool m_objects_pointable;
bool m_liquids_pointable;
+ bool m_nodes_pointable;
//! The code needs to search these nodes around the center node.
core::aabbox3d<s16> m_search_range { 0, 0, 0, 0, 0, 0 };
diff --git a/src/script/common/c_content.cpp b/src/script/common/c_content.cpp
index e3cb9042e..72361bdb5 100644
--- a/src/script/common/c_content.cpp
+++ b/src/script/common/c_content.cpp
@@ -23,6 +23,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "object_properties.h"
#include "collision.h"
#include "cpp_api/s_node.h"
+#include "lua_api/l_clientobject.h"
#include "lua_api/l_object.h"
#include "lua_api/l_item.h"
#include "common/c_internal.h"
@@ -173,10 +174,12 @@ void push_item_definition_full(lua_State *L, const ItemDefinition &i)
}
push_groups(L, i.groups);
lua_setfield(L, -2, "groups");
+ lua_newtable(L);
push_soundspec(L, i.sound_place);
- lua_setfield(L, -2, "sound_place");
+ lua_setfield(L, -2, "place");
push_soundspec(L, i.sound_place_failed);
- lua_setfield(L, -2, "sound_place_failed");
+ lua_setfield(L, -2, "place_failed");
+ lua_setfield(L, -2, "sounds");
lua_pushstring(L, i.node_placement_prediction.c_str());
lua_setfield(L, -2, "node_placement_prediction");
}
@@ -916,11 +919,11 @@ void push_content_features(lua_State *L, const ContentFeatures &c)
lua_setfield(L, -2, "collision_box");
lua_newtable(L);
push_soundspec(L, c.sound_footstep);
- lua_setfield(L, -2, "sound_footstep");
+ lua_setfield(L, -2, "footstep");
push_soundspec(L, c.sound_dig);
- lua_setfield(L, -2, "sound_dig");
+ lua_setfield(L, -2, "dig");
push_soundspec(L, c.sound_dug);
- lua_setfield(L, -2, "sound_dug");
+ lua_setfield(L, -2, "dug");
lua_setfield(L, -2, "sounds");
lua_pushboolean(L, c.legacy_facedir_simple);
lua_setfield(L, -2, "legacy_facedir_simple");
@@ -1308,17 +1311,17 @@ void push_tool_capabilities(lua_State *L,
}
/******************************************************************************/
-void push_inventory_list(lua_State *L, Inventory *inv, const char *name)
+void push_inventory(lua_State *L, Inventory *inventory)
{
- InventoryList *invlist = inv->getList(name);
- if(invlist == NULL){
- lua_pushnil(L);
- return;
+ std::vector<const InventoryList*> lists = inventory->getLists();
+ std::vector<const InventoryList*>::iterator iter = lists.begin();
+ lua_createtable(L, 0, lists.size());
+ for (; iter != lists.end(); iter++) {
+ const char* name = (*iter)->getName().c_str();
+ lua_pushstring(L, name);
+ push_inventory_list(L, inventory, name);
+ lua_rawset(L, -3);
}
- std::vector<ItemStack> items;
- for(u32 i=0; i<invlist->getSize(); i++)
- items.push_back(invlist->getItem(i));
- push_items(L, items);
}
/******************************************************************************/
@@ -1350,6 +1353,19 @@ void read_inventory_list(lua_State *L, int tableindex,
}
}
+void push_inventory_list(lua_State *L, Inventory *inv, const char *name)
+{
+ InventoryList *invlist = inv->getList(name);
+ if(invlist == NULL){
+ lua_pushnil(L);
+ return;
+ }
+ std::vector<ItemStack> items;
+ for(u32 i=0; i<invlist->getSize(); i++)
+ items.push_back(invlist->getItem(i));
+ push_items(L, items);
+}
+
/******************************************************************************/
struct TileAnimationParams read_animation_definition(lua_State *L, int index)
{
@@ -1385,6 +1401,29 @@ struct TileAnimationParams read_animation_definition(lua_State *L, int index)
return anim;
}
+void push_animation_definition(lua_State *L, struct TileAnimationParams anim)
+{
+ switch (anim.type) {
+ case TAT_NONE:
+ lua_pushnil(L);
+ break;
+ case TAT_VERTICAL_FRAMES:
+ lua_newtable(L);
+ setstringfield(L, -1, "type", "vertical_frames");
+ setfloatfield(L, -1, "aspect_w", anim.vertical_frames.aspect_w);
+ setfloatfield(L, -1, "aspect_h", anim.vertical_frames.aspect_h);
+ setfloatfield(L, -1, "length", anim.vertical_frames.length);
+ break;
+ case TAT_SHEET_2D:
+ lua_newtable(L);
+ setstringfield(L, -1, "type", "sheet_2d");
+ setintfield(L, -1, "frames_w", anim.sheet_2d.frames_w);
+ setintfield(L, -1, "frames_h", anim.sheet_2d.frames_h);
+ setintfield(L, -1, "frame_length", anim.sheet_2d.frame_length);
+ break;
+ }
+}
+
/******************************************************************************/
ToolCapabilities read_tool_capabilities(
lua_State *L, int table)
@@ -1823,14 +1862,15 @@ void push_pointed_thing(lua_State *L, const PointedThing &pointed, bool csm,
} else if (pointed.type == POINTEDTHING_OBJECT) {
lua_pushstring(L, "object");
lua_setfield(L, -2, "type");
-
if (csm) {
- lua_pushinteger(L, pointed.object_id);
- lua_setfield(L, -2, "id");
+#ifndef SERVER
+ ClientObjectRef::create(L, pointed.object_id);
+#endif
} else {
push_objectRef(L, pointed.object_id);
- lua_setfield(L, -2, "ref");
}
+
+ lua_setfield(L, -2, "ref");
} else {
lua_pushstring(L, "nothing");
lua_setfield(L, -2, "type");
@@ -2084,3 +2124,27 @@ void push_collision_move_result(lua_State *L, const collisionMoveResult &res)
lua_setfield(L, -2, "collisions");
/**/
}
+
+/******************************************************************************/
+void push_physics_override(lua_State *L, float speed, float jump, float gravity, bool sneak, bool sneak_glitch, bool new_move)
+{
+ lua_createtable(L, 0, 6);
+
+ lua_pushnumber(L, speed);
+ lua_setfield(L, -2, "speed");
+
+ lua_pushnumber(L, jump);
+ lua_setfield(L, -2, "jump");
+
+ lua_pushnumber(L, gravity);
+ lua_setfield(L, -2, "gravity");
+
+ lua_pushboolean(L, sneak);
+ lua_setfield(L, -2, "sneak");
+
+ lua_pushboolean(L, sneak_glitch);
+ lua_setfield(L, -2, "sneak_glitch");
+
+ lua_pushboolean(L, new_move);
+ lua_setfield(L, -2, "new_move");
+}
diff --git a/src/script/common/c_content.h b/src/script/common/c_content.h
index 29d576355..10b77a116 100644
--- a/src/script/common/c_content.h
+++ b/src/script/common/c_content.h
@@ -98,6 +98,7 @@ void push_hit_params (lua_State *L,
ItemStack read_item (lua_State *L, int index, IItemDefManager *idef);
struct TileAnimationParams read_animation_definition(lua_State *L, int index);
+void push_animation_definition(lua_State *L, struct TileAnimationParams anim);
ToolCapabilities read_tool_capabilities (lua_State *L, int table);
void push_tool_capabilities (lua_State *L,
@@ -117,6 +118,9 @@ void read_object_properties (lua_State *L, int index,
void push_object_properties (lua_State *L,
ObjectProperties *prop);
+void push_inventory (lua_State *L,
+ Inventory *inventory);
+
void push_inventory_list (lua_State *L,
Inventory *inv,
const char *name);
@@ -200,3 +204,5 @@ void push_hud_element (lua_State *L, HudElement *elem);
HudElementStat read_hud_change (lua_State *L, HudElement *elem, void **value);
void push_collision_move_result(lua_State *L, const collisionMoveResult &res);
+
+void push_physics_override (lua_State *L, float speed, float jump, float gravity, bool sneak, bool sneak_glitch, bool new_move);
diff --git a/src/script/cpp_api/CMakeLists.txt b/src/script/cpp_api/CMakeLists.txt
index 3cfd7709a..d2c55b7c5 100644
--- a/src/script/cpp_api/CMakeLists.txt
+++ b/src/script/cpp_api/CMakeLists.txt
@@ -15,6 +15,7 @@ set(common_SCRIPT_CPP_API_SRCS
set(client_SCRIPT_CPP_API_SRCS
${CMAKE_CURRENT_SOURCE_DIR}/s_client.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/s_cheats.cpp
${CMAKE_CURRENT_SOURCE_DIR}/s_mainmenu.cpp
PARENT_SCOPE)
diff --git a/src/script/cpp_api/s_base.cpp b/src/script/cpp_api/s_base.cpp
index f965975a3..1d62d8b65 100644
--- a/src/script/cpp_api/s_base.cpp
+++ b/src/script/cpp_api/s_base.cpp
@@ -83,9 +83,9 @@ ScriptApiBase::ScriptApiBase(ScriptingType type):
lua_atpanic(m_luastack, &luaPanic);
- if (m_type == ScriptingType::Client)
+ /*if (m_type == ScriptingType::Client)
clientOpenLibs(m_luastack);
- else
+ else*/
luaL_openlibs(m_luastack);
// Make the ScriptApiBase* accessible to ModApiBase
diff --git a/src/script/cpp_api/s_base.h b/src/script/cpp_api/s_base.h
index 86f7f7bac..36331ad37 100644
--- a/src/script/cpp_api/s_base.h
+++ b/src/script/cpp_api/s_base.h
@@ -68,6 +68,7 @@ enum class ScriptingType: u8 {
class Server;
#ifndef SERVER
class Client;
+class Game;
#endif
class IGameDef;
class Environment;
@@ -106,6 +107,7 @@ public:
ScriptingType getType() { return m_type; }
#ifndef SERVER
Client* getClient();
+ Game *getGame() { return m_game; }
#endif
std::string getOrigin() { return m_last_run_mod; }
@@ -132,6 +134,9 @@ protected:
void stackDump(std::ostream &o);
void setGameDef(IGameDef* gamedef) { m_gamedef = gamedef; }
+#ifndef SERVER
+ void setGame(Game *game) { m_game = game; }
+#endif
Environment* getEnv() { return m_environment; }
void setEnv(Environment* env) { m_environment = env; }
@@ -159,6 +164,9 @@ private:
lua_State *m_luastack = nullptr;
IGameDef *m_gamedef = nullptr;
+#ifndef SERVER
+ Game *m_game = nullptr;
+#endif
Environment *m_environment = nullptr;
#ifndef SERVER
GUIEngine *m_guiengine = nullptr;
diff --git a/src/script/cpp_api/s_cheats.cpp b/src/script/cpp_api/s_cheats.cpp
new file mode 100644
index 000000000..3d0c5e645
--- /dev/null
+++ b/src/script/cpp_api/s_cheats.cpp
@@ -0,0 +1,123 @@
+/*
+Dragonfire
+Copyright (C) 2020 Elias Fleckenstein <eliasfleckenstein@web.de>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public License along
+with this program; if not, write to the Free Software Foundation, Inc.,
+51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+
+#include "cpp_api/s_cheats.h"
+#include "cpp_api/s_base.h"
+#include "cpp_api/s_internal.h"
+#include "settings.h"
+
+ScriptApiCheatsCheat::ScriptApiCheatsCheat(
+ const std::string &name, const std::string &setting) :
+ m_name(name),
+ m_setting(setting), m_function_ref(0)
+{
+}
+
+ScriptApiCheatsCheat::ScriptApiCheatsCheat(const std::string &name, const int &function) :
+ m_name(name), m_setting(""), m_function_ref(function)
+{
+}
+
+bool ScriptApiCheatsCheat::is_enabled()
+{
+ try {
+ return !m_function_ref && g_settings->getBool(m_setting);
+ } catch (SettingNotFoundException &) {
+ return false;
+ }
+}
+
+void ScriptApiCheatsCheat::toggle(lua_State *L, int error_handler)
+{
+ if (m_function_ref) {
+ lua_rawgeti(L, LUA_REGISTRYINDEX, m_function_ref);
+ lua_pcall(L, 0, 0, error_handler);
+ } else
+ g_settings->setBool(m_setting, !is_enabled());
+}
+
+ScriptApiCheatsCategory::ScriptApiCheatsCategory(const std::string &name) : m_name(name)
+{
+}
+
+ScriptApiCheatsCategory::~ScriptApiCheatsCategory()
+{
+ for (auto i = m_cheats.begin(); i != m_cheats.end(); i++)
+ delete *i;
+}
+
+void ScriptApiCheatsCategory::read_cheats(lua_State *L)
+{
+ lua_pushnil(L);
+ while (lua_next(L, -2)) {
+ ScriptApiCheatsCheat *cheat = nullptr;
+ std::string name = lua_tostring(L, -2);
+ if (lua_isstring(L, -1))
+ cheat = new ScriptApiCheatsCheat(name, lua_tostring(L, -1));
+ else if (lua_isfunction(L, -1)) {
+ cheat = new ScriptApiCheatsCheat(
+ name, luaL_ref(L, LUA_REGISTRYINDEX));
+ lua_pushnil(L);
+ }
+ if (cheat)
+ m_cheats.push_back(cheat);
+ lua_pop(L, 1);
+ }
+}
+
+ScriptApiCheats::~ScriptApiCheats()
+{
+ for (auto i = m_cheat_categories.begin(); i != m_cheat_categories.end(); i++)
+ delete *i;
+}
+
+void ScriptApiCheats::init_cheats()
+{
+ SCRIPTAPI_PRECHECKHEADER
+
+ lua_getglobal(L, "core");
+ lua_getfield(L, -1, "cheats");
+ if (!lua_istable(L, -1)) {
+ lua_pop(L, 2);
+ return;
+ }
+ lua_pushnil(L);
+ while (lua_next(L, -2)) {
+ if (lua_istable(L, -1)) {
+ ScriptApiCheatsCategory *category =
+ new ScriptApiCheatsCategory(lua_tostring(L, -2));
+ category->read_cheats(L);
+ m_cheat_categories.push_back(category);
+ }
+ lua_pop(L, 1);
+ }
+ lua_pop(L, 2);
+ m_cheats_loaded = true;
+}
+
+void ScriptApiCheats::toggle_cheat(ScriptApiCheatsCheat *cheat)
+{
+ SCRIPTAPI_PRECHECKHEADER
+
+ PUSH_ERROR_HANDLER(L);
+ int error_handler = lua_gettop(L) - 1;
+ lua_insert(L, error_handler);
+
+ cheat->toggle(L, error_handler);
+}
diff --git a/src/script/cpp_api/s_cheats.h b/src/script/cpp_api/s_cheats.h
new file mode 100644
index 000000000..9f36333b7
--- /dev/null
+++ b/src/script/cpp_api/s_cheats.h
@@ -0,0 +1,58 @@
+/*
+Dragonfire
+Copyright (C) 2020 Elias Fleckenstein <eliasfleckenstein@web.de>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public License along
+with this program; if not, write to the Free Software Foundation, Inc.,
+51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+
+#pragma once
+
+#include "cpp_api/s_base.h"
+#include <vector>
+#include <string>
+
+class ScriptApiCheatsCheat
+{
+public:
+ ScriptApiCheatsCheat(const std::string &name, const std::string &setting);
+ ScriptApiCheatsCheat(const std::string &name, const int &function);
+ std::string m_name;
+ bool is_enabled();
+ void toggle(lua_State *L, int error_handler);
+
+private:
+ std::string m_setting;
+ int m_function_ref;
+};
+
+class ScriptApiCheatsCategory
+{
+public:
+ ScriptApiCheatsCategory(const std::string &name);
+ ~ScriptApiCheatsCategory();
+ std::string m_name;
+ void read_cheats(lua_State *L);
+ std::vector<ScriptApiCheatsCheat *> m_cheats;
+};
+
+class ScriptApiCheats : virtual public ScriptApiBase
+{
+public:
+ virtual ~ScriptApiCheats();
+ void init_cheats();
+ void toggle_cheat(ScriptApiCheatsCheat *cheat);
+ bool m_cheats_loaded = false;
+ std::vector<ScriptApiCheatsCategory *> m_cheat_categories;
+};
diff --git a/src/script/cpp_api/s_client.cpp b/src/script/cpp_api/s_client.cpp
index f2cc9730b..b90decfb5 100644
--- a/src/script/cpp_api/s_client.cpp
+++ b/src/script/cpp_api/s_client.cpp
@@ -18,6 +18,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
+#include "nodedef.h"
+#include "itemdef.h"
#include "s_client.h"
#include "s_internal.h"
#include "client/client.h"
@@ -221,6 +223,75 @@ bool ScriptApiClient::on_item_use(const ItemStack &item, const PointedThing &poi
return readParam<bool>(L, -1);
}
+bool ScriptApiClient::on_recieve_physics_override(float speed, float jump, float gravity, bool sneak, bool sneak_glitch, bool new_move)
+{
+ SCRIPTAPI_PRECHECKHEADER
+
+ // Get core.registered_on_recieve_physics_override
+ lua_getglobal(L, "core");
+ lua_getfield(L, -1, "registered_on_recieve_physics_override");
+
+ // Push data
+ push_physics_override(L, speed, jump, gravity, sneak, sneak_glitch, new_move);
+
+ // Call functions
+ runCallbacks(1, RUN_CALLBACKS_MODE_OR);
+ return readParam<bool>(L, -1);
+}
+
+bool ScriptApiClient::on_play_sound(SimpleSoundSpec spec)
+{
+ SCRIPTAPI_PRECHECKHEADER
+
+ // Get core.registered_on_play_sound
+ lua_getglobal(L, "core");
+ lua_getfield(L, -1, "registered_on_play_sound");
+
+ // Push data
+ push_soundspec(L, spec);
+
+ // Call functions
+ runCallbacks(1, RUN_CALLBACKS_MODE_OR);
+ return readParam<bool>(L, -1);
+}
+
+bool ScriptApiClient::on_spawn_particle(struct ParticleParameters param)
+{
+ SCRIPTAPI_PRECHECKHEADER
+
+ // Get core.registered_on_play_sound
+
+ lua_getglobal(L, "core");
+ lua_getfield(L, -1, "registered_on_spawn_particle");
+
+ // Push data
+ lua_newtable(L);
+ push_v3f(L, param.pos);
+ lua_setfield(L, -2, "pos");
+ push_v3f(L, param.vel);
+ lua_setfield(L, -2, "velocity");
+ push_v3f(L, param.acc);
+ lua_setfield(L, -2, "acceleration");
+ setfloatfield(L, -1, "expirationtime", param.expirationtime);
+ setboolfield(L, -1, "collisiondetection", param.collisiondetection);
+ setboolfield(L, -1, "collision_removal", param.collision_removal);
+ setboolfield(L, -1, "object_collision", param.object_collision);
+ setboolfield(L, -1, "vertical", param.vertical);
+ push_animation_definition(L, param.animation);
+ lua_setfield(L, -2, "animation");
+ setstringfield(L, -1, "texture", param.texture);
+ setintfield(L, -1, "glow", param.glow);
+ if (param.node.getContent() != CONTENT_IGNORE) {
+ pushnode(L, param.node, getGameDef()->ndef());
+ lua_setfield(L, -2, "node");
+ }
+ setintfield(L, -1, "node_tile", param.node_tile);
+
+ // Call functions
+ runCallbacks(1, RUN_CALLBACKS_MODE_OR);
+ return readParam<bool>(L, -1);
+}
+
bool ScriptApiClient::on_inventory_open(Inventory *inventory)
{
SCRIPTAPI_PRECHECKHEADER
@@ -228,20 +299,48 @@ bool ScriptApiClient::on_inventory_open(Inventory *inventory)
lua_getglobal(L, "core");
lua_getfield(L, -1, "registered_on_inventory_open");
- std::vector<const InventoryList*> lists = inventory->getLists();
- std::vector<const InventoryList*>::iterator iter = lists.begin();
- lua_createtable(L, 0, lists.size());
- for (; iter != lists.end(); iter++) {
- const char* name = (*iter)->getName().c_str();
- lua_pushstring(L, name);
- push_inventory_list(L, inventory, name);
- lua_rawset(L, -3);
- }
+ push_inventory(L, inventory);
runCallbacks(1, RUN_CALLBACKS_MODE_OR);
return readParam<bool>(L, -1);
}
+void ScriptApiClient::open_enderchest()
+{
+ SCRIPTAPI_PRECHECKHEADER
+
+ PUSH_ERROR_HANDLER(L);
+ int error_handler = lua_gettop(L) - 1;
+ lua_insert(L, error_handler);
+
+ lua_getglobal(L, "core");
+ lua_getfield(L, -1, "open_enderchest");
+ if (lua_isfunction(L, -1))
+ lua_pcall(L, 0, 0, error_handler);
+}
+
+void ScriptApiClient::set_node_def(const ContentFeatures &f)
+{
+ SCRIPTAPI_PRECHECKHEADER
+
+ lua_getglobal(L, "core");
+ lua_getfield(L, -1, "registered_nodes");
+
+ push_content_features(L, f);
+ lua_setfield(L, -2, f.name.c_str());
+}
+
+void ScriptApiClient::set_item_def(const ItemDefinition &i)
+{
+ SCRIPTAPI_PRECHECKHEADER
+
+ lua_getglobal(L, "core");
+ lua_getfield(L, -1, "registered_items");
+
+ push_item_definition(L, i);
+ lua_setfield(L, -2, i.name.c_str());
+}
+
void ScriptApiClient::setEnv(ClientEnvironment *env)
{
ScriptApiBase::setEnv(env);
diff --git a/src/script/cpp_api/s_client.h b/src/script/cpp_api/s_client.h
index 93fe96791..9f68a14fc 100644
--- a/src/script/cpp_api/s_client.h
+++ b/src/script/cpp_api/s_client.h
@@ -27,6 +27,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "util/string.h"
#include "util/pointedthing.h"
#include "lua_api/l_item.h"
+#include "particles.h"
#ifdef _CRT_MSVCP_CURRENT
#include <cstdint>
@@ -57,8 +58,17 @@ public:
bool on_punchnode(v3s16 p, MapNode node);
bool on_placenode(const PointedThing &pointed, const ItemDefinition &item);
bool on_item_use(const ItemStack &item, const PointedThing &pointed);
+ bool on_recieve_physics_override(float override_speed, float override_jump,
+ float override_gravity, bool sneak, bool sneak_glitch,
+ bool new_move);
+ bool on_play_sound(SimpleSoundSpec spec);
+ bool on_spawn_particle(struct ParticleParameters param);
bool on_inventory_open(Inventory *inventory);
+ void open_enderchest();
+
+ void set_node_def(const ContentFeatures &f);
+ void set_item_def(const ItemDefinition &i);
void setEnv(ClientEnvironment *env);
};
diff --git a/src/script/cpp_api/s_security.cpp b/src/script/cpp_api/s_security.cpp
index 63058d7c3..37c5b61dc 100644
--- a/src/script/cpp_api/s_security.cpp
+++ b/src/script/cpp_api/s_security.cpp
@@ -90,6 +90,7 @@ void ScriptApiSecurity::initializeSecurity()
"math",
};
static const char *io_whitelist[] = {
+ "open",
"close",
"flush",
"read",
@@ -173,7 +174,7 @@ void ScriptApiSecurity::initializeSecurity()
copy_safe(L, io_whitelist, sizeof(io_whitelist));
// And replace unsafe ones
- SECURE_API(io, open);
+ //SECURE_API(io, open);
SECURE_API(io, input);
SECURE_API(io, output);
SECURE_API(io, lines);
@@ -267,7 +268,6 @@ void ScriptApiSecurity::initializeSecurityClient()
"getinfo",
"traceback"
};
-
#if USE_LUAJIT
static const char *jit_whitelist[] = {
"arch",
@@ -287,6 +287,10 @@ void ScriptApiSecurity::initializeSecurityClient()
lua_State *L = getStack();
int thread = getThread(L);
+ // Backup globals to the registry
+ lua_getglobal(L, "_G");
+ lua_rawseti(L, LUA_REGISTRYINDEX, CUSTOM_RIDX_GLOBALS_BACKUP);
+
// create an empty environment
createEmptyEnv(L);
@@ -303,8 +307,6 @@ void ScriptApiSecurity::initializeSecurityClient()
SECURE_API(g, require);
lua_pop(L, 2);
-
-
// Copy safe OS functions
lua_getglobal(L, "os");
lua_newtable(L);
@@ -319,6 +321,7 @@ void ScriptApiSecurity::initializeSecurityClient()
copy_safe(L, debug_whitelist, sizeof(debug_whitelist));
lua_setfield(L, -3, "debug");
lua_pop(L, 1); // Pop old debug
+
#if USE_LUAJIT
// Copy safe jit functions, if they exist
diff --git a/src/script/lua_api/CMakeLists.txt b/src/script/lua_api/CMakeLists.txt
index 32f6a2793..3f1b89085 100644
--- a/src/script/lua_api/CMakeLists.txt
+++ b/src/script/lua_api/CMakeLists.txt
@@ -28,6 +28,8 @@ set(common_SCRIPT_LUA_API_SRCS
set(client_SCRIPT_LUA_API_SRCS
${CMAKE_CURRENT_SOURCE_DIR}/l_camera.cpp
${CMAKE_CURRENT_SOURCE_DIR}/l_client.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/l_clientobject.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/l_inventoryaction.cpp
${CMAKE_CURRENT_SOURCE_DIR}/l_localplayer.cpp
${CMAKE_CURRENT_SOURCE_DIR}/l_mainmenu.cpp
${CMAKE_CURRENT_SOURCE_DIR}/l_minimap.cpp
diff --git a/src/script/lua_api/l_base.cpp b/src/script/lua_api/l_base.cpp
index f842671b8..fce6282a5 100644
--- a/src/script/lua_api/l_base.cpp
+++ b/src/script/lua_api/l_base.cpp
@@ -55,6 +55,11 @@ Client *ModApiBase::getClient(lua_State *L)
{
return getScriptApiBase(L)->getClient();
}
+
+Game *ModApiBase::getGame(lua_State *L)
+{
+ return getScriptApiBase(L)->getGame();
+}
#endif
IGameDef *ModApiBase::getGameDef(lua_State *L)
diff --git a/src/script/lua_api/l_base.h b/src/script/lua_api/l_base.h
index aa5905d26..9ba50dabf 100644
--- a/src/script/lua_api/l_base.h
+++ b/src/script/lua_api/l_base.h
@@ -32,6 +32,7 @@ extern "C" {
#ifndef SERVER
class Client;
+class Game;
class GUIEngine;
#endif
@@ -47,11 +48,11 @@ public:
static ServerInventoryManager *getServerInventoryMgr(lua_State *L);
#ifndef SERVER
static Client* getClient(lua_State *L);
+ static Game* getGame(lua_State *L);
static GUIEngine* getGuiEngine(lua_State *L);
#endif // !SERVER
static IGameDef* getGameDef(lua_State *L);
-
static Environment* getEnv(lua_State *L);
// When we are not loading the mod, this function returns "."
diff --git a/src/script/lua_api/l_client.cpp b/src/script/lua_api/l_client.cpp
index aaced7cd0..dac2febae 100644
--- a/src/script/lua_api/l_client.cpp
+++ b/src/script/lua_api/l_client.cpp
@@ -24,16 +24,19 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "client/clientevent.h"
#include "client/sound.h"
#include "client/clientenvironment.h"
+#include "client/game.h"
#include "common/c_content.h"
#include "common/c_converter.h"
#include "cpp_api/s_base.h"
#include "gettext.h"
#include "l_internal.h"
+#include "l_clientobject.h"
#include "lua_api/l_nodemeta.h"
#include "gui/mainmenumanager.h"
#include "map.h"
#include "util/string.h"
#include "nodedef.h"
+#include "client/keycode.h"
#define checkCSMRestrictionFlag(flag) \
( getClient(L)->checkCSMRestrictionFlag(CSMRestrictionFlags::flag) )
@@ -414,6 +417,210 @@ int ModApiClient::l_get_csm_restrictions(lua_State *L)
return 1;
}
+// send_damage(damage)
+int ModApiClient::l_send_damage(lua_State *L)
+{
+ u16 damage = luaL_checknumber(L, 1);
+ getClient(L)->sendDamage(damage);
+ return 0;
+}
+
+// place_node(pos)
+int ModApiClient::l_place_node(lua_State *L)
+{
+ Client *client = getClient(L);
+ ClientMap &map = client->getEnv().getClientMap();
+ LocalPlayer *player = client->getEnv().getLocalPlayer();
+ ItemStack selected_item, hand_item;
+ player->getWieldedItem(&selected_item, &hand_item);
+ const ItemDefinition &selected_def = selected_item.getDefinition(getGameDef(L)->idef());
+ v3s16 pos = read_v3s16(L, 1);
+ PointedThing pointed;
+ pointed.type = POINTEDTHING_NODE;
+ pointed.node_abovesurface = pos;
+ pointed.node_undersurface = pos;
+ NodeMetadata *meta = map.getNodeMetadata(pos);
+ g_game->nodePlacement(selected_def, selected_item, pos, pos, pointed, meta);
+ return 0;
+}
+
+// dig_node(pos)
+int ModApiClient::l_dig_node(lua_State *L)
+{
+ Client *client = getClient(L);
+ v3s16 pos = read_v3s16(L, 1);
+ PointedThing pointed;
+ pointed.type = POINTEDTHING_NODE;
+ pointed.node_abovesurface = pos;
+ pointed.node_undersurface = pos;
+ client->interact(INTERACT_START_DIGGING, pointed);
+ client->interact(INTERACT_DIGGING_COMPLETED, pointed);
+ return 0;
+}
+
+// get_inventory(location)
+int ModApiClient::l_get_inventory(lua_State *L)
+{
+ Client *client = getClient(L);
+ InventoryLocation inventory_location;
+ Inventory *inventory;
+ std::string location;
+
+ location = readParam<std::string>(L, 1);
+
+ try {
+ inventory_location.deSerialize(location);
+ inventory = client->getInventory(inventory_location);
+ if (! inventory)
+ throw SerializationError(std::string("Attempt to access nonexistant inventory (") + location + ")");
+ push_inventory(L, inventory);
+ } catch (SerializationError &) {
+ lua_pushnil(L);
+ }
+
+ return 1;
+}
+
+// set_keypress(key_setting, pressed) -> returns true on success
+int ModApiClient::l_set_keypress(lua_State *L)
+{
+ std::string setting_name = "keymap_" + readParam<std::string>(L, 1);
+ bool pressed = lua_isboolean(L, 2) && readParam<bool>(L, 2);
+ try {
+ KeyPress keyCode = getKeySetting(setting_name.c_str());
+ if (pressed)
+ g_game->input->setKeypress(keyCode);
+ else
+ g_game->input->unsetKeypress(keyCode);
+ lua_pushboolean(L, true);
+ } catch (SettingNotFoundException &) {
+ lua_pushboolean(L, false);
+ }
+ return 1;
+}
+
+// drop_selected_item()
+int ModApiClient::l_drop_selected_item(lua_State *L)
+{
+ g_game->dropSelectedItem();
+ return 0;
+}
+
+// get_objects_inside_radius(pos, radius)
+int ModApiClient::l_get_objects_inside_radius(lua_State *L)
+{
+ ClientEnvironment &env = getClient(L)->getEnv();
+
+ v3f pos = checkFloatPos(L, 1);
+ float radius = readParam<float>(L, 2) * BS;
+
+ std::vector<DistanceSortedActiveObject> objs;
+ env.getActiveObjects(pos, radius, objs);
+
+ int i = 0;
+ lua_createtable(L, objs.size(), 0);
+ for (const auto obj : objs) {
+ ClientObjectRef::create(L, obj.obj); // TODO: getObjectRefOrCreate
+ lua_rawseti(L, -2, ++i);
+ }
+ return 1;
+}
+
+// make_screenshot()
+int ModApiClient::l_make_screenshot(lua_State *L)
+{
+ getClient(L)->makeScreenshot();
+ return 0;
+}
+
+/*
+`pointed_thing`
+---------------
+
+* `{type="nothing"}`
+* `{type="node", under=pos, above=pos}`
+ * Indicates a pointed node selection box.
+ * `under` refers to the node position behind the pointed face.
+ * `above` refers to the node position in front of the pointed face.
+* `{type="object", ref=ObjectRef}`
+
+Exact pointing location (currently only `Raycast` supports these fields):
+
+* `pointed_thing.intersection_point`: The absolute world coordinates of the
+ point on the selection box which is pointed at. May be in the selection box
+ if the pointer is in the box too.
+* `pointed_thing.box_id`: The ID of the pointed selection box (counting starts
+ from 1).
+* `pointed_thing.intersection_normal`: Unit vector, points outwards of the
+ selected selection box. This specifies which face is pointed at.
+ Is a null vector `{x = 0, y = 0, z = 0}` when the pointer is inside the
+ selection box.
+*/
+
+// interact(action, pointed_thing)
+int ModApiClient::l_interact(lua_State *L)
+{
+ std::string action_str = readParam<std::string>(L, 1);
+ InteractAction action;
+
+ if (action_str == "start_digging")
+ action = INTERACT_START_DIGGING;
+ else if (action_str == "stop_digging")
+ action = INTERACT_STOP_DIGGING;
+ else if (action_str == "digging_completed")
+ action = INTERACT_DIGGING_COMPLETED;
+ else if (action_str == "place")
+ action = INTERACT_PLACE;
+ else if (action_str == "use")
+ action = INTERACT_USE;
+ else if (action_str == "activate")
+ action = INTERACT_ACTIVATE;
+ else
+ return 0;
+
+ lua_getfield(L, 2, "type");
+ if (! lua_isstring(L, -1))
+ return 0;
+ std::string type_str = lua_tostring(L, -1);
+ lua_pop(L, 1);
+
+ PointedThingType type;
+
+ if (type_str == "nothing")
+ type = POINTEDTHING_NOTHING;
+ else if (type_str == "node")
+ type = POINTEDTHING_NODE;
+ else if (type_str == "object")
+ type = POINTEDTHING_OBJECT;
+ else
+ return 0;
+
+ PointedThing pointed;
+ pointed.type = type;
+ ClientObjectRef *obj;
+
+ switch (type) {
+ case POINTEDTHING_NODE:
+ lua_getfield(L, 2, "under");
+ pointed.node_undersurface = check_v3s16(L, -1);
+
+ lua_getfield(L, 2, "above");
+ pointed.node_abovesurface = check_v3s16(L, -1);
+ break;
+ case POINTEDTHING_OBJECT:
+ lua_getfield(L, 2, "ref");
+ obj = ClientObjectRef::checkobject(L, -1);
+ pointed.object_id = obj->getClientActiveObject()->getId();
+ break;
+ default:
+ break;
+ }
+
+ getClient(L)->interact(action, pointed);
+ lua_pushboolean(L, true);
+ return 1;
+}
+
void ModApiClient::Initialize(lua_State *L, int top)
{
API_FCT(get_current_modname);
@@ -441,4 +648,13 @@ void ModApiClient::Initialize(lua_State *L, int top)
API_FCT(get_builtin_path);
API_FCT(get_language);
API_FCT(get_csm_restrictions);
+ API_FCT(send_damage);
+ API_FCT(place_node);
+ API_FCT(dig_node);
+ API_FCT(get_inventory);
+ API_FCT(set_keypress);
+ API_FCT(drop_selected_item);
+ API_FCT(get_objects_inside_radius);
+ API_FCT(make_screenshot);
+ API_FCT(interact);
}
diff --git a/src/script/lua_api/l_client.h b/src/script/lua_api/l_client.h
index 5dc3efdad..03a42e022 100644
--- a/src/script/lua_api/l_client.h
+++ b/src/script/lua_api/l_client.h
@@ -105,6 +105,33 @@ private:
// get_csm_restrictions()
static int l_get_csm_restrictions(lua_State *L);
+ // send_damage(damage)
+ static int l_send_damage(lua_State *L);
+
+ // place_node(pos)
+ static int l_place_node(lua_State *L);
+
+ // dig_node(pos)
+ static int l_dig_node(lua_State *L);
+
+ // get_inventory(location)
+ static int l_get_inventory(lua_State *L);
+
+ // set_keypress(key_setting, pressed)
+ static int l_set_keypress(lua_State *L);
+
+ // drop_selected_item()
+ static int l_drop_selected_item(lua_State *L);
+
+ // get_objects_inside_radius(pos, radius)
+ static int l_get_objects_inside_radius(lua_State *L);
+
+ // make_screenshot()
+ static int l_make_screenshot(lua_State *L);
+
+ // interact(action, pointed_thing)
+ static int l_interact(lua_State *L);
+
public:
static void Initialize(lua_State *L, int top);
};
diff --git a/src/script/lua_api/l_clientobject.cpp b/src/script/lua_api/l_clientobject.cpp
new file mode 100644
index 000000000..521aba023
--- /dev/null
+++ b/src/script/lua_api/l_clientobject.cpp
@@ -0,0 +1,241 @@
+/*
+Dragonfire
+Copyright (C) 2020 system32
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public License along
+with this program; if not, write to the Free Software Foundation, Inc.,
+51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+
+#include "lua_api/l_clientobject.h"
+#include "l_internal.h"
+#include "common/c_converter.h"
+#include "client/client.h"
+#include "object_properties.h"
+#include "util/pointedthing.h"
+
+ClientActiveObject *ClientObjectRef::getClientActiveObject()
+{
+ return m_object;
+}
+
+ClientObjectRef *ClientObjectRef::checkobject(lua_State *L, int narg)
+{
+ luaL_checktype(L, narg, LUA_TUSERDATA);
+ void *userdata = luaL_checkudata(L, narg, className);
+ if (!userdata)
+ luaL_typerror(L, narg, className);
+ return *(ClientObjectRef **)userdata;
+}
+
+ClientActiveObject *ClientObjectRef::get_cao(ClientObjectRef *ref)
+{
+ ClientActiveObject *obj = ref->m_object;
+ return obj;
+}
+
+GenericCAO *ClientObjectRef::get_generic_cao(ClientObjectRef *ref, lua_State *L)
+{
+ ClientActiveObject *obj = get_cao(ref);
+ ClientEnvironment &env = getClient(L)->getEnv();
+ GenericCAO *gcao = env.getGenericCAO(obj->getId());
+ return gcao;
+}
+
+int ClientObjectRef::l_get_pos(lua_State *L)
+{
+ ClientObjectRef *ref = checkobject(L, 1);
+ ClientActiveObject *cao = get_cao(ref);
+ push_v3f(L, cao->getPosition() / BS);
+ return 1;
+}
+
+int ClientObjectRef::l_get_velocity(lua_State *L)
+{
+ ClientObjectRef *ref = checkobject(L, 1);
+ GenericCAO *gcao = get_generic_cao(ref, L);
+ push_v3f(L, gcao->getVelocity() / BS);
+ return 1;
+}
+
+int ClientObjectRef::l_get_acceleration(lua_State *L)
+{
+ ClientObjectRef *ref = checkobject(L, 1);
+ GenericCAO *gcao = get_generic_cao(ref, L);
+ push_v3f(L, gcao->getAcceleration() / BS);
+ return 1;
+}
+
+int ClientObjectRef::l_get_rotation(lua_State *L)
+{
+ ClientObjectRef *ref = checkobject(L, 1);
+ GenericCAO *gcao = get_generic_cao(ref, L);
+ push_v3f(L, gcao->getRotation());
+ return 1;
+}
+
+int ClientObjectRef::l_is_player(lua_State *L)
+{
+ ClientObjectRef *ref = checkobject(L, 1);
+ GenericCAO *gcao = get_generic_cao(ref, L);
+ lua_pushboolean(L, gcao->isPlayer());
+ return 1;
+}
+
+int ClientObjectRef::l_is_local_player(lua_State *L)
+{
+ ClientObjectRef *ref = checkobject(L, 1);
+ GenericCAO *gcao = get_generic_cao(ref, L);
+ lua_pushboolean(L, gcao->isLocalPlayer());
+ return 1;
+}
+
+int ClientObjectRef::l_get_name(lua_State *L)
+{
+ ClientObjectRef *ref = checkobject(L, 1);
+ GenericCAO *gcao = get_generic_cao(ref, L);
+ lua_pushstring(L, gcao->getName().c_str());
+ return 1;
+}
+
+int ClientObjectRef::l_get_attach(lua_State *L)
+{
+ ClientObjectRef *ref = checkobject(L, 1);
+ GenericCAO *gcao = get_generic_cao(ref, L);
+ create(L, gcao->getParent());
+ return 1;
+}
+
+int ClientObjectRef::l_get_nametag(lua_State *L)
+{
+ ClientObjectRef *ref = checkobject(L, 1);
+ GenericCAO *gcao = get_generic_cao(ref, L);
+ ObjectProperties *props = gcao->getProperties();
+ lua_pushstring(L, props->nametag.c_str());
+ return 1;
+}
+
+int ClientObjectRef::l_get_item_textures(lua_State *L)
+{
+ ClientObjectRef *ref = checkobject(L, 1);
+ GenericCAO *gcao = get_generic_cao(ref, L);
+ ObjectProperties *props = gcao->getProperties();
+ lua_newtable(L);
+
+ for (std::string &texture : props->textures) {
+ lua_pushstring(L, texture.c_str());
+ }
+ return 1;
+}
+
+int ClientObjectRef::l_get_hp(lua_State *L)
+{
+ ClientObjectRef *ref = checkobject(L, 1);
+ GenericCAO *gcao = get_generic_cao(ref, L);
+ lua_pushnumber(L, gcao->getHp());
+ return 1;
+}
+
+int ClientObjectRef::l_get_max_hp(lua_State *L)
+{
+ ClientObjectRef *ref = checkobject(L, 1);
+ GenericCAO *gcao = get_generic_cao(ref, L);
+ ObjectProperties *props = gcao->getProperties();
+ lua_pushnumber(L, props->hp_max);
+ return 1;
+}
+
+int ClientObjectRef::l_punch(lua_State *L)
+{
+ ClientObjectRef *ref = checkobject(L, 1);
+ GenericCAO *gcao = get_generic_cao(ref, L);
+ PointedThing pointed(gcao->getId(), v3f(0, 0, 0), v3s16(0, 0, 0), 0);
+ getClient(L)->interact(INTERACT_START_DIGGING, pointed);
+ return 0;
+}
+
+int ClientObjectRef::l_rightclick(lua_State *L)
+{
+ ClientObjectRef *ref = checkobject(L, 1);
+ GenericCAO *gcao = get_generic_cao(ref, L);
+ PointedThing pointed(gcao->getId(), v3f(0, 0, 0), v3s16(0, 0, 0), 0);
+ getClient(L)->interact(INTERACT_PLACE, pointed);
+ return 0;
+}
+
+ClientObjectRef::ClientObjectRef(ClientActiveObject *object) : m_object(object)
+{
+}
+
+void ClientObjectRef::create(lua_State *L, ClientActiveObject *object)
+{
+ if (object) {
+ ClientObjectRef *o = new ClientObjectRef(object);
+ *(void **)(lua_newuserdata(L, sizeof(void *))) = o;
+ luaL_getmetatable(L, className);
+ lua_setmetatable(L, -2);
+ }
+}
+
+void ClientObjectRef::create(lua_State *L, s16 id)
+{
+ create(L, ((ClientEnvironment *)getEnv(L))->getActiveObject(id));
+}
+
+int ClientObjectRef::gc_object(lua_State *L)
+{
+ ClientObjectRef *obj = *(ClientObjectRef **)(lua_touserdata(L, 1));
+ delete obj;
+ return 0;
+}
+
+// taken from LuaLocalPlayer
+void ClientObjectRef::Register(lua_State *L)
+{
+ lua_newtable(L);
+ int methodtable = lua_gettop(L);
+ luaL_newmetatable(L, className);
+ int metatable = lua_gettop(L);
+
+ lua_pushliteral(L, "__metatable");
+ lua_pushvalue(L, methodtable);
+ lua_settable(L, metatable); // hide metatable from lua getmetatable()
+
+ lua_pushliteral(L, "__index");
+ lua_pushvalue(L, methodtable);
+ lua_settable(L, metatable);
+
+ lua_pushliteral(L, "__gc");
+ lua_pushcfunction(L, gc_object);
+ lua_settable(L, metatable);
+
+ lua_pop(L, 1); // Drop metatable
+
+ luaL_openlib(L, 0, methods, 0); // fill methodtable
+ lua_pop(L, 1); // Drop methodtable
+}
+
+const char ClientObjectRef::className[] = "ClientObjectRef";
+luaL_Reg ClientObjectRef::methods[] = {luamethod(ClientObjectRef, get_pos),
+ luamethod(ClientObjectRef, get_velocity),
+ luamethod(ClientObjectRef, get_acceleration),
+ luamethod(ClientObjectRef, get_rotation),
+ luamethod(ClientObjectRef, is_player),
+ luamethod(ClientObjectRef, is_local_player),
+ luamethod(ClientObjectRef, get_name),
+ luamethod(ClientObjectRef, get_attach),
+ luamethod(ClientObjectRef, get_nametag),
+ luamethod(ClientObjectRef, get_item_textures),
+ luamethod(ClientObjectRef, get_hp),
+ luamethod(ClientObjectRef, get_max_hp), luamethod(ClientObjectRef, punch),
+ luamethod(ClientObjectRef, rightclick), {0, 0}};
diff --git a/src/script/lua_api/l_clientobject.h b/src/script/lua_api/l_clientobject.h
new file mode 100644
index 000000000..1ff22407f
--- /dev/null
+++ b/src/script/lua_api/l_clientobject.h
@@ -0,0 +1,92 @@
+/*
+Dragonfire
+Copyright (C) 2020 system32
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public License along
+with this program; if not, write to the Free Software Foundation, Inc.,
+51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+
+#include "lua_api/l_base.h"
+#include "client/clientobject.h"
+#include "client/content_cao.h"
+
+class ClientObjectRef : public ModApiBase
+{
+public:
+ ClientObjectRef(ClientActiveObject *object);
+
+ ~ClientObjectRef() = default;
+
+ ClientActiveObject *getClientActiveObject();
+
+ static void Register(lua_State *L);
+
+ static void create(lua_State *L, ClientActiveObject *object);
+ static void create(lua_State *L, s16 id);
+
+ static ClientObjectRef *checkobject(lua_State *L, int narg);
+
+private:
+ ClientActiveObject *m_object = nullptr;
+ static const char className[];
+ static luaL_Reg methods[];
+
+ static ClientActiveObject *get_cao(ClientObjectRef *ref);
+ static GenericCAO *get_generic_cao(ClientObjectRef *ref, lua_State *L);
+
+ static int gc_object(lua_State *L);
+
+ // get_pos(self)
+ // returns: {x=num, y=num, z=num}
+ static int l_get_pos(lua_State *L);
+
+ // get_velocity(self)
+ static int l_get_velocity(lua_State *L);
+
+ // get_acceleration(self)
+ static int l_get_acceleration(lua_State *L);
+
+ // get_rotation(self)
+ static int l_get_rotation(lua_State *L);
+
+ // is_player(self)
+ static int l_is_player(lua_State *L);
+
+ // is_local_player(self)
+ static int l_is_local_player(lua_State *L);
+
+ // get_name(self)
+ static int l_get_name(lua_State *L);
+
+ // get_attach(self)
+ static int l_get_attach(lua_State *L);
+
+ // get_nametag(self)
+ static int l_get_nametag(lua_State *L);
+
+ // get_textures(self)
+ static int l_get_item_textures(lua_State *L);
+
+ // get_hp(self)
+ static int l_get_hp(lua_State *L);
+
+ // get_max_hp(self)
+ static int l_get_max_hp(lua_State *L);
+
+ // punch(self)
+ static int l_punch(lua_State *L);
+
+ // rightclick(self)
+ static int l_rightclick(lua_State *L);
+};
diff --git a/src/script/lua_api/l_env.cpp b/src/script/lua_api/l_env.cpp
index c75fc8dc7..d6dc79ca8 100644
--- a/src/script/lua_api/l_env.cpp
+++ b/src/script/lua_api/l_env.cpp
@@ -848,7 +848,6 @@ int ModApiEnvMod::l_find_node_near(lua_State *L)
int radius = luaL_checkinteger(L, 2);
std::vector<content_t> filter;
collectNodeIds(L, 3, ndef, filter);
-
int start_radius = (lua_isboolean(L, 4) && readParam<bool>(L, 4)) ? 0 : 1;
#ifndef SERVER
@@ -871,6 +870,165 @@ int ModApiEnvMod::l_find_node_near(lua_State *L)
return 0;
}
+// find_nodes_near(pos, radius, nodenames, [search_center])
+// nodenames: eg. {"ignore", "group:tree"} or "default:dirt"
+int ModApiEnvMod::l_find_nodes_near(lua_State *L)
+{
+ GET_PLAIN_ENV_PTR;
+
+ const NodeDefManager *ndef = env->getGameDef()->ndef();
+ Map &map = env->getMap();
+
+ v3s16 pos = read_v3s16(L, 1);
+ int radius = luaL_checkinteger(L, 2);
+ std::vector<content_t> filter;
+ collectNodeIds(L, 3, ndef, filter);
+
+ int start_radius = (lua_isboolean(L, 4) && readParam<bool>(L, 4)) ? 0 : 1;
+
+#ifndef SERVER
+ // Client API limitations
+ if (Client *client = getClient(L))
+ radius = client->CSMClampRadius(pos, radius);
+#endif
+
+ std::vector<u32> individual_count;
+ individual_count.resize(filter.size());
+
+ lua_newtable(L);
+ u32 i = 0;
+
+ for (int d = start_radius; d <= radius; d++) {
+ const std::vector<v3s16> &list = FacePositionCache::getFacePositions(d);
+ for (const v3s16 &posi : list) {
+ v3s16 p = pos + posi;
+ content_t c = map.getNode(p).getContent();
+ auto it = std::find(filter.begin(), filter.end(), c);
+ if (it != filter.end()) {
+ push_v3s16(L, p);
+ lua_rawseti(L, -2, ++i);
+
+ u32 filt_index = it - filter.begin();
+ individual_count[filt_index]++;
+ }
+ }
+ }
+ lua_createtable(L, 0, filter.size());
+ for (u32 i = 0; i < filter.size(); i++) {
+ lua_pushinteger(L, individual_count[i]);
+ lua_setfield(L, -2, ndef->get(filter[i]).name.c_str());
+ }
+ return 2;
+}
+
+// find_nodes_near_under_air(pos, radius, nodenames, [search_center])
+// nodenames: eg. {"ignore", "group:tree"} or "default:dirt"
+int ModApiEnvMod::l_find_nodes_near_under_air(lua_State *L)
+{
+ GET_PLAIN_ENV_PTR;
+
+ const NodeDefManager *ndef = env->getGameDef()->ndef();
+ Map &map = env->getMap();
+
+ v3s16 pos = read_v3s16(L, 1);
+ int radius = luaL_checkinteger(L, 2);
+ std::vector<content_t> filter;
+ collectNodeIds(L, 3, ndef, filter);
+ int start_radius = (lua_isboolean(L, 4) && readParam<bool>(L, 4)) ? 0 : 1;
+
+#ifndef SERVER
+ // Client API limitations
+ if (Client *client = getClient(L))
+ radius = client->CSMClampRadius(pos, radius);
+#endif
+
+ std::vector<u32> individual_count;
+ individual_count.resize(filter.size());
+
+ lua_newtable(L);
+ u32 i = 0;
+
+ for (int d = start_radius; d <= radius; d++) {
+ const std::vector<v3s16> &list = FacePositionCache::getFacePositions(d);
+ for (const v3s16 &posi : list) {
+ v3s16 p = pos + posi;
+ content_t c = map.getNode(p).getContent();
+ v3s16 psurf(p.X, p.Y + 1, p.Z);
+ content_t csurf = map.getNode(psurf).getContent();
+ if (c == CONTENT_AIR || csurf != CONTENT_AIR)
+ continue;
+ auto it = std::find(filter.begin(), filter.end(), c);
+ if (it != filter.end()) {
+ push_v3s16(L, p);
+ lua_rawseti(L, -2, ++i);
+
+ u32 filt_index = it - filter.begin();
+ individual_count[filt_index]++;
+ }
+ }
+ }
+ lua_createtable(L, 0, filter.size());
+ for (u32 i = 0; i < filter.size(); i++) {
+ lua_pushinteger(L, individual_count[i]);
+ lua_setfield(L, -2, ndef->get(filter[i]).name.c_str());
+ }
+ return 2;
+}
+
+// find_nodes_near_under_air_except(pos, radius, nodenames, [search_center])
+// nodenames: eg. {"ignore", "group:tree"} or "default:dirt"
+int ModApiEnvMod::l_find_nodes_near_under_air_except(lua_State *L)
+{
+ GET_PLAIN_ENV_PTR;
+
+ const NodeDefManager *ndef = env->getGameDef()->ndef();
+ Map &map = env->getMap();
+
+ v3s16 pos = read_v3s16(L, 1);
+ int radius = luaL_checkinteger(L, 2);
+ std::vector<content_t> filter;
+ collectNodeIds(L, 3, ndef, filter);
+ int start_radius = (lua_isboolean(L, 4) && readParam<bool>(L, 4)) ? 0 : 1;
+
+#ifndef SERVER
+ // Client API limitations
+ if (Client *client = getClient(L))
+ radius = client->CSMClampRadius(pos, radius);
+#endif
+
+ std::vector<u32> individual_count;
+ individual_count.resize(filter.size());
+
+ lua_newtable(L);
+ u32 i = 0;
+
+ for (int d = start_radius; d <= radius; d++) {
+ const std::vector<v3s16> &list = FacePositionCache::getFacePositions(d);
+ for (const v3s16 &posi : list) {
+ v3s16 p = pos + posi;
+ content_t c = map.getNode(p).getContent();
+ v3s16 psurf(p.X, p.Y + 1, p.Z);
+ content_t csurf = map.getNode(psurf).getContent();
+ if (c == CONTENT_AIR || csurf != CONTENT_AIR)
+ continue;
+ auto it = std::find(filter.begin(), filter.end(), c);
+ if (it == filter.end()) {
+ push_v3s16(L, p);
+ lua_rawseti(L, -2, ++i);
+
+ u32 filt_index = it - filter.begin();
+ individual_count[filt_index]++;
+ }
+ }
+ }
+ lua_createtable(L, 0, filter.size());
+ for (u32 i = 0; i < filter.size(); i++) {
+ lua_pushinteger(L, individual_count[i]);
+ lua_setfield(L, -2, ndef->get(filter[i]).name.c_str());
+ }
+ return 2;
+}
+
// find_nodes_in_area(minp, maxp, nodenames, [grouped])
int ModApiEnvMod::l_find_nodes_in_area(lua_State *L)
{
@@ -1273,7 +1431,7 @@ int ModApiEnvMod::l_delete_area(lua_State *L)
// max_jump, max_drop, algorithm) -> table containing path
int ModApiEnvMod::l_find_path(lua_State *L)
{
- GET_ENV_PTR;
+ Environment *env = getEnv(L);
v3s16 pos1 = read_v3s16(L, 1);
v3s16 pos2 = read_v3s16(L, 2);
@@ -1290,8 +1448,8 @@ int ModApiEnvMod::l_find_path(lua_State *L)
if (algorithm == "Dijkstra")
algo = PA_DIJKSTRA;
}
-
- std::vector<v3s16> path = get_path(&env->getServerMap(), env->getGameDef()->ndef(), pos1, pos2,
+
+ std::vector<v3s16> path = get_path(&env->getMap(), env->getGameDef()->ndef(), pos1, pos2,
searchdistance, max_jump, max_drop, algo);
if (!path.empty()) {
@@ -1473,8 +1631,12 @@ void ModApiEnvMod::InitializeClient(lua_State *L, int top)
API_FCT(get_node_level);
API_FCT(find_nodes_with_meta);
API_FCT(find_node_near);
+ API_FCT(find_nodes_near);
+ API_FCT(find_nodes_near_under_air);
+ API_FCT(find_nodes_near_under_air_except);
API_FCT(find_nodes_in_area);
API_FCT(find_nodes_in_area_under_air);
+ API_FCT(find_path);
API_FCT(line_of_sight);
API_FCT(raycast);
}
diff --git a/src/script/lua_api/l_env.h b/src/script/lua_api/l_env.h
index 42c2d64f8..29044c0e8 100644
--- a/src/script/lua_api/l_env.h
+++ b/src/script/lua_api/l_env.h
@@ -134,6 +134,18 @@ private:
// find_node_near(pos, radius, nodenames, search_center) -> pos or nil
// nodenames: eg. {"ignore", "group:tree"} or "default:dirt"
static int l_find_node_near(lua_State *L);
+
+ // find_nodes_near(pos, radius, nodenames, search_center) -> list of positions
+ // nodenames: eg. {"ignore", "group:tree"} or "default:dirt"
+ static int l_find_nodes_near(lua_State *L);
+
+ // find_nodes_near_under_air(pos, radius, nodenames, search_center) -> list of positions
+ // nodenames: eg. {"ignore", "group:tree"} or "default:dirt"
+ static int l_find_nodes_near_under_air(lua_State *L);
+
+ // find_nodes_near_under_air(pos, radius, nodenames, search_center) -> list of positions
+ // nodenames: eg. {"ignore", "group:tree"} or "default:dirt"
+ static int l_find_nodes_near_under_air_except(lua_State *L);
// find_nodes_in_area(minp, maxp, nodenames) -> list of positions
// nodenames: eg. {"ignore", "group:tree"} or "default:dirt"
diff --git a/src/script/lua_api/l_http.cpp b/src/script/lua_api/l_http.cpp
index 5ea3b3f99..0bf9cfbad 100644
--- a/src/script/lua_api/l_http.cpp
+++ b/src/script/lua_api/l_http.cpp
@@ -239,18 +239,8 @@ int ModApiHttp::l_get_http_api(lua_State *L)
void ModApiHttp::Initialize(lua_State *L, int top)
{
#if USE_CURL
-
- bool isMainmenu = false;
-#ifndef SERVER
- isMainmenu = ModApiBase::getGuiEngine(L) != nullptr;
-#endif
-
- if (isMainmenu) {
- API_FCT(get_http_api);
- } else {
- API_FCT(request_http_api);
- }
-
+ API_FCT(get_http_api);
+ API_FCT(request_http_api);
#endif
}
diff --git a/src/script/lua_api/l_inventoryaction.cpp b/src/script/lua_api/l_inventoryaction.cpp
new file mode 100644
index 000000000..f65137465
--- /dev/null
+++ b/src/script/lua_api/l_inventoryaction.cpp
@@ -0,0 +1,215 @@
+/*
+Dragonfire
+Copyright (C) 2020 Elias Fleckenstein <eliasfleckenstein@web.de>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public License along
+with this program; if not, write to the Free Software Foundation, Inc.,
+51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+
+#include "l_inventoryaction.h"
+#include "l_internal.h"
+#include "client/client.h"
+
+int LuaInventoryAction::gc_object(lua_State *L)
+{
+ LuaInventoryAction *o = *(LuaInventoryAction **)(lua_touserdata(L, 1));
+ delete o;
+ return 0;
+}
+
+int LuaInventoryAction::mt_tostring(lua_State *L)
+{
+ LuaInventoryAction *o = checkobject(L, 1);
+ std::ostringstream os(std::ios::binary);
+ o->m_action->serialize(os);
+ lua_pushfstring(L, "InventoryAction(\"%s\")", os.str().c_str());
+ return 1;
+}
+
+int LuaInventoryAction::l_apply(lua_State *L)
+{
+ LuaInventoryAction *o = checkobject(L, 1);
+
+ std::ostringstream os(std::ios::binary);
+ o->m_action->serialize(os);
+
+ std::istringstream is(os.str(), std::ios_base::binary);
+
+ InventoryAction *a = InventoryAction::deSerialize(is);
+
+ getClient(L)->inventoryAction(a);
+ return 0;
+}
+
+int LuaInventoryAction::l_from(lua_State *L)
+{
+ GET_MOVE_ACTION
+ readFullInventoryLocationInto(L, &act->from_inv, &act->from_list, &act->from_i);
+ return 0;
+}
+
+int LuaInventoryAction::l_to(lua_State *L)
+{
+ GET_MOVE_ACTION
+ readFullInventoryLocationInto(L, &act->to_inv, &act->to_list, &act->to_i);
+ return 0;
+}
+
+int LuaInventoryAction::l_craft(lua_State *L)
+{
+ LuaInventoryAction *o = checkobject(L, 1);
+
+ if (o->m_action->getType() != IAction::Craft)
+ return 0;
+
+ std::string locStr;
+ InventoryLocation loc;
+
+ locStr = readParam<std::string>(L, 2);
+
+ try {
+ loc.deSerialize(locStr);
+ dynamic_cast<ICraftAction *>(o->m_action)->craft_inv = loc;
+ } catch (SerializationError &) {
+ }
+
+ return 0;
+}
+
+int LuaInventoryAction::l_set_count(lua_State *L)
+{
+ LuaInventoryAction *o = checkobject(L, 1);
+
+ s16 count = luaL_checkinteger(L, 2);
+
+ switch (o->m_action->getType()) {
+ case IAction::Move:
+ ((IMoveAction *)o->m_action)->count = count;
+ break;
+ case IAction::Drop:
+ ((IDropAction *)o->m_action)->count = count;
+ break;
+ case IAction::Craft:
+ ((ICraftAction *)o->m_action)->count = count;
+ break;
+ }
+
+ return 0;
+}
+
+LuaInventoryAction::LuaInventoryAction(const IAction &type) : m_action(nullptr)
+{
+ switch (type) {
+ case IAction::Move:
+ m_action = new IMoveAction();
+ break;
+ case IAction::Drop:
+ m_action = new IDropAction();
+ break;
+ case IAction::Craft:
+ m_action = new ICraftAction();
+ break;
+ }
+}
+
+LuaInventoryAction::~LuaInventoryAction()
+{
+ delete m_action;
+}
+
+void LuaInventoryAction::readFullInventoryLocationInto(
+ lua_State *L, InventoryLocation *loc, std::string *list, s16 *index)
+{
+ try {
+ loc->deSerialize(readParam<std::string>(L, 2));
+ std::string l = readParam<std::string>(L, 3);
+ *list = l;
+ *index = luaL_checkinteger(L, 4) - 1;
+ } catch (SerializationError &) {
+ }
+}
+
+int LuaInventoryAction::create_object(lua_State *L)
+{
+ IAction type;
+ std::string typeStr;
+
+ typeStr = readParam<std::string>(L, 1);
+
+ if (typeStr == "move")
+ type = IAction::Move;
+ else if (typeStr == "drop")
+ type = IAction::Drop;
+ else if (typeStr == "craft")
+ type = IAction::Craft;
+ else
+ return 0;
+
+ LuaInventoryAction *o = new LuaInventoryAction(type);
+ *(void **)(lua_newuserdata(L, sizeof(void *))) = o;
+ luaL_getmetatable(L, className);
+ lua_setmetatable(L, -2);
+ return 1;
+}
+
+int LuaInventoryAction::create(lua_State *L, const IAction &type)
+{
+ LuaInventoryAction *o = new LuaInventoryAction(type);
+ *(void **)(lua_newuserdata(L, sizeof(void *))) = o;
+ luaL_getmetatable(L, className);
+ lua_setmetatable(L, -2);
+ return 1;
+}
+
+LuaInventoryAction *LuaInventoryAction::checkobject(lua_State *L, int narg)
+{
+ return *(LuaInventoryAction **)luaL_checkudata(L, narg, className);
+}
+
+void LuaInventoryAction::Register(lua_State *L)
+{
+ lua_newtable(L);
+ int methodtable = lua_gettop(L);
+ luaL_newmetatable(L, className);
+ int metatable = lua_gettop(L);
+
+ lua_pushliteral(L, "__metatable");
+ lua_pushvalue(L, methodtable);
+ lua_settable(L, metatable);
+
+ lua_pushliteral(L, "__index");
+ lua_pushvalue(L, methodtable);
+ lua_settable(L, metatable);
+
+ lua_pushliteral(L, "__gc");
+ lua_pushcfunction(L, gc_object);
+ lua_settable(L, metatable);
+
+ lua_pushliteral(L, "__tostring");
+ lua_pushcfunction(L, mt_tostring);
+ lua_settable(L, metatable);
+
+ lua_pop(L, 1);
+
+ luaL_openlib(L, 0, methods, 0);
+ lua_pop(L, 1);
+
+ lua_register(L, className, create_object);
+}
+
+const char LuaInventoryAction::className[] = "InventoryAction";
+const luaL_Reg LuaInventoryAction::methods[] = {luamethod(LuaInventoryAction, apply),
+ luamethod(LuaInventoryAction, from), luamethod(LuaInventoryAction, to),
+ luamethod(LuaInventoryAction, craft),
+ luamethod(LuaInventoryAction, set_count), {0, 0}};
diff --git a/src/script/lua_api/l_inventoryaction.h b/src/script/lua_api/l_inventoryaction.h
new file mode 100644
index 000000000..a4cc6cbe5
--- /dev/null
+++ b/src/script/lua_api/l_inventoryaction.h
@@ -0,0 +1,74 @@
+/*
+Dragonfire
+Copyright (C) 2020 Elias Fleckenstein <eliasfleckenstein@web.de>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public License along
+with this program; if not, write to the Free Software Foundation, Inc.,
+51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+
+#include "inventorymanager.h"
+#include "lua_api/l_base.h"
+
+#define GET_MOVE_ACTION \
+ LuaInventoryAction *o = checkobject(L, 1); \
+ if (o->m_action->getType() == IAction::Craft) \
+ return 0; \
+ MoveAction *act = dynamic_cast<MoveAction *>(o->m_action);
+
+class LuaInventoryAction : public ModApiBase
+{
+private:
+ InventoryAction *m_action;
+
+ static void readFullInventoryLocationInto(lua_State *L, InventoryLocation *loc,
+ std::string *list, s16 *index);
+
+ static const char className[];
+ static const luaL_Reg methods[];
+
+ // Exported functions
+
+ // garbage collector
+ static int gc_object(lua_State *L);
+
+ // __tostring metamethod
+ static int mt_tostring(lua_State *L);
+
+ // apply(self)
+ static int l_apply(lua_State *L);
+
+ // from(self, location, list, index)
+ static int l_from(lua_State *L);
+
+ // to(self, location, list, index)
+ static int l_to(lua_State *L);
+
+ // craft(self, location)
+ static int l_craft(lua_State *L);
+
+ // set_count(self, count)
+ static int l_set_count(lua_State *L);
+
+public:
+ LuaInventoryAction(const IAction &type);
+ ~LuaInventoryAction();
+
+ // LuaInventoryAction(inventory action type)
+ // Creates an LuaInventoryAction and leaves it on top of stack
+ static int create_object(lua_State *L);
+ // Not callable from Lua
+ static int create(lua_State *L, const IAction &type);
+ static LuaInventoryAction *checkobject(lua_State *L, int narg);
+ static void Register(lua_State *L);
+};
diff --git a/src/script/lua_api/l_item.cpp b/src/script/lua_api/l_item.cpp
index 9e0da4034..b098eccf0 100644
--- a/src/script/lua_api/l_item.cpp
+++ b/src/script/lua_api/l_item.cpp
@@ -27,7 +27,12 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "server.h"
#include "inventory.h"
#include "log.h"
-
+#include "script/cpp_api/s_base.h"
+#ifndef SERVER
+#include "client/client.h"
+#include "client/renderingengine.h"
+#include "client/shader.h"
+#endif
// garbage collector
int LuaItemStack::gc_object(lua_State *L)
@@ -534,9 +539,9 @@ int ModApiItemMod::l_register_item_raw(lua_State *L)
// Get the writable item and node definition managers from the server
IWritableItemDefManager *idef =
- getServer(L)->getWritableItemDefManager();
+ getGameDef(L)->getWritableItemDefManager();
NodeDefManager *ndef =
- getServer(L)->getWritableNodeDefManager();
+ getGameDef(L)->getWritableNodeDefManager();
// Check if name is defined
std::string name;
@@ -584,8 +589,9 @@ int ModApiItemMod::l_register_item_raw(lua_State *L)
+ itos(MAX_REGISTERED_CONTENT+1)
+ ") exceeded (" + name + ")");
}
+
}
-
+
return 0; /* number of results */
}
@@ -596,12 +602,12 @@ int ModApiItemMod::l_unregister_item_raw(lua_State *L)
std::string name = luaL_checkstring(L, 1);
IWritableItemDefManager *idef =
- getServer(L)->getWritableItemDefManager();
+ getGameDef(L)->getWritableItemDefManager();
// Unregister the node
if (idef->get(name).type == ITEM_NODE) {
NodeDefManager *ndef =
- getServer(L)->getWritableNodeDefManager();
+ getGameDef(L)->getWritableNodeDefManager();
ndef->removeNode(name);
}
@@ -619,7 +625,7 @@ int ModApiItemMod::l_register_alias_raw(lua_State *L)
// Get the writable item definition manager from the server
IWritableItemDefManager *idef =
- getServer(L)->getWritableItemDefManager();
+ getGameDef(L)->getWritableItemDefManager();
idef->registerAlias(name, convert_to);
diff --git a/src/script/lua_api/l_localplayer.cpp b/src/script/lua_api/l_localplayer.cpp
index 33fa27c8b..3f4147227 100644
--- a/src/script/lua_api/l_localplayer.cpp
+++ b/src/script/lua_api/l_localplayer.cpp
@@ -17,6 +17,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
+#include "l_clientobject.h"
#include "l_localplayer.h"
#include "l_internal.h"
#include "lua_api/l_item.h"
@@ -24,7 +25,9 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "client/localplayer.h"
#include "hud.h"
#include "common/c_content.h"
+#include "client/client.h"
#include "client/content_cao.h"
+#include "client/game.h"
LuaLocalPlayer::LuaLocalPlayer(LocalPlayer *m) : m_localplayer(m)
{
@@ -60,6 +63,57 @@ int LuaLocalPlayer::l_get_velocity(lua_State *L)
return 1;
}
+int LuaLocalPlayer::l_set_velocity(lua_State *L)
+{
+ LocalPlayer *player = getobject(L, 1);
+
+ v3f pos = checkFloatPos(L, 2);
+ player->setSpeed(pos);
+
+ return 0;
+}
+
+int LuaLocalPlayer::l_get_yaw(lua_State *L)
+{
+ lua_pushnumber(L, wrapDegrees_0_360(g_game->cam_view.camera_yaw));
+ return 1;
+}
+
+int LuaLocalPlayer::l_set_yaw(lua_State *L)
+{
+ LocalPlayer *player = getobject(L, 1);
+
+ if (lua_isnumber(L, 2)) {
+ int yaw = lua_tonumber(L, 2);
+ player->setYaw(yaw);
+ g_game->cam_view.camera_yaw = yaw;
+ g_game->cam_view_target.camera_yaw = yaw;
+ }
+
+ return 0;
+}
+
+int LuaLocalPlayer::l_get_pitch(lua_State *L)
+{
+ lua_pushnumber(L, -wrapDegrees_180(g_game->cam_view.camera_pitch) );
+ return 1;
+}
+
+int LuaLocalPlayer::l_set_pitch(lua_State *L)
+{
+ LocalPlayer *player = getobject(L, 1);
+
+ if (lua_isnumber(L, 2)) {
+ int pitch = lua_tonumber(L, 2);
+ player->setPitch(pitch);
+ g_game->cam_view.camera_pitch = pitch;
+ g_game->cam_view_target.camera_pitch = pitch;
+ }
+
+ return 0;
+}
+
+
int LuaLocalPlayer::l_get_hp(lua_State *L)
{
LocalPlayer *player = getobject(L, 1);
@@ -81,10 +135,24 @@ int LuaLocalPlayer::l_get_wield_index(lua_State *L)
{
LocalPlayer *player = getobject(L, 1);
- lua_pushinteger(L, player->getWieldIndex());
+ lua_pushinteger(L, player->getWieldIndex() + 1);
return 1;
}
+// set_wield_index(self)
+int LuaLocalPlayer::l_set_wield_index(lua_State *L)
+{
+ LocalPlayer *player = getobject(L, 1);
+ u32 index = luaL_checkinteger(L, 2) - 1;
+
+ player->setWieldIndex(index);
+ g_game->processItemSelection(&g_game->runData.new_playeritem);
+ ItemStack selected_item, hand_item;
+ ItemStack &tool_item = player->getWieldedItem(&selected_item, &hand_item);
+ g_game->camera->wield(tool_item);
+ return 0;
+}
+
// get_wielded_item(self)
int LuaLocalPlayer::l_get_wielded_item(lua_State *L)
{
@@ -157,26 +225,30 @@ int LuaLocalPlayer::l_get_physics_override(lua_State *L)
{
LocalPlayer *player = getobject(L, 1);
- lua_newtable(L);
- lua_pushnumber(L, player->physics_override_speed);
- lua_setfield(L, -2, "speed");
-
- lua_pushnumber(L, player->physics_override_jump);
- lua_setfield(L, -2, "jump");
-
- lua_pushnumber(L, player->physics_override_gravity);
- lua_setfield(L, -2, "gravity");
-
- lua_pushboolean(L, player->physics_override_sneak);
- lua_setfield(L, -2, "sneak");
-
- lua_pushboolean(L, player->physics_override_sneak_glitch);
- lua_setfield(L, -2, "sneak_glitch");
+ push_physics_override(L, player->physics_override_speed, player->physics_override_jump, player->physics_override_gravity, player->physics_override_sneak, player->physics_override_sneak_glitch, player->physics_override_new_move);
+
+ return 1;
+}
- lua_pushboolean(L, player->physics_override_new_move);
- lua_setfield(L, -2, "new_move");
+// set_physics_override(self, override)
+int LuaLocalPlayer::l_set_physics_override(lua_State *L)
+{
+ LocalPlayer *player = getobject(L, 1);
+
+ player->physics_override_speed = getfloatfield_default(
+ L, 2, "speed", player->physics_override_speed);
+ player->physics_override_jump = getfloatfield_default(
+ L, 2, "jump", player->physics_override_jump);
+ player->physics_override_gravity = getfloatfield_default(
+ L, 2, "gravity", player->physics_override_gravity);
+ player->physics_override_sneak = getboolfield_default(
+ L, 2, "sneak", player->physics_override_sneak);
+ player->physics_override_sneak_glitch = getboolfield_default(
+ L, 2, "sneak_glitch", player->physics_override_sneak_glitch);
+ player->physics_override_new_move = getboolfield_default(
+ L, 2, "new_move", player->physics_override_new_move);
- return 1;
+ return 0;
}
int LuaLocalPlayer::l_get_last_pos(lua_State *L)
@@ -255,6 +327,17 @@ int LuaLocalPlayer::l_get_pos(lua_State *L)
return 1;
}
+// set_pos(self, pos)
+int LuaLocalPlayer::l_set_pos(lua_State *L)
+{
+ LocalPlayer *player = getobject(L, 1);
+
+ v3f pos = checkFloatPos(L, 2);
+ player->setPosition(pos);
+ getClient(L)->sendPlayerPos();
+ return 0;
+}
+
// get_movement_acceleration(self)
int LuaLocalPlayer::l_get_movement_acceleration(lua_State *L)
{
@@ -393,6 +476,17 @@ int LuaLocalPlayer::l_hud_get(lua_State *L)
return 1;
}
+int LuaLocalPlayer::l_get_object(lua_State *L)
+{
+ LocalPlayer *player = getobject(L, 1);
+ ClientEnvironment &env = getClient(L)->getEnv();
+ ClientActiveObject *obj = env.getGenericCAO(player->getCAO()->getId());
+
+ ClientObjectRef::create(L, obj);
+
+ return 1;
+}
+
LuaLocalPlayer *LuaLocalPlayer::checkobject(lua_State *L, int narg)
{
luaL_checktype(L, narg, LUA_TUSERDATA);
@@ -453,9 +547,15 @@ void LuaLocalPlayer::Register(lua_State *L)
const char LuaLocalPlayer::className[] = "LocalPlayer";
const luaL_Reg LuaLocalPlayer::methods[] = {
luamethod(LuaLocalPlayer, get_velocity),
+ luamethod(LuaLocalPlayer, set_velocity),
+ luamethod(LuaLocalPlayer, get_yaw),
+ luamethod(LuaLocalPlayer, set_yaw),
+ luamethod(LuaLocalPlayer, get_pitch),
+ luamethod(LuaLocalPlayer, set_pitch),
luamethod(LuaLocalPlayer, get_hp),
luamethod(LuaLocalPlayer, get_name),
luamethod(LuaLocalPlayer, get_wield_index),
+ luamethod(LuaLocalPlayer, set_wield_index),
luamethod(LuaLocalPlayer, get_wielded_item),
luamethod(LuaLocalPlayer, is_attached),
luamethod(LuaLocalPlayer, is_touching_ground),
@@ -465,6 +565,7 @@ const luaL_Reg LuaLocalPlayer::methods[] = {
luamethod(LuaLocalPlayer, is_climbing),
luamethod(LuaLocalPlayer, swimming_vertical),
luamethod(LuaLocalPlayer, get_physics_override),
+ luamethod(LuaLocalPlayer, set_physics_override),
// TODO: figure our if these are useful in any way
luamethod(LuaLocalPlayer, get_last_pos),
luamethod(LuaLocalPlayer, get_last_velocity),
@@ -474,6 +575,7 @@ const luaL_Reg LuaLocalPlayer::methods[] = {
luamethod(LuaLocalPlayer, get_control),
luamethod(LuaLocalPlayer, get_breath),
luamethod(LuaLocalPlayer, get_pos),
+ luamethod(LuaLocalPlayer, set_pos),
luamethod(LuaLocalPlayer, get_movement_acceleration),
luamethod(LuaLocalPlayer, get_movement_speed),
luamethod(LuaLocalPlayer, get_movement),
@@ -482,6 +584,7 @@ const luaL_Reg LuaLocalPlayer::methods[] = {
luamethod(LuaLocalPlayer, hud_remove),
luamethod(LuaLocalPlayer, hud_change),
luamethod(LuaLocalPlayer, hud_get),
+ luamethod(LuaLocalPlayer, get_object),
{0, 0}
};
diff --git a/src/script/lua_api/l_localplayer.h b/src/script/lua_api/l_localplayer.h
index 4413f2bdb..33e23d178 100644
--- a/src/script/lua_api/l_localplayer.h
+++ b/src/script/lua_api/l_localplayer.h
@@ -35,6 +35,21 @@ private:
// get_velocity(self)
static int l_get_velocity(lua_State *L);
+ // set_velocity(self, vel)
+ static int l_set_velocity(lua_State *L);
+
+ // get_yaw(self)
+ static int l_get_yaw(lua_State *L);
+
+ // set_yaw(self, yaw)
+ static int l_set_yaw(lua_State *L);
+
+ // get_pitch(self)
+ static int l_get_pitch(lua_State *L);
+
+ // set_pitch(self,pitch)
+ static int l_set_pitch(lua_State *L);
+
// get_hp(self)
static int l_get_hp(lua_State *L);
@@ -44,6 +59,9 @@ private:
// get_wield_index(self)
static int l_get_wield_index(lua_State *L);
+ // set_wield_index(self)
+ static int l_set_wield_index(lua_State *L);
+
// get_wielded_item(self)
static int l_get_wielded_item(lua_State *L);
@@ -56,6 +74,7 @@ private:
static int l_swimming_vertical(lua_State *L);
static int l_get_physics_override(lua_State *L);
+ static int l_set_physics_override(lua_State *L);
static int l_get_override_pos(lua_State *L);
@@ -73,6 +92,9 @@ private:
// get_pos(self)
static int l_get_pos(lua_State *L);
+ // set_pos(self, pos)
+ static int l_set_pos(lua_State *L);
+
// get_movement_acceleration(self)
static int l_get_movement_acceleration(lua_State *L);
@@ -96,6 +118,9 @@ private:
// hud_get(self, id)
static int l_hud_get(lua_State *L);
+ // get_object(self)
+ static int l_get_object(lua_State *L);
+
LocalPlayer *m_localplayer = nullptr;
public:
diff --git a/src/script/lua_api/l_mainmenu.cpp b/src/script/lua_api/l_mainmenu.cpp
index 5070ec7d4..3ea5eb4ba 100644
--- a/src/script/lua_api/l_mainmenu.cpp
+++ b/src/script/lua_api/l_mainmenu.cpp
@@ -919,6 +919,9 @@ bool ModApiMainMenu::mayModifyPath(const std::string &path)
if (fs::PathStartsWith(path, fs::RemoveRelativePathComponents(porting::path_user + DIR_DELIM "mods")))
return true;
+ if (fs::PathStartsWith(path, fs::RemoveRelativePathComponents(porting::path_user + DIR_DELIM "clientmods")))
+ return true;
+
if (fs::PathStartsWith(path, fs::RemoveRelativePathComponents(porting::path_user + DIR_DELIM "textures")))
return true;
diff --git a/src/script/lua_api/l_server.cpp b/src/script/lua_api/l_server.cpp
index 6f934bb9d..64ae924d2 100644
--- a/src/script/lua_api/l_server.cpp
+++ b/src/script/lua_api/l_server.cpp
@@ -338,6 +338,7 @@ int ModApiServer::l_kick_player(lua_State *L)
return 1;
}
+// remove_player(name)
int ModApiServer::l_remove_player(lua_State *L)
{
NO_MAP_LOCK_REQUIRED;
@@ -562,7 +563,6 @@ void ModApiServer::Initialize(lua_State *L, int top)
API_FCT(get_ban_description);
API_FCT(ban_player);
API_FCT(kick_player);
- API_FCT(remove_player);
API_FCT(unban_player_or_ip);
API_FCT(notify_authentication_modified);
diff --git a/src/script/lua_api/l_util.cpp b/src/script/lua_api/l_util.cpp
index 6490eb578..e2730c6d9 100644
--- a/src/script/lua_api/l_util.cpp
+++ b/src/script/lua_api/l_util.cpp
@@ -520,11 +520,16 @@ void ModApiUtil::InitializeClient(lua_State *L, int top)
API_FCT(compress);
API_FCT(decompress);
+ API_FCT(request_insecure_environment);
+
API_FCT(encode_base64);
API_FCT(decode_base64);
API_FCT(get_version);
API_FCT(sha1);
+
+ LuaSettings::create(L, g_settings, g_settings_path);
+ lua_setfield(L, top, "settings");
}
void ModApiUtil::InitializeAsync(lua_State *L, int top)
diff --git a/src/script/scripting_client.cpp b/src/script/scripting_client.cpp
index 6643a9509..729645678 100644
--- a/src/script/scripting_client.cpp
+++ b/src/script/scripting_client.cpp
@@ -20,9 +20,12 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "scripting_client.h"
#include "client/client.h"
+#include "client/game.h"
#include "cpp_api/s_internal.h"
#include "lua_api/l_client.h"
+#include "lua_api/l_clientobject.h"
#include "lua_api/l_env.h"
+#include "lua_api/l_inventoryaction.h"
#include "lua_api/l_item.h"
#include "lua_api/l_itemstackmeta.h"
#include "lua_api/l_minimap.h"
@@ -35,11 +38,14 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "lua_api/l_nodemeta.h"
#include "lua_api/l_localplayer.h"
#include "lua_api/l_camera.h"
+#include "lua_api/l_settings.h"
+#include "lua_api/l_http.h"
ClientScripting::ClientScripting(Client *client):
ScriptApiBase(ScriptingType::Client)
{
setGameDef(client);
+ setGame(g_game);
SCRIPTAPI_PRECHECKHEADER
@@ -73,8 +79,13 @@ void ClientScripting::InitializeModApi(lua_State *L, int top)
LuaLocalPlayer::Register(L);
LuaCamera::Register(L);
ModChannelRef::Register(L);
+ LuaSettings::Register(L);
+ ClientObjectRef::Register(L);
+ LuaInventoryAction::Register(L);
+ ModApiItemMod::Initialize(L, top);
ModApiUtil::InitializeClient(L, top);
+ ModApiHttp::Initialize(L, top);
ModApiClient::Initialize(L, top);
ModApiStorage::Initialize(L, top);
ModApiEnvMod::InitializeClient(L, top);
diff --git a/src/script/scripting_client.h b/src/script/scripting_client.h
index 3088029f0..e162f8bcf 100644
--- a/src/script/scripting_client.h
+++ b/src/script/scripting_client.h
@@ -22,6 +22,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "cpp_api/s_base.h"
#include "cpp_api/s_client.h"
+#include "cpp_api/s_cheats.h"
#include "cpp_api/s_modchannels.h"
#include "cpp_api/s_security.h"
@@ -34,7 +35,8 @@ class ClientScripting:
virtual public ScriptApiBase,
public ScriptApiSecurity,
public ScriptApiClient,
- public ScriptApiModChannels
+ public ScriptApiModChannels,
+ public ScriptApiCheats
{
public:
ClientScripting(Client *client);
diff --git a/src/unittest/test.cpp b/src/unittest/test.cpp
index a783ccd32..0f6b36649 100644
--- a/src/unittest/test.cpp
+++ b/src/unittest/test.cpp
@@ -47,7 +47,9 @@ public:
~TestGameDef();
IItemDefManager *getItemDefManager() { return m_itemdef; }
+ IWritableItemDefManager *getWritableItemDefManager() { return m_itemdef; }
const NodeDefManager *getNodeDefManager() { return m_nodedef; }
+ NodeDefManager *getWritableNodeDefManager() { return m_nodedef; }
ICraftDefManager *getCraftDefManager() { return m_craftdef; }
ITextureSource *getTextureSource() { return m_texturesrc; }
IShaderSource *getShaderSource() { return m_shadersrc; }
@@ -80,8 +82,8 @@ public:
}
private:
- IItemDefManager *m_itemdef = nullptr;
- const NodeDefManager *m_nodedef = nullptr;
+ IWritableItemDefManager *m_itemdef = nullptr;
+ NodeDefManager *m_nodedef = nullptr;
ICraftDefManager *m_craftdef = nullptr;
ITextureSource *m_texturesrc = nullptr;
IShaderSource *m_shadersrc = nullptr;