From 307d7376cf88f3ef30a73f4500971e3a77977068 Mon Sep 17 00:00:00 2001 From: LNJ Date: Sat, 4 Apr 2020 15:52:41 +0200 Subject: Fix 'the the' typos in comments (#9554) --- src/mapgen/mapgen_valleys.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/mapgen') diff --git a/src/mapgen/mapgen_valleys.cpp b/src/mapgen/mapgen_valleys.cpp index 2b8703fa5..ff908b7bb 100644 --- a/src/mapgen/mapgen_valleys.cpp +++ b/src/mapgen/mapgen_valleys.cpp @@ -390,7 +390,7 @@ int MapgenValleys::generateTerrain() // Rivers are placed where 'river' is negative if (river < 0.0f) { - // Use the the function -sqrt(1-x^2) which models a circle + // Use the function -sqrt(1-x^2) which models a circle float tr = river / river_size_factor + 1.0f; float depth = (river_depth_bed * std::sqrt(std::fmax(0.0f, 1.0f - tr * tr))); -- cgit v1.2.3 From aa3cf400e2ca4096517e926dbae5b6337b2f1876 Mon Sep 17 00:00:00 2001 From: Wuzzy Date: Fri, 10 Apr 2020 20:36:16 +0200 Subject: Print error if invalid mapgen alias was detected (#9579) --- src/mapgen/mapgen.cpp | 7 +++++++ src/mapgen/mapgen_v6.cpp | 15 +++++++++++++++ src/mapgen/treegen.cpp | 17 +++++++++++++++++ 3 files changed, 39 insertions(+) (limited to 'src/mapgen') diff --git a/src/mapgen/mapgen.cpp b/src/mapgen/mapgen.cpp index 79c429ff6..6c426ba41 100644 --- a/src/mapgen/mapgen.cpp +++ b/src/mapgen/mapgen.cpp @@ -629,6 +629,13 @@ MapgenBasic::MapgenBasic(int mapgenid, MapgenParams *params, EmergeManager *emer // Lava falls back to water as both are suitable as cave liquids. if (c_lava_source == CONTENT_IGNORE) c_lava_source = c_water_source; + + if (c_stone == CONTENT_IGNORE) + errorstream << "Mapgen: Mapgen alias 'mapgen_stone' is invalid!" << std::endl; + if (c_water_source == CONTENT_IGNORE) + errorstream << "Mapgen: Mapgen alias 'mapgen_water_source' is invalid!" << std::endl; + if (c_river_water_source == CONTENT_IGNORE) + warningstream << "Mapgen: Mapgen alias 'mapgen_river_water_source' is invalid!" << std::endl; } diff --git a/src/mapgen/mapgen_v6.cpp b/src/mapgen/mapgen_v6.cpp index 653adc8ec..8a863c044 100644 --- a/src/mapgen/mapgen_v6.cpp +++ b/src/mapgen/mapgen_v6.cpp @@ -132,6 +132,21 @@ MapgenV6::MapgenV6(MapgenV6Params *params, EmergeManager *emerge) c_stair_cobble = c_cobble; if (c_stair_desert_stone == CONTENT_IGNORE) c_stair_desert_stone = c_desert_stone; + + if (c_stone == CONTENT_IGNORE) + errorstream << "Mapgen v6: Mapgen alias 'mapgen_stone' is invalid!" << std::endl; + if (c_dirt == CONTENT_IGNORE) + errorstream << "Mapgen v6: Mapgen alias 'mapgen_dirt' is invalid!" << std::endl; + if (c_dirt_with_grass == CONTENT_IGNORE) + errorstream << "Mapgen v6: Mapgen alias 'mapgen_dirt_with_grass' is invalid!" << std::endl; + if (c_sand == CONTENT_IGNORE) + errorstream << "Mapgen v6: Mapgen alias 'mapgen_sand' is invalid!" << std::endl; + if (c_water_source == CONTENT_IGNORE) + errorstream << "Mapgen v6: Mapgen alias 'mapgen_water_source' is invalid!" << std::endl; + if (c_lava_source == CONTENT_IGNORE) + errorstream << "Mapgen v6: Mapgen alias 'mapgen_lava_source' is invalid!" << std::endl; + if (c_cobble == CONTENT_IGNORE) + errorstream << "Mapgen v6: Mapgen alias 'mapgen_cobble' is invalid!" << std::endl; } diff --git a/src/mapgen/treegen.cpp b/src/mapgen/treegen.cpp index 0d8af2851..89bdef73b 100644 --- a/src/mapgen/treegen.cpp +++ b/src/mapgen/treegen.cpp @@ -44,6 +44,12 @@ void make_tree(MMVManip &vmanip, v3s16 p0, bool is_apple_tree, MapNode treenode(ndef->getId("mapgen_tree")); MapNode leavesnode(ndef->getId("mapgen_leaves")); MapNode applenode(ndef->getId("mapgen_apple")); + if (treenode == CONTENT_IGNORE) + errorstream << "Treegen: Mapgen alias 'mapgen_tree' is invalid!" << std::endl; + if (leavesnode == CONTENT_IGNORE) + errorstream << "Treegen: Mapgen alias 'mapgen_leaves' is invalid!" << std::endl; + if (applenode == CONTENT_IGNORE) + errorstream << "Treegen: Mapgen alias 'mapgen_apple' is invalid!" << std::endl; PseudoRandom pr(seed); s16 trunk_h = pr.range(4, 5); @@ -145,6 +151,9 @@ treegen::error make_ltree(MMVManip &vmanip, v3s16 p0, const NodeDefManager *ndef, TreeDef tree_definition) { MapNode dirtnode(ndef->getId("mapgen_dirt")); + if (dirtnode == CONTENT_IGNORE) + errorstream << "Treegen (make_ltree): Mapgen alias 'mapgen_dirt' is invalid!" << std::endl; + s32 seed; if (tree_definition.explicit_seed) seed = tree_definition.seed + 14002; @@ -662,6 +671,10 @@ void make_jungletree(MMVManip &vmanip, v3s16 p0, const NodeDefManager *ndef, c_tree = ndef->getId("mapgen_tree"); if (c_leaves == CONTENT_IGNORE) c_leaves = ndef->getId("mapgen_leaves"); + if (c_tree == CONTENT_IGNORE) + errorstream << "Treegen: Mapgen alias 'mapgen_jungletree' is invalid!" << std::endl; + if (c_leaves == CONTENT_IGNORE) + errorstream << "Treegen: Mapgen alias 'mapgen_jungleleaves' is invalid!" << std::endl; MapNode treenode(c_tree); MapNode leavesnode(c_leaves); @@ -765,6 +778,10 @@ void make_pine_tree(MMVManip &vmanip, v3s16 p0, const NodeDefManager *ndef, c_leaves = ndef->getId("mapgen_leaves"); if (c_snow == CONTENT_IGNORE) c_snow = CONTENT_AIR; + if (c_tree == CONTENT_IGNORE) + errorstream << "Treegen: Mapgen alias 'mapgen_pine_tree' is invalid!" << std::endl; + if (c_leaves == CONTENT_IGNORE) + errorstream << "Treegen: Mapgen alias 'mapgen_pine_needles' is invalid!" << std::endl; MapNode treenode(c_tree); MapNode leavesnode(c_leaves); -- cgit v1.2.3 From 6d43736172f8459cb70219186ae003c56c389f2a Mon Sep 17 00:00:00 2001 From: Loic Blot Date: Fri, 10 Apr 2020 21:25:42 +0200 Subject: Move serveractiveobject & unitsao Move serverobject.{cpp,h} to server/serveractiveobject.{cpp,h} Move UnitSAO class to dedicated files --- build/android/jni/Android.mk | 2 +- src/CMakeLists.txt | 1 - src/collision.cpp | 2 +- src/content_sao.cpp | 296 ------------------------------ src/content_sao.h | 92 +--------- src/emerge.cpp | 1 - src/environment.cpp | 1 - src/inventorymanager.cpp | 2 +- src/mapgen/mapgen_v6.cpp | 1 - src/script/common/c_content.cpp | 2 +- src/script/cpp_api/s_base.cpp | 2 +- src/script/lua_api/l_object.cpp | 2 +- src/server.cpp | 2 +- src/server/CMakeLists.txt | 2 + src/server/activeobjectmgr.h | 2 +- src/server/serveractiveobject.cpp | 114 ++++++++++++ src/server/serveractiveobject.h | 265 +++++++++++++++++++++++++++ src/server/unit_sao.cpp | 318 +++++++++++++++++++++++++++++++++ src/server/unit_sao.h | 113 ++++++++++++ src/serverobject.cpp | 114 ------------ src/serverobject.h | 265 --------------------------- util/travis/clang-format-whitelist.txt | 6 +- 22 files changed, 823 insertions(+), 782 deletions(-) create mode 100644 src/server/serveractiveobject.cpp create mode 100644 src/server/serveractiveobject.h create mode 100644 src/server/unit_sao.cpp create mode 100644 src/server/unit_sao.h delete mode 100644 src/serverobject.cpp delete mode 100644 src/serverobject.h (limited to 'src/mapgen') diff --git a/build/android/jni/Android.mk b/build/android/jni/Android.mk index a2f32440a..32a16c174 100644 --- a/build/android/jni/Android.mk +++ b/build/android/jni/Android.mk @@ -259,7 +259,7 @@ LOCAL_SRC_FILES := \ jni/src/serverenvironment.cpp \ jni/src/serverlist.cpp \ jni/src/server/mods.cpp \ - jni/src/serverobject.cpp \ + jni/src/server/serveractiveobject.cpp \ jni/src/settings.cpp \ jni/src/staticobject.cpp \ jni/src/tileanimation.cpp \ diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 4b1d6d647..faa117d41 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -421,7 +421,6 @@ set(common_SRCS server.cpp serverenvironment.cpp serverlist.cpp - serverobject.cpp settings.cpp staticobject.cpp terminal_chat_console.cpp diff --git a/src/collision.cpp b/src/collision.cpp index 0d37ea436..d9fbd3202 100644 --- a/src/collision.cpp +++ b/src/collision.cpp @@ -28,7 +28,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "client/localplayer.h" #endif #include "serverenvironment.h" -#include "serverobject.h" +#include "server/serveractiveobject.h" #include "util/timetaker.h" #include "profiler.h" diff --git a/src/content_sao.cpp b/src/content_sao.cpp index be7674f52..0d387b53a 100644 --- a/src/content_sao.cpp +++ b/src/content_sao.cpp @@ -106,302 +106,6 @@ private: // Prototype (registers item for deserialization) TestSAO proto_TestSAO(NULL, v3f(0,0,0)); -/* - UnitSAO - */ - -UnitSAO::UnitSAO(ServerEnvironment *env, v3f pos): - ServerActiveObject(env, pos) -{ - // Initialize something to armor groups - m_armor_groups["fleshy"] = 100; -} - -ServerActiveObject *UnitSAO::getParent() const -{ - if (!m_attachment_parent_id) - return nullptr; - // Check if the parent still exists - ServerActiveObject *obj = m_env->getActiveObject(m_attachment_parent_id); - - return obj; -} - -void UnitSAO::setArmorGroups(const ItemGroupList &armor_groups) -{ - m_armor_groups = armor_groups; - m_armor_groups_sent = false; -} - -const ItemGroupList &UnitSAO::getArmorGroups() const -{ - return m_armor_groups; -} - -void UnitSAO::setAnimation(v2f frame_range, float frame_speed, float frame_blend, bool frame_loop) -{ - // store these so they can be updated to clients - m_animation_range = frame_range; - m_animation_speed = frame_speed; - m_animation_blend = frame_blend; - m_animation_loop = frame_loop; - m_animation_sent = false; -} - -void UnitSAO::getAnimation(v2f *frame_range, float *frame_speed, float *frame_blend, bool *frame_loop) -{ - *frame_range = m_animation_range; - *frame_speed = m_animation_speed; - *frame_blend = m_animation_blend; - *frame_loop = m_animation_loop; -} - -void UnitSAO::setAnimationSpeed(float frame_speed) -{ - m_animation_speed = frame_speed; - m_animation_speed_sent = false; -} - -void UnitSAO::setBonePosition(const std::string &bone, v3f position, v3f rotation) -{ - // store these so they can be updated to clients - m_bone_position[bone] = core::vector2d(position, rotation); - m_bone_position_sent = false; -} - -void UnitSAO::getBonePosition(const std::string &bone, v3f *position, v3f *rotation) -{ - *position = m_bone_position[bone].X; - *rotation = m_bone_position[bone].Y; -} - -void UnitSAO::setAttachment(int parent_id, const std::string &bone, v3f position, v3f rotation) -{ - // Attachments need to be handled on both the server and client. - // If we just attach on the server, we can only copy the position of the parent. Attachments - // are still sent to clients at an interval so players might see them lagging, plus we can't - // read and attach to skeletal bones. - // If we just attach on the client, the server still sees the child at its original location. - // This breaks some things so we also give the server the most accurate representation - // even if players only see the client changes. - - int old_parent = m_attachment_parent_id; - m_attachment_parent_id = parent_id; - m_attachment_bone = bone; - m_attachment_position = position; - m_attachment_rotation = rotation; - m_attachment_sent = false; - - if (parent_id != old_parent) { - onDetach(old_parent); - onAttach(parent_id); - } -} - -void UnitSAO::getAttachment(int *parent_id, std::string *bone, v3f *position, - v3f *rotation) const -{ - *parent_id = m_attachment_parent_id; - *bone = m_attachment_bone; - *position = m_attachment_position; - *rotation = m_attachment_rotation; -} - -void UnitSAO::clearChildAttachments() -{ - for (int child_id : m_attachment_child_ids) { - // Child can be NULL if it was deleted earlier - if (ServerActiveObject *child = m_env->getActiveObject(child_id)) - child->setAttachment(0, "", v3f(0, 0, 0), v3f(0, 0, 0)); - } - m_attachment_child_ids.clear(); -} - -void UnitSAO::clearParentAttachment() -{ - ServerActiveObject *parent = nullptr; - if (m_attachment_parent_id) { - parent = m_env->getActiveObject(m_attachment_parent_id); - setAttachment(0, "", m_attachment_position, m_attachment_rotation); - } else { - setAttachment(0, "", v3f(0, 0, 0), v3f(0, 0, 0)); - } - // Do it - if (parent) - parent->removeAttachmentChild(m_id); -} - -void UnitSAO::addAttachmentChild(int child_id) -{ - m_attachment_child_ids.insert(child_id); -} - -void UnitSAO::removeAttachmentChild(int child_id) -{ - m_attachment_child_ids.erase(child_id); -} - -const std::unordered_set &UnitSAO::getAttachmentChildIds() const -{ - return m_attachment_child_ids; -} - -void UnitSAO::onAttach(int parent_id) -{ - if (!parent_id) - return; - - ServerActiveObject *parent = m_env->getActiveObject(parent_id); - - if (!parent || parent->isGone()) - return; // Do not try to notify soon gone parent - - if (parent->getType() == ACTIVEOBJECT_TYPE_LUAENTITY) { - // Call parent's on_attach field - m_env->getScriptIface()->luaentity_on_attach_child(parent_id, this); - } -} - -void UnitSAO::onDetach(int parent_id) -{ - if (!parent_id) - return; - - ServerActiveObject *parent = m_env->getActiveObject(parent_id); - if (getType() == ACTIVEOBJECT_TYPE_LUAENTITY) - m_env->getScriptIface()->luaentity_on_detach(m_id, parent); - - if (!parent || parent->isGone()) - return; // Do not try to notify soon gone parent - - if (parent->getType() == ACTIVEOBJECT_TYPE_LUAENTITY) - m_env->getScriptIface()->luaentity_on_detach_child(parent_id, this); -} - -ObjectProperties* UnitSAO::accessObjectProperties() -{ - return &m_prop; -} - -void UnitSAO::notifyObjectPropertiesModified() -{ - m_properties_sent = false; -} - -std::string UnitSAO::generateUpdateAttachmentCommand() const -{ - std::ostringstream os(std::ios::binary); - // command - writeU8(os, AO_CMD_ATTACH_TO); - // parameters - writeS16(os, m_attachment_parent_id); - os << serializeString(m_attachment_bone); - writeV3F32(os, m_attachment_position); - writeV3F32(os, m_attachment_rotation); - return os.str(); -} - -std::string UnitSAO::generateUpdateBonePositionCommand(const std::string &bone, - const v3f &position, const v3f &rotation) -{ - std::ostringstream os(std::ios::binary); - // command - writeU8(os, AO_CMD_SET_BONE_POSITION); - // parameters - os << serializeString(bone); - writeV3F32(os, position); - writeV3F32(os, rotation); - return os.str(); -} - - -std::string UnitSAO::generateUpdateAnimationSpeedCommand() const -{ - std::ostringstream os(std::ios::binary); - // command - writeU8(os, AO_CMD_SET_ANIMATION_SPEED); - // parameters - writeF32(os, m_animation_speed); - return os.str(); -} - -std::string UnitSAO::generateUpdateAnimationCommand() const -{ - std::ostringstream os(std::ios::binary); - // command - writeU8(os, AO_CMD_SET_ANIMATION); - // parameters - writeV2F32(os, m_animation_range); - writeF32(os, m_animation_speed); - writeF32(os, m_animation_blend); - // these are sent inverted so we get true when the server sends nothing - writeU8(os, !m_animation_loop); - return os.str(); -} - - -std::string UnitSAO::generateUpdateArmorGroupsCommand() const -{ - std::ostringstream os(std::ios::binary); - writeU8(os, AO_CMD_UPDATE_ARMOR_GROUPS); - writeU16(os, m_armor_groups.size()); - for (const auto &armor_group : m_armor_groups) { - os< &getAttachmentChildIds() const; - ServerActiveObject *getParent() const; - ObjectProperties* accessObjectProperties(); - void notifyObjectPropertiesModified(); - - std::string generateUpdateAttachmentCommand() const; - std::string generateUpdateAnimationSpeedCommand() const; - std::string generateUpdateAnimationCommand() const; - std::string generateUpdateArmorGroupsCommand() const; - static std::string generateUpdatePositionCommand(const v3f &position, const v3f &velocity, - const v3f &acceleration, const v3f &rotation, bool do_interpolate, - bool is_movement_end, f32 update_interval); - std::string generateSetPropertiesCommand(const ObjectProperties &prop) const; - void sendPunchCommand(); - static std::string generateUpdateBonePositionCommand(const std::string &bone, - const v3f &position, const v3f &rotation); - -protected: - u16 m_hp = 1; - - v3f m_rotation; - - bool m_properties_sent = true; - ObjectProperties m_prop; - - ItemGroupList m_armor_groups; - bool m_armor_groups_sent = false; - - v2f m_animation_range; - float m_animation_speed = 0.0f; - float m_animation_blend = 0.0f; - bool m_animation_loop = true; - bool m_animation_sent = false; - bool m_animation_speed_sent = false; - - // Stores position and rotation for each bone name - std::unordered_map> m_bone_position; - bool m_bone_position_sent = false; - - int m_attachment_parent_id = 0; - std::unordered_set m_attachment_child_ids; - std::string m_attachment_bone = ""; - v3f m_attachment_position; - v3f m_attachment_rotation; - bool m_attachment_sent = false; -private: - void onAttach(int parent_id); - void onDetach(int parent_id); - - std::string generatePunchCommand(u16 result_hp) const; -}; - /* LuaEntitySAO needs some internals exposed. */ diff --git a/src/emerge.cpp b/src/emerge.cpp index 4835c3fad..fe885447c 100644 --- a/src/emerge.cpp +++ b/src/emerge.cpp @@ -42,7 +42,6 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "profiler.h" #include "scripting_server.h" #include "server.h" -#include "serverobject.h" #include "settings.h" #include "voxel.h" diff --git a/src/environment.cpp b/src/environment.cpp index c997be3ff..6751f39e4 100644 --- a/src/environment.cpp +++ b/src/environment.cpp @@ -21,7 +21,6 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "environment.h" #include "collision.h" #include "raycast.h" -#include "serverobject.h" #include "scripting_server.h" #include "server.h" #include "daynightratio.h" diff --git a/src/inventorymanager.cpp b/src/inventorymanager.cpp index 5a24f95a4..b6f464901 100644 --- a/src/inventorymanager.cpp +++ b/src/inventorymanager.cpp @@ -22,7 +22,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "log.h" #include "serverenvironment.h" #include "scripting_server.h" -#include "serverobject.h" +#include "server/serveractiveobject.h" #include "settings.h" #include "craftdef.h" #include "rollback_interface.h" diff --git a/src/mapgen/mapgen_v6.cpp b/src/mapgen/mapgen_v6.cpp index 8a863c044..f473f725d 100644 --- a/src/mapgen/mapgen_v6.cpp +++ b/src/mapgen/mapgen_v6.cpp @@ -27,7 +27,6 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "mapblock.h" #include "mapnode.h" #include "map.h" -//#include "serverobject.h" #include "content_sao.h" #include "nodedef.h" #include "voxelalgorithms.h" diff --git a/src/script/common/c_content.cpp b/src/script/common/c_content.cpp index accbb1a87..60f12052f 100644 --- a/src/script/common/c_content.cpp +++ b/src/script/common/c_content.cpp @@ -29,7 +29,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "server.h" #include "log.h" #include "tool.h" -#include "serverobject.h" +#include "server/serveractiveobject.h" #include "porting.h" #include "mapgen/mg_schematic.h" #include "noise.h" diff --git a/src/script/cpp_api/s_base.cpp b/src/script/cpp_api/s_base.cpp index f234a15d4..16c20eeae 100644 --- a/src/script/cpp_api/s_base.cpp +++ b/src/script/cpp_api/s_base.cpp @@ -22,7 +22,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "cpp_api/s_security.h" #include "lua_api/l_object.h" #include "common/c_converter.h" -#include "serverobject.h" +#include "server/serveractiveobject.h" #include "filesys.h" #include "content/mods.h" #include "porting.h" diff --git a/src/script/lua_api/l_object.cpp b/src/script/lua_api/l_object.cpp index 5cd978d73..1ea144a1c 100644 --- a/src/script/lua_api/l_object.cpp +++ b/src/script/lua_api/l_object.cpp @@ -27,7 +27,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "common/c_content.h" #include "log.h" #include "tool.h" -#include "serverobject.h" +#include "server/serveractiveobject.h" #include "content_sao.h" #include "remoteplayer.h" #include "server.h" diff --git a/src/server.cpp b/src/server.cpp index 062fe0798..529466f6b 100644 --- a/src/server.cpp +++ b/src/server.cpp @@ -34,7 +34,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "version.h" #include "filesys.h" #include "mapblock.h" -#include "serverobject.h" +#include "server/serveractiveobject.h" #include "settings.h" #include "profiler.h" #include "log.h" diff --git a/src/server/CMakeLists.txt b/src/server/CMakeLists.txt index e964c69ff..9fa5ed9fa 100644 --- a/src/server/CMakeLists.txt +++ b/src/server/CMakeLists.txt @@ -1,4 +1,6 @@ set(server_SRCS ${CMAKE_CURRENT_SOURCE_DIR}/activeobjectmgr.cpp ${CMAKE_CURRENT_SOURCE_DIR}/mods.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/serveractiveobject.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/unit_sao.cpp PARENT_SCOPE) diff --git a/src/server/activeobjectmgr.h b/src/server/activeobjectmgr.h index a502ac6ed..5fea1bea6 100644 --- a/src/server/activeobjectmgr.h +++ b/src/server/activeobjectmgr.h @@ -22,7 +22,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include #include #include "../activeobjectmgr.h" -#include "serverobject.h" +#include "serveractiveobject.h" namespace server { diff --git a/src/server/serveractiveobject.cpp b/src/server/serveractiveobject.cpp new file mode 100644 index 000000000..3aa78c7d5 --- /dev/null +++ b/src/server/serveractiveobject.cpp @@ -0,0 +1,114 @@ +/* +Minetest +Copyright (C) 2010-2013 celeron55, Perttu Ahola + +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 "serveractiveobject.h" +#include +#include "inventory.h" +#include "constants.h" // BS +#include "log.h" + +ServerActiveObject::ServerActiveObject(ServerEnvironment *env, v3f pos): + ActiveObject(0), + m_env(env), + m_base_position(pos) +{ +} + +ServerActiveObject* ServerActiveObject::create(ActiveObjectType type, + ServerEnvironment *env, u16 id, v3f pos, + const std::string &data) +{ + // Find factory function + std::map::iterator n; + n = m_types.find(type); + if(n == m_types.end()) { + // These are 0.3 entity types, return without error. + if (ACTIVEOBJECT_TYPE_ITEM <= type && type <= ACTIVEOBJECT_TYPE_MOBV2) { + return NULL; + } + + // If factory is not found, just return. + warningstream<<"ServerActiveObject: No factory for type=" + <second; + ServerActiveObject *object = (*f)(env, pos, data); + return object; +} + +void ServerActiveObject::registerType(u16 type, Factory f) +{ + std::map::iterator n; + n = m_types.find(type); + if(n != m_types.end()) + return; + m_types[type] = f; +} + +float ServerActiveObject::getMinimumSavedMovement() +{ + return 2.0*BS; +} + +ItemStack ServerActiveObject::getWieldedItem(ItemStack *selected, ItemStack *hand) const +{ + *selected = ItemStack(); + if (hand) + *hand = ItemStack(); + + return ItemStack(); +} + +bool ServerActiveObject::setWieldedItem(const ItemStack &item) +{ + return false; +} + +std::string ServerActiveObject::generateUpdateInfantCommand(u16 infant_id, u16 protocol_version) +{ + std::ostringstream os(std::ios::binary); + // command + writeU8(os, AO_CMD_SPAWN_INFANT); + // parameters + writeU16(os, infant_id); + writeU8(os, getSendType()); + os << serializeLongString(getClientInitializationData(protocol_version)); + return os.str(); +} + +std::string ServerActiveObject::generateUpdateNametagAttributesCommand(const video::SColor &color) const +{ + std::ostringstream os(std::ios::binary); + // command + writeU8(os, AO_CMD_UPDATE_NAMETAG_ATTRIBUTES); + // parameters + writeU8(os, 1); // version for forward compatibility + writeARGB8(os, color); + return os.str(); +} + +void ServerActiveObject::dumpAOMessagesToQueue(std::queue &queue) +{ + while (!m_messages_out.empty()) { + queue.push(m_messages_out.front()); + m_messages_out.pop(); + } +} \ No newline at end of file diff --git a/src/server/serveractiveobject.h b/src/server/serveractiveobject.h new file mode 100644 index 000000000..2e013a6b6 --- /dev/null +++ b/src/server/serveractiveobject.h @@ -0,0 +1,265 @@ +/* +Minetest +Copyright (C) 2010-2013 celeron55, Perttu Ahola + +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 +#include "irrlichttypes_bloated.h" +#include "activeobject.h" +#include "inventorymanager.h" +#include "itemgroup.h" +#include "util/container.h" + +/* + +Some planning +------------- + +* Server environment adds an active object, which gets the id 1 +* The active object list is scanned for each client once in a while, + and it finds out what objects have been added that are not known + by the client yet. This scan is initiated by the Server class and + the result ends up directly to the server. +* A network packet is created with the info and sent to the client. +* Environment converts objects to static data and static data to + objects, based on how close players are to them. + +*/ + +class ServerEnvironment; +struct ItemStack; +struct ToolCapabilities; +struct ObjectProperties; +struct PlayerHPChangeReason; + +class ServerActiveObject : public ActiveObject +{ +public: + /* + NOTE: m_env can be NULL, but step() isn't called if it is. + Prototypes are used that way. + */ + ServerActiveObject(ServerEnvironment *env, v3f pos); + virtual ~ServerActiveObject() = default; + + virtual ActiveObjectType getSendType() const + { return getType(); } + + // Called after id has been set and has been inserted in environment + virtual void addedToEnvironment(u32 dtime_s){}; + // Called before removing from environment + virtual void removingFromEnvironment(){}; + // Returns true if object's deletion is the job of the + // environment + virtual bool environmentDeletes() const + { return true; } + + // Create a certain type of ServerActiveObject + static ServerActiveObject* create(ActiveObjectType type, + ServerEnvironment *env, u16 id, v3f pos, + const std::string &data); + + /* + Some simple getters/setters + */ + v3f getBasePosition() const { return m_base_position; } + void setBasePosition(v3f pos){ m_base_position = pos; } + ServerEnvironment* getEnv(){ return m_env; } + + /* + Some more dynamic interface + */ + + virtual void setPos(const v3f &pos) + { setBasePosition(pos); } + // continuous: if true, object does not stop immediately at pos + virtual void moveTo(v3f pos, bool continuous) + { setBasePosition(pos); } + // If object has moved less than this and data has not changed, + // saving to disk may be omitted + virtual float getMinimumSavedMovement(); + + virtual std::string getDescription(){return "SAO";} + + /* + Step object in time. + Messages added to messages are sent to client over network. + + send_recommended: + True at around 5-10 times a second, same for all objects. + This is used to let objects send most of the data at the + same time so that the data can be combined in a single + packet. + */ + virtual void step(float dtime, bool send_recommended){} + + /* + The return value of this is passed to the client-side object + when it is created + */ + virtual std::string getClientInitializationData(u16 protocol_version) {return "";} + + /* + The return value of this is passed to the server-side object + when it is created (converted from static to active - actually + the data is the static form) + */ + virtual void getStaticData(std::string *result) const + { + assert(isStaticAllowed()); + *result = ""; + } + /* + Return false in here to never save and instead remove object + on unload. getStaticData() will not be called in that case. + */ + virtual bool isStaticAllowed() const + {return true;} + + // Returns tool wear + virtual u16 punch(v3f dir, + const ToolCapabilities *toolcap = nullptr, + ServerActiveObject *puncher = nullptr, + float time_from_last_punch = 1000000.0f) + { return 0; } + virtual void rightClick(ServerActiveObject *clicker) + {} + virtual void setHP(s32 hp, const PlayerHPChangeReason &reason) + {} + virtual u16 getHP() const + { return 0; } + + virtual void setArmorGroups(const ItemGroupList &armor_groups) + {} + virtual const ItemGroupList &getArmorGroups() const + { static ItemGroupList rv; return rv; } + virtual void setPhysicsOverride(float physics_override_speed, float physics_override_jump, float physics_override_gravity) + {} + virtual void setAnimation(v2f frames, float frame_speed, float frame_blend, bool frame_loop) + {} + virtual void getAnimation(v2f *frames, float *frame_speed, float *frame_blend, bool *frame_loop) + {} + virtual void setAnimationSpeed(float frame_speed) + {} + virtual void setBonePosition(const std::string &bone, v3f position, v3f rotation) + {} + virtual void getBonePosition(const std::string &bone, v3f *position, v3f *lotation) + {} + virtual const std::unordered_set &getAttachmentChildIds() const + { static std::unordered_set rv; return rv; } + virtual ServerActiveObject *getParent() const { return nullptr; } + virtual ObjectProperties* accessObjectProperties() + { return NULL; } + virtual void notifyObjectPropertiesModified() + {} + + // Inventory and wielded item + virtual Inventory *getInventory() const + { return NULL; } + virtual InventoryLocation getInventoryLocation() const + { return InventoryLocation(); } + virtual void setInventoryModified() + {} + virtual std::string getWieldList() const + { return ""; } + virtual u16 getWieldIndex() const + { return 0; } + virtual ItemStack getWieldedItem(ItemStack *selected, + ItemStack *hand = nullptr) const; + virtual bool setWieldedItem(const ItemStack &item); + inline void attachParticleSpawner(u32 id) + { + m_attached_particle_spawners.insert(id); + } + inline void detachParticleSpawner(u32 id) + { + m_attached_particle_spawners.erase(id); + } + + std::string generateUpdateInfantCommand(u16 infant_id, u16 protocol_version); + std::string generateUpdateNametagAttributesCommand(const video::SColor &color) const; + + void dumpAOMessagesToQueue(std::queue &queue); + + /* + Number of players which know about this object. Object won't be + deleted until this is 0 to keep the id preserved for the right + object. + */ + u16 m_known_by_count = 0; + + /* + - Whether this object is to be removed when nobody knows about + it anymore. + - Removal is delayed to preserve the id for the time during which + it could be confused to some other object by some client. + - This is usually set to true by the step() method when the object wants + to be deleted but can be set by anything else too. + */ + bool m_pending_removal = false; + + /* + Same purpose as m_pending_removal but for deactivation. + deactvation = save static data in block, remove active object + + If this is set alongside with m_pending_removal, removal takes + priority. + */ + bool m_pending_deactivation = false; + + /* + A getter that unifies the above to answer the question: + "Can the environment still interact with this object?" + */ + inline bool isGone() const + { return m_pending_removal || m_pending_deactivation; } + + /* + Whether the object's static data has been stored to a block + */ + bool m_static_exists = false; + /* + The block from which the object was loaded from, and in which + a copy of the static data resides. + */ + v3s16 m_static_block = v3s16(1337,1337,1337); + +protected: + virtual void onAttach(int parent_id) {} + virtual void onDetach(int parent_id) {} + + // Used for creating objects based on type + typedef ServerActiveObject* (*Factory) + (ServerEnvironment *env, v3f pos, + const std::string &data); + static void registerType(u16 type, Factory f); + + ServerEnvironment *m_env; + v3f m_base_position; + std::unordered_set m_attached_particle_spawners; + + /* + Queue of messages to be sent to the client + */ + std::queue m_messages_out; + +private: + // Used for creating objects based on type + static std::map m_types; +}; diff --git a/src/server/unit_sao.cpp b/src/server/unit_sao.cpp new file mode 100644 index 000000000..66be67522 --- /dev/null +++ b/src/server/unit_sao.cpp @@ -0,0 +1,318 @@ +/* +Minetest +Copyright (C) 2010-2013 celeron55, Perttu Ahola +Copyright (C) 2013-2020 Minetest core developers & community + +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 "unit_sao.h" +#include "scripting_server.h" +#include "serverenvironment.h" + +/* + UnitSAO + */ + +UnitSAO::UnitSAO(ServerEnvironment *env, v3f pos): + ServerActiveObject(env, pos) +{ + // Initialize something to armor groups + m_armor_groups["fleshy"] = 100; +} + +ServerActiveObject *UnitSAO::getParent() const +{ + if (!m_attachment_parent_id) + return nullptr; + // Check if the parent still exists + ServerActiveObject *obj = m_env->getActiveObject(m_attachment_parent_id); + + return obj; +} + +void UnitSAO::setArmorGroups(const ItemGroupList &armor_groups) +{ + m_armor_groups = armor_groups; + m_armor_groups_sent = false; +} + +const ItemGroupList &UnitSAO::getArmorGroups() const +{ + return m_armor_groups; +} + +void UnitSAO::setAnimation(v2f frame_range, float frame_speed, float frame_blend, bool frame_loop) +{ + // store these so they can be updated to clients + m_animation_range = frame_range; + m_animation_speed = frame_speed; + m_animation_blend = frame_blend; + m_animation_loop = frame_loop; + m_animation_sent = false; +} + +void UnitSAO::getAnimation(v2f *frame_range, float *frame_speed, float *frame_blend, bool *frame_loop) +{ + *frame_range = m_animation_range; + *frame_speed = m_animation_speed; + *frame_blend = m_animation_blend; + *frame_loop = m_animation_loop; +} + +void UnitSAO::setAnimationSpeed(float frame_speed) +{ + m_animation_speed = frame_speed; + m_animation_speed_sent = false; +} + +void UnitSAO::setBonePosition(const std::string &bone, v3f position, v3f rotation) +{ + // store these so they can be updated to clients + m_bone_position[bone] = core::vector2d(position, rotation); + m_bone_position_sent = false; +} + +void UnitSAO::getBonePosition(const std::string &bone, v3f *position, v3f *rotation) +{ + *position = m_bone_position[bone].X; + *rotation = m_bone_position[bone].Y; +} + +void UnitSAO::setAttachment(int parent_id, const std::string &bone, v3f position, v3f rotation) +{ + // Attachments need to be handled on both the server and client. + // If we just attach on the server, we can only copy the position of the parent. Attachments + // are still sent to clients at an interval so players might see them lagging, plus we can't + // read and attach to skeletal bones. + // If we just attach on the client, the server still sees the child at its original location. + // This breaks some things so we also give the server the most accurate representation + // even if players only see the client changes. + + int old_parent = m_attachment_parent_id; + m_attachment_parent_id = parent_id; + m_attachment_bone = bone; + m_attachment_position = position; + m_attachment_rotation = rotation; + m_attachment_sent = false; + + if (parent_id != old_parent) { + onDetach(old_parent); + onAttach(parent_id); + } +} + +void UnitSAO::getAttachment(int *parent_id, std::string *bone, v3f *position, + v3f *rotation) const +{ + *parent_id = m_attachment_parent_id; + *bone = m_attachment_bone; + *position = m_attachment_position; + *rotation = m_attachment_rotation; +} + +void UnitSAO::clearChildAttachments() +{ + for (int child_id : m_attachment_child_ids) { + // Child can be NULL if it was deleted earlier + if (ServerActiveObject *child = m_env->getActiveObject(child_id)) + child->setAttachment(0, "", v3f(0, 0, 0), v3f(0, 0, 0)); + } + m_attachment_child_ids.clear(); +} + +void UnitSAO::clearParentAttachment() +{ + ServerActiveObject *parent = nullptr; + if (m_attachment_parent_id) { + parent = m_env->getActiveObject(m_attachment_parent_id); + setAttachment(0, "", m_attachment_position, m_attachment_rotation); + } else { + setAttachment(0, "", v3f(0, 0, 0), v3f(0, 0, 0)); + } + // Do it + if (parent) + parent->removeAttachmentChild(m_id); +} + +void UnitSAO::addAttachmentChild(int child_id) +{ + m_attachment_child_ids.insert(child_id); +} + +void UnitSAO::removeAttachmentChild(int child_id) +{ + m_attachment_child_ids.erase(child_id); +} + +const std::unordered_set &UnitSAO::getAttachmentChildIds() const +{ + return m_attachment_child_ids; +} + +void UnitSAO::onAttach(int parent_id) +{ + if (!parent_id) + return; + + ServerActiveObject *parent = m_env->getActiveObject(parent_id); + + if (!parent || parent->isGone()) + return; // Do not try to notify soon gone parent + + if (parent->getType() == ACTIVEOBJECT_TYPE_LUAENTITY) { + // Call parent's on_attach field + m_env->getScriptIface()->luaentity_on_attach_child(parent_id, this); + } +} + +void UnitSAO::onDetach(int parent_id) +{ + if (!parent_id) + return; + + ServerActiveObject *parent = m_env->getActiveObject(parent_id); + if (getType() == ACTIVEOBJECT_TYPE_LUAENTITY) + m_env->getScriptIface()->luaentity_on_detach(m_id, parent); + + if (!parent || parent->isGone()) + return; // Do not try to notify soon gone parent + + if (parent->getType() == ACTIVEOBJECT_TYPE_LUAENTITY) + m_env->getScriptIface()->luaentity_on_detach_child(parent_id, this); +} + +ObjectProperties* UnitSAO::accessObjectProperties() +{ + return &m_prop; +} + +void UnitSAO::notifyObjectPropertiesModified() +{ + m_properties_sent = false; +} + +std::string UnitSAO::generateUpdateAttachmentCommand() const +{ + std::ostringstream os(std::ios::binary); + // command + writeU8(os, AO_CMD_ATTACH_TO); + // parameters + writeS16(os, m_attachment_parent_id); + os << serializeString(m_attachment_bone); + writeV3F32(os, m_attachment_position); + writeV3F32(os, m_attachment_rotation); + return os.str(); +} + +std::string UnitSAO::generateUpdateBonePositionCommand(const std::string &bone, + const v3f &position, const v3f &rotation) +{ + std::ostringstream os(std::ios::binary); + // command + writeU8(os, AO_CMD_SET_BONE_POSITION); + // parameters + os << serializeString(bone); + writeV3F32(os, position); + writeV3F32(os, rotation); + return os.str(); +} + + +std::string UnitSAO::generateUpdateAnimationSpeedCommand() const +{ + std::ostringstream os(std::ios::binary); + // command + writeU8(os, AO_CMD_SET_ANIMATION_SPEED); + // parameters + writeF32(os, m_animation_speed); + return os.str(); +} + +std::string UnitSAO::generateUpdateAnimationCommand() const +{ + std::ostringstream os(std::ios::binary); + // command + writeU8(os, AO_CMD_SET_ANIMATION); + // parameters + writeV2F32(os, m_animation_range); + writeF32(os, m_animation_speed); + writeF32(os, m_animation_blend); + // these are sent inverted so we get true when the server sends nothing + writeU8(os, !m_animation_loop); + return os.str(); +} + + +std::string UnitSAO::generateUpdateArmorGroupsCommand() const +{ + std::ostringstream os(std::ios::binary); + writeU8(os, AO_CMD_UPDATE_ARMOR_GROUPS); + writeU16(os, m_armor_groups.size()); + for (const auto &armor_group : m_armor_groups) { + os< +Copyright (C) 2013-2020 Minetest core developers & community + +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 "object_properties.h" +#include "serveractiveobject.h" + +class UnitSAO: public ServerActiveObject +{ +public: + UnitSAO(ServerEnvironment *env, v3f pos); + virtual ~UnitSAO() = default; + + void setRotation(v3f rotation) { m_rotation = rotation; } + const v3f &getRotation() const { return m_rotation; } + v3f getRadRotation() { return m_rotation * core::DEGTORAD; } + + // Deprecated + f32 getRadYawDep() const { return (m_rotation.Y + 90.) * core::DEGTORAD; } + + u16 getHP() const { return m_hp; } + // Use a function, if isDead can be defined by other conditions + bool isDead() const { return m_hp == 0; } + + inline bool isAttached() const + { return getParent(); } + + inline bool isImmortal() const + { return itemgroup_get(getArmorGroups(), "immortal"); } + + void setArmorGroups(const ItemGroupList &armor_groups); + const ItemGroupList &getArmorGroups() const; + void setAnimation(v2f frame_range, float frame_speed, float frame_blend, bool frame_loop); + void getAnimation(v2f *frame_range, float *frame_speed, float *frame_blend, bool *frame_loop); + void setAnimationSpeed(float frame_speed); + void setBonePosition(const std::string &bone, v3f position, v3f rotation); + void getBonePosition(const std::string &bone, v3f *position, v3f *rotation); + void setAttachment(int parent_id, const std::string &bone, v3f position, v3f rotation); + void getAttachment(int *parent_id, std::string *bone, v3f *position, + v3f *rotation) const; + void clearChildAttachments(); + void clearParentAttachment(); + void addAttachmentChild(int child_id); + void removeAttachmentChild(int child_id); + const std::unordered_set &getAttachmentChildIds() const; + ServerActiveObject *getParent() const; + ObjectProperties* accessObjectProperties(); + void notifyObjectPropertiesModified(); + + std::string generateUpdateAttachmentCommand() const; + std::string generateUpdateAnimationSpeedCommand() const; + std::string generateUpdateAnimationCommand() const; + std::string generateUpdateArmorGroupsCommand() const; + static std::string generateUpdatePositionCommand(const v3f &position, const v3f &velocity, + const v3f &acceleration, const v3f &rotation, bool do_interpolate, + bool is_movement_end, f32 update_interval); + std::string generateSetPropertiesCommand(const ObjectProperties &prop) const; + void sendPunchCommand(); + static std::string generateUpdateBonePositionCommand(const std::string &bone, + const v3f &position, const v3f &rotation); + +protected: + u16 m_hp = 1; + + v3f m_rotation; + + bool m_properties_sent = true; + ObjectProperties m_prop; + + ItemGroupList m_armor_groups; + bool m_armor_groups_sent = false; + + v2f m_animation_range; + float m_animation_speed = 0.0f; + float m_animation_blend = 0.0f; + bool m_animation_loop = true; + bool m_animation_sent = false; + bool m_animation_speed_sent = false; + + // Stores position and rotation for each bone name + std::unordered_map> m_bone_position; + bool m_bone_position_sent = false; + + int m_attachment_parent_id = 0; + std::unordered_set m_attachment_child_ids; + std::string m_attachment_bone = ""; + v3f m_attachment_position; + v3f m_attachment_rotation; + bool m_attachment_sent = false; +private: + void onAttach(int parent_id); + void onDetach(int parent_id); + + std::string generatePunchCommand(u16 result_hp) const; +}; diff --git a/src/serverobject.cpp b/src/serverobject.cpp deleted file mode 100644 index 119a41b7b..000000000 --- a/src/serverobject.cpp +++ /dev/null @@ -1,114 +0,0 @@ -/* -Minetest -Copyright (C) 2010-2013 celeron55, Perttu Ahola - -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 "serverobject.h" -#include -#include "inventory.h" -#include "constants.h" // BS -#include "log.h" - -ServerActiveObject::ServerActiveObject(ServerEnvironment *env, v3f pos): - ActiveObject(0), - m_env(env), - m_base_position(pos) -{ -} - -ServerActiveObject* ServerActiveObject::create(ActiveObjectType type, - ServerEnvironment *env, u16 id, v3f pos, - const std::string &data) -{ - // Find factory function - std::map::iterator n; - n = m_types.find(type); - if(n == m_types.end()) { - // These are 0.3 entity types, return without error. - if (ACTIVEOBJECT_TYPE_ITEM <= type && type <= ACTIVEOBJECT_TYPE_MOBV2) { - return NULL; - } - - // If factory is not found, just return. - warningstream<<"ServerActiveObject: No factory for type=" - <second; - ServerActiveObject *object = (*f)(env, pos, data); - return object; -} - -void ServerActiveObject::registerType(u16 type, Factory f) -{ - std::map::iterator n; - n = m_types.find(type); - if(n != m_types.end()) - return; - m_types[type] = f; -} - -float ServerActiveObject::getMinimumSavedMovement() -{ - return 2.0*BS; -} - -ItemStack ServerActiveObject::getWieldedItem(ItemStack *selected, ItemStack *hand) const -{ - *selected = ItemStack(); - if (hand) - *hand = ItemStack(); - - return ItemStack(); -} - -bool ServerActiveObject::setWieldedItem(const ItemStack &item) -{ - return false; -} - -std::string ServerActiveObject::generateUpdateInfantCommand(u16 infant_id, u16 protocol_version) -{ - std::ostringstream os(std::ios::binary); - // command - writeU8(os, AO_CMD_SPAWN_INFANT); - // parameters - writeU16(os, infant_id); - writeU8(os, getSendType()); - os << serializeLongString(getClientInitializationData(protocol_version)); - return os.str(); -} - -std::string ServerActiveObject::generateUpdateNametagAttributesCommand(const video::SColor &color) const -{ - std::ostringstream os(std::ios::binary); - // command - writeU8(os, AO_CMD_UPDATE_NAMETAG_ATTRIBUTES); - // parameters - writeU8(os, 1); // version for forward compatibility - writeARGB8(os, color); - return os.str(); -} - -void ServerActiveObject::dumpAOMessagesToQueue(std::queue &queue) -{ - while (!m_messages_out.empty()) { - queue.push(m_messages_out.front()); - m_messages_out.pop(); - } -} \ No newline at end of file diff --git a/src/serverobject.h b/src/serverobject.h deleted file mode 100644 index 2e013a6b6..000000000 --- a/src/serverobject.h +++ /dev/null @@ -1,265 +0,0 @@ -/* -Minetest -Copyright (C) 2010-2013 celeron55, Perttu Ahola - -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 -#include "irrlichttypes_bloated.h" -#include "activeobject.h" -#include "inventorymanager.h" -#include "itemgroup.h" -#include "util/container.h" - -/* - -Some planning -------------- - -* Server environment adds an active object, which gets the id 1 -* The active object list is scanned for each client once in a while, - and it finds out what objects have been added that are not known - by the client yet. This scan is initiated by the Server class and - the result ends up directly to the server. -* A network packet is created with the info and sent to the client. -* Environment converts objects to static data and static data to - objects, based on how close players are to them. - -*/ - -class ServerEnvironment; -struct ItemStack; -struct ToolCapabilities; -struct ObjectProperties; -struct PlayerHPChangeReason; - -class ServerActiveObject : public ActiveObject -{ -public: - /* - NOTE: m_env can be NULL, but step() isn't called if it is. - Prototypes are used that way. - */ - ServerActiveObject(ServerEnvironment *env, v3f pos); - virtual ~ServerActiveObject() = default; - - virtual ActiveObjectType getSendType() const - { return getType(); } - - // Called after id has been set and has been inserted in environment - virtual void addedToEnvironment(u32 dtime_s){}; - // Called before removing from environment - virtual void removingFromEnvironment(){}; - // Returns true if object's deletion is the job of the - // environment - virtual bool environmentDeletes() const - { return true; } - - // Create a certain type of ServerActiveObject - static ServerActiveObject* create(ActiveObjectType type, - ServerEnvironment *env, u16 id, v3f pos, - const std::string &data); - - /* - Some simple getters/setters - */ - v3f getBasePosition() const { return m_base_position; } - void setBasePosition(v3f pos){ m_base_position = pos; } - ServerEnvironment* getEnv(){ return m_env; } - - /* - Some more dynamic interface - */ - - virtual void setPos(const v3f &pos) - { setBasePosition(pos); } - // continuous: if true, object does not stop immediately at pos - virtual void moveTo(v3f pos, bool continuous) - { setBasePosition(pos); } - // If object has moved less than this and data has not changed, - // saving to disk may be omitted - virtual float getMinimumSavedMovement(); - - virtual std::string getDescription(){return "SAO";} - - /* - Step object in time. - Messages added to messages are sent to client over network. - - send_recommended: - True at around 5-10 times a second, same for all objects. - This is used to let objects send most of the data at the - same time so that the data can be combined in a single - packet. - */ - virtual void step(float dtime, bool send_recommended){} - - /* - The return value of this is passed to the client-side object - when it is created - */ - virtual std::string getClientInitializationData(u16 protocol_version) {return "";} - - /* - The return value of this is passed to the server-side object - when it is created (converted from static to active - actually - the data is the static form) - */ - virtual void getStaticData(std::string *result) const - { - assert(isStaticAllowed()); - *result = ""; - } - /* - Return false in here to never save and instead remove object - on unload. getStaticData() will not be called in that case. - */ - virtual bool isStaticAllowed() const - {return true;} - - // Returns tool wear - virtual u16 punch(v3f dir, - const ToolCapabilities *toolcap = nullptr, - ServerActiveObject *puncher = nullptr, - float time_from_last_punch = 1000000.0f) - { return 0; } - virtual void rightClick(ServerActiveObject *clicker) - {} - virtual void setHP(s32 hp, const PlayerHPChangeReason &reason) - {} - virtual u16 getHP() const - { return 0; } - - virtual void setArmorGroups(const ItemGroupList &armor_groups) - {} - virtual const ItemGroupList &getArmorGroups() const - { static ItemGroupList rv; return rv; } - virtual void setPhysicsOverride(float physics_override_speed, float physics_override_jump, float physics_override_gravity) - {} - virtual void setAnimation(v2f frames, float frame_speed, float frame_blend, bool frame_loop) - {} - virtual void getAnimation(v2f *frames, float *frame_speed, float *frame_blend, bool *frame_loop) - {} - virtual void setAnimationSpeed(float frame_speed) - {} - virtual void setBonePosition(const std::string &bone, v3f position, v3f rotation) - {} - virtual void getBonePosition(const std::string &bone, v3f *position, v3f *lotation) - {} - virtual const std::unordered_set &getAttachmentChildIds() const - { static std::unordered_set rv; return rv; } - virtual ServerActiveObject *getParent() const { return nullptr; } - virtual ObjectProperties* accessObjectProperties() - { return NULL; } - virtual void notifyObjectPropertiesModified() - {} - - // Inventory and wielded item - virtual Inventory *getInventory() const - { return NULL; } - virtual InventoryLocation getInventoryLocation() const - { return InventoryLocation(); } - virtual void setInventoryModified() - {} - virtual std::string getWieldList() const - { return ""; } - virtual u16 getWieldIndex() const - { return 0; } - virtual ItemStack getWieldedItem(ItemStack *selected, - ItemStack *hand = nullptr) const; - virtual bool setWieldedItem(const ItemStack &item); - inline void attachParticleSpawner(u32 id) - { - m_attached_particle_spawners.insert(id); - } - inline void detachParticleSpawner(u32 id) - { - m_attached_particle_spawners.erase(id); - } - - std::string generateUpdateInfantCommand(u16 infant_id, u16 protocol_version); - std::string generateUpdateNametagAttributesCommand(const video::SColor &color) const; - - void dumpAOMessagesToQueue(std::queue &queue); - - /* - Number of players which know about this object. Object won't be - deleted until this is 0 to keep the id preserved for the right - object. - */ - u16 m_known_by_count = 0; - - /* - - Whether this object is to be removed when nobody knows about - it anymore. - - Removal is delayed to preserve the id for the time during which - it could be confused to some other object by some client. - - This is usually set to true by the step() method when the object wants - to be deleted but can be set by anything else too. - */ - bool m_pending_removal = false; - - /* - Same purpose as m_pending_removal but for deactivation. - deactvation = save static data in block, remove active object - - If this is set alongside with m_pending_removal, removal takes - priority. - */ - bool m_pending_deactivation = false; - - /* - A getter that unifies the above to answer the question: - "Can the environment still interact with this object?" - */ - inline bool isGone() const - { return m_pending_removal || m_pending_deactivation; } - - /* - Whether the object's static data has been stored to a block - */ - bool m_static_exists = false; - /* - The block from which the object was loaded from, and in which - a copy of the static data resides. - */ - v3s16 m_static_block = v3s16(1337,1337,1337); - -protected: - virtual void onAttach(int parent_id) {} - virtual void onDetach(int parent_id) {} - - // Used for creating objects based on type - typedef ServerActiveObject* (*Factory) - (ServerEnvironment *env, v3f pos, - const std::string &data); - static void registerType(u16 type, Factory f); - - ServerEnvironment *m_env; - v3f m_base_position; - std::unordered_set m_attached_particle_spawners; - - /* - Queue of messages to be sent to the client - */ - std::queue m_messages_out; - -private: - // Used for creating objects based on type - static std::map m_types; -}; diff --git a/util/travis/clang-format-whitelist.txt b/util/travis/clang-format-whitelist.txt index 7b2fd8236..816ec2c59 100644 --- a/util/travis/clang-format-whitelist.txt +++ b/util/travis/clang-format-whitelist.txt @@ -402,16 +402,14 @@ src/script/scripting_server.cpp src/script/scripting_server.h src/serialization.cpp src/serialization.h -src/serveractiveobjectmap.cpp -src/serveractiveobjectmap.h src/server.cpp src/serverenvironment.cpp src/serverenvironment.h src/server.h src/serverlist.cpp src/serverlist.h -src/serverobject.cpp -src/serverobject.h +src/server/serveractiveobject.cpp +src/server/serveractiveobject.h src/settings.cpp src/settings.h src/settings_translation_file.cpp -- cgit v1.2.3 From 5146086a64d5eeb480948d612a008a2ec81455d4 Mon Sep 17 00:00:00 2001 From: Loic Blot Date: Sat, 11 Apr 2020 11:22:15 +0200 Subject: Drop content_sao.{cpp,h} Move LuaEntitySAO to a new dedicated file Drop TestSAO (useless object) Drop the old static startup initialized SAO factory, which was pretty useless. This factory was using a std::map for 2 elements, now just use a simple condition owned by ServerEnvironment, which will be lightweight, that will also drop a one time useful test on each LuaEntitySAO creation. This should reduce server load on massive SAO creation --- build/android/jni/Android.mk | 4 +- src/CMakeLists.txt | 1 - src/clientiface.cpp | 2 +- src/content_sao.cpp | 681 --------------------------------- src/content_sao.h | 101 ----- src/mapgen/mapgen.cpp | 1 - src/mapgen/mapgen_carpathian.cpp | 1 - src/mapgen/mapgen_flat.cpp | 1 - src/mapgen/mapgen_fractal.cpp | 1 - src/mapgen/mapgen_v5.cpp | 1 - src/mapgen/mapgen_v6.cpp | 1 - src/mapgen/mapgen_v7.cpp | 1 - src/script/cpp_api/s_base.cpp | 1 - src/script/lua_api/l_env.cpp | 2 +- src/script/lua_api/l_item.cpp | 1 - src/script/lua_api/l_object.cpp | 2 +- src/server/CMakeLists.txt | 1 + src/server/luaentity_sao.cpp | 581 ++++++++++++++++++++++++++++ src/server/luaentity_sao.h | 93 +++++ src/server/player_sao.h | 83 ++-- src/server/serveractiveobject.cpp | 33 -- src/server/serveractiveobject.h | 10 - src/serverenvironment.cpp | 19 +- src/serverenvironment.h | 2 + src/staticobject.cpp | 2 +- src/unittest/test_player.cpp | 1 - util/travis/clang-format-whitelist.txt | 4 +- 27 files changed, 731 insertions(+), 900 deletions(-) delete mode 100644 src/content_sao.cpp delete mode 100644 src/content_sao.h create mode 100644 src/server/luaentity_sao.cpp create mode 100644 src/server/luaentity_sao.h (limited to 'src/mapgen') diff --git a/build/android/jni/Android.mk b/build/android/jni/Android.mk index 32a16c174..fdbfba9bc 100644 --- a/build/android/jni/Android.mk +++ b/build/android/jni/Android.mk @@ -161,7 +161,6 @@ LOCAL_SRC_FILES := \ jni/src/content/mods.cpp \ jni/src/content_nodemeta.cpp \ jni/src/content/packages.cpp \ - jni/src/content_sao.cpp \ jni/src/content/subgames.cpp \ jni/src/convert_json.cpp \ jni/src/craftdef.cpp \ @@ -258,8 +257,11 @@ LOCAL_SRC_FILES := \ jni/src/server.cpp \ jni/src/serverenvironment.cpp \ jni/src/serverlist.cpp \ + jni/src/server/luaentity_sao.cpp \ jni/src/server/mods.cpp \ + jni/src/server/player_sao.cpp \ jni/src/server/serveractiveobject.cpp \ + jni/src/server/unit_sao.cpp \ jni/src/settings.cpp \ jni/src/staticobject.cpp \ jni/src/tileanimation.cpp \ diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index faa117d41..0ebbd628c 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -375,7 +375,6 @@ set(common_SRCS collision.cpp content_mapnode.cpp content_nodemeta.cpp - content_sao.cpp convert_json.cpp craftdef.cpp debug.cpp diff --git a/src/clientiface.cpp b/src/clientiface.cpp index 17237f73e..4f954342a 100644 --- a/src/clientiface.cpp +++ b/src/clientiface.cpp @@ -19,7 +19,6 @@ with this program; if not, write to the Free Software Foundation, Inc., #include #include "clientiface.h" -#include "content_sao.h" #include "network/connection.h" #include "network/serveropcodes.h" #include "remoteplayer.h" @@ -28,6 +27,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "serverenvironment.h" #include "map.h" #include "emerge.h" +#include "server/luaentity_sao.h" #include "server/player_sao.h" #include "log.h" #include "util/srp.h" diff --git a/src/content_sao.cpp b/src/content_sao.cpp deleted file mode 100644 index 7ec17aa82..000000000 --- a/src/content_sao.cpp +++ /dev/null @@ -1,681 +0,0 @@ -/* -Minetest -Copyright (C) 2010-2013 celeron55, Perttu Ahola - -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 "content_sao.h" -#include "util/serialize.h" -#include "collision.h" -#include "environment.h" -#include "tool.h" // For ToolCapabilities -#include "gamedef.h" -#include "nodedef.h" -#include "remoteplayer.h" -#include "server.h" -#include "scripting_server.h" -#include "server/player_sao.h" -#include "settings.h" -#include -#include - -std::map ServerActiveObject::m_types; - -/* - TestSAO -*/ - -class TestSAO : public ServerActiveObject -{ -public: - TestSAO(ServerEnvironment *env, v3f pos): - ServerActiveObject(env, pos), - m_timer1(0), - m_age(0) - { - ServerActiveObject::registerType(getType(), create); - } - ActiveObjectType getType() const - { return ACTIVEOBJECT_TYPE_TEST; } - - static ServerActiveObject* create(ServerEnvironment *env, v3f pos, - const std::string &data) - { - return new TestSAO(env, pos); - } - - void step(float dtime, bool send_recommended) - { - m_age += dtime; - if(m_age > 10) - { - m_pending_removal = true; - return; - } - - m_base_position.Y += dtime * BS * 2; - if(m_base_position.Y > 8*BS) - m_base_position.Y = 2*BS; - - if (!send_recommended) - return; - - m_timer1 -= dtime; - if(m_timer1 < 0.0) - { - m_timer1 += 0.125; - - std::string data; - - data += itos(0); // 0 = position - data += " "; - data += itos(m_base_position.X); - data += " "; - data += itos(m_base_position.Y); - data += " "; - data += itos(m_base_position.Z); - - ActiveObjectMessage aom(getId(), false, data); - m_messages_out.push(aom); - } - } - - bool getCollisionBox(aabb3f *toset) const { return false; } - - virtual bool getSelectionBox(aabb3f *toset) const { return false; } - - bool collideWithObjects() const { return false; } - -private: - float m_timer1; - float m_age; -}; - -// Prototype (registers item for deserialization) -TestSAO proto_TestSAO(NULL, v3f(0,0,0)); - -/* - LuaEntitySAO -*/ - -// Prototype (registers item for deserialization) -LuaEntitySAO proto_LuaEntitySAO(NULL, v3f(0,0,0), "_prototype", ""); - -LuaEntitySAO::LuaEntitySAO(ServerEnvironment *env, v3f pos, - const std::string &name, const std::string &state): - UnitSAO(env, pos), - m_init_name(name), - m_init_state(state) -{ - // Only register type if no environment supplied - if(env == NULL){ - ServerActiveObject::registerType(getType(), create); - return; - } -} - -LuaEntitySAO::~LuaEntitySAO() -{ - if(m_registered){ - m_env->getScriptIface()->luaentity_Remove(m_id); - } - - for (u32 attached_particle_spawner : m_attached_particle_spawners) { - m_env->deleteParticleSpawner(attached_particle_spawner, false); - } -} - -void LuaEntitySAO::addedToEnvironment(u32 dtime_s) -{ - ServerActiveObject::addedToEnvironment(dtime_s); - - // Create entity from name - m_registered = m_env->getScriptIface()-> - luaentity_Add(m_id, m_init_name.c_str()); - - if(m_registered){ - // Get properties - m_env->getScriptIface()-> - luaentity_GetProperties(m_id, this, &m_prop); - // Initialize HP from properties - m_hp = m_prop.hp_max; - // Activate entity, supplying serialized state - m_env->getScriptIface()-> - luaentity_Activate(m_id, m_init_state, dtime_s); - } else { - m_prop.infotext = m_init_name; - } -} - -ServerActiveObject* LuaEntitySAO::create(ServerEnvironment *env, v3f pos, - const std::string &data) -{ - std::string name; - std::string state; - u16 hp = 1; - v3f velocity; - v3f rotation; - - while (!data.empty()) { // breakable, run for one iteration - std::istringstream is(data, std::ios::binary); - // 'version' does not allow to incrementally extend the parameter list thus - // we need another variable to build on top of 'version=1'. Ugly hack but worksâ„¢ - u8 version2 = 0; - u8 version = readU8(is); - - name = deSerializeString(is); - state = deSerializeLongString(is); - - if (version < 1) - break; - - hp = readU16(is); - velocity = readV3F1000(is); - // yaw must be yaw to be backwards-compatible - rotation.Y = readF1000(is); - - if (is.good()) // EOF for old formats - version2 = readU8(is); - - if (version2 < 1) // PROTOCOL_VERSION < 37 - break; - - // version2 >= 1 - rotation.X = readF1000(is); - rotation.Z = readF1000(is); - - // if (version2 < 2) - // break; - // - break; - } - // create object - infostream << "LuaEntitySAO::create(name=\"" << name << "\" state=\"" - << state << "\")" << std::endl; - LuaEntitySAO *sao = new LuaEntitySAO(env, pos, name, state); - sao->m_hp = hp; - sao->m_velocity = velocity; - sao->m_rotation = rotation; - return sao; -} - -void LuaEntitySAO::step(float dtime, bool send_recommended) -{ - if(!m_properties_sent) - { - m_properties_sent = true; - std::string str = getPropertyPacket(); - // create message and add to list - ActiveObjectMessage aom(getId(), true, str); - m_messages_out.push(aom); - } - - // If attached, check that our parent is still there. If it isn't, detach. - if(m_attachment_parent_id && !isAttached()) - { - m_attachment_parent_id = 0; - m_attachment_bone = ""; - m_attachment_position = v3f(0,0,0); - m_attachment_rotation = v3f(0,0,0); - sendPosition(false, true); - } - - m_last_sent_position_timer += dtime; - - // Each frame, parent position is copied if the object is attached, otherwise it's calculated normally - // If the object gets detached this comes into effect automatically from the last known origin - if(isAttached()) - { - v3f pos = m_env->getActiveObject(m_attachment_parent_id)->getBasePosition(); - m_base_position = pos; - m_velocity = v3f(0,0,0); - m_acceleration = v3f(0,0,0); - } - else - { - if(m_prop.physical){ - aabb3f box = m_prop.collisionbox; - box.MinEdge *= BS; - box.MaxEdge *= BS; - collisionMoveResult moveresult; - f32 pos_max_d = BS*0.25; // Distance per iteration - v3f p_pos = m_base_position; - v3f p_velocity = m_velocity; - v3f p_acceleration = m_acceleration; - moveresult = collisionMoveSimple(m_env, m_env->getGameDef(), - pos_max_d, box, m_prop.stepheight, dtime, - &p_pos, &p_velocity, p_acceleration, - this, m_prop.collideWithObjects); - - // Apply results - m_base_position = p_pos; - m_velocity = p_velocity; - m_acceleration = p_acceleration; - } else { - m_base_position += dtime * m_velocity + 0.5 * dtime - * dtime * m_acceleration; - m_velocity += dtime * m_acceleration; - } - - if (m_prop.automatic_face_movement_dir && - (fabs(m_velocity.Z) > 0.001 || fabs(m_velocity.X) > 0.001)) { - float target_yaw = atan2(m_velocity.Z, m_velocity.X) * 180 / M_PI - + m_prop.automatic_face_movement_dir_offset; - float max_rotation_per_sec = - m_prop.automatic_face_movement_max_rotation_per_sec; - - if (max_rotation_per_sec > 0) { - m_rotation.Y = wrapDegrees_0_360(m_rotation.Y); - wrappedApproachShortest(m_rotation.Y, target_yaw, - dtime * max_rotation_per_sec, 360.f); - } else { - // Negative values of max_rotation_per_sec mean disabled. - m_rotation.Y = target_yaw; - } - } - } - - if(m_registered){ - m_env->getScriptIface()->luaentity_Step(m_id, dtime); - } - - if (!send_recommended) - return; - - if(!isAttached()) - { - // TODO: force send when acceleration changes enough? - float minchange = 0.2*BS; - if(m_last_sent_position_timer > 1.0){ - minchange = 0.01*BS; - } else if(m_last_sent_position_timer > 0.2){ - minchange = 0.05*BS; - } - float move_d = m_base_position.getDistanceFrom(m_last_sent_position); - move_d += m_last_sent_move_precision; - float vel_d = m_velocity.getDistanceFrom(m_last_sent_velocity); - if (move_d > minchange || vel_d > minchange || - std::fabs(m_rotation.X - m_last_sent_rotation.X) > 1.0f || - std::fabs(m_rotation.Y - m_last_sent_rotation.Y) > 1.0f || - std::fabs(m_rotation.Z - m_last_sent_rotation.Z) > 1.0f) { - - sendPosition(true, false); - } - } - - if (!m_armor_groups_sent) { - m_armor_groups_sent = true; - // create message and add to list - m_messages_out.emplace(getId(), true, generateUpdateArmorGroupsCommand()); - } - - if (!m_animation_sent) { - m_animation_sent = true; - std::string str = generateUpdateAnimationCommand(); - // create message and add to list - ActiveObjectMessage aom(getId(), true, str); - m_messages_out.push(aom); - } - - if (!m_animation_speed_sent) { - m_animation_speed_sent = true; - std::string str = generateUpdateAnimationSpeedCommand(); - // create message and add to list - ActiveObjectMessage aom(getId(), true, str); - m_messages_out.push(aom); - } - - if (!m_bone_position_sent) { - m_bone_position_sent = true; - for (std::unordered_map>::const_iterator - ii = m_bone_position.begin(); ii != m_bone_position.end(); ++ii){ - std::string str = generateUpdateBonePositionCommand((*ii).first, - (*ii).second.X, (*ii).second.Y); - // create message and add to list - ActiveObjectMessage aom(getId(), true, str); - m_messages_out.push(aom); - } - } - - if (!m_attachment_sent) { - m_attachment_sent = true; - std::string str = generateUpdateAttachmentCommand(); - // create message and add to list - ActiveObjectMessage aom(getId(), true, str); - m_messages_out.push(aom); - } -} - -std::string LuaEntitySAO::getClientInitializationData(u16 protocol_version) -{ - std::ostringstream os(std::ios::binary); - - // PROTOCOL_VERSION >= 37 - writeU8(os, 1); // version - os << serializeString(""); // name - writeU8(os, 0); // is_player - writeU16(os, getId()); //id - writeV3F32(os, m_base_position); - writeV3F32(os, m_rotation); - writeU16(os, m_hp); - - std::ostringstream msg_os(std::ios::binary); - msg_os << serializeLongString(getPropertyPacket()); // message 1 - msg_os << serializeLongString(generateUpdateArmorGroupsCommand()); // 2 - msg_os << serializeLongString(generateUpdateAnimationCommand()); // 3 - for (std::unordered_map>::const_iterator - ii = m_bone_position.begin(); ii != m_bone_position.end(); ++ii) { - msg_os << serializeLongString(generateUpdateBonePositionCommand((*ii).first, - (*ii).second.X, (*ii).second.Y)); // m_bone_position.size - } - msg_os << serializeLongString(generateUpdateAttachmentCommand()); // 4 - int message_count = 4 + m_bone_position.size(); - for (std::unordered_set::const_iterator ii = m_attachment_child_ids.begin(); - (ii != m_attachment_child_ids.end()); ++ii) { - if (ServerActiveObject *obj = m_env->getActiveObject(*ii)) { - message_count++; - // TODO after a protocol bump: only send the object initialization data - // to older clients (superfluous since this message exists) - msg_os << serializeLongString(obj->generateUpdateInfantCommand(*ii, protocol_version)); - } - } - - msg_os << serializeLongString(generateSetTextureModCommand()); - message_count++; - - writeU8(os, message_count); - os.write(msg_os.str().c_str(), msg_os.str().size()); - - // return result - return os.str(); -} - -void LuaEntitySAO::getStaticData(std::string *result) const -{ - verbosestream<getScriptIface()-> - luaentity_GetStaticdata(m_id); - os<= 37 - - writeF1000(os, m_rotation.X); - writeF1000(os, m_rotation.Z); - - // - - *result = os.str(); -} - -u16 LuaEntitySAO::punch(v3f dir, - const ToolCapabilities *toolcap, - ServerActiveObject *puncher, - float time_from_last_punch) -{ - if (!m_registered) { - // Delete unknown LuaEntities when punched - m_pending_removal = true; - return 0; - } - - FATAL_ERROR_IF(!puncher, "Punch action called without SAO"); - - s32 old_hp = getHP(); - ItemStack selected_item, hand_item; - ItemStack tool_item = puncher->getWieldedItem(&selected_item, &hand_item); - - PunchDamageResult result = getPunchDamage( - m_armor_groups, - toolcap, - &tool_item, - time_from_last_punch); - - bool damage_handled = m_env->getScriptIface()->luaentity_Punch(m_id, puncher, - time_from_last_punch, toolcap, dir, result.did_punch ? result.damage : 0); - - if (!damage_handled) { - 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); - m_pending_removal = true; - } - - actionstream << puncher->getDescription() << " (id=" << puncher->getId() << - ", hp=" << puncher->getHP() << ") punched " << - getDescription() << " (id=" << m_id << ", hp=" << m_hp << - "), damage=" << (old_hp - (s32)getHP()) << - (damage_handled ? " (handled by Lua)" : "") << std::endl; - - // TODO: give Lua control over wear - return result.wear; -} - -void LuaEntitySAO::rightClick(ServerActiveObject *clicker) -{ - if (!m_registered) - return; - - m_env->getScriptIface()->luaentity_Rightclick(m_id, clicker); -} - -void LuaEntitySAO::setPos(const v3f &pos) -{ - if(isAttached()) - return; - m_base_position = pos; - sendPosition(false, true); -} - -void LuaEntitySAO::moveTo(v3f pos, bool continuous) -{ - if(isAttached()) - return; - m_base_position = pos; - if(!continuous) - sendPosition(true, true); -} - -float LuaEntitySAO::getMinimumSavedMovement() -{ - return 0.1 * BS; -} - -std::string LuaEntitySAO::getDescription() -{ - std::ostringstream oss; - oss << "LuaEntitySAO \"" << m_init_name << "\" "; - auto pos = floatToInt(m_base_position, BS); - oss << "at " << PP(pos); - return oss.str(); -} - -void LuaEntitySAO::setHP(s32 hp, const PlayerHPChangeReason &reason) -{ - m_hp = rangelim(hp, 0, U16_MAX); -} - -u16 LuaEntitySAO::getHP() const -{ - return m_hp; -} - -void LuaEntitySAO::setVelocity(v3f velocity) -{ - m_velocity = velocity; -} - -v3f LuaEntitySAO::getVelocity() -{ - return m_velocity; -} - -void LuaEntitySAO::setAcceleration(v3f acceleration) -{ - m_acceleration = acceleration; -} - -v3f LuaEntitySAO::getAcceleration() -{ - return m_acceleration; -} - -void LuaEntitySAO::setTextureMod(const std::string &mod) -{ - m_current_texture_modifier = mod; - // create message and add to list - m_messages_out.emplace(getId(), true, generateSetTextureModCommand()); -} - -std::string LuaEntitySAO::getTextureMod() const -{ - return m_current_texture_modifier; -} - - -std::string LuaEntitySAO::generateSetTextureModCommand() const -{ - std::ostringstream os(std::ios::binary); - // command - writeU8(os, AO_CMD_SET_TEXTURE_MOD); - // parameters - os << serializeString(m_current_texture_modifier); - return os.str(); -} - -std::string LuaEntitySAO::generateSetSpriteCommand(v2s16 p, u16 num_frames, - f32 framelength, bool select_horiz_by_yawpitch) -{ - std::ostringstream os(std::ios::binary); - // command - writeU8(os, AO_CMD_SET_SPRITE); - // parameters - writeV2S16(os, p); - writeU16(os, num_frames); - writeF32(os, framelength); - writeU8(os, select_horiz_by_yawpitch); - return os.str(); -} - -void LuaEntitySAO::setSprite(v2s16 p, int num_frames, float framelength, - bool select_horiz_by_yawpitch) -{ - std::string str = generateSetSpriteCommand( - p, - num_frames, - framelength, - select_horiz_by_yawpitch - ); - // create message and add to list - m_messages_out.emplace(getId(), true, str); -} - -std::string LuaEntitySAO::getName() -{ - return m_init_name; -} - -std::string LuaEntitySAO::getPropertyPacket() -{ - return generateSetPropertiesCommand(m_prop); -} - -void LuaEntitySAO::sendPosition(bool do_interpolate, bool is_movement_end) -{ - // If the object is attached client-side, don't waste bandwidth sending its position to clients - if(isAttached()) - return; - - m_last_sent_move_precision = m_base_position.getDistanceFrom( - m_last_sent_position); - m_last_sent_position_timer = 0; - m_last_sent_position = m_base_position; - m_last_sent_velocity = m_velocity; - //m_last_sent_acceleration = m_acceleration; - m_last_sent_rotation = m_rotation; - - float update_interval = m_env->getSendRecommendedInterval(); - - std::string str = generateUpdatePositionCommand( - m_base_position, - m_velocity, - m_acceleration, - m_rotation, - do_interpolate, - is_movement_end, - update_interval - ); - // create message and add to list - m_messages_out.emplace(getId(), false, str); -} - -bool LuaEntitySAO::getCollisionBox(aabb3f *toset) const -{ - if (m_prop.physical) - { - //update collision box - toset->MinEdge = m_prop.collisionbox.MinEdge * BS; - toset->MaxEdge = m_prop.collisionbox.MaxEdge * BS; - - toset->MinEdge += m_base_position; - toset->MaxEdge += m_base_position; - - return true; - } - - return false; -} - -bool LuaEntitySAO::getSelectionBox(aabb3f *toset) const -{ - if (!m_prop.is_visible || !m_prop.pointable) { - return false; - } - - toset->MinEdge = m_prop.selectionbox.MinEdge * BS; - toset->MaxEdge = m_prop.selectionbox.MaxEdge * BS; - - return true; -} - -bool LuaEntitySAO::collideWithObjects() const -{ - return m_prop.collideWithObjects; -} diff --git a/src/content_sao.h b/src/content_sao.h deleted file mode 100644 index 5387fd108..000000000 --- a/src/content_sao.h +++ /dev/null @@ -1,101 +0,0 @@ -/* -Minetest -Copyright (C) 2010-2013 celeron55, Perttu Ahola - -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 "network/networkprotocol.h" -#include "util/numeric.h" -#include "server/unit_sao.h" -#include "itemgroup.h" -#include "constants.h" - -/* - LuaEntitySAO needs some internals exposed. -*/ - -class LuaEntitySAO : public UnitSAO -{ -public: - LuaEntitySAO(ServerEnvironment *env, v3f pos, - const std::string &name, const std::string &state); - ~LuaEntitySAO(); - ActiveObjectType getType() const - { return ACTIVEOBJECT_TYPE_LUAENTITY; } - ActiveObjectType getSendType() const - { return ACTIVEOBJECT_TYPE_GENERIC; } - virtual void addedToEnvironment(u32 dtime_s); - static ServerActiveObject* create(ServerEnvironment *env, v3f pos, - const std::string &data); - void step(float dtime, bool send_recommended); - std::string getClientInitializationData(u16 protocol_version); - bool isStaticAllowed() const - { return m_prop.static_save; } - void getStaticData(std::string *result) const; - u16 punch(v3f dir, - const ToolCapabilities *toolcap = nullptr, - ServerActiveObject *puncher = nullptr, - float time_from_last_punch = 1000000.0f); - 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; - - /* LuaEntitySAO-specific */ - void setVelocity(v3f velocity); - void addVelocity(v3f velocity) - { - m_velocity += velocity; - } - v3f getVelocity(); - void setAcceleration(v3f acceleration); - v3f getAcceleration(); - - void setTextureMod(const std::string &mod); - std::string getTextureMod() const; - void setSprite(v2s16 p, int num_frames, float framelength, - bool select_horiz_by_yawpitch); - std::string getName(); - bool getCollisionBox(aabb3f *toset) const; - bool getSelectionBox(aabb3f *toset) const; - bool collideWithObjects() const; -private: - std::string getPropertyPacket(); - void sendPosition(bool do_interpolate, bool is_movement_end); - std::string generateSetTextureModCommand() const; - static std::string generateSetSpriteCommand(v2s16 p, u16 num_frames, f32 framelength, - bool select_horiz_by_yawpitch); - - std::string m_init_name; - std::string m_init_state; - bool m_registered = false; - - v3f m_velocity; - v3f m_acceleration; - - v3f m_last_sent_position; - v3f m_last_sent_velocity; - v3f m_last_sent_rotation; - float m_last_sent_position_timer = 0.0f; - float m_last_sent_move_precision = 0.0f; - std::string m_current_texture_modifier = ""; -}; - diff --git a/src/mapgen/mapgen.cpp b/src/mapgen/mapgen.cpp index 6c426ba41..0094608ec 100644 --- a/src/mapgen/mapgen.cpp +++ b/src/mapgen/mapgen.cpp @@ -28,7 +28,6 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "mapblock.h" #include "mapnode.h" #include "map.h" -#include "content_sao.h" #include "nodedef.h" #include "emerge.h" #include "voxelalgorithms.h" diff --git a/src/mapgen/mapgen_carpathian.cpp b/src/mapgen/mapgen_carpathian.cpp index 0dc1d33be..bd7ae5e7c 100644 --- a/src/mapgen/mapgen_carpathian.cpp +++ b/src/mapgen/mapgen_carpathian.cpp @@ -26,7 +26,6 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "mapblock.h" #include "mapnode.h" #include "map.h" -#include "content_sao.h" #include "nodedef.h" #include "voxelalgorithms.h" //#include "profiler.h" // For TimeTaker diff --git a/src/mapgen/mapgen_flat.cpp b/src/mapgen/mapgen_flat.cpp index 879435948..272964b51 100644 --- a/src/mapgen/mapgen_flat.cpp +++ b/src/mapgen/mapgen_flat.cpp @@ -25,7 +25,6 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "mapblock.h" #include "mapnode.h" #include "map.h" -#include "content_sao.h" #include "nodedef.h" #include "voxelalgorithms.h" //#include "profiler.h" // For TimeTaker diff --git a/src/mapgen/mapgen_fractal.cpp b/src/mapgen/mapgen_fractal.cpp index 96febb4f4..97f77d947 100644 --- a/src/mapgen/mapgen_fractal.cpp +++ b/src/mapgen/mapgen_fractal.cpp @@ -26,7 +26,6 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "mapblock.h" #include "mapnode.h" #include "map.h" -#include "content_sao.h" #include "nodedef.h" #include "voxelalgorithms.h" //#include "profiler.h" // For TimeTaker diff --git a/src/mapgen/mapgen_v5.cpp b/src/mapgen/mapgen_v5.cpp index 447fe8c50..3bd7615c4 100644 --- a/src/mapgen/mapgen_v5.cpp +++ b/src/mapgen/mapgen_v5.cpp @@ -25,7 +25,6 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "mapblock.h" #include "mapnode.h" #include "map.h" -#include "content_sao.h" #include "nodedef.h" #include "voxelalgorithms.h" //#include "profiler.h" // For TimeTaker diff --git a/src/mapgen/mapgen_v6.cpp b/src/mapgen/mapgen_v6.cpp index f473f725d..da9ae1428 100644 --- a/src/mapgen/mapgen_v6.cpp +++ b/src/mapgen/mapgen_v6.cpp @@ -27,7 +27,6 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "mapblock.h" #include "mapnode.h" #include "map.h" -#include "content_sao.h" #include "nodedef.h" #include "voxelalgorithms.h" //#include "profiler.h" // For TimeTaker diff --git a/src/mapgen/mapgen_v7.cpp b/src/mapgen/mapgen_v7.cpp index 325c4957a..82556cc4f 100644 --- a/src/mapgen/mapgen_v7.cpp +++ b/src/mapgen/mapgen_v7.cpp @@ -26,7 +26,6 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "mapblock.h" #include "mapnode.h" #include "map.h" -#include "content_sao.h" #include "nodedef.h" #include "voxelalgorithms.h" //#include "profiler.h" // For TimeTaker diff --git a/src/script/cpp_api/s_base.cpp b/src/script/cpp_api/s_base.cpp index 150baf77e..df07206d7 100644 --- a/src/script/cpp_api/s_base.cpp +++ b/src/script/cpp_api/s_base.cpp @@ -43,7 +43,6 @@ extern "C" { #include #include #include "script/common/c_content.h" -#include "content_sao.h" #include diff --git a/src/script/lua_api/l_env.cpp b/src/script/lua_api/l_env.cpp index 438669feb..40e50e64a 100644 --- a/src/script/lua_api/l_env.cpp +++ b/src/script/lua_api/l_env.cpp @@ -33,12 +33,12 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "nodedef.h" #include "daynightratio.h" #include "util/pointedthing.h" -#include "content_sao.h" #include "mapgen/treegen.h" #include "emerge.h" #include "pathfinder.h" #include "face_position_cache.h" #include "remoteplayer.h" +#include "server/luaentity_sao.h" #include "server/player_sao.h" #ifndef SERVER #include "client/client.h" diff --git a/src/script/lua_api/l_item.cpp b/src/script/lua_api/l_item.cpp index ff77cba32..9f12d3ac7 100644 --- a/src/script/lua_api/l_item.cpp +++ b/src/script/lua_api/l_item.cpp @@ -25,7 +25,6 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "itemdef.h" #include "nodedef.h" #include "server.h" -#include "content_sao.h" #include "inventory.h" #include "log.h" diff --git a/src/script/lua_api/l_object.cpp b/src/script/lua_api/l_object.cpp index 95c96235e..fa34260bf 100644 --- a/src/script/lua_api/l_object.cpp +++ b/src/script/lua_api/l_object.cpp @@ -27,11 +27,11 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "common/c_content.h" #include "log.h" #include "tool.h" -#include "content_sao.h" #include "remoteplayer.h" #include "server.h" #include "hud.h" #include "scripting_server.h" +#include "server/luaentity_sao.h" #include "server/player_sao.h" /* diff --git a/src/server/CMakeLists.txt b/src/server/CMakeLists.txt index 26eaed5ac..4d94504f6 100644 --- a/src/server/CMakeLists.txt +++ b/src/server/CMakeLists.txt @@ -1,5 +1,6 @@ set(server_SRCS ${CMAKE_CURRENT_SOURCE_DIR}/activeobjectmgr.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/luaentity_sao.cpp ${CMAKE_CURRENT_SOURCE_DIR}/mods.cpp ${CMAKE_CURRENT_SOURCE_DIR}/player_sao.cpp ${CMAKE_CURRENT_SOURCE_DIR}/serveractiveobject.cpp diff --git a/src/server/luaentity_sao.cpp b/src/server/luaentity_sao.cpp new file mode 100644 index 000000000..125939241 --- /dev/null +++ b/src/server/luaentity_sao.cpp @@ -0,0 +1,581 @@ +/* +Minetest +Copyright (C) 2010-2013 celeron55, Perttu Ahola +Copyright (C) 2013-2020 Minetest core developers & community + +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 "luaentity_sao.h" +#include "collision.h" +#include "constants.h" +#include "player_sao.h" +#include "scripting_server.h" +#include "server.h" +#include "serverenvironment.h" + +LuaEntitySAO::LuaEntitySAO(ServerEnvironment *env, v3f pos, const std::string &data) + : UnitSAO(env, pos) +{ + std::string name; + std::string state; + u16 hp = 1; + v3f velocity; + v3f rotation; + + while (!data.empty()) { // breakable, run for one iteration + std::istringstream is(data, std::ios::binary); + // 'version' does not allow to incrementally extend the parameter list thus + // we need another variable to build on top of 'version=1'. Ugly hack but worksâ„¢ + u8 version2 = 0; + u8 version = readU8(is); + + name = deSerializeString(is); + state = deSerializeLongString(is); + + if (version < 1) + break; + + hp = readU16(is); + velocity = readV3F1000(is); + // yaw must be yaw to be backwards-compatible + rotation.Y = readF1000(is); + + if (is.good()) // EOF for old formats + version2 = readU8(is); + + if (version2 < 1) // PROTOCOL_VERSION < 37 + break; + + // version2 >= 1 + rotation.X = readF1000(is); + rotation.Z = readF1000(is); + + // if (version2 < 2) + // break; + // + break; + } + // create object + infostream << "LuaEntitySAO::create(name=\"" << name << "\" state=\"" + << state << "\")" << std::endl; + + m_init_name = name; + m_init_state = state; + m_hp = hp; + m_velocity = velocity; + m_rotation = rotation; +} + +LuaEntitySAO::~LuaEntitySAO() +{ + if(m_registered){ + m_env->getScriptIface()->luaentity_Remove(m_id); + } + + for (u32 attached_particle_spawner : m_attached_particle_spawners) { + m_env->deleteParticleSpawner(attached_particle_spawner, false); + } +} + +void LuaEntitySAO::addedToEnvironment(u32 dtime_s) +{ + ServerActiveObject::addedToEnvironment(dtime_s); + + // Create entity from name + m_registered = m_env->getScriptIface()-> + luaentity_Add(m_id, m_init_name.c_str()); + + if(m_registered){ + // Get properties + m_env->getScriptIface()-> + luaentity_GetProperties(m_id, this, &m_prop); + // Initialize HP from properties + m_hp = m_prop.hp_max; + // Activate entity, supplying serialized state + m_env->getScriptIface()-> + luaentity_Activate(m_id, m_init_state, dtime_s); + } else { + m_prop.infotext = m_init_name; + } +} + +void LuaEntitySAO::step(float dtime, bool send_recommended) +{ + if(!m_properties_sent) + { + m_properties_sent = true; + std::string str = getPropertyPacket(); + // create message and add to list + ActiveObjectMessage aom(getId(), true, str); + m_messages_out.push(aom); + } + + // If attached, check that our parent is still there. If it isn't, detach. + if(m_attachment_parent_id && !isAttached()) + { + m_attachment_parent_id = 0; + m_attachment_bone = ""; + m_attachment_position = v3f(0,0,0); + m_attachment_rotation = v3f(0,0,0); + sendPosition(false, true); + } + + m_last_sent_position_timer += dtime; + + // Each frame, parent position is copied if the object is attached, otherwise it's calculated normally + // If the object gets detached this comes into effect automatically from the last known origin + if(isAttached()) + { + v3f pos = m_env->getActiveObject(m_attachment_parent_id)->getBasePosition(); + m_base_position = pos; + m_velocity = v3f(0,0,0); + m_acceleration = v3f(0,0,0); + } + else + { + if(m_prop.physical){ + aabb3f box = m_prop.collisionbox; + box.MinEdge *= BS; + box.MaxEdge *= BS; + collisionMoveResult moveresult; + f32 pos_max_d = BS*0.25; // Distance per iteration + v3f p_pos = m_base_position; + v3f p_velocity = m_velocity; + v3f p_acceleration = m_acceleration; + moveresult = collisionMoveSimple(m_env, m_env->getGameDef(), + pos_max_d, box, m_prop.stepheight, dtime, + &p_pos, &p_velocity, p_acceleration, + this, m_prop.collideWithObjects); + + // Apply results + m_base_position = p_pos; + m_velocity = p_velocity; + m_acceleration = p_acceleration; + } else { + m_base_position += dtime * m_velocity + 0.5 * dtime + * dtime * m_acceleration; + m_velocity += dtime * m_acceleration; + } + + if (m_prop.automatic_face_movement_dir && + (fabs(m_velocity.Z) > 0.001 || fabs(m_velocity.X) > 0.001)) { + float target_yaw = atan2(m_velocity.Z, m_velocity.X) * 180 / M_PI + + m_prop.automatic_face_movement_dir_offset; + float max_rotation_per_sec = + m_prop.automatic_face_movement_max_rotation_per_sec; + + if (max_rotation_per_sec > 0) { + m_rotation.Y = wrapDegrees_0_360(m_rotation.Y); + wrappedApproachShortest(m_rotation.Y, target_yaw, + dtime * max_rotation_per_sec, 360.f); + } else { + // Negative values of max_rotation_per_sec mean disabled. + m_rotation.Y = target_yaw; + } + } + } + + if(m_registered){ + m_env->getScriptIface()->luaentity_Step(m_id, dtime); + } + + if (!send_recommended) + return; + + if(!isAttached()) + { + // TODO: force send when acceleration changes enough? + float minchange = 0.2*BS; + if(m_last_sent_position_timer > 1.0){ + minchange = 0.01*BS; + } else if(m_last_sent_position_timer > 0.2){ + minchange = 0.05*BS; + } + float move_d = m_base_position.getDistanceFrom(m_last_sent_position); + move_d += m_last_sent_move_precision; + float vel_d = m_velocity.getDistanceFrom(m_last_sent_velocity); + if (move_d > minchange || vel_d > minchange || + std::fabs(m_rotation.X - m_last_sent_rotation.X) > 1.0f || + std::fabs(m_rotation.Y - m_last_sent_rotation.Y) > 1.0f || + std::fabs(m_rotation.Z - m_last_sent_rotation.Z) > 1.0f) { + + sendPosition(true, false); + } + } + + if (!m_armor_groups_sent) { + m_armor_groups_sent = true; + // create message and add to list + m_messages_out.emplace(getId(), true, generateUpdateArmorGroupsCommand()); + } + + if (!m_animation_sent) { + m_animation_sent = true; + std::string str = generateUpdateAnimationCommand(); + // create message and add to list + ActiveObjectMessage aom(getId(), true, str); + m_messages_out.push(aom); + } + + if (!m_animation_speed_sent) { + m_animation_speed_sent = true; + std::string str = generateUpdateAnimationSpeedCommand(); + // create message and add to list + ActiveObjectMessage aom(getId(), true, str); + m_messages_out.push(aom); + } + + if (!m_bone_position_sent) { + m_bone_position_sent = true; + for (std::unordered_map>::const_iterator + ii = m_bone_position.begin(); ii != m_bone_position.end(); ++ii){ + std::string str = generateUpdateBonePositionCommand((*ii).first, + (*ii).second.X, (*ii).second.Y); + // create message and add to list + ActiveObjectMessage aom(getId(), true, str); + m_messages_out.push(aom); + } + } + + if (!m_attachment_sent) { + m_attachment_sent = true; + std::string str = generateUpdateAttachmentCommand(); + // create message and add to list + ActiveObjectMessage aom(getId(), true, str); + m_messages_out.push(aom); + } +} + +std::string LuaEntitySAO::getClientInitializationData(u16 protocol_version) +{ + std::ostringstream os(std::ios::binary); + + // PROTOCOL_VERSION >= 37 + writeU8(os, 1); // version + os << serializeString(""); // name + writeU8(os, 0); // is_player + writeU16(os, getId()); //id + writeV3F32(os, m_base_position); + writeV3F32(os, m_rotation); + writeU16(os, m_hp); + + std::ostringstream msg_os(std::ios::binary); + msg_os << serializeLongString(getPropertyPacket()); // message 1 + msg_os << serializeLongString(generateUpdateArmorGroupsCommand()); // 2 + msg_os << serializeLongString(generateUpdateAnimationCommand()); // 3 + for (std::unordered_map>::const_iterator + ii = m_bone_position.begin(); ii != m_bone_position.end(); ++ii) { + msg_os << serializeLongString(generateUpdateBonePositionCommand((*ii).first, + (*ii).second.X, (*ii).second.Y)); // m_bone_position.size + } + msg_os << serializeLongString(generateUpdateAttachmentCommand()); // 4 + int message_count = 4 + m_bone_position.size(); + for (std::unordered_set::const_iterator ii = m_attachment_child_ids.begin(); + (ii != m_attachment_child_ids.end()); ++ii) { + if (ServerActiveObject *obj = m_env->getActiveObject(*ii)) { + message_count++; + // TODO after a protocol bump: only send the object initialization data + // to older clients (superfluous since this message exists) + msg_os << serializeLongString(obj->generateUpdateInfantCommand(*ii, protocol_version)); + } + } + + msg_os << serializeLongString(generateSetTextureModCommand()); + message_count++; + + writeU8(os, message_count); + os.write(msg_os.str().c_str(), msg_os.str().size()); + + // return result + return os.str(); +} + +void LuaEntitySAO::getStaticData(std::string *result) const +{ + verbosestream<getScriptIface()-> + luaentity_GetStaticdata(m_id); + os<= 37 + + writeF1000(os, m_rotation.X); + writeF1000(os, m_rotation.Z); + + // + + *result = os.str(); +} + +u16 LuaEntitySAO::punch(v3f dir, + const ToolCapabilities *toolcap, + ServerActiveObject *puncher, + float time_from_last_punch) +{ + if (!m_registered) { + // Delete unknown LuaEntities when punched + m_pending_removal = true; + return 0; + } + + FATAL_ERROR_IF(!puncher, "Punch action called without SAO"); + + s32 old_hp = getHP(); + ItemStack selected_item, hand_item; + ItemStack tool_item = puncher->getWieldedItem(&selected_item, &hand_item); + + PunchDamageResult result = getPunchDamage( + m_armor_groups, + toolcap, + &tool_item, + time_from_last_punch); + + bool damage_handled = m_env->getScriptIface()->luaentity_Punch(m_id, puncher, + time_from_last_punch, toolcap, dir, result.did_punch ? result.damage : 0); + + if (!damage_handled) { + 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); + m_pending_removal = true; + } + + actionstream << puncher->getDescription() << " (id=" << puncher->getId() << + ", hp=" << puncher->getHP() << ") punched " << + getDescription() << " (id=" << m_id << ", hp=" << m_hp << + "), damage=" << (old_hp - (s32)getHP()) << + (damage_handled ? " (handled by Lua)" : "") << std::endl; + + // TODO: give Lua control over wear + return result.wear; +} + +void LuaEntitySAO::rightClick(ServerActiveObject *clicker) +{ + if (!m_registered) + return; + + m_env->getScriptIface()->luaentity_Rightclick(m_id, clicker); +} + +void LuaEntitySAO::setPos(const v3f &pos) +{ + if(isAttached()) + return; + m_base_position = pos; + sendPosition(false, true); +} + +void LuaEntitySAO::moveTo(v3f pos, bool continuous) +{ + if(isAttached()) + return; + m_base_position = pos; + if(!continuous) + sendPosition(true, true); +} + +float LuaEntitySAO::getMinimumSavedMovement() +{ + return 0.1 * BS; +} + +std::string LuaEntitySAO::getDescription() +{ + std::ostringstream oss; + oss << "LuaEntitySAO \"" << m_init_name << "\" "; + auto pos = floatToInt(m_base_position, BS); + oss << "at " << PP(pos); + return oss.str(); +} + +void LuaEntitySAO::setHP(s32 hp, const PlayerHPChangeReason &reason) +{ + m_hp = rangelim(hp, 0, U16_MAX); +} + +u16 LuaEntitySAO::getHP() const +{ + return m_hp; +} + +void LuaEntitySAO::setVelocity(v3f velocity) +{ + m_velocity = velocity; +} + +v3f LuaEntitySAO::getVelocity() +{ + return m_velocity; +} + +void LuaEntitySAO::setAcceleration(v3f acceleration) +{ + m_acceleration = acceleration; +} + +v3f LuaEntitySAO::getAcceleration() +{ + return m_acceleration; +} + +void LuaEntitySAO::setTextureMod(const std::string &mod) +{ + m_current_texture_modifier = mod; + // create message and add to list + m_messages_out.emplace(getId(), true, generateSetTextureModCommand()); +} + +std::string LuaEntitySAO::getTextureMod() const +{ + return m_current_texture_modifier; +} + + +std::string LuaEntitySAO::generateSetTextureModCommand() const +{ + std::ostringstream os(std::ios::binary); + // command + writeU8(os, AO_CMD_SET_TEXTURE_MOD); + // parameters + os << serializeString(m_current_texture_modifier); + return os.str(); +} + +std::string LuaEntitySAO::generateSetSpriteCommand(v2s16 p, u16 num_frames, + f32 framelength, bool select_horiz_by_yawpitch) +{ + std::ostringstream os(std::ios::binary); + // command + writeU8(os, AO_CMD_SET_SPRITE); + // parameters + writeV2S16(os, p); + writeU16(os, num_frames); + writeF32(os, framelength); + writeU8(os, select_horiz_by_yawpitch); + return os.str(); +} + +void LuaEntitySAO::setSprite(v2s16 p, int num_frames, float framelength, + bool select_horiz_by_yawpitch) +{ + std::string str = generateSetSpriteCommand( + p, + num_frames, + framelength, + select_horiz_by_yawpitch + ); + // create message and add to list + m_messages_out.emplace(getId(), true, str); +} + +std::string LuaEntitySAO::getName() +{ + return m_init_name; +} + +std::string LuaEntitySAO::getPropertyPacket() +{ + return generateSetPropertiesCommand(m_prop); +} + +void LuaEntitySAO::sendPosition(bool do_interpolate, bool is_movement_end) +{ + // If the object is attached client-side, don't waste bandwidth sending its position to clients + if(isAttached()) + return; + + m_last_sent_move_precision = m_base_position.getDistanceFrom( + m_last_sent_position); + m_last_sent_position_timer = 0; + m_last_sent_position = m_base_position; + m_last_sent_velocity = m_velocity; + //m_last_sent_acceleration = m_acceleration; + m_last_sent_rotation = m_rotation; + + float update_interval = m_env->getSendRecommendedInterval(); + + std::string str = generateUpdatePositionCommand( + m_base_position, + m_velocity, + m_acceleration, + m_rotation, + do_interpolate, + is_movement_end, + update_interval + ); + // create message and add to list + m_messages_out.emplace(getId(), false, str); +} + +bool LuaEntitySAO::getCollisionBox(aabb3f *toset) const +{ + if (m_prop.physical) + { + //update collision box + toset->MinEdge = m_prop.collisionbox.MinEdge * BS; + toset->MaxEdge = m_prop.collisionbox.MaxEdge * BS; + + toset->MinEdge += m_base_position; + toset->MaxEdge += m_base_position; + + return true; + } + + return false; +} + +bool LuaEntitySAO::getSelectionBox(aabb3f *toset) const +{ + if (!m_prop.is_visible || !m_prop.pointable) { + return false; + } + + toset->MinEdge = m_prop.selectionbox.MinEdge * BS; + toset->MaxEdge = m_prop.selectionbox.MaxEdge * BS; + + return true; +} + +bool LuaEntitySAO::collideWithObjects() const +{ + return m_prop.collideWithObjects; +} diff --git a/src/server/luaentity_sao.h b/src/server/luaentity_sao.h new file mode 100644 index 000000000..2520c8f5d --- /dev/null +++ b/src/server/luaentity_sao.h @@ -0,0 +1,93 @@ +/* +Minetest +Copyright (C) 2010-2013 celeron55, Perttu Ahola +Copyright (C) 2013-2020 Minetest core developers & community + +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 "unit_sao.h" + +class LuaEntitySAO : public UnitSAO +{ +public: + LuaEntitySAO() = delete; + // Used by the environment to load SAO + LuaEntitySAO(ServerEnvironment *env, v3f pos, const std::string &data); + // Used by the Lua API + LuaEntitySAO(ServerEnvironment *env, v3f pos, const std::string &name, + const std::string &state) : + UnitSAO(env, pos), + m_init_name(name), m_init_state(state) + { + } + ~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; } + void getStaticData(std::string *result) const; + u16 punch(v3f dir, const ToolCapabilities *toolcap = nullptr, + ServerActiveObject *puncher = nullptr, + float time_from_last_punch = 1000000.0f); + 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; + + /* LuaEntitySAO-specific */ + void setVelocity(v3f velocity); + void addVelocity(v3f velocity) { m_velocity += velocity; } + v3f getVelocity(); + void setAcceleration(v3f acceleration); + v3f getAcceleration(); + + void setTextureMod(const std::string &mod); + std::string getTextureMod() const; + void setSprite(v2s16 p, int num_frames, float framelength, + bool select_horiz_by_yawpitch); + std::string getName(); + bool getCollisionBox(aabb3f *toset) const; + bool getSelectionBox(aabb3f *toset) const; + bool collideWithObjects() const; + +private: + std::string getPropertyPacket(); + void sendPosition(bool do_interpolate, bool is_movement_end); + std::string generateSetTextureModCommand() const; + static std::string generateSetSpriteCommand(v2s16 p, u16 num_frames, + f32 framelength, bool select_horiz_by_yawpitch); + + std::string m_init_name; + std::string m_init_state; + bool m_registered = false; + + v3f m_velocity; + v3f m_acceleration; + + v3f m_last_sent_position; + v3f m_last_sent_velocity; + v3f m_last_sent_rotation; + float m_last_sent_position_timer = 0.0f; + float m_last_sent_move_precision = 0.0f; + std::string m_current_texture_modifier = ""; +}; diff --git a/src/server/player_sao.h b/src/server/player_sao.h index ce1cb1677..8571bd4f9 100644 --- a/src/server/player_sao.h +++ b/src/server/player_sao.h @@ -1,4 +1,3 @@ - /* Minetest Copyright (C) 2010-2013 celeron55, Perttu Ahola @@ -19,6 +18,8 @@ with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ +#pragma once + #include "constants.h" #include "network/networkprotocol.h" #include "unit_sao.h" @@ -32,33 +33,31 @@ class LagPool { float m_pool = 15.0f; float m_max = 15.0f; + public: LagPool() = default; void setMax(float new_max) { m_max = new_max; - if(m_pool > new_max) + if (m_pool > new_max) m_pool = new_max; } void add(float dtime) { m_pool -= dtime; - if(m_pool < 0) + if (m_pool < 0) m_pool = 0; } - void empty() - { - m_pool = m_max; - } + void empty() { m_pool = m_max; } bool grab(float dtime) { - if(dtime <= 0) + if (dtime <= 0) return true; - if(m_pool + dtime > m_max) + if (m_pool + dtime > m_max) return false; m_pool += dtime; return true; @@ -73,10 +72,8 @@ public: PlayerSAO(ServerEnvironment *env_, RemotePlayer *player_, session_t peer_id_, bool is_singleplayer); - ActiveObjectType getType() const - { return ACTIVEOBJECT_TYPE_PLAYER; } - ActiveObjectType getSendType() const - { return ACTIVEOBJECT_TYPE_GENERIC; } + ActiveObjectType getType() const { return ACTIVEOBJECT_TYPE_PLAYER; } + ActiveObjectType getSendType() const { return ACTIVEOBJECT_TYPE_GENERIC; } std::string getDescription(); /* @@ -111,10 +108,8 @@ public: Interaction interface */ - u16 punch(v3f dir, - const ToolCapabilities *toolcap, - ServerActiveObject *puncher, - float time_from_last_punch); + u16 punch(v3f dir, const ToolCapabilities *toolcap, ServerActiveObject *puncher, + float time_from_last_punch); void rightClick(ServerActiveObject *clicker) {} void setHP(s32 hp, const PlayerHPChangeReason &reason); void setHPRaw(u16 hp) { m_hp = hp; } @@ -144,10 +139,7 @@ public: // Cheat prevention - v3f getLastGoodPosition() const - { - return m_last_good_position; - } + v3f getLastGoodPosition() const { return m_last_good_position; } float resetTimeFromLastPunch() { float r = m_time_from_last_punch; @@ -159,30 +151,17 @@ public: m_nocheat_dig_pos = p; m_nocheat_dig_time = 0; } - v3s16 getNoCheatDigPos() - { - return m_nocheat_dig_pos; - } - float getNoCheatDigTime() - { - return m_nocheat_dig_time; - } - void noCheatDigEnd() - { - m_nocheat_dig_pos = v3s16(32767, 32767, 32767); - } - LagPool& getDigPool() - { - return m_dig_pool; - } + v3s16 getNoCheatDigPos() { return m_nocheat_dig_pos; } + float getNoCheatDigTime() { return m_nocheat_dig_time; } + void noCheatDigEnd() { m_nocheat_dig_pos = v3s16(32767, 32767, 32767); } + LagPool &getDigPool() { return m_dig_pool; } void setMaxSpeedOverride(const v3f &vel); // Returns true if cheated bool checkMovementCheat(); // Other - void updatePrivileges(const std::set &privs, - bool is_singleplayer) + void updatePrivileges(const std::set &privs, bool is_singleplayer) { m_privs = privs; m_is_singleplayer = is_singleplayer; @@ -236,6 +215,7 @@ private: s16 m_wanted_range = 0.0f; Metadata m_meta; + public: float m_physics_override_speed = 1.0f; float m_physics_override_jump = 1.0f; @@ -246,9 +226,10 @@ public: bool m_physics_override_sent = false; }; - -struct PlayerHPChangeReason { - enum Type : u8 { +struct PlayerHPChangeReason +{ + enum Type : u8 + { SET_HP, PLAYER_PUNCH, FALL, @@ -266,10 +247,7 @@ struct PlayerHPChangeReason { // For NODE_DAMAGE std::string node; - inline bool hasLuaReference() const - { - return lua_reference >= 0; - } + inline bool hasLuaReference() const { return lua_reference >= 0; } bool setTypeFromString(const std::string &typestr) { @@ -311,15 +289,12 @@ struct PlayerHPChangeReason { } } - PlayerHPChangeReason(Type type): - type(type) - {} + PlayerHPChangeReason(Type type) : type(type) {} - PlayerHPChangeReason(Type type, ServerActiveObject *object): + PlayerHPChangeReason(Type type, ServerActiveObject *object) : type(type), object(object) - {} + { + } - PlayerHPChangeReason(Type type, std::string node): - type(type), node(node) - {} + PlayerHPChangeReason(Type type, std::string node) : type(type), node(node) {} }; diff --git a/src/server/serveractiveobject.cpp b/src/server/serveractiveobject.cpp index 3aa78c7d5..8345ebd47 100644 --- a/src/server/serveractiveobject.cpp +++ b/src/server/serveractiveobject.cpp @@ -30,39 +30,6 @@ ServerActiveObject::ServerActiveObject(ServerEnvironment *env, v3f pos): { } -ServerActiveObject* ServerActiveObject::create(ActiveObjectType type, - ServerEnvironment *env, u16 id, v3f pos, - const std::string &data) -{ - // Find factory function - std::map::iterator n; - n = m_types.find(type); - if(n == m_types.end()) { - // These are 0.3 entity types, return without error. - if (ACTIVEOBJECT_TYPE_ITEM <= type && type <= ACTIVEOBJECT_TYPE_MOBV2) { - return NULL; - } - - // If factory is not found, just return. - warningstream<<"ServerActiveObject: No factory for type=" - <second; - ServerActiveObject *object = (*f)(env, pos, data); - return object; -} - -void ServerActiveObject::registerType(u16 type, Factory f) -{ - std::map::iterator n; - n = m_types.find(type); - if(n != m_types.end()) - return; - m_types[type] = f; -} - float ServerActiveObject::getMinimumSavedMovement() { return 2.0*BS; diff --git a/src/server/serveractiveobject.h b/src/server/serveractiveobject.h index 2e013a6b6..927009aef 100644 --- a/src/server/serveractiveobject.h +++ b/src/server/serveractiveobject.h @@ -244,12 +244,6 @@ protected: virtual void onAttach(int parent_id) {} virtual void onDetach(int parent_id) {} - // Used for creating objects based on type - typedef ServerActiveObject* (*Factory) - (ServerEnvironment *env, v3f pos, - const std::string &data); - static void registerType(u16 type, Factory f); - ServerEnvironment *m_env; v3f m_base_position; std::unordered_set m_attached_particle_spawners; @@ -258,8 +252,4 @@ protected: Queue of messages to be sent to the client */ std::queue m_messages_out; - -private: - // Used for creating objects based on type - static std::map m_types; }; diff --git a/src/serverenvironment.cpp b/src/serverenvironment.cpp index c2ab5c07d..32d10f8c0 100644 --- a/src/serverenvironment.cpp +++ b/src/serverenvironment.cpp @@ -44,6 +44,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #if USE_POSTGRESQL #include "database/database-postgresql.h" #endif +#include "server/luaentity_sao.h" #include "server/player_sao.h" #define LBM_NAME_ALLOWED_CHARS "abcdefghijklmnopqrstuvwxyz0123456789_:" @@ -1778,6 +1779,18 @@ static void print_hexdump(std::ostream &o, const std::string &data) } } +ServerActiveObject* ServerEnvironment::createSAO(ActiveObjectType type, v3f pos, + const std::string &data) +{ + switch (type) { + case ACTIVEOBJECT_TYPE_LUAENTITY: + return new LuaEntitySAO(this, pos, data); + default: + warningstream << "ServerActiveObject: No factory for type=" << type << std::endl; + } + return nullptr; +} + /* Convert stored objects from blocks near the players to active. */ @@ -1811,10 +1824,10 @@ void ServerEnvironment::activateObjects(MapBlock *block, u32 dtime_s) std::vector new_stored; for (const StaticObject &s_obj : block->m_static_objects.m_stored) { // Create an active object from the data - ServerActiveObject *obj = ServerActiveObject::create - ((ActiveObjectType) s_obj.type, this, 0, s_obj.pos, s_obj.data); + ServerActiveObject *obj = createSAO((ActiveObjectType) s_obj.type, s_obj.pos, + s_obj.data); // If couldn't create object, store static data back. - if(obj == NULL) { + if (!obj) { errorstream<<"ServerEnvironment::activateObjects(): " <<"failed to create active object from static object " <<"in block "< m_particle_spawners; std::unordered_map m_particle_spawner_attachments; + + ServerActiveObject* createSAO(ActiveObjectType type, v3f pos, const std::string &data); }; diff --git a/src/staticobject.cpp b/src/staticobject.cpp index bebca12ec..5ccb7baf5 100644 --- a/src/staticobject.cpp +++ b/src/staticobject.cpp @@ -19,7 +19,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "staticobject.h" #include "util/serialize.h" -#include "content_sao.h" +#include "server/serveractiveobject.h" StaticObject::StaticObject(const ServerActiveObject *s_obj, const v3f &pos_): type(s_obj->getType()), diff --git a/src/unittest/test_player.cpp b/src/unittest/test_player.cpp index e2b1cd855..6990b4016 100644 --- a/src/unittest/test_player.cpp +++ b/src/unittest/test_player.cpp @@ -21,7 +21,6 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "exceptions.h" #include "remoteplayer.h" -#include "content_sao.h" #include "server.h" class TestPlayer : public TestBase diff --git a/util/travis/clang-format-whitelist.txt b/util/travis/clang-format-whitelist.txt index 816ec2c59..bb97da7b5 100644 --- a/util/travis/clang-format-whitelist.txt +++ b/util/travis/clang-format-whitelist.txt @@ -118,8 +118,6 @@ src/content_mapblock.h src/content_mapnode.cpp src/content_nodemeta.cpp src/content_nodemeta.h -src/content_sao.cpp -src/content_sao.h src/convert_json.cpp src/convert_json.h src/craftdef.cpp @@ -408,6 +406,8 @@ src/serverenvironment.h src/server.h src/serverlist.cpp src/serverlist.h +src/server/luaentity_sao.cpp +src/server/player_sao.cpp src/server/serveractiveobject.cpp src/server/serveractiveobject.h src/settings.cpp -- cgit v1.2.3 From 5cc06e4748a82acb36310fee89e72f30b2b35a36 Mon Sep 17 00:00:00 2001 From: Loïc Blot Date: Sat, 11 Apr 2020 19:59:43 +0200 Subject: Reduce ServerEnvironment propagation (#9642) ServerEnvironment is a huge class with many accessors. In various places it's not needed Remove it to reduce the ServerEnvironment view. Idea here is to reduce size of some of our objects to transport lightweight managers and permit easier testing Pathfinder is now tied to a generic map, not a ServerMap, it can be ported to client --- src/mapgen/treegen.cpp | 4 +- src/mapgen/treegen.h | 5 +- src/pathfinder.cpp | 102 ++++++++++++++++--------------------- src/pathfinder.h | 17 ++++--- src/script/lua_api/l_env.cpp | 7 +-- src/script/lua_api/l_nodetimer.cpp | 44 +++------------- src/script/lua_api/l_nodetimer.h | 10 ++-- 7 files changed, 71 insertions(+), 118 deletions(-) (limited to 'src/mapgen') diff --git a/src/mapgen/treegen.cpp b/src/mapgen/treegen.cpp index 89bdef73b..d538e15b4 100644 --- a/src/mapgen/treegen.cpp +++ b/src/mapgen/treegen.cpp @@ -25,7 +25,6 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "util/numeric.h" #include "map.h" #include "mapblock.h" -#include "serverenvironment.h" #include "nodedef.h" #include "treegen.h" #include "voxelalgorithms.h" @@ -120,10 +119,9 @@ void make_tree(MMVManip &vmanip, v3s16 p0, bool is_apple_tree, // L-System tree LUA spawner -treegen::error spawn_ltree(ServerEnvironment *env, v3s16 p0, +treegen::error spawn_ltree(ServerMap *map, v3s16 p0, const NodeDefManager *ndef, const TreeDef &tree_definition) { - ServerMap *map = &env->getServerMap(); std::map modified_blocks; MMVManip vmanip(map); v3s16 tree_blockp = getNodeBlockPos(p0); diff --git a/src/mapgen/treegen.h b/src/mapgen/treegen.h index 5ab79f428..447baabb3 100644 --- a/src/mapgen/treegen.h +++ b/src/mapgen/treegen.h @@ -26,8 +26,7 @@ with this program; if not, write to the Free Software Foundation, Inc., class MMVManip; class NodeDefManager; -class ServerEnvironment; - +class ServerMap; namespace treegen { @@ -73,7 +72,7 @@ namespace treegen { treegen::error make_ltree(MMVManip &vmanip, v3s16 p0, const NodeDefManager *ndef, TreeDef tree_definition); // Spawn L-systems tree from LUA - treegen::error spawn_ltree (ServerEnvironment *env, v3s16 p0, + treegen::error spawn_ltree (ServerMap *map, v3s16 p0, const NodeDefManager *ndef, const TreeDef &tree_definition); // L-System tree gen helper functions diff --git a/src/pathfinder.cpp b/src/pathfinder.cpp index 8195bd643..3f0b98c10 100644 --- a/src/pathfinder.cpp +++ b/src/pathfinder.cpp @@ -23,8 +23,7 @@ with this program; if not, write to the Free Software Foundation, Inc., /******************************************************************************/ #include "pathfinder.h" -#include "serverenvironment.h" -#include "server.h" +#include "map.h" #include "nodedef.h" //#define PATHFINDER_DEBUG @@ -180,10 +179,8 @@ private: class Pathfinder { public: - /** - * default constructor - */ - Pathfinder() = default; + Pathfinder() = delete; + Pathfinder(Map *map, const NodeDefManager *ndef) : m_map(map), m_ndef(ndef) {} ~Pathfinder(); @@ -197,8 +194,7 @@ public: * @param max_drop maximum number of blocks a path may drop * @param algo Algorithm to use for finding a path */ - std::vector getPath(ServerEnvironment *env, - v3s16 source, + std::vector getPath(v3s16 source, v3s16 destination, unsigned int searchdistance, unsigned int max_jump, @@ -328,7 +324,9 @@ private: friend class GridNodeContainer; GridNodeContainer *m_nodes_container = nullptr; - ServerEnvironment *m_env = 0; /**< minetest environment pointer */ + Map *m_map = nullptr; + + const NodeDefManager *m_ndef = nullptr; friend class PathfinderCompareHeuristic; @@ -410,18 +408,15 @@ class PathfinderCompareHeuristic /* implementation */ /******************************************************************************/ -std::vector get_path(ServerEnvironment* env, - v3s16 source, - v3s16 destination, - unsigned int searchdistance, - unsigned int max_jump, - unsigned int max_drop, - PathAlgorithm algo) +std::vector get_path(Map* map, const NodeDefManager *ndef, + v3s16 source, + v3s16 destination, + unsigned int searchdistance, + unsigned int max_jump, + unsigned int max_drop, + PathAlgorithm algo) { - Pathfinder searchclass; - - return searchclass.getPath(env, - source, destination, + return Pathfinder(map, ndef).getPath(source, destination, searchdistance, max_jump, max_drop, algo); } @@ -521,13 +516,13 @@ void PathGridnode::setCost(v3s16 dir, const PathCost &cost) void GridNodeContainer::initNode(v3s16 ipos, PathGridnode *p_node) { - const NodeDefManager *ndef = m_pathf->m_env->getGameDef()->ndef(); + const NodeDefManager *ndef = m_pathf->m_ndef; PathGridnode &elem = *p_node; v3s16 realpos = m_pathf->getRealPos(ipos); - MapNode current = m_pathf->m_env->getMap().getNode(realpos); - MapNode below = m_pathf->m_env->getMap().getNode(realpos + v3s16(0, -1, 0)); + MapNode current = m_pathf->m_map->getNode(realpos); + MapNode below = m_pathf->m_map->getNode(realpos + v3s16(0, -1, 0)); if ((current.param0 == CONTENT_IGNORE) || @@ -610,8 +605,7 @@ PathGridnode &MapGridNodeContainer::access(v3s16 p) /******************************************************************************/ -std::vector Pathfinder::getPath(ServerEnvironment *env, - v3s16 source, +std::vector Pathfinder::getPath(v3s16 source, v3s16 destination, unsigned int searchdistance, unsigned int max_jump, @@ -624,15 +618,8 @@ std::vector Pathfinder::getPath(ServerEnvironment *env, #endif std::vector retval; - //check parameters - if (env == 0) { - ERROR_TARGET << "Missing environment pointer" << std::endl; - return retval; - } - //initialization m_searchdistance = searchdistance; - m_env = env; m_maxjump = max_jump; m_maxdrop = max_drop; m_start = source; @@ -681,15 +668,14 @@ std::vector Pathfinder::getPath(ServerEnvironment *env, #endif //fail if source or destination is walkable - const NodeDefManager *ndef = m_env->getGameDef()->ndef(); - MapNode node_at_pos = m_env->getMap().getNode(destination); - if (ndef->get(node_at_pos).walkable) { + MapNode node_at_pos = m_map->getNode(destination); + if (m_ndef->get(node_at_pos).walkable) { VERBOSE_TARGET << "Destination is walkable. " << "Pos: " << PP(destination) << std::endl; return retval; } - node_at_pos = m_env->getMap().getNode(source); - if (ndef->get(node_at_pos).walkable) { + node_at_pos = m_map->getNode(source); + if (m_ndef->get(node_at_pos).walkable) { VERBOSE_TARGET << "Source is walkable. " << "Pos: " << PP(source) << std::endl; return retval; @@ -843,7 +829,6 @@ v3s16 Pathfinder::getRealPos(v3s16 ipos) /******************************************************************************/ PathCost Pathfinder::calcCost(v3s16 pos, v3s16 dir) { - const NodeDefManager *ndef = m_env->getGameDef()->ndef(); PathCost retval; retval.updated = true; @@ -857,7 +842,7 @@ PathCost Pathfinder::calcCost(v3s16 pos, v3s16 dir) return retval; } - MapNode node_at_pos2 = m_env->getMap().getNode(pos2); + MapNode node_at_pos2 = m_map->getNode(pos2); //did we get information about node? if (node_at_pos2.param0 == CONTENT_IGNORE ) { @@ -866,9 +851,9 @@ PathCost Pathfinder::calcCost(v3s16 pos, v3s16 dir) return retval; } - if (!ndef->get(node_at_pos2).walkable) { + if (!m_ndef->get(node_at_pos2).walkable) { MapNode node_below_pos2 = - m_env->getMap().getNode(pos2 + v3s16(0, -1, 0)); + m_map->getNode(pos2 + v3s16(0, -1, 0)); //did we get information about node? if (node_below_pos2.param0 == CONTENT_IGNORE ) { @@ -878,7 +863,7 @@ PathCost Pathfinder::calcCost(v3s16 pos, v3s16 dir) } //test if the same-height neighbor is suitable - if (ndef->get(node_below_pos2).walkable) { + if (m_ndef->get(node_below_pos2).walkable) { //SUCCESS! retval.valid = true; retval.value = 1; @@ -889,19 +874,19 @@ PathCost Pathfinder::calcCost(v3s16 pos, v3s16 dir) else { //test if we can fall a couple of nodes (m_maxdrop) v3s16 testpos = pos2 + v3s16(0, -1, 0); - MapNode node_at_pos = m_env->getMap().getNode(testpos); + MapNode node_at_pos = m_map->getNode(testpos); while ((node_at_pos.param0 != CONTENT_IGNORE) && - (!ndef->get(node_at_pos).walkable) && + (!m_ndef->get(node_at_pos).walkable) && (testpos.Y > m_limits.MinEdge.Y)) { testpos += v3s16(0, -1, 0); - node_at_pos = m_env->getMap().getNode(testpos); + node_at_pos = m_map->getNode(testpos); } //did we find surface? if ((testpos.Y >= m_limits.MinEdge.Y) && (node_at_pos.param0 != CONTENT_IGNORE) && - (ndef->get(node_at_pos).walkable)) { + (m_ndef->get(node_at_pos).walkable)) { if ((pos2.Y - testpos.Y - 1) <= m_maxdrop) { //SUCCESS! retval.valid = true; @@ -927,34 +912,34 @@ PathCost Pathfinder::calcCost(v3s16 pos, v3s16 dir) v3s16 targetpos = pos2; // position for jump target v3s16 jumppos = pos; // position for checking if jumping space is free - MapNode node_target = m_env->getMap().getNode(targetpos); - MapNode node_jump = m_env->getMap().getNode(jumppos); + MapNode node_target = m_map->getNode(targetpos); + MapNode node_jump = m_map->getNode(jumppos); bool headbanger = false; // true if anything blocks jumppath while ((node_target.param0 != CONTENT_IGNORE) && - (ndef->get(node_target).walkable) && + (m_ndef->get(node_target).walkable) && (targetpos.Y < m_limits.MaxEdge.Y)) { //if the jump would hit any solid node, discard if ((node_jump.param0 == CONTENT_IGNORE) || - (ndef->get(node_jump).walkable)) { + (m_ndef->get(node_jump).walkable)) { headbanger = true; break; } targetpos += v3s16(0, 1, 0); jumppos += v3s16(0, 1, 0); - node_target = m_env->getMap().getNode(targetpos); - node_jump = m_env->getMap().getNode(jumppos); + node_target = m_map->getNode(targetpos); + node_jump = m_map->getNode(jumppos); } //check headbanger one last time if ((node_jump.param0 == CONTENT_IGNORE) || - (ndef->get(node_jump).walkable)) { + (m_ndef->get(node_jump).walkable)) { headbanger = true; } //did we find surface without banging our head? if ((!headbanger) && (targetpos.Y <= m_limits.MaxEdge.Y) && - (!ndef->get(node_target).walkable)) { + (!m_ndef->get(node_target).walkable)) { if (targetpos.Y - pos2.Y <= m_maxjump) { //SUCCESS! @@ -1254,21 +1239,20 @@ v3s16 Pathfinder::walkDownwards(v3s16 pos, unsigned int max_down) { if (max_down == 0) return pos; v3s16 testpos = v3s16(pos); - MapNode node_at_pos = m_env->getMap().getNode(testpos); - const NodeDefManager *ndef = m_env->getGameDef()->ndef(); + MapNode node_at_pos = m_map->getNode(testpos); unsigned int down = 0; while ((node_at_pos.param0 != CONTENT_IGNORE) && - (!ndef->get(node_at_pos).walkable) && + (!m_ndef->get(node_at_pos).walkable) && (testpos.Y > m_limits.MinEdge.Y) && (down <= max_down)) { testpos += v3s16(0, -1, 0); down++; - node_at_pos = m_env->getMap().getNode(testpos); + node_at_pos = m_map->getNode(testpos); } //did we find surface? if ((testpos.Y >= m_limits.MinEdge.Y) && (node_at_pos.param0 != CONTENT_IGNORE) && - (ndef->get(node_at_pos).walkable)) { + (m_ndef->get(node_at_pos).walkable)) { if (down == 0) { pos = testpos; } else if ((down - 1) <= max_down) { diff --git a/src/pathfinder.h b/src/pathfinder.h index 70f3d6bbc..526aa0ee8 100644 --- a/src/pathfinder.h +++ b/src/pathfinder.h @@ -29,7 +29,8 @@ with this program; if not, write to the Free Software Foundation, Inc., /* Forward declarations */ /******************************************************************************/ -class ServerEnvironment; +class NodeDefManager; +class Map; /******************************************************************************/ /* Typedefs and macros */ @@ -54,10 +55,10 @@ typedef enum { /******************************************************************************/ /** c wrapper function to use from scriptapi */ -std::vector get_path(ServerEnvironment *env, - v3s16 source, - v3s16 destination, - unsigned int searchdistance, - unsigned int max_jump, - unsigned int max_drop, - PathAlgorithm algo); +std::vector get_path(Map *map, const NodeDefManager *ndef, + v3s16 source, + v3s16 destination, + unsigned int searchdistance, + unsigned int max_jump, + unsigned int max_drop, + PathAlgorithm algo); diff --git a/src/script/lua_api/l_env.cpp b/src/script/lua_api/l_env.cpp index 40e50e64a..e3afe1862 100644 --- a/src/script/lua_api/l_env.cpp +++ b/src/script/lua_api/l_env.cpp @@ -577,7 +577,7 @@ int ModApiEnvMod::l_get_node_timer(lua_State *L) // Do it v3s16 p = read_v3s16(L, 1); - NodeTimerRef::create(L, p, env); + NodeTimerRef::create(L, p, &env->getServerMap()); return 1; } @@ -1193,7 +1193,7 @@ int ModApiEnvMod::l_find_path(lua_State *L) algo = PA_DIJKSTRA; } - std::vector path = get_path(env, pos1, pos2, + std::vector path = get_path(&env->getServerMap(), env->getGameDef()->ndef(), pos1, pos2, searchdistance, max_jump, max_drop, algo); if (!path.empty()) { @@ -1257,8 +1257,9 @@ int ModApiEnvMod::l_spawn_tree(lua_State *L) else return 0; + ServerMap *map = &env->getServerMap(); treegen::error e; - if ((e = treegen::spawn_ltree (env, p0, ndef, tree_def)) != treegen::SUCCESS) { + if ((e = treegen::spawn_ltree (map, p0, ndef, tree_def)) != treegen::SUCCESS) { if (e == treegen::UNBALANCED_BRACKETS) { luaL_error(L, "spawn_tree(): closing ']' has no matching opening bracket"); } else { diff --git a/src/script/lua_api/l_nodetimer.cpp b/src/script/lua_api/l_nodetimer.cpp index 15a59744f..c2df52c05 100644 --- a/src/script/lua_api/l_nodetimer.cpp +++ b/src/script/lua_api/l_nodetimer.cpp @@ -41,11 +41,9 @@ int NodeTimerRef::l_set(lua_State *L) { MAP_LOCK_REQUIRED; NodeTimerRef *o = checkobject(L, 1); - ServerEnvironment *env = o->m_env; - if(env == NULL) return 0; f32 t = readParam(L,2); f32 e = readParam(L,3); - env->getMap().setNodeTimer(NodeTimer(t, e, o->m_p)); + o->m_map->setNodeTimer(NodeTimer(t, e, o->m_p)); return 0; } @@ -53,10 +51,8 @@ int NodeTimerRef::l_start(lua_State *L) { MAP_LOCK_REQUIRED; NodeTimerRef *o = checkobject(L, 1); - ServerEnvironment *env = o->m_env; - if(env == NULL) return 0; f32 t = readParam(L,2); - env->getMap().setNodeTimer(NodeTimer(t, 0, o->m_p)); + o->m_map->setNodeTimer(NodeTimer(t, 0, o->m_p)); return 0; } @@ -64,9 +60,7 @@ int NodeTimerRef::l_stop(lua_State *L) { MAP_LOCK_REQUIRED; NodeTimerRef *o = checkobject(L, 1); - ServerEnvironment *env = o->m_env; - if(env == NULL) return 0; - env->getMap().removeNodeTimer(o->m_p); + o->m_map->removeNodeTimer(o->m_p); return 0; } @@ -74,10 +68,7 @@ int NodeTimerRef::l_is_started(lua_State *L) { MAP_LOCK_REQUIRED; NodeTimerRef *o = checkobject(L, 1); - ServerEnvironment *env = o->m_env; - if(env == NULL) return 0; - - NodeTimer t = env->getMap().getNodeTimer(o->m_p); + NodeTimer t = o->m_map->getNodeTimer(o->m_p); lua_pushboolean(L,(t.timeout != 0)); return 1; } @@ -86,10 +77,7 @@ int NodeTimerRef::l_get_timeout(lua_State *L) { MAP_LOCK_REQUIRED; NodeTimerRef *o = checkobject(L, 1); - ServerEnvironment *env = o->m_env; - if(env == NULL) return 0; - - NodeTimer t = env->getMap().getNodeTimer(o->m_p); + NodeTimer t = o->m_map->getNodeTimer(o->m_p); lua_pushnumber(L,t.timeout); return 1; } @@ -98,37 +86,21 @@ int NodeTimerRef::l_get_elapsed(lua_State *L) { MAP_LOCK_REQUIRED; NodeTimerRef *o = checkobject(L, 1); - ServerEnvironment *env = o->m_env; - if(env == NULL) return 0; - - NodeTimer t = env->getMap().getNodeTimer(o->m_p); + NodeTimer t = o->m_map->getNodeTimer(o->m_p); lua_pushnumber(L,t.elapsed); return 1; } - -NodeTimerRef::NodeTimerRef(v3s16 p, ServerEnvironment *env): - m_p(p), - m_env(env) -{ -} - // Creates an NodeTimerRef and leaves it on top of stack // Not callable from Lua; all references are created on the C side. -void NodeTimerRef::create(lua_State *L, v3s16 p, ServerEnvironment *env) +void NodeTimerRef::create(lua_State *L, v3s16 p, ServerMap *map) { - NodeTimerRef *o = new NodeTimerRef(p, env); + NodeTimerRef *o = new NodeTimerRef(p, map); *(void **)(lua_newuserdata(L, sizeof(void *))) = o; luaL_getmetatable(L, className); lua_setmetatable(L, -2); } -void NodeTimerRef::set_null(lua_State *L) -{ - NodeTimerRef *o = checkobject(L, -1); - o->m_env = NULL; -} - void NodeTimerRef::Register(lua_State *L) { lua_newtable(L); diff --git a/src/script/lua_api/l_nodetimer.h b/src/script/lua_api/l_nodetimer.h index b894c5c8c..bbc975fd2 100644 --- a/src/script/lua_api/l_nodetimer.h +++ b/src/script/lua_api/l_nodetimer.h @@ -22,13 +22,13 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "irr_v3d.h" #include "lua_api/l_base.h" -class ServerEnvironment; +class ServerMap; class NodeTimerRef : public ModApiBase { private: v3s16 m_p; - ServerEnvironment *m_env = nullptr; + ServerMap *m_map; static const char className[]; static const luaL_Reg methods[]; @@ -50,14 +50,12 @@ private: static int l_get_elapsed(lua_State *L); public: - NodeTimerRef(v3s16 p, ServerEnvironment *env); + NodeTimerRef(v3s16 p, ServerMap *map) : m_p(p), m_map(map) {} ~NodeTimerRef() = default; // Creates an NodeTimerRef and leaves it on top of stack // Not callable from Lua; all references are created on the C side. - static void create(lua_State *L, v3s16 p, ServerEnvironment *env); - - static void set_null(lua_State *L); + static void create(lua_State *L, v3s16 p, ServerMap *map); static void Register(lua_State *L); }; -- cgit v1.2.3 From 2062c80e21b657fed8e68aa48523fa12ad5ef095 Mon Sep 17 00:00:00 2001 From: sfan5 Date: Thu, 9 Apr 2020 23:40:12 +0200 Subject: Allow ObjDefManager instances to be cloned --- src/mapgen/mg_biome.cpp | 45 ++++++++++++++++++++ src/mapgen/mg_biome.h | 6 +++ src/mapgen/mg_decoration.cpp | 55 +++++++++++++++++++++++++ src/mapgen/mg_decoration.h | 12 ++++++ src/mapgen/mg_ore.cpp | 97 ++++++++++++++++++++++++++++++++++++++++++++ src/mapgen/mg_ore.h | 20 +++++++++ src/mapgen/mg_schematic.cpp | 8 +++- src/mapgen/mg_schematic.h | 4 ++ src/nodedef.cpp | 12 ++++++ src/nodedef.h | 3 ++ src/objdef.cpp | 19 +++++++++ src/objdef.h | 18 ++++++++ src/unittest/test_objdef.cpp | 76 ++++++++++++++++++++++++++++++++-- 13 files changed, 370 insertions(+), 5 deletions(-) (limited to 'src/mapgen') diff --git a/src/mapgen/mg_biome.cpp b/src/mapgen/mg_biome.cpp index 345bc8c6a..3a72c43bf 100644 --- a/src/mapgen/mg_biome.cpp +++ b/src/mapgen/mg_biome.cpp @@ -92,6 +92,16 @@ void BiomeManager::clear() } +BiomeManager *BiomeManager::clone() const +{ + auto mgr = new BiomeManager(); + assert(mgr); + ObjDefManager::cloneTo(mgr); + mgr->m_server = m_server; + return mgr; +} + + // For BiomeGen type 'BiomeGenOriginal' float BiomeManager::getHeatAtPosOriginal(v3s16 pos, NoiseParams &np_heat, NoiseParams &np_heat_blend, u64 seed) @@ -321,6 +331,41 @@ Biome *BiomeGenOriginal::calcBiomeFromNoise(float heat, float humidity, v3s16 po //////////////////////////////////////////////////////////////////////////////// +ObjDef *Biome::clone() const +{ + auto obj = new Biome(); + ObjDef::cloneTo(obj); + NodeResolver::cloneTo(obj); + + obj->flags = flags; + + obj->c_top = c_top; + obj->c_filler = c_filler; + obj->c_stone = c_stone; + obj->c_water_top = c_water_top; + obj->c_water = c_water; + obj->c_river_water = c_river_water; + obj->c_riverbed = c_riverbed; + obj->c_dust = c_dust; + obj->c_cave_liquid = c_cave_liquid; + obj->c_dungeon = c_dungeon; + obj->c_dungeon_alt = c_dungeon_alt; + obj->c_dungeon_stair = c_dungeon_stair; + + obj->depth_top = depth_top; + obj->depth_filler = depth_filler; + obj->depth_water_top = depth_water_top; + obj->depth_riverbed = depth_riverbed; + + obj->min_pos = min_pos; + obj->max_pos = max_pos; + obj->heat_point = heat_point; + obj->humidity_point = humidity_point; + obj->vertical_blend = vertical_blend; + + return obj; +} + void Biome::resolveNodeNames() { getIdFromNrBacklog(&c_top, "mapgen_stone", CONTENT_AIR, false); diff --git a/src/mapgen/mg_biome.h b/src/mapgen/mg_biome.h index ee148adbc..6aadc32fa 100644 --- a/src/mapgen/mg_biome.h +++ b/src/mapgen/mg_biome.h @@ -42,6 +42,8 @@ enum BiomeType { class Biome : public ObjDef, public NodeResolver { public: + ObjDef *clone() const; + u32 flags; content_t c_top; @@ -191,6 +193,8 @@ public: BiomeManager(Server *server); virtual ~BiomeManager() = default; + BiomeManager *clone() const; + const char *getObjectTitle() const { return "biome"; @@ -232,6 +236,8 @@ public: Biome *getBiomeFromNoiseOriginal(float heat, float humidity, v3s16 pos); private: + BiomeManager() {}; + Server *m_server; }; diff --git a/src/mapgen/mg_decoration.cpp b/src/mapgen/mg_decoration.cpp index 28dde0209..db9c696ed 100644 --- a/src/mapgen/mg_decoration.cpp +++ b/src/mapgen/mg_decoration.cpp @@ -67,6 +67,13 @@ size_t DecorationManager::placeAllDecos(Mapgen *mg, u32 blockseed, return nplaced; } +DecorationManager *DecorationManager::clone() const +{ + auto mgr = new DecorationManager(); + ObjDefManager::cloneTo(mgr); + return mgr; +} + /////////////////////////////////////////////////////////////////////////////// @@ -269,9 +276,42 @@ size_t Decoration::placeDeco(Mapgen *mg, u32 blockseed, v3s16 nmin, v3s16 nmax) } +void Decoration::cloneTo(Decoration *def) const +{ + ObjDef::cloneTo(def); + def->flags = flags; + def->mapseed = mapseed; + def->c_place_on = c_place_on; + def->sidelen = sidelen; + def->y_min = y_min; + def->y_max = y_max; + def->fill_ratio = fill_ratio; + def->np = np; + def->c_spawnby = c_spawnby; + def->nspawnby = nspawnby; + def->place_offset_y = place_offset_y; + def->biomes = biomes; +} + + /////////////////////////////////////////////////////////////////////////////// +ObjDef *DecoSimple::clone() const +{ + auto def = new DecoSimple(); + Decoration::cloneTo(def); + + def->c_decos = c_decos; + def->deco_height = deco_height; + def->deco_height_max = deco_height_max; + def->deco_param2 = deco_param2; + def->deco_param2_max = deco_param2_max; + + return def; +} + + void DecoSimple::resolveNodeNames() { Decoration::resolveNodeNames(); @@ -351,6 +391,21 @@ size_t DecoSimple::generate(MMVManip *vm, PcgRandom *pr, v3s16 p, bool ceiling) /////////////////////////////////////////////////////////////////////////////// +ObjDef *DecoSchematic::clone() const +{ + auto def = new DecoSchematic(); + Decoration::cloneTo(def); + NodeResolver::cloneTo(def); + + def->rotation = rotation; + /* FIXME: This is not ideal, we only have a pointer to the schematic despite + * not owning it. Optimally this would be a handle. */ + def->schematic = schematic; // not cloned + + return def; +} + + size_t DecoSchematic::generate(MMVManip *vm, PcgRandom *pr, v3s16 p, bool ceiling) { // Schematic could have been unloaded but not the decoration diff --git a/src/mapgen/mg_decoration.h b/src/mapgen/mg_decoration.h index 03fec04fd..af8fcd7bf 100644 --- a/src/mapgen/mg_decoration.h +++ b/src/mapgen/mg_decoration.h @@ -73,11 +73,16 @@ public: s16 place_offset_y = 0; std::unordered_set biomes; + +protected: + void cloneTo(Decoration *def) const; }; class DecoSimple : public Decoration { public: + ObjDef *clone() const; + virtual void resolveNodeNames(); virtual size_t generate(MMVManip *vm, PcgRandom *pr, v3s16 p, bool ceiling); @@ -91,6 +96,8 @@ public: class DecoSchematic : public Decoration { public: + ObjDef *clone() const; + DecoSchematic() = default; virtual size_t generate(MMVManip *vm, PcgRandom *pr, v3s16 p, bool ceiling); @@ -113,6 +120,8 @@ public: DecorationManager(IGameDef *gamedef); virtual ~DecorationManager() = default; + DecorationManager *clone() const; + const char *getObjectTitle() const { return "decoration"; @@ -133,4 +142,7 @@ public: } size_t placeAllDecos(Mapgen *mg, u32 blockseed, v3s16 nmin, v3s16 nmax); + +private: + DecorationManager() {}; }; diff --git a/src/mapgen/mg_ore.cpp b/src/mapgen/mg_ore.cpp index c36249cb9..db647f82b 100644 --- a/src/mapgen/mg_ore.cpp +++ b/src/mapgen/mg_ore.cpp @@ -72,6 +72,14 @@ void OreManager::clear() } +OreManager *OreManager::clone() const +{ + auto mgr = new OreManager(); + ObjDefManager::cloneTo(mgr); + return mgr; +} + + /////////////////////////////////////////////////////////////////////////////// @@ -106,9 +114,37 @@ size_t Ore::placeOre(Mapgen *mg, u32 blockseed, v3s16 nmin, v3s16 nmax) } +void Ore::cloneTo(Ore *def) const +{ + ObjDef::cloneTo(def); + NodeResolver::cloneTo(def); + def->c_ore = c_ore; + def->c_wherein = c_wherein; + def->clust_scarcity = clust_scarcity; + def->clust_num_ores = clust_num_ores; + def->clust_size = clust_size; + def->y_min = y_min; + def->y_max = y_max; + def->ore_param2 = ore_param2; + def->flags = flags; + def->nthresh = nthresh; + def->np = np; + def->noise = nullptr; // cannot be shared! so created on demand + def->biomes = biomes; +} + + /////////////////////////////////////////////////////////////////////////////// +ObjDef *OreScatter::clone() const +{ + auto def = new OreScatter(); + Ore::cloneTo(def); + return def; +} + + void OreScatter::generate(MMVManip *vm, int mapseed, u32 blockseed, v3s16 nmin, v3s16 nmax, u8 *biomemap) { @@ -158,6 +194,19 @@ void OreScatter::generate(MMVManip *vm, int mapseed, u32 blockseed, /////////////////////////////////////////////////////////////////////////////// +ObjDef *OreSheet::clone() const +{ + auto def = new OreSheet(); + Ore::cloneTo(def); + + def->column_height_max = column_height_max; + def->column_height_min = column_height_min; + def->column_midpoint_factor = column_midpoint_factor; + + return def; +} + + void OreSheet::generate(MMVManip *vm, int mapseed, u32 blockseed, v3s16 nmin, v3s16 nmax, u8 *biomemap) { @@ -221,6 +270,20 @@ OrePuff::~OrePuff() } +ObjDef *OrePuff::clone() const +{ + auto def = new OrePuff(); + Ore::cloneTo(def); + + def->np_puff_top = np_puff_top; + def->np_puff_bottom = np_puff_bottom; + def->noise_puff_top = nullptr; // cannot be shared, on-demand + def->noise_puff_bottom = nullptr; + + return def; +} + + void OrePuff::generate(MMVManip *vm, int mapseed, u32 blockseed, v3s16 nmin, v3s16 nmax, u8 *biomemap) { @@ -294,6 +357,14 @@ void OrePuff::generate(MMVManip *vm, int mapseed, u32 blockseed, /////////////////////////////////////////////////////////////////////////////// +ObjDef *OreBlob::clone() const +{ + auto def = new OreBlob(); + Ore::cloneTo(def); + return def; +} + + void OreBlob::generate(MMVManip *vm, int mapseed, u32 blockseed, v3s16 nmin, v3s16 nmax, u8 *biomemap) { @@ -366,6 +437,19 @@ OreVein::~OreVein() } +ObjDef *OreVein::clone() const +{ + auto def = new OreVein(); + Ore::cloneTo(def); + + def->random_factor = random_factor; + def->noise2 = nullptr; // cannot be shared, on-demand + def->sizey_prev = sizey_prev; + + return def; +} + + void OreVein::generate(MMVManip *vm, int mapseed, u32 blockseed, v3s16 nmin, v3s16 nmax, u8 *biomemap) { @@ -434,6 +518,19 @@ OreStratum::~OreStratum() } +ObjDef *OreStratum::clone() const +{ + auto def = new OreStratum(); + Ore::cloneTo(def); + + def->np_stratum_thickness = np_stratum_thickness; + def->noise_stratum_thickness = nullptr; // cannot be shared, on-demand + def->stratum_thickness = stratum_thickness; + + return def; +} + + void OreStratum::generate(MMVManip *vm, int mapseed, u32 blockseed, v3s16 nmin, v3s16 nmax, u8 *biomemap) { diff --git a/src/mapgen/mg_ore.h b/src/mapgen/mg_ore.h index d89360c3c..213bdc964 100644 --- a/src/mapgen/mg_ore.h +++ b/src/mapgen/mg_ore.h @@ -74,12 +74,17 @@ public: size_t placeOre(Mapgen *mg, u32 blockseed, v3s16 nmin, v3s16 nmax); virtual void generate(MMVManip *vm, int mapseed, u32 blockseed, v3s16 nmin, v3s16 nmax, u8 *biomemap) = 0; + +protected: + void cloneTo(Ore *def) const; }; class OreScatter : public Ore { public: static const bool NEEDS_NOISE = false; + ObjDef *clone() const; + virtual void generate(MMVManip *vm, int mapseed, u32 blockseed, v3s16 nmin, v3s16 nmax, u8 *biomemap); }; @@ -88,6 +93,8 @@ class OreSheet : public Ore { public: static const bool NEEDS_NOISE = true; + ObjDef *clone() const; + u16 column_height_min; u16 column_height_max; float column_midpoint_factor; @@ -100,6 +107,8 @@ class OrePuff : public Ore { public: static const bool NEEDS_NOISE = true; + ObjDef *clone() const; + NoiseParams np_puff_top; NoiseParams np_puff_bottom; Noise *noise_puff_top = nullptr; @@ -116,6 +125,8 @@ class OreBlob : public Ore { public: static const bool NEEDS_NOISE = true; + ObjDef *clone() const; + virtual void generate(MMVManip *vm, int mapseed, u32 blockseed, v3s16 nmin, v3s16 nmax, u8 *biomemap); }; @@ -124,6 +135,8 @@ class OreVein : public Ore { public: static const bool NEEDS_NOISE = true; + ObjDef *clone() const; + float random_factor; Noise *noise2 = nullptr; int sizey_prev = 0; @@ -139,6 +152,8 @@ class OreStratum : public Ore { public: static const bool NEEDS_NOISE = false; + ObjDef *clone() const; + NoiseParams np_stratum_thickness; Noise *noise_stratum_thickness = nullptr; u16 stratum_thickness; @@ -155,6 +170,8 @@ public: OreManager(IGameDef *gamedef); virtual ~OreManager() = default; + OreManager *clone() const; + const char *getObjectTitle() const { return "ore"; @@ -183,4 +200,7 @@ public: void clear(); size_t placeAllOres(Mapgen *mg, u32 blockseed, v3s16 nmin, v3s16 nmax); + +private: + OreManager() {}; }; diff --git a/src/mapgen/mg_schematic.cpp b/src/mapgen/mg_schematic.cpp index c1acbfd9d..2e04d30e6 100644 --- a/src/mapgen/mg_schematic.cpp +++ b/src/mapgen/mg_schematic.cpp @@ -77,6 +77,11 @@ Schematic::~Schematic() delete []slice_probs; } +ObjDef *Schematic::clone() const +{ + FATAL_ERROR("not cloneable"); +} + void Schematic::resolveNodeNames() { @@ -93,6 +98,7 @@ void Schematic::resolveNodeNames() void Schematic::blitToVManip(MMVManip *vm, v3s16 p, Rotation rot, bool force_place) { + assert(schemdata && slice_probs); sanity_check(m_ndef != NULL); int xstride = 1; @@ -177,7 +183,7 @@ bool Schematic::placeOnVManip(MMVManip *vm, v3s16 p, u32 flags, Rotation rot, bool force_place) { assert(vm != NULL); - assert(schemdata != NULL); + assert(schemdata && slice_probs); sanity_check(m_ndef != NULL); //// Determine effective rotation and effective schematic dimensions diff --git a/src/mapgen/mg_schematic.h b/src/mapgen/mg_schematic.h index 371b37557..770f74053 100644 --- a/src/mapgen/mg_schematic.h +++ b/src/mapgen/mg_schematic.h @@ -95,6 +95,8 @@ public: Schematic(); virtual ~Schematic(); + ObjDef *clone() const; + virtual void resolveNodeNames(); bool loadSchematicFromFile(const std::string &filename, @@ -128,6 +130,8 @@ public: SchematicManager(Server *server); virtual ~SchematicManager() = default; + // not cloneable + virtual void clear(); const char *getObjectTitle() const diff --git a/src/nodedef.cpp b/src/nodedef.cpp index 37332c3c6..65199830f 100644 --- a/src/nodedef.cpp +++ b/src/nodedef.cpp @@ -1572,6 +1572,18 @@ NodeResolver::~NodeResolver() } +void NodeResolver::cloneTo(NodeResolver *res) const +{ + FATAL_ERROR_IF(!m_resolve_done, "NodeResolver can only be cloned" + " after resolving has completed"); + /* We don't actually do anything significant. Since the node resolving has + * already completed, the class that called us will already have the + * resolved IDs in its data structures (which it copies on its own) */ + res->m_ndef = m_ndef; + res->m_resolve_done = true; +} + + void NodeResolver::nodeResolveInternal() { m_nodenames_idx = 0; diff --git a/src/nodedef.h b/src/nodedef.h index c77d53324..0fce6eab1 100644 --- a/src/nodedef.h +++ b/src/nodedef.h @@ -739,6 +739,9 @@ public: virtual ~NodeResolver(); virtual void resolveNodeNames() = 0; + // required because this class is used as mixin for ObjDef + void cloneTo(NodeResolver *res) const; + bool getIdFromNrBacklog(content_t *result_out, const std::string &node_alt, content_t c_fallback, bool error_on_fallback = true); diff --git a/src/objdef.cpp b/src/objdef.cpp index 08d6844fc..482544d37 100644 --- a/src/objdef.cpp +++ b/src/objdef.cpp @@ -182,3 +182,22 @@ bool ObjDefManager::decodeHandle(ObjDefHandle handle, u32 *index, *uid = get_bits(handle, 24, 7); return true; } + +// Cloning + +void ObjDef::cloneTo(ObjDef *def) const +{ + def->index = index; + def->uid = uid; + def->handle = handle; + def->name = name; +} + +void ObjDefManager::cloneTo(ObjDefManager *mgr) const +{ + mgr->m_ndef = m_ndef; + mgr->m_objects.reserve(m_objects.size()); + for (const auto &obj : m_objects) + mgr->m_objects.push_back(obj->clone()); + mgr->m_objtype = m_objtype; +} diff --git a/src/objdef.h b/src/objdef.h index 9ab3df977..20565029c 100644 --- a/src/objdef.h +++ b/src/objdef.h @@ -45,10 +45,22 @@ class ObjDef { public: virtual ~ObjDef() = default; + // Only implemented by child classes (leafs in class hierarchy) + // Should create new object of its own type, call cloneTo() of parent class + // and copy its own instance variables over + virtual ObjDef *clone() const = 0; + u32 index; u32 uid; ObjDefHandle handle; std::string name; + +protected: + // Only implemented by classes that have children themselves + // by copying the defintion and changing that argument type (!!!) + // Should defer to parent class cloneTo() if applicable and then copy + // over its own properties + void cloneTo(ObjDef *def) const; }; // WARNING: Ownership of ObjDefs is transferred to the ObjDefManager it is @@ -60,6 +72,8 @@ public: virtual ~ObjDefManager(); DISABLE_CLASS_COPY(ObjDefManager); + // T *clone() const; // implemented in child class with correct type + virtual const char *getObjectTitle() const { return "ObjDef"; } virtual void clear(); @@ -88,6 +102,10 @@ public: ObjDefType *type, u32 *uid); protected: + ObjDefManager() {}; + // Helper for child classes to implement clone() + void cloneTo(ObjDefManager *mgr) const; + const NodeDefManager *m_ndef; std::vector m_objects; ObjDefType m_objtype; diff --git a/src/unittest/test_objdef.cpp b/src/unittest/test_objdef.cpp index c2acdcfe7..40f7faa9d 100644 --- a/src/unittest/test_objdef.cpp +++ b/src/unittest/test_objdef.cpp @@ -32,6 +32,7 @@ public: void testHandles(); void testAddGetSetClear(); + void testClone(); }; static TestObjDef g_test_instance; @@ -40,10 +41,42 @@ void TestObjDef::runTests(IGameDef *gamedef) { TEST(testHandles); TEST(testAddGetSetClear); + TEST(testClone); } //////////////////////////////////////////////////////////////////////////////// +/* Minimal implementation of ObjDef and ObjDefManager subclass */ + +class MyObjDef : public ObjDef +{ +public: + ObjDef *clone() const + { + auto def = new MyObjDef(); + ObjDef::cloneTo(def); + def->testvalue = testvalue; + return def; + }; + + u32 testvalue; +}; + +class MyObjDefManager : public ObjDefManager +{ +public: + MyObjDefManager(ObjDefType type) : ObjDefManager(NULL, type){}; + MyObjDefManager *clone() const + { + auto mgr = new MyObjDefManager(); + ObjDefManager::cloneTo(mgr); + return mgr; + }; + +protected: + MyObjDefManager(){}; +}; + void TestObjDef::testHandles() { u32 uid = 0; @@ -69,25 +102,25 @@ void TestObjDef::testAddGetSetClear() UASSERTEQ(ObjDefType, testmgr.getType(), OBJDEF_GENERIC); - obj0 = new ObjDef; + obj0 = new MyObjDef; obj0->name = "foobar"; hObj0 = testmgr.add(obj0); UASSERT(hObj0 != OBJDEF_INVALID_HANDLE); UASSERTEQ(u32, obj0->index, 0); - obj1 = new ObjDef; + obj1 = new MyObjDef; obj1->name = "FooBaz"; hObj1 = testmgr.add(obj1); UASSERT(hObj1 != OBJDEF_INVALID_HANDLE); UASSERTEQ(u32, obj1->index, 1); - obj2 = new ObjDef; + obj2 = new MyObjDef; obj2->name = "asdf"; hObj2 = testmgr.add(obj2); UASSERT(hObj2 != OBJDEF_INVALID_HANDLE); UASSERTEQ(u32, obj2->index, 2); - obj3 = new ObjDef; + obj3 = new MyObjDef; obj3->name = "foobaz"; hObj3 = testmgr.add(obj3); UASSERT(hObj3 == OBJDEF_INVALID_HANDLE); @@ -104,3 +137,38 @@ void TestObjDef::testAddGetSetClear() testmgr.clear(); UASSERTEQ(size_t, testmgr.getNumObjects(), 0); } + +void TestObjDef::testClone() +{ + MyObjDefManager testmgr(OBJDEF_GENERIC); + ObjDefManager *mgrcopy; + MyObjDef *obj, *temp2; + ObjDef *temp1; + ObjDefHandle hObj; + + obj = new MyObjDef; + obj->testvalue = 0xee00ff11; + hObj = testmgr.add(obj); + UASSERT(hObj != OBJDEF_INVALID_HANDLE); + + mgrcopy = testmgr.clone(); + UASSERT(mgrcopy); + UASSERTEQ(ObjDefType, mgrcopy->getType(), testmgr.getType()); + UASSERTEQ(size_t, mgrcopy->getNumObjects(), testmgr.getNumObjects()); + + // 1) check that the same handle is still valid on the copy + temp1 = mgrcopy->get(hObj); + UASSERT(temp1); + UASSERT(temp1 == mgrcopy->getRaw(0)); + // 2) check that the copy has the correct C++ class + temp2 = dynamic_cast(temp1); + UASSERT(temp2); + // 3) check that it was correctly copied + UASSERTEQ(u32, obj->testvalue, temp2->testvalue); + // 4) check that it was copied AT ALL (not the same) + UASSERT(obj != temp2); + + testmgr.clear(); + mgrcopy->clear(); + delete mgrcopy; +} -- cgit v1.2.3 From 3c65d1acec27366d88fc3686d3f820175673e203 Mon Sep 17 00:00:00 2001 From: sfan5 Date: Fri, 10 Apr 2020 02:05:20 +0200 Subject: Give the Mapgen on each EmergeThread its own Biome/Ore/Deco/SchemManager copy --- src/emerge.cpp | 60 ++++++++++++++++++++++++++++++++++++-- src/emerge.h | 48 ++++++++++++++++++++++++++---- src/mapgen/mapgen.cpp | 17 ++++++----- src/mapgen/mapgen.h | 15 +++++----- src/mapgen/mapgen_carpathian.cpp | 2 +- src/mapgen/mapgen_carpathian.h | 2 +- src/mapgen/mapgen_flat.cpp | 2 +- src/mapgen/mapgen_flat.h | 2 +- src/mapgen/mapgen_fractal.cpp | 2 +- src/mapgen/mapgen_fractal.h | 2 +- src/mapgen/mapgen_singlenode.cpp | 2 +- src/mapgen/mapgen_singlenode.h | 2 +- src/mapgen/mapgen_v5.cpp | 2 +- src/mapgen/mapgen_v5.h | 2 +- src/mapgen/mapgen_v6.cpp | 4 ++- src/mapgen/mapgen_v6.h | 4 +-- src/mapgen/mapgen_v7.cpp | 2 +- src/mapgen/mapgen_v7.h | 2 +- src/mapgen/mapgen_valleys.cpp | 2 +- src/mapgen/mapgen_valleys.h | 2 +- src/mapgen/mg_biome.cpp | 8 ++--- src/mapgen/mg_biome.h | 6 ++-- src/mapgen/mg_decoration.cpp | 16 ++++++++-- src/mapgen/mg_decoration.h | 2 ++ src/mapgen/mg_schematic.cpp | 27 +++++++++++++++-- src/mapgen/mg_schematic.h | 4 ++- src/script/lua_api/l_mapgen.cpp | 63 ++++++++++++++++++++++++---------------- 27 files changed, 225 insertions(+), 77 deletions(-) (limited to 'src/mapgen') diff --git a/src/emerge.cpp b/src/emerge.cpp index fe885447c..6e05a45c9 100644 --- a/src/emerge.cpp +++ b/src/emerge.cpp @@ -109,6 +109,28 @@ private: VoxelArea *m_ignorevariable; }; +EmergeParams::~EmergeParams() +{ + infostream << "EmergeParams: destroying " << this << std::endl; + // Delete everything that was cloned on creation of EmergeParams + delete biomemgr; + delete oremgr; + delete decomgr; + delete schemmgr; +} + +EmergeParams::EmergeParams(EmergeManager *parent, const BiomeManager *biomemgr, + const OreManager *oremgr, const DecorationManager *decomgr, + const SchematicManager *schemmgr) : + ndef(parent->ndef), + enable_mapgen_debug_info(parent->enable_mapgen_debug_info), + gen_notify_on(parent->gen_notify_on), + gen_notify_on_deco_ids(&parent->gen_notify_on_deco_ids), + biomemgr(biomemgr->clone()), oremgr(oremgr->clone()), + decomgr(decomgr->clone()), schemmgr(schemmgr->clone()) +{ +} + //// //// EmergeManager //// @@ -182,14 +204,48 @@ EmergeManager::~EmergeManager() } +BiomeManager *EmergeManager::getWritableBiomeManager() +{ + FATAL_ERROR_IF(!m_mapgens.empty(), + "Writable managers can only be returned before mapgen init"); + return biomemgr; +} + +OreManager *EmergeManager::getWritableOreManager() +{ + FATAL_ERROR_IF(!m_mapgens.empty(), + "Writable managers can only be returned before mapgen init"); + return oremgr; +} + +DecorationManager *EmergeManager::getWritableDecorationManager() +{ + FATAL_ERROR_IF(!m_mapgens.empty(), + "Writable managers can only be returned before mapgen init"); + return decomgr; +} + +SchematicManager *EmergeManager::getWritableSchematicManager() +{ + FATAL_ERROR_IF(!m_mapgens.empty(), + "Writable managers can only be returned before mapgen init"); + return schemmgr; +} + + void EmergeManager::initMapgens(MapgenParams *params) { FATAL_ERROR_IF(!m_mapgens.empty(), "Mapgen already initialised."); mgparams = params; - for (u32 i = 0; i != m_threads.size(); i++) - m_mapgens.push_back(Mapgen::createMapgen(params->mgtype, params, this)); + for (u32 i = 0; i != m_threads.size(); i++) { + EmergeParams *p = new EmergeParams( + this, biomemgr, oremgr, decomgr, schemmgr); + infostream << "EmergeManager: Created params " << p + << " for thread " << i << std::endl; + m_mapgens.push_back(Mapgen::createMapgen(params->mgtype, params, p)); + } } diff --git a/src/emerge.h b/src/emerge.h index df849e542..ab9fca2ba 100644 --- a/src/emerge.h +++ b/src/emerge.h @@ -86,6 +86,30 @@ struct BlockEmergeData { EmergeCallbackList callbacks; }; +class EmergeParams { + friend class EmergeManager; +public: + EmergeParams() = delete; + ~EmergeParams(); + DISABLE_CLASS_COPY(EmergeParams); + + const NodeDefManager *ndef; // shared + bool enable_mapgen_debug_info; + + u32 gen_notify_on; + const std::set *gen_notify_on_deco_ids; // shared + + BiomeManager *biomemgr; + OreManager *oremgr; + DecorationManager *decomgr; + SchematicManager *schemmgr; + +private: + EmergeParams(EmergeManager *parent, const BiomeManager *biomemgr, + const OreManager *oremgr, const DecorationManager *decomgr, + const SchematicManager *schemmgr); +}; + class EmergeManager { public: const NodeDefManager *ndef; @@ -106,17 +130,22 @@ public: // Environment is not created until after script initialization. MapSettingsManager *map_settings_mgr; - // Managers of various map generation-related components - BiomeManager *biomemgr; - OreManager *oremgr; - DecorationManager *decomgr; - SchematicManager *schemmgr; - // Methods EmergeManager(Server *server); ~EmergeManager(); DISABLE_CLASS_COPY(EmergeManager); + // no usage restrictions + const BiomeManager *getBiomeManager() const { return biomemgr; } + const OreManager *getOreManager() const { return oremgr; } + const DecorationManager *getDecorationManager() const { return decomgr; } + const SchematicManager *getSchematicManager() const { return schemmgr; } + // only usable before mapgen init + BiomeManager *getWritableBiomeManager(); + OreManager *getWritableOreManager(); + DecorationManager *getWritableDecorationManager(); + SchematicManager *getWritableSchematicManager(); + void initMapgens(MapgenParams *mgparams); void startThreads(); @@ -160,6 +189,13 @@ private: u16 m_qlimit_diskonly; u16 m_qlimit_generate; + // Managers of various map generation-related components + // Note that each Mapgen gets a copy(!) of these to work with + BiomeManager *biomemgr; + OreManager *oremgr; + DecorationManager *decomgr; + SchematicManager *schemmgr; + // Requires m_queue_mutex held EmergeThread *getOptimalThread(); diff --git a/src/mapgen/mapgen.cpp b/src/mapgen/mapgen.cpp index 0094608ec..f57529082 100644 --- a/src/mapgen/mapgen.cpp +++ b/src/mapgen/mapgen.cpp @@ -106,8 +106,8 @@ STATIC_ASSERT( //// Mapgen //// -Mapgen::Mapgen(int mapgenid, MapgenParams *params, EmergeManager *emerge) : - gennotify(emerge->gen_notify_on, &emerge->gen_notify_on_deco_ids) +Mapgen::Mapgen(int mapgenid, MapgenParams *params, EmergeParams *emerge) : + gennotify(emerge->gen_notify_on, emerge->gen_notify_on_deco_ids) { id = mapgenid; water_level = params->water_level; @@ -156,7 +156,7 @@ const char *Mapgen::getMapgenName(MapgenType mgtype) Mapgen *Mapgen::createMapgen(MapgenType mgtype, MapgenParams *params, - EmergeManager *emerge) + EmergeParams *emerge) { switch (mgtype) { case MAPGEN_CARPATHIAN: @@ -585,7 +585,7 @@ void Mapgen::spreadLight(const v3s16 &nmin, const v3s16 &nmax) //// MapgenBasic //// -MapgenBasic::MapgenBasic(int mapgenid, MapgenParams *params, EmergeManager *emerge) +MapgenBasic::MapgenBasic(int mapgenid, MapgenParams *params, EmergeParams *emerge) : Mapgen(mapgenid, params, emerge) { this->m_emerge = emerge; @@ -642,6 +642,8 @@ MapgenBasic::~MapgenBasic() { delete biomegen; delete []heightmap; + + delete m_emerge; // destroying EmergeParams is our responsibility } @@ -974,7 +976,7 @@ void MapgenBasic::generateDungeons(s16 max_stone_y) //// GenerateNotifier::GenerateNotifier(u32 notify_on, - std::set *notify_on_deco_ids) + const std::set *notify_on_deco_ids) { m_notify_on = notify_on; m_notify_on_deco_ids = notify_on_deco_ids; @@ -987,7 +989,8 @@ void GenerateNotifier::setNotifyOn(u32 notify_on) } -void GenerateNotifier::setNotifyOnDecoIds(std::set *notify_on_deco_ids) +void GenerateNotifier::setNotifyOnDecoIds( + const std::set *notify_on_deco_ids) { m_notify_on_deco_ids = notify_on_deco_ids; } @@ -999,7 +1002,7 @@ bool GenerateNotifier::addEvent(GenNotifyType type, v3s16 pos, u32 id) return false; if (type == GENNOTIFY_DECORATION && - m_notify_on_deco_ids->find(id) == m_notify_on_deco_ids->end()) + m_notify_on_deco_ids->find(id) == m_notify_on_deco_ids->cend()) return false; GenNotifyEvent gne; diff --git a/src/mapgen/mapgen.h b/src/mapgen/mapgen.h index dc325c791..7845c5349 100644 --- a/src/mapgen/mapgen.h +++ b/src/mapgen/mapgen.h @@ -51,6 +51,7 @@ class Biome; class BiomeGen; struct BiomeParams; class BiomeManager; +class EmergeParams; class EmergeManager; class MapBlock; class VoxelManipulator; @@ -87,10 +88,10 @@ struct GenNotifyEvent { class GenerateNotifier { public: GenerateNotifier() = default; - GenerateNotifier(u32 notify_on, std::set *notify_on_deco_ids); + GenerateNotifier(u32 notify_on, const std::set *notify_on_deco_ids); void setNotifyOn(u32 notify_on); - void setNotifyOnDecoIds(std::set *notify_on_deco_ids); + void setNotifyOnDecoIds(const std::set *notify_on_deco_ids); bool addEvent(GenNotifyType type, v3s16 pos, u32 id=0); void getEvents(std::map > &event_map); @@ -98,7 +99,7 @@ public: private: u32 m_notify_on = 0; - std::set *m_notify_on_deco_ids; + const std::set *m_notify_on_deco_ids; std::list m_notify_events; }; @@ -176,7 +177,7 @@ public: GenerateNotifier gennotify; Mapgen() = default; - Mapgen(int mapgenid, MapgenParams *params, EmergeManager *emerge); + Mapgen(int mapgenid, MapgenParams *params, EmergeParams *emerge); virtual ~Mapgen() = default; DISABLE_CLASS_COPY(Mapgen); @@ -215,7 +216,7 @@ public: static MapgenType getMapgenType(const std::string &mgname); static const char *getMapgenName(MapgenType mgtype); static Mapgen *createMapgen(MapgenType mgtype, MapgenParams *params, - EmergeManager *emerge); + EmergeParams *emerge); static MapgenParams *createMapgenParams(MapgenType mgtype); static void getMapgenNames(std::vector *mgnames, bool include_hidden); static void setDefaultSettings(Settings *settings); @@ -243,7 +244,7 @@ private: */ class MapgenBasic : public Mapgen { public: - MapgenBasic(int mapgenid, MapgenParams *params, EmergeManager *emerge); + MapgenBasic(int mapgenid, MapgenParams *params, EmergeParams *emerge); virtual ~MapgenBasic(); virtual void generateBiomes(); @@ -254,7 +255,7 @@ public: virtual void generateDungeons(s16 max_stone_y); protected: - EmergeManager *m_emerge; + EmergeParams *m_emerge; BiomeManager *m_bmgr; Noise *noise_filler_depth; diff --git a/src/mapgen/mapgen_carpathian.cpp b/src/mapgen/mapgen_carpathian.cpp index bd7ae5e7c..feb9b428c 100644 --- a/src/mapgen/mapgen_carpathian.cpp +++ b/src/mapgen/mapgen_carpathian.cpp @@ -49,7 +49,7 @@ FlagDesc flagdesc_mapgen_carpathian[] = { /////////////////////////////////////////////////////////////////////////////// -MapgenCarpathian::MapgenCarpathian(MapgenCarpathianParams *params, EmergeManager *emerge) +MapgenCarpathian::MapgenCarpathian(MapgenCarpathianParams *params, EmergeParams *emerge) : MapgenBasic(MAPGEN_CARPATHIAN, params, emerge) { base_level = params->base_level; diff --git a/src/mapgen/mapgen_carpathian.h b/src/mapgen/mapgen_carpathian.h index acd379958..31b2b91d8 100644 --- a/src/mapgen/mapgen_carpathian.h +++ b/src/mapgen/mapgen_carpathian.h @@ -79,7 +79,7 @@ struct MapgenCarpathianParams : public MapgenParams class MapgenCarpathian : public MapgenBasic { public: - MapgenCarpathian(MapgenCarpathianParams *params, EmergeManager *emerge); + MapgenCarpathian(MapgenCarpathianParams *params, EmergeParams *emerge); ~MapgenCarpathian(); virtual MapgenType getType() const { return MAPGEN_CARPATHIAN; } diff --git a/src/mapgen/mapgen_flat.cpp b/src/mapgen/mapgen_flat.cpp index 272964b51..369777ad2 100644 --- a/src/mapgen/mapgen_flat.cpp +++ b/src/mapgen/mapgen_flat.cpp @@ -47,7 +47,7 @@ FlagDesc flagdesc_mapgen_flat[] = { /////////////////////////////////////////////////////////////////////////////////////// -MapgenFlat::MapgenFlat(MapgenFlatParams *params, EmergeManager *emerge) +MapgenFlat::MapgenFlat(MapgenFlatParams *params, EmergeParams *emerge) : MapgenBasic(MAPGEN_FLAT, params, emerge) { spflags = params->spflags; diff --git a/src/mapgen/mapgen_flat.h b/src/mapgen/mapgen_flat.h index c314c7605..4902a802c 100644 --- a/src/mapgen/mapgen_flat.h +++ b/src/mapgen/mapgen_flat.h @@ -64,7 +64,7 @@ struct MapgenFlatParams : public MapgenParams class MapgenFlat : public MapgenBasic { public: - MapgenFlat(MapgenFlatParams *params, EmergeManager *emerge); + MapgenFlat(MapgenFlatParams *params, EmergeParams *emerge); ~MapgenFlat(); virtual MapgenType getType() const { return MAPGEN_FLAT; } diff --git a/src/mapgen/mapgen_fractal.cpp b/src/mapgen/mapgen_fractal.cpp index 97f77d947..cb55bc288 100644 --- a/src/mapgen/mapgen_fractal.cpp +++ b/src/mapgen/mapgen_fractal.cpp @@ -47,7 +47,7 @@ FlagDesc flagdesc_mapgen_fractal[] = { /////////////////////////////////////////////////////////////////////////////////////// -MapgenFractal::MapgenFractal(MapgenFractalParams *params, EmergeManager *emerge) +MapgenFractal::MapgenFractal(MapgenFractalParams *params, EmergeParams *emerge) : MapgenBasic(MAPGEN_FRACTAL, params, emerge) { spflags = params->spflags; diff --git a/src/mapgen/mapgen_fractal.h b/src/mapgen/mapgen_fractal.h index 971dfd822..23af925bc 100644 --- a/src/mapgen/mapgen_fractal.h +++ b/src/mapgen/mapgen_fractal.h @@ -72,7 +72,7 @@ struct MapgenFractalParams : public MapgenParams class MapgenFractal : public MapgenBasic { public: - MapgenFractal(MapgenFractalParams *params, EmergeManager *emerge); + MapgenFractal(MapgenFractalParams *params, EmergeParams *emerge); ~MapgenFractal(); virtual MapgenType getType() const { return MAPGEN_FRACTAL; } diff --git a/src/mapgen/mapgen_singlenode.cpp b/src/mapgen/mapgen_singlenode.cpp index b64524e1c..cade9e7a8 100644 --- a/src/mapgen/mapgen_singlenode.cpp +++ b/src/mapgen/mapgen_singlenode.cpp @@ -29,7 +29,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "emerge.h" -MapgenSinglenode::MapgenSinglenode(MapgenParams *params, EmergeManager *emerge) +MapgenSinglenode::MapgenSinglenode(MapgenParams *params, EmergeParams *emerge) : Mapgen(MAPGEN_SINGLENODE, params, emerge) { const NodeDefManager *ndef = emerge->ndef; diff --git a/src/mapgen/mapgen_singlenode.h b/src/mapgen/mapgen_singlenode.h index c21089eda..e056d9ab1 100644 --- a/src/mapgen/mapgen_singlenode.h +++ b/src/mapgen/mapgen_singlenode.h @@ -38,7 +38,7 @@ public: content_t c_node; u8 set_light; - MapgenSinglenode(MapgenParams *params, EmergeManager *emerge); + MapgenSinglenode(MapgenParams *params, EmergeParams *emerge); ~MapgenSinglenode() = default; virtual MapgenType getType() const { return MAPGEN_SINGLENODE; } diff --git a/src/mapgen/mapgen_v5.cpp b/src/mapgen/mapgen_v5.cpp index 3bd7615c4..124667e5d 100644 --- a/src/mapgen/mapgen_v5.cpp +++ b/src/mapgen/mapgen_v5.cpp @@ -44,7 +44,7 @@ FlagDesc flagdesc_mapgen_v5[] = { }; -MapgenV5::MapgenV5(MapgenV5Params *params, EmergeManager *emerge) +MapgenV5::MapgenV5(MapgenV5Params *params, EmergeParams *emerge) : MapgenBasic(MAPGEN_V5, params, emerge) { spflags = params->spflags; diff --git a/src/mapgen/mapgen_v5.h b/src/mapgen/mapgen_v5.h index 17bc466f0..cf4ee4899 100644 --- a/src/mapgen/mapgen_v5.h +++ b/src/mapgen/mapgen_v5.h @@ -64,7 +64,7 @@ struct MapgenV5Params : public MapgenParams class MapgenV5 : public MapgenBasic { public: - MapgenV5(MapgenV5Params *params, EmergeManager *emerge); + MapgenV5(MapgenV5Params *params, EmergeParams *emerge); ~MapgenV5(); virtual MapgenType getType() const { return MAPGEN_V5; } diff --git a/src/mapgen/mapgen_v6.cpp b/src/mapgen/mapgen_v6.cpp index da9ae1428..e9692246c 100644 --- a/src/mapgen/mapgen_v6.cpp +++ b/src/mapgen/mapgen_v6.cpp @@ -54,7 +54,7 @@ FlagDesc flagdesc_mapgen_v6[] = { ///////////////////////////////////////////////////////////////////////////// -MapgenV6::MapgenV6(MapgenV6Params *params, EmergeManager *emerge) +MapgenV6::MapgenV6(MapgenV6Params *params, EmergeParams *emerge) : Mapgen(MAPGEN_V6, params, emerge) { m_emerge = emerge; @@ -160,6 +160,8 @@ MapgenV6::~MapgenV6() delete noise_humidity; delete[] heightmap; + + delete m_emerge; // our responsibility } diff --git a/src/mapgen/mapgen_v6.h b/src/mapgen/mapgen_v6.h index d8cdcb26f..ff565edec 100644 --- a/src/mapgen/mapgen_v6.h +++ b/src/mapgen/mapgen_v6.h @@ -83,7 +83,7 @@ struct MapgenV6Params : public MapgenParams { class MapgenV6 : public Mapgen { public: - EmergeManager *m_emerge; + EmergeParams *m_emerge; int ystride; u32 spflags; @@ -133,7 +133,7 @@ public: content_t c_stair_cobble; content_t c_stair_desert_stone; - MapgenV6(MapgenV6Params *params, EmergeManager *emerge); + MapgenV6(MapgenV6Params *params, EmergeParams *emerge); ~MapgenV6(); virtual MapgenType getType() const { return MAPGEN_V6; } diff --git a/src/mapgen/mapgen_v7.cpp b/src/mapgen/mapgen_v7.cpp index 82556cc4f..43d5d822f 100644 --- a/src/mapgen/mapgen_v7.cpp +++ b/src/mapgen/mapgen_v7.cpp @@ -51,7 +51,7 @@ FlagDesc flagdesc_mapgen_v7[] = { //////////////////////////////////////////////////////////////////////////////// -MapgenV7::MapgenV7(MapgenV7Params *params, EmergeManager *emerge) +MapgenV7::MapgenV7(MapgenV7Params *params, EmergeParams *emerge) : MapgenBasic(MAPGEN_V7, params, emerge) { spflags = params->spflags; diff --git a/src/mapgen/mapgen_v7.h b/src/mapgen/mapgen_v7.h index 0605c5c97..eeae3a956 100644 --- a/src/mapgen/mapgen_v7.h +++ b/src/mapgen/mapgen_v7.h @@ -75,7 +75,7 @@ struct MapgenV7Params : public MapgenParams { class MapgenV7 : public MapgenBasic { public: - MapgenV7(MapgenV7Params *params, EmergeManager *emerge); + MapgenV7(MapgenV7Params *params, EmergeParams *emerge); ~MapgenV7(); virtual MapgenType getType() const { return MAPGEN_V7; } diff --git a/src/mapgen/mapgen_valleys.cpp b/src/mapgen/mapgen_valleys.cpp index ff908b7bb..efcc8ee85 100644 --- a/src/mapgen/mapgen_valleys.cpp +++ b/src/mapgen/mapgen_valleys.cpp @@ -54,7 +54,7 @@ FlagDesc flagdesc_mapgen_valleys[] = { }; -MapgenValleys::MapgenValleys(MapgenValleysParams *params, EmergeManager *emerge) +MapgenValleys::MapgenValleys(MapgenValleysParams *params, EmergeParams *emerge) : MapgenBasic(MAPGEN_VALLEYS, params, emerge) { // NOTE: MapgenValleys has a hard dependency on BiomeGenOriginal diff --git a/src/mapgen/mapgen_valleys.h b/src/mapgen/mapgen_valleys.h index 1aec68842..34a923dfa 100644 --- a/src/mapgen/mapgen_valleys.h +++ b/src/mapgen/mapgen_valleys.h @@ -84,7 +84,7 @@ class MapgenValleys : public MapgenBasic { public: MapgenValleys(MapgenValleysParams *params, - EmergeManager *emerge); + EmergeParams *emerge); ~MapgenValleys(); virtual MapgenType getType() const { return MAPGEN_VALLEYS; } diff --git a/src/mapgen/mg_biome.cpp b/src/mapgen/mg_biome.cpp index 3a72c43bf..f3bc4e829 100644 --- a/src/mapgen/mg_biome.cpp +++ b/src/mapgen/mg_biome.cpp @@ -78,7 +78,7 @@ void BiomeManager::clear() EmergeManager *emerge = m_server->getEmergeManager(); // Remove all dangling references in Decorations - DecorationManager *decomgr = emerge->decomgr; + DecorationManager *decomgr = emerge->getWritableDecorationManager(); for (size_t i = 0; i != decomgr->getNumObjects(); i++) { Decoration *deco = (Decoration *)decomgr->getRaw(i); deco->biomes.clear(); @@ -104,7 +104,7 @@ BiomeManager *BiomeManager::clone() const // For BiomeGen type 'BiomeGenOriginal' float BiomeManager::getHeatAtPosOriginal(v3s16 pos, NoiseParams &np_heat, - NoiseParams &np_heat_blend, u64 seed) + NoiseParams &np_heat_blend, u64 seed) const { return NoisePerlin2D(&np_heat, pos.X, pos.Z, seed) + @@ -114,7 +114,7 @@ float BiomeManager::getHeatAtPosOriginal(v3s16 pos, NoiseParams &np_heat, // For BiomeGen type 'BiomeGenOriginal' float BiomeManager::getHumidityAtPosOriginal(v3s16 pos, NoiseParams &np_humidity, - NoiseParams &np_humidity_blend, u64 seed) + NoiseParams &np_humidity_blend, u64 seed) const { return NoisePerlin2D(&np_humidity, pos.X, pos.Z, seed) + @@ -123,7 +123,7 @@ float BiomeManager::getHumidityAtPosOriginal(v3s16 pos, NoiseParams &np_humidity // For BiomeGen type 'BiomeGenOriginal' -Biome *BiomeManager::getBiomeFromNoiseOriginal(float heat, float humidity, v3s16 pos) +Biome *BiomeManager::getBiomeFromNoiseOriginal(float heat, float humidity, v3s16 pos) const { Biome *biome_closest = nullptr; Biome *biome_closest_blend = nullptr; diff --git a/src/mapgen/mg_biome.h b/src/mapgen/mg_biome.h index 6aadc32fa..0a4471cc3 100644 --- a/src/mapgen/mg_biome.h +++ b/src/mapgen/mg_biome.h @@ -230,10 +230,10 @@ public: // For BiomeGen type 'BiomeGenOriginal' float getHeatAtPosOriginal(v3s16 pos, NoiseParams &np_heat, - NoiseParams &np_heat_blend, u64 seed); + NoiseParams &np_heat_blend, u64 seed) const; float getHumidityAtPosOriginal(v3s16 pos, NoiseParams &np_humidity, - NoiseParams &np_humidity_blend, u64 seed); - Biome *getBiomeFromNoiseOriginal(float heat, float humidity, v3s16 pos); + NoiseParams &np_humidity_blend, u64 seed) const; + Biome *getBiomeFromNoiseOriginal(float heat, float humidity, v3s16 pos) const; private: BiomeManager() {}; diff --git a/src/mapgen/mg_decoration.cpp b/src/mapgen/mg_decoration.cpp index db9c696ed..a9b67d239 100644 --- a/src/mapgen/mg_decoration.cpp +++ b/src/mapgen/mg_decoration.cpp @@ -391,6 +391,13 @@ size_t DecoSimple::generate(MMVManip *vm, PcgRandom *pr, v3s16 p, bool ceiling) /////////////////////////////////////////////////////////////////////////////// +DecoSchematic::~DecoSchematic() +{ + if (was_cloned) + delete schematic; +} + + ObjDef *DecoSchematic::clone() const { auto def = new DecoSchematic(); @@ -398,9 +405,12 @@ ObjDef *DecoSchematic::clone() const NodeResolver::cloneTo(def); def->rotation = rotation; - /* FIXME: This is not ideal, we only have a pointer to the schematic despite - * not owning it. Optimally this would be a handle. */ - def->schematic = schematic; // not cloned + /* FIXME: We do not own this schematic, yet we only have a pointer to it + * and not a handle. We are left with no option but to clone it ourselves. + * This is a waste of memory and should be replaced with an alternative + * approach sometime. */ + def->schematic = dynamic_cast(schematic->clone()); + def->was_cloned = true; return def; } diff --git a/src/mapgen/mg_decoration.h b/src/mapgen/mg_decoration.h index af8fcd7bf..1f9eb4510 100644 --- a/src/mapgen/mg_decoration.h +++ b/src/mapgen/mg_decoration.h @@ -99,11 +99,13 @@ public: ObjDef *clone() const; DecoSchematic() = default; + virtual ~DecoSchematic(); virtual size_t generate(MMVManip *vm, PcgRandom *pr, v3s16 p, bool ceiling); Rotation rotation; Schematic *schematic = nullptr; + bool was_cloned = false; // see FIXME inside DecoSchemtic::clone() }; diff --git a/src/mapgen/mg_schematic.cpp b/src/mapgen/mg_schematic.cpp index 2e04d30e6..c3bd89f3a 100644 --- a/src/mapgen/mg_schematic.cpp +++ b/src/mapgen/mg_schematic.cpp @@ -43,12 +43,21 @@ SchematicManager::SchematicManager(Server *server) : } +SchematicManager *SchematicManager::clone() const +{ + auto mgr = new SchematicManager(); + assert(mgr); + ObjDefManager::cloneTo(mgr); + return mgr; +} + + void SchematicManager::clear() { EmergeManager *emerge = m_server->getEmergeManager(); // Remove all dangling references in Decorations - DecorationManager *decomgr = emerge->decomgr; + DecorationManager *decomgr = emerge->getWritableDecorationManager(); for (size_t i = 0; i != decomgr->getNumObjects(); i++) { Decoration *deco = (Decoration *)decomgr->getRaw(i); @@ -79,7 +88,21 @@ Schematic::~Schematic() ObjDef *Schematic::clone() const { - FATAL_ERROR("not cloneable"); + auto def = new Schematic(); + ObjDef::cloneTo(def); + NodeResolver::cloneTo(def); + + def->c_nodes = c_nodes; + def->flags = flags; + def->size = size; + FATAL_ERROR_IF(!schemdata, "Schematic can only be cloned after loading"); + u32 nodecount = size.X * size.Y * size.Z; + def->schemdata = new MapNode[nodecount]; + memcpy(def->schemdata, schemdata, sizeof(MapNode) * nodecount); + def->slice_probs = new u8[size.Y]; + memcpy(def->slice_probs, slice_probs, sizeof(u8) * size.Y); + + return def; } diff --git a/src/mapgen/mg_schematic.h b/src/mapgen/mg_schematic.h index 770f74053..3222085e6 100644 --- a/src/mapgen/mg_schematic.h +++ b/src/mapgen/mg_schematic.h @@ -130,7 +130,7 @@ public: SchematicManager(Server *server); virtual ~SchematicManager() = default; - // not cloneable + SchematicManager *clone() const; virtual void clear(); @@ -145,6 +145,8 @@ public: } private: + SchematicManager() {}; + Server *m_server; }; diff --git a/src/script/lua_api/l_mapgen.cpp b/src/script/lua_api/l_mapgen.cpp index afe77826a..ba0304be3 100644 --- a/src/script/lua_api/l_mapgen.cpp +++ b/src/script/lua_api/l_mapgen.cpp @@ -91,7 +91,7 @@ struct EnumString ModApiMapgen::es_SchematicFormatType[] = {0, NULL}, }; -ObjDef *get_objdef(lua_State *L, int index, ObjDefManager *objmgr); +ObjDef *get_objdef(lua_State *L, int index, const ObjDefManager *objmgr); Biome *get_or_load_biome(lua_State *L, int index, BiomeManager *biomemgr); @@ -114,7 +114,7 @@ bool read_deco_schematic(lua_State *L, SchematicManager *schemmgr, DecoSchematic /////////////////////////////////////////////////////////////////////////////// -ObjDef *get_objdef(lua_State *L, int index, ObjDefManager *objmgr) +ObjDef *get_objdef(lua_State *L, int index, const ObjDefManager *objmgr) { if (index < 0) index = lua_gettop(L) + 1 + index; @@ -486,7 +486,7 @@ int ModApiMapgen::l_get_biome_id(lua_State *L) if (!biome_str) return 0; - BiomeManager *bmgr = getServer(L)->getEmergeManager()->biomemgr; + const BiomeManager *bmgr = getServer(L)->getEmergeManager()->getBiomeManager(); if (!bmgr) return 0; @@ -508,7 +508,7 @@ int ModApiMapgen::l_get_biome_name(lua_State *L) int biome_id = luaL_checkinteger(L, 1); - BiomeManager *bmgr = getServer(L)->getEmergeManager()->biomemgr; + const BiomeManager *bmgr = getServer(L)->getEmergeManager()->getBiomeManager(); if (!bmgr) return 0; @@ -546,7 +546,7 @@ int ModApiMapgen::l_get_heat(lua_State *L) u64 seed; ss >> seed; - BiomeManager *bmgr = getServer(L)->getEmergeManager()->biomemgr; + const BiomeManager *bmgr = getServer(L)->getEmergeManager()->getBiomeManager(); if (!bmgr) return 0; @@ -587,7 +587,7 @@ int ModApiMapgen::l_get_humidity(lua_State *L) u64 seed; ss >> seed; - BiomeManager *bmgr = getServer(L)->getEmergeManager()->biomemgr; + const BiomeManager *bmgr = getServer(L)->getEmergeManager()->getBiomeManager(); if (!bmgr) return 0; @@ -635,7 +635,7 @@ int ModApiMapgen::l_get_biome_data(lua_State *L) u64 seed; ss >> seed; - BiomeManager *bmgr = getServer(L)->getEmergeManager()->biomemgr; + const BiomeManager *bmgr = getServer(L)->getEmergeManager()->getBiomeManager(); if (!bmgr) return 0; @@ -1066,7 +1066,8 @@ int ModApiMapgen::l_get_decoration_id(lua_State *L) if (!deco_str) return 0; - DecorationManager *dmgr = getServer(L)->getEmergeManager()->decomgr; + const DecorationManager *dmgr = + getServer(L)->getEmergeManager()->getDecorationManager(); if (!dmgr) return 0; @@ -1091,7 +1092,7 @@ int ModApiMapgen::l_register_biome(lua_State *L) luaL_checktype(L, index, LUA_TTABLE); const NodeDefManager *ndef = getServer(L)->getNodeDefManager(); - BiomeManager *bmgr = getServer(L)->getEmergeManager()->biomemgr; + BiomeManager *bmgr = getServer(L)->getEmergeManager()->getWritableBiomeManager(); Biome *biome = read_biome_def(L, index, ndef); if (!biome) @@ -1117,9 +1118,10 @@ int ModApiMapgen::l_register_decoration(lua_State *L) luaL_checktype(L, index, LUA_TTABLE); const NodeDefManager *ndef = getServer(L)->getNodeDefManager(); - DecorationManager *decomgr = getServer(L)->getEmergeManager()->decomgr; - BiomeManager *biomemgr = getServer(L)->getEmergeManager()->biomemgr; - SchematicManager *schemmgr = getServer(L)->getEmergeManager()->schemmgr; + EmergeManager *emerge = getServer(L)->getEmergeManager(); + DecorationManager *decomgr = emerge->getWritableDecorationManager(); + BiomeManager *biomemgr = emerge->getWritableBiomeManager(); + SchematicManager *schemmgr = emerge->getWritableSchematicManager(); enum DecorationType decotype = (DecorationType)getenumfield(L, index, "deco_type", es_DecorationType, -1); @@ -1274,8 +1276,9 @@ int ModApiMapgen::l_register_ore(lua_State *L) luaL_checktype(L, index, LUA_TTABLE); const NodeDefManager *ndef = getServer(L)->getNodeDefManager(); - BiomeManager *bmgr = getServer(L)->getEmergeManager()->biomemgr; - OreManager *oremgr = getServer(L)->getEmergeManager()->oremgr; + EmergeManager *emerge = getServer(L)->getEmergeManager(); + BiomeManager *bmgr = emerge->getWritableBiomeManager(); + OreManager *oremgr = emerge->getWritableOreManager(); enum OreType oretype = (OreType)getenumfield(L, index, "ore_type", es_OreType, ORE_SCATTER); @@ -1422,7 +1425,8 @@ int ModApiMapgen::l_register_schematic(lua_State *L) { NO_MAP_LOCK_REQUIRED; - SchematicManager *schemmgr = getServer(L)->getEmergeManager()->schemmgr; + SchematicManager *schemmgr = + getServer(L)->getEmergeManager()->getWritableSchematicManager(); StringMap replace_names; if (lua_istable(L, 2)) @@ -1449,7 +1453,8 @@ int ModApiMapgen::l_clear_registered_biomes(lua_State *L) { NO_MAP_LOCK_REQUIRED; - BiomeManager *bmgr = getServer(L)->getEmergeManager()->biomemgr; + BiomeManager *bmgr = + getServer(L)->getEmergeManager()->getWritableBiomeManager(); bmgr->clear(); return 0; } @@ -1460,7 +1465,8 @@ int ModApiMapgen::l_clear_registered_decorations(lua_State *L) { NO_MAP_LOCK_REQUIRED; - DecorationManager *dmgr = getServer(L)->getEmergeManager()->decomgr; + DecorationManager *dmgr = + getServer(L)->getEmergeManager()->getWritableDecorationManager(); dmgr->clear(); return 0; } @@ -1471,7 +1477,8 @@ int ModApiMapgen::l_clear_registered_ores(lua_State *L) { NO_MAP_LOCK_REQUIRED; - OreManager *omgr = getServer(L)->getEmergeManager()->oremgr; + OreManager *omgr = + getServer(L)->getEmergeManager()->getWritableOreManager(); omgr->clear(); return 0; } @@ -1482,7 +1489,8 @@ int ModApiMapgen::l_clear_registered_schematics(lua_State *L) { NO_MAP_LOCK_REQUIRED; - SchematicManager *smgr = getServer(L)->getEmergeManager()->schemmgr; + SchematicManager *smgr = + getServer(L)->getEmergeManager()->getWritableSchematicManager(); smgr->clear(); return 0; } @@ -1508,7 +1516,8 @@ int ModApiMapgen::l_generate_ores(lua_State *L) u32 blockseed = Mapgen::getBlockSeed(pmin, mg.seed); - emerge->oremgr->placeAllOres(&mg, blockseed, pmin, pmax); + OreManager *oremgr = (OreManager*) emerge->getOreManager(); // FIXME FIXME + oremgr->placeAllOres(&mg, blockseed, pmin, pmax); return 0; } @@ -1534,7 +1543,8 @@ int ModApiMapgen::l_generate_decorations(lua_State *L) u32 blockseed = Mapgen::getBlockSeed(pmin, mg.seed); - emerge->decomgr->placeAllDecos(&mg, blockseed, pmin, pmax); + DecorationManager *decomgr = (DecorationManager*) emerge->getDecorationManager(); // FIXME FIXME + decomgr->placeAllDecos(&mg, blockseed, pmin, pmax); return 0; } @@ -1614,7 +1624,8 @@ int ModApiMapgen::l_place_schematic(lua_State *L) GET_ENV_PTR; ServerMap *map = &(env->getServerMap()); - SchematicManager *schemmgr = getServer(L)->getEmergeManager()->schemmgr; + SchematicManager *schemmgr = (SchematicManager*) + getServer(L)->getEmergeManager()->getSchematicManager(); // FIXME FIXME //// Read position v3s16 p = check_v3s16(L, 1); @@ -1659,7 +1670,8 @@ int ModApiMapgen::l_place_schematic_on_vmanip(lua_State *L) { NO_MAP_LOCK_REQUIRED; - SchematicManager *schemmgr = getServer(L)->getEmergeManager()->schemmgr; + SchematicManager *schemmgr = (SchematicManager*) + getServer(L)->getEmergeManager()->getSchematicManager(); // FIXME FIXME //// Read VoxelManip object MMVManip *vm = LuaVoxelManip::checkobject(L, 1)->vm; @@ -1707,7 +1719,7 @@ int ModApiMapgen::l_serialize_schematic(lua_State *L) { NO_MAP_LOCK_REQUIRED; - SchematicManager *schemmgr = getServer(L)->getEmergeManager()->schemmgr; + const SchematicManager *schemmgr = getServer(L)->getEmergeManager()->getSchematicManager(); //// Read options bool use_comments = getboolfield_default(L, 3, "lua_use_comments", false); @@ -1758,7 +1770,8 @@ int ModApiMapgen::l_read_schematic(lua_State *L) { NO_MAP_LOCK_REQUIRED; - SchematicManager *schemmgr = getServer(L)->getEmergeManager()->schemmgr; + const SchematicManager *schemmgr = + getServer(L)->getEmergeManager()->getSchematicManager(); //// Read options std::string write_yslice = getstringfield_default(L, 2, "write_yslice_prob", "all"); -- cgit v1.2.3 From c28fbd06a8bfafc9691a92c90f0cf10ec94cd314 Mon Sep 17 00:00:00 2001 From: sfan5 Date: Fri, 10 Apr 2020 02:43:49 +0200 Subject: Fix remaining issues with mapgen scriptapi --- src/emerge.h | 6 ++++++ src/mapgen/mg_biome.cpp | 3 ++- src/mapgen/mg_biome.h | 4 +++- src/mapgen/mg_schematic.cpp | 5 +++-- src/mapgen/mg_schematic.h | 5 +++-- src/objdef.h | 1 + src/script/lua_api/l_mapgen.cpp | 24 ++++++++---------------- 7 files changed, 26 insertions(+), 22 deletions(-) (limited to 'src/mapgen') diff --git a/src/emerge.h b/src/emerge.h index ab9fca2ba..6f204666d 100644 --- a/src/emerge.h +++ b/src/emerge.h @@ -44,6 +44,7 @@ class OreManager; class DecorationManager; class SchematicManager; class Server; +class ModApiMapgen; // Structure containing inputs/outputs for chunk generation struct BlockMakeData { @@ -111,6 +112,11 @@ private: }; class EmergeManager { + /* The mod API needs unchecked access to allow: + * - using decomgr or oremgr to place decos/ores + * - using schemmgr to load and place schematics + */ + friend class ModApiMapgen; public: const NodeDefManager *ndef; bool enable_mapgen_debug_info; diff --git a/src/mapgen/mg_biome.cpp b/src/mapgen/mg_biome.cpp index f3bc4e829..8c59ac9e6 100644 --- a/src/mapgen/mg_biome.cpp +++ b/src/mapgen/mg_biome.cpp @@ -123,7 +123,8 @@ float BiomeManager::getHumidityAtPosOriginal(v3s16 pos, NoiseParams &np_humidity // For BiomeGen type 'BiomeGenOriginal' -Biome *BiomeManager::getBiomeFromNoiseOriginal(float heat, float humidity, v3s16 pos) const +const Biome *BiomeManager::getBiomeFromNoiseOriginal(float heat, + float humidity, v3s16 pos) const { Biome *biome_closest = nullptr; Biome *biome_closest_blend = nullptr; diff --git a/src/mapgen/mg_biome.h b/src/mapgen/mg_biome.h index 0a4471cc3..57f4aa20d 100644 --- a/src/mapgen/mg_biome.h +++ b/src/mapgen/mg_biome.h @@ -90,6 +90,7 @@ struct BiomeParams { s32 seed; }; +// WARNING: this class is not thread-safe class BiomeGen { public: virtual ~BiomeGen() = default; @@ -233,7 +234,8 @@ public: NoiseParams &np_heat_blend, u64 seed) const; float getHumidityAtPosOriginal(v3s16 pos, NoiseParams &np_humidity, NoiseParams &np_humidity_blend, u64 seed) const; - Biome *getBiomeFromNoiseOriginal(float heat, float humidity, v3s16 pos) const; + const Biome *getBiomeFromNoiseOriginal(float heat, float humidity, + v3s16 pos) const; private: BiomeManager() {}; diff --git a/src/mapgen/mg_schematic.cpp b/src/mapgen/mg_schematic.cpp index c3bd89f3a..ba102d997 100644 --- a/src/mapgen/mg_schematic.cpp +++ b/src/mapgen/mg_schematic.cpp @@ -359,7 +359,7 @@ bool Schematic::deserializeFromMts(std::istream *is, bool Schematic::serializeToMts(std::ostream *os, - const std::vector &names) + const std::vector &names) const { std::ostream &ss = *os; @@ -383,7 +383,8 @@ bool Schematic::serializeToMts(std::ostream *os, bool Schematic::serializeToLua(std::ostream *os, - const std::vector &names, bool use_comments, u32 indent_spaces) + const std::vector &names, bool use_comments, + u32 indent_spaces) const { std::ostream &ss = *os; diff --git a/src/mapgen/mg_schematic.h b/src/mapgen/mg_schematic.h index 3222085e6..6b31251b6 100644 --- a/src/mapgen/mg_schematic.h +++ b/src/mapgen/mg_schematic.h @@ -106,9 +106,10 @@ public: bool getSchematicFromMap(Map *map, v3s16 p1, v3s16 p2); bool deserializeFromMts(std::istream *is, std::vector *names); - bool serializeToMts(std::ostream *os, const std::vector &names); + bool serializeToMts(std::ostream *os, + const std::vector &names) const; bool serializeToLua(std::ostream *os, const std::vector &names, - bool use_comments, u32 indent_spaces); + bool use_comments, u32 indent_spaces) const; void blitToVManip(MMVManip *vm, v3s16 p, Rotation rot, bool force_place); bool placeOnVManip(MMVManip *vm, v3s16 p, u32 flags, Rotation rot, bool force_place); diff --git a/src/objdef.h b/src/objdef.h index 20565029c..e40324a88 100644 --- a/src/objdef.h +++ b/src/objdef.h @@ -66,6 +66,7 @@ protected: // WARNING: Ownership of ObjDefs is transferred to the ObjDefManager it is // added/set to. Note that ObjDefs managed by ObjDefManager are NOT refcounted, // so the same ObjDef instance must not be referenced multiple +// TODO: const correctness for getter methods class ObjDefManager { public: ObjDefManager(IGameDef *gamedef, ObjDefType type); diff --git a/src/script/lua_api/l_mapgen.cpp b/src/script/lua_api/l_mapgen.cpp index ba0304be3..584085428 100644 --- a/src/script/lua_api/l_mapgen.cpp +++ b/src/script/lua_api/l_mapgen.cpp @@ -490,7 +490,7 @@ int ModApiMapgen::l_get_biome_id(lua_State *L) if (!bmgr) return 0; - Biome *biome = (Biome *)bmgr->getByName(biome_str); + const Biome *biome = (Biome *)bmgr->getByName(biome_str); if (!biome || biome->index == OBJDEF_INVALID_INDEX) return 0; @@ -512,7 +512,7 @@ int ModApiMapgen::l_get_biome_name(lua_State *L) if (!bmgr) return 0; - Biome *b = (Biome *)bmgr->getRaw(biome_id); + const Biome *b = (Biome *)bmgr->getRaw(biome_id); lua_pushstring(L, b->name.c_str()); return 1; @@ -551,8 +551,6 @@ int ModApiMapgen::l_get_heat(lua_State *L) return 0; float heat = bmgr->getHeatAtPosOriginal(pos, np_heat, np_heat_blend, seed); - if (!heat) - return 0; lua_pushnumber(L, heat); @@ -593,8 +591,6 @@ int ModApiMapgen::l_get_humidity(lua_State *L) float humidity = bmgr->getHumidityAtPosOriginal(pos, np_humidity, np_humidity_blend, seed); - if (!humidity) - return 0; lua_pushnumber(L, humidity); @@ -648,7 +644,7 @@ int ModApiMapgen::l_get_biome_data(lua_State *L) if (!humidity) return 0; - Biome *biome = (Biome *)bmgr->getBiomeFromNoiseOriginal(heat, humidity, pos); + const Biome *biome = bmgr->getBiomeFromNoiseOriginal(heat, humidity, pos); if (!biome || biome->index == OBJDEF_INVALID_INDEX) return 0; @@ -1516,8 +1512,7 @@ int ModApiMapgen::l_generate_ores(lua_State *L) u32 blockseed = Mapgen::getBlockSeed(pmin, mg.seed); - OreManager *oremgr = (OreManager*) emerge->getOreManager(); // FIXME FIXME - oremgr->placeAllOres(&mg, blockseed, pmin, pmax); + emerge->oremgr->placeAllOres(&mg, blockseed, pmin, pmax); return 0; } @@ -1543,8 +1538,7 @@ int ModApiMapgen::l_generate_decorations(lua_State *L) u32 blockseed = Mapgen::getBlockSeed(pmin, mg.seed); - DecorationManager *decomgr = (DecorationManager*) emerge->getDecorationManager(); // FIXME FIXME - decomgr->placeAllDecos(&mg, blockseed, pmin, pmax); + emerge->decomgr->placeAllDecos(&mg, blockseed, pmin, pmax); return 0; } @@ -1624,8 +1618,7 @@ int ModApiMapgen::l_place_schematic(lua_State *L) GET_ENV_PTR; ServerMap *map = &(env->getServerMap()); - SchematicManager *schemmgr = (SchematicManager*) - getServer(L)->getEmergeManager()->getSchematicManager(); // FIXME FIXME + SchematicManager *schemmgr = getServer(L)->getEmergeManager()->schemmgr; //// Read position v3s16 p = check_v3s16(L, 1); @@ -1670,8 +1663,7 @@ int ModApiMapgen::l_place_schematic_on_vmanip(lua_State *L) { NO_MAP_LOCK_REQUIRED; - SchematicManager *schemmgr = (SchematicManager*) - getServer(L)->getEmergeManager()->getSchematicManager(); // FIXME FIXME + SchematicManager *schemmgr = getServer(L)->getEmergeManager()->schemmgr; //// Read VoxelManip object MMVManip *vm = LuaVoxelManip::checkobject(L, 1)->vm; @@ -1727,7 +1719,7 @@ int ModApiMapgen::l_serialize_schematic(lua_State *L) //// Get schematic bool was_loaded = false; - Schematic *schem = (Schematic *)get_objdef(L, 1, schemmgr); + const Schematic *schem = (Schematic *)get_objdef(L, 1, schemmgr); if (!schem) { schem = load_schematic(L, 1, NULL, NULL); was_loaded = true; -- cgit v1.2.3 From f3e87c53a5afc264e657acd99d3a39fbec3b63c9 Mon Sep 17 00:00:00 2001 From: sfan5 Date: Sun, 26 Apr 2020 18:33:50 +0200 Subject: Fix thread safety of PcgRandom use in BiomeGen --- src/mapgen/mg_biome.cpp | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) (limited to 'src/mapgen') diff --git a/src/mapgen/mg_biome.cpp b/src/mapgen/mg_biome.cpp index 8c59ac9e6..610c38594 100644 --- a/src/mapgen/mg_biome.cpp +++ b/src/mapgen/mg_biome.cpp @@ -154,9 +154,11 @@ const Biome *BiomeManager::getBiomeFromNoiseOriginal(float heat, } } - mysrand(pos.Y + (heat + humidity) * 0.9f); + const u64 seed = pos.Y + (heat + humidity) * 0.9f; + PcgRandom rng(seed); + if (biome_closest_blend && dist_min_blend <= dist_min && - myrand_range(0, biome_closest_blend->vertical_blend) >= + rng.range(0, biome_closest_blend->vertical_blend) >= pos.Y - biome_closest_blend->max_pos.Y) return biome_closest_blend; @@ -319,10 +321,11 @@ Biome *BiomeGenOriginal::calcBiomeFromNoise(float heat, float humidity, v3s16 po // Carefully tune pseudorandom seed variation to avoid single node dither // and create larger scale blending patterns similar to horizontal biome // blend. - mysrand(pos.Y + (heat + humidity) * 0.9f); + const u64 seed = pos.Y + (heat + humidity) * 0.9f; + PcgRandom rng(seed); if (biome_closest_blend && dist_min_blend <= dist_min && - myrand_range(0, biome_closest_blend->vertical_blend) >= + rng.range(0, biome_closest_blend->vertical_blend) >= pos.Y - biome_closest_blend->max_pos.Y) return biome_closest_blend; -- cgit v1.2.3 From af0f7ac4a2032780eb731918c8fe9dc9e1262b5f Mon Sep 17 00:00:00 2001 From: Paramat Date: Thu, 14 May 2020 22:27:54 +0100 Subject: Add new Mapgen V7 floatland implementation (#9296) Floatland structure is vertically-compressed 3D noise. Uses a lacunarity of 1.618 (the golden ratio) for high quality noise. Floatlands appear between user-settable Y limits, with smooth tapering at each limit. Simple user-settable density adjustment. Shadow propagation is disabled in and just below floatlands, no shadows are cast on the world surface. Can be reconfigured to create a solid upper world layer between the Y limits, lakes/seas can be optionally added to this. --- builtin/settingtypes.txt | 49 ++++++++++++++++++++++- src/mapgen/mapgen_v7.cpp | 102 ++++++++++++++++++++++++++++++++++++++++++----- src/mapgen/mapgen_v7.h | 21 +++++++++- 3 files changed, 160 insertions(+), 12 deletions(-) (limited to 'src/mapgen') diff --git a/builtin/settingtypes.txt b/builtin/settingtypes.txt index b75bf2de5..d3f2c60b5 100644 --- a/builtin/settingtypes.txt +++ b/builtin/settingtypes.txt @@ -1607,12 +1607,53 @@ mgv6_np_apple_trees (Apple trees noise) noise_params_2d 0, 1, (100, 100, 100), 3 [*Mapgen V7] # Map generation attributes specific to Mapgen v7. -# 'ridges' enables the rivers. +# 'ridges': Rivers. +# 'floatlands': Floating land masses in the atmosphere. +# 'caverns': Giant caves deep underground. mgv7_spflags (Mapgen V7 specific flags) flags mountains,ridges,nofloatlands,caverns mountains,ridges,floatlands,caverns,nomountains,noridges,nofloatlands,nocaverns # Y of mountain density gradient zero level. Used to shift mountains vertically. mgv7_mount_zero_level (Mountain zero level) int 0 +# Lower Y limit of floatlands. +mgv7_floatland_ymin (Floatland minimum Y) int 1024 + +# Upper Y limit of floatlands. +mgv7_floatland_ymax (Floatland maximum Y) int 4096 + +# Y-distance over which floatlands taper from full density to nothing. +# Tapering starts at this distance from the Y limit. +# For a solid floatland layer, this controls the height of hills/mountains. +# Must be less than or equal to half the distance between the Y limits. +mgv7_floatland_taper (Floatland tapering distance) int 256 + +# Exponent of the floatland tapering. Alters the tapering behaviour. +# Value = 1.0 creates a uniform, linear tapering. +# Values > 1.0 create a smooth tapering suitable for the default separated +# floatlands. +# Values < 1.0 (for example 0.25) create a more defined surface level with +# flatter lowlands, suitable for a solid floatland layer. +mgv7_float_taper_exp (Floatland taper exponent) float 2.0 + +# Adjusts the density of the floatland layer. +# Increase value to increase density. Can be positive or negative. +# Value = 0.0: 50% of volume is floatland. +# Value = 2.0 (can be higher depending on 'mgv7_np_floatland', always test +# to be sure) creates a solid floatland layer. +mgv7_floatland_density (Floatland density) float -0.9 + +# Surface level of optional water placed on a solid floatland layer. +# Water is disabled by default and will only be placed if this value is set +# to above 'mgv7_floatland_ymax' - 'mgv7_floatland_taper' (the start of the +# upper tapering). +# ***WARNING, POTENTIAL DANGER TO WORLDS AND SERVER PERFORMANCE***: +# When enabling water placement the floatlands must be configured and tested +# to be a solid layer by setting 'mgv7_floatland_density' to 2.0 (or other +# required value depending on 'mgv7_np_floatland'), to avoid +# server-intensive extreme water flow and to avoid vast flooding of the +# world surface below. +mgv7_floatland_ywater (Floatland water level) int -31000 + # Controls width of tunnels, a smaller value creates wider tunnels. # Value >= 10.0 completely disables generation of tunnels and avoids the # intensive noise calculations. @@ -1682,6 +1723,12 @@ mgv7_np_mountain (Mountain noise) noise_params_3d -0.6, 1, (250, 350, 250), 5333 # 3D noise defining structure of river canyon walls. mgv7_np_ridge (Ridge noise) noise_params_3d 0, 1, (100, 100, 100), 6467, 4, 0.75, 2.0 +# 3D noise defining structure of floatlands. +# If altered from the default, the noise 'scale' (0.7 by default) may need +# to be adjusted, as floatland tapering functions best when this noise has +# a value range of approximately -2.0 to 2.0. +mgv7_np_floatland (Floatland noise) noise_params_3d 0, 0.7, (384, 96, 384), 1009, 4, 0.75, 1.618 + # 3D noise defining giant caverns. mgv7_np_cavern (Cavern noise) noise_params_3d 0, 1, (384, 128, 384), 723, 5, 0.63, 2.0 diff --git a/src/mapgen/mapgen_v7.cpp b/src/mapgen/mapgen_v7.cpp index 43d5d822f..e93dc9140 100644 --- a/src/mapgen/mapgen_v7.cpp +++ b/src/mapgen/mapgen_v7.cpp @@ -1,7 +1,7 @@ /* Minetest -Copyright (C) 2013-2019 kwolekr, Ryan Kwolek -Copyright (C) 2014-2019 paramat +Copyright (C) 2014-2020 paramat +Copyright (C) 2013-2016 kwolekr, Ryan Kwolek 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 @@ -56,6 +56,12 @@ MapgenV7::MapgenV7(MapgenV7Params *params, EmergeParams *emerge) { spflags = params->spflags; mount_zero_level = params->mount_zero_level; + floatland_ymin = params->floatland_ymin; + floatland_ymax = params->floatland_ymax; + floatland_taper = params->floatland_taper; + float_taper_exp = params->float_taper_exp; + floatland_density = params->floatland_density; + floatland_ywater = params->floatland_ywater; cave_width = params->cave_width; large_cave_depth = params->large_cave_depth; @@ -70,6 +76,9 @@ MapgenV7::MapgenV7(MapgenV7Params *params, EmergeParams *emerge) dungeon_ymin = params->dungeon_ymin; dungeon_ymax = params->dungeon_ymax; + // Allocate floatland noise offset cache + this->float_offset_cache = new float[csize.Y + 2]; + // 2D noise noise_terrain_base = new Noise(¶ms->np_terrain_base, seed, csize.X, csize.Z); @@ -100,6 +109,12 @@ MapgenV7::MapgenV7(MapgenV7Params *params, EmergeParams *emerge) new Noise(¶ms->np_ridge, seed, csize.X, csize.Y + 2, csize.Z); } + if (spflags & MGV7_FLOATLANDS) { + // 3D noise, 1 up, 1 down overgeneration + noise_floatland = + new Noise(¶ms->np_floatland, seed, csize.X, csize.Y + 2, csize.Z); + } + // 3D noise, 1 down overgeneration MapgenBasic::np_cave1 = params->np_cave1; MapgenBasic::np_cave2 = params->np_cave2; @@ -126,6 +141,12 @@ MapgenV7::~MapgenV7() delete noise_ridge_uwater; delete noise_ridge; } + + if (spflags & MGV7_FLOATLANDS) { + delete noise_floatland; + } + + delete []float_offset_cache; } @@ -139,6 +160,7 @@ MapgenV7Params::MapgenV7Params(): np_ridge_uwater (0.0, 1.0, v3f(1000, 1000, 1000), 85039, 5, 0.6, 2.0), np_mountain (-0.6, 1.0, v3f(250, 350, 250), 5333, 5, 0.63, 2.0), np_ridge (0.0, 1.0, v3f(100, 100, 100), 6467, 4, 0.75, 2.0), + np_floatland (0.0, 0.7, v3f(384, 96, 384), 1009, 4, 0.75, 1.618), np_cavern (0.0, 1.0, v3f(384, 128, 384), 723, 5, 0.63, 2.0), np_cave1 (0.0, 12.0, v3f(61, 61, 61), 52534, 3, 0.5, 2.0), np_cave2 (0.0, 12.0, v3f(67, 67, 67), 10325, 3, 0.5, 2.0), @@ -151,6 +173,13 @@ void MapgenV7Params::readParams(const Settings *settings) { settings->getFlagStrNoEx("mgv7_spflags", spflags, flagdesc_mapgen_v7); settings->getS16NoEx("mgv7_mount_zero_level", mount_zero_level); + settings->getS16NoEx("mgv7_floatland_ymin", floatland_ymin); + settings->getS16NoEx("mgv7_floatland_ymax", floatland_ymax); + settings->getS16NoEx("mgv7_floatland_taper", floatland_taper); + settings->getFloatNoEx("mgv7_float_taper_exp", float_taper_exp); + settings->getFloatNoEx("mgv7_floatland_density", floatland_density); + settings->getS16NoEx("mgv7_floatland_ywater", floatland_ywater); + settings->getFloatNoEx("mgv7_cave_width", cave_width); settings->getS16NoEx("mgv7_large_cave_depth", large_cave_depth); settings->getU16NoEx("mgv7_small_cave_num_min", small_cave_num_min); @@ -173,6 +202,7 @@ void MapgenV7Params::readParams(const Settings *settings) settings->getNoiseParams("mgv7_np_ridge_uwater", np_ridge_uwater); settings->getNoiseParams("mgv7_np_mountain", np_mountain); settings->getNoiseParams("mgv7_np_ridge", np_ridge); + settings->getNoiseParams("mgv7_np_floatland", np_floatland); settings->getNoiseParams("mgv7_np_cavern", np_cavern); settings->getNoiseParams("mgv7_np_cave1", np_cave1); settings->getNoiseParams("mgv7_np_cave2", np_cave2); @@ -184,6 +214,13 @@ void MapgenV7Params::writeParams(Settings *settings) const { settings->setFlagStr("mgv7_spflags", spflags, flagdesc_mapgen_v7); settings->setS16("mgv7_mount_zero_level", mount_zero_level); + settings->setS16("mgv7_floatland_ymin", floatland_ymin); + settings->setS16("mgv7_floatland_ymax", floatland_ymax); + settings->setS16("mgv7_floatland_taper", floatland_taper); + settings->setFloat("mgv7_float_taper_exp", float_taper_exp); + settings->setFloat("mgv7_floatland_density", floatland_density); + settings->setS16("mgv7_floatland_ywater", floatland_ywater); + settings->setFloat("mgv7_cave_width", cave_width); settings->setS16("mgv7_large_cave_depth", large_cave_depth); settings->setU16("mgv7_small_cave_num_min", small_cave_num_min); @@ -206,6 +243,7 @@ void MapgenV7Params::writeParams(Settings *settings) const settings->setNoiseParams("mgv7_np_ridge_uwater", np_ridge_uwater); settings->setNoiseParams("mgv7_np_mountain", np_mountain); settings->setNoiseParams("mgv7_np_ridge", np_ridge); + settings->setNoiseParams("mgv7_np_floatland", np_floatland); settings->setNoiseParams("mgv7_np_cavern", np_cavern); settings->setNoiseParams("mgv7_np_cave1", np_cave1); settings->setNoiseParams("mgv7_np_cave2", np_cave2); @@ -357,8 +395,9 @@ void MapgenV7::makeChunk(BlockMakeData *data) updateLiquid(&data->transforming_liquid, full_node_min, full_node_max); // Calculate lighting - // TODO disable in and just below floatlands - bool propagate_shadow = true; + // Limit floatland shadows + bool propagate_shadow = !((spflags & MGV7_FLOATLANDS) && + node_max.Y >= floatland_ymin - csize.Y * 2 && node_min.Y <= floatland_ymax); if (flags & MG_LIGHT) calcLighting(node_min - v3s16(0, 1, 0), node_max + v3s16(0, 1, 0), @@ -427,6 +466,12 @@ bool MapgenV7::getMountainTerrainFromMap(int idx_xyz, int idx_xz, s16 y) } +bool MapgenV7::getFloatlandTerrainFromMap(int idx_xyz, float float_offset) +{ + return noise_floatland->result[idx_xyz] + floatland_density - float_offset >= 0.0f; +} + + int MapgenV7::generateTerrain() { MapNode n_air(CONTENT_AIR); @@ -446,6 +491,35 @@ int MapgenV7::generateTerrain() noise_mountain->perlinMap3D(node_min.X, node_min.Y - 1, node_min.Z); } + //// Floatlands + // 'Generate floatlands in this mapchunk' bool for + // simplification of condition checks in y-loop. + bool gen_floatlands = false; + u8 cache_index = 0; + // Y values where floatland tapering starts + s16 float_taper_ymax = floatland_ymax - floatland_taper; + s16 float_taper_ymin = floatland_ymin + floatland_taper; + + if ((spflags & MGV7_FLOATLANDS) && + node_max.Y >= floatland_ymin && node_min.Y <= floatland_ymax) { + gen_floatlands = true; + // Calculate noise for floatland generation + noise_floatland->perlinMap3D(node_min.X, node_min.Y - 1, node_min.Z); + + // Cache floatland noise offset values, for floatland tapering + for (s16 y = node_min.Y - 1; y <= node_max.Y + 1; y++, cache_index++) { + float float_offset = 0.0f; + if (y > float_taper_ymax) { + float_offset = std::pow((y - float_taper_ymax) / (float)floatland_taper, + float_taper_exp) * 4.0f; + } else if (y < float_taper_ymin) { + float_offset = std::pow((float_taper_ymin - y) / (float)floatland_taper, + float_taper_exp) * 4.0f; + } + float_offset_cache[cache_index] = float_offset; + } + } + //// Place nodes const v3s16 &em = vm->m_area.getExtent(); s16 stone_surface_max_y = -MAX_MAP_GENERATION_LIMIT; @@ -457,13 +531,15 @@ int MapgenV7::generateTerrain() if (surface_y > stone_surface_max_y) stone_surface_max_y = surface_y; + cache_index = 0; u32 vi = vm->m_area.index(x, node_min.Y - 1, z); u32 index3d = (z - node_min.Z) * zstride_1u1d + (x - node_min.X); for (s16 y = node_min.Y - 1; y <= node_max.Y + 1; y++, index3d += ystride, - VoxelArea::add_y(em, vi, 1)) { + VoxelArea::add_y(em, vi, 1), + cache_index++) { if (vm->m_data[vi].getContent() != CONTENT_IGNORE) continue; @@ -474,10 +550,18 @@ int MapgenV7::generateTerrain() vm->m_data[vi] = n_stone; // Mountain terrain if (y > stone_surface_max_y) stone_surface_max_y = y; - } else if (y <= water_level) { + } else if (gen_floatlands && + getFloatlandTerrainFromMap(index3d, + float_offset_cache[cache_index])) { + vm->m_data[vi] = n_stone; // Floatland terrain + if (y > stone_surface_max_y) + stone_surface_max_y = y; + } else if (y <= water_level) { // Surface water vm->m_data[vi] = n_water; + } else if (gen_floatlands && y >= float_taper_ymax && y <= floatland_ywater) { + vm->m_data[vi] = n_water; // Water for solid floatland layer only } else { - vm->m_data[vi] = n_air; + vm->m_data[vi] = n_air; // Air } } } @@ -488,8 +572,8 @@ int MapgenV7::generateTerrain() void MapgenV7::generateRidgeTerrain() { - // TODO disable river canyons in floatlands - if (node_max.Y < water_level - 16) + if (node_max.Y < water_level - 16 || + (node_max.Y >= floatland_ymin && node_min.Y <= floatland_ymax)) return; noise_ridge->perlinMap3D(node_min.X, node_min.Y - 1, node_min.Z); diff --git a/src/mapgen/mapgen_v7.h b/src/mapgen/mapgen_v7.h index eeae3a956..4020cd935 100644 --- a/src/mapgen/mapgen_v7.h +++ b/src/mapgen/mapgen_v7.h @@ -1,7 +1,7 @@ /* Minetest -Copyright (C) 2013-2018 kwolekr, Ryan Kwolek -Copyright (C) 2014-2018 paramat +Copyright (C) 2014-2020 paramat +Copyright (C) 2013-2016 kwolekr, Ryan Kwolek 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 @@ -36,6 +36,12 @@ extern FlagDesc flagdesc_mapgen_v7[]; struct MapgenV7Params : public MapgenParams { s16 mount_zero_level = 0; + s16 floatland_ymin = 1024; + s16 floatland_ymax = 4096; + s16 floatland_taper = 256; + float float_taper_exp = 2.0f; + float floatland_density = -0.6f; + s16 floatland_ywater = -31000; float cave_width = 0.09f; s16 large_cave_depth = -33; @@ -59,6 +65,7 @@ struct MapgenV7Params : public MapgenParams { NoiseParams np_ridge_uwater; NoiseParams np_mountain; NoiseParams np_ridge; + NoiseParams np_floatland; NoiseParams np_cavern; NoiseParams np_cave1; NoiseParams np_cave2; @@ -87,12 +94,21 @@ public: float baseTerrainLevelFromMap(int index); bool getMountainTerrainAtPoint(s16 x, s16 y, s16 z); bool getMountainTerrainFromMap(int idx_xyz, int idx_xz, s16 y); + bool getFloatlandTerrainFromMap(int idx_xyz, float float_offset); int generateTerrain(); void generateRidgeTerrain(); private: s16 mount_zero_level; + s16 floatland_ymin; + s16 floatland_ymax; + s16 floatland_taper; + float float_taper_exp; + float floatland_density; + s16 floatland_ywater; + + float *float_offset_cache = nullptr; Noise *noise_terrain_base; Noise *noise_terrain_alt; @@ -102,4 +118,5 @@ private: Noise *noise_ridge_uwater; Noise *noise_mountain; Noise *noise_ridge; + Noise *noise_floatland; }; -- cgit v1.2.3 From 42fcfb75e85523a2fa5d99a453c2fabc2c04c0f6 Mon Sep 17 00:00:00 2001 From: Paramat Date: Wed, 20 May 2020 22:16:14 +0100 Subject: Allow more than 255 biomes, document new maximum (#9855) Change biomemap data type from u8 to u16. New technical (not practical) maximum is 65535 biomes. --- doc/lua_api.txt | 4 ++++ src/mapgen/cavegen.cpp | 8 ++++---- src/mapgen/cavegen.h | 8 +++++--- src/mapgen/mapgen.h | 8 ++++---- src/mapgen/mg_biome.h | 6 +++--- src/mapgen/mg_decoration.cpp | 6 ++---- src/mapgen/mg_decoration.h | 4 +++- src/mapgen/mg_ore.cpp | 28 ++++++++++++++-------------- src/mapgen/mg_ore.h | 22 ++++++++++++---------- src/script/lua_api/l_mapgen.cpp | 4 ++-- src/script/lua_api/l_mapgen.h | 2 ++ 11 files changed, 55 insertions(+), 45 deletions(-) (limited to 'src/mapgen') diff --git a/doc/lua_api.txt b/doc/lua_api.txt index 8b7c412ab..0101bd4cf 100644 --- a/doc/lua_api.txt +++ b/doc/lua_api.txt @@ -7443,6 +7443,10 @@ Biome definition Used by `minetest.register_biome`. +The maximum number of biomes that can be used is 65535. However, using an +excessive number of biomes will slow down map generation. Depending on desired +performance and computing power the practical limit is much lower. + { name = "tundra", diff --git a/src/mapgen/cavegen.cpp b/src/mapgen/cavegen.cpp index a9df4506f..340079821 100644 --- a/src/mapgen/cavegen.cpp +++ b/src/mapgen/cavegen.cpp @@ -1,8 +1,8 @@ /* Minetest -Copyright (C) 2010-2018 celeron55, Perttu Ahola -Copyright (C) 2010-2018 kwolekr, Ryan Kwolek -Copyright (C) 2015-2018 paramat +Copyright (C) 2010-2020 celeron55, Perttu Ahola +Copyright (C) 2015-2020 paramat +Copyright (C) 2010-2016 kwolekr, Ryan Kwolek 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 @@ -69,7 +69,7 @@ CavesNoiseIntersection::~CavesNoiseIntersection() void CavesNoiseIntersection::generateCaves(MMVManip *vm, - v3s16 nmin, v3s16 nmax, u8 *biomemap) + v3s16 nmin, v3s16 nmax, biome_t *biomemap) { assert(vm); assert(biomemap); diff --git a/src/mapgen/cavegen.h b/src/mapgen/cavegen.h index ff09f9423..d678d365b 100644 --- a/src/mapgen/cavegen.h +++ b/src/mapgen/cavegen.h @@ -1,7 +1,7 @@ /* Minetest -Copyright (C) 2010-2018 kwolekr, Ryan Kwolek -Copyright (C) 2015-2018 paramat +Copyright (C) 2015-2020 paramat +Copyright (C) 2010-2016 kwolekr, Ryan Kwolek 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 @@ -22,6 +22,8 @@ with this program; if not, write to the Free Software Foundation, Inc., #define VMANIP_FLAG_CAVE VOXELFLAG_CHECKED1 +typedef u16 biome_t; // copy from mg_biome.h to avoid an unnecessary include + class GenerateNotifier; /* @@ -44,7 +46,7 @@ public: NoiseParams *np_cave2, s32 seed, float cave_width); ~CavesNoiseIntersection(); - void generateCaves(MMVManip *vm, v3s16 nmin, v3s16 nmax, u8 *biomemap); + void generateCaves(MMVManip *vm, v3s16 nmin, v3s16 nmax, biome_t *biomemap); private: const NodeDefManager *m_ndef; diff --git a/src/mapgen/mapgen.h b/src/mapgen/mapgen.h index 7845c5349..a92b3b0d0 100644 --- a/src/mapgen/mapgen.h +++ b/src/mapgen/mapgen.h @@ -1,8 +1,8 @@ /* Minetest -Copyright (C) 2010-2018 celeron55, Perttu Ahola -Copyright (C) 2013-2018 kwolekr, Ryan Kwolek -Copyright (C) 2015-2018 paramat +Copyright (C) 2010-2020 celeron55, Perttu Ahola +Copyright (C) 2015-2020 paramat +Copyright (C) 2013-2016 kwolekr, Ryan Kwolek 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 @@ -38,7 +38,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #define MG_DECORATIONS 0x20 #define MG_BIOMES 0x40 -typedef u8 biome_t; // copy from mg_biome.h to avoid an unnecessary include +typedef u16 biome_t; // copy from mg_biome.h to avoid an unnecessary include class Settings; class MMVManip; diff --git a/src/mapgen/mg_biome.h b/src/mapgen/mg_biome.h index 57f4aa20d..be4cfea4d 100644 --- a/src/mapgen/mg_biome.h +++ b/src/mapgen/mg_biome.h @@ -1,7 +1,7 @@ /* Minetest -Copyright (C) 2014-2018 kwolekr, Ryan Kwolek -Copyright (C) 2014-2018 paramat +Copyright (C) 2014-2020 paramat +Copyright (C) 2014-2016 kwolekr, Ryan Kwolek 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 @@ -32,7 +32,7 @@ class BiomeManager; //// Biome //// -typedef u8 biome_t; +typedef u16 biome_t; #define BIOME_NONE ((biome_t)0) diff --git a/src/mapgen/mg_decoration.cpp b/src/mapgen/mg_decoration.cpp index a9b67d239..a4cada396 100644 --- a/src/mapgen/mg_decoration.cpp +++ b/src/mapgen/mg_decoration.cpp @@ -206,8 +206,7 @@ size_t Decoration::placeDeco(Mapgen *mg, u32 blockseed, v3s16 nmin, v3s16 nmax) // All-surfaces decorations // Check biome of column if (mg->biomemap && !biomes.empty()) { - std::unordered_set::const_iterator iter = - biomes.find(mg->biomemap[mapindex]); + auto iter = biomes.find(mg->biomemap[mapindex]); if (iter == biomes.end()) continue; } @@ -259,8 +258,7 @@ size_t Decoration::placeDeco(Mapgen *mg, u32 blockseed, v3s16 nmin, v3s16 nmax) continue; if (mg->biomemap && !biomes.empty()) { - std::unordered_set::const_iterator iter = - biomes.find(mg->biomemap[mapindex]); + auto iter = biomes.find(mg->biomemap[mapindex]); if (iter == biomes.end()) continue; } diff --git a/src/mapgen/mg_decoration.h b/src/mapgen/mg_decoration.h index 1f9eb4510..1ea02a527 100644 --- a/src/mapgen/mg_decoration.h +++ b/src/mapgen/mg_decoration.h @@ -25,6 +25,8 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "noise.h" #include "nodedef.h" +typedef u16 biome_t; // copy from mg_biome.h to avoid an unnecessary include + class Mapgen; class MMVManip; class PcgRandom; @@ -72,7 +74,7 @@ public: s16 nspawnby; s16 place_offset_y = 0; - std::unordered_set biomes; + std::unordered_set biomes; protected: void cloneTo(Decoration *def) const; diff --git a/src/mapgen/mg_ore.cpp b/src/mapgen/mg_ore.cpp index db647f82b..b50ed6a32 100644 --- a/src/mapgen/mg_ore.cpp +++ b/src/mapgen/mg_ore.cpp @@ -1,7 +1,7 @@ /* Minetest -Copyright (C) 2014-2018 kwolekr, Ryan Kwolek -Copyright (C) 2015-2018 paramat +Copyright (C) 2015-2020 paramat +Copyright (C) 2014-2016 kwolekr, Ryan Kwolek 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 @@ -146,7 +146,7 @@ ObjDef *OreScatter::clone() const void OreScatter::generate(MMVManip *vm, int mapseed, u32 blockseed, - v3s16 nmin, v3s16 nmax, u8 *biomemap) + v3s16 nmin, v3s16 nmax, biome_t *biomemap) { PcgRandom pr(blockseed); MapNode n_ore(c_ore, 0, ore_param2); @@ -170,7 +170,7 @@ void OreScatter::generate(MMVManip *vm, int mapseed, u32 blockseed, if (biomemap && !biomes.empty()) { u32 index = sizex * (z0 - nmin.Z) + (x0 - nmin.X); - std::unordered_set::const_iterator it = biomes.find(biomemap[index]); + auto it = biomes.find(biomemap[index]); if (it == biomes.end()) continue; } @@ -208,7 +208,7 @@ ObjDef *OreSheet::clone() const void OreSheet::generate(MMVManip *vm, int mapseed, u32 blockseed, - v3s16 nmin, v3s16 nmax, u8 *biomemap) + v3s16 nmin, v3s16 nmax, biome_t *biomemap) { PcgRandom pr(blockseed + 4234); MapNode n_ore(c_ore, 0, ore_param2); @@ -237,7 +237,7 @@ void OreSheet::generate(MMVManip *vm, int mapseed, u32 blockseed, continue; if (biomemap && !biomes.empty()) { - std::unordered_set::const_iterator it = biomes.find(biomemap[index]); + auto it = biomes.find(biomemap[index]); if (it == biomes.end()) continue; } @@ -285,7 +285,7 @@ ObjDef *OrePuff::clone() const void OrePuff::generate(MMVManip *vm, int mapseed, u32 blockseed, - v3s16 nmin, v3s16 nmax, u8 *biomemap) + v3s16 nmin, v3s16 nmax, biome_t *biomemap) { PcgRandom pr(blockseed + 4234); MapNode n_ore(c_ore, 0, ore_param2); @@ -312,7 +312,7 @@ void OrePuff::generate(MMVManip *vm, int mapseed, u32 blockseed, continue; if (biomemap && !biomes.empty()) { - std::unordered_set::const_iterator it = biomes.find(biomemap[index]); + auto it = biomes.find(biomemap[index]); if (it == biomes.end()) continue; } @@ -366,7 +366,7 @@ ObjDef *OreBlob::clone() const void OreBlob::generate(MMVManip *vm, int mapseed, u32 blockseed, - v3s16 nmin, v3s16 nmax, u8 *biomemap) + v3s16 nmin, v3s16 nmax, biome_t *biomemap) { PcgRandom pr(blockseed + 2404); MapNode n_ore(c_ore, 0, ore_param2); @@ -388,7 +388,7 @@ void OreBlob::generate(MMVManip *vm, int mapseed, u32 blockseed, if (biomemap && !biomes.empty()) { u32 bmapidx = sizex * (z0 - nmin.Z) + (x0 - nmin.X); - std::unordered_set::const_iterator it = biomes.find(biomemap[bmapidx]); + auto it = biomes.find(biomemap[bmapidx]); if (it == biomes.end()) continue; } @@ -451,7 +451,7 @@ ObjDef *OreVein::clone() const void OreVein::generate(MMVManip *vm, int mapseed, u32 blockseed, - v3s16 nmin, v3s16 nmax, u8 *biomemap) + v3s16 nmin, v3s16 nmax, biome_t *biomemap) { PcgRandom pr(blockseed + 520); MapNode n_ore(c_ore, 0, ore_param2); @@ -485,7 +485,7 @@ void OreVein::generate(MMVManip *vm, int mapseed, u32 blockseed, if (biomemap && !biomes.empty()) { u32 bmapidx = sizex * (z - nmin.Z) + (x - nmin.X); - std::unordered_set::const_iterator it = biomes.find(biomemap[bmapidx]); + auto it = biomes.find(biomemap[bmapidx]); if (it == biomes.end()) continue; } @@ -532,7 +532,7 @@ ObjDef *OreStratum::clone() const void OreStratum::generate(MMVManip *vm, int mapseed, u32 blockseed, - v3s16 nmin, v3s16 nmax, u8 *biomemap) + v3s16 nmin, v3s16 nmax, biome_t *biomemap) { PcgRandom pr(blockseed + 4234); MapNode n_ore(c_ore, 0, ore_param2); @@ -560,7 +560,7 @@ void OreStratum::generate(MMVManip *vm, int mapseed, u32 blockseed, for (int z = nmin.Z; z <= nmax.Z; z++) for (int x = nmin.X; x <= nmax.X; x++, index++) { if (biomemap && !biomes.empty()) { - std::unordered_set::const_iterator it = biomes.find(biomemap[index]); + auto it = biomes.find(biomemap[index]); if (it == biomes.end()) continue; } diff --git a/src/mapgen/mg_ore.h b/src/mapgen/mg_ore.h index 213bdc964..76420fab4 100644 --- a/src/mapgen/mg_ore.h +++ b/src/mapgen/mg_ore.h @@ -1,7 +1,7 @@ /* Minetest -Copyright (C) 2014-2018 kwolekr, Ryan Kwolek -Copyright (C) 2015-2018 paramat +Copyright (C) 2015-2020 paramat +Copyright (C) 2014-2016 kwolekr, Ryan Kwolek 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 @@ -25,6 +25,8 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "noise.h" #include "nodedef.h" +typedef u16 biome_t; // copy from mg_biome.h to avoid an unnecessary include + class Noise; class Mapgen; class MMVManip; @@ -64,7 +66,7 @@ public: float nthresh; // threshold for noise at which an ore is placed NoiseParams np; // noise for distribution of clusters (NULL for uniform scattering) Noise *noise = nullptr; - std::unordered_set biomes; + std::unordered_set biomes; Ore() = default;; virtual ~Ore(); @@ -73,7 +75,7 @@ public: size_t placeOre(Mapgen *mg, u32 blockseed, v3s16 nmin, v3s16 nmax); virtual void generate(MMVManip *vm, int mapseed, u32 blockseed, - v3s16 nmin, v3s16 nmax, u8 *biomemap) = 0; + v3s16 nmin, v3s16 nmax, biome_t *biomemap) = 0; protected: void cloneTo(Ore *def) const; @@ -86,7 +88,7 @@ public: ObjDef *clone() const; virtual void generate(MMVManip *vm, int mapseed, u32 blockseed, - v3s16 nmin, v3s16 nmax, u8 *biomemap); + v3s16 nmin, v3s16 nmax, biome_t *biomemap); }; class OreSheet : public Ore { @@ -100,7 +102,7 @@ public: float column_midpoint_factor; virtual void generate(MMVManip *vm, int mapseed, u32 blockseed, - v3s16 nmin, v3s16 nmax, u8 *biomemap); + v3s16 nmin, v3s16 nmax, biome_t *biomemap); }; class OrePuff : public Ore { @@ -118,7 +120,7 @@ public: virtual ~OrePuff(); virtual void generate(MMVManip *vm, int mapseed, u32 blockseed, - v3s16 nmin, v3s16 nmax, u8 *biomemap); + v3s16 nmin, v3s16 nmax, biome_t *biomemap); }; class OreBlob : public Ore { @@ -128,7 +130,7 @@ public: ObjDef *clone() const; virtual void generate(MMVManip *vm, int mapseed, u32 blockseed, - v3s16 nmin, v3s16 nmax, u8 *biomemap); + v3s16 nmin, v3s16 nmax, biome_t *biomemap); }; class OreVein : public Ore { @@ -145,7 +147,7 @@ public: virtual ~OreVein(); virtual void generate(MMVManip *vm, int mapseed, u32 blockseed, - v3s16 nmin, v3s16 nmax, u8 *biomemap); + v3s16 nmin, v3s16 nmax, biome_t *biomemap); }; class OreStratum : public Ore { @@ -162,7 +164,7 @@ public: virtual ~OreStratum(); virtual void generate(MMVManip *vm, int mapseed, u32 blockseed, - v3s16 nmin, v3s16 nmax, u8 *biomemap); + v3s16 nmin, v3s16 nmax, biome_t *biomemap); }; class OreManager : public ObjDefManager { diff --git a/src/script/lua_api/l_mapgen.cpp b/src/script/lua_api/l_mapgen.cpp index 584085428..834938e56 100644 --- a/src/script/lua_api/l_mapgen.cpp +++ b/src/script/lua_api/l_mapgen.cpp @@ -97,7 +97,7 @@ Biome *get_or_load_biome(lua_State *L, int index, BiomeManager *biomemgr); Biome *read_biome_def(lua_State *L, int index, const NodeDefManager *ndef); size_t get_biome_list(lua_State *L, int index, - BiomeManager *biomemgr, std::unordered_set *biome_id_list); + BiomeManager *biomemgr, std::unordered_set *biome_id_list); Schematic *get_or_load_schematic(lua_State *L, int index, SchematicManager *schemmgr, StringMap *replace_names); @@ -425,7 +425,7 @@ Biome *read_biome_def(lua_State *L, int index, const NodeDefManager *ndef) size_t get_biome_list(lua_State *L, int index, - BiomeManager *biomemgr, std::unordered_set *biome_id_list) + BiomeManager *biomemgr, std::unordered_set *biome_id_list) { if (index < 0) index = lua_gettop(L) + 1 + index; diff --git a/src/script/lua_api/l_mapgen.h b/src/script/lua_api/l_mapgen.h index 4a6a9ccf4..0bdc56fc5 100644 --- a/src/script/lua_api/l_mapgen.h +++ b/src/script/lua_api/l_mapgen.h @@ -21,6 +21,8 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "lua_api/l_base.h" +typedef u16 biome_t; // copy from mg_biome.h to avoid an unnecessary include + class ModApiMapgen : public ModApiBase { private: -- cgit v1.2.3 From b546e8938d41aa9e3101fb9d4d5b02924ed73b60 Mon Sep 17 00:00:00 2001 From: Paramat Date: Mon, 25 May 2020 21:11:57 +0100 Subject: L-System trees: Remove hardcoded use of 'mapgen_dirt' alias (#9931) Games often and increasingly do not use this mapgen alias, as it is only required for Mapgen V6. Such games were triggering the recently added error message. Even if this mapgen alias was defined, dirt nodes placed under a wide trunk were inconsistent with biomes that do not use dirt surface nodes. Place trunk nodes below a wide trunk instead of 'mapgen_dirt'. On sloping ground, the trunk then extends down to the surface, instead of the surface rising up to meet the trunk. This looks more natural and does not alter the terrain. --- src/mapgen/treegen.cpp | 36 ++++++++++++++++-------------------- 1 file changed, 16 insertions(+), 20 deletions(-) (limited to 'src/mapgen') diff --git a/src/mapgen/treegen.cpp b/src/mapgen/treegen.cpp index d538e15b4..e7e30c880 100644 --- a/src/mapgen/treegen.cpp +++ b/src/mapgen/treegen.cpp @@ -148,10 +148,6 @@ treegen::error spawn_ltree(ServerMap *map, v3s16 p0, treegen::error make_ltree(MMVManip &vmanip, v3s16 p0, const NodeDefManager *ndef, TreeDef tree_definition) { - MapNode dirtnode(ndef->getId("mapgen_dirt")); - if (dirtnode == CONTENT_IGNORE) - errorstream << "Treegen (make_ltree): Mapgen alias 'mapgen_dirt' is invalid!" << std::endl; - s32 seed; if (tree_definition.explicit_seed) seed = tree_definition.seed + 14002; @@ -229,43 +225,43 @@ treegen::error make_ltree(MMVManip &vmanip, v3s16 p0, axiom = temp; } - //make sure tree is not floating in the air + // Add trunk nodes below a wide trunk to avoid gaps when tree is on sloping ground if (tree_definition.trunk_type == "double") { - tree_node_placement( + tree_trunk_placement( vmanip, v3f(position.X + 1, position.Y - 1, position.Z), - dirtnode + tree_definition ); - tree_node_placement( + tree_trunk_placement( vmanip, v3f(position.X, position.Y - 1, position.Z + 1), - dirtnode + tree_definition ); - tree_node_placement( + tree_trunk_placement( vmanip, v3f(position.X + 1, position.Y - 1, position.Z + 1), - dirtnode + tree_definition ); } else if (tree_definition.trunk_type == "crossed") { - tree_node_placement( + tree_trunk_placement( vmanip, v3f(position.X + 1, position.Y - 1, position.Z), - dirtnode + tree_definition ); - tree_node_placement( + tree_trunk_placement( vmanip, v3f(position.X - 1, position.Y - 1, position.Z), - dirtnode + tree_definition ); - tree_node_placement( + tree_trunk_placement( vmanip, v3f(position.X, position.Y - 1, position.Z + 1), - dirtnode + tree_definition ); - tree_node_placement( + tree_trunk_placement( vmanip, v3f(position.X, position.Y - 1, position.Z - 1), - dirtnode + tree_definition ); } @@ -372,7 +368,7 @@ treegen::error make_ltree(MMVManip &vmanip, v3s16 p0, !tree_definition.thin_branches)) { tree_trunk_placement( vmanip, - v3f(position.X +1 , position.Y, position.Z), + v3f(position.X + 1, position.Y, position.Z), tree_definition ); tree_trunk_placement( -- cgit v1.2.3