diff options
Diffstat (limited to 'src')
31 files changed, 374 insertions, 258 deletions
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 7bba68a64..c068be575 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -136,6 +136,7 @@ if(ENABLE_POSTGRESQL) if(PostgreSQL_INCLUDE_DIR AND PostgreSQL_LIBRARY) set(PostgreSQL_FOUND TRUE) set(PostgreSQL_INCLUDE_DIRS ${PostgreSQL_INCLUDE_DIR}) + set(PostgreSQL_LIBRARIES ${PostgreSQL_LIBRARY}) endif() else() find_package(PostgreSQL) diff --git a/src/client/client.cpp b/src/client/client.cpp index 2d9d226e4..5e31387ab 100644 --- a/src/client/client.cpp +++ b/src/client/client.cpp @@ -533,6 +533,7 @@ void Client::step(float dtime) { int num_processed_meshes = 0; std::vector<v3s16> blocks_to_ack; + bool force_update_shadows = false; while (!m_mesh_update_thread.m_queue_out.empty()) { num_processed_meshes++; @@ -559,9 +560,11 @@ void Client::step(float dtime) if (is_empty) delete r.mesh; - else + else { // Replace with the new mesh block->mesh = r.mesh; + force_update_shadows = true; + } } } else { delete r.mesh; @@ -586,6 +589,10 @@ void Client::step(float dtime) if (num_processed_meshes > 0) g_profiler->graphAdd("num_processed_meshes", num_processed_meshes); + + auto shadow_renderer = RenderingEngine::get_shadow_renderer(); + if (shadow_renderer && force_update_shadows) + shadow_renderer->setForceUpdateShadowMap(); } /* @@ -799,7 +806,7 @@ void Client::deletingPeer(con::Peer *peer, bool timeout) m_access_denied = true; if (timeout) m_access_denied_reason = gettext("Connection timed out."); - else + else if (m_access_denied_reason.empty()) m_access_denied_reason = gettext("Connection aborted (protocol error?)."); } diff --git a/src/client/mapblock_mesh.cpp b/src/client/mapblock_mesh.cpp index 9e82fc3e4..263601121 100644 --- a/src/client/mapblock_mesh.cpp +++ b/src/client/mapblock_mesh.cpp @@ -1417,30 +1417,22 @@ MapBlockMesh::MapBlockMesh(MeshMakeData *data, v3s16 camera_offset): scene::SMeshBuffer *buf = new scene::SMeshBuffer(); buf->Material = material; - switch (p.layer.material_type) { - // list of transparent materials taken from tile.h - case TILE_MATERIAL_ALPHA: - case TILE_MATERIAL_LIQUID_TRANSPARENT: - case TILE_MATERIAL_WAVING_LIQUID_TRANSPARENT: - { - buf->append(&p.vertices[0], p.vertices.size(), - &p.indices[0], 0); - - MeshTriangle t; - t.buffer = buf; - for (u32 i = 0; i < p.indices.size(); i += 3) { - t.p1 = p.indices[i]; - t.p2 = p.indices[i + 1]; - t.p3 = p.indices[i + 2]; - t.updateAttributes(); - m_transparent_triangles.push_back(t); - } + if (p.layer.isTransparent()) { + buf->append(&p.vertices[0], p.vertices.size(), nullptr, 0); + + MeshTriangle t; + t.buffer = buf; + m_transparent_triangles.reserve(p.indices.size() / 3); + for (u32 i = 0; i < p.indices.size(); i += 3) { + t.p1 = p.indices[i]; + t.p2 = p.indices[i + 1]; + t.p3 = p.indices[i + 2]; + t.updateAttributes(); + m_transparent_triangles.push_back(t); } - break; - default: + } else { buf->append(&p.vertices[0], p.vertices.size(), &p.indices[0], p.indices.size()); - break; } mesh->addMeshBuffer(buf); buf->drop(); diff --git a/src/client/renderingengine.cpp b/src/client/renderingengine.cpp index 6ebcc784d..224efce3e 100644 --- a/src/client/renderingengine.cpp +++ b/src/client/renderingengine.cpp @@ -637,25 +637,10 @@ float RenderingEngine::getDisplayDensity() #endif -v2u32 RenderingEngine::getDisplaySize() -{ - IrrlichtDevice *nulldevice = createDevice(video::EDT_NULL); - - core::dimension2d<u32> deskres = - nulldevice->getVideoModeList()->getDesktopResolution(); - nulldevice->drop(); - - return deskres; -} - #else // __ANDROID__ float RenderingEngine::getDisplayDensity() { return porting::getDisplayDensity(); } -v2u32 RenderingEngine::getDisplaySize() -{ - return porting::getDisplaySize(); -} #endif // __ANDROID__ diff --git a/src/client/renderingengine.h b/src/client/renderingengine.h index 6f104bba9..38420010f 100644 --- a/src/client/renderingengine.h +++ b/src/client/renderingengine.h @@ -55,7 +55,6 @@ public: static const VideoDriverInfo &getVideoDriverInfo(irr::video::E_DRIVER_TYPE type); static float getDisplayDensity(); - static v2u32 getDisplaySize(); bool setupTopLevelWindow(const std::string &name); void setupTopLevelXorgWindow(const std::string &name); diff --git a/src/client/shadows/dynamicshadows.cpp b/src/client/shadows/dynamicshadows.cpp index ca2d3ce37..9f26ba94a 100644 --- a/src/client/shadows/dynamicshadows.cpp +++ b/src/client/shadows/dynamicshadows.cpp @@ -27,10 +27,24 @@ with this program; if not, write to the Free Software Foundation, Inc., using m4f = core::matrix4; +static v3f quantizeDirection(v3f direction, float step) +{ + + float yaw = std::atan2(direction.Z, direction.X); + float pitch = std::asin(direction.Y); // assume look is normalized + + yaw = std::floor(yaw / step) * step; + pitch = std::floor(pitch / step) * step; + + return v3f(std::cos(yaw)*std::cos(pitch), std::sin(pitch), std::sin(yaw)*std::cos(pitch)); +} + void DirectionalLight::createSplitMatrices(const Camera *cam) { + const float DISTANCE_STEP = BS * 2.0; // 2 meters v3f newCenter; v3f look = cam->getDirection(); + look = quantizeDirection(look, M_PI / 12.0); // 15 degrees // camera view tangents float tanFovY = tanf(cam->getFovY() * 0.5f); @@ -42,6 +56,10 @@ void DirectionalLight::createSplitMatrices(const Camera *cam) // adjusted camera positions v3f cam_pos_world = cam->getPosition(); + cam_pos_world = v3f( + floor(cam_pos_world.X / DISTANCE_STEP) * DISTANCE_STEP, + floor(cam_pos_world.Y / DISTANCE_STEP) * DISTANCE_STEP, + floor(cam_pos_world.Z / DISTANCE_STEP) * DISTANCE_STEP); v3f cam_pos_scene = v3f(cam_pos_world.X - cam->getOffset().X * BS, cam_pos_world.Y - cam->getOffset().Y * BS, cam_pos_world.Z - cam->getOffset().Z * BS); @@ -61,7 +79,7 @@ void DirectionalLight::createSplitMatrices(const Camera *cam) v3f boundVec = (cam_pos_scene + farCorner * sfFar) - center_scene; float radius = boundVec.getLength(); float length = radius * 3.0f; - v3f eye_displacement = direction * length; + v3f eye_displacement = quantizeDirection(direction, M_PI / 2880 /*15 seconds*/) * length; // we must compute the viewmat with the position - the camera offset // but the future_frustum position must be the actual world position diff --git a/src/client/shadows/dynamicshadowsrender.cpp b/src/client/shadows/dynamicshadowsrender.cpp index c13cfe252..b8ceeb623 100644 --- a/src/client/shadows/dynamicshadowsrender.cpp +++ b/src/client/shadows/dynamicshadowsrender.cpp @@ -242,7 +242,7 @@ void ShadowRenderer::updateSMTextures() // detect if SM should be regenerated for (DirectionalLight &light : m_light_list) { - if (light.should_update_map_shadow) { + if (light.should_update_map_shadow || m_force_update_shadow_map) { light.should_update_map_shadow = false; m_current_frame = 0; reset_sm_texture = true; @@ -271,14 +271,14 @@ void ShadowRenderer::updateSMTextures() // should put some gl* fn here - if (m_current_frame < m_map_shadow_update_frames) { + if (m_current_frame < m_map_shadow_update_frames || m_force_update_shadow_map) { m_driver->setRenderTarget(shadowMapTargetTexture, reset_sm_texture, true, video::SColor(255, 255, 255, 255)); renderShadowMap(shadowMapTargetTexture, light); // Render transparent part in one pass. // This is also handled in ClientMap. - if (m_current_frame == m_map_shadow_update_frames - 1) { + if (m_current_frame == m_map_shadow_update_frames - 1 || m_force_update_shadow_map) { if (m_shadow_map_colored) { m_driver->setRenderTarget(0, false, false); m_driver->setRenderTarget(shadowMapTextureColors, @@ -298,7 +298,7 @@ void ShadowRenderer::updateSMTextures() ++m_current_frame; // pass finished, swap textures and commit light changes - if (m_current_frame == m_map_shadow_update_frames) { + if (m_current_frame == m_map_shadow_update_frames || m_force_update_shadow_map) { if (shadowMapClientMapFuture != nullptr) std::swap(shadowMapClientMapFuture, shadowMapClientMap); @@ -306,6 +306,7 @@ void ShadowRenderer::updateSMTextures() for (DirectionalLight &light : m_light_list) light.commitFrustum(); } + m_force_update_shadow_map = false; } } @@ -432,7 +433,10 @@ void ShadowRenderer::renderShadowMap(video::ITexture *target, m_driver->setTransform(video::ETS_WORLD, map_node->getAbsoluteTransformation()); - map_node->renderMapShadows(m_driver, material, pass, m_current_frame, m_map_shadow_update_frames); + int frame = m_force_update_shadow_map ? 0 : m_current_frame; + int total_frames = m_force_update_shadow_map ? 1 : m_map_shadow_update_frames; + + map_node->renderMapShadows(m_driver, material, pass, frame, total_frames); break; } } diff --git a/src/client/shadows/dynamicshadowsrender.h b/src/client/shadows/dynamicshadowsrender.h index 0e4ef6b70..2e3b58f6f 100644 --- a/src/client/shadows/dynamicshadowsrender.h +++ b/src/client/shadows/dynamicshadowsrender.h @@ -74,6 +74,7 @@ public: void removeNodeFromShadowList(scene::ISceneNode *node); void update(video::ITexture *outputTarget = nullptr); + void setForceUpdateShadowMap() { m_force_update_shadow_map = true; } void drawDebug(); video::ITexture *get_texture() @@ -131,6 +132,7 @@ private: bool m_shadows_enabled; bool m_shadows_supported; bool m_shadow_map_colored; + bool m_force_update_shadow_map; u8 m_map_shadow_update_frames; /* Use this number of frames to update map shaodw */ u8 m_current_frame{0}; /* Current frame */ f32 m_perspective_bias_xy; diff --git a/src/gui/modalMenu.cpp b/src/gui/modalMenu.cpp index d27f63d94..b05bed490 100644 --- a/src/gui/modalMenu.cpp +++ b/src/gui/modalMenu.cpp @@ -252,13 +252,11 @@ bool GUIModalMenu::preprocessEvent(const SEvent &event) return retval; m_jni_field_name = field_name; - /*~ Imperative, as in "Enter/type in text". - Don't forget the space. */ - std::string message = gettext("Enter "); std::string label = wide_to_utf8(getLabelByID(hovered->getID())); if (label.empty()) label = "text"; - message += strgettext(label) + ":"; + /*~ Imperative, as in "Type in text" */ + std::string message = fmtgettext("Enter %s:"); // single line text input int type = 2; diff --git a/src/log.cpp b/src/log.cpp index 51652fe0a..ef998f161 100644 --- a/src/log.cpp +++ b/src/log.cpp @@ -152,12 +152,14 @@ void Logger::addOutput(ILogOutput *out) void Logger::addOutput(ILogOutput *out, LogLevel lev) { + MutexAutoLock lock(m_mutex); m_outputs[lev].push_back(out); m_has_outputs[lev] = true; } void Logger::addOutputMasked(ILogOutput *out, LogLevelMask mask) { + MutexAutoLock lock(m_mutex); for (size_t i = 0; i < LL_MAX; i++) { if (mask & LOGLEVEL_TO_MASKLEVEL(i)) { m_outputs[i].push_back(out); @@ -168,6 +170,7 @@ void Logger::addOutputMasked(ILogOutput *out, LogLevelMask mask) void Logger::addOutputMaxLevel(ILogOutput *out, LogLevel lev) { + MutexAutoLock lock(m_mutex); assert(lev < LL_MAX); for (size_t i = 0; i <= lev; i++) { m_outputs[i].push_back(out); @@ -177,6 +180,7 @@ void Logger::addOutputMaxLevel(ILogOutput *out, LogLevel lev) LogLevelMask Logger::removeOutput(ILogOutput *out) { + MutexAutoLock lock(m_mutex); LogLevelMask ret_mask = 0; for (size_t i = 0; i < LL_MAX; i++) { std::vector<ILogOutput *>::iterator it; @@ -386,6 +390,6 @@ void LogOutputBuffer::logRaw(LogLevel lev, const std::string &line) default: break; } } - - m_buffer.push(color.append(line)); + MutexAutoLock lock(m_buffer_mutex); + m_buffer.emplace(color.append(line)); } @@ -29,6 +29,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #if !defined(_WIN32) // POSIX #include <unistd.h> #endif +#include "threading/mutex_auto_lock.h" #include "util/basic_macros.h" #include "util/stream.h" #include "irrlichttypes.h" @@ -168,24 +169,31 @@ public: void clear() { + MutexAutoLock lock(m_buffer_mutex); m_buffer = std::queue<std::string>(); } bool empty() const { + MutexAutoLock lock(m_buffer_mutex); return m_buffer.empty(); } std::string get() { - if (empty()) + MutexAutoLock lock(m_buffer_mutex); + if (m_buffer.empty()) return ""; - std::string s = m_buffer.front(); + std::string s = std::move(m_buffer.front()); m_buffer.pop(); return s; } private: + // g_logger serializes calls to logRaw() with a mutex, but that + // doesn't prevent get() / clear() from being called on top of it. + // This mutex prevents that. + mutable std::mutex m_buffer_mutex; std::queue<std::string> m_buffer; Logger &m_logger; }; diff --git a/src/map.cpp b/src/map.cpp index 7bc1334b0..cb63d2583 100644 --- a/src/map.cpp +++ b/src/map.cpp @@ -102,7 +102,7 @@ MapSector * Map::getSectorNoGenerateNoLock(v2s16 p) return sector; } - std::map<v2s16, MapSector*>::iterator n = m_sectors.find(p); + auto n = m_sectors.find(p); if (n == m_sectors.end()) return NULL; @@ -268,7 +268,7 @@ protected: std::set<MapEventReceiver*> m_event_receivers; - std::map<v2s16, MapSector*> m_sectors; + std::unordered_map<v2s16, MapSector*> m_sectors; // Be sure to set this to NULL when the cached sector is deleted MapSector *m_sector_cache = nullptr; diff --git a/src/mapblock.cpp b/src/mapblock.cpp index e3a6caa19..2bbc0ebbf 100644 --- a/src/mapblock.cpp +++ b/src/mapblock.cpp @@ -221,33 +221,36 @@ void MapBlock::expireDayNightDiff() /* Serialization */ + // List relevant id-name pairs for ids in the block using nodedef -// Renumbers the content IDs (starting at 0 and incrementing -// use static memory requires about 65535 * sizeof(int) ram in order to be -// sure we can handle all content ids. But it's absolutely worth it as it's -// a speedup of 4 for one of the major time consuming functions on storing -// mapblocks. -static content_t getBlockNodeIdMapping_mapping[USHRT_MAX + 1]; +// Renumbers the content IDs (starting at 0 and incrementing) static void getBlockNodeIdMapping(NameIdMapping *nimap, MapNode *nodes, const NodeDefManager *nodedef) { - memset(getBlockNodeIdMapping_mapping, 0xFF, (USHRT_MAX + 1) * sizeof(content_t)); - - std::set<content_t> unknown_contents; + // The static memory requires about 65535 * sizeof(int) RAM in order to be + // sure we can handle all content ids. But it's absolutely worth it as it's + // a speedup of 4 for one of the major time consuming functions on storing + // mapblocks. + thread_local std::unique_ptr<content_t[]> mapping; + static_assert(sizeof(content_t) == 2, "content_t must be 16-bit"); + if (!mapping) + mapping = std::make_unique<content_t[]>(USHRT_MAX + 1); + + memset(mapping.get(), 0xFF, (USHRT_MAX + 1) * sizeof(content_t)); + + std::unordered_set<content_t> unknown_contents; content_t id_counter = 0; for (u32 i = 0; i < MapBlock::nodecount; i++) { content_t global_id = nodes[i].getContent(); content_t id = CONTENT_IGNORE; // Try to find an existing mapping - if (getBlockNodeIdMapping_mapping[global_id] != 0xFFFF) { - id = getBlockNodeIdMapping_mapping[global_id]; - } - else - { + if (mapping[global_id] != 0xFFFF) { + id = mapping[global_id]; + } else { // We have to assign a new mapping id = id_counter++; - getBlockNodeIdMapping_mapping[global_id] = id; + mapping[global_id] = id; const ContentFeatures &f = nodedef->get(global_id); const std::string &name = f.name; @@ -265,6 +268,7 @@ static void getBlockNodeIdMapping(NameIdMapping *nimap, MapNode *nodes, << "Name for node id " << unknown_content << " not known" << std::endl; } } + // Correct ids in the block to match nodedef based on names. // Unknown ones are added to nodedef. // Will not update itself to match id-name pairs in nodedef. diff --git a/src/mapnode.cpp b/src/mapnode.cpp index 73bd620fb..42f020e71 100644 --- a/src/mapnode.cpp +++ b/src/mapnode.cpp @@ -266,10 +266,12 @@ void transformNodeBox(const MapNode &n, const NodeBox &nodebox, std::vector<aabb3f> &boxes = *p_boxes; if (nodebox.type == NODEBOX_FIXED || nodebox.type == NODEBOX_LEVELED) { - const std::vector<aabb3f> &fixed = nodebox.fixed; + const auto &fixed = nodebox.fixed; int facedir = n.getFaceDir(nodemgr, true); u8 axisdir = facedir>>2; facedir&=0x03; + + boxes.reserve(boxes.size() + fixed.size()); for (aabb3f box : fixed) { if (nodebox.type == NODEBOX_LEVELED) box.MaxEdge.Y = (-0.5f + n.getLevel(nodemgr) / 64.0f) * BS; @@ -437,41 +439,43 @@ void transformNodeBox(const MapNode &n, const NodeBox &nodebox, { size_t boxes_size = boxes.size(); boxes_size += nodebox.fixed.size(); + const auto &c = nodebox.getConnected(); + if (neighbors & 1) - boxes_size += nodebox.connect_top.size(); + boxes_size += c.connect_top.size(); else - boxes_size += nodebox.disconnected_top.size(); + boxes_size += c.disconnected_top.size(); if (neighbors & 2) - boxes_size += nodebox.connect_bottom.size(); + boxes_size += c.connect_bottom.size(); else - boxes_size += nodebox.disconnected_bottom.size(); + boxes_size += c.disconnected_bottom.size(); if (neighbors & 4) - boxes_size += nodebox.connect_front.size(); + boxes_size += c.connect_front.size(); else - boxes_size += nodebox.disconnected_front.size(); + boxes_size += c.disconnected_front.size(); if (neighbors & 8) - boxes_size += nodebox.connect_left.size(); + boxes_size += c.connect_left.size(); else - boxes_size += nodebox.disconnected_left.size(); + boxes_size += c.disconnected_left.size(); if (neighbors & 16) - boxes_size += nodebox.connect_back.size(); + boxes_size += c.connect_back.size(); else - boxes_size += nodebox.disconnected_back.size(); + boxes_size += c.disconnected_back.size(); if (neighbors & 32) - boxes_size += nodebox.connect_right.size(); + boxes_size += c.connect_right.size(); else - boxes_size += nodebox.disconnected_right.size(); + boxes_size += c.disconnected_right.size(); if (neighbors == 0) - boxes_size += nodebox.disconnected.size(); + boxes_size += c.disconnected.size(); if (neighbors < 4) - boxes_size += nodebox.disconnected_sides.size(); + boxes_size += c.disconnected_sides.size(); boxes.reserve(boxes_size); @@ -484,47 +488,47 @@ void transformNodeBox(const MapNode &n, const NodeBox &nodebox, BOXESPUSHBACK(nodebox.fixed); if (neighbors & 1) { - BOXESPUSHBACK(nodebox.connect_top); + BOXESPUSHBACK(c.connect_top); } else { - BOXESPUSHBACK(nodebox.disconnected_top); + BOXESPUSHBACK(c.disconnected_top); } if (neighbors & 2) { - BOXESPUSHBACK(nodebox.connect_bottom); + BOXESPUSHBACK(c.connect_bottom); } else { - BOXESPUSHBACK(nodebox.disconnected_bottom); + BOXESPUSHBACK(c.disconnected_bottom); } if (neighbors & 4) { - BOXESPUSHBACK(nodebox.connect_front); + BOXESPUSHBACK(c.connect_front); } else { - BOXESPUSHBACK(nodebox.disconnected_front); + BOXESPUSHBACK(c.disconnected_front); } if (neighbors & 8) { - BOXESPUSHBACK(nodebox.connect_left); + BOXESPUSHBACK(c.connect_left); } else { - BOXESPUSHBACK(nodebox.disconnected_left); + BOXESPUSHBACK(c.disconnected_left); } if (neighbors & 16) { - BOXESPUSHBACK(nodebox.connect_back); + BOXESPUSHBACK(c.connect_back); } else { - BOXESPUSHBACK(nodebox.disconnected_back); + BOXESPUSHBACK(c.disconnected_back); } if (neighbors & 32) { - BOXESPUSHBACK(nodebox.connect_right); + BOXESPUSHBACK(c.connect_right); } else { - BOXESPUSHBACK(nodebox.disconnected_right); + BOXESPUSHBACK(c.disconnected_right); } if (neighbors == 0) { - BOXESPUSHBACK(nodebox.disconnected); + BOXESPUSHBACK(c.disconnected); } if (neighbors < 4) { - BOXESPUSHBACK(nodebox.disconnected_sides); + BOXESPUSHBACK(c.disconnected_sides); } } diff --git a/src/nodedef.cpp b/src/nodedef.cpp index 2b8ebd773..5954dac1e 100644 --- a/src/nodedef.cpp +++ b/src/nodedef.cpp @@ -56,20 +56,7 @@ void NodeBox::reset() wall_bottom = aabb3f(-BS/2, -BS/2, -BS/2, BS/2, -BS/2+BS/16., BS/2); wall_side = aabb3f(-BS/2, -BS/2, -BS/2, -BS/2+BS/16., BS/2, BS/2); // no default for other parts - connect_top.clear(); - connect_bottom.clear(); - connect_front.clear(); - connect_left.clear(); - connect_back.clear(); - connect_right.clear(); - disconnected_top.clear(); - disconnected_bottom.clear(); - disconnected_front.clear(); - disconnected_left.clear(); - disconnected_back.clear(); - disconnected_right.clear(); - disconnected.clear(); - disconnected_sides.clear(); + connected.reset(); } void NodeBox::serialize(std::ostream &os, u16 protocol_version) const @@ -99,7 +86,7 @@ void NodeBox::serialize(std::ostream &os, u16 protocol_version) const writeV3F32(os, wall_side.MinEdge); writeV3F32(os, wall_side.MaxEdge); break; - case NODEBOX_CONNECTED: + case NODEBOX_CONNECTED: { writeU8(os, type); #define WRITEBOX(box) \ @@ -109,22 +96,25 @@ void NodeBox::serialize(std::ostream &os, u16 protocol_version) const writeV3F32(os, i.MaxEdge); \ }; + const auto &c = getConnected(); + WRITEBOX(fixed); - WRITEBOX(connect_top); - WRITEBOX(connect_bottom); - WRITEBOX(connect_front); - WRITEBOX(connect_left); - WRITEBOX(connect_back); - WRITEBOX(connect_right); - WRITEBOX(disconnected_top); - WRITEBOX(disconnected_bottom); - WRITEBOX(disconnected_front); - WRITEBOX(disconnected_left); - WRITEBOX(disconnected_back); - WRITEBOX(disconnected_right); - WRITEBOX(disconnected); - WRITEBOX(disconnected_sides); + WRITEBOX(c.connect_top); + WRITEBOX(c.connect_bottom); + WRITEBOX(c.connect_front); + WRITEBOX(c.connect_left); + WRITEBOX(c.connect_back); + WRITEBOX(c.connect_right); + WRITEBOX(c.disconnected_top); + WRITEBOX(c.disconnected_bottom); + WRITEBOX(c.disconnected_front); + WRITEBOX(c.disconnected_left); + WRITEBOX(c.disconnected_back); + WRITEBOX(c.disconnected_right); + WRITEBOX(c.disconnected); + WRITEBOX(c.disconnected_sides); break; + } default: writeU8(os, type); break; @@ -173,21 +163,23 @@ void NodeBox::deSerialize(std::istream &is) u16 count; + auto &c = getConnected(); + READBOXES(fixed); - READBOXES(connect_top); - READBOXES(connect_bottom); - READBOXES(connect_front); - READBOXES(connect_left); - READBOXES(connect_back); - READBOXES(connect_right); - READBOXES(disconnected_top); - READBOXES(disconnected_bottom); - READBOXES(disconnected_front); - READBOXES(disconnected_left); - READBOXES(disconnected_back); - READBOXES(disconnected_right); - READBOXES(disconnected); - READBOXES(disconnected_sides); + READBOXES(c.connect_top); + READBOXES(c.connect_bottom); + READBOXES(c.connect_front); + READBOXES(c.connect_left); + READBOXES(c.connect_back); + READBOXES(c.connect_right); + READBOXES(c.disconnected_top); + READBOXES(c.disconnected_bottom); + READBOXES(c.disconnected_front); + READBOXES(c.disconnected_left); + READBOXES(c.disconnected_back); + READBOXES(c.disconnected_right); + READBOXES(c.disconnected); + READBOXES(c.disconnected_sides); } } @@ -409,9 +401,9 @@ void ContentFeatures::reset() drowning = 0; light_source = 0; damage_per_second = 0; - node_box = NodeBox(); - selection_box = NodeBox(); - collision_box = NodeBox(); + node_box.reset(); + selection_box.reset(); + collision_box.reset(); waving = 0; legacy_facedir_simple = false; legacy_wallmounted = false; @@ -909,8 +901,15 @@ void ContentFeatures::updateTextures(ITextureSource *tsrc, IShaderSource *shdsrc solidness = 0; visual_solidness = 1; } else { - drawtype = NDT_NORMAL; - solidness = 2; + if (waving >= 1) { + // waving nodes must make faces so there are no gaps + drawtype = NDT_ALLFACES; + solidness = 0; + visual_solidness = 1; + } else { + drawtype = NDT_NORMAL; + solidness = 2; + } for (TileDef &td : tdef) td.name += std::string("^[noalpha"); } @@ -1091,10 +1090,8 @@ void NodeDefManager::clear() { ContentFeatures f; f.name = "unknown"; - TileDef unknownTile; - unknownTile.name = "unknown_node.png"; for (int t = 0; t < 6; t++) - f.tiledef[t] = unknownTile; + f.tiledef[t].name = "unknown_node.png"; // Insert directly into containers content_t c = CONTENT_UNKNOWN; m_content_features[c] = f; @@ -1296,22 +1293,23 @@ void getNodeBoxUnion(const NodeBox &nodebox, const ContentFeatures &features, break; } case NODEBOX_CONNECTED: { + const auto &c = nodebox.getConnected(); // Add all possible connected boxes - boxVectorUnion(nodebox.fixed, box_union); - boxVectorUnion(nodebox.connect_top, box_union); - boxVectorUnion(nodebox.connect_bottom, box_union); - boxVectorUnion(nodebox.connect_front, box_union); - boxVectorUnion(nodebox.connect_left, box_union); - boxVectorUnion(nodebox.connect_back, box_union); - boxVectorUnion(nodebox.connect_right, box_union); - boxVectorUnion(nodebox.disconnected_top, box_union); - boxVectorUnion(nodebox.disconnected_bottom, box_union); - boxVectorUnion(nodebox.disconnected_front, box_union); - boxVectorUnion(nodebox.disconnected_left, box_union); - boxVectorUnion(nodebox.disconnected_back, box_union); - boxVectorUnion(nodebox.disconnected_right, box_union); - boxVectorUnion(nodebox.disconnected, box_union); - boxVectorUnion(nodebox.disconnected_sides, box_union); + boxVectorUnion(nodebox.fixed, box_union); + boxVectorUnion(c.connect_top, box_union); + boxVectorUnion(c.connect_bottom, box_union); + boxVectorUnion(c.connect_front, box_union); + boxVectorUnion(c.connect_left, box_union); + boxVectorUnion(c.connect_back, box_union); + boxVectorUnion(c.connect_right, box_union); + boxVectorUnion(c.disconnected_top, box_union); + boxVectorUnion(c.disconnected_bottom, box_union); + boxVectorUnion(c.disconnected_front, box_union); + boxVectorUnion(c.disconnected_left, box_union); + boxVectorUnion(c.disconnected_back, box_union); + boxVectorUnion(c.disconnected_right, box_union); + boxVectorUnion(c.disconnected, box_union); + boxVectorUnion(c.disconnected_sides, box_union); break; } default: { diff --git a/src/nodedef.h b/src/nodedef.h index f90caff8a..edd8d00a7 100644 --- a/src/nodedef.h +++ b/src/nodedef.h @@ -99,17 +99,8 @@ enum NodeBoxType NODEBOX_CONNECTED, // optionally draws nodeboxes if a neighbor node attaches }; -struct NodeBox +struct NodeBoxConnected { - enum NodeBoxType type; - // NODEBOX_REGULAR (no parameters) - // NODEBOX_FIXED - std::vector<aabb3f> fixed; - // NODEBOX_WALLMOUNTED - aabb3f wall_top; - aabb3f wall_bottom; - aabb3f wall_side; // being at the -X side - // NODEBOX_CONNECTED std::vector<aabb3f> connect_top; std::vector<aabb3f> connect_bottom; std::vector<aabb3f> connect_front; @@ -124,9 +115,35 @@ struct NodeBox std::vector<aabb3f> disconnected_right; std::vector<aabb3f> disconnected; std::vector<aabb3f> disconnected_sides; +}; + +struct NodeBox +{ + enum NodeBoxType type; + // NODEBOX_REGULAR (no parameters) + // NODEBOX_FIXED + std::vector<aabb3f> fixed; + // NODEBOX_WALLMOUNTED + aabb3f wall_top; + aabb3f wall_bottom; + aabb3f wall_side; // being at the -X side + // NODEBOX_CONNECTED + // (kept externally to not bloat the structure) + std::shared_ptr<NodeBoxConnected> connected; NodeBox() { reset(); } + ~NodeBox() = default; + + inline NodeBoxConnected &getConnected() { + if (!connected) + connected = std::make_shared<NodeBoxConnected>(); + return *connected; + } + inline const NodeBoxConnected &getConnected() const { + assert(connected); + return *connected; + } void reset(); void serialize(std::ostream &os, u16 protocol_version) const; @@ -290,7 +307,6 @@ struct ContentFeatures // up down right left back front TileSpec tiles[6]; // Special tiles - // - Currently used for flowing liquids TileSpec special_tiles[CF_SPECIAL_COUNT]; u8 solidness; // Used when choosing which face is drawn u8 visual_solidness; // When solidness=0, this tells how it looks like @@ -539,7 +555,7 @@ public: */ inline const ContentFeatures& get(content_t c) const { return - c < m_content_features.size() ? + (c < m_content_features.size() && !m_content_features[c].name.empty()) ? m_content_features[c] : m_content_features[CONTENT_UNKNOWN]; } diff --git a/src/script/common/c_content.cpp b/src/script/common/c_content.cpp index 0bdeaab9e..b954197c2 100644 --- a/src/script/common/c_content.cpp +++ b/src/script/common/c_content.cpp @@ -1055,22 +1055,25 @@ void push_nodebox(lua_State *L, const NodeBox &box) push_aabb3f(L, box.wall_side); lua_setfield(L, -2, "wall_side"); break; - case NODEBOX_CONNECTED: + case NODEBOX_CONNECTED: { lua_pushstring(L, "connected"); lua_setfield(L, -2, "type"); - push_box(L, box.connect_top); + const auto &c = box.getConnected(); + push_box(L, c.connect_top); lua_setfield(L, -2, "connect_top"); - push_box(L, box.connect_bottom); + push_box(L, c.connect_bottom); lua_setfield(L, -2, "connect_bottom"); - push_box(L, box.connect_front); + push_box(L, c.connect_front); lua_setfield(L, -2, "connect_front"); - push_box(L, box.connect_back); + push_box(L, c.connect_back); lua_setfield(L, -2, "connect_back"); - push_box(L, box.connect_left); + push_box(L, c.connect_left); lua_setfield(L, -2, "connect_left"); - push_box(L, box.connect_right); + push_box(L, c.connect_right); lua_setfield(L, -2, "connect_right"); + // half the boxes are missing here? break; + } default: FATAL_ERROR("Invalid box.type"); break; @@ -1198,20 +1201,24 @@ NodeBox read_nodebox(lua_State *L, int index) NODEBOXREAD(nodebox.wall_top, "wall_top"); NODEBOXREAD(nodebox.wall_bottom, "wall_bottom"); NODEBOXREAD(nodebox.wall_side, "wall_side"); - NODEBOXREADVEC(nodebox.connect_top, "connect_top"); - NODEBOXREADVEC(nodebox.connect_bottom, "connect_bottom"); - NODEBOXREADVEC(nodebox.connect_front, "connect_front"); - NODEBOXREADVEC(nodebox.connect_left, "connect_left"); - NODEBOXREADVEC(nodebox.connect_back, "connect_back"); - NODEBOXREADVEC(nodebox.connect_right, "connect_right"); - NODEBOXREADVEC(nodebox.disconnected_top, "disconnected_top"); - NODEBOXREADVEC(nodebox.disconnected_bottom, "disconnected_bottom"); - NODEBOXREADVEC(nodebox.disconnected_front, "disconnected_front"); - NODEBOXREADVEC(nodebox.disconnected_left, "disconnected_left"); - NODEBOXREADVEC(nodebox.disconnected_back, "disconnected_back"); - NODEBOXREADVEC(nodebox.disconnected_right, "disconnected_right"); - NODEBOXREADVEC(nodebox.disconnected, "disconnected"); - NODEBOXREADVEC(nodebox.disconnected_sides, "disconnected_sides"); + + if (nodebox.type == NODEBOX_CONNECTED) { + auto &c = nodebox.getConnected(); + NODEBOXREADVEC(c.connect_top, "connect_top"); + NODEBOXREADVEC(c.connect_bottom, "connect_bottom"); + NODEBOXREADVEC(c.connect_front, "connect_front"); + NODEBOXREADVEC(c.connect_left, "connect_left"); + NODEBOXREADVEC(c.connect_back, "connect_back"); + NODEBOXREADVEC(c.connect_right, "connect_right"); + NODEBOXREADVEC(c.disconnected_top, "disconnected_top"); + NODEBOXREADVEC(c.disconnected_bottom, "disconnected_bottom"); + NODEBOXREADVEC(c.disconnected_front, "disconnected_front"); + NODEBOXREADVEC(c.disconnected_left, "disconnected_left"); + NODEBOXREADVEC(c.disconnected_back, "disconnected_back"); + NODEBOXREADVEC(c.disconnected_right, "disconnected_right"); + NODEBOXREADVEC(c.disconnected, "disconnected"); + NODEBOXREADVEC(c.disconnected_sides, "disconnected_sides"); + } return nodebox; } diff --git a/src/script/cpp_api/s_security.cpp b/src/script/cpp_api/s_security.cpp index 76509038f..037bd8cf9 100644 --- a/src/script/cpp_api/s_security.cpp +++ b/src/script/cpp_api/s_security.cpp @@ -129,8 +129,6 @@ void ScriptApiSecurity::initializeSecurity() "gethook", "traceback", "getinfo", - "getmetatable", - "setmetatable", "upvalueid", "sethook", "debug", diff --git a/src/script/lua_api/l_item.cpp b/src/script/lua_api/l_item.cpp index 9220259ff..bae6701a0 100644 --- a/src/script/lua_api/l_item.cpp +++ b/src/script/lua_api/l_item.cpp @@ -599,6 +599,9 @@ int ModApiItemMod::l_register_item_raw(lua_State *L) // be done if (f.name == "ignore") return 0; + // This would break everything + if (f.name.empty()) + throw LuaError("Cannot register node with empty name"); content_t id = ndef->set(f.name, f); diff --git a/src/script/lua_api/l_nodemeta.cpp b/src/script/lua_api/l_nodemeta.cpp index 1d052685e..bdc4844c0 100644 --- a/src/script/lua_api/l_nodemeta.cpp +++ b/src/script/lua_api/l_nodemeta.cpp @@ -40,7 +40,7 @@ NodeMetaRef* NodeMetaRef::checkobject(lua_State *L, int narg) Metadata* NodeMetaRef::getmeta(bool auto_create) { if (m_is_local) - return m_meta; + return m_local_meta; NodeMetadata *meta = m_env->getMap().getNodeMetadata(m_p); if (meta == NULL && auto_create) { @@ -62,9 +62,14 @@ void NodeMetaRef::clearMeta() void NodeMetaRef::reportMetadataChange(const std::string *name) { SANITY_CHECK(!m_is_local); - // NOTE: This same code is in rollback_interface.cpp // Inform other things that the metadata has changed - NodeMetadata *meta = dynamic_cast<NodeMetadata*>(m_meta); + NodeMetadata *meta = dynamic_cast<NodeMetadata*>(getmeta(false)); + + // If the metadata is now empty, get rid of it + if (meta && meta->empty()) { + clearMeta(); + meta = nullptr; + } MapEditEvent event; event.type = MEET_BLOCK_NODE_METADATA_CHANGED; @@ -174,8 +179,8 @@ NodeMetaRef::NodeMetaRef(v3s16 p, ServerEnvironment *env): } NodeMetaRef::NodeMetaRef(Metadata *meta): - m_meta(meta), - m_is_local(true) + m_is_local(true), + m_local_meta(meta) { } diff --git a/src/script/lua_api/l_nodemeta.h b/src/script/lua_api/l_nodemeta.h index fdc1766ed..265ece3d0 100644 --- a/src/script/lua_api/l_nodemeta.h +++ b/src/script/lua_api/l_nodemeta.h @@ -33,10 +33,12 @@ class NodeMetadata; class NodeMetaRef : public MetaDataRef { private: + bool m_is_local = false; + // Set for server metadata v3s16 m_p; ServerEnvironment *m_env = nullptr; - Metadata *m_meta = nullptr; - bool m_is_local = false; + // Set for client metadata + Metadata *m_local_meta = nullptr; static const char className[]; static const luaL_Reg methodsServer[]; diff --git a/src/script/lua_api/l_object.cpp b/src/script/lua_api/l_object.cpp index 39b19364e..37ba1521a 100644 --- a/src/script/lua_api/l_object.cpp +++ b/src/script/lua_api/l_object.cpp @@ -2323,6 +2323,21 @@ int ObjectRef::l_get_lighting(lua_State *L) return 1; } +// respawn(self) +int ObjectRef::l_respawn(lua_State *L) +{ + NO_MAP_LOCK_REQUIRED; + ObjectRef *ref = checkobject(L, 1); + RemotePlayer *player = getplayer(ref); + if (player == nullptr) + return 0; + + getServer(L)->RespawnPlayer(player->getPeerId()); + lua_pushboolean(L, true); + return 1; +} + + ObjectRef::ObjectRef(ServerActiveObject *object): m_object(object) {} @@ -2478,5 +2493,7 @@ luaL_Reg ObjectRef::methods[] = { luamethod(ObjectRef, set_minimap_modes), luamethod(ObjectRef, set_lighting), luamethod(ObjectRef, get_lighting), + luamethod(ObjectRef, respawn), + {0,0} }; diff --git a/src/script/lua_api/l_object.h b/src/script/lua_api/l_object.h index 3e4e6681a..b36bab492 100644 --- a/src/script/lua_api/l_object.h +++ b/src/script/lua_api/l_object.h @@ -382,4 +382,7 @@ private: // get_lighting(self) static int l_get_lighting(lua_State *L); + + // respawn(self) + static int l_respawn(lua_State *L); }; diff --git a/src/script/lua_api/l_settings.cpp b/src/script/lua_api/l_settings.cpp index 14398dda2..3f3fda56e 100644 --- a/src/script/lua_api/l_settings.cpp +++ b/src/script/lua_api/l_settings.cpp @@ -27,9 +27,11 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "log.h" -/* This protects: - * 'secure.*' settings from being set - * some mapgen settings from being set +/* This protects the following from being set: + * 'secure.*' settings + * some security-relevant settings + * (better solution pending) + * some mapgen settings * (not security-criticial, just to avoid messing up user configs) */ #define CHECK_SETTING_SECURITY(L, name) \ @@ -41,7 +43,7 @@ with this program; if not, write to the Free Software Foundation, Inc., static inline int checkSettingSecurity(lua_State* L, const std::string &name) { if (ScriptApiSecurity::isSecure(L) && name.compare(0, 7, "secure.") == 0) - throw LuaError("Attempt to set secure setting."); + throw LuaError("Attempted to set secure setting."); bool is_mainmenu = false; #ifndef SERVER @@ -54,6 +56,17 @@ static inline int checkSettingSecurity(lua_State* L, const std::string &name) return -1; } + const char *disallowed[] = { + "main_menu_script", "shader_path", "texture_path", "screenshot_path", + "serverlist_file", "serverlist_url", "map-dir", "contentdb_url", + }; + if (!is_mainmenu) { + for (const char *name2 : disallowed) { + if (name == name2) + throw LuaError("Attempted to set disallowed setting."); + } + } + return 0; } diff --git a/src/server.cpp b/src/server.cpp index b6330c96a..013c039c3 100644 --- a/src/server.cpp +++ b/src/server.cpp @@ -891,7 +891,7 @@ void Server::AsyncRunStep(bool initial_step) // We'll log the amount of each Profiler prof; - std::list<v3s16> node_meta_updates; + std::unordered_set<v3s16> node_meta_updates; while (!m_unsent_map_edit_queue.empty()) { MapEditEvent* event = m_unsent_map_edit_queue.front(); @@ -918,9 +918,7 @@ void Server::AsyncRunStep(bool initial_step) case MEET_BLOCK_NODE_METADATA_CHANGED: { prof.add("MEET_BLOCK_NODE_METADATA_CHANGED", 1); if (!event->is_private_change) { - // Don't send the change yet. Collect them to eliminate dupes. - node_meta_updates.remove(event->p); - node_meta_updates.push_back(event->p); + node_meta_updates.emplace(event->p); } if (MapBlock *block = m_env->getMap().getBlockNoCreateNoEx( @@ -973,7 +971,7 @@ void Server::AsyncRunStep(bool initial_step) } // Send all metadata updates - if (node_meta_updates.size()) + if (!node_meta_updates.empty()) sendMetadataChanged(node_meta_updates); } @@ -2290,12 +2288,12 @@ void Server::sendAddNode(v3s16 p, MapNode n, std::unordered_set<u16> *far_player } } -void Server::sendMetadataChanged(const std::list<v3s16> &meta_updates, float far_d_nodes) +void Server::sendMetadataChanged(const std::unordered_set<v3s16> &positions, float far_d_nodes) { - float maxd = far_d_nodes * BS; NodeMetadataList meta_updates_list(false); - std::vector<session_t> clients = m_clients.getClientIDs(); + std::ostringstream os(std::ios::binary); + std::vector<session_t> clients = m_clients.getClientIDs(); ClientInterface::AutoLock clientlock(m_clients); for (session_t i : clients) { @@ -2303,18 +2301,20 @@ void Server::sendMetadataChanged(const std::list<v3s16> &meta_updates, float far if (!client) continue; - ServerActiveObject *player = m_env->getActiveObject(i); - v3f player_pos = player ? player->getBasePosition() : v3f(); + ServerActiveObject *player = getPlayerSAO(i); + v3s16 player_pos; + if (player) + player_pos = floatToInt(player->getBasePosition(), BS); - for (const v3s16 &pos : meta_updates) { + for (const v3s16 pos : positions) { NodeMetadata *meta = m_env->getMap().getNodeMetadata(pos); if (!meta) continue; v3s16 block_pos = getNodeBlockPos(pos); - if (!client->isBlockSent(block_pos) || (player && - player_pos.getDistanceFrom(intToFloat(pos, BS)) > maxd)) { + if (!client->isBlockSent(block_pos) || + player_pos.getDistanceFrom(pos) > far_d_nodes) { client->SetBlockNotSent(block_pos); continue; } @@ -2326,14 +2326,15 @@ void Server::sendMetadataChanged(const std::list<v3s16> &meta_updates, float far continue; // Send the meta changes - std::ostringstream os(std::ios::binary); + os.str(""); meta_updates_list.serialize(os, client->serialization_version, false, true, true); - std::ostringstream oss(std::ios::binary); - compressZlib(os.str(), oss); + std::string raw = os.str(); + os.str(""); + compressZlib(raw, os); - NetworkPacket pkt(TOCLIENT_NODEMETA_CHANGED, 0); - pkt.putLongString(oss.str()); - m_clients.send(i, 0, &pkt, true); + NetworkPacket pkt(TOCLIENT_NODEMETA_CHANGED, 0, i); + pkt.putLongString(os.str()); + Send(&pkt); meta_updates_list.clear(); } @@ -2784,9 +2785,10 @@ void Server::RespawnPlayer(session_t peer_id) << playersao->getPlayer()->getName() << " respawns" << std::endl; - playersao->setHP(playersao->accessObjectProperties()->hp_max, + const auto *prop = playersao->accessObjectProperties(); + playersao->setHP(prop->hp_max, PlayerHPChangeReason(PlayerHPChangeReason::RESPAWN)); - playersao->setBreath(playersao->accessObjectProperties()->breath_max); + playersao->setBreath(prop->breath_max); bool repositioned = m_script->on_respawnplayer(playersao); if (!repositioned) { diff --git a/src/server.h b/src/server.h index 2c21f5dfc..f1958701f 100644 --- a/src/server.h +++ b/src/server.h @@ -336,6 +336,8 @@ public: void setLighting(RemotePlayer *player, const Lighting &lighting); + void RespawnPlayer(session_t peer_id); + /* con::PeerHandler implementation. */ void peerAdded(con::Peer *peer); void deletingPeer(con::Peer *peer, bool timeout); @@ -425,11 +427,10 @@ private: std::unordered_set<session_t> waiting_players; }; - // the standard library does not implement std::hash for pairs so we have this: + // The standard library does not implement std::hash for pairs so we have this: struct SBCHash { size_t operator() (const std::pair<v3s16, u16> &p) const { - return (((size_t) p.first.X) << 48) | (((size_t) p.first.Y) << 32) | - (((size_t) p.first.Z) << 16) | ((size_t) p.second); + return std::hash<v3s16>()(p.first) ^ p.second; } }; @@ -491,7 +492,7 @@ private: std::unordered_set<u16> *far_players = nullptr, float far_d_nodes = 100, bool remove_metadata = true); - void sendMetadataChanged(const std::list<v3s16> &meta_updates, + void sendMetadataChanged(const std::unordered_set<v3s16> &positions, float far_d_nodes = 100); // Environment and Connection must be locked when called @@ -530,7 +531,6 @@ private: */ void HandlePlayerDeath(PlayerSAO* sao, const PlayerHPChangeReason &reason); - void RespawnPlayer(session_t peer_id); void DeleteClient(session_t peer_id, ClientDeletionReason reason); void UpdateCrafting(RemotePlayer *player); bool checkInteractDistance(RemotePlayer *player, const f32 d, const std::string &what); diff --git a/src/server/luaentity_sao.cpp b/src/server/luaentity_sao.cpp index 82f6da231..a4b37ee09 100644 --- a/src/server/luaentity_sao.cpp +++ b/src/server/luaentity_sao.cpp @@ -337,19 +337,9 @@ u32 LuaEntitySAO::punch(v3f dir, if (result.did_punch) { setHP((s32)getHP() - result.damage, PlayerHPChangeReason(PlayerHPChangeReason::PLAYER_PUNCH, puncher)); - - // create message and add to list - sendPunchCommand(); } } - if (getHP() == 0 && !isGone()) { - clearParentAttachment(); - clearChildAttachments(); - m_env->getScriptIface()->luaentity_on_death(m_id, puncher); - markForRemoval(); - } - actionstream << puncher->getDescription() << " (id=" << puncher->getId() << ", hp=" << puncher->getHP() << ") punched " << getDescription() << " (id=" << m_id << ", hp=" << m_hp << @@ -402,6 +392,20 @@ std::string LuaEntitySAO::getDescription() void LuaEntitySAO::setHP(s32 hp, const PlayerHPChangeReason &reason) { m_hp = rangelim(hp, 0, U16_MAX); + + sendPunchCommand(); + + if (m_hp == 0 && !isGone()) { + clearParentAttachment(); + clearChildAttachments(); + if (m_registered) { + ServerActiveObject *killer = nullptr; + if (reason.type == PlayerHPChangeReason::PLAYER_PUNCH) + killer = reason.object; + m_env->getScriptIface()->luaentity_on_death(m_id, killer); + } + markForRemoval(); + } } u16 LuaEntitySAO::getHP() const diff --git a/src/server/luaentity_sao.h b/src/server/luaentity_sao.h index 87b664a8b..5a5aea7a9 100644 --- a/src/server/luaentity_sao.h +++ b/src/server/luaentity_sao.h @@ -36,23 +36,30 @@ public: { } ~LuaEntitySAO(); + ActiveObjectType getType() const { return ACTIVEOBJECT_TYPE_LUAENTITY; } ActiveObjectType getSendType() const { return ACTIVEOBJECT_TYPE_GENERIC; } virtual void addedToEnvironment(u32 dtime_s); void step(float dtime, bool send_recommended); std::string getClientInitializationData(u16 protocol_version); + bool isStaticAllowed() const { return m_prop.static_save; } bool shouldUnload() const { return true; } void getStaticData(std::string *result) const; + u32 punch(v3f dir, const ToolCapabilities *toolcap = nullptr, ServerActiveObject *puncher = nullptr, float time_from_last_punch = 1000000.0f, u16 initial_wear = 0); + void rightClick(ServerActiveObject *clicker); + void setPos(const v3f &pos); void moveTo(v3f pos, bool continuous); float getMinimumSavedMovement(); + std::string getDescription(); + void setHP(s32 hp, const PlayerHPChangeReason &reason); u16 getHP() const; diff --git a/src/serverenvironment.cpp b/src/serverenvironment.cpp index 6a9001052..2855f04b8 100644 --- a/src/serverenvironment.cpp +++ b/src/serverenvironment.cpp @@ -378,10 +378,7 @@ void ActiveBlockList::update(std::vector<PlayerSAO*> &active_players, /* Update m_list */ - m_list.clear(); - for (v3s16 p : newlist) { - m_list.insert(p); - } + m_list = std::move(newlist); } /* @@ -626,6 +623,9 @@ PlayerSAO *ServerEnvironment::loadPlayer(RemotePlayer *player, bool *new_player, /* Add object to environment */ addActiveObject(playersao); + // Update active blocks asap so objects in those blocks appear on the client + m_force_update_active_blocks = true; + return playersao; } @@ -1332,13 +1332,16 @@ void ServerEnvironment::step(float dtime) /* Manage active block list */ - if (m_active_blocks_management_interval.step(dtime, m_cache_active_block_mgmt_interval)) { + if (m_active_blocks_mgmt_interval.step(dtime, m_cache_active_block_mgmt_interval) || + m_force_update_active_blocks) { ScopeProfiler sp(g_profiler, "ServerEnv: update active blocks", SPT_AVG); + /* Get player block positions */ std::vector<PlayerSAO*> players; - for (RemotePlayer *player: m_players) { + players.reserve(m_players.size()); + for (RemotePlayer *player : m_players) { // Ignore disconnected players if (player->getPeerId() == PEER_ID_INEXISTENT) continue; @@ -1363,8 +1366,6 @@ void ServerEnvironment::step(float dtime) m_active_blocks.update(players, active_block_range, active_object_range, blocks_removed, blocks_added); - m_active_block_gauge->set(m_active_blocks.size()); - /* Handle removed blocks */ @@ -1388,14 +1389,21 @@ void ServerEnvironment::step(float dtime) for (const v3s16 &p: blocks_added) { MapBlock *block = m_map->getBlockOrEmerge(p); if (!block) { - m_active_blocks.m_list.erase(p); - m_active_blocks.m_abm_list.erase(p); + // TODO: The blocks removed here will only be picked up again + // on the next cycle. To minimize the latency of objects being + // activated we could remember the blocks pending activating + // and activate them instantly as soon as they're loaded. + m_active_blocks.remove(p); continue; } activateBlock(block); } + + // Some blocks may be removed again by the code above so do this here + m_active_block_gauge->set(m_active_blocks.size()); } + m_force_update_active_blocks = false; /* Mess around in active blocks diff --git a/src/serverenvironment.h b/src/serverenvironment.h index 5dc329a60..00184421e 100644 --- a/src/serverenvironment.h +++ b/src/serverenvironment.h @@ -180,8 +180,14 @@ public: m_list.clear(); } + void remove(v3s16 p) { + m_list.erase(p); + m_abm_list.erase(p); + } + std::set<v3s16> m_list; std::set<v3s16> m_abm_list; + // list of blocks that are always active, not modified by this class std::set<v3s16> m_forceloaded_list; }; @@ -454,7 +460,8 @@ private: IntervalLimiter m_object_management_interval; // List of active blocks ActiveBlockList m_active_blocks; - IntervalLimiter m_active_blocks_management_interval; + bool m_force_update_active_blocks = false; + IntervalLimiter m_active_blocks_mgmt_interval; IntervalLimiter m_active_block_modifier_interval; IntervalLimiter m_active_blocks_nodemetadata_interval; // Whether the variables below have been read from file yet |