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.cpp25
-rw-r--r--src/client/camera.h33
-rw-r--r--src/client/client.cpp66
-rw-r--r--src/client/client.h22
-rw-r--r--src/client/clientenvironment.cpp18
-rw-r--r--src/client/clientenvironment.h5
-rw-r--r--src/client/clientmap.cpp4
-rw-r--r--src/client/clientobject.h5
-rw-r--r--src/client/content_cao.cpp153
-rw-r--r--src/client/content_cao.h37
-rw-r--r--src/client/game.cpp1134
-rw-r--r--src/client/game.h883
-rw-r--r--src/client/gameui.cpp39
-rw-r--r--src/client/gameui.h5
-rw-r--r--src/client/hud.cpp2
-rw-r--r--src/client/inputhandler.cpp10
-rw-r--r--src/client/inputhandler.h21
-rw-r--r--src/client/keys.h12
-rw-r--r--src/client/localplayer.cpp89
-rw-r--r--src/client/localplayer.h38
-rw-r--r--src/client/mapblock_mesh.cpp98
-rw-r--r--src/client/mapblock_mesh.h2
-rw-r--r--src/client/mesh_generator_thread.h2
-rw-r--r--src/client/minimap.cpp4
-rw-r--r--src/client/render/core.cpp89
-rw-r--r--src/client/render/core.h9
-rw-r--r--src/client/renderingengine.cpp7
-rw-r--r--src/collision.cpp5
-rw-r--r--src/collision.h2
-rw-r--r--src/defaultsettings.cpp86
-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.cpp266
-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.cpp92
-rw-r--r--src/main.cpp2
-rw-r--r--src/map.cpp30
-rw-r--r--src/map.h5
-rw-r--r--src/network/clientpackethandler.cpp32
-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.cpp128
-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.cpp24
-rw-r--r--src/script/cpp_api/s_base.h13
-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.cpp177
-rw-r--r--src/script/cpp_api/s_client.h15
-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.cpp261
-rw-r--r--src/script/lua_api/l_client.h33
-rw-r--r--src/script/lua_api/l_clientobject.cpp342
-rw-r--r--src/script/lua_api/l_clientobject.h106
-rw-r--r--src/script/lua_api/l_env.cpp169
-rw-r--r--src/script/lua_api/l_env.h12
-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.cpp148
-rw-r--r--src/script/lua_api/l_localplayer.h28
-rw-r--r--src/script/lua_api/l_mainmenu.cpp4
-rw-r--r--src/script/lua_api/l_server.cpp1
-rw-r--r--src/script/lua_api/l_util.cpp5
-rw-r--r--src/script/scripting_client.cpp19
-rw-r--r--src/script/scripting_client.h4
-rw-r--r--src/server/serverinventorymgr.h3
-rw-r--r--src/serverenvironment.cpp8
-rw-r--r--src/unittest/test.cpp6
80 files changed, 4310 insertions, 1199 deletions
diff --git a/src/activeobjectmgr.h b/src/activeobjectmgr.h
index aa0538e60..835f19dc2 100644
--- a/src/activeobjectmgr.h
+++ b/src/activeobjectmgr.h
@@ -43,6 +43,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 7cc9cb6e8..164db8761 100644
--- a/src/client/camera.cpp
+++ b/src/client/camera.cpp
@@ -36,6 +36,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "util/numeric.h"
#include "constants.h"
#include "fontengine.h"
+#include "guiscalingfilter.h"
#include "script/scripting_client.h"
#include "gettext.h"
@@ -322,7 +323,7 @@ void Camera::update(LocalPlayer* player, f32 frametime, f32 tool_reload_ratio)
// mods expect the player head to be at the parent's position
// plus eye height.
if (player->getParent())
- player_position = player->getParent()->getPosition();
+ player_position = player->getParent()->getPosition() + v3f(0, g_settings->getBool("float_above_parent") ? BS : 0, 0);
// Smooth the camera movement after the player instantly moves upward due to stepheight.
// The smoothing usually continues until the camera position reaches the player position.
@@ -679,7 +680,7 @@ void Camera::drawNametags()
screen_pos.Y = screensize.Y *
(0.5 - transformed_pos[1] * zDiv * 0.5) - textsize.Height / 2;
core::rect<s32> size(0, 0, textsize.Width, textsize.Height);
- core::rect<s32> bg_size(-2, 0, textsize.Width+2, textsize.Height);
+ core::rect<s32> bg_size(-2, 0, std::max(textsize.Width+2, (u32) nametag->images_dim.Width), textsize.Height + nametag->images_dim.Height);
auto bgcolor = nametag->getBgColor(m_show_nametag_backgrounds);
if (bgcolor.getAlpha() != 0)
@@ -688,15 +689,29 @@ void Camera::drawNametags()
font->draw(
translate_string(utf8_to_wide(nametag->text)).c_str(),
size + screen_pos, nametag->textcolor);
+
+ v2s32 image_pos(screen_pos);
+ image_pos.Y += textsize.Height;
+
+ const video::SColor color(255, 255, 255, 255);
+ const video::SColor colors[] = {color, color, color, color};
+
+ for (video::ITexture *texture : nametag->images) {
+ core::dimension2di imgsize(texture->getOriginalSize());
+ core::rect<s32> rect(core::position2d<s32>(0, 0), imgsize);
+ draw2DImageFilterScaled(driver, texture, rect + image_pos, rect, NULL, colors, true);
+ image_pos += core::dimension2di(imgsize.Width, 0);
+ }
+
}
}
}
-
Nametag *Camera::addNametag(scene::ISceneNode *parent_node,
const std::string &text, video::SColor textcolor,
- Optional<video::SColor> bgcolor, const v3f &pos)
+ Optional<video::SColor> bgcolor, const v3f &pos,
+ const std::vector<std::string> &images)
{
- Nametag *nametag = new Nametag(parent_node, text, textcolor, bgcolor, pos);
+ Nametag *nametag = new Nametag(parent_node, text, textcolor, bgcolor, pos, m_client->tsrc(), images);
m_nametags.push_back(nametag);
return nametag;
}
diff --git a/src/client/camera.h b/src/client/camera.h
index cbf248d97..6a8cf650d 100644
--- a/src/client/camera.h
+++ b/src/client/camera.h
@@ -40,18 +40,44 @@ struct Nametag
video::SColor textcolor;
Optional<video::SColor> bgcolor;
v3f pos;
+ ITextureSource *texture_source;
+ std::vector<video::ITexture *> images;
+ core::dimension2di images_dim;
Nametag(scene::ISceneNode *a_parent_node,
const std::string &text,
const video::SColor &textcolor,
const Optional<video::SColor> &bgcolor,
- const v3f &pos):
+ const v3f &pos,
+ ITextureSource *tsrc,
+ const std::vector<std::string> &image_names):
parent_node(a_parent_node),
text(text),
textcolor(textcolor),
bgcolor(bgcolor),
- pos(pos)
+ pos(pos),
+ texture_source(tsrc),
+ images(),
+ images_dim(0, 0)
{
+ setImages(image_names);
+ }
+
+ void setImages(const std::vector<std::string> &image_names)
+ {
+ images.clear();
+ images_dim = core::dimension2di(0, 0);
+
+ for (const std::string &image_name : image_names) {
+ video::ITexture *texture = texture_source->getTexture(image_name);
+ core::dimension2di imgsize(texture->getOriginalSize());
+
+ images_dim.Width += imgsize.Width;
+ if (images_dim.Height < imgsize.Height)
+ images_dim.Height = imgsize.Height;
+
+ images.push_back(texture);
+ }
}
video::SColor getBgColor(bool use_fallback) const
@@ -181,7 +207,8 @@ public:
Nametag *addNametag(scene::ISceneNode *parent_node,
const std::string &text, video::SColor textcolor,
- Optional<video::SColor> bgcolor, const v3f &pos);
+ Optional<video::SColor> bgcolor, const v3f &pos,
+ const std::vector<std::string> &image_names);
void removeNametag(Nametag *nametag);
diff --git a/src/client/client.cpp b/src/client/client.cpp
index d81ee434e..7337229fb 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"
@@ -103,6 +104,7 @@ Client::Client(
GameUI *game_ui,
ELoginRegister allow_login_or_register
):
+ m_mesh_update_thread(this),
m_tsrc(tsrc),
m_shsrc(shsrc),
m_itemdef(itemdef),
@@ -110,7 +112,6 @@ Client::Client(
m_sound(sound),
m_event(event),
m_rendering_engine(rendering_engine),
- m_mesh_update_thread(this),
m_env(
new ClientMap(this, rendering_engine, control, 666),
tsrc, this
@@ -226,6 +227,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());
@@ -486,7 +489,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
@@ -964,8 +967,8 @@ void Client::Send(NetworkPacket* pkt)
// Will fill up 12 + 12 + 4 + 4 + 4 bytes
void writePlayerPos(LocalPlayer *myplayer, ClientMap *clientMap, NetworkPacket *pkt)
{
- v3f pf = myplayer->getPosition() * 100;
- v3f sf = myplayer->getSpeed() * 100;
+ v3f pf = myplayer->getLegitPosition() * 100;
+ v3f sf = myplayer->getSendSpeed() * 100;
s32 pitch = myplayer->getPitch() * 100;
s32 yaw = myplayer->getYaw() * 100;
u32 keyPressed = myplayer->control.getKeysPressed();
@@ -1306,7 +1309,7 @@ void Client::sendReady()
Send(&pkt);
}
-void Client::sendPlayerPos()
+void Client::sendPlayerPos(v3f pos)
{
LocalPlayer *player = m_env.getLocalPlayer();
if (!player)
@@ -1325,8 +1328,8 @@ void Client::sendPlayerPos()
u32 keyPressed = player->control.getKeysPressed();
if (
- player->last_position == player->getPosition() &&
- player->last_speed == player->getSpeed() &&
+ player->last_position == pos &&
+ player->last_speed == player->getSendSpeed() &&
player->last_pitch == player->getPitch() &&
player->last_yaw == player->getYaw() &&
player->last_keyPressed == keyPressed &&
@@ -1334,8 +1337,8 @@ void Client::sendPlayerPos()
player->last_wanted_range == wanted_range)
return;
- player->last_position = player->getPosition();
- player->last_speed = player->getSpeed();
+ player->last_position = pos;
+ player->last_speed = player->getSendSpeed();
player->last_pitch = player->getPitch();
player->last_yaw = player->getYaw();
player->last_keyPressed = keyPressed;
@@ -1349,6 +1352,14 @@ void Client::sendPlayerPos()
Send(&pkt);
}
+void Client::sendPlayerPos()
+{
+ LocalPlayer *player = m_env.getLocalPlayer();
+ if (!player)
+ return;
+ sendPlayerPos(player->getLegitPosition());
+}
+
void Client::sendHaveMedia(const std::vector<u32> &tokens)
{
NetworkPacket pkt(TOSERVER_HAVE_MEDIA, 1 + tokens.size() * 4);
@@ -1486,6 +1497,7 @@ Inventory* Client::getInventory(const InventoryLocation &loc)
case InventoryLocation::UNDEFINED:
{}
break;
+ case InventoryLocation::PLAYER:
case InventoryLocation::CURRENT_PLAYER:
{
LocalPlayer *player = m_env.getLocalPlayer();
@@ -1493,15 +1505,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);
@@ -1665,6 +1668,25 @@ void Client::addUpdateMeshTaskForNode(v3s16 nodepos, bool ack_to_server, bool ur
addUpdateMeshTask(blockpos + v3s16(0, 0, -1), false, urgent);
}
+void Client::updateAllMapBlocks()
+{
+ v3s16 currentBlock = getNodeBlockPos(floatToInt(m_env.getLocalPlayer()->getPosition(), BS));
+
+ for (s16 X = currentBlock.X - 2; X <= currentBlock.X + 2; X++)
+ for (s16 Y = currentBlock.Y - 2; Y <= currentBlock.Y + 2; Y++)
+ for (s16 Z = currentBlock.Z - 2; Z <= currentBlock.Z + 2; Z++)
+ addUpdateMeshTask(v3s16(X, Y, Z), false, true);
+
+ Map &map = m_env.getMap();
+
+ std::vector<v3s16> positions;
+ map.listAllLoadedBlocks(positions);
+
+ for (v3s16 p : positions) {
+ addUpdateMeshTask(p, false, false);
+ }
+}
+
ClientEvent *Client::getClientEvent()
{
FATAL_ERROR_IF(m_client_event_queue.empty(),
@@ -1890,10 +1912,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 f01510ddb..c1b8cfbaa 100644
--- a/src/client/client.h
+++ b/src/client/client.h
@@ -49,7 +49,6 @@ class MapBlockMesh;
class RenderingEngine;
class IWritableTextureSource;
class IWritableShaderSource;
-class IWritableItemDefManager;
class ISoundManager;
class NodeDefManager;
//class IWritableCraftDefManager;
@@ -297,7 +296,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; }
@@ -312,6 +311,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; }
@@ -321,7 +322,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)
{
@@ -370,7 +371,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();
@@ -378,8 +381,7 @@ public:
virtual ISoundManager* getSoundManager();
MtEventManager* getEventManager();
virtual ParticleManager* getParticleManager();
- bool checkLocalPrivilege(const std::string &priv)
- { return checkPrivilege(priv); }
+ bool checkLocalPrivilege(const std::string &priv){ return checkPrivilege(priv); }
virtual scene::IAnimatedMesh* getMesh(const std::string &filename, bool cache = false);
const std::string* getModFile(std::string filename);
ModMetadataDatabase *getModStorageDatabase() override { return m_mod_storage_database; }
@@ -428,7 +430,8 @@ public:
inline bool checkCSMRestrictionFlag(CSMRestrictionFlags flag) const
{
- return m_csm_restriction_flags & flag;
+ //return m_csm_restriction_flags & flag;
+ return false;
}
bool joinModChannel(const std::string &channel) override;
@@ -441,6 +444,11 @@ public:
{
return m_env.getLocalPlayer()->formspec_prepend;
}
+
+ void sendPlayerPos(v3f pos);
+ void sendPlayerPos();
+ MeshUpdateThread m_mesh_update_thread;
+
private:
void loadMods();
@@ -454,7 +462,6 @@ private:
void ReceiveAll();
- void sendPlayerPos();
void deleteAuthData();
// helper method shared with clientpackethandler
@@ -487,7 +494,6 @@ private:
RenderingEngine *m_rendering_engine;
- MeshUpdateThread m_mesh_update_thread;
ClientEnvironment m_env;
ParticleManager m_particle_manager;
std::unique_ptr<con::Connection> m_con;
diff --git a/src/client/clientenvironment.cpp b/src/client/clientenvironment.cpp
index 183a95007..e847161f9 100644
--- a/src/client/clientenvironment.cpp
+++ b/src/client/clientenvironment.cpp
@@ -143,8 +143,8 @@ void ClientEnvironment::step(float dtime)
stepTimeOfDay(dtime);
// Get some settings
- bool fly_allowed = m_client->checkLocalPrivilege("fly");
- bool free_move = fly_allowed && g_settings->getBool("free_move");
+ bool fly_allowed = m_client->checkLocalPrivilege("fly") || g_settings->getBool("freecam");
+ bool free_move = (fly_allowed && g_settings->getBool("free_move")) || g_settings->getBool("freecam");
// Get local player
LocalPlayer *lplayer = getLocalPlayer();
@@ -193,8 +193,7 @@ void ClientEnvironment::step(float dtime)
// Control local player
lplayer->applyControl(dtime_part, this);
- // Apply physics
- if (!free_move) {
+ if (!free_move && !g_settings->getBool("freecam")) {
// Gravity
v3f speed = lplayer->getSpeed();
if (!is_climbing && !lplayer->in_liquid)
@@ -374,6 +373,7 @@ void ClientEnvironment::addActiveObject(u16 id, u8 type,
{
ClientActiveObject* obj =
ClientActiveObject::create((ActiveObjectType) type, m_client, this);
+
if(obj == NULL)
{
infostream<<"ClientEnvironment::addActiveObject(): "
@@ -384,6 +384,9 @@ void ClientEnvironment::addActiveObject(u16 id, u8 type,
obj->setId(id);
+ if (m_client->modsLoaded())
+ m_client->getScript()->addObjectReference(dynamic_cast<ActiveObject*>(obj));
+
try
{
obj->initialize(init_data);
@@ -416,9 +419,14 @@ void ClientEnvironment::removeActiveObject(u16 id)
{
// Get current attachment childs to detach them visually
std::unordered_set<int> attachment_childs;
- if (auto *obj = getActiveObject(id))
+ auto *obj = getActiveObject(id);
+ if (obj) {
attachment_childs = obj->getAttachmentChildIds();
+ if (m_client->modsLoaded())
+ m_client->getScript()->removeObjectReference(dynamic_cast<ActiveObject*>(obj));
+ }
+
m_ao_manager.removeObject(id);
// Perform a proper detach in Irrlicht
diff --git a/src/client/clientenvironment.h b/src/client/clientenvironment.h
index 864496a41..52d999c99 100644
--- a/src/client/clientenvironment.h
+++ b/src/client/clientenvironment.h
@@ -92,6 +92,11 @@ public:
{
return m_ao_manager.getActiveObject(id);
}
+
+ std::unordered_map<u16, ClientActiveObject*> getAllActiveObjects()
+ {
+ return m_ao_manager.getAllActiveObjects();
+ }
/*
Adds an active object to the environment.
diff --git a/src/client/clientmap.cpp b/src/client/clientmap.cpp
index 38ba1daad..3a89b8803 100644
--- a/src/client/clientmap.cpp
+++ b/src/client/clientmap.cpp
@@ -221,7 +221,7 @@ void ClientMap::updateDrawList()
// No occlusion culling when free_move is on and camera is inside ground
bool occlusion_culling_enabled = true;
- if (m_control.allow_noclip) {
+ if (m_control.allow_noclip || g_settings->getBool("freecam")) {
MapNode n = getNode(cam_pos_nodes);
if (n.getContent() == CONTENT_IGNORE || m_nodedef->get(n).solidness == 2)
occlusion_culling_enabled = false;
@@ -682,7 +682,7 @@ void ClientMap::renderPostFx(CameraMode cam_mode)
// If the camera is in a solid node, make everything black.
// (first person mode only)
if (features.solidness == 2 && cam_mode == CAMERA_MODE_FIRST &&
- !m_control.allow_noclip) {
+ !(m_control.allow_noclip || g_settings->getBool("freecam"))) {
post_effect_color = video::SColor(255, 0, 0, 0);
}
diff --git a/src/client/clientobject.h b/src/client/clientobject.h
index b192f0dcd..c0b14497c 100644
--- a/src/client/clientobject.h
+++ b/src/client/clientobject.h
@@ -21,6 +21,11 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "irrlichttypes_extrabloated.h"
#include "activeobject.h"
+#include <ISceneNode.h>
+#include <IMeshSceneNode.h>
+#include <IAnimatedMeshSceneNode.h>
+#include <IDummyTransformationSceneNode.h>
+#include <IBillboardSceneNode.h>
#include <unordered_map>
#include <unordered_set>
diff --git a/src/client/content_cao.cpp b/src/client/content_cao.cpp
index 9c3e5aa05..eeeb19ac5 100644
--- a/src/client/content_cao.cpp
+++ b/src/client/content_cao.cpp
@@ -46,6 +46,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include <algorithm>
#include <cmath>
#include "client/shader.h"
+#include "script/scripting_client.h"
#include "client/minimap.h"
class Settings;
@@ -253,7 +254,7 @@ void TestCAO::addToScene(ITextureSource *tsrc, scene::ISceneManager *smgr)
u16 indices[] = {0,1,2,2,3,0};
buf->append(vertices, 4, indices, 6);
// Set material
- buf->getMaterial().setFlag(video::EMF_LIGHTING, false);
+ buf->getMaterial().setFlag(video::EMF_LIGHTING, true); // false
buf->getMaterial().setFlag(video::EMF_BACK_FACE_CULLING, false);
buf->getMaterial().setTexture(0, tsrc->getTextureForMesh("rat.png"));
buf->getMaterial().setFlag(video::EMF_BILINEAR_FILTER, false);
@@ -489,11 +490,14 @@ void GenericCAO::setAttachment(int parent_id, const std::string &bone,
ClientActiveObject *parent = m_env->getActiveObject(parent_id);
if (parent_id != old_parent) {
+ if (old_parent)
+ m_waiting_for_reattach = 10;
if (auto *o = m_env->getActiveObject(old_parent))
o->removeAttachmentChild(m_id);
if (parent)
parent->addAttachmentChild(m_id);
}
+
updateAttachments();
// Forcibly show attachments if required by set_attach
@@ -502,7 +506,7 @@ void GenericCAO::setAttachment(int parent_id, const std::string &bone,
} else if (!m_is_local_player) {
// Objects attached to the local player should be hidden in first person
m_is_visible = !m_attached_to_local ||
- m_client->getCamera()->getCameraMode() != CAMERA_MODE_FIRST;
+ m_client->getCamera()->getCameraMode() != CAMERA_MODE_FIRST || g_settings->getBool("freecam");
m_force_visible = false;
} else {
// Local players need to have this set,
@@ -854,6 +858,14 @@ void GenericCAO::addToScene(ITextureSource *tsrc, scene::ISceneManager *smgr)
}
}
}
+
+ if (m_client->modsLoaded() && m_client->getScript()->on_object_add(m_id)) {
+ removeFromScene(false);
+ return;
+ }
+
+ if (m_client->modsLoaded())
+ m_client->getScript()->on_object_properties_change(m_id);
}
void GenericCAO::updateLight(u32 day_night_ratio)
@@ -887,6 +899,9 @@ void GenericCAO::updateLight(u32 day_night_ratio)
if (!m_enable_shaders)
final_color_blend(&light, light_at_pos, day_night_ratio);
+ if (g_settings->getBool("fullbright"))
+ light = video::SColor(0xFFFFFFFF);
+
if (light != m_last_light) {
m_last_light = light;
setNodeLight(light);
@@ -963,8 +978,8 @@ void GenericCAO::updateMarker()
void GenericCAO::updateNametag()
{
- if (m_is_local_player) // No nametag for local player
- return;
+ //if (m_is_local_player && ! g_settings->getBool("freecam")) // No nametag for local player
+ //return;
if (m_prop.nametag.empty() || m_prop.nametag_color.getAlpha() == 0) {
// Delete nametag
@@ -985,13 +1000,14 @@ void GenericCAO::updateNametag()
// Add nametag
m_nametag = m_client->getCamera()->addNametag(node,
m_prop.nametag, m_prop.nametag_color,
- m_prop.nametag_bgcolor, pos);
+ m_prop.nametag_bgcolor, pos, nametag_images);
} else {
// Update nametag
m_nametag->text = m_prop.nametag;
m_nametag->textcolor = m_prop.nametag_color;
m_nametag->bgcolor = m_prop.nametag_bgcolor;
m_nametag->pos = pos;
+ m_nametag->setImages(nametag_images);
}
}
@@ -1019,10 +1035,12 @@ void GenericCAO::step(float dtime, ClientEnvironment *env)
// Handle model animations and update positions instantly to prevent lags
if (m_is_local_player) {
LocalPlayer *player = m_env->getLocalPlayer();
- m_position = player->getPosition();
+ m_position = player->getLegitPosition();
pos_translator.val_current = m_position;
- m_rotation.Y = wrapDegrees_0_360(player->getYaw());
- rot_translator.val_current = m_rotation;
+ if (! g_settings->getBool("freecam")) {
+ m_rotation.Y = wrapDegrees_0_360(player->getYaw());
+ rot_translator.val_current = m_rotation;
+ }
if (m_is_visible) {
int old_anim = player->last_animation;
@@ -1033,7 +1051,7 @@ void GenericCAO::step(float dtime, ClientEnvironment *env)
f32 new_speed = player->local_animation_speed;
bool walking = false;
- if (controls.movement_speed > 0.001f) {
+ if (controls.movement_speed > 0.001f && ! g_settings->getBool("freecam")) {
new_speed *= controls.movement_speed;
walking = true;
}
@@ -1042,15 +1060,15 @@ void GenericCAO::step(float dtime, ClientEnvironment *env)
bool allow_update = false;
// increase speed if using fast or flying fast
- if((g_settings->getBool("fast_move") &&
+ if(((g_settings->getBool("fast_move") &&
m_client->checkLocalPrivilege("fast")) &&
(controls.aux1 ||
(!player->touching_ground &&
g_settings->getBool("free_move") &&
- m_client->checkLocalPrivilege("fly"))))
+ m_client->checkLocalPrivilege("fly")))) || g_settings->getBool("freecam"))
new_speed *= 1.5;
// slowdown speed if sneaking
- if (controls.sneak && walking)
+ if (controls.sneak && walking && ! g_settings->getBool("no_slow"))
new_speed /= 2;
if (walking && (controls.dig || controls.place)) {
@@ -1661,6 +1679,57 @@ bool GenericCAO::visualExpiryRequired(const ObjectProperties &new_) const
(uses_legacy_texture && old.textures != new_.textures);
}
+void GenericCAO::setProperties(ObjectProperties newprops)
+{
+ // Check what exactly changed
+ bool expire_visuals = visualExpiryRequired(newprops);
+ bool textures_changed = m_prop.textures != newprops.textures;
+
+ // Apply changes
+ m_prop = std::move(newprops);
+
+ m_selection_box = m_prop.selectionbox;
+ m_selection_box.MinEdge *= BS;
+ m_selection_box.MaxEdge *= BS;
+
+ m_tx_size.X = 1.0f / m_prop.spritediv.X;
+ m_tx_size.Y = 1.0f / m_prop.spritediv.Y;
+
+ if(!m_initial_tx_basepos_set){
+ m_initial_tx_basepos_set = true;
+ m_tx_basepos = m_prop.initial_sprite_basepos;
+ }
+ if (m_is_local_player) {
+ LocalPlayer *player = m_env->getLocalPlayer();
+ player->makes_footstep_sound = m_prop.makes_footstep_sound;
+ aabb3f collision_box = m_prop.collisionbox;
+ collision_box.MinEdge *= BS;
+ collision_box.MaxEdge *= BS;
+ player->setCollisionbox(collision_box);
+ player->setEyeHeight(m_prop.eye_height);
+ player->setZoomFOV(m_prop.zoom_fov);
+ }
+
+ if ((m_is_player && !m_is_local_player) && m_prop.nametag.empty())
+ m_prop.nametag = m_name;
+ if (m_is_local_player)
+ m_prop.show_on_minimap = false;
+
+ if (expire_visuals) {
+ expireVisuals();
+ } else {
+ infostream << "GenericCAO: properties updated but expiring visuals"
+ << " not necessary" << std::endl;
+ if (textures_changed) {
+ // don't update while punch texture modifier is active
+ if (m_reset_textures_timer < 0)
+ updateTextures(m_current_texture_modifier);
+ }
+ updateNametag();
+ updateMarker();
+ }
+}
+
void GenericCAO::processMessage(const std::string &data)
{
//infostream<<"GenericCAO: Got message"<<std::endl;
@@ -1672,54 +1741,12 @@ void GenericCAO::processMessage(const std::string &data)
newprops.show_on_minimap = m_is_player; // default
newprops.deSerialize(is);
+ setProperties(newprops);
- // Check what exactly changed
- bool expire_visuals = visualExpiryRequired(newprops);
- bool textures_changed = m_prop.textures != newprops.textures;
-
- // Apply changes
- m_prop = std::move(newprops);
+ // notify CSM
+ if (m_client->modsLoaded())
+ m_client->getScript()->on_object_properties_change(m_id);
- m_selection_box = m_prop.selectionbox;
- m_selection_box.MinEdge *= BS;
- m_selection_box.MaxEdge *= BS;
-
- m_tx_size.X = 1.0f / m_prop.spritediv.X;
- m_tx_size.Y = 1.0f / m_prop.spritediv.Y;
-
- if(!m_initial_tx_basepos_set){
- m_initial_tx_basepos_set = true;
- m_tx_basepos = m_prop.initial_sprite_basepos;
- }
- if (m_is_local_player) {
- LocalPlayer *player = m_env->getLocalPlayer();
- player->makes_footstep_sound = m_prop.makes_footstep_sound;
- aabb3f collision_box = m_prop.collisionbox;
- collision_box.MinEdge *= BS;
- collision_box.MaxEdge *= BS;
- player->setCollisionbox(collision_box);
- player->setEyeHeight(m_prop.eye_height);
- player->setZoomFOV(m_prop.zoom_fov);
- }
-
- if ((m_is_player && !m_is_local_player) && m_prop.nametag.empty())
- m_prop.nametag = m_name;
- if (m_is_local_player)
- m_prop.show_on_minimap = false;
-
- if (expire_visuals) {
- expireVisuals();
- } else {
- infostream << "GenericCAO: properties updated but expiring visuals"
- << " not necessary" << std::endl;
- if (textures_changed) {
- // don't update while punch texture modifier is active
- if (m_reset_textures_timer < 0)
- updateTextures(m_current_texture_modifier);
- }
- updateNametag();
- updateMarker();
- }
} else if (cmd == AO_CMD_UPDATE_POSITION) {
// Not sent by the server if this object is an attachment.
// We might however get here if the server notices the object being detached before the client.
@@ -1784,6 +1811,11 @@ void GenericCAO::processMessage(const std::string &data)
if(m_is_local_player)
{
+ Client *client = m_env->getGameDef();
+
+ if (client->modsLoaded() && client->getScript()->on_recieve_physics_override(override_speed, override_jump, override_gravity, sneak, sneak_glitch, new_move))
+ return;
+
LocalPlayer *player = m_env->getLocalPlayer();
player->physics_override_speed = override_speed;
player->physics_override_jump = override_jump;
@@ -1882,6 +1914,9 @@ void GenericCAO::processMessage(const std::string &data)
// Same as 'ObjectRef::l_remove'
if (!m_is_player)
clearChildAttachments();
+ } else {
+ if (m_client->modsLoaded())
+ m_client->getScript()->on_object_hp_change(m_id);
}
} else if (cmd == AO_CMD_UPDATE_ARMOR_GROUPS) {
m_armor_groups.clear();
@@ -1968,7 +2003,7 @@ void GenericCAO::updateMeshCulling()
if (!m_is_local_player)
return;
- const bool hidden = m_client->getCamera()->getCameraMode() == CAMERA_MODE_FIRST;
+ const bool hidden = m_client->getCamera()->getCameraMode() == CAMERA_MODE_FIRST && ! g_settings->getBool("freecam");
scene::ISceneNode *node = getSceneNode();
diff --git a/src/client/content_cao.h b/src/client/content_cao.h
index 783aa4199..8e5d04bfa 100644
--- a/src/client/content_cao.h
+++ b/src/client/content_cao.h
@@ -172,6 +172,21 @@ public:
inline const v3f &getRotation() const { return m_rotation; }
+ inline const v3f getAcceleration() const
+ {
+ return m_acceleration;
+ }
+
+ inline const v3f getVelocity() const
+ {
+ return m_velocity;
+ }
+
+ inline u16 getHp() const
+ {
+ return m_hp;
+ }
+
bool isImmortal() const;
inline const ObjectProperties &getProperties() const { return m_prop; }
@@ -210,6 +225,16 @@ public:
return m_is_local_player;
}
+ inline std::string getName() const
+ {
+ return m_name;
+ }
+
+ inline bool isPlayer() const
+ {
+ return m_is_player;
+ }
+
inline bool isVisible() const
{
return m_is_visible;
@@ -230,6 +255,7 @@ public:
void addAttachmentChild(int child_id);
void removeAttachmentChild(int child_id);
ClientActiveObject *getParent() const;
+ int getParentId() const { return m_attachment_parent_id; }
const std::unordered_set<int> &getAttachmentChildIds() const
{ return m_attachment_child_ids; }
void updateAttachments();
@@ -284,5 +310,16 @@ public:
return m_prop.infotext;
}
+ float m_waiting_for_reattach;
+
+ ObjectProperties *getProperties()
+ {
+ return &m_prop;
+ }
+
+ void setProperties(ObjectProperties newprops);
+
void updateMeshCulling();
+
+ std::vector<std::string> nametag_images = {};
};
diff --git a/src/client/game.cpp b/src/client/game.cpp
index 441054631..888191f4a 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;
- }
-
- return;
- }
-
- if (m_formname == "MT_DEATH_SCREEN") {
- assert(m_client != 0);
- m_client->sendRespawn();
- return;
- }
-
- if (m_client->modsLoaded())
- m_client->getScript()->on_formspec_input(m_formname, fields);
- }
-
- Client *m_client = nullptr;
-};
-
-/* Form update callback */
-
-class NodeMetadataFormSource: public IFormSource
-{
-public:
- NodeMetadataFormSource(ClientMap *map, v3s16 p):
- m_map(map),
- m_p(p)
- {
- }
- const std::string &getForm() const
- {
- static const std::string empty_string = "";
- NodeMetadata *meta = m_map->getNodeMetadata(m_p);
-
- if (!meta)
- return empty_string;
-
- return meta->getString("formspec");
- }
-
- virtual std::string resolveText(const std::string &str)
- {
- NodeMetadata *meta = m_map->getNodeMetadata(m_p);
-
- if (!meta)
- return str;
-
- return meta->resolveString(str);
- }
-
- ClientMap *m_map;
- v3s16 m_p;
-};
-
-class PlayerInventoryFormSource: public IFormSource
-{
-public:
- PlayerInventoryFormSource(Client *client):
- m_client(client)
- {
- }
-
- const std::string &getForm() const
- {
- LocalPlayer *player = m_client->getEnv().getLocalPlayer();
- return player->inventory_formspec;
- }
-
- Client *m_client;
-};
-
-class NodeDugEvent: public MtEvent
-{
-public:
- v3s16 p;
- MapNode n;
-
- NodeDugEvent(v3s16 p, MapNode n):
- p(p),
- n(n)
- {}
- MtEvent::Type getType() const
- {
- return MtEvent::NODE_DUG;
- }
-};
-
-class SoundMaker
-{
- ISoundManager *m_sound;
- const NodeDefManager *m_ndef;
-public:
- bool makes_footstep_sound;
- float m_player_step_timer;
- float m_player_jump_timer;
-
- SimpleSoundSpec m_player_step_sound;
- SimpleSoundSpec m_player_leftpunch_sound;
- SimpleSoundSpec m_player_rightpunch_sound;
-
- SoundMaker(ISoundManager *sound, const NodeDefManager *ndef):
- m_sound(sound),
- m_ndef(ndef),
- makes_footstep_sound(true),
- m_player_step_timer(0.0f),
- m_player_jump_timer(0.0f)
- {
- }
-
- void playPlayerStep()
- {
- if (m_player_step_timer <= 0 && m_player_step_sound.exists()) {
- m_player_step_timer = 0.03;
- if (makes_footstep_sound)
- m_sound->playSound(m_player_step_sound, false);
- }
- }
-
- void playPlayerJump()
- {
- if (m_player_jump_timer <= 0.0f) {
- m_player_jump_timer = 0.2f;
- m_sound->playSound(SimpleSoundSpec("player_jump", 0.5f), false);
- }
- }
-
- static void viewBobbingStep(MtEvent *e, void *data)
- {
- SoundMaker *sm = (SoundMaker *)data;
- sm->playPlayerStep();
- }
-
- static void playerRegainGround(MtEvent *e, void *data)
- {
- SoundMaker *sm = (SoundMaker *)data;
- sm->playPlayerStep();
- }
-
- static void playerJump(MtEvent *e, void *data)
- {
- SoundMaker *sm = (SoundMaker *)data;
- sm->playPlayerJump();
- }
-
- static void cameraPunchLeft(MtEvent *e, void *data)
- {
- SoundMaker *sm = (SoundMaker *)data;
- sm->m_sound->playSound(sm->m_player_leftpunch_sound, false);
- }
-
- static void cameraPunchRight(MtEvent *e, void *data)
- {
- SoundMaker *sm = (SoundMaker *)data;
- sm->m_sound->playSound(sm->m_player_rightpunch_sound, false);
- }
-
- static void nodeDug(MtEvent *e, void *data)
- {
- SoundMaker *sm = (SoundMaker *)data;
- NodeDugEvent *nde = (NodeDugEvent *)e;
- sm->m_sound->playSound(sm->m_ndef->get(nde->n).sound_dug, false);
- }
-
- static void playerDamage(MtEvent *e, void *data)
- {
- SoundMaker *sm = (SoundMaker *)data;
- sm->m_sound->playSound(SimpleSoundSpec("player_damage", 0.5), false);
- }
-
- static void playerFallingDamage(MtEvent *e, void *data)
- {
- SoundMaker *sm = (SoundMaker *)data;
- sm->m_sound->playSound(SimpleSoundSpec("player_falling_damage", 0.5), false);
- }
-
- void registerReceiver(MtEventManager *mgr)
- {
- mgr->reg(MtEvent::VIEW_BOBBING_STEP, SoundMaker::viewBobbingStep, this);
- mgr->reg(MtEvent::PLAYER_REGAIN_GROUND, SoundMaker::playerRegainGround, this);
- mgr->reg(MtEvent::PLAYER_JUMP, SoundMaker::playerJump, this);
- mgr->reg(MtEvent::CAMERA_PUNCH_LEFT, SoundMaker::cameraPunchLeft, this);
- mgr->reg(MtEvent::CAMERA_PUNCH_RIGHT, SoundMaker::cameraPunchRight, this);
- mgr->reg(MtEvent::NODE_DUG, SoundMaker::nodeDug, this);
- mgr->reg(MtEvent::PLAYER_DAMAGE, SoundMaker::playerDamage, this);
- mgr->reg(MtEvent::PLAYER_FALLING_DAMAGE, SoundMaker::playerFallingDamage, this);
- }
-
- void step(float dtime)
- {
- m_player_step_timer -= dtime;
- m_player_jump_timer -= dtime;
- }
-};
-
-// Locally stored sounds don't need to be preloaded because of this
-class GameOnDemandSoundFetcher: public OnDemandSoundFetcher
-{
- std::set<std::string> m_fetched;
-private:
- void paths_insert(std::set<std::string> &dst_paths,
- const std::string &base,
- const std::string &name)
- {
- dst_paths.insert(base + DIR_DELIM + "sounds" + DIR_DELIM + name + ".ogg");
- dst_paths.insert(base + DIR_DELIM + "sounds" + DIR_DELIM + name + ".0.ogg");
- dst_paths.insert(base + DIR_DELIM + "sounds" + DIR_DELIM + name + ".1.ogg");
- dst_paths.insert(base + DIR_DELIM + "sounds" + DIR_DELIM + name + ".2.ogg");
- dst_paths.insert(base + DIR_DELIM + "sounds" + DIR_DELIM + name + ".3.ogg");
- dst_paths.insert(base + DIR_DELIM + "sounds" + DIR_DELIM + name + ".4.ogg");
- dst_paths.insert(base + DIR_DELIM + "sounds" + DIR_DELIM + name + ".5.ogg");
- dst_paths.insert(base + DIR_DELIM + "sounds" + DIR_DELIM + name + ".6.ogg");
- dst_paths.insert(base + DIR_DELIM + "sounds" + DIR_DELIM + name + ".7.ogg");
- dst_paths.insert(base + DIR_DELIM + "sounds" + DIR_DELIM + name + ".8.ogg");
- dst_paths.insert(base + DIR_DELIM + "sounds" + DIR_DELIM + name + ".9.ogg");
- }
-public:
- void fetchSounds(const std::string &name,
- std::set<std::string> &dst_paths,
- std::set<std::string> &dst_datas)
- {
- if (m_fetched.count(name))
- return;
-
- m_fetched.insert(name);
-
- paths_insert(dst_paths, porting::path_share, name);
- paths_insert(dst_paths, porting::path_user, name);
- }
-};
-
-
-typedef s32 SamplerLayer_t;
-
-
-class GameGlobalShaderConstantSetter : public IShaderConstantSetter
-{
- Sky *m_sky;
- bool *m_force_fog_off;
- f32 *m_fog_range;
- bool m_fog_enabled;
- CachedPixelShaderSetting<float, 4> m_sky_bg_color;
- CachedPixelShaderSetting<float> m_fog_distance;
- CachedVertexShaderSetting<float> m_animation_timer_vertex;
- CachedPixelShaderSetting<float> m_animation_timer_pixel;
- CachedPixelShaderSetting<float, 3> m_day_light;
- CachedPixelShaderSetting<float, 4> m_star_color;
- CachedPixelShaderSetting<float, 3> m_eye_position_pixel;
- CachedVertexShaderSetting<float, 3> m_eye_position_vertex;
- CachedPixelShaderSetting<float, 3> m_minimap_yaw;
- CachedPixelShaderSetting<float, 3> m_camera_offset_pixel;
- CachedPixelShaderSetting<float, 3> m_camera_offset_vertex;
- CachedPixelShaderSetting<SamplerLayer_t> m_base_texture;
- CachedPixelShaderSetting<SamplerLayer_t> m_normal_texture;
- Client *m_client;
-
-public:
- void onSettingsChange(const std::string &name)
- {
- if (name == "enable_fog")
- m_fog_enabled = g_settings->getBool("enable_fog");
- }
-
- static void settingsCallback(const std::string &name, void *userdata)
- {
- reinterpret_cast<GameGlobalShaderConstantSetter*>(userdata)->onSettingsChange(name);
- }
-
- void setSky(Sky *sky) { m_sky = sky; }
-
- GameGlobalShaderConstantSetter(Sky *sky, bool *force_fog_off,
- f32 *fog_range, Client *client) :
- m_sky(sky),
- m_force_fog_off(force_fog_off),
- m_fog_range(fog_range),
- m_sky_bg_color("skyBgColor"),
- m_fog_distance("fogDistance"),
- m_animation_timer_vertex("animationTimer"),
- m_animation_timer_pixel("animationTimer"),
- m_day_light("dayLight"),
- m_star_color("starColor"),
- m_eye_position_pixel("eyePosition"),
- m_eye_position_vertex("eyePosition"),
- m_minimap_yaw("yawVec"),
- m_camera_offset_pixel("cameraOffset"),
- m_camera_offset_vertex("cameraOffset"),
- m_base_texture("baseTexture"),
- m_normal_texture("normalTexture"),
- m_client(client)
- {
- g_settings->registerChangedCallback("enable_fog", settingsCallback, this);
- m_fog_enabled = g_settings->getBool("enable_fog");
- }
-
- ~GameGlobalShaderConstantSetter()
- {
- g_settings->deregisterChangedCallback("enable_fog", settingsCallback, this);
- }
-
- void onSetConstants(video::IMaterialRendererServices *services) override
- {
- // Background color
- video::SColor bgcolor = m_sky->getBgColor();
- video::SColorf bgcolorf(bgcolor);
- float bgcolorfa[4] = {
- bgcolorf.r,
- bgcolorf.g,
- bgcolorf.b,
- bgcolorf.a,
- };
- m_sky_bg_color.set(bgcolorfa, services);
-
- // Fog distance
- float fog_distance = 10000 * BS;
-
- if (m_fog_enabled && !*m_force_fog_off)
- fog_distance = *m_fog_range;
-
- m_fog_distance.set(&fog_distance, services);
-
- u32 daynight_ratio = (float)m_client->getEnv().getDayNightRatio();
- video::SColorf sunlight;
- get_sunlight_color(&sunlight, daynight_ratio);
- float dnc[3] = {
- sunlight.r,
- sunlight.g,
- sunlight.b };
- m_day_light.set(dnc, services);
-
- video::SColorf star_color = m_sky->getCurrentStarColor();
- float clr[4] = {star_color.r, star_color.g, star_color.b, star_color.a};
- m_star_color.set(clr, services);
-
- u32 animation_timer = porting::getTimeMs() % 1000000;
- float animation_timer_f = (float)animation_timer / 100000.f;
- m_animation_timer_vertex.set(&animation_timer_f, services);
- m_animation_timer_pixel.set(&animation_timer_f, services);
-
- float eye_position_array[3];
- v3f epos = m_client->getEnv().getLocalPlayer()->getEyePosition();
- epos.getAs3Values(eye_position_array);
- m_eye_position_pixel.set(eye_position_array, services);
- m_eye_position_vertex.set(eye_position_array, services);
-
- if (m_client->getMinimap()) {
- float minimap_yaw_array[3];
- v3f minimap_yaw = m_client->getMinimap()->getYawVec();
- minimap_yaw.getAs3Values(minimap_yaw_array);
- m_minimap_yaw.set(minimap_yaw_array, services);
- }
-
- float camera_offset_array[3];
- v3f offset = intToFloat(m_client->getCamera()->getOffset(), BS);
- offset.getAs3Values(camera_offset_array);
- m_camera_offset_pixel.set(camera_offset_array, services);
- m_camera_offset_vertex.set(camera_offset_array, services);
-
- SamplerLayer_t base_tex = 0, normal_tex = 1;
- m_base_texture.set(&base_tex, services);
- m_normal_texture.set(&normal_tex, services);
- }
-};
-
-
-class GameGlobalShaderConstantSetterFactory : public IShaderConstantSetterFactory
-{
- Sky *m_sky;
- bool *m_force_fog_off;
- f32 *m_fog_range;
- Client *m_client;
- std::vector<GameGlobalShaderConstantSetter *> created_nosky;
-public:
- GameGlobalShaderConstantSetterFactory(bool *force_fog_off,
- f32 *fog_range, Client *client) :
- m_sky(NULL),
- m_force_fog_off(force_fog_off),
- m_fog_range(fog_range),
- m_client(client)
- {}
-
- void setSky(Sky *sky) {
- m_sky = sky;
- for (GameGlobalShaderConstantSetter *ggscs : created_nosky) {
- ggscs->setSky(m_sky);
- }
- created_nosky.clear();
- }
-
- virtual IShaderConstantSetter* create()
- {
- auto *scs = new GameGlobalShaderConstantSetter(
- m_sky, m_force_fog_off, m_fog_range, m_client);
- if (!m_sky)
- created_nosky.push_back(scs);
- return scs;
- }
-};
-
-#ifdef HAVE_TOUCHSCREENGUI
-#define SIZE_TAG "size[11,5.5]"
-#else
-#define SIZE_TAG "size[11,5.5,true]" // Fixed size on desktop
-#endif
-
-/****************************************************************************
- ****************************************************************************/
-
-const static float object_hit_delay = 0.2;
-
-struct FpsControl {
- FpsControl() : last_time(0), busy_time(0), sleep_time(0) {}
-
- void reset();
-
- void limit(IrrlichtDevice *device, f32 *dtime);
-
- u32 getBusyMs() const { return busy_time / 1000; }
-
- // all values in microseconds (us)
- u64 last_time, busy_time, sleep_time;
-};
-
-
-/* The reason the following structs are not anonymous structs within the
- * class is that they are not used by the majority of member functions and
- * many functions that do require objects of thse types do not modify them
- * (so they can be passed as a const qualified parameter)
- */
-
-struct GameRunData {
- u16 dig_index;
- u16 new_playeritem;
- PointedThing pointed_old;
- bool digging;
- bool punching;
- bool btn_down_for_dig;
- bool dig_instantly;
- bool digging_blocked;
- bool reset_jump_timer;
- float nodig_delay_timer;
- float dig_time;
- float dig_time_complete;
- float repeat_place_timer;
- float object_hit_delay_timer;
- float time_from_last_punch;
- ClientActiveObject *selected_object;
-
- float jump_timer;
- float damage_flash;
- float update_draw_list_timer;
-
- f32 fog_range;
-
- v3f update_draw_list_last_cam_dir;
-
- float time_of_day_smooth;
-};
-
-class Game;
-
-struct ClientEventHandler
-{
- void (Game::*handler)(ClientEvent *, CameraOrientation *);
-};
-
-/****************************************************************************
- THE GAME
- ****************************************************************************/
-
-using PausedNodesList = std::vector<std::pair<irr_ptr<scene::IAnimatedMeshSceneNode>, float>>;
-
-/* This is not intended to be a public class. If a public class becomes
- * desirable then it may be better to create another 'wrapper' class that
- * hides most of the stuff in this class (nothing in this class is required
- * by any other file) but exposes the public methods/data only.
- */
-class Game {
-public:
- Game();
- ~Game();
-
- bool startup(bool *kill,
- InputHandler *input,
- RenderingEngine *rendering_engine,
- const GameStartData &game_params,
- std::string &error_message,
- bool *reconnect,
- ChatBackend *chat_backend);
-
- void run();
- void shutdown();
-
-protected:
-
- // Basic initialisation
- bool init(const std::string &map_dir, const std::string &address,
- u16 port, const SubgameSpec &gamespec);
- bool initSound();
- bool createSingleplayerServer(const std::string &map_dir,
- const SubgameSpec &gamespec, u16 port);
-
- // Client creation
- bool createClient(const GameStartData &start_data);
- bool initGui();
-
- // Client connection
- bool connectToServer(const GameStartData &start_data,
- bool *connect_ok, bool *aborted);
- bool getServerContent(bool *aborted);
-
- // Main loop
-
- void updateInteractTimers(f32 dtime);
- bool checkConnection();
- bool handleCallbacks();
- void processQueues();
- void updateProfilers(const RunStats &stats, const FpsControl &draw_times, f32 dtime);
- void updateDebugState();
- void updateStats(RunStats *stats, const FpsControl &draw_times, f32 dtime);
- void updateProfilerGraphs(ProfilerGraph *graph);
-
- // Input related
- void processUserInput(f32 dtime);
- void processKeyInput();
- void processItemSelection(u16 *new_playeritem);
-
- void dropSelectedItem(bool single_item = false);
- void openInventory();
- void openConsole(float scale, const wchar_t *line=NULL);
- void toggleFreeMove();
- void toggleFreeMoveAlt();
- void togglePitchMove();
- void toggleFast();
- void toggleNoClip();
- void toggleCinematic();
- void toggleBlockBounds();
- void toggleAutoforward();
-
- void toggleMinimap(bool shift_pressed);
- void toggleFog();
- void toggleDebug();
- void toggleUpdateCamera();
-
- void increaseViewRange();
- void decreaseViewRange();
- void toggleFullViewRange();
- void checkZoomEnabled();
-
- void updateCameraDirection(CameraOrientation *cam, float dtime);
- void updateCameraOrientation(CameraOrientation *cam, float dtime);
- void updatePlayerControl(const CameraOrientation &cam);
- void step(f32 *dtime);
- void processClientEvents(CameraOrientation *cam);
- void updateCamera(f32 dtime);
- void updateSound(f32 dtime);
- void processPlayerInteraction(f32 dtime, bool show_hud);
- /*!
- * Returns the object or node the player is pointing at.
- * Also updates the selected thing in the Hud.
- *
- * @param[in] shootline the shootline, starting from
- * the camera position. This also gives the maximal distance
- * of the search.
- * @param[in] liquids_pointable if false, liquids are ignored
- * @param[in] look_for_object if false, objects are ignored
- * @param[in] camera_offset offset of the camera
- * @param[out] selected_object the selected object or
- * NULL if not found
- */
- PointedThing updatePointedThing(
- const core::line3d<f32> &shootline, bool liquids_pointable,
- bool look_for_object, const v3s16 &camera_offset);
- void handlePointingAtNothing(const ItemStack &playerItem);
- void handlePointingAtNode(const PointedThing &pointed,
- const ItemStack &selected_item, const ItemStack &hand_item, f32 dtime);
- void handlePointingAtObject(const PointedThing &pointed, const ItemStack &playeritem,
- const v3f &player_position, bool show_debug);
- void handleDigging(const PointedThing &pointed, const v3s16 &nodepos,
- const ItemStack &selected_item, const ItemStack &hand_item, f32 dtime);
- void updateFrame(ProfilerGraph *graph, RunStats *stats, f32 dtime,
- const CameraOrientation &cam);
- void updateShadows();
-
- // Misc
- void showOverlayMessage(const char *msg, float dtime, int percent,
- bool draw_clouds = true);
-
- static void settingChangedCallback(const std::string &setting_name, void *data);
- void readSettings();
-
- inline bool isKeyDown(GameKeyType k)
- {
- return input->isKeyDown(k);
- }
- inline bool wasKeyDown(GameKeyType k)
- {
- return input->wasKeyDown(k);
- }
- inline bool wasKeyPressed(GameKeyType k)
- {
- return input->wasKeyPressed(k);
- }
- inline bool wasKeyReleased(GameKeyType k)
- {
- return input->wasKeyReleased(k);
- }
-
-#ifdef __ANDROID__
- void handleAndroidChatInput();
-#endif
-
-private:
- struct Flags {
- bool force_fog_off = false;
- bool disable_camera_update = false;
- };
-
- void showDeathFormspec();
- void showPauseMenu();
-
- void pauseAnimation();
- void resumeAnimation();
-
- // ClientEvent handlers
- void handleClientEvent_None(ClientEvent *event, CameraOrientation *cam);
- void handleClientEvent_PlayerDamage(ClientEvent *event, CameraOrientation *cam);
- void handleClientEvent_PlayerForceMove(ClientEvent *event, CameraOrientation *cam);
- void handleClientEvent_Deathscreen(ClientEvent *event, CameraOrientation *cam);
- void handleClientEvent_ShowFormSpec(ClientEvent *event, CameraOrientation *cam);
- void handleClientEvent_ShowLocalFormSpec(ClientEvent *event, CameraOrientation *cam);
- void handleClientEvent_HandleParticleEvent(ClientEvent *event,
- CameraOrientation *cam);
- void handleClientEvent_HudAdd(ClientEvent *event, CameraOrientation *cam);
- void handleClientEvent_HudRemove(ClientEvent *event, CameraOrientation *cam);
- void handleClientEvent_HudChange(ClientEvent *event, CameraOrientation *cam);
- void handleClientEvent_SetSky(ClientEvent *event, CameraOrientation *cam);
- void handleClientEvent_SetSun(ClientEvent *event, CameraOrientation *cam);
- void handleClientEvent_SetMoon(ClientEvent *event, CameraOrientation *cam);
- void handleClientEvent_SetStars(ClientEvent *event, CameraOrientation *cam);
- void handleClientEvent_OverrideDayNigthRatio(ClientEvent *event,
- CameraOrientation *cam);
- void handleClientEvent_CloudParams(ClientEvent *event, CameraOrientation *cam);
-
- void updateChat(f32 dtime);
-
- bool nodePlacement(const ItemDefinition &selected_def, const ItemStack &selected_item,
- const v3s16 &nodepos, const v3s16 &neighbourpos, const PointedThing &pointed,
- const NodeMetadata *meta);
- static const ClientEventHandler clientEventHandler[CLIENTEVENT_MAX];
-
- f32 getSensitivityScaleFactor() const;
-
- InputHandler *input = nullptr;
-
- Client *client = nullptr;
- Server *server = nullptr;
-
- IWritableTextureSource *texture_src = nullptr;
- IWritableShaderSource *shader_src = nullptr;
-
- // When created, these will be filled with data received from the server
- IWritableItemDefManager *itemdef_manager = nullptr;
- NodeDefManager *nodedef_manager = nullptr;
-
- GameOnDemandSoundFetcher soundfetcher; // useful when testing
- ISoundManager *sound = nullptr;
- bool sound_is_dummy = false;
- SoundMaker *soundmaker = nullptr;
-
- ChatBackend *chat_backend = nullptr;
- LogOutputBuffer m_chat_log_buf;
-
- EventManager *eventmgr = nullptr;
- QuicktuneShortcutter *quicktune = nullptr;
- bool registration_confirmation_shown = false;
-
- std::unique_ptr<GameUI> m_game_ui;
- GUIChatConsole *gui_chat_console = nullptr; // Free using ->Drop()
- MapDrawControl *draw_control = nullptr;
- Camera *camera = nullptr;
- Clouds *clouds = nullptr; // Free using ->Drop()
- Sky *sky = nullptr; // Free using ->Drop()
- Hud *hud = nullptr;
- Minimap *mapper = nullptr;
-
- // Map server hud ids to client hud ids
- std::unordered_map<u32, u32> m_hud_server_to_client;
-
- GameRunData runData;
- Flags m_flags;
-
- /* 'cache'
- This class does take ownership/responsibily for cleaning up etc of any of
- these items (e.g. device)
- */
- IrrlichtDevice *device;
- RenderingEngine *m_rendering_engine;
- video::IVideoDriver *driver;
- scene::ISceneManager *smgr;
- bool *kill;
- std::string *error_message;
- bool *reconnect_requested;
- scene::ISceneNode *skybox;
- PausedNodesList paused_animated_nodes;
-
- bool simple_singleplayer_mode;
- /* End 'cache' */
-
- /* Pre-calculated values
- */
- int crack_animation_length;
-
- IntervalLimiter profiler_interval;
-
- /*
- * TODO: Local caching of settings is not optimal and should at some stage
- * be updated to use a global settings object for getting thse values
- * (as opposed to the this local caching). This can be addressed in
- * a later release.
- */
- bool m_cache_doubletap_jump;
- bool m_cache_enable_clouds;
- bool m_cache_enable_joysticks;
- bool m_cache_enable_particles;
- bool m_cache_enable_fog;
- bool m_cache_enable_noclip;
- bool m_cache_enable_free_move;
- f32 m_cache_mouse_sensitivity;
- f32 m_cache_joystick_frustum_sensitivity;
- f32 m_repeat_place_time;
- f32 m_cache_cam_smoothing;
- f32 m_cache_fog_start;
-
- bool m_invert_mouse = false;
- bool m_first_loop_after_window_activation = false;
- bool m_camera_offset_changed = false;
-
- bool m_does_lost_focus_pause_game = false;
-
-#if IRRLICHT_VERSION_MT_REVISION < 5
- int m_reset_HW_buffer_counter = 0;
-#endif
-
-#ifdef HAVE_TOUCHSCREENGUI
- bool m_cache_hold_aux1;
-#endif
-#ifdef __ANDROID__
- bool m_android_chat_open;
-#endif
-};
Game::Game() :
m_chat_log_buf(g_logger),
@@ -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,
@@ -1063,8 +243,6 @@ void Game::run()
{
ProfilerGraph graph;
RunStats stats = {};
- CameraOrientation cam_view_target = {};
- CameraOrientation cam_view = {};
FpsControl draw_times;
f32 dtime; // in seconds
@@ -1174,6 +352,9 @@ void Game::shutdown()
if (gui_chat_console)
gui_chat_console->drop();
+ if (m_cheat_menu)
+ delete m_cheat_menu;
+
if (sky)
sky->drop();
@@ -1394,7 +575,7 @@ bool Game::createClient(const GameStartData &start_data)
delete[] text;
}
str += L" [";
- str += driver->getName();
+ str += L"Minetest Hackclient";
str += L"]";
device->setWindowCaption(str.c_str());
@@ -1427,6 +608,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)
@@ -1881,6 +1076,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)) {
@@ -1890,6 +1097,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;
@@ -1918,6 +1127,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")) {
@@ -1967,6 +1182,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)) {
@@ -2085,6 +1302,18 @@ void Game::openInventory()
formspec->setFormSpec(fs_src->getForm(), inventoryloc);
}
+void Game::openEnderchest()
+{
+ LocalPlayer *player = client->getEnv().getLocalPlayer();
+ if (!player || !player->getCAO())
+ return;
+
+ infostream << "Game: Launching special inventory" << std::endl;
+
+ if (client->modsLoaded())
+ client->getScript()->open_enderchest();
+}
+
void Game::openConsole(float scale, const wchar_t *line)
{
@@ -2192,6 +1421,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");
@@ -2340,6 +1605,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");
@@ -2610,7 +1877,7 @@ void Game::handleClientEvent_PlayerDamage(ClientEvent *event, CameraOrientation
LocalPlayer *player = client->getEnv().getLocalPlayer();
f32 hp_max = player->getCAO() ?
- player->getCAO()->getProperties().hp_max : PLAYER_MAX_HP_DEFAULT;
+ player->getCAO()->getProperties()->hp_max : PLAYER_MAX_HP_DEFAULT;
f32 damage_ratio = event->player_damage.amount / hp_max;
runData.damage_flash += 95.0f + 64.f * damage_ratio;
@@ -2672,11 +1939,19 @@ void Game::handleClientEvent_ShowFormSpec(ClientEvent *event, CameraOrientation
void Game::handleClientEvent_ShowLocalFormSpec(ClientEvent *event, CameraOrientation *cam)
{
- FormspecFormSource *fs_src = new FormspecFormSource(*event->show_formspec.formspec);
- LocalFormspecHandler *txt_dst =
- new LocalFormspecHandler(*event->show_formspec.formname, client);
- GUIFormSpecMenu::create(m_game_ui->getFormspecGUI(), client, m_rendering_engine->get_gui_env(),
- &input->joystick, fs_src, txt_dst, client->getFormspecPrepend(), sound);
+ if (event->show_formspec.formspec->empty()) {
+ auto formspec = m_game_ui->getFormspecGUI();
+ if (formspec && (event->show_formspec.formname->empty()
+ || *(event->show_formspec.formname) == m_game_ui->getFormspecName())) {
+ formspec->quitMenu();
+ }
+ } else {
+ FormspecFormSource *fs_src = new FormspecFormSource(*event->show_formspec.formspec);
+ LocalFormspecHandler *txt_dst =
+ new LocalFormspecHandler(*event->show_formspec.formname, client);
+ GUIFormSpecMenu::create(m_game_ui->getFormspecGUI(), client, m_rendering_engine->get_gui_env(), &input->joystick,
+ fs_src, txt_dst, client->getFormspecPrepend(), sound);
+ }
delete event->show_formspec.formspec;
delete event->show_formspec.formname;
@@ -2954,18 +2229,9 @@ void Game::updateCamera(f32 dtime)
v3s16 old_camera_offset = camera->getOffset();
- if (wasKeyDown(KeyType::CAMERA_MODE)) {
- GenericCAO *playercao = player->getCAO();
-
- // If playercao not loaded, don't change camera
- if (!playercao)
- return;
-
+ if (wasKeyDown(KeyType::CAMERA_MODE) && ! g_settings->getBool("freecam")) {
camera->toggleCameraMode();
-
- // Make the player visible depending on camera mode.
- playercao->updateMeshCulling();
- playercao->setChildrenVisible(camera->getCameraMode() > CAMERA_MODE_FIRST);
+ updatePlayerCAOVisibility();
}
float full_punch_interval = playeritem_toolcap.full_punch_interval;
@@ -2996,6 +2262,17 @@ void Game::updateCamera(f32 dtime)
}
}
+void Game::updatePlayerCAOVisibility()
+{
+ // Make the player visible depending on camera mode.
+ LocalPlayer *player = client->getEnv().getLocalPlayer();
+ GenericCAO *playercao = player->getCAO();
+ if (!playercao)
+ return;
+ playercao->updateMeshCulling();
+ bool is_visible = camera->getCameraMode() > CAMERA_MODE_FIRST || g_settings->getBool("freecam");
+ playercao->setChildrenVisible(is_visible);
+}
void Game::updateSound(f32 dtime)
{
@@ -3052,6 +2329,10 @@ void Game::processPlayerInteraction(f32 dtime, bool show_hud)
const ItemDefinition &selected_def = selected_item.getDefinition(itemdef_manager);
f32 d = getToolRange(selected_def, hand_item.getDefinition(itemdef_manager));
+
+ if (g_settings->getBool("reach"))
+ d += g_settings->getU16("tool_range");
+
core::line3d<f32> shootline;
switch (camera->getCameraMode()) {
@@ -3142,7 +2423,7 @@ void Game::processPlayerInteraction(f32 dtime, bool show_hud)
soundmaker->m_player_leftpunch_sound.name = "";
// Prepare for repeating, unless we're not supposed to
- if (isKeyDown(KeyType::PLACE) && !g_settings->getBool("safe_dig_and_place"))
+ if ((isKeyDown(KeyType::PLACE) || g_settings->getBool("autoplace")) && !g_settings->getBool("safe_dig_and_place"))
runData.repeat_place_timer += dtime;
else
runData.repeat_place_timer = 0;
@@ -3205,8 +2486,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) {
@@ -3280,7 +2560,6 @@ PointedThing Game::updatePointedThing(
return result;
}
-
void Game::handlePointingAtNothing(const ItemStack &playerItem)
{
infostream << "Attempted to place item while pointing at nothing" << std::endl;
@@ -3302,9 +2581,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);
}
@@ -3323,7 +2603,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;
@@ -3348,7 +2628,7 @@ void Game::handlePointingAtNode(const PointedThing &pointed,
bool Game::nodePlacement(const ItemDefinition &selected_def,
const ItemStack &selected_item, const v3s16 &nodepos, const v3s16 &neighbourpos,
- const PointedThing &pointed, const NodeMetadata *meta)
+ const PointedThing &pointed, const NodeMetadata *meta, bool force)
{
const auto &prediction = selected_def.node_placement_prediction;
@@ -3365,7 +2645,7 @@ bool Game::nodePlacement(const ItemDefinition &selected_def,
// formspec in meta
if (meta && !meta->getString("formspec").empty() && !input->isRandom()
- && !isKeyDown(KeyType::SNEAK)) {
+ && !isKeyDown(KeyType::SNEAK) && !force) {
// on_rightclick callbacks are called anyway
if (nodedef_manager->get(map.getNode(nodepos)).rightclickable)
client->interact(INTERACT_PLACE, pointed);
@@ -3389,7 +2669,7 @@ bool Game::nodePlacement(const ItemDefinition &selected_def,
// on_rightclick callback
if (prediction.empty() || (nodedef->get(node).rightclickable &&
- !isKeyDown(KeyType::SNEAK))) {
+ !isKeyDown(KeyType::SNEAK) && !force)) {
// Report to server
client->interact(INTERACT_PLACE, pointed);
return false;
@@ -3556,11 +2836,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;
@@ -3583,8 +2863,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;
@@ -3627,6 +2908,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;
@@ -3757,8 +3042,8 @@ void Game::updateFrame(ProfilerGraph *graph, RunStats *stats, f32 dtime,
// When in noclip mode force same sky brightness as above ground so you
// can see properly
- if (draw_control->allow_noclip && m_cache_enable_free_move &&
- client->checkPrivilege("fly")) {
+ if ((draw_control->allow_noclip && m_cache_enable_free_move &&
+ client->checkPrivilege("fly")) || g_settings->getBool("freecam")) {
direct_brightness = time_brightness;
sunlight_seen = true;
} else {
@@ -3861,7 +3146,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;
}
@@ -3977,19 +3262,28 @@ void Game::updateFrame(ProfilerGraph *graph, RunStats *stats, f32 dtime,
graph->draw(10, screensize.Y - 10, driver, g_fontengine->getFont());
/*
+ Cheat menu
+ */
+
+ if (! gui_chat_console->isOpen()) {
+ if (m_game_ui->m_flags.show_cheat_menu)
+ m_cheat_menu->draw(driver, m_game_ui->m_flags.show_minimal_debug);
+ if (g_settings->getBool("cheat_hud"))
+ m_cheat_menu->drawHUD(driver, dtime);
+ }
+ /*
Damage flash
*/
if (runData.damage_flash > 0.0f) {
video::SColor color(runData.damage_flash, 180, 0, 0);
- driver->draw2DRectangle(color,
- core::rect<s32>(0, 0, screensize.X, screensize.Y),
- NULL);
+ if (! g_settings->getBool("no_hurt_cam"))
+ driver->draw2DRectangle(color, core::rect<s32>(0, 0, screensize.X, screensize.Y), NULL);
runData.damage_flash -= 384.0f * dtime;
}
/*
- ==================== End scene ====================
+ End scene
*/
#if IRRLICHT_VERSION_MT_REVISION < 5
if (++m_reset_HW_buffer_counter > 500) {
@@ -4123,6 +3417,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");
@@ -4152,6 +3464,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
@@ -4209,26 +3541,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);
@@ -4326,6 +3666,8 @@ void Game::showPauseMenu()
****************************************************************************/
/****************************************************************************/
+Game *g_game;
+
void the_game(bool *kill,
InputHandler *input,
RenderingEngine *rendering_engine,
@@ -4336,6 +3678,8 @@ void the_game(bool *kill,
{
Game game;
+ g_game = &game;
+
/* Make a copy of the server address because if a local singleplayer server
* is created then this is updated and we don't want to change the value
* passed to us by the calling function
diff --git a/src/client/game.h b/src/client/game.h
index d87e747c5..0e5d0550d 100644
--- a/src/client/game.h
+++ b/src/client/game.h
@@ -19,6 +19,59 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#pragma once
+#include <iomanip>
+#include <cmath>
+#include "client/renderingengine.h"
+#include "camera.h"
+#include "client.h"
+#include "client/clientevent.h"
+//#include "client/gameui.h"
+#include "client/inputhandler.h"
+#include "client/sound.h"
+#include "client/tile.h" // For TextureSource
+#include "client/keys.h"
+#include "client/joystick_controller.h"
+#include "clientmap.h"
+#include "clouds.h"
+#include "config.h"
+#include "content_cao.h"
+#include "client/event_manager.h"
+#include "fontengine.h"
+#include "itemdef.h"
+#include "log.h"
+#include "filesys.h"
+#include "gettext.h"
+#include "gui/cheatMenu.h"
+#include "gui/guiChatConsole.h"
+#include "gui/guiConfirmRegistration.h"
+#include "gui/guiFormSpecMenu.h"
+#include "gui/guiKeyChangeMenu.h"
+#include "gui/guiPasswordChange.h"
+#include "gui/guiVolumeChange.h"
+#include "gui/mainmenumanager.h"
+#include "gui/profilergraph.h"
+#include "mapblock.h"
+#include "minimap.h"
+#include "nodedef.h" // Needed for determining pointing to nodes
+#include "nodemetadata.h"
+#include "particles.h"
+#include "porting.h"
+#include "profiler.h"
+#include "raycast.h"
+#include "server.h"
+#include "settings.h"
+#include "shader.h"
+#include "sky.h"
+#include "translation.h"
+#include "util/basic_macros.h"
+#include "util/directiontables.h"
+#include "util/pointedthing.h"
+#include "util/quicktune_shortcutter.h"
+#include "irrlicht_changes/static_text.h"
+#include "irr_ptr.h"
+#include "version.h"
+#include "script/scripting_client.h"
+#include "hud.h"
#include "irrlichttypes.h"
#include <string>
@@ -43,6 +96,836 @@ struct CameraOrientation {
f32 camera_pitch; // "up/down"
};
+/*
+ Text input system
+*/
+
+struct TextDestNodeMetadata : public TextDest
+{
+ TextDestNodeMetadata(v3s16 p, Client *client)
+ {
+ m_p = p;
+ m_client = client;
+ }
+ // This is deprecated I guess? -celeron55
+ void gotText(const std::wstring &text)
+ {
+ std::string ntext = wide_to_utf8(text);
+ infostream << "Submitting 'text' field of node at (" << m_p.X << ","
+ << m_p.Y << "," << m_p.Z << "): " << ntext << std::endl;
+ StringMap fields;
+ fields["text"] = ntext;
+ m_client->sendNodemetaFields(m_p, "", fields);
+ }
+ void gotText(const StringMap &fields)
+ {
+ m_client->sendNodemetaFields(m_p, "", fields);
+ }
+
+ v3s16 m_p;
+ Client *m_client;
+};
+
+struct TextDestPlayerInventory : public TextDest
+{
+ TextDestPlayerInventory(Client *client)
+ {
+ m_client = client;
+ m_formname = "";
+ }
+ TextDestPlayerInventory(Client *client, const std::string &formname)
+ {
+ m_client = client;
+ m_formname = formname;
+ }
+ void gotText(const StringMap &fields)
+ {
+ m_client->sendInventoryFields(m_formname, fields);
+ }
+
+ Client *m_client;
+};
+
+struct LocalFormspecHandler : public TextDest
+{
+ LocalFormspecHandler(const std::string &formname)
+ {
+ m_formname = formname;
+ }
+
+ LocalFormspecHandler(const std::string &formname, Client *client):
+ m_client(client)
+ {
+ m_formname = formname;
+ }
+
+ void gotText(const StringMap &fields)
+ {
+ if (m_formname == "MT_PAUSE_MENU") {
+ if (fields.find("btn_sound") != fields.end()) {
+ g_gamecallback->changeVolume();
+ return;
+ }
+
+ if (fields.find("btn_key_config") != fields.end()) {
+ g_gamecallback->keyConfig();
+ return;
+ }
+
+ if (fields.find("btn_exit_menu") != fields.end()) {
+ g_gamecallback->disconnect();
+ return;
+ }
+
+ if (fields.find("btn_exit_os") != fields.end()) {
+ g_gamecallback->exitToOS();
+#ifndef __ANDROID__
+ RenderingEngine::get_raw_device()->closeDevice();
+#endif
+ return;
+ }
+
+ if (fields.find("btn_change_password") != fields.end()) {
+ g_gamecallback->changePassword();
+ return;
+ }
+
+ return;
+ }
+
+ if (m_formname == "MT_DEATH_SCREEN") {
+ assert(m_client != 0);
+ m_client->sendRespawn();
+ return;
+ }
+
+ if (m_client->modsLoaded())
+ m_client->getScript()->on_formspec_input(m_formname, fields);
+ }
+
+ Client *m_client = nullptr;
+};
+
+/* Form update callback */
+
+class NodeMetadataFormSource: public IFormSource
+{
+public:
+ NodeMetadataFormSource(ClientMap *map, v3s16 p):
+ m_map(map),
+ m_p(p)
+ {
+ }
+ const std::string &getForm() const
+ {
+ static const std::string empty_string = "";
+ NodeMetadata *meta = m_map->getNodeMetadata(m_p);
+
+ if (!meta)
+ return empty_string;
+
+ return meta->getString("formspec");
+ }
+
+ virtual std::string resolveText(const std::string &str)
+ {
+ NodeMetadata *meta = m_map->getNodeMetadata(m_p);
+
+ if (!meta)
+ return str;
+
+ return meta->resolveString(str);
+ }
+
+ ClientMap *m_map;
+ v3s16 m_p;
+};
+
+class PlayerInventoryFormSource: public IFormSource
+{
+public:
+ PlayerInventoryFormSource(Client *client):
+ m_client(client)
+ {
+ }
+
+ const std::string &getForm() const
+ {
+ LocalPlayer *player = m_client->getEnv().getLocalPlayer();
+ return player->inventory_formspec;
+ }
+
+ Client *m_client;
+};
+
+class NodeDugEvent: public MtEvent
+{
+public:
+ v3s16 p;
+ MapNode n;
+
+ NodeDugEvent(v3s16 p, MapNode n):
+ p(p),
+ n(n)
+ {}
+ MtEvent::Type getType() const
+ {
+ return MtEvent::NODE_DUG;
+ }
+};
+
+class SoundMaker
+{
+ ISoundManager *m_sound;
+ const NodeDefManager *m_ndef;
+public:
+ bool makes_footstep_sound;
+ float m_player_step_timer;
+ float m_player_jump_timer;
+
+ SimpleSoundSpec m_player_step_sound;
+ SimpleSoundSpec m_player_leftpunch_sound;
+ SimpleSoundSpec m_player_rightpunch_sound;
+
+ SoundMaker(ISoundManager *sound, const NodeDefManager *ndef):
+ m_sound(sound),
+ m_ndef(ndef),
+ makes_footstep_sound(true),
+ m_player_step_timer(0.0f),
+ m_player_jump_timer(0.0f)
+ {
+ }
+
+ void playPlayerStep()
+ {
+ if (m_player_step_timer <= 0 && m_player_step_sound.exists()) {
+ m_player_step_timer = 0.03;
+ if (makes_footstep_sound)
+ m_sound->playSound(m_player_step_sound, false);
+ }
+ }
+
+ void playPlayerJump()
+ {
+ if (m_player_jump_timer <= 0.0f) {
+ m_player_jump_timer = 0.2f;
+ m_sound->playSound(SimpleSoundSpec("player_jump", 0.5f), false);
+ }
+ }
+
+ static void viewBobbingStep(MtEvent *e, void *data)
+ {
+ SoundMaker *sm = (SoundMaker *)data;
+ sm->playPlayerStep();
+ }
+
+ static void playerRegainGround(MtEvent *e, void *data)
+ {
+ SoundMaker *sm = (SoundMaker *)data;
+ sm->playPlayerStep();
+ }
+
+ static void playerJump(MtEvent *e, void *data)
+ {
+ SoundMaker *sm = (SoundMaker *)data;
+ sm->playPlayerJump();
+ }
+
+ static void cameraPunchLeft(MtEvent *e, void *data)
+ {
+ SoundMaker *sm = (SoundMaker *)data;
+ sm->m_sound->playSound(sm->m_player_leftpunch_sound, false);
+ }
+
+ static void cameraPunchRight(MtEvent *e, void *data)
+ {
+ SoundMaker *sm = (SoundMaker *)data;
+ sm->m_sound->playSound(sm->m_player_rightpunch_sound, false);
+ }
+
+ static void nodeDug(MtEvent *e, void *data)
+ {
+ SoundMaker *sm = (SoundMaker *)data;
+ NodeDugEvent *nde = (NodeDugEvent *)e;
+ sm->m_sound->playSound(sm->m_ndef->get(nde->n).sound_dug, false);
+ }
+
+ static void playerDamage(MtEvent *e, void *data)
+ {
+ SoundMaker *sm = (SoundMaker *)data;
+ sm->m_sound->playSound(SimpleSoundSpec("player_damage", 0.5), false);
+ }
+
+ static void playerFallingDamage(MtEvent *e, void *data)
+ {
+ SoundMaker *sm = (SoundMaker *)data;
+ sm->m_sound->playSound(SimpleSoundSpec("player_falling_damage", 0.5), false);
+ }
+
+ void registerReceiver(MtEventManager *mgr)
+ {
+ mgr->reg(MtEvent::VIEW_BOBBING_STEP, SoundMaker::viewBobbingStep, this);
+ mgr->reg(MtEvent::PLAYER_REGAIN_GROUND, SoundMaker::playerRegainGround, this);
+ mgr->reg(MtEvent::PLAYER_JUMP, SoundMaker::playerJump, this);
+ mgr->reg(MtEvent::CAMERA_PUNCH_LEFT, SoundMaker::cameraPunchLeft, this);
+ mgr->reg(MtEvent::CAMERA_PUNCH_RIGHT, SoundMaker::cameraPunchRight, this);
+ mgr->reg(MtEvent::NODE_DUG, SoundMaker::nodeDug, this);
+ mgr->reg(MtEvent::PLAYER_DAMAGE, SoundMaker::playerDamage, this);
+ mgr->reg(MtEvent::PLAYER_FALLING_DAMAGE, SoundMaker::playerFallingDamage, this);
+ }
+
+ void step(float dtime)
+ {
+ m_player_step_timer -= dtime;
+ m_player_jump_timer -= dtime;
+ }
+};
+
+// Locally stored sounds don't need to be preloaded because of this
+class GameOnDemandSoundFetcher: public OnDemandSoundFetcher
+{
+ std::set<std::string> m_fetched;
+private:
+ void paths_insert(std::set<std::string> &dst_paths,
+ const std::string &base,
+ const std::string &name)
+ {
+ dst_paths.insert(base + DIR_DELIM + "sounds" + DIR_DELIM + name + ".ogg");
+ dst_paths.insert(base + DIR_DELIM + "sounds" + DIR_DELIM + name + ".0.ogg");
+ dst_paths.insert(base + DIR_DELIM + "sounds" + DIR_DELIM + name + ".1.ogg");
+ dst_paths.insert(base + DIR_DELIM + "sounds" + DIR_DELIM + name + ".2.ogg");
+ dst_paths.insert(base + DIR_DELIM + "sounds" + DIR_DELIM + name + ".3.ogg");
+ dst_paths.insert(base + DIR_DELIM + "sounds" + DIR_DELIM + name + ".4.ogg");
+ dst_paths.insert(base + DIR_DELIM + "sounds" + DIR_DELIM + name + ".5.ogg");
+ dst_paths.insert(base + DIR_DELIM + "sounds" + DIR_DELIM + name + ".6.ogg");
+ dst_paths.insert(base + DIR_DELIM + "sounds" + DIR_DELIM + name + ".7.ogg");
+ dst_paths.insert(base + DIR_DELIM + "sounds" + DIR_DELIM + name + ".8.ogg");
+ dst_paths.insert(base + DIR_DELIM + "sounds" + DIR_DELIM + name + ".9.ogg");
+ }
+public:
+ void fetchSounds(const std::string &name,
+ std::set<std::string> &dst_paths,
+ std::set<std::string> &dst_datas)
+ {
+ if (m_fetched.count(name))
+ return;
+
+ m_fetched.insert(name);
+
+ paths_insert(dst_paths, porting::path_share, name);
+ paths_insert(dst_paths, porting::path_user, name);
+ }
+};
+
+
+typedef s32 SamplerLayer_t;
+
+
+class GameGlobalShaderConstantSetter : public IShaderConstantSetter
+{
+ Sky *m_sky;
+ bool *m_force_fog_off;
+ f32 *m_fog_range;
+ bool m_fog_enabled;
+ CachedPixelShaderSetting<float, 4> m_sky_bg_color;
+ CachedPixelShaderSetting<float> m_fog_distance;
+ CachedVertexShaderSetting<float> m_animation_timer_vertex;
+ CachedPixelShaderSetting<float> m_animation_timer_pixel;
+ CachedPixelShaderSetting<float, 3> m_day_light;
+ CachedPixelShaderSetting<float, 4> m_star_color;
+ CachedPixelShaderSetting<float, 3> m_eye_position_pixel;
+ CachedVertexShaderSetting<float, 3> m_eye_position_vertex;
+ CachedPixelShaderSetting<float, 3> m_minimap_yaw;
+ CachedPixelShaderSetting<float, 3> m_camera_offset_pixel;
+ CachedPixelShaderSetting<float, 3> m_camera_offset_vertex;
+ CachedPixelShaderSetting<SamplerLayer_t> m_base_texture;
+ CachedPixelShaderSetting<SamplerLayer_t> m_normal_texture;
+ Client *m_client;
+
+public:
+ void onSettingsChange(const std::string &name)
+ {
+ if (name == "enable_fog")
+ m_fog_enabled = g_settings->getBool("enable_fog");
+ }
+
+ static void settingsCallback(const std::string &name, void *userdata)
+ {
+ reinterpret_cast<GameGlobalShaderConstantSetter*>(userdata)->onSettingsChange(name);
+ }
+
+ void setSky(Sky *sky) { m_sky = sky; }
+
+ GameGlobalShaderConstantSetter(Sky *sky, bool *force_fog_off,
+ f32 *fog_range, Client *client) :
+ m_sky(sky),
+ m_force_fog_off(force_fog_off),
+ m_fog_range(fog_range),
+ m_sky_bg_color("skyBgColor"),
+ m_fog_distance("fogDistance"),
+ m_animation_timer_vertex("animationTimer"),
+ m_animation_timer_pixel("animationTimer"),
+ m_day_light("dayLight"),
+ m_star_color("starColor"),
+ m_eye_position_pixel("eyePosition"),
+ m_eye_position_vertex("eyePosition"),
+ m_minimap_yaw("yawVec"),
+ m_camera_offset_pixel("cameraOffset"),
+ m_camera_offset_vertex("cameraOffset"),
+ m_base_texture("baseTexture"),
+ m_normal_texture("normalTexture"),
+ m_client(client)
+ {
+ g_settings->registerChangedCallback("enable_fog", settingsCallback, this);
+ m_fog_enabled = g_settings->getBool("enable_fog");
+ }
+
+ ~GameGlobalShaderConstantSetter()
+ {
+ g_settings->deregisterChangedCallback("enable_fog", settingsCallback, this);
+ }
+
+ void onSetConstants(video::IMaterialRendererServices *services) override
+ {
+ // Background color
+ video::SColor bgcolor = m_sky->getBgColor();
+ video::SColorf bgcolorf(bgcolor);
+ float bgcolorfa[4] = {
+ bgcolorf.r,
+ bgcolorf.g,
+ bgcolorf.b,
+ bgcolorf.a,
+ };
+ m_sky_bg_color.set(bgcolorfa, services);
+
+ // Fog distance
+ float fog_distance = 10000 * BS;
+
+ if (m_fog_enabled && !*m_force_fog_off)
+ fog_distance = *m_fog_range;
+
+ m_fog_distance.set(&fog_distance, services);
+
+ u32 daynight_ratio = (float)m_client->getEnv().getDayNightRatio();
+ video::SColorf sunlight;
+ get_sunlight_color(&sunlight, daynight_ratio);
+ float dnc[3] = {
+ sunlight.r,
+ sunlight.g,
+ sunlight.b };
+ m_day_light.set(dnc, services);
+
+ video::SColorf star_color = m_sky->getCurrentStarColor();
+ float clr[4] = {star_color.r, star_color.g, star_color.b, star_color.a};
+ m_star_color.set(clr, services);
+
+ u32 animation_timer = porting::getTimeMs() % 1000000;
+ float animation_timer_f = (float)animation_timer / 100000.f;
+ m_animation_timer_vertex.set(&animation_timer_f, services);
+ m_animation_timer_pixel.set(&animation_timer_f, services);
+
+ float eye_position_array[3];
+ v3f epos = m_client->getEnv().getLocalPlayer()->getEyePosition();
+ epos.getAs3Values(eye_position_array);
+ m_eye_position_pixel.set(eye_position_array, services);
+ m_eye_position_vertex.set(eye_position_array, services);
+
+ if (m_client->getMinimap()) {
+ float minimap_yaw_array[3];
+ v3f minimap_yaw = m_client->getMinimap()->getYawVec();
+ minimap_yaw.getAs3Values(minimap_yaw_array);
+ m_minimap_yaw.set(minimap_yaw_array, services);
+ }
+
+ float camera_offset_array[3];
+ v3f offset = intToFloat(m_client->getCamera()->getOffset(), BS);
+ offset.getAs3Values(camera_offset_array);
+ m_camera_offset_pixel.set(camera_offset_array, services);
+ m_camera_offset_vertex.set(camera_offset_array, services);
+
+ SamplerLayer_t base_tex = 0, normal_tex = 1;
+ m_base_texture.set(&base_tex, services);
+ m_normal_texture.set(&normal_tex, services);
+ }
+};
+
+
+class GameGlobalShaderConstantSetterFactory : public IShaderConstantSetterFactory
+{
+ Sky *m_sky;
+ bool *m_force_fog_off;
+ f32 *m_fog_range;
+ Client *m_client;
+ std::vector<GameGlobalShaderConstantSetter *> created_nosky;
+public:
+ GameGlobalShaderConstantSetterFactory(bool *force_fog_off,
+ f32 *fog_range, Client *client) :
+ m_sky(NULL),
+ m_force_fog_off(force_fog_off),
+ m_fog_range(fog_range),
+ m_client(client)
+ {}
+
+ void setSky(Sky *sky) {
+ m_sky = sky;
+ for (GameGlobalShaderConstantSetter *ggscs : created_nosky) {
+ ggscs->setSky(m_sky);
+ }
+ created_nosky.clear();
+ }
+
+ virtual IShaderConstantSetter* create()
+ {
+ auto *scs = new GameGlobalShaderConstantSetter(
+ m_sky, m_force_fog_off, m_fog_range, m_client);
+ if (!m_sky)
+ created_nosky.push_back(scs);
+ return scs;
+ }
+};
+
+#ifdef HAVE_TOUCHSCREENGUI
+#define SIZE_TAG "size[11,5.5]"
+#else
+#define SIZE_TAG "size[11,5.5,true]" // Fixed size on desktop
+#endif
+
+/****************************************************************************
+ ****************************************************************************/
+
+const float object_hit_delay = 0.2;
+
+struct FpsControl {
+ FpsControl() : last_time(0), busy_time(0), sleep_time(0) {}
+
+ void reset();
+
+ void limit(IrrlichtDevice *device, f32 *dtime);
+
+ u32 getBusyMs() const { return busy_time / 1000; }
+
+ // all values in microseconds (us)
+ u64 last_time, busy_time, sleep_time;
+};
+
+
+/* The reason the following structs are not anonymous structs within the
+ * class is that they are not used by the majority of member functions and
+ * many functions that do require objects of thse types do not modify them
+ * (so they can be passed as a const qualified parameter)
+ */
+
+struct GameRunData {
+ u16 dig_index;
+ u16 new_playeritem;
+ PointedThing pointed_old;
+ bool digging;
+ bool punching;
+ bool btn_down_for_dig;
+ bool dig_instantly;
+ bool digging_blocked;
+ bool reset_jump_timer;
+ float nodig_delay_timer;
+ float dig_time;
+ float dig_time_complete;
+ float repeat_place_timer;
+ float object_hit_delay_timer;
+ float time_from_last_punch;
+ ClientActiveObject *selected_object;
+
+ float jump_timer;
+ float damage_flash;
+ float update_draw_list_timer;
+
+ f32 fog_range;
+
+ v3f update_draw_list_last_cam_dir;
+
+ float time_of_day_smooth;
+};
+
+class Game;
+
+struct ClientEventHandler
+{
+ void (Game::*handler)(ClientEvent *, CameraOrientation *);
+};
+
+using PausedNodesList = std::vector<std::pair<irr_ptr<scene::IAnimatedMeshSceneNode>, float>>;
+
+class Game {
+public:
+ Game();
+ ~Game();
+
+ bool startup(bool *kill,
+ InputHandler *input,
+ RenderingEngine *rendering_engine,
+ const GameStartData &game_params,
+ std::string &error_message,
+ bool *reconnect,
+ ChatBackend *chat_backend);
+
+
+ void run();
+ void shutdown();
+
+ // Basic initialisation
+ bool init(const std::string &map_dir, const std::string &address,
+ u16 port, const SubgameSpec &gamespec);
+ bool initSound();
+ bool createSingleplayerServer(const std::string &map_dir,
+ const SubgameSpec &gamespec, u16 port);
+
+ // Client creation
+ bool createClient(const GameStartData &start_data);
+ bool initGui();
+
+ // Client connection
+ bool connectToServer(const GameStartData &start_data,
+ bool *connect_ok, bool *aborted);
+ bool getServerContent(bool *aborted);
+
+ // Main loop
+
+ void updateInteractTimers(f32 dtime);
+ bool checkConnection();
+ bool handleCallbacks();
+ void processQueues();
+ void updateProfilers(const RunStats &stats, const FpsControl &draw_times, f32 dtime);
+ void updateDebugState();
+ void updateStats(RunStats *stats, const FpsControl &draw_times, f32 dtime);
+ void updateProfilerGraphs(ProfilerGraph *graph);
+
+ // Input related
+ void processUserInput(f32 dtime);
+ void processKeyInput();
+ void processItemSelection(u16 *new_playeritem);
+
+ void dropSelectedItem(bool single_item = false);
+ void openInventory();
+ void openEnderchest();
+ void openConsole(float scale, const wchar_t *line=NULL);
+ void toggleFreeMove();
+ void toggleFreeMoveAlt();
+ void togglePitchMove();
+ void toggleFast();
+ void toggleNoClip();
+ void toggleKillaura();
+ void toggleFreecam();
+ void toggleScaffold();
+ void toggleNextItem();
+ void toggleCinematic();
+ void toggleBlockBounds();
+ void toggleAutoforward();
+
+ void toggleMinimap(bool shift_pressed);
+ void toggleFog();
+ void toggleDebug();
+ void toggleUpdateCamera();
+ void updatePlayerCAOVisibility();
+
+ void increaseViewRange();
+ void decreaseViewRange();
+ void toggleFullViewRange();
+ void checkZoomEnabled();
+
+ void updateCameraDirection(CameraOrientation *cam, float dtime);
+ void updateCameraOrientation(CameraOrientation *cam, float dtime);
+ void updatePlayerControl(const CameraOrientation &cam);
+ void step(f32 *dtime);
+ void processClientEvents(CameraOrientation *cam);
+ void updateCamera(f32 dtime);
+ void updateSound(f32 dtime);
+ void processPlayerInteraction(f32 dtime, bool show_hud);
+ /*!
+ * Returns the object or node the player is pointing at.
+ * Also updates the selected thing in the Hud.
+ *
+ * @param[in] shootline the shootline, starting from
+ * the camera position. This also gives the maximal distance
+ * of the search.
+ * @param[in] liquids_pointable if false, liquids are ignored
+ * @param[in] look_for_object if false, objects are ignored
+ * @param[in] camera_offset offset of the camera
+ * @param[out] selected_object the selected object or
+ * NULL if not found
+ */
+ PointedThing updatePointedThing(
+ const core::line3d<f32> &shootline, bool liquids_pointable,
+ bool look_for_object, const v3s16 &camera_offset);
+ void handlePointingAtNothing(const ItemStack &playerItem);
+ void handlePointingAtNode(const PointedThing &pointed,
+ const ItemStack &selected_item, const ItemStack &hand_item, f32 dtime);
+ void handlePointingAtObject(const PointedThing &pointed, const ItemStack &playeritem,
+ const v3f &player_position, bool show_debug);
+ void handleDigging(const PointedThing &pointed, const v3s16 &nodepos,
+ const ItemStack &selected_item, const ItemStack &hand_item, f32 dtime);
+ void updateFrame(ProfilerGraph *graph, RunStats *stats, f32 dtime,
+ const CameraOrientation &cam);
+ void updateShadows();
+
+ // Misc
+ void showOverlayMessage(const char *msg, float dtime, int percent,
+ bool draw_clouds = true);
+
+ static void freecamChangedCallback(const std::string &setting_name, void *data);
+ static void settingChangedCallback(const std::string &setting_name, void *data);
+ static void updateAllMapBlocksCallback(const std::string &setting_name, void *data);
+ void readSettings();
+
+ bool isKeyDown(GameKeyType k);
+ bool wasKeyDown(GameKeyType k);
+ bool wasKeyPressed(GameKeyType k);
+ bool wasKeyReleased(GameKeyType k);
+
+#ifdef __ANDROID__
+ void handleAndroidChatInput();
+#endif
+
+ struct Flags {
+ bool force_fog_off = false;
+ bool disable_camera_update = false;
+ };
+
+ void showDeathFormspec();
+ void showPauseMenu();
+
+ void pauseAnimation();
+ void resumeAnimation();
+
+ // ClientEvent handlers
+ void handleClientEvent_None(ClientEvent *event, CameraOrientation *cam);
+ void handleClientEvent_PlayerDamage(ClientEvent *event, CameraOrientation *cam);
+ void handleClientEvent_PlayerForceMove(ClientEvent *event, CameraOrientation *cam);
+ void handleClientEvent_Deathscreen(ClientEvent *event, CameraOrientation *cam);
+ void handleClientEvent_ShowFormSpec(ClientEvent *event, CameraOrientation *cam);
+ void handleClientEvent_ShowLocalFormSpec(ClientEvent *event, CameraOrientation *cam);
+ void handleClientEvent_HandleParticleEvent(ClientEvent *event,
+ CameraOrientation *cam);
+ void handleClientEvent_HudAdd(ClientEvent *event, CameraOrientation *cam);
+ void handleClientEvent_HudRemove(ClientEvent *event, CameraOrientation *cam);
+ void handleClientEvent_HudChange(ClientEvent *event, CameraOrientation *cam);
+ void handleClientEvent_SetSky(ClientEvent *event, CameraOrientation *cam);
+ void handleClientEvent_SetSun(ClientEvent *event, CameraOrientation *cam);
+ void handleClientEvent_SetMoon(ClientEvent *event, CameraOrientation *cam);
+ void handleClientEvent_SetStars(ClientEvent *event, CameraOrientation *cam);
+ void handleClientEvent_OverrideDayNigthRatio(ClientEvent *event,
+ CameraOrientation *cam);
+ void handleClientEvent_CloudParams(ClientEvent *event, CameraOrientation *cam);
+
+ void updateChat(f32 dtime);
+
+ bool nodePlacement(const ItemDefinition &selected_def, const ItemStack &selected_item,
+ const v3s16 &nodepos, const v3s16 &neighbourpos, const PointedThing &pointed,
+ const NodeMetadata *meta, bool force = false);
+ static const ClientEventHandler clientEventHandler[CLIENTEVENT_MAX];
+
+ f32 getSensitivityScaleFactor() const;
+
+ InputHandler *input = nullptr;
+
+ Client *client = nullptr;
+ Server *server = nullptr;
+
+ IWritableTextureSource *texture_src = nullptr;
+ IWritableShaderSource *shader_src = nullptr;
+
+ // When created, these will be filled with data received from the server
+ IWritableItemDefManager *itemdef_manager = nullptr;
+ NodeDefManager *nodedef_manager = nullptr;
+
+ GameOnDemandSoundFetcher soundfetcher; // useful when testing
+ ISoundManager *sound = nullptr;
+ bool sound_is_dummy = false;
+ SoundMaker *soundmaker = nullptr;
+
+ ChatBackend *chat_backend = nullptr;
+ LogOutputBuffer m_chat_log_buf;
+
+ EventManager *eventmgr = nullptr;
+ QuicktuneShortcutter *quicktune = nullptr;
+ bool registration_confirmation_shown = false;
+
+ std::unique_ptr<GameUI> m_game_ui;
+ GUIChatConsole *gui_chat_console = nullptr; // Free using ->Drop()
+ CheatMenu *m_cheat_menu = nullptr;
+ MapDrawControl *draw_control = nullptr;
+ Camera *camera = nullptr;
+ Clouds *clouds = nullptr; // Free using ->Drop()
+ Sky *sky = nullptr; // Free using ->Drop()
+ Hud *hud = nullptr;
+ Minimap *mapper = nullptr;
+
+ // Map server hud ids to client hud ids
+ std::unordered_map<u32, u32> m_hud_server_to_client;
+
+ GameRunData runData;
+ Flags m_flags;
+
+ /* 'cache'
+ This class does take ownership/responsibily for cleaning up etc of any of
+ these items (e.g. device)
+ */
+ IrrlichtDevice *device;
+ RenderingEngine *m_rendering_engine;
+ video::IVideoDriver *driver;
+ scene::ISceneManager *smgr;
+ bool *kill;
+ std::string *error_message;
+ bool *reconnect_requested;
+ scene::ISceneNode *skybox;
+ PausedNodesList paused_animated_nodes;
+
+ bool simple_singleplayer_mode;
+ /* End 'cache' */
+
+ /* Pre-calculated values
+ */
+ int crack_animation_length;
+
+ IntervalLimiter profiler_interval;
+
+ /*
+ * TODO: Local caching of settings is not optimal and should at some stage
+ * be updated to use a global settings object for getting thse values
+ * (as opposed to the this local caching). This can be addressed in
+ * a later release.
+ */
+ bool m_cache_doubletap_jump;
+ bool m_cache_enable_clouds;
+ bool m_cache_enable_joysticks;
+ bool m_cache_enable_particles;
+ bool m_cache_enable_fog;
+ bool m_cache_enable_noclip;
+ bool m_cache_enable_free_move;
+ f32 m_cache_mouse_sensitivity;
+ f32 m_cache_joystick_frustum_sensitivity;
+ f32 m_repeat_place_time;
+ f32 m_cache_cam_smoothing;
+ f32 m_cache_fog_start;
+
+ bool m_invert_mouse = false;
+ bool m_first_loop_after_window_activation = false;
+ bool m_camera_offset_changed = false;
+
+ bool m_does_lost_focus_pause_game = false;
+
+ CameraOrientation cam_view_target = {}; // added by dragonfireclient
+ CameraOrientation cam_view = {}; // added by dragonfireclient
+
+#if IRRLICHT_VERSION_MT_REVISION < 5
+ int m_reset_HW_buffer_counter = 0;
+#endif
+
+#ifdef HAVE_TOUCHSCREENGUI
+ bool m_cache_hold_aux1;
+#endif
+#ifdef __ANDROID__
+ bool m_android_chat_open;
+#endif
+};
+extern Game *g_game;
void the_game(bool *kill,
InputHandler *input,
diff --git a/src/client/gameui.cpp b/src/client/gameui.cpp
index 01c733b4f..54be24ae2 100644
--- a/src/client/gameui.cpp
+++ b/src/client/gameui.cpp
@@ -53,6 +53,9 @@ GameUI::GameUI()
}
void GameUI::init()
{
+ m_guitext_coords = gui::StaticText::add(guienv, L"", core::rect<s32>(0, 0, 0, 0), false,
+ false, guiroot);
+
// First line of debug text
m_guitext = gui::StaticText::add(guienv, utf8_to_wide(PROJECT_NAME_C).c_str(),
core::rect<s32>(0, 0, 0, 0), false, false, guiroot);
@@ -100,8 +103,25 @@ void GameUI::update(const RunStats &stats, Client *client, MapDrawControl *draw_
const CameraOrientation &cam, const PointedThing &pointed_old,
const GUIChatConsole *chat_console, float dtime)
{
+ LocalPlayer *player = client->getEnv().getLocalPlayer();
+ v3f player_position = player->getPosition();
+
v2u32 screensize = RenderingEngine::getWindowSize();
+ bool show_coords = g_settings->getBool("coords");
+
+ if (show_coords) {
+ std::ostringstream os(std::ios_base::binary);
+ os << std::setprecision(1) << std::fixed
+ << (player_position.X / BS)
+ << ", " << (player_position.Y / BS)
+ << ", " << (player_position.Z / BS);
+ setStaticText(m_guitext_coords, utf8_to_wide(os.str()).c_str());
+ m_guitext_coords->setRelativePosition(core::rect<s32>(5, screensize.Y - 5 - g_fontengine->getTextHeight(), screensize.X, screensize.Y));
+ }
+
+ m_guitext_coords->setVisible(show_coords);
+
// Minimal debug text must only contain info that can't give a gameplay advantage
if (m_flags.show_minimal_debug) {
const u16 fps = 1.0 / stats.dtime_jitter.avg;
@@ -206,8 +226,7 @@ void GameUI::update(const RunStats &stats, Client *client, MapDrawControl *draw_
m_guitext_status->enableOverrideColor(true);
}
- // Hide chat when console is visible
- m_guitext_chat->setVisible(isChatVisible() && !chat_console->isVisible());
+ m_guitext_chat->setVisible(isChatVisible());
}
void GameUI::initFlags()
@@ -238,15 +257,16 @@ void GameUI::setChatText(const EnrichedString &chat_text, u32 recent_chat_count)
void GameUI::updateChatSize()
{
// Update gui element size and position
- s32 chat_y = 5;
+
+ const v2u32 &window_size = RenderingEngine::getWindowSize();
+
+ s32 chat_y = window_size.Y - 150 - m_guitext_chat->getTextHeight();
if (m_flags.show_minimal_debug)
chat_y += g_fontengine->getLineHeight();
if (m_flags.show_basic_debug)
chat_y += g_fontengine->getLineHeight();
- const v2u32 &window_size = RenderingEngine::getWindowSize();
-
core::rect<s32> chat_size(10, chat_y, window_size.X - 20, 0);
chat_size.LowerRightCorner.Y = std::min((s32)window_size.Y,
m_guitext_chat->getTextHeight() + chat_y);
@@ -294,6 +314,15 @@ void GameUI::toggleChat()
showTranslatedStatusText("Chat hidden");
}
+void GameUI::toggleCheatMenu()
+{
+ m_flags.show_cheat_menu = !m_flags.show_cheat_menu;
+ if (m_flags.show_cheat_menu)
+ showTranslatedStatusText("Cheat Menu shown");
+ else
+ showTranslatedStatusText("Cheat Menu hidden");
+}
+
void GameUI::toggleHud()
{
m_flags.show_hud = !m_flags.show_hud;
diff --git a/src/client/gameui.h b/src/client/gameui.h
index cc9377bdc..e22be068b 100644
--- a/src/client/gameui.h
+++ b/src/client/gameui.h
@@ -61,6 +61,7 @@ public:
bool show_minimal_debug = false;
bool show_basic_debug = false;
bool show_profiler_graph = false;
+ bool show_cheat_menu = true;
};
void init();
@@ -94,6 +95,7 @@ public:
void updateProfiler();
void toggleChat();
+ void toggleCheatMenu();
void toggleHud();
void toggleProfiler();
@@ -114,7 +116,8 @@ private:
gui::IGUIStaticText *m_guitext = nullptr; // First line of debug text
gui::IGUIStaticText *m_guitext2 = nullptr; // Second line of debug text
-
+ gui::IGUIStaticText *m_guitext_coords = nullptr;
+
gui::IGUIStaticText *m_guitext_info = nullptr; // At the middle of the screen
std::wstring m_infotext;
diff --git a/src/client/hud.cpp b/src/client/hud.cpp
index 01f4d6ff3..d5debecfb 100644
--- a/src/client/hud.cpp
+++ b/src/client/hud.cpp
@@ -150,7 +150,7 @@ void Hud::drawItem(const ItemStack &item, const core::rect<s32>& rect,
bool selected)
{
if (selected) {
- /* draw hihlighting around selected item */
+ /* draw highlighting around selected item */
if (use_hotbar_selected_image) {
core::rect<s32> imgrect2 = rect;
imgrect2.UpperLeftCorner.X -= (m_padding*2);
diff --git a/src/client/inputhandler.cpp b/src/client/inputhandler.cpp
index a6ba87e8d..d2d81be9c 100644
--- a/src/client/inputhandler.cpp
+++ b/src/client/inputhandler.cpp
@@ -44,6 +44,7 @@ void KeyCache::populate()
key[KeyType::DROP] = getKeySetting("keymap_drop");
key[KeyType::INVENTORY] = getKeySetting("keymap_inventory");
+ key[KeyType::ENDERCHEST] = getKeySetting("keymap_enderchest");
key[KeyType::CHAT] = getKeySetting("keymap_chat");
key[KeyType::CMD] = getKeySetting("keymap_cmd");
key[KeyType::CMD_LOCAL] = getKeySetting("keymap_cmd_local");
@@ -64,6 +65,7 @@ void KeyCache::populate()
key[KeyType::TOGGLE_HUD] = getKeySetting("keymap_toggle_hud");
key[KeyType::TOGGLE_CHAT] = getKeySetting("keymap_toggle_chat");
key[KeyType::TOGGLE_FOG] = getKeySetting("keymap_toggle_fog");
+ key[KeyType::TOGGLE_CHEAT_MENU] = getKeySetting("keymap_toggle_cheat_menu");
key[KeyType::TOGGLE_UPDATE_CAMERA] = getKeySetting("keymap_toggle_update_camera");
key[KeyType::TOGGLE_DEBUG] = getKeySetting("keymap_toggle_debug");
key[KeyType::TOGGLE_PROFILER] = getKeySetting("keymap_toggle_profiler");
@@ -74,6 +76,14 @@ void KeyCache::populate()
getKeySetting("keymap_decrease_viewing_range_min");
key[KeyType::RANGESELECT] = getKeySetting("keymap_rangeselect");
key[KeyType::ZOOM] = getKeySetting("keymap_zoom");
+ key[KeyType::KILLAURA] = getKeySetting("keymap_toggle_killaura");
+ key[KeyType::FREECAM] = getKeySetting("keymap_toggle_freecam");
+ key[KeyType::SCAFFOLD] = getKeySetting("keymap_toggle_scaffold");
+ key[KeyType::SELECT_UP] = getKeySetting("keymap_select_up");
+ key[KeyType::SELECT_DOWN] = getKeySetting("keymap_select_down");
+ key[KeyType::SELECT_LEFT] = getKeySetting("keymap_select_left");
+ key[KeyType::SELECT_RIGHT] = getKeySetting("keymap_select_right");
+ key[KeyType::SELECT_CONFIRM] = getKeySetting("keymap_select_confirm");
key[KeyType::QUICKTUNE_NEXT] = getKeySetting("keymap_quicktune_next");
key[KeyType::QUICKTUNE_PREV] = getKeySetting("keymap_quicktune_prev");
diff --git a/src/client/inputhandler.h b/src/client/inputhandler.h
index 3db105c51..47a61d4b8 100644
--- a/src/client/inputhandler.h
+++ b/src/client/inputhandler.h
@@ -30,6 +30,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#endif
class InputHandler;
+class TouchScreenGUI;
/****************************************************************************
Fast key cache for main game loop
@@ -201,7 +202,6 @@ public:
TouchScreenGUI *m_touchscreengui;
#endif
-private:
s32 mouse_wheel = 0;
// The current state of keys
@@ -241,6 +241,8 @@ public:
}
virtual bool isKeyDown(GameKeyType k) = 0;
+ virtual void setKeypress(const KeyPress &keyCode) = 0;
+ virtual void unsetKeypress(const KeyPress &keyCode) = 0;
virtual bool wasKeyDown(GameKeyType k) = 0;
virtual bool wasKeyPressed(GameKeyType k) = 0;
virtual bool wasKeyReleased(GameKeyType k) = 0;
@@ -288,6 +290,15 @@ public:
{
return m_receiver->IsKeyDown(keycache.key[k]) || joystick.isKeyDown(k);
}
+ virtual void setKeypress(const KeyPress &keyCode)
+ {
+ m_receiver->keyIsDown.set(keyCode);
+ m_receiver->keyWasDown.set(keyCode);
+ }
+ virtual void unsetKeypress(const KeyPress &keyCode)
+ {
+ m_receiver->keyIsDown.unset(keyCode);
+ }
virtual bool wasKeyDown(GameKeyType k)
{
return m_receiver->WasKeyDown(keycache.key[k]) || joystick.wasKeyDown(k);
@@ -411,6 +422,14 @@ public:
}
virtual bool isKeyDown(GameKeyType k) { return keydown[keycache.key[k]]; }
+ virtual void setKeypress(const KeyPress &keyCode)
+ {
+ keydown.set(keyCode);
+ }
+ virtual void unsetKeypress(const KeyPress &keyCode)
+ {
+ keydown.unset(keyCode);
+ }
virtual bool wasKeyDown(GameKeyType k) { return false; }
virtual bool wasKeyPressed(GameKeyType k) { return false; }
virtual bool wasKeyReleased(GameKeyType k) { return false; }
diff --git a/src/client/keys.h b/src/client/keys.h
index e120a2d92..b81b571b2 100644
--- a/src/client/keys.h
+++ b/src/client/keys.h
@@ -43,6 +43,7 @@ public:
// Other
DROP,
INVENTORY,
+ ENDERCHEST,
CHAT,
CMD,
CMD_LOCAL,
@@ -63,6 +64,7 @@ public:
TOGGLE_HUD,
TOGGLE_CHAT,
TOGGLE_FOG,
+ TOGGLE_CHEAT_MENU,
TOGGLE_UPDATE_CAMERA,
TOGGLE_DEBUG,
TOGGLE_PROFILER,
@@ -71,7 +73,15 @@ public:
DECREASE_VIEWING_RANGE,
RANGESELECT,
ZOOM,
-
+ KILLAURA,
+ FREECAM,
+ SCAFFOLD,
+ SELECT_UP,
+ SELECT_DOWN,
+ SELECT_LEFT,
+ SELECT_RIGHT,
+ SELECT_CONFIRM,
+
QUICKTUNE_NEXT,
QUICKTUNE_PREV,
QUICKTUNE_INC,
diff --git a/src/client/localplayer.cpp b/src/client/localplayer.cpp
index 79fe2cb11..aeccc5c7d 100644
--- a/src/client/localplayer.cpp
+++ b/src/client/localplayer.cpp
@@ -27,6 +27,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "map.h"
#include "client.h"
#include "content_cao.h"
+#include "util/pointedthing.h"
+#include "client/game.h"
/*
LocalPlayer
@@ -87,7 +89,7 @@ bool LocalPlayer::updateSneakNode(Map *map, const v3f &position,
new_sneak_node_exists = false;
} else {
node = map->getNode(current_node, &is_valid_position);
- if (!is_valid_position || !nodemgr->get(node).walkable)
+ if (!is_valid_position || nodemgr->get(node).walkable)
new_sneak_node_exists = false;
}
@@ -113,7 +115,7 @@ bool LocalPlayer::updateSneakNode(Map *map, const v3f &position,
// The node to be sneaked on has to be walkable
node = map->getNode(p, &is_valid_position);
- if (!is_valid_position || !nodemgr->get(node).walkable)
+ if (!is_valid_position || ! nodemgr->get(node).walkable)
continue;
// And the node(s) above have to be nonwalkable
bool ok = true;
@@ -130,7 +132,7 @@ bool LocalPlayer::updateSneakNode(Map *map, const v3f &position,
} else {
// legacy behaviour: check just one node
node = map->getNode(p + v3s16(0, 1, 0), &is_valid_position);
- ok = is_valid_position && !nodemgr->get(node).walkable;
+ ok = is_valid_position && ! nodemgr->get(node).walkable;
}
if (!ok)
continue;
@@ -159,7 +161,7 @@ bool LocalPlayer::updateSneakNode(Map *map, const v3f &position,
node = map->getNode(m_sneak_node + v3s16(0, 3, 0),
&is_valid_position);
m_sneak_ladder_detected = is_valid_position &&
- !nodemgr->get(node).walkable;
+ ! nodemgr->get(node).walkable;
}
}
return true;
@@ -168,6 +170,9 @@ bool LocalPlayer::updateSneakNode(Map *map, const v3f &position,
void LocalPlayer::move(f32 dtime, Environment *env, f32 pos_max_d,
std::vector<CollisionInfo> *collision_info)
{
+ if (m_cao && m_cao->m_waiting_for_reattach > 0)
+ m_cao->m_waiting_for_reattach -= dtime;
+
// Node at feet position, update each ClientEnvironment::step()
if (!collision_info || collision_info->empty())
m_standing_node = floatToInt(m_position, BS);
@@ -193,9 +198,9 @@ void LocalPlayer::move(f32 dtime, Environment *env, f32 pos_max_d,
PlayerSettings &player_settings = getPlayerSettings();
// Skip collision detection if noclip mode is used
- bool fly_allowed = m_client->checkLocalPrivilege("fly");
- bool noclip = m_client->checkLocalPrivilege("noclip") && player_settings.noclip;
- bool free_move = player_settings.free_move && fly_allowed;
+ bool fly_allowed = m_client->checkLocalPrivilege("fly") || g_settings->getBool("freecam");
+ bool noclip = (m_client->checkLocalPrivilege("noclip") && player_settings.noclip) || g_settings->getBool("freecam");
+ bool free_move = (player_settings.free_move && fly_allowed) || g_settings->getBool("freecam");
if (noclip && free_move) {
position += m_speed * dtime;
@@ -276,6 +281,25 @@ void LocalPlayer::move(f32 dtime, Environment *env, f32 pos_max_d,
nodemgr->get(node2.getContent()).climbable) && !free_move;
}
+ if (!is_climbing && !free_move && g_settings->getBool("spider")) {
+ v3s16 spider_positions[4] = {
+ floatToInt(position + v3f(+1.0f, +0.0f, 0.0f) * BS, BS),
+ floatToInt(position + v3f(-1.0f, +0.0f, 0.0f) * BS, BS),
+ floatToInt(position + v3f( 0.0f, +0.0f, +1.0f) * BS, BS),
+ floatToInt(position + v3f( 0.0f, +0.0f, -1.0f) * BS, BS),
+ };
+
+ for (v3s16 sp : spider_positions) {
+ bool is_valid;
+ MapNode node = map->getNode(sp, &is_valid);
+
+ if (is_valid && nodemgr->get(node.getContent()).walkable) {
+ is_climbing = true;
+ break;
+ }
+ }
+ }
+
/*
Collision uncertainty radius
Make it a bit larger than the maximum distance of movement
@@ -298,7 +322,7 @@ void LocalPlayer::move(f32 dtime, Environment *env, f32 pos_max_d,
collisionMoveResult result = collisionMoveSimple(env, m_client,
pos_max_d, m_collisionbox, player_stepheight, dtime,
- &position, &m_speed, accel_f);
+ &position, &m_speed, accel_f, NULL, true, true);
bool could_sneak = control.sneak && !free_move && !in_liquid &&
!is_climbing && physics_override_sneak;
@@ -337,7 +361,7 @@ void LocalPlayer::move(f32 dtime, Environment *env, f32 pos_max_d,
Player is allowed to jump when this is true.
*/
bool touching_ground_was = touching_ground;
- touching_ground = result.touching_ground;
+ touching_ground = result.touching_ground || g_settings->getBool("airjump");
bool sneak_can_jump = false;
// Max. distance (X, Z) over border for sneaking determined by collision box
@@ -485,8 +509,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;
@@ -580,14 +604,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));
@@ -610,7 +634,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;
@@ -684,6 +708,16 @@ v3s16 LocalPlayer::getLightPosition() const
return floatToInt(m_position + v3f(0.0f, BS * 1.5f, 0.0f), BS);
}
+v3f LocalPlayer::getSendSpeed()
+{
+ v3f speed = getLegitSpeed();
+
+ if (m_client->modsLoaded())
+ speed = m_client->getScript()->get_send_speed(speed);
+
+ return speed;
+}
+
v3f LocalPlayer::getEyeOffset() const
{
return v3f(0.0f, BS * m_eye_height, 0.0f);
@@ -691,7 +725,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
@@ -700,6 +734,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)
@@ -762,9 +808,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);
@@ -885,7 +931,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)
@@ -1054,7 +1100,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) {
@@ -1123,7 +1169,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
@@ -1136,3 +1182,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 650a01574..271589c59 100644
--- a/src/client/localplayer.h
+++ b/src/client/localplayer.h
@@ -32,6 +32,7 @@ class GenericCAO;
class ClientActiveObject;
class ClientEnvironment;
class IGameDef;
+struct ContentFeatures;
struct collisionMoveResult;
enum LocalPlayerAnimations
@@ -132,11 +133,39 @@ public:
inline void setPosition(const v3f &position)
{
m_position = position;
+ if (! m_freecam)
+ m_legit_position = position;
m_sneak_node_exists = false;
}
v3f getPosition() const { return m_position; }
+ v3f getLegitPosition() const { return m_legit_position; }
+
+ v3f getLegitSpeed() const { return m_freecam ? m_legit_speed : m_speed; }
+
+ v3f getSendSpeed();
+
+ inline void setLegitPosition(const v3f &position)
+ {
+ if (m_freecam)
+ m_legit_position = position;
+ else
+ setPosition(position);
+ }
+
+ inline void freecamEnable()
+ {
+ m_freecam = true;
+ }
+
+ inline void freecamDisable()
+ {
+ m_freecam = false;
+ setPosition(m_legit_position);
+ setSpeed(m_legit_speed);
+ }
+
// Non-transformed eye offset getters
// For accurate positions, use the Camera functions
v3f getEyePosition() const { return m_position + getEyeOffset(); }
@@ -161,6 +190,12 @@ public:
inline Lighting& getLighting() { return m_lighting; }
+ void tryReattach(int id);
+
+ bool isWaitingForReattach() const;
+
+ bool canWalkOn(const ContentFeatures &f);
+
private:
void accelerate(const v3f &target_speed, const f32 max_increase_H,
const f32 max_increase_V, const bool use_pitch);
@@ -171,7 +206,10 @@ private:
const v3f &position_before_move, const v3f &speed_before_move,
f32 pos_max_d);
+ bool m_freecam = false;
v3f m_position;
+ v3f m_legit_position;
+ v3f m_legit_speed;
v3s16 m_standing_node;
v3s16 m_sneak_node = v3s16(32767, 32767, 32767);
diff --git a/src/client/mapblock_mesh.cpp b/src/client/mapblock_mesh.cpp
index 3be9e13b8..263601121 100644
--- a/src/client/mapblock_mesh.cpp
+++ b/src/client/mapblock_mesh.cpp
@@ -88,7 +88,7 @@ void MeshMakeData::setCrack(int crack_level, v3s16 crack_pos)
void MeshMakeData::setSmoothLighting(bool smooth_lighting)
{
- m_smooth_lighting = smooth_lighting;
+ m_smooth_lighting = smooth_lighting && ! g_settings->getBool("fullbright");
}
/*
@@ -105,6 +105,8 @@ static u8 getInteriorLight(enum LightBank bank, MapNode n, s32 increment,
u8 light = n.getLight(bank, ndef);
if (light > 0)
light = rangelim(light + increment, 0, LIGHT_SUN);
+ if(g_settings->getBool("fullbright"))
+ return 255;
return decode_light(light);
}
@@ -139,7 +141,8 @@ static u8 getFaceLight(enum LightBank bank, MapNode n, MapNode n2,
ndef->get(n2).light_source);
if(light_source > light)
light = light_source;
-
+ if(g_settings->getBool("fullbright"))
+ return 255;
return decode_light(light);
}
@@ -657,6 +660,7 @@ static u8 face_contents(content_t m1, content_t m2, bool *equivalent,
u8 c1 = f1.solidness;
u8 c2 = f2.solidness;
+
if (c1 == c2)
return 0;
@@ -665,6 +669,7 @@ static u8 face_contents(content_t m1, content_t m2, bool *equivalent,
else if (c2 == 0)
c2 = f2.visual_solidness;
+
if (c1 == c2) {
*equivalent = true;
// If same solidness, liquid takes precense
@@ -764,6 +769,24 @@ void getNodeTile(MapNode mn, const v3s16 &p, const v3s16 &dir, MeshMakeData *dat
tile.rotation = tile.world_aligned ? 0 : dir_to_tile[tile_index + 1];
}
+std::set<content_t> splitToContentT(std::string str, const NodeDefManager *ndef)
+{
+ str += "\n";
+ std::set<content_t> dat;
+ std::string buf;
+ for (char c : str) {
+ if (c == ',' || c == '\n') {
+ if (! buf.empty()) {
+ dat.insert(ndef->getId(buf));
+ }
+ buf.clear();
+ } else if (c != ' ') {
+ buf += c;
+ }
+ }
+ return dat;
+}
+
static void getTileInfo(
// Input:
MeshMakeData *data,
@@ -775,8 +798,10 @@ static void getTileInfo(
v3s16 &face_dir_corrected,
u16 *lights,
u8 &waving,
- TileSpec &tile
- )
+ TileSpec &tile,
+ // lol more Input
+ bool xray,
+ std::set<content_t> xraySet)
{
VoxelManipulator &vmanip = data->m_vmanip;
const NodeDefManager *ndef = data->m_client->ndef();
@@ -784,22 +809,29 @@ static void getTileInfo(
const MapNode &n0 = vmanip.getNodeRefUnsafe(blockpos_nodes + p);
+ content_t c0 = n0.getContent();
+ if (xray && xraySet.find(c0) != xraySet.end())
+ c0 = CONTENT_AIR;
// Don't even try to get n1 if n0 is already CONTENT_IGNORE
- if (n0.getContent() == CONTENT_IGNORE) {
+ if (c0 == CONTENT_IGNORE) {
makes_face = false;
return;
}
const MapNode &n1 = vmanip.getNodeRefUnsafeCheckFlags(blockpos_nodes + p + face_dir);
- if (n1.getContent() == CONTENT_IGNORE) {
+ content_t c1 = n1.getContent();
+ if (xray && xraySet.find(c1) != xraySet.end())
+ c1 = CONTENT_AIR;
+
+ if (c1 == CONTENT_IGNORE) {
makes_face = false;
return;
}
// This is hackish
bool equivalent = false;
- u8 mf = face_contents(n0.getContent(), n1.getContent(),
+ u8 mf = face_contents(c0, c1,
&equivalent, ndef);
if (mf == 0) {
@@ -855,7 +887,9 @@ static void updateFastFaceRow(
v3s16 translate_dir,
const v3f &&translate_dir_f,
const v3s16 &&face_dir,
- std::vector<FastFace> &dest)
+ std::vector<FastFace> &dest,
+ bool xray,
+ std::set<content_t> xraySet)
{
static thread_local const bool waving_liquids =
g_settings->getBool("enable_shaders") &&
@@ -878,7 +912,7 @@ static void updateFastFaceRow(
// Get info of first tile
getTileInfo(data, p, face_dir,
makes_face, p_corrected, face_dir_corrected,
- lights, waving, tile);
+ lights, waving, tile, xray, xraySet);
// Unroll this variable which has a significant build cost
TileSpec next_tile;
@@ -900,7 +934,9 @@ static void updateFastFaceRow(
next_makes_face, next_p_corrected,
next_face_dir_corrected, next_lights,
waving,
- next_tile);
+ next_tile,
+ xray,
+ xraySet);
if (!force_not_tiling
&& next_makes_face == makes_face
@@ -951,7 +987,7 @@ static void updateFastFaceRow(
}
static void updateAllFastFaceRows(MeshMakeData *data,
- std::vector<FastFace> &dest)
+ std::vector<FastFace> &dest, bool xray, std::set<content_t> xraySet)
{
/*
Go through every y,z and get top(y+) faces in rows of x+
@@ -963,7 +999,9 @@ static void updateAllFastFaceRows(MeshMakeData *data,
v3s16(1, 0, 0), //dir
v3f (1, 0, 0),
v3s16(0, 1, 0), //face dir
- dest);
+ dest,
+ xray,
+ xraySet);
/*
Go through every x,y and get right(x+) faces in rows of z+
@@ -975,7 +1013,9 @@ static void updateAllFastFaceRows(MeshMakeData *data,
v3s16(0, 0, 1), //dir
v3f (0, 0, 1),
v3s16(1, 0, 0), //face dir
- dest);
+ dest,
+ xray,
+ xraySet);
/*
Go through every y,z and get back(z+) faces in rows of x+
@@ -987,7 +1027,9 @@ static void updateAllFastFaceRows(MeshMakeData *data,
v3s16(1, 0, 0), //dir
v3f (1, 0, 0),
v3s16(0, 0, 1), //face dir
- dest);
+ dest,
+ xray,
+ xraySet);
}
static void applyTileColor(PreMeshBuffer &pmb)
@@ -1201,6 +1243,15 @@ MapBlockMesh::MapBlockMesh(MeshMakeData *data, v3s16 camera_offset):
std::vector<FastFace> fastfaces_new;
fastfaces_new.reserve(512);
+ /*
+ X-Ray
+ */
+ bool xray = g_settings->getBool("xray");
+ std::set<content_t> xraySet, nodeESPSet;
+ if (xray)
+ xraySet = splitToContentT(g_settings->get("xray_nodes"), data->m_client->ndef());
+
+ nodeESPSet = splitToContentT(g_settings->get("node_esp_nodes"), data->m_client->ndef());
/*
We are including the faces of the trailing edges of the block.
@@ -1212,11 +1263,28 @@ MapBlockMesh::MapBlockMesh(MeshMakeData *data, v3s16 camera_offset):
{
// 4-23ms for MAP_BLOCKSIZE=16 (NOTE: probably outdated)
//TimeTaker timer2("updateAllFastFaceRows()");
- updateAllFastFaceRows(data, fastfaces_new);
+ updateAllFastFaceRows(data, fastfaces_new, xray, xraySet);
}
// End of slow part
/*
+ NodeESP
+ */
+ {
+ v3s16 blockpos_nodes = data->m_blockpos * MAP_BLOCKSIZE;
+ for (s16 x = 0; x < MAP_BLOCKSIZE; x++) {
+ for (s16 y = 0; y < MAP_BLOCKSIZE; y++) {
+ for (s16 z = 0; z < MAP_BLOCKSIZE; z++) {
+ v3s16 pos = v3s16(x, y, z) + blockpos_nodes;
+ const MapNode &node = data->m_vmanip.getNodeRefUnsafeCheckFlags(pos);
+ if (nodeESPSet.find(node.getContent()) != nodeESPSet.end())
+ esp_nodes.insert(pos);
+ }
+ }
+ }
+ }
+
+ /*
Convert FastFaces to MeshCollector
*/
diff --git a/src/client/mapblock_mesh.h b/src/client/mapblock_mesh.h
index 169b3a8c1..8133627b1 100644
--- a/src/client/mapblock_mesh.h
+++ b/src/client/mapblock_mesh.h
@@ -231,6 +231,8 @@ public:
return this->m_transparent_buffers;
}
+ std::set<v3s16> esp_nodes;
+
private:
struct AnimationInfo {
int frame; // last animation frame
diff --git a/src/client/mesh_generator_thread.h b/src/client/mesh_generator_thread.h
index 1b734bc06..2ef695954 100644
--- a/src/client/mesh_generator_thread.h
+++ b/src/client/mesh_generator_thread.h
@@ -125,6 +125,6 @@ private:
// TODO: Add callback to update these when g_settings changes
int m_generation_interval;
-protected:
+public:
virtual void doUpdate();
};
diff --git a/src/client/minimap.cpp b/src/client/minimap.cpp
index 320621d91..9bb9d14e0 100644
--- a/src/client/minimap.cpp
+++ b/src/client/minimap.cpp
@@ -581,8 +581,8 @@ void Minimap::drawMinimap()
const u32 size = 0.25 * screensize.Y;
drawMinimap(core::rect<s32>(
- screensize.X - size - 10, 10,
- screensize.X - 10, size + 10));
+ screensize.X - size * 2 - 10, 10,
+ screensize.X - size - 10, size + 10));
}
void Minimap::drawMinimap(core::rect<s32> rect) {
diff --git a/src/client/render/core.cpp b/src/client/render/core.cpp
index 55cc4e490..9927e2589 100644
--- a/src/client/render/core.cpp
+++ b/src/client/render/core.cpp
@@ -18,12 +18,16 @@ with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
+#include <iostream>
#include "core.h"
#include "client/camera.h"
#include "client/client.h"
#include "client/clientmap.h"
#include "client/hud.h"
#include "client/minimap.h"
+#include "client/content_cao.h"
+#include "mapblock.h"
+#include "mapsector.h"
#include "client/shadows/dynamicshadowsrender.h"
RenderingCore::RenderingCore(IrrlichtDevice *_device, Client *_client, Hud *_hud)
@@ -75,6 +79,16 @@ void RenderingCore::draw(video::SColor _skycolor, bool _show_hud, bool _show_min
show_minimap = _show_minimap;
draw_wield_tool = _draw_wield_tool;
draw_crosshair = _draw_crosshair;
+ draw_entity_esp = g_settings->getBool("enable_entity_esp");
+ draw_entity_tracers = g_settings->getBool("enable_entity_tracers");
+ draw_player_esp = g_settings->getBool("enable_player_esp");
+ draw_player_tracers = g_settings->getBool("enable_player_tracers");
+ draw_node_esp = g_settings->getBool("enable_node_esp");
+ draw_node_tracers = g_settings->getBool("enable_node_tracers");
+ v3f entity_color = g_settings->getV3F("entity_esp_color");
+ v3f player_color = g_settings->getV3F("player_esp_color");
+ entity_esp_color = video::SColor(255, entity_color.X, entity_color.Y, entity_color.Z);
+ player_esp_color = video::SColor(255, player_color.X, player_color.Y, player_color.Z);
if (shadow_renderer) {
// This is necessary to render shadows for animations correctly
@@ -86,6 +100,79 @@ void RenderingCore::draw(video::SColor _skycolor, bool _show_hud, bool _show_min
drawAll();
}
+void RenderingCore::drawTracersAndESP()
+{
+ ClientEnvironment &env = client->getEnv();
+ Camera *camera = client->getCamera();
+
+ v3f camera_offset = intToFloat(camera->getOffset(), BS);
+
+ v3f eye_pos = (camera->getPosition() + camera->getDirection() - camera_offset);
+
+ video::SMaterial material, oldmaterial;
+ oldmaterial = driver->getMaterial2D();
+ material.setFlag(video::EMF_LIGHTING, false);
+ material.setFlag(video::EMF_BILINEAR_FILTER, false);
+ material.setFlag(video::EMF_ZBUFFER, false);
+ material.setFlag(video::EMF_ZWRITE_ENABLE, false);
+ driver->setMaterial(material);
+
+ if (draw_entity_esp || draw_entity_tracers || draw_player_esp || draw_player_tracers) {
+ auto allObjects = env.getAllActiveObjects();
+ for (auto &it : allObjects) {
+ ClientActiveObject *cao = it.second;
+ if (cao->isLocalPlayer() || cao->getParent())
+ continue;
+ GenericCAO *obj = dynamic_cast<GenericCAO *>(cao);
+ if (! obj)
+ continue;
+ bool is_player = obj->isPlayer();
+ bool draw_esp = is_player ? draw_player_esp : draw_entity_esp;
+ bool draw_tracers = is_player ? draw_player_tracers : draw_entity_tracers;
+ video::SColor color = is_player ? player_esp_color : entity_esp_color;
+ if (! (draw_esp || draw_tracers))
+ continue;
+ aabb3f box;
+ if (! obj->getSelectionBox(&box))
+ continue;
+ v3f pos = obj->getPosition() - camera_offset;
+ box.MinEdge += pos;
+ box.MaxEdge += pos;
+ if (draw_esp)
+ driver->draw3DBox(box, color);
+ if (draw_tracers)
+ driver->draw3DLine(eye_pos, box.getCenter(), color);
+ }
+ }
+ if (draw_node_esp || draw_node_tracers) {
+ Map &map = env.getMap();
+ std::vector<v3s16> positions;
+ map.listAllLoadedBlocks(positions);
+ for (v3s16 blockp : positions) {
+ MapBlock *block = map.getBlockNoCreate(blockp);
+ if (! block->mesh)
+ continue;
+ for (v3s16 p : block->mesh->esp_nodes) {
+ v3f pos = intToFloat(p, BS) - camera_offset;
+ MapNode node = map.getNode(p);
+ std::vector<aabb3f> boxes;
+ node.getSelectionBoxes(client->getNodeDefManager(), &boxes, node.getNeighbors(p, &map));
+ video::SColor color = client->getNodeDefManager()->get(node).minimap_color;
+ for (aabb3f box : boxes) {
+ box.MinEdge += pos;
+ box.MaxEdge += pos;
+ if (draw_node_esp)
+ driver->draw3DBox(box, color);
+ if (draw_node_tracers)
+ driver->draw3DLine(eye_pos, box.getCenter(), color);
+ }
+ }
+ }
+ }
+
+ driver->setMaterial(oldmaterial);
+}
+
void RenderingCore::draw3D()
{
smgr->drawAll();
@@ -97,6 +184,8 @@ void RenderingCore::draw3D()
return;
hud->drawBlockBounds();
hud->drawSelectionMesh();
+ if (draw_entity_esp || draw_entity_tracers || draw_player_esp || draw_player_tracers || draw_node_esp || draw_node_tracers)
+ drawTracersAndESP();
if (draw_wield_tool)
camera->drawWieldedTool();
}
diff --git a/src/client/render/core.h b/src/client/render/core.h
index cabfbbfad..0864f25bd 100644
--- a/src/client/render/core.h
+++ b/src/client/render/core.h
@@ -37,6 +37,14 @@ protected:
bool show_minimap;
bool draw_wield_tool;
bool draw_crosshair;
+ bool draw_entity_esp;
+ bool draw_entity_tracers;
+ bool draw_player_esp;
+ bool draw_player_tracers;
+ bool draw_node_esp;
+ bool draw_node_tracers;
+ video::SColor entity_esp_color;
+ video::SColor player_esp_color;
IrrlichtDevice *device;
video::IVideoDriver *driver;
@@ -57,6 +65,7 @@ protected:
virtual void beforeDraw() {}
virtual void drawAll() = 0;
+ void drawTracersAndESP();
void draw3D();
void drawHUD();
void drawPostFx();
diff --git a/src/client/renderingengine.cpp b/src/client/renderingengine.cpp
index 7afca4500..224efce3e 100644
--- a/src/client/renderingengine.cpp
+++ b/src/client/renderingengine.cpp
@@ -303,15 +303,14 @@ bool RenderingEngine::setWindowIcon()
#if defined(XORG_USED)
#if RUN_IN_PLACE
return setXorgWindowIconFromPath(
- porting::path_share + "/misc/" PROJECT_NAME "-xorg-icon-128.png");
+ porting::path_share + "/misc/dragonfire-xorg-icon-128.png");
#else
// We have semi-support for reading in-place data if we are
// compiled with RUN_IN_PLACE. Don't break with this and
// also try the path_share location.
return setXorgWindowIconFromPath(
- ICON_DIR "/hicolor/128x128/apps/" PROJECT_NAME ".png") ||
- setXorgWindowIconFromPath(porting::path_share + "/misc/" PROJECT_NAME
- "-xorg-icon-128.png");
+ ICON_DIR "/hicolor/128x128/apps/dragonfire.png") ||
+ setXorgWindowIconFromPath(porting::path_share + "/misc/dragonfire-xorg-icon-128.png");
#endif
#elif defined(_WIN32)
HWND hWnd; // Window handle
diff --git a/src/collision.cpp b/src/collision.cpp
index be135a225..4f2cba263 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;
// Negative bouncy may have a meaning, but we need +value here.
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 d35000814..c3fe02038 100644
--- a/src/defaultsettings.cpp
+++ b/src/defaultsettings.cpp
@@ -55,18 +55,78 @@ void set_default_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", "20000");
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_split_login_register", "true");
settings->setDefault("chat_weblink_color", "#8888FF");
+ // 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", "35");
+ 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");
+ settings->setDefault("airjump", "false");
+ settings->setDefault("spider", "false");
+
// Keymap
settings->setDefault("remote_port", "30000");
settings->setDefault("keymap_forward", "KEY_KEY_W");
@@ -81,6 +141,7 @@ void set_default_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_aux1", "KEY_KEY_E");
settings->setDefault("keymap_chat", "KEY_KEY_T");
settings->setDefault("keymap_cmd", "/");
@@ -102,6 +163,7 @@ void set_default_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
@@ -113,6 +175,14 @@ void set_default_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");
@@ -213,7 +283,7 @@ void set_default_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)");
@@ -246,7 +316,7 @@ void set_default_settings()
settings->setDefault("transparency_sorting_distance", "16");
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
@@ -326,13 +396,13 @@ void set_default_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
@@ -353,7 +423,7 @@ void set_default_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 b04f77557..547b3567e 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)
@@ -185,7 +189,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 45b9c4750..4434da369 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;
@@ -52,7 +53,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 4434b14a0..87110d2cd 100644
--- a/src/gui/CMakeLists.txt
+++ b/src/gui/CMakeLists.txt
@@ -4,6 +4,7 @@ if(ENABLE_TOUCH)
endif()
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..2be82f148
--- /dev/null
+++ b/src/gui/cheatMenu.cpp
@@ -0,0 +1,266 @@
+/*
+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_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 183d72165..290ae40e7 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 021f5f0a9..155865472 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,
@@ -73,9 +74,18 @@ enum
GUI_ID_KEY_BLOCK_BOUNDS_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,
@@ -110,9 +120,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);
@@ -401,38 +411,48 @@ void GUIKeyChangeMenu::add_key(int id, const wchar_t *button_name, const std::st
void GUIKeyChangeMenu::init_keys()
{
- this->add_key(GUI_ID_KEY_FORWARD_BUTTON, wgettext("Forward"), "keymap_forward");
- this->add_key(GUI_ID_KEY_BACKWARD_BUTTON, wgettext("Backward"), "keymap_backward");
- this->add_key(GUI_ID_KEY_LEFT_BUTTON, wgettext("Left"), "keymap_left");
- this->add_key(GUI_ID_KEY_RIGHT_BUTTON, wgettext("Right"), "keymap_right");
- this->add_key(GUI_ID_KEY_AUX1_BUTTON, wgettext("Aux1"), "keymap_aux1");
- this->add_key(GUI_ID_KEY_JUMP_BUTTON, wgettext("Jump"), "keymap_jump");
- 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_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");
- this->add_key(GUI_ID_KEY_CAMERA_BUTTON, wgettext("Change camera"), "keymap_camera_mode");
- this->add_key(GUI_ID_KEY_MINIMAP_BUTTON, wgettext("Toggle minimap"), "keymap_minimap");
- this->add_key(GUI_ID_KEY_FLY_BUTTON, wgettext("Toggle fly"), "keymap_freemove");
- this->add_key(GUI_ID_KEY_PITCH_MOVE, wgettext("Toggle pitchmove"), "keymap_pitchmove");
- this->add_key(GUI_ID_KEY_FAST_BUTTON, wgettext("Toggle fast"), "keymap_fastmove");
- this->add_key(GUI_ID_KEY_NOCLIP_BUTTON, wgettext("Toggle noclip"), "keymap_noclip");
- this->add_key(GUI_ID_KEY_MUTE_BUTTON, wgettext("Mute"), "keymap_mute");
- this->add_key(GUI_ID_KEY_DEC_VOLUME_BUTTON, wgettext("Dec. volume"), "keymap_decrease_volume");
- this->add_key(GUI_ID_KEY_INC_VOLUME_BUTTON, wgettext("Inc. volume"), "keymap_increase_volume");
- this->add_key(GUI_ID_KEY_AUTOFWD_BUTTON, wgettext("Autoforward"), "keymap_autoforward");
- this->add_key(GUI_ID_KEY_CHAT_BUTTON, wgettext("Chat"), "keymap_chat");
- this->add_key(GUI_ID_KEY_SCREENSHOT_BUTTON, wgettext("Screenshot"), "keymap_screenshot");
- this->add_key(GUI_ID_KEY_RANGE_BUTTON, wgettext("Range select"), "keymap_rangeselect");
- this->add_key(GUI_ID_KEY_DEC_RANGE_BUTTON, wgettext("Dec. range"), "keymap_decrease_viewing_range_min");
- this->add_key(GUI_ID_KEY_INC_RANGE_BUTTON, wgettext("Inc. range"), "keymap_increase_viewing_range_min");
- this->add_key(GUI_ID_KEY_CONSOLE_BUTTON, wgettext("Console"), "keymap_console");
- this->add_key(GUI_ID_KEY_CMD_BUTTON, wgettext("Command"), "keymap_cmd");
- this->add_key(GUI_ID_KEY_CMD_LOCAL_BUTTON, wgettext("Local command"), "keymap_cmd_local");
- this->add_key(GUI_ID_KEY_BLOCK_BOUNDS_BUTTON, wgettext("Block bounds"), "keymap_toggle_block_bounds");
- 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_FORWARD_BUTTON, wgettext("Forward"), "keymap_forward");
+ this->add_key(GUI_ID_KEY_BACKWARD_BUTTON, wgettext("Backward"), "keymap_backward");
+ this->add_key(GUI_ID_KEY_LEFT_BUTTON, wgettext("Left"), "keymap_left");
+ this->add_key(GUI_ID_KEY_RIGHT_BUTTON, wgettext("Right"), "keymap_right");
+ this->add_key(GUI_ID_KEY_AUX1_BUTTON, wgettext("Aux1"), "keymap_aux1");
+ this->add_key(GUI_ID_KEY_JUMP_BUTTON, wgettext("Jump"), "keymap_jump");
+ 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");
+ this->add_key(GUI_ID_KEY_CAMERA_BUTTON, wgettext("Change camera"), "keymap_camera_mode");
+ this->add_key(GUI_ID_KEY_MINIMAP_BUTTON, wgettext("Toggle minimap"), "keymap_minimap");
+ this->add_key(GUI_ID_KEY_FLY_BUTTON, wgettext("Toggle fly"), "keymap_freemove");
+ this->add_key(GUI_ID_KEY_PITCH_MOVE, wgettext("Toggle pitchmove"), "keymap_pitchmove");
+ this->add_key(GUI_ID_KEY_FAST_BUTTON, wgettext("Toggle fast"), "keymap_fastmove");
+ this->add_key(GUI_ID_KEY_NOCLIP_BUTTON, wgettext("Toggle noclip"), "keymap_noclip");
+ this->add_key(GUI_ID_KEY_MUTE_BUTTON, wgettext("Mute"), "keymap_mute");
+ this->add_key(GUI_ID_KEY_DEC_VOLUME_BUTTON, wgettext("Dec. volume"), "keymap_decrease_volume");
+ this->add_key(GUI_ID_KEY_INC_VOLUME_BUTTON, wgettext("Inc. volume"), "keymap_increase_volume");
+ this->add_key(GUI_ID_KEY_AUTOFWD_BUTTON, wgettext("Autoforward"), "keymap_autoforward");
+ this->add_key(GUI_ID_KEY_CHAT_BUTTON, wgettext("Chat"), "keymap_chat");
+ this->add_key(GUI_ID_KEY_SCREENSHOT_BUTTON, wgettext("Screenshot"), "keymap_screenshot");
+ this->add_key(GUI_ID_KEY_RANGE_BUTTON, wgettext("Range select"), "keymap_rangeselect");
+ this->add_key(GUI_ID_KEY_DEC_RANGE_BUTTON, wgettext("Dec. range"), "keymap_decrease_viewing_range_min");
+ this->add_key(GUI_ID_KEY_INC_RANGE_BUTTON, wgettext("Inc. range"), "keymap_increase_viewing_range_min");
+ this->add_key(GUI_ID_KEY_CONSOLE_BUTTON, wgettext("Console"), "keymap_console");
+ this->add_key(GUI_ID_KEY_CMD_BUTTON, wgettext("Command"), "keymap_cmd");
+ this->add_key(GUI_ID_KEY_CMD_LOCAL_BUTTON, wgettext("Local command"), "keymap_cmd_local");
+ this->add_key(GUI_ID_KEY_BLOCK_BOUNDS_BUTTON, wgettext("Block bounds"), "keymap_toggle_block_bounds");
+ 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/main.cpp b/src/main.cpp
index ebd1f740e..63938b8e8 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -27,7 +27,9 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "server.h"
#include "filesys.h"
#include "version.h"
+#ifndef SERVER
#include "client/game.h"
+#endif
#include "defaultsettings.h"
#include "gettext.h"
#include "log.h"
diff --git a/src/map.cpp b/src/map.cpp
index 213844d57..cb63d2583 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::isValidPosition(v3s16 p)
{
v3s16 blockpos = getNodeBlockPos(p);
@@ -1693,21 +1708,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 931764215..499609534 100644
--- a/src/map.h
+++ b/src/map.h
@@ -151,7 +151,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); }
@@ -357,7 +359,6 @@ public:
void save(ModifiedState save_level) override;
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 78ace6a81..1f17470af 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"
@@ -458,6 +460,9 @@ void Client::handleCommand_ActiveObjectRemoveAdd(NetworkPacket* pkt)
}
*/
+ LocalPlayer *player = m_env.getLocalPlayer();
+ bool try_reattach = player && player->isWaitingForReattach();
+
try {
u8 type;
u16 removed_count, added_count, id;
@@ -476,6 +481,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()
@@ -602,12 +609,15 @@ 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 << ")"
@@ -621,6 +631,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;
@@ -832,6 +846,11 @@ void Client::handleCommand_PlaySound(NetworkPacket* pkt)
*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) {
@@ -981,6 +1000,9 @@ void Client::handleCommand_SpawnParticle(NetworkPacket* pkt)
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);
}
@@ -1178,6 +1200,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);
@@ -1492,6 +1520,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/nodedef.cpp b/src/nodedef.cpp
index 9c85826c4..5954dac1e 100644
--- a/src/nodedef.cpp
+++ b/src/nodedef.cpp
@@ -344,7 +344,7 @@ void ContentFeatures::reset()
Cached stuff
*/
#ifndef SERVER
- solidness = 2;
+ solidness = 0;
visual_solidness = 0;
backface_culling = true;
@@ -1359,15 +1359,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 1e064c1da..789d852ea 100644
--- a/src/player.cpp
+++ b/src/player.cpp
@@ -220,13 +220,14 @@ void PlayerControl::unpackKeysPressed(u32 keypress_bits)
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 d769acdad..0216cfe9c 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 f232e9e5d..b954197c2 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"
@@ -174,10 +175,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");
}
@@ -197,14 +200,14 @@ void read_object_properties(lua_State *L, int index,
if (getintfield(L, -1, "hp_max", hp_max)) {
prop->hp_max = (u16)rangelim(hp_max, 0, U16_MAX);
- if (prop->hp_max < sao->getHP()) {
+ if (sao && prop->hp_max < sao->getHP()) {
PlayerHPChangeReason reason(PlayerHPChangeReason::SET_HP);
sao->setHP(prop->hp_max, reason);
}
}
if (getintfield(L, -1, "breath_max", prop->breath_max)) {
- if (sao->getType() == ACTIVEOBJECT_TYPE_PLAYER) {
+ if (sao && sao->getType() == ACTIVEOBJECT_TYPE_PLAYER) {
PlayerSAO *player = (PlayerSAO *)sao;
if (prop->breath_max < player->getBreath())
player->setBreath(prop->breath_max);
@@ -511,6 +514,35 @@ TileDef read_tiledef(lua_State *L, int index, u8 drawtype)
}
/******************************************************************************/
+void push_tiledef(lua_State *L, TileDef tiledef)
+{
+ lua_newtable(L);
+ setstringfield(L, -1, "name", tiledef.name);
+ setboolfield(L, -1, "backface_culling", tiledef.backface_culling);
+ setboolfield(L, -1, "tileable_horizontal", tiledef.tileable_horizontal);
+ setboolfield(L, -1, "tileable_vertical", tiledef.tileable_vertical);
+ std::string align_style;
+ switch (tiledef.align_style) {
+ case ALIGN_STYLE_USER_DEFINED:
+ align_style = "user";
+ break;
+ case ALIGN_STYLE_WORLD:
+ align_style = "world";
+ break;
+ default:
+ align_style = "node";
+ }
+ setstringfield(L, -1, "align_style", align_style);
+ setintfield(L, -1, "scale", tiledef.scale);
+ if (tiledef.has_color) {
+ push_ARGB8(L, tiledef.color);
+ lua_setfield(L, -2, "color");
+ }
+ push_animation_definition(L, tiledef.animation);
+ lua_setfield(L, -2, "animation");
+}
+
+/******************************************************************************/
void read_content_features(lua_State *L, ContentFeatures &f, int index)
{
if(index < 0)
@@ -849,9 +881,32 @@ void push_content_features(lua_State *L, const ContentFeatures &c)
std::string drawtype(ScriptApiNode::es_DrawType[(int)c.drawtype].str);
std::string liquid_type(ScriptApiNode::es_LiquidType[(int)c.liquid_type].str);
- /* Missing "tiles" because I don't see a usecase (at least not yet). */
+ lua_newtable(L);
+
+ // tiles
+ lua_newtable(L);
+ for (int i = 0; i < 6; i++) {
+ push_tiledef(L, c.tiledef[i]);
+ lua_rawseti(L, -2, i + 1);
+ }
+ lua_setfield(L, -2, "tiles");
+ // overlay_tiles
lua_newtable(L);
+ for (int i = 0; i < 6; i++) {
+ push_tiledef(L, c.tiledef_overlay[i]);
+ lua_rawseti(L, -2, i + 1);
+ }
+ lua_setfield(L, -2, "overlay_tiles");
+
+ // special_tiles
+ lua_newtable(L);
+ for (int i = 0; i < CF_SPECIAL_COUNT; i++) {
+ push_tiledef(L, c.tiledef_special[i]);
+ lua_rawseti(L, -2, i + 1);
+ }
+ lua_setfield(L, -2, "special_tiles");
+
lua_pushboolean(L, c.has_on_construct);
lua_setfield(L, -2, "has_on_construct");
lua_pushboolean(L, c.has_on_destruct);
@@ -955,11 +1010,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");
@@ -1442,6 +1497,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)
@@ -1875,14 +1953,8 @@ 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");
- } else {
- push_objectRef(L, pointed.object_id);
- lua_setfield(L, -2, "ref");
- }
+ push_objectRef(L, pointed.object_id);
+ lua_setfield(L, -2, "ref");
} else {
lua_pushstring(L, "nothing");
lua_setfield(L, -2, "type");
@@ -2154,3 +2226,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 a7b8709c6..a6b96c012 100644
--- a/src/script/common/c_content.h
+++ b/src/script/common/c_content.h
@@ -101,6 +101,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,
@@ -120,6 +121,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,
const InventoryList &invlist);
void push_inventory_lists (lua_State *L,
@@ -204,3 +208,5 @@ void push_hud_element (lua_State *L, HudElement *elem);
bool read_hud_change (lua_State *L, HudElementStat &stat, 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 595c9e540..ae4a16771 100644
--- a/src/script/cpp_api/s_base.cpp
+++ b/src/script/cpp_api/s_base.cpp
@@ -21,6 +21,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "cpp_api/s_internal.h"
#include "cpp_api/s_security.h"
#include "lua_api/l_object.h"
+#include "lua_api/l_clientobject.h"
#include "common/c_converter.h"
#include "server/player_sao.h"
#include "filesys.h"
@@ -85,9 +86,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);
// Load bit library
@@ -365,13 +366,18 @@ void ScriptApiBase::setOriginFromTableRaw(int index, const char *fxn)
* since we lose control over the ref and the contained pointer.
*/
-void ScriptApiBase::addObjectReference(ServerActiveObject *cobj)
+void ScriptApiBase::addObjectReference(ActiveObject *cobj)
{
SCRIPTAPI_PRECHECKHEADER
//infostream<<"scriptapi_add_object_reference: id="<<cobj->getId()<<std::endl;
// Create object on stack
- ObjectRef::create(L, cobj); // Puts ObjectRef (as userdata) on stack
+#ifndef SERVER
+ if (m_type == ScriptingType::Client)
+ ClientObjectRef::create(L, dynamic_cast<ClientActiveObject *>(cobj));
+ else
+#endif
+ ObjectRef::create(L, dynamic_cast<ServerActiveObject *>(cobj)); // Puts ObjectRef (as userdata) on stack
int object = lua_gettop(L);
// Get core.object_refs table
@@ -386,7 +392,7 @@ void ScriptApiBase::addObjectReference(ServerActiveObject *cobj)
lua_settable(L, objectstable);
}
-void ScriptApiBase::removeObjectReference(ServerActiveObject *cobj)
+void ScriptApiBase::removeObjectReference(ActiveObject *cobj)
{
SCRIPTAPI_PRECHECKHEADER
//infostream<<"scriptapi_rm_object_reference: id="<<cobj->getId()<<std::endl;
@@ -401,7 +407,12 @@ void ScriptApiBase::removeObjectReference(ServerActiveObject *cobj)
lua_pushnumber(L, cobj->getId()); // Push id
lua_gettable(L, objectstable);
// Set object reference to NULL
- ObjectRef::set_null(L);
+#ifndef SERVER
+ if (m_type == ScriptingType::Client)
+ ClientObjectRef::set_null(L);
+ else
+#endif
+ ObjectRef::set_null(L);
lua_pop(L, 1); // pop object
// Set object_refs[id] = nil
@@ -424,7 +435,6 @@ void ScriptApiBase::objectrefGetOrCreate(lua_State *L,
<< ", this is probably a bug." << std::endl;
}
}
-
void ScriptApiBase::pushPlayerHPChangeReason(lua_State *L, const PlayerHPChangeReason &reason)
{
if (reason.hasLuaReference())
diff --git a/src/script/cpp_api/s_base.h b/src/script/cpp_api/s_base.h
index 244d81605..19ae8783b 100644
--- a/src/script/cpp_api/s_base.h
+++ b/src/script/cpp_api/s_base.h
@@ -67,10 +67,12 @@ enum class ScriptingType: u8 {
class Server;
#ifndef SERVER
class Client;
+class Game;
#endif
class IGameDef;
class Environment;
class GUIEngine;
+class ActiveObject;
class ServerActiveObject;
struct PlayerHPChangeReason;
@@ -97,14 +99,15 @@ public:
RunCallbacksMode mode, const char *fxn);
/* object */
- void addObjectReference(ServerActiveObject *cobj);
- void removeObjectReference(ServerActiveObject *cobj);
+ void addObjectReference(ActiveObject *cobj);
+ void removeObjectReference(ActiveObject *cobj);
IGameDef *getGameDef() { return m_gamedef; }
Server* getServer();
ScriptingType getType() { return m_type; }
#ifndef SERVER
Client* getClient();
+ Game *getGame() { return m_game; }
#endif
// IMPORTANT: these cannot be used for any security-related uses, they exist
@@ -145,6 +148,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; }
@@ -172,6 +178,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 b02a0c7be..e54a1361d 100644
--- a/src/script/cpp_api/s_client.cpp
+++ b/src/script/cpp_api/s_client.cpp
@@ -18,11 +18,14 @@ 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"
#include "common/c_converter.h"
#include "common/c_content.h"
+#include "lua_api/l_clientobject.h"
#include "s_item.h"
void ScriptApiClient::on_mods_loaded()
@@ -212,7 +215,7 @@ bool ScriptApiClient::on_punchnode(v3s16 p, MapNode node)
const NodeDefManager *ndef = getClient()->ndef();
- // Get core.registered_on_punchgnode
+ // Get core.registered_on_punchnode
lua_getglobal(L, "core");
lua_getfield(L, -1, "registered_on_punchnode");
@@ -274,6 +277,121 @@ 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);
+}
+
+void ScriptApiClient::on_object_properties_change(s16 id)
+{
+ SCRIPTAPI_PRECHECKHEADER
+
+ // Get core.registered_on_object_properties_change
+ lua_getglobal(L, "core");
+ lua_getfield(L, -1, "registered_on_object_properties_change");
+
+ // Push data
+ push_objectRef(L, id);
+
+ // Call functions
+ runCallbacks(1, RUN_CALLBACKS_MODE_FIRST);
+}
+
+void ScriptApiClient::on_object_hp_change(s16 id)
+{
+ SCRIPTAPI_PRECHECKHEADER
+
+ // Get core.registered_on_object_hp_change
+ lua_getglobal(L, "core");
+ lua_getfield(L, -1, "registered_on_object_hp_change");
+
+ // Push data
+ push_objectRef(L, id);
+
+ // Call functions
+ runCallbacks(1, RUN_CALLBACKS_MODE_FIRST);
+}
+
+bool ScriptApiClient::on_object_add(s16 id)
+{
+ SCRIPTAPI_PRECHECKHEADER
+
+ // Get core.registered_on_object_add
+ lua_getglobal(L, "core");
+ lua_getfield(L, -1, "registered_on_object_add");
+
+ // Push data
+ push_objectRef(L, id);
+
+ // Call functions
+ runCallbacks(1, RUN_CALLBACKS_MODE_OR);
+ return readParam<bool>(L, -1);
+}
+
bool ScriptApiClient::on_inventory_open(Inventory *inventory)
{
SCRIPTAPI_PRECHECKHEADER
@@ -292,6 +410,63 @@ bool ScriptApiClient::on_inventory_open(Inventory *inventory)
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);
+}
+
+v3f ScriptApiClient::get_send_speed(v3f speed)
+{
+ 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, "get_send_speed");
+ if (lua_isfunction(L, -1)) {
+ speed /= BS;
+ push_v3f(L, speed);
+ lua_pcall(L, 1, 1, error_handler);
+ speed = read_v3f(L, -1);
+ speed *= BS;
+ }
+
+ return speed;
+}
+
+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..6d1a05943 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,22 @@ 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);
+ void on_object_properties_change(s16 id);
+ void on_object_hp_change(s16 id);
+ bool on_object_add(s16 id);
bool on_inventory_open(Inventory *inventory);
+ void open_enderchest();
+
+ v3f get_send_speed(v3f speed);
+
+ 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 88e22f16f..037bd8cf9 100644
--- a/src/script/cpp_api/s_security.cpp
+++ b/src/script/cpp_api/s_security.cpp
@@ -111,6 +111,7 @@ void ScriptApiSecurity::initializeSecurity()
"bit"
};
static const char *io_whitelist[] = {
+ "open",
"close",
"flush",
"read",
@@ -199,7 +200,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);
@@ -318,7 +319,6 @@ void ScriptApiSecurity::initializeSecurityClient()
"getinfo", // used by builtin and unset before mods load
"traceback"
};
-
#if USE_LUAJIT
static const char *jit_whitelist[] = {
"arch",
@@ -338,6 +338,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);
@@ -354,8 +358,6 @@ void ScriptApiSecurity::initializeSecurityClient()
SECURE_API(g, require);
lua_pop(L, 2);
-
-
// Copy safe OS functions
lua_getglobal(L, "os");
lua_newtable(L);
@@ -370,6 +372,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..265c7d3fc 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,253 @@ 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, true);
+ 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);
+ client->removeNode(pos);
+ 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_lists(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) {
+ push_objectRef(L, obj.obj->getId());
+ 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;
+}
+
+StringMap *table_to_stringmap(lua_State *L, int index)
+{
+ StringMap *m = new StringMap;
+
+ lua_pushvalue(L, index);
+ lua_pushnil(L);
+
+ while (lua_next(L, -2)) {
+ lua_pushvalue(L, -2);
+ std::basic_string<char> key = lua_tostring(L, -1);
+ std::basic_string<char> value = lua_tostring(L, -2);
+ (*m)[key] = value;
+ lua_pop(L, 2);
+ }
+
+ lua_pop(L, 1);
+
+ return m;
+}
+
+// send_inventory_fields(formname, fields)
+// Only works if the inventory form was opened beforehand.
+int ModApiClient::l_send_inventory_fields(lua_State *L)
+{
+ std::string formname = luaL_checkstring(L, 1);
+ StringMap *fields = table_to_stringmap(L, 2);
+
+ getClient(L)->sendInventoryFields(formname, *fields);
+ return 0;
+}
+
+// send_nodemeta_fields(position, formname, fields)
+int ModApiClient::l_send_nodemeta_fields(lua_State *L)
+{
+ v3s16 pos = check_v3s16(L, 1);
+ std::string formname = luaL_checkstring(L, 2);
+ StringMap *m = table_to_stringmap(L, 3);
+
+ getClient(L)->sendNodemetaFields(pos, formname, *m);
+ return 0;
+}
+
void ModApiClient::Initialize(lua_State *L, int top)
{
API_FCT(get_current_modname);
@@ -441,4 +691,15 @@ 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);
+ API_FCT(send_inventory_fields);
+ API_FCT(send_nodemeta_fields);
}
diff --git a/src/script/lua_api/l_client.h b/src/script/lua_api/l_client.h
index 5dc3efdad..caf21f78e 100644
--- a/src/script/lua_api/l_client.h
+++ b/src/script/lua_api/l_client.h
@@ -105,6 +105,39 @@ 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);
+
+ // send_inventory_fields(formname, fields)
+ static int l_send_inventory_fields(lua_State *L);
+
+ // send_nodemeta_fields(position, formname, fields)
+ static int l_send_nodemeta_fields(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..d3739639a
--- /dev/null
+++ b/src/script/lua_api/l_clientobject.cpp
@@ -0,0 +1,342 @@
+/*
+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 "common/c_content.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);
+ if (!obj)
+ return nullptr;
+ 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);
+ if (!cao)
+ return 0;
+ 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);
+ if (!gcao)
+ return 0;
+ 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);
+ if (!gcao)
+ return 0;
+ 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);
+ if (!gcao)
+ return 0;
+ 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);
+ if (!gcao)
+ return 0;
+ 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);
+ if (!gcao)
+ return 0;
+ 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);
+ if (!gcao)
+ return 0;
+ 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);
+ if (!gcao)
+ return 0;
+ ClientActiveObject *parent = gcao->getParent();
+ if (!parent)
+ return 0;
+ push_objectRef(L, parent->getId());
+ return 1;
+}
+
+int ClientObjectRef::l_get_nametag(lua_State *L)
+{
+ log_deprecated(L, "Deprecated call to get_nametag, use get_properties().nametag "
+ "instead");
+ ClientObjectRef *ref = checkobject(L, 1);
+ GenericCAO *gcao = get_generic_cao(ref, L);
+ if (!gcao)
+ return 0;
+ ObjectProperties *props = gcao->getProperties();
+ lua_pushstring(L, props->nametag.c_str());
+ return 1;
+}
+
+int ClientObjectRef::l_get_item_textures(lua_State *L)
+{
+ log_deprecated(L, "Deprecated call to get_item_textures, use "
+ "get_properties().textures instead");
+ ClientObjectRef *ref = checkobject(L, 1);
+ GenericCAO *gcao = get_generic_cao(ref, L);
+ if (!gcao)
+ return 0;
+ 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_max_hp(lua_State *L)
+{
+ log_deprecated(L, "Deprecated call to get_max_hp, use get_properties().hp_max "
+ "instead");
+ ClientObjectRef *ref = checkobject(L, 1);
+ GenericCAO *gcao = get_generic_cao(ref, L);
+ if (!gcao)
+ return 0;
+ ObjectProperties *props = gcao->getProperties();
+ lua_pushnumber(L, props->hp_max);
+ return 1;
+}
+
+int ClientObjectRef::l_get_properties(lua_State *L)
+{
+ ClientObjectRef *ref = checkobject(L, 1);
+ GenericCAO *gcao = get_generic_cao(ref, L);
+ if (!gcao)
+ return 0;
+ ObjectProperties *prop = gcao->getProperties();
+ push_object_properties(L, prop);
+ return 1;
+}
+
+int ClientObjectRef::l_set_properties(lua_State *L)
+{
+ ClientObjectRef *ref = checkobject(L, 1);
+ GenericCAO *gcao = get_generic_cao(ref, L);
+ if (!gcao)
+ return 0;
+ ObjectProperties prop = *gcao->getProperties();
+ read_object_properties(L, 2, nullptr, &prop, getClient(L)->idef());
+ gcao->setProperties(prop);
+ return 1;
+}
+
+int ClientObjectRef::l_get_hp(lua_State *L)
+{
+ ClientObjectRef *ref = checkobject(L, 1);
+ GenericCAO *gcao = get_generic_cao(ref, L);
+ if (!gcao)
+ return 0;
+ lua_pushnumber(L, gcao->getHp());
+ return 1;
+}
+
+int ClientObjectRef::l_punch(lua_State *L)
+{
+ ClientObjectRef *ref = checkobject(L, 1);
+ GenericCAO *gcao = get_generic_cao(ref, L);
+ if (!gcao)
+ return 0;
+ 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);
+ if (!gcao)
+ return 0;
+ PointedThing pointed(gcao->getId(), v3f(0, 0, 0), v3s16(0, 0, 0), 0);
+ getClient(L)->interact(INTERACT_PLACE, pointed);
+ return 0;
+}
+
+int ClientObjectRef::l_remove(lua_State *L)
+{
+ ClientObjectRef *ref = checkobject(L, 1);
+ ClientActiveObject *cao = get_cao(ref);
+ if (!cao)
+ return 0;
+ getClient(L)->getEnv().removeActiveObject(cao->getId());
+
+ return 0;
+}
+
+int ClientObjectRef::l_set_nametag_images(lua_State *L)
+{
+ ClientObjectRef *ref = checkobject(L, 1);
+ GenericCAO *gcao = get_generic_cao(ref, L);
+ if (!gcao)
+ return 0;
+ gcao->nametag_images.clear();
+ if (lua_istable(L, 2)) {
+ lua_pushnil(L);
+ while (lua_next(L, 2) != 0) {
+ gcao->nametag_images.push_back(lua_tostring(L, -1));
+ lua_pop(L, 1);
+ }
+ }
+ gcao->updateNametag();
+
+ return 0;
+}
+
+ClientObjectRef::ClientObjectRef(ClientActiveObject *object) : m_object(object)
+{
+}
+
+void ClientObjectRef::create(lua_State *L, ClientActiveObject *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));
+}
+
+void ClientObjectRef::set_null(lua_State *L)
+{
+ ClientObjectRef *obj = checkobject(L, -1);
+ obj->m_object = nullptr;
+}
+
+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_properties),
+ luamethod(ClientObjectRef, set_properties),
+ luamethod(ClientObjectRef, get_hp),
+ luamethod(ClientObjectRef, get_max_hp), luamethod(ClientObjectRef, punch),
+ luamethod(ClientObjectRef, rightclick),
+ luamethod(ClientObjectRef, remove),
+ luamethod(ClientObjectRef, set_nametag_images), {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..c4c95cb41
--- /dev/null
+++ b/src/script/lua_api/l_clientobject.h
@@ -0,0 +1,106 @@
+/*
+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 void set_null(lua_State *L);
+
+ 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_item_textures(self)
+ static int l_get_item_textures(lua_State *L);
+
+ // get_properties(self)
+ static int l_get_properties(lua_State *L);
+
+ // set_properties(self, properties)
+ static int l_set_properties(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);
+
+ // remove(self)
+ static int l_remove(lua_State *L);
+
+ // set_nametag_images(self, images)
+ static int l_set_nametag_images(lua_State *L);
+};
diff --git a/src/script/lua_api/l_env.cpp b/src/script/lua_api/l_env.cpp
index 7640f2782..a489d245c 100644
--- a/src/script/lua_api/l_env.cpp
+++ b/src/script/lua_api/l_env.cpp
@@ -857,7 +857,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
@@ -880,6 +879,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;
+}
+
static void checkArea(v3s16 &minp, v3s16 &maxp)
{
auto volume = VoxelArea(minp, maxp).getVolume();
@@ -1285,7 +1443,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);
@@ -1303,7 +1461,7 @@ int ModApiEnvMod::l_find_path(lua_State *L)
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()) {
@@ -1504,8 +1662,13 @@ 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(get_voxel_manip);
+ 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 a7d406d2a..70a8d2398 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_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 13d046d00..160bb4e83 100644
--- a/src/script/lua_api/l_item.cpp
+++ b/src/script/lua_api/l_item.cpp
@@ -28,7 +28,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)
@@ -572,9 +577,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;
@@ -625,8 +630,9 @@ int ModApiItemMod::l_register_item_raw(lua_State *L)
+ itos(MAX_REGISTERED_CONTENT+1)
+ ") exceeded (" + name + ")");
}
+
}
-
+
return 0; /* number of results */
}
@@ -637,12 +643,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);
}
@@ -660,7 +666,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 2efb976c7..1da0679d6 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)) {
+ double 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)) {
+ double 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");
+ 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);
- 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");
+ return 1;
+}
- lua_pushboolean(L, player->physics_override_sneak_glitch);
- lua_setfield(L, -2, "sneak_glitch");
+// set_physics_override(self, override)
+int LuaLocalPlayer::l_set_physics_override(lua_State *L)
+{
+ LocalPlayer *player = getobject(L, 1);
- lua_pushboolean(L, player->physics_override_new_move);
- lua_setfield(L, -2, "new_move");
+ 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)
@@ -261,6 +333,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)
{
@@ -400,6 +483,27 @@ int LuaLocalPlayer::l_hud_get(lua_State *L)
return 1;
}
+// get_object(self)
+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());
+
+ push_objectRef(L, obj->getId());
+
+ return 1;
+}
+
+// get_hotbar_size(self)
+int LuaLocalPlayer::l_get_hotbar_size(lua_State *L)
+{
+ LocalPlayer *player = getobject(L, 1);
+ lua_pushnumber(L, player->hud_hotbar_itemcount);
+
+ return 1;
+}
+
LuaLocalPlayer *LuaLocalPlayer::checkobject(lua_State *L, int narg)
{
luaL_checktype(L, narg, LUA_TUSERDATA);
@@ -460,9 +564,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),
@@ -471,6 +581,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),
@@ -480,6 +591,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),
@@ -488,6 +600,8 @@ const luaL_Reg LuaLocalPlayer::methods[] = {
luamethod(LuaLocalPlayer, hud_remove),
luamethod(LuaLocalPlayer, hud_change),
luamethod(LuaLocalPlayer, hud_get),
+ luamethod(LuaLocalPlayer, get_object),
+ luamethod(LuaLocalPlayer, get_hotbar_size),
luamethod(LuaLocalPlayer, get_move_resistance),
diff --git a/src/script/lua_api/l_localplayer.h b/src/script/lua_api/l_localplayer.h
index 041545a49..458c824e6 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,9 +59,15 @@ 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);
+ // get_hotbar_size(self)
+ static int l_get_hotbar_size(lua_State *L);
+
static int l_is_attached(lua_State *L);
static int l_is_touching_ground(lua_State *L);
static int l_is_in_liquid(lua_State *L);
@@ -55,6 +76,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);
@@ -72,6 +94,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);
@@ -97,6 +122,9 @@ private:
static int l_get_move_resistance(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 4a847ed6d..c1530f0d3 100644
--- a/src/script/lua_api/l_mainmenu.cpp
+++ b/src/script/lua_api/l_mainmenu.cpp
@@ -722,6 +722,10 @@ bool ModApiMainMenu::mayModifyPath(std::string path)
if (fs::PathStartsWith(path, path_user + DIR_DELIM "client"))
return true;
+ if (fs::PathStartsWith(path, path_user + DIR_DELIM "clientmods"))
+ return true;
+ if (fs::PathStartsWith(path, path_user + DIR_DELIM "textures"))
+ return true;
if (fs::PathStartsWith(path, path_user + DIR_DELIM "games"))
return true;
if (fs::PathStartsWith(path, path_user + DIR_DELIM "mods"))
diff --git a/src/script/lua_api/l_server.cpp b/src/script/lua_api/l_server.cpp
index 4b0b45887..e8105dd75 100644
--- a/src/script/lua_api/l_server.cpp
+++ b/src/script/lua_api/l_server.cpp
@@ -336,6 +336,7 @@ int ModApiServer::l_disconnect_player(lua_State *L)
return 1;
}
+// remove_player(name)
int ModApiServer::l_remove_player(lua_State *L)
{
NO_MAP_LOCK_REQUIRED;
diff --git a/src/script/lua_api/l_util.cpp b/src/script/lua_api/l_util.cpp
index f774daf97..44973f968 100644
--- a/src/script/lua_api/l_util.cpp
+++ b/src/script/lua_api/l_util.cpp
@@ -652,6 +652,8 @@ 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);
@@ -659,6 +661,9 @@ void ModApiUtil::InitializeClient(lua_State *L, int top)
API_FCT(sha1);
API_FCT(colorspec_to_colorstring);
API_FCT(colorspec_to_bytes);
+
+ 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..c30de9ee8 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"
@@ -33,13 +36,18 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "lua_api/l_util.h"
#include "lua_api/l_item.h"
#include "lua_api/l_nodemeta.h"
+#include "lua_api/l_noise.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"
+#include "lua_api/l_vmanip.h"
ClientScripting::ClientScripting(Client *client):
ScriptApiBase(ScriptingType::Client)
{
setGameDef(client);
+ setGame(g_game);
SCRIPTAPI_PRECHECKHEADER
@@ -65,6 +73,11 @@ ClientScripting::ClientScripting(Client *client):
void ClientScripting::InitializeModApi(lua_State *L, int top)
{
LuaItemStack::Register(L);
+ LuaPerlinNoise::Register(L);
+ LuaPerlinNoiseMap::Register(L);
+ LuaPseudoRandom::Register(L);
+ LuaPcgRandom::Register(L);
+ LuaSecureRandom::Register(L);
ItemStackMetaRef::Register(L);
LuaRaycast::Register(L);
StorageRef::Register(L);
@@ -73,8 +86,14 @@ 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);
+ LuaVoxelManip::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/server/serverinventorymgr.h b/src/server/serverinventorymgr.h
index 0e4b72415..b6541bd3c 100644
--- a/src/server/serverinventorymgr.h
+++ b/src/server/serverinventorymgr.h
@@ -43,7 +43,8 @@ public:
Inventory *createDetachedInventory(const std::string &name, IItemDefManager *idef,
const std::string &player = "");
bool removeDetachedInventory(const std::string &name);
- bool checkDetachedInventoryAccess(const InventoryLocation &loc, const std::string &player) const;
+ bool checkDetachedInventoryAccess(
+ const InventoryLocation &loc, const std::string &player) const;
void sendDetachedInventories(const std::string &peer_name, bool incremental,
std::function<void(const std::string &, Inventory *)> apply_cb);
diff --git a/src/serverenvironment.cpp b/src/serverenvironment.cpp
index 8989fb05f..9da5f98bd 100644
--- a/src/serverenvironment.cpp
+++ b/src/serverenvironment.cpp
@@ -1185,7 +1185,7 @@ void ServerEnvironment::clearObjects(ClearObjectsMode mode)
// Tell the object about removal
obj->removingFromEnvironment();
// Deregister in scripting api
- m_script->removeObjectReference(obj);
+ m_script->removeObjectReference(dynamic_cast<ActiveObject *>(obj));
// Delete active object
if (obj->environmentDeletes())
@@ -1788,7 +1788,7 @@ u16 ServerEnvironment::addActiveObjectRaw(ServerActiveObject *object,
}
// Register reference in scripting api (must be done before post-init)
- m_script->addObjectReference(object);
+ m_script->addObjectReference(dynamic_cast<ActiveObject *>(object));
// Post-initialize object
object->addedToEnvironment(dtime_s);
@@ -1878,7 +1878,7 @@ void ServerEnvironment::removeRemovedObjects()
// Tell the object about removal
obj->removingFromEnvironment();
// Deregister in scripting api
- m_script->removeObjectReference(obj);
+ m_script->removeObjectReference(dynamic_cast<ActiveObject *>(obj));
// Delete
if (obj->environmentDeletes())
@@ -2143,7 +2143,7 @@ void ServerEnvironment::deactivateFarObjects(bool _force_delete)
// Tell the object about removal
obj->removingFromEnvironment();
// Deregister in scripting api
- m_script->removeObjectReference(obj);
+ m_script->removeObjectReference(dynamic_cast<ActiveObject *>(obj));
// Delete active object
if (obj->environmentDeletes())
diff --git a/src/unittest/test.cpp b/src/unittest/test.cpp
index af30c209d..e5a4fac5b 100644
--- a/src/unittest/test.cpp
+++ b/src/unittest/test.cpp
@@ -48,7 +48,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; }
@@ -81,8 +83,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;