From 8be64408bf3b570fe6bd7be7eb1e72c951726904 Mon Sep 17 00:00:00 2001 From: Aokromes Date: Wed, 13 Mar 2024 02:37:18 +0100 Subject: [PATCH 01/19] DB/Misc: Kill runtime error when someone fishes on Violet Hold. --- sql/updates/world/3.3.5/2024_03_13_00_world.sql | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 sql/updates/world/3.3.5/2024_03_13_00_world.sql diff --git a/sql/updates/world/3.3.5/2024_03_13_00_world.sql b/sql/updates/world/3.3.5/2024_03_13_00_world.sql new file mode 100644 index 0000000000..102c2290eb --- /dev/null +++ b/sql/updates/world/3.3.5/2024_03_13_00_world.sql @@ -0,0 +1,3 @@ +DELETE FROM skill_fishing_base_level WHERE entry=4415; +INSERT INTO skill_fishing_base_level (entry, skill) +VALUES (4415, 550) From b0eee5589795da55ac7235cb4322fa81699df56f Mon Sep 17 00:00:00 2001 From: Shauren Date: Mon, 11 Mar 2024 18:16:34 +0100 Subject: [PATCH 02/19] Core/Utils: Added a custom smart pointer type unique_trackable_ptr - a specialized variant of std::shared_ptr that enforces unique ownership * This is intended to be used by external code unable to track object lifetime such as custom scripting engines (cherry picked from commit 32e54b6bd168c196adb45360b18721851162d731) --- src/common/Utilities/UniqueTrackablePtr.h | 274 ++++++++++++++++++++++ tests/common/UniqueTrackablePtr.cpp | 90 +++++++ 2 files changed, 364 insertions(+) create mode 100644 src/common/Utilities/UniqueTrackablePtr.h create mode 100644 tests/common/UniqueTrackablePtr.cpp diff --git a/src/common/Utilities/UniqueTrackablePtr.h b/src/common/Utilities/UniqueTrackablePtr.h new file mode 100644 index 0000000000..0a09ead1ee --- /dev/null +++ b/src/common/Utilities/UniqueTrackablePtr.h @@ -0,0 +1,274 @@ +/* + * This file is part of the TrinityCore Project. See AUTHORS file for Copyright information + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 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 General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + */ + +#ifndef TRINITYCORE_UNIQUE_TRACKING_PTR_H +#define TRINITYCORE_UNIQUE_TRACKING_PTR_H + +#include "Define.h" +#include + +namespace Trinity +{ +template > +class unique_trackable_ptr; + +template +class unique_weak_ptr; + +template +class unique_strong_ref_ptr; + +/** + * \brief Specialized variant of std::shared_ptr that enforces unique ownership and/or std::unique_ptr with std::weak_ptr capabilities + * Implementation has the same overhead as a std::shared_ptr, that is, a separate allocation for control block that holds use counters + * \tparam T Type of held object + * \tparam Deleter Object deleter (defaults to std::default_delete) + */ +template +class unique_trackable_ptr +{ +public: + using element_type = T; + using pointer = T*; + using deleter_type = Deleter; + + unique_trackable_ptr() : _ptr(nullptr, deleter_type()) { } + + explicit unique_trackable_ptr(pointer ptr) : _ptr(ptr, deleter_type()) { } + + explicit unique_trackable_ptr(pointer ptr, deleter_type deleter) : _ptr(ptr, std::move(deleter)) { } + + unique_trackable_ptr(unique_trackable_ptr const&) = delete; + + unique_trackable_ptr(unique_trackable_ptr&& other) noexcept + : _ptr(std::move(other._ptr)) { } + + unique_trackable_ptr& operator=(unique_trackable_ptr const&) = delete; + + unique_trackable_ptr& operator=(unique_trackable_ptr&& other) noexcept + { + _ptr = std::move(other); + return *this; + } + + ~unique_trackable_ptr() = default; + + unique_trackable_ptr& operator=(std::nullptr_t) + { + reset(); + return *this; + } + + void swap(unique_trackable_ptr& other) noexcept + { + using std::swap; + swap(_ptr, other._ptr); + } + + element_type& operator*() const + { + return *_ptr; + } + + pointer operator->() const + { + return _ptr.operator->(); + } + + pointer get() const + { + return _ptr.get(); + } + + explicit operator bool() const + { + return static_cast(_ptr); + } + + void reset(pointer ptr = nullptr, deleter_type deleter = {}) + { + _ptr.reset(ptr, std::move(deleter)); + } + +private: + template + friend class unique_weak_ptr; + + template + friend std::enable_if_t, unique_trackable_ptr> make_unique_trackable(Args&&... args); + + template + friend std::enable_if_t, unique_trackable_ptr> make_unique_trackable(std::size_t N); + + template + friend std::enable_if_t, unique_trackable_ptr> make_unique_trackable(std::size_t N, std::remove_extent_t const& val); + + template + friend std::enable_if_t, unique_trackable_ptr> make_unique_trackable(); + + template + friend std::enable_if_t, unique_trackable_ptr> make_unique_trackable(std::remove_extent_t const& val); + + std::shared_ptr _ptr; +}; + +/** + * \brief Trinity::unique_trackable_ptr companion class, replicating what std::weak_ptr is to std::shared_ptr + * \tparam T Type of held object + */ +template +class unique_weak_ptr +{ +public: + using element_type = T; + using pointer = T*; + + unique_weak_ptr() = default; + + template + unique_weak_ptr(unique_trackable_ptr const& trackable) : _ptr(trackable._ptr) + { + } + + unique_weak_ptr(unique_weak_ptr const& other) = default; + unique_weak_ptr(unique_weak_ptr&& other) noexcept = default; + + template + unique_weak_ptr& operator=(unique_trackable_ptr const& trackable) + { + _ptr = trackable._ptr; + return *this; + } + + unique_weak_ptr& operator=(unique_weak_ptr const& other) = default; + unique_weak_ptr& operator=(unique_weak_ptr&& other) noexcept = default; + + ~unique_weak_ptr() = default; + + void swap(unique_weak_ptr& other) noexcept + { + using std::swap; + swap(_ptr, other._ptr); + } + + bool expired() const + { + return _ptr.expired(); + } + + unique_strong_ref_ptr lock() const + { + return unique_strong_ref_ptr(_ptr.lock()); + } + +private: + std::weak_ptr _ptr; +}; + +/** + * \brief Result of unique_weak_ptr::lock() function, this class holds a temporary strong reference to held object + * to prevent it from being deallocated by another thread while it is being actively accessed. + * This class is non-movable and non-copypable and is intended only for short lived local variables + * \tparam T Type of held object + */ +template +class unique_strong_ref_ptr +{ +public: + using element_type = T; + using pointer = T*; + + unique_strong_ref_ptr(unique_strong_ref_ptr const&) = delete; + unique_strong_ref_ptr(unique_strong_ref_ptr&&) = delete; + unique_strong_ref_ptr& operator=(unique_strong_ref_ptr const&) = delete; + unique_strong_ref_ptr& operator=(unique_strong_ref_ptr&&) = delete; + + ~unique_strong_ref_ptr() = default; + + element_type& operator*() const + { + return *_ptr; + } + + pointer operator->() const + { + return _ptr.operator->(); + } + + pointer get() const + { + return _ptr.get(); + } + + explicit operator bool() const + { + return static_cast(_ptr); + } + + friend std::strong_ordering operator<=>(unique_strong_ref_ptr const&, unique_strong_ref_ptr const&) = default; + +private: + template + friend class unique_weak_ptr; + + unique_strong_ref_ptr(std::shared_ptr ptr) : _ptr(std::move(ptr)) { } + + std::shared_ptr _ptr; +}; + +template +std::enable_if_t, unique_trackable_ptr> make_unique_trackable(Args&&... args) +{ + unique_trackable_ptr ptr; + ptr._ptr = std::make_shared(std::forward(args)...); + return ptr; +} + +template +std::enable_if_t, unique_trackable_ptr> make_unique_trackable(std::size_t N) +{ + unique_trackable_ptr ptr; + ptr._ptr = std::make_shared(N); + return ptr; +} + +template +std::enable_if_t, unique_trackable_ptr> make_unique_trackable(std::size_t N, std::remove_extent_t const& val) +{ + unique_trackable_ptr ptr; + ptr._ptr = std::make_shared(N, val); + return ptr; +} + +template +std::enable_if_t, unique_trackable_ptr> make_unique_trackable() +{ + unique_trackable_ptr ptr; + ptr._ptr = std::make_shared(); + return ptr; +} + +template +std::enable_if_t, unique_trackable_ptr> make_unique_trackable(std::remove_extent_t const& val) +{ + unique_trackable_ptr ptr; + ptr._ptr = std::make_shared(val); + return ptr; +} +} + +#endif // TRINITYCORE_UNIQUE_TRACKING_PTR_H diff --git a/tests/common/UniqueTrackablePtr.cpp b/tests/common/UniqueTrackablePtr.cpp new file mode 100644 index 0000000000..6a1db9fa27 --- /dev/null +++ b/tests/common/UniqueTrackablePtr.cpp @@ -0,0 +1,90 @@ +/* + * This file is part of the TrinityCore Project. See AUTHORS file for Copyright information + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 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 General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + */ + +#include "tc_catch2.h" + +#include "UniqueTrackingPtr.h" + +struct TestObj +{ + TestObj(bool* deleted = nullptr) : Deleted(deleted) { } + + ~TestObj() + { + if (Deleted) + *Deleted = true; + } + + bool* Deleted = nullptr; +}; + +TEST_CASE("Trinity::unique_trackable_ptr frees memory", "[UniqueTrackingPtr]") +{ + bool deleted = false; + + SECTION("reassigning new object deletes old one") + { + Trinity::unique_trackable_ptr ptr = Trinity::make_unique_trackable(&deleted); + + ptr.reset(new TestObj()); + + REQUIRE(deleted == true); + } + + SECTION("going out of scope deletes object") + { + REQUIRE(deleted == false); + + { + Trinity::unique_trackable_ptr ptr = Trinity::make_unique_trackable(&deleted); + } + + REQUIRE(deleted == true); + } +} + +TEST_CASE("Trinity::unique_weak_ptr", "[UniqueTrackingPtr]") +{ + Trinity::unique_trackable_ptr ptr = Trinity::make_unique_trackable(); + + Trinity::unique_weak_ptr weakRef = ptr; + + SECTION("when unique_trackable_ptr no longer holds a value then weak cannot retrieve it") + { + ptr.reset(); + + REQUIRE(weakRef.expired()); + REQUIRE(!weakRef.lock()); + } + + SECTION("when unique_trackable_ptr is reassigned then weak cannot retrieve old value") + { + ptr.reset(new int); + + Trinity::unique_weak_ptr weakRef2 = ptr; + + REQUIRE(weakRef.expired()); + REQUIRE(!weakRef2.expired()); + REQUIRE(weakRef.lock() != weakRef2.lock()); + } + + SECTION("when unique_trackable_ptr holds a value then weak can retrieve it") + { + REQUIRE(!weakRef.expired()); + REQUIRE(!!weakRef.lock()); + } +} From e48cedb3ed3409552ab88022567cabddd705d51e Mon Sep 17 00:00:00 2001 From: Shauren Date: Mon, 11 Mar 2024 18:17:08 +0100 Subject: [PATCH 03/19] Core/Misc: Fixed windows nopch build (cherry picked from commit 261a237cfa159e52dbb7ec4ab9ae5a5c6257b9ef) --- cmake/compiler/msvc/settings.cmake | 6 ++++++ src/common/Define.h | 1 - 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/cmake/compiler/msvc/settings.cmake b/cmake/compiler/msvc/settings.cmake index 0132c45423..a8be99d6ba 100644 --- a/cmake/compiler/msvc/settings.cmake +++ b/cmake/compiler/msvc/settings.cmake @@ -111,6 +111,12 @@ message(STATUS "MSVC: Disabled NON-SECURE warnings") target_compile_definitions(trinity-compile-option-interface INTERFACE -D_CRT_NONSTDC_NO_WARNINGS) + +# Force math constants like M_PI to be available +target_compile_definitions(trinity-compile-option-interface + INTERFACE + -D_USE_MATH_DEFINES) + message(STATUS "MSVC: Disabled POSIX warnings") # Ignore specific warnings diff --git a/src/common/Define.h b/src/common/Define.h index d1780b33d0..1bcb89117f 100644 --- a/src/common/Define.h +++ b/src/common/Define.h @@ -56,7 +56,6 @@ #if TRINITY_PLATFORM == TRINITY_PLATFORM_WINDOWS # define TRINITY_PATH_MAX 260 -# define _USE_MATH_DEFINES #else // TRINITY_PLATFORM != TRINITY_PLATFORM_WINDOWS # define TRINITY_PATH_MAX PATH_MAX #endif // TRINITY_PLATFORM From 92547f4b3154dc3769f1f5d9d50b92ee19788c9e Mon Sep 17 00:00:00 2001 From: Shauren Date: Mon, 11 Mar 2024 18:25:17 +0100 Subject: [PATCH 04/19] Fix tests build (cherry picked from commit 1f3ebbb23cea1778ddc5ca52941861a98b667530) --- src/common/Utilities/UniqueTrackablePtr.h | 6 +++--- tests/common/UniqueTrackablePtr.cpp | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/common/Utilities/UniqueTrackablePtr.h b/src/common/Utilities/UniqueTrackablePtr.h index 0a09ead1ee..b3a747d4b0 100644 --- a/src/common/Utilities/UniqueTrackablePtr.h +++ b/src/common/Utilities/UniqueTrackablePtr.h @@ -15,8 +15,8 @@ * with this program. If not, see . */ -#ifndef TRINITYCORE_UNIQUE_TRACKING_PTR_H -#define TRINITYCORE_UNIQUE_TRACKING_PTR_H +#ifndef TRINITYCORE_UNIQUE_TRACKABLE_PTR_H +#define TRINITYCORE_UNIQUE_TRACKABLE_PTR_H #include "Define.h" #include @@ -271,4 +271,4 @@ std::enable_if_t, unique_trackable_ptr> make_uniqu } } -#endif // TRINITYCORE_UNIQUE_TRACKING_PTR_H +#endif // TRINITYCORE_UNIQUE_TRACKABLE_PTR_H diff --git a/tests/common/UniqueTrackablePtr.cpp b/tests/common/UniqueTrackablePtr.cpp index 6a1db9fa27..11fdb226ba 100644 --- a/tests/common/UniqueTrackablePtr.cpp +++ b/tests/common/UniqueTrackablePtr.cpp @@ -17,7 +17,7 @@ #include "tc_catch2.h" -#include "UniqueTrackingPtr.h" +#include "UniqueTrackablePtr.h" struct TestObj { @@ -32,7 +32,7 @@ struct TestObj bool* Deleted = nullptr; }; -TEST_CASE("Trinity::unique_trackable_ptr frees memory", "[UniqueTrackingPtr]") +TEST_CASE("Trinity::unique_trackable_ptr frees memory", "[UniqueTrackablePtr]") { bool deleted = false; @@ -57,7 +57,7 @@ TEST_CASE("Trinity::unique_trackable_ptr frees memory", "[UniqueTrackingPtr]") } } -TEST_CASE("Trinity::unique_weak_ptr", "[UniqueTrackingPtr]") +TEST_CASE("Trinity::unique_weak_ptr", "[UniqueTrackablePtr]") { Trinity::unique_trackable_ptr ptr = Trinity::make_unique_trackable(); From 9ebf232d7e7dd5df4f635b2573b03c21b277225b Mon Sep 17 00:00:00 2001 From: Shauren Date: Tue, 12 Mar 2024 21:02:28 +0100 Subject: [PATCH 05/19] Core/Utils: Added missing member access in unique_trackable_ptr move assignment operator (cherry picked from commit 6b255efb2dae561224b6ac1c02f4e6377ea39098) --- src/common/Utilities/UniqueTrackablePtr.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/common/Utilities/UniqueTrackablePtr.h b/src/common/Utilities/UniqueTrackablePtr.h index b3a747d4b0..b315bbd643 100644 --- a/src/common/Utilities/UniqueTrackablePtr.h +++ b/src/common/Utilities/UniqueTrackablePtr.h @@ -61,7 +61,7 @@ class unique_trackable_ptr unique_trackable_ptr& operator=(unique_trackable_ptr&& other) noexcept { - _ptr = std::move(other); + _ptr = std::move(other._ptr); return *this; } From e3ecd87a76bac891c233d16c1354376ab470ca8e Mon Sep 17 00:00:00 2001 From: Shauren Date: Wed, 13 Mar 2024 17:04:26 +0100 Subject: [PATCH 06/19] Core/Utils: unique_trackable_ptr improvements * Added comparison operators * Added type casting helper functions (cherry picked from commit f690b693386ef44754fa4528f3c565d563ad9468) --- src/common/Utilities/UniqueTrackablePtr.h | 252 ++++++++++++++++++++-- tests/common/UniqueTrackablePtr.cpp | 66 +++++- 2 files changed, 301 insertions(+), 17 deletions(-) diff --git a/src/common/Utilities/UniqueTrackablePtr.h b/src/common/Utilities/UniqueTrackablePtr.h index b315bbd643..7b1d9c236d 100644 --- a/src/common/Utilities/UniqueTrackablePtr.h +++ b/src/common/Utilities/UniqueTrackablePtr.h @@ -18,12 +18,11 @@ #ifndef TRINITYCORE_UNIQUE_TRACKABLE_PTR_H #define TRINITYCORE_UNIQUE_TRACKABLE_PTR_H -#include "Define.h" #include namespace Trinity { -template > +template class unique_trackable_ptr; template @@ -36,27 +35,32 @@ class unique_strong_ref_ptr; * \brief Specialized variant of std::shared_ptr that enforces unique ownership and/or std::unique_ptr with std::weak_ptr capabilities * Implementation has the same overhead as a std::shared_ptr, that is, a separate allocation for control block that holds use counters * \tparam T Type of held object - * \tparam Deleter Object deleter (defaults to std::default_delete) */ -template +template class unique_trackable_ptr { public: using element_type = T; using pointer = T*; - using deleter_type = Deleter; - unique_trackable_ptr() : _ptr(nullptr, deleter_type()) { } + unique_trackable_ptr() : _ptr() { } - explicit unique_trackable_ptr(pointer ptr) : _ptr(ptr, deleter_type()) { } + explicit unique_trackable_ptr(pointer ptr) + : _ptr(ptr) { } - explicit unique_trackable_ptr(pointer ptr, deleter_type deleter) : _ptr(ptr, std::move(deleter)) { } + template , std::is_invocable>, int> = 0> + explicit unique_trackable_ptr(pointer ptr, Deleter deleter) + : _ptr(ptr, std::move(deleter)) { } unique_trackable_ptr(unique_trackable_ptr const&) = delete; unique_trackable_ptr(unique_trackable_ptr&& other) noexcept : _ptr(std::move(other._ptr)) { } + template , int> = 0> + unique_trackable_ptr(unique_trackable_ptr&& other) noexcept + : _ptr(std::move(other)._ptr) { } + unique_trackable_ptr& operator=(unique_trackable_ptr const&) = delete; unique_trackable_ptr& operator=(unique_trackable_ptr&& other) noexcept @@ -65,6 +69,13 @@ class unique_trackable_ptr return *this; } + template , int> = 0> + unique_trackable_ptr& operator=(unique_trackable_ptr&& other) noexcept + { + _ptr = std::move(other)._ptr; + return *this; + } + ~unique_trackable_ptr() = default; unique_trackable_ptr& operator=(std::nullptr_t) @@ -99,12 +110,26 @@ class unique_trackable_ptr return static_cast(_ptr); } - void reset(pointer ptr = nullptr, deleter_type deleter = {}) + void reset() + { + _ptr.reset(); + } + + void reset(pointer ptr) + { + _ptr.reset(ptr); + } + + template , std::is_invocable>, int> = 0> + void reset(pointer ptr, Deleter deleter) { _ptr.reset(ptr, std::move(deleter)); } private: + template + friend class unique_trackable_ptr; + template friend class unique_weak_ptr; @@ -139,22 +164,36 @@ class unique_weak_ptr unique_weak_ptr() = default; - template - unique_weak_ptr(unique_trackable_ptr const& trackable) : _ptr(trackable._ptr) - { - } + unique_weak_ptr(unique_trackable_ptr const& trackable) + : _ptr(trackable._ptr) { } unique_weak_ptr(unique_weak_ptr const& other) = default; + + template , int> = 0> + unique_weak_ptr(unique_weak_ptr const& other) noexcept + : _ptr(other._ptr) { } + unique_weak_ptr(unique_weak_ptr&& other) noexcept = default; - template - unique_weak_ptr& operator=(unique_trackable_ptr const& trackable) + template , int> = 0> + unique_weak_ptr(unique_weak_ptr&& other) noexcept + : _ptr(std::move(other)._ptr) { } + + unique_weak_ptr& operator=(unique_trackable_ptr const& trackable) { _ptr = trackable._ptr; return *this; } unique_weak_ptr& operator=(unique_weak_ptr const& other) = default; + + template , int> = 0> + unique_weak_ptr& operator=(unique_weak_ptr&& other) + { + _ptr = std::move(other)._ptr; + return *this; + } + unique_weak_ptr& operator=(unique_weak_ptr&& other) noexcept = default; ~unique_weak_ptr() = default; @@ -176,6 +215,24 @@ class unique_weak_ptr } private: + template + friend class unique_weak_ptr; + + template + friend class unique_strong_ref_ptr; + + template + friend unique_weak_ptr static_pointer_cast(unique_weak_ptr const& other); + + template + friend unique_weak_ptr const_pointer_cast(unique_weak_ptr const& other); + + template + friend unique_weak_ptr reinterpret_pointer_cast(unique_weak_ptr const& other); + + template + friend unique_weak_ptr dynamic_pointer_cast(unique_weak_ptr const& other); + std::weak_ptr _ptr; }; @@ -219,17 +276,72 @@ class unique_strong_ref_ptr return static_cast(_ptr); } - friend std::strong_ordering operator<=>(unique_strong_ref_ptr const&, unique_strong_ref_ptr const&) = default; + operator unique_weak_ptr() const + { + unique_weak_ptr weak; + weak._ptr = _ptr; + return weak; + } private: template friend class unique_weak_ptr; + template + friend unique_strong_ref_ptr static_pointer_cast(unique_strong_ref_ptr const& other); + + template + friend unique_strong_ref_ptr static_pointer_cast(unique_strong_ref_ptr&& other); + + template + friend unique_strong_ref_ptr const_pointer_cast(unique_strong_ref_ptr const& other); + + template + friend unique_strong_ref_ptr const_pointer_cast(unique_strong_ref_ptr&& other); + + template + friend unique_strong_ref_ptr reinterpret_pointer_cast(unique_strong_ref_ptr const& other); + + template + friend unique_strong_ref_ptr reinterpret_pointer_cast(unique_strong_ref_ptr&& other); + + template + friend unique_strong_ref_ptr dynamic_pointer_cast(unique_strong_ref_ptr const& other); + + template + friend unique_strong_ref_ptr dynamic_pointer_cast(unique_strong_ref_ptr&& other); + unique_strong_ref_ptr(std::shared_ptr ptr) : _ptr(std::move(ptr)) { } std::shared_ptr _ptr; }; +// unique_trackable_ptr funcions + +template +bool operator==(unique_trackable_ptr const& left, unique_trackable_ptr const& right) +{ + return left.get() == right.get(); +} + +template +std::strong_ordering operator<=>(unique_trackable_ptr const& left, unique_trackable_ptr const& right) +{ + return left.get() <=> right.get(); +} + +template +bool operator==(unique_trackable_ptr const& left, std::nullptr_t) +{ + return left.get() == nullptr; +} + +template +std::strong_ordering operator<=>(unique_trackable_ptr const& left, std::nullptr_t) +{ + return left.get() <=> nullptr; +} + template std::enable_if_t, unique_trackable_ptr> make_unique_trackable(Args&&... args) { @@ -269,6 +381,114 @@ std::enable_if_t, unique_trackable_ptr> make_uniqu ptr._ptr = std::make_shared(val); return ptr; } + +// unique_weak_ptr funcions + +template +unique_weak_ptr static_pointer_cast(unique_weak_ptr const& other) +{ + unique_weak_ptr to; + to._ptr = std::static_pointer_cast(other._ptr.lock()); + return to; +} + +template +unique_weak_ptr const_pointer_cast(unique_weak_ptr const& other) +{ + unique_weak_ptr to; + to._ptr = std::const_pointer_cast(other._ptr.lock()); + return to; +} + +template +unique_weak_ptr reinterpret_pointer_cast(unique_weak_ptr const& other) +{ + unique_weak_ptr to; + to._ptr = std::reinterpret_pointer_cast(other._ptr.lock()); + return to; +} + +template +unique_weak_ptr dynamic_pointer_cast(unique_weak_ptr const& other) +{ + unique_weak_ptr to; + to._ptr = std::dynamic_pointer_cast(other._ptr.lock()); + return to; +} + +// unique_strong_ref_ptr funcions + +template +bool operator==(unique_strong_ref_ptr const& left, unique_strong_ref_ptr const& right) +{ + return left.get() == right.get(); +} + +template +std::strong_ordering operator<=>(unique_strong_ref_ptr const& left, unique_strong_ref_ptr const& right) +{ + return left.get() <=> right.get(); +} + +template +bool operator==(unique_strong_ref_ptr const& left, std::nullptr_t) +{ + return left.get() == nullptr; +} + +template +std::strong_ordering operator<=>(unique_strong_ref_ptr const& left, std::nullptr_t) +{ + return left.get() <=> nullptr; +} + +template +unique_strong_ref_ptr static_pointer_cast(unique_strong_ref_ptr const& other) +{ + return unique_strong_ref_ptr(std::static_pointer_cast(other._ptr)); +} + +template +unique_strong_ref_ptr static_pointer_cast(unique_strong_ref_ptr&& other) +{ + return unique_strong_ref_ptr(std::static_pointer_cast(std::move(other._ptr))); +} + +template +unique_strong_ref_ptr const_pointer_cast(unique_strong_ref_ptr const& other) +{ + return unique_strong_ref_ptr(std::const_pointer_cast(other._ptr)); +} + +template +unique_strong_ref_ptr const_pointer_cast(unique_strong_ref_ptr&& other) +{ + return unique_strong_ref_ptr(std::const_pointer_cast(std::move(other._ptr))); +} + +template +unique_strong_ref_ptr reinterpret_pointer_cast(unique_strong_ref_ptr const& other) +{ + return unique_strong_ref_ptr(std::reinterpret_pointer_cast(other._ptr)); +} + +template +unique_strong_ref_ptr reinterpret_pointer_cast(unique_strong_ref_ptr&& other) +{ + return unique_strong_ref_ptr(std::reinterpret_pointer_cast(std::move(other._ptr))); +} + +template +unique_strong_ref_ptr dynamic_pointer_cast(unique_strong_ref_ptr const& other) +{ + return unique_strong_ref_ptr(std::dynamic_pointer_cast(other._ptr)); +} + +template +unique_strong_ref_ptr dynamic_pointer_cast(unique_strong_ref_ptr&& other) +{ + return unique_strong_ref_ptr(std::dynamic_pointer_cast(std::move(other._ptr))); +} } #endif // TRINITYCORE_UNIQUE_TRACKABLE_PTR_H diff --git a/tests/common/UniqueTrackablePtr.cpp b/tests/common/UniqueTrackablePtr.cpp index 11fdb226ba..3ab4cee1a5 100644 --- a/tests/common/UniqueTrackablePtr.cpp +++ b/tests/common/UniqueTrackablePtr.cpp @@ -23,7 +23,7 @@ struct TestObj { TestObj(bool* deleted = nullptr) : Deleted(deleted) { } - ~TestObj() + virtual ~TestObj() { if (Deleted) *Deleted = true; @@ -32,6 +32,21 @@ struct TestObj bool* Deleted = nullptr; }; +struct TestObj2 +{ + virtual ~TestObj2() = default; + + int a = 5; +}; + +struct TestObj3 : public TestObj2, public TestObj +{ +}; + +struct TestObj4 : public TestObj +{ +}; + TEST_CASE("Trinity::unique_trackable_ptr frees memory", "[UniqueTrackablePtr]") { bool deleted = false; @@ -88,3 +103,52 @@ TEST_CASE("Trinity::unique_weak_ptr", "[UniqueTrackablePtr]") REQUIRE(!!weakRef.lock()); } } + +TEST_CASE("Trinity::unique_strong_ref_ptr type casts", "[UniqueTrackablePtr]") +{ + Trinity::unique_trackable_ptr ptr = Trinity::make_unique_trackable(); + + Trinity::unique_weak_ptr weak = ptr; + + Trinity::unique_strong_ref_ptr temp = weak.lock(); + REQUIRE(temp != nullptr); + + SECTION("static_pointer_cast") + { + Trinity::unique_strong_ref_ptr testObj2 = Trinity::static_pointer_cast(temp); + + REQUIRE(testObj2.get() == static_cast(ptr.get())); + + // sanity check that we didn't accidentally setup inheritance of TestObjs incorrectly + REQUIRE(testObj2.get() != reinterpret_cast(ptr.get())); + + REQUIRE(testObj2 == Trinity::static_pointer_cast(weak).lock()); + } + + SECTION("reinterpret_pointer_cast") + { + Trinity::unique_strong_ref_ptr testObj2 = Trinity::reinterpret_pointer_cast(temp); + + REQUIRE(testObj2.get() == reinterpret_cast(ptr.get())); + + REQUIRE(testObj2 == Trinity::reinterpret_pointer_cast(weak).lock()); + } + + SECTION("succeeding dynamic_pointer_cast") + { + Trinity::unique_strong_ref_ptr testObj2 = Trinity::dynamic_pointer_cast(temp); + + REQUIRE(testObj2.get() == dynamic_cast(ptr.get())); + + REQUIRE(testObj2 == Trinity::dynamic_pointer_cast(weak).lock()); + } + + SECTION("failing dynamic_pointer_cast") + { + Trinity::unique_strong_ref_ptr testObj2 = Trinity::dynamic_pointer_cast(temp); + + REQUIRE(testObj2 == nullptr); + + REQUIRE(testObj2 == Trinity::dynamic_pointer_cast(weak).lock()); + } +} From 668932cf1d6d27f546b0ab8d2aea173454faf187 Mon Sep 17 00:00:00 2001 From: Shauren Date: Wed, 13 Mar 2024 18:17:04 +0100 Subject: [PATCH 07/19] Tests: Disable intentionally triggered warning in test code (cherry picked from commit 37899f395476c5f1c9d092a8f8425d2a379eeac7) --- tests/common/UniqueTrackablePtr.cpp | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/tests/common/UniqueTrackablePtr.cpp b/tests/common/UniqueTrackablePtr.cpp index 3ab4cee1a5..a6de1d68ce 100644 --- a/tests/common/UniqueTrackablePtr.cpp +++ b/tests/common/UniqueTrackablePtr.cpp @@ -17,6 +17,7 @@ #include "tc_catch2.h" +#include "CompilerDefs.h" #include "UniqueTrackablePtr.h" struct TestObj @@ -104,6 +105,12 @@ TEST_CASE("Trinity::unique_weak_ptr", "[UniqueTrackablePtr]") } } +// disable warning about invalid reinterpret_cast, test intentionally tests this +#if TRINITY_COMPILER == TRINITY_COMPILER_GNU +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wreinterpret-base-class" +#endif + TEST_CASE("Trinity::unique_strong_ref_ptr type casts", "[UniqueTrackablePtr]") { Trinity::unique_trackable_ptr ptr = Trinity::make_unique_trackable(); @@ -152,3 +159,7 @@ TEST_CASE("Trinity::unique_strong_ref_ptr type casts", "[UniqueTrackablePtr]") REQUIRE(testObj2 == Trinity::dynamic_pointer_cast(weak).lock()); } } + +#if TRINITY_COMPILER == TRINITY_COMPILER_GNU +#pragma GCC diagnostic pop +#endif From 7850107a42e7709f6e92f542860160b8c1432c94 Mon Sep 17 00:00:00 2001 From: Shauren Date: Wed, 13 Mar 2024 18:19:22 +0100 Subject: [PATCH 08/19] Core/vmaps: Reset BIH::bounds on tree rebuilds (cherry picked from commit 18200e1b88596dbead10d0b8ecbd10557db43323) --- src/common/Collision/BoundingIntervalHierarchy.h | 1 + 1 file changed, 1 insertion(+) diff --git a/src/common/Collision/BoundingIntervalHierarchy.h b/src/common/Collision/BoundingIntervalHierarchy.h index 382d8abdf7..a5717637a3 100644 --- a/src/common/Collision/BoundingIntervalHierarchy.h +++ b/src/common/Collision/BoundingIntervalHierarchy.h @@ -70,6 +70,7 @@ class TC_COMMON_API BIH { tree.clear(); objects.clear(); + bounds = G3D::AABox::empty(); // create space for the first node tree.push_back(3u << 30u); // dummy leaf tree.insert(tree.end(), 2, 0); From a79b42bf681e211997923dbc6c191aae187aded6 Mon Sep 17 00:00:00 2001 From: Shauren Date: Wed, 13 Mar 2024 18:51:29 +0100 Subject: [PATCH 09/19] Core/Misc: Use our new unique_trackable_ptr for various classes exposed to scripts (not actually used anywhere currently) (cherry picked from commit 4779fa5048642b57a0f69de7ab56b9d563c1cbc4) --- .../game/Battlegrounds/Battleground.cpp | 1 - src/server/game/Battlegrounds/Battleground.h | 6 +++ .../game/Battlegrounds/BattlegroundMgr.cpp | 38 +++++++------------ .../game/Battlegrounds/BattlegroundMgr.h | 9 ++++- src/server/game/Entities/Object/Object.cpp | 9 ++++- src/server/game/Entities/Object/Object.h | 7 ++++ src/server/game/Entities/Player/Player.cpp | 2 +- src/server/game/Entities/Unit/Unit.cpp | 14 ++++--- src/server/game/Entities/Unit/Unit.h | 5 ++- src/server/game/Entities/Vehicle/Vehicle.cpp | 5 +++ src/server/game/Entities/Vehicle/Vehicle.h | 11 +++--- src/server/game/Globals/ObjectMgr.cpp | 18 +++++---- src/server/game/Globals/ObjectMgr.h | 3 +- src/server/game/Groups/Group.cpp | 3 +- src/server/game/Groups/Group.h | 6 +++ src/server/game/Guilds/Guild.cpp | 31 +++++++-------- src/server/game/Guilds/Guild.h | 8 +++- src/server/game/Guilds/GuildMgr.cpp | 26 ++++++------- src/server/game/Guilds/GuildMgr.h | 3 +- src/server/game/Handlers/CharacterHandler.cpp | 8 ++-- src/server/game/Instances/InstanceSaveMgr.cpp | 15 +++----- src/server/game/Maps/Map.h | 5 +++ src/server/game/Maps/MapInstanced.cpp | 13 +++---- src/server/game/Maps/MapInstanced.h | 9 +++-- src/server/game/Maps/MapManager.cpp | 37 +++++++++--------- src/server/game/Maps/MapManager.h | 13 ++++--- src/server/game/Quests/QuestDef.h | 5 +++ src/server/game/Spells/Auras/SpellAuras.cpp | 4 +- src/server/game/Spells/Auras/SpellAuras.h | 12 ++++++ src/server/game/Spells/Spell.cpp | 35 +++++++++-------- src/server/game/Spells/Spell.h | 4 ++ src/server/scripts/Commands/cs_guild.cpp | 4 +- src/server/scripts/Commands/cs_learn.cpp | 4 +- src/server/scripts/Commands/cs_lookup.cpp | 6 +-- 34 files changed, 218 insertions(+), 161 deletions(-) diff --git a/src/server/game/Battlegrounds/Battleground.cpp b/src/server/game/Battlegrounds/Battleground.cpp index a06c87d2ee..938ac559b4 100644 --- a/src/server/game/Battlegrounds/Battleground.cpp +++ b/src/server/game/Battlegrounds/Battleground.cpp @@ -145,7 +145,6 @@ Battleground::~Battleground() for (uint32 i = 0; i < size; ++i) DelObject(i); - sBattlegroundMgr->RemoveBattleground(GetTypeID(), GetInstanceID()); // unload map if (m_Map) { diff --git a/src/server/game/Battlegrounds/Battleground.h b/src/server/game/Battlegrounds/Battleground.h index 4671ba2278..76c98c3f6c 100644 --- a/src/server/game/Battlegrounds/Battleground.h +++ b/src/server/game/Battlegrounds/Battleground.h @@ -23,6 +23,7 @@ #include "ObjectGuid.h" #include "Position.h" #include "SharedDefines.h" +#include "UniqueTrackablePtr.h" #include #include @@ -496,6 +497,9 @@ class TC_GAME_API Battleground // because BattleGrounds with different types and same level range has different m_BracketId uint8 GetUniqueBracketId() const; + Trinity::unique_weak_ptr GetWeakPtr() const { return m_weakRef; } + void SetWeakPtr(Trinity::unique_weak_ptr weakRef) { m_weakRef = std::move(weakRef); } + protected: // this method is called, when BG cannot spawn its own spirit guide, or something is wrong, It correctly ends Battleground void EndNow(); @@ -626,5 +630,7 @@ class TC_GAME_API Battleground Position StartPosition[PVP_TEAMS_COUNT]; float m_StartMaxDist; uint32 ScriptId; + + Trinity::unique_weak_ptr m_weakRef; }; #endif diff --git a/src/server/game/Battlegrounds/BattlegroundMgr.cpp b/src/server/game/Battlegrounds/BattlegroundMgr.cpp index b59831ff05..1b3d2f0c85 100644 --- a/src/server/game/Battlegrounds/BattlegroundMgr.cpp +++ b/src/server/game/Battlegrounds/BattlegroundMgr.cpp @@ -69,18 +69,6 @@ BattlegroundMgr::~BattlegroundMgr() void BattlegroundMgr::DeleteAllBattlegrounds() { - for (BattlegroundDataContainer::iterator itr1 = bgDataStore.begin(); itr1 != bgDataStore.end(); ++itr1) - { - BattlegroundData& data = itr1->second; - - while (!data.m_Battlegrounds.empty()) - delete data.m_Battlegrounds.begin()->second; - data.m_Battlegrounds.clear(); - - while (!data.BGFreeSlotQueue.empty()) - delete data.BGFreeSlotQueue.front(); - } - bgDataStore.clear(); } @@ -104,18 +92,19 @@ void BattlegroundMgr::Update(uint32 diff) for (BattlegroundContainer::iterator itr = ++itrDelete; itr != bgs.end();) { itrDelete = itr++; - Battleground* bg = itrDelete->second; + Battleground* bg = itrDelete->second.get(); bg->Update(m_UpdateTimer); if (bg->ToBeDeleted()) { - itrDelete->second = nullptr; - bgs.erase(itrDelete); BattlegroundClientIdsContainer& clients = itr1->second.m_ClientBattlegroundIds[bg->GetBracketId()]; if (!clients.empty()) clients.erase(bg->GetClientInstanceID()); - delete bg; + // move out unique_ptr to delete after erasing + Trinity::unique_trackable_ptr bgPtr = std::move(itrDelete->second); + + bgs.erase(itrDelete); } } } @@ -274,7 +263,7 @@ Battleground* BattlegroundMgr::GetBattlegroundThroughClientInstance(uint32 insta for (BattlegroundContainer::const_iterator itr = it->second.m_Battlegrounds.begin(); itr != it->second.m_Battlegrounds.end(); ++itr) { if (itr->second->GetClientInstanceID() == instanceId) - return itr->second; + return itr->second.get(); } return nullptr; @@ -305,7 +294,7 @@ Battleground* BattlegroundMgr::GetBattleground(uint32 instanceId, BattlegroundTy BattlegroundContainer const& bgs = it->second.m_Battlegrounds; BattlegroundContainer::const_iterator itr = bgs.find(instanceId); if (itr != bgs.end()) - return itr->second; + return itr->second.get(); } return nullptr; @@ -319,7 +308,7 @@ Battleground* BattlegroundMgr::GetBattlegroundTemplate(BattlegroundTypeId bgType BattlegroundContainer const& bgs = itr->second.m_Battlegrounds; //map is sorted and we can be sure that lowest instance id has only BG template - return bgs.empty() ? nullptr : bgs.begin()->second; + return bgs.empty() ? nullptr : bgs.begin()->second.get(); } uint32 BattlegroundMgr::CreateClientVisibleInstanceId(BattlegroundTypeId bgTypeId, BattlegroundBracketId bracket_id) @@ -1015,10 +1004,9 @@ void BattlegroundMgr::RemoveFromBGFreeSlotQueue(BattlegroundTypeId bgTypeId, uin void BattlegroundMgr::AddBattleground(Battleground* bg) { if (bg) - bgDataStore[bg->GetTypeID()].m_Battlegrounds[bg->GetInstanceID()] = bg; -} - -void BattlegroundMgr::RemoveBattleground(BattlegroundTypeId bgTypeId, uint32 instanceId) -{ - bgDataStore[bgTypeId].m_Battlegrounds.erase(instanceId); + { + Trinity::unique_trackable_ptr& ptr = bgDataStore[bg->GetTypeID()].m_Battlegrounds[bg->GetInstanceID()]; + ptr.reset(bg); + bg->SetWeakPtr(ptr); + } } diff --git a/src/server/game/Battlegrounds/BattlegroundMgr.h b/src/server/game/Battlegrounds/BattlegroundMgr.h index 7335abe190..939d3ef87b 100644 --- a/src/server/game/Battlegrounds/BattlegroundMgr.h +++ b/src/server/game/Battlegrounds/BattlegroundMgr.h @@ -22,11 +22,12 @@ #include "DBCEnums.h" #include "Battleground.h" #include "BattlegroundQueue.h" +#include "UniqueTrackablePtr.h" #include struct BattlemasterListEntry; -typedef std::map BattlegroundContainer; +typedef std::map> BattlegroundContainer; typedef std::set BattlegroundClientIdsContainer; typedef std::unordered_map BattleMastersMap; @@ -68,6 +69,11 @@ class TC_GAME_API BattlegroundMgr ~BattlegroundMgr(); public: + BattlegroundMgr(BattlegroundMgr const& right) = delete; + BattlegroundMgr(BattlegroundMgr&& right) = delete; + BattlegroundMgr& operator=(BattlegroundMgr const& right) = delete; + BattlegroundMgr& operator=(BattlegroundMgr&& right) = delete; + static BattlegroundMgr* instance(); void Update(uint32 diff); @@ -87,7 +93,6 @@ class TC_GAME_API BattlegroundMgr Battleground* CreateNewBattleground(BattlegroundTypeId bgTypeId, PvPDifficultyEntry const* bracketEntry, uint8 arenaType, bool isRated); void AddBattleground(Battleground* bg); - void RemoveBattleground(BattlegroundTypeId bgTypeId, uint32 instanceId); void AddToBGFreeSlotQueue(BattlegroundTypeId bgTypeId, Battleground* bg); void RemoveFromBGFreeSlotQueue(BattlegroundTypeId bgTypeId, uint32 instanceId); BGFreeSlotQueueContainer& GetBGFreeSlotQueueStore(BattlegroundTypeId bgTypeId); diff --git a/src/server/game/Entities/Object/Object.cpp b/src/server/game/Entities/Object/Object.cpp index 416df2cce7..9765ef9143 100644 --- a/src/server/game/Entities/Object/Object.cpp +++ b/src/server/game/Entities/Object/Object.cpp @@ -61,7 +61,7 @@ constexpr float VisibilityDistances[AsUnderlyingType(VisibilityDistanceType::Max MAX_VISIBILITY_DISTANCE }; -Object::Object() +Object::Object() : m_scriptRef(this, NoopObjectDeleter()) { m_objectTypeId = TYPEID_OBJECT; m_objectType = TYPEMASK_OBJECT; @@ -151,6 +151,11 @@ void Object::AddToWorld() // synchronize values mirror with values array (changes will send in updatecreate opcode any way ASSERT(!m_objectUpdated); ClearUpdateMask(false); + + // Set new ref when adding to world (except if we already have one - also set in constructor to allow scripts to work in initialization phase) + // Changing the ref when adding/removing from world prevents accessing players on different maps (possibly from another thread) + if (!m_scriptRef) + m_scriptRef.reset(this, NoopObjectDeleter()); } void Object::RemoveFromWorld() @@ -162,6 +167,8 @@ void Object::RemoveFromWorld() // if we remove from world then sending changes not required ClearUpdateMask(true); + + m_scriptRef = nullptr; } void Object::BuildMovementUpdateBlock(UpdateData* data, uint32 flags) const diff --git a/src/server/game/Entities/Object/Object.h b/src/server/game/Entities/Object/Object.h index 3a72759bb7..abf3bd3bf9 100644 --- a/src/server/game/Entities/Object/Object.h +++ b/src/server/game/Entities/Object/Object.h @@ -29,6 +29,7 @@ #include "Position.h" #include "SharedDefines.h" #include "SpellDefines.h" +#include "UniqueTrackablePtr.h" #include "UpdateFields.h" #include "UpdateMask.h" #include @@ -200,6 +201,8 @@ class TC_GAME_API Object virtual std::string GetDebugInfo() const; + Trinity::unique_weak_ptr GetWeakPtr() const { return m_scriptRef; } + protected: Object(); @@ -243,8 +246,12 @@ class TC_GAME_API Object PackedGuid m_PackGUID; + struct NoopObjectDeleter { void operator()(Object*) const { /*noop - not managed*/ } }; + Trinity::unique_trackable_ptr m_scriptRef; + // for output helpfull error messages from asserts bool PrintIndexError(uint32 index, bool set) const; + Object(Object const& right) = delete; Object(Object&& right) = delete; Object& operator=(Object const& right) = delete; diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp index ef84452914..b4c0139c76 100644 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -4018,7 +4018,7 @@ void Player::DeleteFromDB(ObjectGuid playerguid, uint32 accountId, bool updateRe CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction(); if (ObjectGuid::LowType guildId = sCharacterCache->GetCharacterGuildIdByGuid(playerguid)) if (Guild* guild = sGuildMgr->GetGuildById(guildId)) - guild->DeleteMember(trans, playerguid, false, false, true); + guild->DeleteMember(trans, playerguid, false, false); // close player ticket if any GmTicket* ticket = sTicketMgr->GetTicketByPlayer(playerguid); diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp index d31025c40c..71ca198c61 100644 --- a/src/server/game/Entities/Unit/Unit.cpp +++ b/src/server/game/Entities/Unit/Unit.cpp @@ -4177,8 +4177,8 @@ void Unit::RemoveAllAuras() { sstr << "m_ownedAuras:" << "\n"; - for (std::pair& auraPair : m_ownedAuras) - sstr << auraPair.second->GetDebugInfo() << "\n"; + for (auto const& [spellId, aura] : m_ownedAuras) + sstr << aura->GetDebugInfo() << "\n"; } TC_LOG_ERROR("entities.unit", "{}", sstr.str()); @@ -9638,6 +9638,12 @@ void Unit::CleanupBeforeRemoveFromMap(bool finalCleanup) if (IsInWorld()) RemoveFromWorld(); + else + { + // cleanup that must happen even if not in world + if (IsVehicle()) + RemoveVehicleKit(); + } ASSERT(GetGUID()); @@ -11810,7 +11816,7 @@ bool Unit::CreateVehicleKit(uint32 id, uint32 creatureEntry) if (!vehInfo) return false; - m_vehicleKit = new Vehicle(this, vehInfo, creatureEntry); + m_vehicleKit = Trinity::make_unique_trackable(this, vehInfo, creatureEntry); m_updateFlag |= UPDATEFLAG_VEHICLE; m_unitTypeMask |= UNIT_MASK_VEHICLE; return true; @@ -11822,8 +11828,6 @@ void Unit::RemoveVehicleKit() return; m_vehicleKit->Uninstall(); - delete m_vehicleKit; - m_vehicleKit = nullptr; m_updateFlag &= ~UPDATEFLAG_VEHICLE; diff --git a/src/server/game/Entities/Unit/Unit.h b/src/server/game/Entities/Unit/Unit.h index c39eb4328b..970d55a274 100644 --- a/src/server/game/Entities/Unit/Unit.h +++ b/src/server/game/Entities/Unit/Unit.h @@ -1730,7 +1730,8 @@ class TC_GAME_API Unit : public WorldObject ObjectGuid LastCharmerGUID; bool CreateVehicleKit(uint32 id, uint32 creatureEntry); void RemoveVehicleKit(); - Vehicle* GetVehicleKit() const { return m_vehicleKit; } + Vehicle* GetVehicleKit() const { return m_vehicleKit.get(); } + Trinity::unique_weak_ptr GetVehicleKitWeakPtr() const { return m_vehicleKit; } Vehicle* GetVehicle() const { return m_vehicle; } void SetVehicle(Vehicle* vehicle) { m_vehicle = vehicle; } bool IsOnVehicle(Unit const* vehicle) const; @@ -1892,7 +1893,7 @@ class TC_GAME_API Unit : public WorldObject uint32 m_regenTimer; Vehicle* m_vehicle; - Vehicle* m_vehicleKit; + Trinity::unique_trackable_ptr m_vehicleKit; uint32 m_unitTypeMask; LiquidTypeEntry const* _lastLiquid; diff --git a/src/server/game/Entities/Vehicle/Vehicle.cpp b/src/server/game/Entities/Vehicle/Vehicle.cpp index c94ea836f0..4011703c7c 100755 --- a/src/server/game/Entities/Vehicle/Vehicle.cpp +++ b/src/server/game/Entities/Vehicle/Vehicle.cpp @@ -989,3 +989,8 @@ std::string Vehicle::GetDebugInfo() const return sstr.str(); } + +Trinity::unique_weak_ptr Vehicle::GetWeakPtr() const +{ + return _me->GetVehicleKitWeakPtr(); +} diff --git a/src/server/game/Entities/Vehicle/Vehicle.h b/src/server/game/Entities/Vehicle/Vehicle.h index b9cc63bc74..d59c440bfd 100644 --- a/src/server/game/Entities/Vehicle/Vehicle.h +++ b/src/server/game/Entities/Vehicle/Vehicle.h @@ -20,8 +20,9 @@ #include "ObjectDefines.h" #include "Object.h" -#include "VehicleDefines.h" +#include "UniqueTrackablePtr.h" #include "Unit.h" +#include "VehicleDefines.h" #include struct VehicleEntry; @@ -30,14 +31,10 @@ class VehicleJoinEvent; class TC_GAME_API Vehicle : public TransportBase { - protected: - friend bool Unit::CreateVehicleKit(uint32 id, uint32 creatureEntry); + public: Vehicle(Unit* unit, VehicleEntry const* vehInfo, uint32 creatureEntry); - - friend void Unit::RemoveVehicleKit(); ~Vehicle(); - public: void Install(); void Uninstall(); void Reset(bool evading = false); @@ -73,6 +70,8 @@ class TC_GAME_API Vehicle : public TransportBase std::string GetDebugInfo() const; + Trinity::unique_weak_ptr GetWeakPtr() const; + protected: friend class VehicleJoinEvent; uint32 UsableSeatNum; ///< Number of seats that match VehicleSeatEntry::UsableByPlayer, used for proper display flags diff --git a/src/server/game/Globals/ObjectMgr.cpp b/src/server/game/Globals/ObjectMgr.cpp index 67bf9047c8..3aea616d60 100644 --- a/src/server/game/Globals/ObjectMgr.cpp +++ b/src/server/game/Globals/ObjectMgr.cpp @@ -4759,7 +4759,8 @@ void ObjectMgr::LoadQuests() Field* fields = result->Fetch(); uint32 questId = fields[0].GetUInt32(); - _questTemplates.emplace(std::piecewise_construct, std::forward_as_tuple(questId), std::forward_as_tuple(fields)); + auto itr = _questTemplates.emplace(std::piecewise_construct, std::forward_as_tuple(questId), std::forward_as_tuple(new Quest(fields))).first; + itr->second->_weakRef = itr->second; } while (result->NextRow()); std::unordered_map usedMailTemplates; @@ -4808,7 +4809,7 @@ void ObjectMgr::LoadQuests() auto itr = _questTemplates.find(questId); if (itr != _questTemplates.end()) - (itr->second.*loader.LoaderFunction)(fields); + (itr->second.get()->*loader.LoaderFunction)(fields); else TC_LOG_ERROR("server.loading", "Table `{}` has data for quest {} but such quest does not exist", loader.TableName, questId); } while (result->NextRow()); @@ -4822,7 +4823,7 @@ void ObjectMgr::LoadQuests() if (DisableMgr::IsDisabledFor(DISABLE_TYPE_QUEST, questPair.first, nullptr)) continue; - Quest* qinfo = &questPair.second; + Quest* qinfo = questPair.second.get(); // additional quest integrity checks (GO, creature_template and item_template must be loaded already) @@ -5329,7 +5330,7 @@ void ObjectMgr::LoadQuests() auto prevQuestItr = _questTemplates.find(prevQuestId); if (prevQuestItr == _questTemplates.end()) TC_LOG_ERROR("sql.sql", "Quest {} has PrevQuestId {}, but no such quest", qinfo->GetQuestId(), qinfo->_prevQuestId); - else if (prevQuestItr->second._breadcrumbForQuestId) + else if (prevQuestItr->second->_breadcrumbForQuestId) TC_LOG_ERROR("sql.sql", "Quest {} should not be unlocked by breadcrumb quest {}", qinfo->_id, prevQuestId); else if (qinfo->_prevQuestId > 0) qinfo->DependentPreviousQuests.push_back(prevQuestId); @@ -5341,7 +5342,7 @@ void ObjectMgr::LoadQuests() if (nextQuestItr == _questTemplates.end()) TC_LOG_ERROR("sql.sql", "Quest {} has NextQuestId {}, but no such quest", qinfo->GetQuestId(), qinfo->_nextQuestId); else - nextQuestItr->second.DependentPreviousQuests.push_back(qinfo->GetQuestId()); + nextQuestItr->second->DependentPreviousQuests.push_back(qinfo->GetQuestId()); } if (uint32 breadcrumbForQuestId = std::abs(qinfo->_breadcrumbForQuestId)) @@ -5390,7 +5391,7 @@ void ObjectMgr::LoadQuests() if (DisableMgr::IsDisabledFor(DISABLE_TYPE_QUEST, questPair.first, nullptr)) continue; - Quest* qinfo = &questPair.second; + Quest* qinfo = questPair.second.get(); uint32 qid = qinfo->GetQuestId(); uint32 breadcrumbForQuestId = std::abs(qinfo->_breadcrumbForQuestId); std::set questSet; @@ -6934,7 +6935,8 @@ uint32 ObjectMgr::GetTaxiMountDisplayId(uint32 id, uint32 team, bool allowed_alt Quest const* ObjectMgr::GetQuestTemplate(uint32 quest_id) const { - return Trinity::Containers::MapGetValuePtr(_questTemplates, quest_id); + auto itr = _questTemplates.find(quest_id); + return itr != _questTemplates.end() ? itr->second.get() : nullptr; } void ObjectMgr::LoadGraveyardZones() @@ -10475,7 +10477,7 @@ void ObjectMgr::InitializeQueriesData(QueryDataGroup mask) // Initialize Query Data for quests if (mask & QUERY_DATA_QUESTS) for (auto& questTemplatePair : _questTemplates) - pool.PostWork([quest = &questTemplatePair.second]() { quest->InitializeQueryData(); }); + pool.PostWork([quest = questTemplatePair.second.get()]() { quest->InitializeQueryData(); }); // Initialize Quest POI data if (mask & QUERY_DATA_POIS) diff --git a/src/server/game/Globals/ObjectMgr.h b/src/server/game/Globals/ObjectMgr.h index 6eb3976784..cdd1981ada 100644 --- a/src/server/game/Globals/ObjectMgr.h +++ b/src/server/game/Globals/ObjectMgr.h @@ -34,6 +34,7 @@ #include "SharedDefines.h" #include "Trainer.h" #include "VehicleDefines.h" +#include "UniqueTrackablePtr.h" #include #include #include @@ -945,7 +946,7 @@ class TC_GAME_API ObjectMgr static ObjectMgr* instance(); - typedef std::unordered_map QuestContainer; + typedef std::unordered_map> QuestContainer; typedef std::unordered_map AreaTriggerContainer; diff --git a/src/server/game/Groups/Group.cpp b/src/server/game/Groups/Group.cpp index 3a8ba730fa..e3b870cba5 100644 --- a/src/server/game/Groups/Group.cpp +++ b/src/server/game/Groups/Group.cpp @@ -62,7 +62,8 @@ Loot* Roll::getLoot() Group::Group() : m_leaderGuid(), m_leaderName(""), m_groupType(GROUPTYPE_NORMAL), m_dungeonDifficulty(DUNGEON_DIFFICULTY_NORMAL), m_raidDifficulty(RAID_DIFFICULTY_10MAN_NORMAL), m_bgGroup(nullptr), m_bfGroup(nullptr), m_lootMethod(FREE_FOR_ALL), m_lootThreshold(ITEM_QUALITY_UNCOMMON), m_looterGuid(), -m_masterLooterGuid(), m_subGroupsCounts(nullptr), m_guid(), m_counter(0), m_maxEnchantingLevel(0), m_dbStoreId(0), m_isLeaderOffline(false) +m_masterLooterGuid(), m_subGroupsCounts(nullptr), m_guid(), m_counter(0), m_maxEnchantingLevel(0), m_dbStoreId(0), m_isLeaderOffline(false), + m_scriptRef(this, NoopGroupDeleter()) { for (uint8 i = 0; i < TARGET_ICONS_COUNT; ++i) m_targetIcons[i].Clear(); diff --git a/src/server/game/Groups/Group.h b/src/server/game/Groups/Group.h index 402264f19e..f03a2fc44f 100644 --- a/src/server/game/Groups/Group.h +++ b/src/server/game/Groups/Group.h @@ -24,6 +24,7 @@ #include "Loot.h" #include "SharedDefines.h" #include "Timer.h" +#include "UniqueTrackablePtr.h" #include class Battlefield; @@ -338,6 +339,8 @@ class TC_GAME_API Group // FG: evil hacks void BroadcastGroupUpdate(void); + Trinity::unique_weak_ptr GetWeakPtr() const { return m_scriptRef; } + protected: bool _setMembersGroup(ObjectGuid guid, uint8 group); void _homebindIfInstance(Player* player); @@ -373,5 +376,8 @@ class TC_GAME_API Group uint32 m_dbStoreId; // Represents the ID used in database (Can be reused by other groups if group was disbanded) bool m_isLeaderOffline; TimeTracker m_leaderOfflineTimer; + + struct NoopGroupDeleter { void operator()(Group*) const { /*noop - not managed*/ } }; + Trinity::unique_trackable_ptr m_scriptRef; }; #endif diff --git a/src/server/game/Guilds/Guild.cpp b/src/server/game/Guilds/Guild.cpp index 568194d1f0..18fed0e33c 100644 --- a/src/server/game/Guilds/Guild.cpp +++ b/src/server/game/Guilds/Guild.cpp @@ -1532,7 +1532,8 @@ void Guild::HandleAcceptMember(WorldSession* session) void Guild::HandleLeaveMember(WorldSession* session) { Player* player = session->GetPlayer(); - bool disband = false; + + sCalendarMgr->RemovePlayerGuildEventsAndSignups(player->GetGUID(), GetId()); // If leader is leaving if (_IsLeader(player)) @@ -1544,7 +1545,6 @@ void Guild::HandleLeaveMember(WorldSession* session) { // Guild is disbanded if leader leaves. Disband(); - disband = true; } } else @@ -1557,11 +1557,6 @@ void Guild::HandleLeaveMember(WorldSession* session) SendCommandResult(session, GUILD_COMMAND_QUIT, ERR_GUILD_COMMAND_SUCCESS, m_name); } - - sCalendarMgr->RemovePlayerGuildEventsAndSignups(player->GetGUID(), GetId()); - - if (disband) - delete this; } void Guild::HandleRemoveMember(WorldSession* session, std::string_view name) @@ -1786,7 +1781,6 @@ void Guild::HandleDisband(WorldSession* session) { Disband(); TC_LOG_DEBUG("guild", "Guild Successfully Disbanded"); - delete this; } } @@ -2110,13 +2104,8 @@ bool Guild::Validate() if (!pLeader) { CharacterDatabaseTransaction dummy(nullptr); - DeleteMember(dummy, m_leaderGuid); - // If no more members left, disband guild - if (m_members.empty()) - { - Disband(); + if (DeleteMember(dummy, m_leaderGuid)) return false; - } } else if (!pLeader->IsRank(GR_GUILDMASTER)) _SetLeaderGUID(*pLeader); @@ -2276,7 +2265,7 @@ bool Guild::AddMember(CharacterDatabaseTransaction trans, ObjectGuid guid, uint8 return true; } -void Guild::DeleteMember(CharacterDatabaseTransaction trans, ObjectGuid guid, bool isDisbanding, bool isKicked, bool canDeleteGuild) +bool Guild::DeleteMember(CharacterDatabaseTransaction trans, ObjectGuid guid, bool isDisbanding, bool isKicked) { ObjectGuid::LowType lowguid = guid.GetCounter(); Player* player = ObjectAccessor::FindConnectedPlayer(guid); @@ -2298,9 +2287,7 @@ void Guild::DeleteMember(CharacterDatabaseTransaction trans, ObjectGuid guid, bo if (!newLeader) { Disband(); - if (canDeleteGuild) - delete this; - return; + return true; } _SetLeaderGUID(*newLeader); @@ -2333,6 +2320,14 @@ void Guild::DeleteMember(CharacterDatabaseTransaction trans, ObjectGuid guid, bo _DeleteMemberFromDB(trans, lowguid); if (!isDisbanding) _UpdateAccountsNumber(); + + if (m_members.empty()) + { + Disband(); + return true; + } + + return false; } bool Guild::ChangeMemberRank(CharacterDatabaseTransaction trans, ObjectGuid guid, uint8 newRank) diff --git a/src/server/game/Guilds/Guild.h b/src/server/game/Guilds/Guild.h index ba11f5fb47..45e75a985e 100644 --- a/src/server/game/Guilds/Guild.h +++ b/src/server/game/Guilds/Guild.h @@ -22,6 +22,7 @@ #include "ObjectGuid.h" #include "Optional.h" #include "SharedDefines.h" +#include "UniqueTrackablePtr.h" #include #include #include @@ -714,7 +715,7 @@ class TC_GAME_API Guild // Members // Adds member to guild. If rankId == GUILD_RANK_NONE, lowest rank is assigned. bool AddMember(CharacterDatabaseTransaction trans, ObjectGuid guid, uint8 rankId = GUILD_RANK_NONE); - void DeleteMember(CharacterDatabaseTransaction trans, ObjectGuid guid, bool isDisbanding = false, bool isKicked = false, bool canDeleteGuild = false); + bool DeleteMember(CharacterDatabaseTransaction trans, ObjectGuid guid, bool isDisbanding = false, bool isKicked = false); bool ChangeMemberRank(CharacterDatabaseTransaction trans, ObjectGuid guid, uint8 newRank); uint64 GetMemberAvailableMoneyForRepairItems(ObjectGuid guid) const; @@ -727,6 +728,9 @@ class TC_GAME_API Guild void ResetTimes(); + Trinity::unique_weak_ptr GetWeakPtr() const { return m_weakRef; } + void SetWeakPtr(Trinity::unique_weak_ptr weakRef) { m_weakRef = std::move(weakRef); } + protected: ObjectGuid::LowType m_id; std::string m_name; @@ -747,6 +751,8 @@ class TC_GAME_API Guild LogHolder m_eventLog; std::array, GUILD_BANK_MAX_TABS + 1> m_bankEventLog = {}; + Trinity::unique_weak_ptr m_weakRef; + private: inline uint8 _GetRanksSize() const { return uint8(m_ranks.size()); } inline RankInfo const* GetRankInfo(uint8 rankId) const { return rankId < _GetRanksSize() ? &m_ranks[rankId] : nullptr; } diff --git a/src/server/game/Guilds/GuildMgr.cpp b/src/server/game/Guilds/GuildMgr.cpp index 21f5896251..bf804ecb9c 100644 --- a/src/server/game/Guilds/GuildMgr.cpp +++ b/src/server/game/Guilds/GuildMgr.cpp @@ -26,15 +26,13 @@ GuildMgr::GuildMgr() : NextGuildId(1) { } -GuildMgr::~GuildMgr() -{ - for (GuildContainer::iterator itr = GuildStore.begin(); itr != GuildStore.end(); ++itr) - delete itr->second; -} +GuildMgr::~GuildMgr() = default; void GuildMgr::AddGuild(Guild* guild) { - GuildStore[guild->GetId()] = guild; + Trinity::unique_trackable_ptr& ptr = GuildStore[guild->GetId()]; + ptr.reset(guild); + guild->SetWeakPtr(ptr); } void GuildMgr::RemoveGuild(ObjectGuid::LowType guildId) @@ -57,16 +55,16 @@ Guild* GuildMgr::GetGuildById(ObjectGuid::LowType guildId) const { GuildContainer::const_iterator itr = GuildStore.find(guildId); if (itr != GuildStore.end()) - return itr->second; + return itr->second.get(); return nullptr; } Guild* GuildMgr::GetGuildByName(std::string_view guildName) const { - for (auto [id, guild] : GuildStore) + for (auto const& [id, guild] : GuildStore) if (StringEqualI(guild->GetName(), guildName)) - return guild; + return guild.get(); return nullptr; } @@ -89,7 +87,7 @@ Guild* GuildMgr::GetGuildByLeader(ObjectGuid guid) const { for (GuildContainer::const_iterator itr = GuildStore.begin(); itr != GuildStore.end(); ++itr) if (itr->second->GetLeaderGUID() == guid) - return itr->second; + return itr->second.get(); return nullptr; } @@ -387,10 +385,10 @@ void GuildMgr::LoadGuilds() for (GuildContainer::iterator itr = GuildStore.begin(); itr != GuildStore.end();) { - Guild* guild = itr->second; + Guild* guild = itr->second.get(); ++itr; - if (guild && !guild->Validate()) - delete guild; + if (guild) + guild->Validate(); } TC_LOG_INFO("server.loading", ">> Validated data of loaded guilds in {} ms", GetMSTimeDiffToNow(oldMSTime)); @@ -400,7 +398,7 @@ void GuildMgr::LoadGuilds() void GuildMgr::ResetTimes() { for (GuildContainer::const_iterator itr = GuildStore.begin(); itr != GuildStore.end(); ++itr) - if (Guild* guild = itr->second) + if (Guild* guild = itr->second.get()) guild->ResetTimes(); CharacterDatabase.DirectExecute("TRUNCATE guild_member_withdraw"); diff --git a/src/server/game/Guilds/GuildMgr.h b/src/server/game/Guilds/GuildMgr.h index 00d2136623..8a48ae32b2 100644 --- a/src/server/game/Guilds/GuildMgr.h +++ b/src/server/game/Guilds/GuildMgr.h @@ -20,6 +20,7 @@ #include "Define.h" #include "ObjectGuid.h" +#include "UniqueTrackablePtr.h" #include #include @@ -50,7 +51,7 @@ class TC_GAME_API GuildMgr void ResetTimes(); protected: - typedef std::unordered_map GuildContainer; + typedef std::unordered_map> GuildContainer; ObjectGuid::LowType NextGuildId; GuildContainer GuildStore; }; diff --git a/src/server/game/Handlers/CharacterHandler.cpp b/src/server/game/Handlers/CharacterHandler.cpp index 7e972ce874..1678a94292 100644 --- a/src/server/game/Handlers/CharacterHandler.cpp +++ b/src/server/game/Handlers/CharacterHandler.cpp @@ -1877,7 +1877,7 @@ void WorldSession::HandleCharFactionOrRaceChangeCallback(std::shared_ptrGetGuildById(characterInfo->GuildId)) - guild->DeleteMember(trans, factionChangeInfo->Guid, false, false, true); + guild->DeleteMember(trans, factionChangeInfo->Guid, false, false); Player::LeaveAllArenaTeams(factionChangeInfo->Guid); } @@ -1992,14 +1992,14 @@ void WorldSession::HandleCharFactionOrRaceChangeCallback(std::shared_ptrGetQuestTemplates(); - for (auto const& questTemplatePair : questTemplates) + for (auto const& [questId, quest] : questTemplates) { uint32 newRaceMask = (newTeam == ALLIANCE) ? RACEMASK_ALLIANCE : RACEMASK_HORDE; - if (questTemplatePair.second.GetAllowableRaces() && !(questTemplatePair.second.GetAllowableRaces() & newRaceMask)) + if (quest->GetAllowableRaces() && !(quest->GetAllowableRaces() & newRaceMask)) { stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_CHAR_QUESTSTATUS_REWARDED_ACTIVE_BY_QUEST); stmt->setUInt32(0, lowGuid); - stmt->setUInt32(1, questTemplatePair.first); + stmt->setUInt32(1, questId); trans->Append(stmt); } } diff --git a/src/server/game/Instances/InstanceSaveMgr.cpp b/src/server/game/Instances/InstanceSaveMgr.cpp index cfd11dcfb7..90914ba621 100644 --- a/src/server/game/Instances/InstanceSaveMgr.cpp +++ b/src/server/game/Instances/InstanceSaveMgr.cpp @@ -689,17 +689,12 @@ void InstanceSaveManager::_ResetOrWarnAll(uint32 mapid, Difficulty difficulty, b } // note: this isn't fast but it's meant to be executed very rarely - Map const* map = sMapMgr->CreateBaseMap(mapid); // _not_ include difficulty - MapInstanced::InstancedMaps &instMaps = ((MapInstanced*)map)->GetInstancedMaps(); - MapInstanced::InstancedMaps::iterator mitr; + Map* baseMap = sMapMgr->CreateBaseMap(mapid); // _not_ include difficulty uint32 timeLeft; - for (mitr = instMaps.begin(); mitr != instMaps.end(); ++mitr) + for (auto& [_, map] : baseMap->ToMapInstanced()->GetInstancedMaps()) { - Map* map2 = mitr->second; - if (!map2->IsDungeon()) - continue; - + InstanceMap* instanceMap = map->ToInstanceMap(); if (warn) { if (now >= resetTime) @@ -707,10 +702,10 @@ void InstanceSaveManager::_ResetOrWarnAll(uint32 mapid, Difficulty difficulty, b else timeLeft = uint32(resetTime - now); - ((InstanceMap*)map2)->SendResetWarnings(timeLeft); + instanceMap->SendResetWarnings(timeLeft); } else - ((InstanceMap*)map2)->Reset(INSTANCE_RESET_GLOBAL); + instanceMap->Reset(INSTANCE_RESET_GLOBAL); } /// @todo delete creature/gameobject respawn times even if the maps are not loaded diff --git a/src/server/game/Maps/Map.h b/src/server/game/Maps/Map.h index dadd8cc14d..e51e50cbf7 100644 --- a/src/server/game/Maps/Map.h +++ b/src/server/game/Maps/Map.h @@ -32,6 +32,7 @@ #include "SpawnData.h" #include "Timer.h" #include "Transaction.h" +#include "UniqueTrackablePtr.h" #include #include #include @@ -429,6 +430,9 @@ class TC_GAME_API Map : public GridRefManager uint32 GetInstanceId() const { return i_InstanceId; } uint8 GetSpawnMode() const { return (i_spawnMode); } + Trinity::unique_weak_ptr GetWeakPtr() const { return m_weakRef; } + void SetWeakPtr(Trinity::unique_weak_ptr weakRef) { m_weakRef = std::move(weakRef); } + enum EnterState { CAN_ENTER = 0, @@ -710,6 +714,7 @@ class TC_GAME_API Map : public GridRefManager MapEntry const* i_mapEntry; uint8 i_spawnMode; uint32 i_InstanceId; + Trinity::unique_weak_ptr m_weakRef; uint32 m_unloadTimer; float m_VisibleDistance; DynamicMapTree _dynamicTree; diff --git a/src/server/game/Maps/MapInstanced.cpp b/src/server/game/Maps/MapInstanced.cpp index 141f1808eb..ccd2d96215 100644 --- a/src/server/game/Maps/MapInstanced.cpp +++ b/src/server/game/Maps/MapInstanced.cpp @@ -97,10 +97,6 @@ void MapInstanced::UnloadAll() for (InstancedMaps::iterator i = m_InstancedMaps.begin(); i != m_InstancedMaps.end(); ++i) i->second->UnloadAll(); - // Delete the maps only after everything is unloaded to prevent crashes - for (InstancedMaps::iterator i = m_InstancedMaps.begin(); i != m_InstancedMaps.end(); ++i) - delete i->second; - m_InstancedMaps.clear(); // Unload own grids (just dummy(placeholder) grids, neccesary to unload GridMaps!) @@ -237,7 +233,9 @@ InstanceMap* MapInstanced::CreateInstance(uint32 InstanceId, InstanceSave* save, if (sWorld->getBoolConfig(CONFIG_INSTANCEMAP_LOAD_GRIDS)) map->LoadAllCells(); - m_InstancedMaps[InstanceId] = map; + Trinity::unique_trackable_ptr& ptr = m_InstancedMaps[InstanceId]; + ptr.reset(map); + map->SetWeakPtr(ptr); return map; } @@ -262,7 +260,9 @@ BattlegroundMap* MapInstanced::CreateBattleground(uint32 InstanceId, Battlegroun map->SetBG(bg); bg->SetBgMap(map); - m_InstancedMaps[InstanceId] = map; + Trinity::unique_trackable_ptr& ptr = m_InstancedMaps[InstanceId]; + ptr.reset(map); + map->SetWeakPtr(ptr); return map; } @@ -292,7 +292,6 @@ bool MapInstanced::DestroyInstance(InstancedMaps::iterator &itr) sMapMgr->FreeInstanceId(itr->second->GetInstanceId()); // erase map - delete itr->second; m_InstancedMaps.erase(itr++); return true; diff --git a/src/server/game/Maps/MapInstanced.h b/src/server/game/Maps/MapInstanced.h index d60abbc25d..2d26f559ba 100644 --- a/src/server/game/Maps/MapInstanced.h +++ b/src/server/game/Maps/MapInstanced.h @@ -18,15 +18,16 @@ #ifndef TRINITY_MAP_INSTANCED_H #define TRINITY_MAP_INSTANCED_H -#include "Map.h" -#include "InstanceSaveMgr.h" #include "DBCEnums.h" +#include "InstanceSaveMgr.h" +#include "Map.h" +#include "UniqueTrackablePtr.h" class TC_GAME_API MapInstanced : public Map { friend class MapManager; public: - typedef std::unordered_map< uint32, Map*> InstancedMaps; + typedef std::unordered_map> InstancedMaps; MapInstanced(uint32 id, time_t expiry); ~MapInstanced() { } @@ -42,7 +43,7 @@ class TC_GAME_API MapInstanced : public Map Map* FindInstanceMap(uint32 instanceId) const { InstancedMaps::const_iterator i = m_InstancedMaps.find(instanceId); - return(i == m_InstancedMaps.end() ? nullptr : i->second); + return(i == m_InstancedMaps.end() ? nullptr : i->second.get()); } bool DestroyInstance(InstancedMaps::iterator &itr); diff --git a/src/server/game/Maps/MapManager.cpp b/src/server/game/Maps/MapManager.cpp index 1d17f6caa9..d340a85e4d 100644 --- a/src/server/game/Maps/MapManager.cpp +++ b/src/server/game/Maps/MapManager.cpp @@ -33,6 +33,7 @@ #include "Player.h" #include "WorldSession.h" #include "Opcodes.h" +#include MapManager::MapManager() : _nextInstanceId(0), _scheduledScripts(0) @@ -85,7 +86,9 @@ Map* MapManager::CreateBaseMap(uint32 id) map->LoadCorpseData(); } - i_maps[id] = map; + Trinity::unique_trackable_ptr& ptr = i_maps[id]; + ptr.reset(map); + map->SetWeakPtr(ptr); } ASSERT(map); @@ -255,12 +258,12 @@ bool MapManager::IsValidMAP(uint32 mapid, bool startUp) void MapManager::UnloadAll() { - for (MapMapType::iterator iter = i_maps.begin(); iter != i_maps.end();) - { + // first unload maps + for (auto iter = i_maps.begin(); iter != i_maps.end(); ++iter) iter->second->UnloadAll(); - delete iter->second; - i_maps.erase(iter++); - } + + // then delete them + i_maps.clear(); if (m_updater.activated()) m_updater.deactivate(); @@ -273,14 +276,12 @@ uint32 MapManager::GetNumInstances() std::lock_guard lock(_mapsLock); uint32 ret = 0; - for (MapMapType::iterator itr = i_maps.begin(); itr != i_maps.end(); ++itr) + for (auto const& [_, map] : i_maps) { - Map* map = itr->second; - if (!map->Instanceable()) + MapInstanced* mapInstanced = map->ToMapInstanced(); + if (!mapInstanced) continue; - MapInstanced::InstancedMaps &maps = ((MapInstanced*)map)->GetInstancedMaps(); - for (MapInstanced::InstancedMaps::iterator mitr = maps.begin(); mitr != maps.end(); ++mitr) - if (mitr->second->IsDungeon()) ret++; + ret += mapInstanced->GetInstancedMaps().size(); } return ret; } @@ -290,15 +291,13 @@ uint32 MapManager::GetNumPlayersInInstances() std::lock_guard lock(_mapsLock); uint32 ret = 0; - for (MapMapType::iterator itr = i_maps.begin(); itr != i_maps.end(); ++itr) + for (auto& [_, map] : i_maps) { - Map* map = itr->second; - if (!map->Instanceable()) + MapInstanced* mapInstanced = map->ToMapInstanced(); + if (!mapInstanced) continue; - MapInstanced::InstancedMaps &maps = ((MapInstanced*)map)->GetInstancedMaps(); - for (MapInstanced::InstancedMaps::iterator mitr = maps.begin(); mitr != maps.end(); ++mitr) - if (mitr->second->IsDungeon()) - ret += ((InstanceMap*)mitr->second)->GetPlayers().getSize(); + MapInstanced::InstancedMaps& maps = mapInstanced->GetInstancedMaps(); + ret += std::accumulate(maps.begin(), maps.end(), 0u, [](uint32 total, MapInstanced::InstancedMaps::value_type const& value) { return total + value.second->GetPlayers().getSize(); }); } return ret; } diff --git a/src/server/game/Maps/MapManager.h b/src/server/game/Maps/MapManager.h index 2323e31ab9..5754415ba7 100644 --- a/src/server/game/Maps/MapManager.h +++ b/src/server/game/Maps/MapManager.h @@ -23,6 +23,7 @@ #include "MapInstanced.h" #include "GridStates.h" #include "MapUpdater.h" +#include "UniqueTrackablePtr.h" #include class Transport; @@ -140,7 +141,7 @@ class TC_GAME_API MapManager bool IsScriptScheduled() const { return _scheduledScripts > 0; } private: - typedef std::unordered_map MapMapType; + typedef std::unordered_map> MapMapType; typedef boost::dynamic_bitset InstanceIds; MapManager(); @@ -149,7 +150,7 @@ class TC_GAME_API MapManager Map* FindBaseMap(uint32 mapId) const { MapMapType::const_iterator iter = i_maps.find(mapId); - return (iter == i_maps.end() ? nullptr : iter->second); + return (iter == i_maps.end() ? nullptr : iter->second.get()); } MapManager(MapManager const&) = delete; @@ -175,12 +176,12 @@ void MapManager::DoForAllMaps(Worker&& worker) for (auto& mapPair : i_maps) { - Map* map = mapPair.second; + Map* map = mapPair.second.get(); if (MapInstanced* mapInstanced = map->ToMapInstanced()) { MapInstanced::InstancedMaps& instances = mapInstanced->GetInstancedMaps(); for (auto& instancePair : instances) - worker(instancePair.second); + worker(instancePair.second.get()); } else worker(map); @@ -195,12 +196,12 @@ inline void MapManager::DoForAllMapsWithMapId(uint32 mapId, Worker&& worker) auto itr = i_maps.find(mapId); if (itr != i_maps.end()) { - Map* map = itr->second; + Map* map = itr->second.get(); if (MapInstanced* mapInstanced = map->ToMapInstanced()) { MapInstanced::InstancedMaps& instances = mapInstanced->GetInstancedMaps(); for (auto& p : instances) - worker(p.second); + worker(p.second.get()); } else worker(map); diff --git a/src/server/game/Quests/QuestDef.h b/src/server/game/Quests/QuestDef.h index a8d3fa9866..6e9a0be33d 100644 --- a/src/server/game/Quests/QuestDef.h +++ b/src/server/game/Quests/QuestDef.h @@ -22,6 +22,7 @@ #include "DatabaseEnvFwd.h" #include "DBCEnums.h" #include "SharedDefines.h" +#include "UniqueTrackablePtr.h" #include "WorldPacket.h" #include @@ -332,6 +333,8 @@ class TC_GAME_API Quest void BuildQuestRewards(WorldPackets::Quest::QuestRewards& rewards, Player* player, bool sendHiddenRewards = false) const; + Trinity::unique_weak_ptr GetWeakPtr() const { return _weakRef; } + std::vector DependentPreviousQuests; std::vector DependentBreadcrumbQuests; WorldPacket QueryData[TOTAL_LOCALES]; @@ -408,6 +411,8 @@ class TC_GAME_API Quest // Helpers static uint32 RoundXPValue(uint32 xp); + + Trinity::unique_weak_ptr _weakRef; }; struct QuestStatusData diff --git a/src/server/game/Spells/Auras/SpellAuras.cpp b/src/server/game/Spells/Auras/SpellAuras.cpp index 2543219d43..c987893f2b 100644 --- a/src/server/game/Spells/Auras/SpellAuras.cpp +++ b/src/server/game/Spells/Auras/SpellAuras.cpp @@ -428,7 +428,7 @@ m_castItemGuid(createInfo.CastItemGUID), m_applyTime(GameTime::GetGameTime()), m_owner(createInfo._owner), m_timeCla(0), m_updateTargetMapInterval(0), _casterInfo(), m_procCharges(0), m_stackAmount(1), m_isRemoved(false), m_isSingleTarget(false), m_isUsingCharges(false), m_dropEvent(nullptr), -m_procCooldown(TimePoint::min()) +m_procCooldown(TimePoint::min()), m_scriptRef(this, NoopAuraDeleter()) { if (m_spellInfo->ManaPerSecond || m_spellInfo->ManaPerSecondPerLevel) m_timeCla = 1 * IN_MILLISECONDS; @@ -618,6 +618,8 @@ void Aura::_Remove(AuraRemoveMode removeMode) m_dropEvent->ScheduleAbort(); m_dropEvent = nullptr; } + + m_scriptRef = nullptr; } void Aura::UpdateTargetMap(Unit* caster, bool apply) diff --git a/src/server/game/Spells/Auras/SpellAuras.h b/src/server/game/Spells/Auras/SpellAuras.h index 126f11141b..f392ad6fb2 100644 --- a/src/server/game/Spells/Auras/SpellAuras.h +++ b/src/server/game/Spells/Auras/SpellAuras.h @@ -20,6 +20,7 @@ #include "SpellAuraDefines.h" #include "SpellInfo.h" +#include "UniqueTrackablePtr.h" class SpellInfo; struct SpellModifier; @@ -269,6 +270,14 @@ class TC_GAME_API Aura virtual std::string GetDebugInfo() const; + Trinity::unique_weak_ptr GetWeakPtr() const { return m_scriptRef; } + + Aura(Aura const&) = delete; + Aura(Aura&&) = delete; + + Aura& operator=(Aura const&) = delete; + Aura& operator=(Aura&&) = delete; + private: AuraScript* GetScriptByName(std::string const& scriptName) const; void _DeleteRemovedApplications(); @@ -302,6 +311,9 @@ class TC_GAME_API Aura private: std::vector _removedApplications; + + struct NoopAuraDeleter { void operator()(Aura*) const { /*noop - not managed*/ } }; + Trinity::unique_trackable_ptr m_scriptRef; }; class TC_GAME_API UnitAura : public Aura diff --git a/src/server/game/Spells/Spell.cpp b/src/server/game/Spells/Spell.cpp index 13731b2679..22b2b3a4c1 100644 --- a/src/server/game/Spells/Spell.cpp +++ b/src/server/game/Spells/Spell.cpp @@ -55,6 +55,7 @@ #include "Unit.h" #include "UpdateData.h" #include "UpdateMask.h" +#include "UniqueTrackablePtr.h" #include "Util.h" #include "Vehicle.h" #include "VMapFactory.h" @@ -487,16 +488,20 @@ SpellValue::SpellValue(SpellInfo const* proto) class TC_GAME_API SpellEvent : public BasicEvent { - public: - SpellEvent(Spell* spell); - ~SpellEvent(); +public: + explicit SpellEvent(Spell* spell); + ~SpellEvent(); + + bool Execute(uint64 e_time, uint32 p_time) override; + void Abort(uint64 e_time) override; + bool IsDeletable() const override; + Spell const* GetSpell() const { return m_Spell.get(); } + Trinity::unique_weak_ptr GetSpellWeakPtr() const { return m_Spell; } - bool Execute(uint64 e_time, uint32 p_time) override; - void Abort(uint64 e_time) override; - bool IsDeletable() const override; + std::string GetDebugInfo() const { return m_Spell->GetDebugInfo(); } - protected: - Spell* m_Spell; +protected: + Trinity::unique_trackable_ptr m_Spell; }; Spell::Spell(WorldObject* caster, SpellInfo const* info, TriggerCastFlags triggerFlags, ObjectGuid originalCasterGUID) : @@ -7430,9 +7435,8 @@ Unit* Spell::GetUnitCasterForEffectHandlers() const return m_originalCaster ? m_originalCaster : m_caster->ToUnit(); } -SpellEvent::SpellEvent(Spell* spell) : BasicEvent() +SpellEvent::SpellEvent(Spell* spell) : BasicEvent(), m_Spell(spell) { - m_Spell = spell; } SpellEvent::~SpellEvent() @@ -7440,11 +7444,7 @@ SpellEvent::~SpellEvent() if (m_Spell->getState() != SPELL_STATE_FINISHED) m_Spell->cancel(); - if (m_Spell->IsDeletable()) - { - delete m_Spell; - } - else + if (!m_Spell->IsDeletable()) { TC_LOG_ERROR("spells", "~SpellEvent: {} {} tried to delete non-deletable spell {}. Was not deleted, causes memory leak.", (m_Spell->GetCaster()->GetTypeId() == TYPEID_PLAYER ? "Player" : "Creature"), m_Spell->GetCaster()->GetGUID().ToString(), m_Spell->m_spellInfo->Id); @@ -8177,6 +8177,11 @@ std::string Spell::GetDebugInfo() const return sstr.str(); } +Trinity::unique_weak_ptr Spell::GetWeakPtr() const +{ + return _spellEvent->GetSpellWeakPtr(); +} + void Spell::CallScriptOnResistAbsorbCalculateHandlers(DamageInfo const& damageInfo, uint32& resistAmount, int32& absorbAmount) { for (auto scritr = m_loadedScripts.begin(); scritr != m_loadedScripts.end(); ++scritr) diff --git a/src/server/game/Spells/Spell.h b/src/server/game/Spells/Spell.h index 3359bf6d73..8dbcdd9ad7 100644 --- a/src/server/game/Spells/Spell.h +++ b/src/server/game/Spells/Spell.h @@ -24,6 +24,7 @@ #include "Position.h" #include "SharedDefines.h" #include "SpellDefines.h" +#include "UniqueTrackablePtr.h" #include namespace WorldPackets @@ -458,6 +459,9 @@ class TC_GAME_API Spell Spell** m_selfContainer; // pointer to our spell container (if applicable) std::string GetDebugInfo() const; + + Trinity::unique_weak_ptr GetWeakPtr() const; + void CallScriptOnResistAbsorbCalculateHandlers(DamageInfo const& damageInfo, uint32& resistAmount, int32& absorbAmount); protected: diff --git a/src/server/scripts/Commands/cs_guild.cpp b/src/server/scripts/Commands/cs_guild.cpp index 73255185c6..bd3403fa40 100644 --- a/src/server/scripts/Commands/cs_guild.cpp +++ b/src/server/scripts/Commands/cs_guild.cpp @@ -141,8 +141,6 @@ class guild_commandscript : public CommandScript return false; targetGuild->Disband(); - delete targetGuild; - return true; } @@ -190,7 +188,7 @@ class guild_commandscript : public CommandScript return false; CharacterDatabaseTransaction trans(nullptr); - targetGuild->DeleteMember(trans, targetGuid, false, true, true); + targetGuild->DeleteMember(trans, targetGuid, false, true); return true; } diff --git a/src/server/scripts/Commands/cs_learn.cpp b/src/server/scripts/Commands/cs_learn.cpp index 57fe66a981..2da6946a2e 100644 --- a/src/server/scripts/Commands/cs_learn.cpp +++ b/src/server/scripts/Commands/cs_learn.cpp @@ -140,8 +140,8 @@ class learn_commandscript : public CommandScript Player* player = handler->GetPlayer(); for (auto const& [id, quest] : sObjectMgr->GetQuestTemplates()) { - if (quest.GetRequiredClasses() && player->SatisfyQuestClass(&quest, false)) - player->LearnQuestRewardedSpells(&quest); + if (quest->GetRequiredClasses() && player->SatisfyQuestClass(quest.get(), false)) + player->LearnQuestRewardedSpells(quest.get()); } return true; } diff --git a/src/server/scripts/Commands/cs_lookup.cpp b/src/server/scripts/Commands/cs_lookup.cpp index b14bc9661c..dfdbdc3958 100644 --- a/src/server/scripts/Commands/cs_lookup.cpp +++ b/src/server/scripts/Commands/cs_lookup.cpp @@ -710,7 +710,7 @@ class lookup_commandscript : public CommandScript } if (handler->GetSession()) - handler->PSendSysMessage(LANG_QUEST_LIST_CHAT, questTemplatePair.first, questTemplatePair.first, questTemplatePair.second.GetQuestLevel(), title.c_str(), statusStr); + handler->PSendSysMessage(LANG_QUEST_LIST_CHAT, questTemplatePair.first, questTemplatePair.first, questTemplatePair.second->GetQuestLevel(), title.c_str(), statusStr); else handler->PSendSysMessage(LANG_QUEST_LIST_CONSOLE, questTemplatePair.first, title.c_str(), statusStr); @@ -722,7 +722,7 @@ class lookup_commandscript : public CommandScript } } - std::string const& title = questTemplatePair.second.GetTitle(); + std::string const& title = questTemplatePair.second->GetTitle(); if (title.empty()) continue; @@ -755,7 +755,7 @@ class lookup_commandscript : public CommandScript } if (handler->GetSession()) - handler->PSendSysMessage(LANG_QUEST_LIST_CHAT, questTemplatePair.first, questTemplatePair.first, questTemplatePair.second.GetQuestLevel(), title.c_str(), statusStr); + handler->PSendSysMessage(LANG_QUEST_LIST_CHAT, questTemplatePair.first, questTemplatePair.first, questTemplatePair.second->GetQuestLevel(), title.c_str(), statusStr); else handler->PSendSysMessage(LANG_QUEST_LIST_CONSOLE, questTemplatePair.first, title.c_str(), statusStr); From 08c293462f19684cb7bbab9ce2d371cf05742c60 Mon Sep 17 00:00:00 2001 From: Shauren Date: Wed, 13 Mar 2024 19:56:34 +0100 Subject: [PATCH 10/19] GCC build fix (cherry picked from commit b705283d0e6c1619ea3e436a15d40a0670caf1a3) --- tests/common/UniqueTrackablePtr.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/common/UniqueTrackablePtr.cpp b/tests/common/UniqueTrackablePtr.cpp index a6de1d68ce..12d1188a9a 100644 --- a/tests/common/UniqueTrackablePtr.cpp +++ b/tests/common/UniqueTrackablePtr.cpp @@ -106,7 +106,7 @@ TEST_CASE("Trinity::unique_weak_ptr", "[UniqueTrackablePtr]") } // disable warning about invalid reinterpret_cast, test intentionally tests this -#if TRINITY_COMPILER == TRINITY_COMPILER_GNU +#ifdef __clang__ #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wreinterpret-base-class" #endif @@ -160,6 +160,6 @@ TEST_CASE("Trinity::unique_strong_ref_ptr type casts", "[UniqueTrackablePtr]") } } -#if TRINITY_COMPILER == TRINITY_COMPILER_GNU +#ifdef __clang__ #pragma GCC diagnostic pop #endif From fd0b00cff4e2dd2508b2f15a3329d17e8e6658c7 Mon Sep 17 00:00:00 2001 From: Aokromes Date: Thu, 14 Mar 2024 19:42:51 +0100 Subject: [PATCH 11/19] DB/Quest: The Purification of Quel'Delar closes #4866 by CraftedRO One issue exist, you need to enter creating raid but you cannot complete on raid, you must wait to end the blablabla then leave raid --- .../world/3.3.5/2024_03_14_00_world.sql | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 sql/updates/world/3.3.5/2024_03_14_00_world.sql diff --git a/sql/updates/world/3.3.5/2024_03_14_00_world.sql b/sql/updates/world/3.3.5/2024_03_14_00_world.sql new file mode 100644 index 0000000000..92b793d1fa --- /dev/null +++ b/sql/updates/world/3.3.5/2024_03_14_00_world.sql @@ -0,0 +1,18 @@ +-- Cast aura 70193 on player if one of the following conditions are meet +DELETE FROM `conditions` WHERE `SourceTypeOrReferenceId` = 17 AND `SourceGroup` = 0 AND `SourceEntry` = 70193; +INSERT INTO `conditions` (`SourceTypeOrReferenceId`, `SourceGroup`, `SourceEntry`, `SourceId`, `ElseGroup`, `ConditionTypeOrReference`, `ConditionTarget`, `ConditionValue1`, `ConditionValue2`, `ConditionValue3`, `NegativeCondition`, `ErrorType`, `ErrorTextId`, `ScriptName`, `Comment`) VALUES +(17, 0, 70193, 0, 1, 8, 0, 24480, 0, 0, 0, 0, 0, '', "Cast aura 70193 on player only if quest The Halls Of Reflection (A) rewarded"), +(17, 0, 70193, 0, 2, 47, 0, 24522, 74, 0, 0, 0, 0, '', "Cast aura 70193 on player only if quest Journey To The Sunwell (A) progress | completed | rewarded"), +(17, 0, 70193, 0, 3, 47, 0, 24535, 74, 0, 0, 0, 0, '', "Cast aura 70193 on player only if quest Thalorien Dawnseeker (A) progress | completed | rewarded"), +(17, 0, 70193, 0, 4, 8, 0, 24561, 0, 0, 0, 0, 0, '', "Cast aura 70193 on player only if quest The Halls Of Reflection (H) rewarded"), +(17, 0, 70193, 0, 5, 47, 0, 24562, 74, 0, 0, 0, 0, '', "Cast aura 70193 on player only if quest Journey To The Sunwell (H) progress | completed | rewarded"), +(17, 0, 70193, 0, 6, 47, 0, 24563, 74, 0, 0, 0, 0, '', "Cast aura 70193 on player only if quest Thalorien Dawnseeker (H) progress | completed | rewarded"); + +-- +DELETE FROM `spell_area` WHERE `spell`=70193 AND `quest_start` IN (24535,24563); +INSERT INTO `spell_area` (`spell`, `area`, `quest_start`, `quest_end`, `aura_spell`, `racemask`, `gender`, `autocast`, `quest_start_status`, `quest_end_status`) VALUES +(70193, 4092, 24535, 24535, 0, 0, 2, 1, 75, 75), +(70193, 4092, 24563, 24563, 0, 0, 2, 1, 75, 75); + +-- +UPDATE `spell_area` SET `quest_start_status`=75,`quest_end_status`=75 WHERE `spell`=70193 AND `area`=4094; From 767e9f3046afdce52df3b40a52ce9ca239f892fd Mon Sep 17 00:00:00 2001 From: Aokromes Date: Thu, 14 Mar 2024 19:52:01 +0100 Subject: [PATCH 12/19] DB/Creature: Update Kialon Nightblade closes #29760 by CraftedRO --- .../world/3.3.5/2024_03_14_01_world.sql | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 sql/updates/world/3.3.5/2024_03_14_01_world.sql diff --git a/sql/updates/world/3.3.5/2024_03_14_01_world.sql b/sql/updates/world/3.3.5/2024_03_14_01_world.sql new file mode 100644 index 0000000000..fb3c010527 --- /dev/null +++ b/sql/updates/world/3.3.5/2024_03_14_01_world.sql @@ -0,0 +1,23 @@ +-- Update Kialon Nightblade +UPDATE `creature_template_addon` SET `PvPFlags`=1 WHERE `entry`=18098; +UPDATE `creature_template` SET `speed_walk`=1 WHERE `entry`=18098; + +-- Waypoints +SET @PATH=64051 * 10; +DELETE FROM `waypoint_data` WHERE `id`=@PATH; +INSERT INTO `waypoint_data` (`id`, `point`, `position_x`, `position_y`, `position_z`, `orientation`, `delay`, `move_type`, `action`, `action_chance`, `wpguid`) VALUES +(@PATH, 0, 1955.909, 6887.554, 162.2125, NULL, 0, 0, 0, 100, 0), +(@PATH, 1, 1957.126, 6870.499, 161.0544, NULL, 0, 0, 0, 100, 0), +(@PATH, 2, 1963.431, 6862.901, 160.0951, NULL, 0, 0, 0, 100, 0), +(@PATH, 3, 1972.715, 6859.702, 162.0977, NULL, 60000, 0, 0, 100, 0), +(@PATH, 4, 1964.917, 6866.565, 160.7522, NULL, 0, 0, 0, 100, 0), +(@PATH, 5, 1956.629, 6881.325, 161.8812, NULL, 0, 0, 0, 100, 0), +(@PATH, 6, 1955.969, 6887.533, 162.1539, NULL, 0, 0, 0, 100, 0), +(@PATH, 7, 1957.679, 6894.385, 161.872, NULL, 300000, 0, 0, 100, 0); + +-- SAI +UPDATE `creature_template` SET `AIName` = 'SmartAI' WHERE `entry` = 18098; +DELETE FROM `smart_scripts` WHERE `source_type` = 0 AND `entryorguid` = 18098; +INSERT INTO `smart_scripts` (`entryorguid`, `source_type`, `id`, `link`, `event_type`, `event_phase_mask`, `event_chance`, `event_flags`, `event_param1`, `event_param2`, `event_param3`, `event_param4`, `event_param5`, `action_type`, `action_param1`, `action_param2`, `action_param3`, `action_param4`, `action_param5`, `action_param6`, `target_type`, `target_param1`, `target_param2`, `target_param3`, `target_param4`, `target_x`, `target_y`, `target_z`, `target_o`, `comment`) VALUES +(18098, 0, 0, 0, 40, 0, 100, 0, 3, 640510, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, "Kialon Nightblade - On Waypoint 3 reached - Say Line 0"), +(18098, 0, 1, 0, 40, 0, 100, 0, 7, 640510, 0, 0, 0, 66, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 4.45059, "Kialon Nightblade - On Waypoint 7 reached - Set Orientation"); From f46f617c33090b22239ff73574f65df2e2a3f58f Mon Sep 17 00:00:00 2001 From: Aokromes Date: Thu, 14 Mar 2024 19:54:13 +0100 Subject: [PATCH 13/19] DB/Locales: Correct wrong translation and add a missing esES/esMX item locale closes #29803 by Odyssey --- sql/updates/world/3.3.5/2024_03_14_02_world.sql | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 sql/updates/world/3.3.5/2024_03_14_02_world.sql diff --git a/sql/updates/world/3.3.5/2024_03_14_02_world.sql b/sql/updates/world/3.3.5/2024_03_14_02_world.sql new file mode 100644 index 0000000000..7d307eb342 --- /dev/null +++ b/sql/updates/world/3.3.5/2024_03_14_02_world.sql @@ -0,0 +1,7 @@ +-- Update wrong translation for 'Scroll of enchant shield: defense' +UPDATE `item_template_locale` SET `Name`='Pergamino de Encantar escudo: defensa' WHERE `ID`=38954 AND `locale` IN ('esES','esMX'); +-- Add missing locale for 'Scroll of enchant shield: greater intellect' +DELETE FROM `item_template_locale` WHERE `ID`=44455 AND `locale` IN ('esES','esMX'); +INSERT INTO `item_template_locale` (`ID`, `locale`, `Name`, `Description`, `VerifiedBuild`) VALUES +(44455, 'esES', 'Pergamino de Encantar escudo: intelecto superior', '', -12340), +(44455, 'esMX', 'Pergamino de Encantar escudo: intelecto superior', '', -12340); From b64e261e942e093be906e0591c8b4232706ee0e7 Mon Sep 17 00:00:00 2001 From: Shauren Date: Thu, 14 Mar 2024 11:01:58 +0100 Subject: [PATCH 14/19] Core/Objects: Rename Object::m_isWorldObject and related functions to avoid conflicting with "WorldObject" class name (cherry picked from commit 9402c66e8423243d13dbc19e8713e298bea0ac7b) --- .../Entities/DynamicObject/DynamicObject.cpp | 2 +- src/server/game/Entities/Object/Object.cpp | 42 +++++++++---------- src/server/game/Entities/Object/Object.h | 8 ++-- src/server/game/Entities/Unit/Unit.cpp | 4 +- src/server/game/Grids/ObjectGridLoader.cpp | 2 +- src/server/game/Maps/Map.cpp | 16 +++---- 6 files changed, 37 insertions(+), 37 deletions(-) diff --git a/src/server/game/Entities/DynamicObject/DynamicObject.cpp b/src/server/game/Entities/DynamicObject/DynamicObject.cpp index dbb527da01..84d268f562 100644 --- a/src/server/game/Entities/DynamicObject/DynamicObject.cpp +++ b/src/server/game/Entities/DynamicObject/DynamicObject.cpp @@ -108,7 +108,7 @@ bool DynamicObject::CreateDynamicObject(ObjectGuid::LowType guidlow, Unit* caste SetFloatValue(DYNAMICOBJECT_RADIUS, radius); SetUInt32Value(DYNAMICOBJECT_CASTTIME, GameTime::GetGameTimeMS()); - if (IsWorldObject()) + if (IsStoredInWorldObjectGridContainer()) setActive(true); //must before add to map to be put in world container Transport* transport = caster->GetTransport(); diff --git a/src/server/game/Entities/Object/Object.cpp b/src/server/game/Entities/Object/Object.cpp index 9765ef9143..155596e7e3 100644 --- a/src/server/game/Entities/Object/Object.cpp +++ b/src/server/game/Entities/Object/Object.cpp @@ -76,21 +76,6 @@ Object::Object() : m_scriptRef(this, NoopObjectDeleter()) m_objectUpdated = false; } -WorldObject::~WorldObject() -{ - // this may happen because there are many !create/delete - if (IsWorldObject() && m_currMap) - { - if (GetTypeId() == TYPEID_CORPSE) - { - TC_LOG_FATAL("misc", "WorldObject::~WorldObject Corpse Type: {} ({}) deleted but still in map!!", - ToCorpse()->GetType(), GetGUID().ToString()); - ABORT(); - } - ResetMap(); - } -} - Object::~Object() { if (IsInWorld()) @@ -973,7 +958,7 @@ void MovementInfo::OutDebug() } WorldObject::WorldObject(bool isWorldObject) : Object(), WorldLocation(), LastUsedScriptID(0), -m_movementInfo(), m_name(), m_isActive(false), m_isFarVisible(false), m_isWorldObject(isWorldObject), m_zoneScript(nullptr), +m_movementInfo(), m_name(), m_isActive(false), m_isFarVisible(false), m_isStoredInWorldObjectGridContainer(isWorldObject), m_zoneScript(nullptr), m_transport(nullptr), m_zoneId(0), m_areaId(0), m_staticFloorZ(VMAP_INVALID_HEIGHT), m_outdoors(false), m_liquidStatus(LIQUID_MAP_NO_WATER), m_currMap(nullptr), m_InstanceId(0), m_phaseMask(PHASEMASK_NORMAL), m_notifyflags(0) { @@ -981,7 +966,22 @@ m_currMap(nullptr), m_InstanceId(0), m_phaseMask(PHASEMASK_NORMAL), m_notifyflag m_serverSideVisibilityDetect.SetValue(SERVERSIDE_VISIBILITY_GHOST, GHOST_VISIBILITY_ALIVE); } -void WorldObject::SetWorldObject(bool on) +WorldObject::~WorldObject() +{ + // this may happen because there are many !create/delete + if (IsStoredInWorldObjectGridContainer() && m_currMap) + { + if (GetTypeId() == TYPEID_CORPSE) + { + TC_LOG_FATAL("misc", "WorldObject::~WorldObject Corpse Type: {} ({}) deleted but still in map!!", + ToCorpse()->GetType(), GetGUID().ToString()); + ABORT(); + } + ResetMap(); + } +} + +void WorldObject::SetIsStoredInWorldObjectGridContainer(bool on) { if (!IsInWorld()) return; @@ -989,9 +989,9 @@ void WorldObject::SetWorldObject(bool on) GetMap()->AddObjectToSwitchList(this, on); } -bool WorldObject::IsWorldObject() const +bool WorldObject::IsStoredInWorldObjectGridContainer() const { - if (m_isWorldObject) + if (m_isStoredInWorldObjectGridContainer) return true; if (ToCreature() && ToCreature()->m_isTempWorldObject) @@ -1826,7 +1826,7 @@ void WorldObject::SetMap(Map* map) m_currMap = map; m_mapId = map->GetId(); m_InstanceId = map->GetInstanceId(); - if (IsWorldObject()) + if (IsStoredInWorldObjectGridContainer()) m_currMap->AddWorldObject(this); } @@ -1834,7 +1834,7 @@ void WorldObject::ResetMap() { ASSERT(m_currMap); ASSERT(!IsInWorld()); - if (IsWorldObject()) + if (IsStoredInWorldObjectGridContainer()) m_currMap->RemoveWorldObject(this); m_currMap = nullptr; //maybe not for corpse diff --git a/src/server/game/Entities/Object/Object.h b/src/server/game/Entities/Object/Object.h index abf3bd3bf9..c0a1a2b265 100644 --- a/src/server/game/Entities/Object/Object.h +++ b/src/server/game/Entities/Object/Object.h @@ -497,9 +497,9 @@ class TC_GAME_API WorldObject : public Object, public WorldLocation void SetFarVisible(bool on); bool IsVisibilityOverridden() const { return m_visibilityDistanceOverride.has_value(); } void SetVisibilityDistanceOverride(VisibilityDistanceType type); - void SetWorldObject(bool apply); - bool IsPermanentWorldObject() const { return m_isWorldObject; } - bool IsWorldObject() const; + void SetIsStoredInWorldObjectGridContainer(bool apply); + bool IsAlwaysStoredInWorldObjectGridContainer() const { return m_isStoredInWorldObjectGridContainer; } + bool IsStoredInWorldObjectGridContainer() const; uint32 LastUsedScriptID; @@ -538,7 +538,7 @@ class TC_GAME_API WorldObject : public Object, public WorldLocation bool m_isActive; bool m_isFarVisible; Optional m_visibilityDistanceOverride; - bool const m_isWorldObject; + bool const m_isStoredInWorldObjectGridContainer; ZoneScript* m_zoneScript; // transports diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp index 71ca198c61..43c3446daf 100644 --- a/src/server/game/Entities/Unit/Unit.cpp +++ b/src/server/game/Entities/Unit/Unit.cpp @@ -6348,7 +6348,7 @@ void Unit::AddPlayerToVision(Player* player) if (m_sharedVision.empty()) { setActive(true); - SetWorldObject(true); + SetIsStoredInWorldObjectGridContainer(true); } m_sharedVision.push_back(player); } @@ -6360,7 +6360,7 @@ void Unit::RemovePlayerFromVision(Player* player) if (m_sharedVision.empty()) { setActive(false); - SetWorldObject(false); + SetIsStoredInWorldObjectGridContainer(false); } } diff --git a/src/server/game/Grids/ObjectGridLoader.cpp b/src/server/game/Grids/ObjectGridLoader.cpp index b5e5826f04..2e8a85e61c 100644 --- a/src/server/game/Grids/ObjectGridLoader.cpp +++ b/src/server/game/Grids/ObjectGridLoader.cpp @@ -141,7 +141,7 @@ void ObjectWorldLoader::Visit(CorpseMapType& /*m*/) { corpse->AddToWorld(); GridType& cell = i_grid.GetGridType(i_cell.CellX(), i_cell.CellY()); - if (corpse->IsWorldObject()) + if (corpse->IsStoredInWorldObjectGridContainer()) cell.AddWorldObject(corpse); else cell.AddGridObject(corpse); diff --git a/src/server/game/Maps/Map.cpp b/src/server/game/Maps/Map.cpp index e58d4e17a5..ded02362b1 100644 --- a/src/server/game/Maps/Map.cpp +++ b/src/server/game/Maps/Map.cpp @@ -97,7 +97,7 @@ Map::~Map() while (!i_worldObjects.empty()) { WorldObject* obj = *i_worldObjects.begin(); - ASSERT(obj->IsWorldObject()); + ASSERT(obj->IsStoredInWorldObjectGridContainer()); //ASSERT(obj->GetTypeId() == TYPEID_CORPSE); obj->RemoveFromWorld(); obj->ResetMap(); @@ -316,7 +316,7 @@ template void Map::AddToGrid(T* obj, Cell const& cell) { NGridType* grid = getNGrid(cell.GridX(), cell.GridY()); - if (obj->IsWorldObject()) + if (obj->IsStoredInWorldObjectGridContainer()) grid->GetGridType(cell.CellX(), cell.CellY()).template AddWorldObject(obj); else grid->GetGridType(cell.CellX(), cell.CellY()).template AddGridObject(obj); @@ -326,7 +326,7 @@ template<> void Map::AddToGrid(Creature* obj, Cell const& cell) { NGridType* grid = getNGrid(cell.GridX(), cell.GridY()); - if (obj->IsWorldObject()) + if (obj->IsStoredInWorldObjectGridContainer()) grid->GetGridType(cell.CellX(), cell.CellY()).AddWorldObject(obj); else grid->GetGridType(cell.CellX(), cell.CellY()).AddGridObject(obj); @@ -347,7 +347,7 @@ template<> void Map::AddToGrid(DynamicObject* obj, Cell const& cell) { NGridType* grid = getNGrid(cell.GridX(), cell.GridY()); - if (obj->IsWorldObject()) + if (obj->IsStoredInWorldObjectGridContainer()) grid->GetGridType(cell.CellX(), cell.CellY()).AddWorldObject(obj); else grid->GetGridType(cell.CellX(), cell.CellY()).AddGridObject(obj); @@ -367,7 +367,7 @@ void Map::AddToGrid(Corpse* obj, Cell const& cell) // to avoid failing an assertion in GridObject::AddToGrid if (grid->isGridObjectDataLoaded()) { - if (obj->IsWorldObject()) + if (obj->IsStoredInWorldObjectGridContainer()) grid->GetGridType(cell.CellX(), cell.CellY()).AddWorldObject(obj); else grid->GetGridType(cell.CellX(), cell.CellY()).AddGridObject(obj); @@ -380,7 +380,7 @@ void Map::SwitchGridContainers(T* /*obj*/, bool /*on*/) { } template<> void Map::SwitchGridContainers(Creature* obj, bool on) { - ASSERT(!obj->IsPermanentWorldObject()); + ASSERT(!obj->IsAlwaysStoredInWorldObjectGridContainer()); CellCoord p = Trinity::ComputeCellCoord(obj->GetPositionX(), obj->GetPositionY()); if (!p.IsCoordValid()) { @@ -425,7 +425,7 @@ void Map::SwitchGridContainers(Creature* obj, bool on) template<> void Map::SwitchGridContainers(GameObject* obj, bool on) { - ASSERT(!obj->IsPermanentWorldObject()); + ASSERT(!obj->IsAlwaysStoredInWorldObjectGridContainer()); CellCoord p = Trinity::ComputeCellCoord(obj->GetPositionX(), obj->GetPositionY()); if (!p.IsCoordValid()) { @@ -3603,7 +3603,7 @@ void Map::RemoveAllObjectsInRemoveList() bool on = itr->second; i_objectsToSwitch.erase(itr); - if (!obj->IsPermanentWorldObject()) + if (!obj->IsAlwaysStoredInWorldObjectGridContainer()) { switch (obj->GetTypeId()) { From 0dcff2624e6df1c27d7a4d6a66ebcc0b2d698413 Mon Sep 17 00:00:00 2001 From: Shauren Date: Thu, 14 Mar 2024 11:37:32 +0100 Subject: [PATCH 15/19] Core/Objects: Added ToWorldObject and ToItem (cherry picked from commit 6f6af6a1a1508508d0e42b90f0acf4f363cf91bd) --- src/server/game/Entities/Object/Object.cpp | 37 ++++++++++++------- src/server/game/Entities/Object/Object.h | 13 +++++++ src/server/game/Entities/Object/ObjectGuid.h | 8 ++-- src/server/game/Entities/Player/Player.cpp | 25 ++++++------- src/server/game/Maps/MapScripts.cpp | 11 +++--- src/server/game/Spells/Auras/SpellAuras.cpp | 6 +-- src/server/game/Spells/Spell.cpp | 3 +- .../Outland/zone_blades_edge_mountains.cpp | 2 +- 8 files changed, 63 insertions(+), 42 deletions(-) diff --git a/src/server/game/Entities/Object/Object.cpp b/src/server/game/Entities/Object/Object.cpp index 155596e7e3..21f296fcad 100644 --- a/src/server/game/Entities/Object/Object.cpp +++ b/src/server/game/Entities/Object/Object.cpp @@ -81,8 +81,8 @@ Object::~Object() if (IsInWorld()) { TC_LOG_FATAL("misc", "Object::~Object {} deleted but still in world!!", GetGUID().ToString()); - if (isType(TYPEMASK_ITEM)) - TC_LOG_FATAL("misc", "Item slot {}", ((Item*)this)->GetSlot()); + if (Item* item = ToItem()) + TC_LOG_FATAL("misc", "Item slot {}", item->GetSlot()); ABORT(); } @@ -180,9 +180,9 @@ void Object::BuildCreateUpdateBlockForPlayer(UpdateData* data, Player* target) c if (target == this) // building packet for yourself flags |= UPDATEFLAG_SELF; - if (isType(TYPEMASK_UNIT)) + if (Unit const* unit = ToUnit()) { - if (ToUnit()->GetVictim()) + if (unit->GetVictim()) flags |= UPDATEFLAG_HAS_TARGET; } @@ -233,7 +233,7 @@ void Object::DestroyForPlayer(Player* target, bool onDeath) const { ASSERT(target); - if (isType(TYPEMASK_UNIT) || isType(TYPEMASK_PLAYER)) + if (IsUnit()) { if (Battleground* bg = target->GetBattleground()) { @@ -303,10 +303,9 @@ void Object::BuildMovementUpdate(ByteBuffer* data, uint16 flags) const Unit const* unit = nullptr; WorldObject const* object = nullptr; - if (isType(TYPEMASK_UNIT)) - unit = ToUnit(); - else - object = (WorldObject const*)this; + unit = ToUnit(); + if (!unit) + object = ToWorldObject(); *data << uint16(flags); // update flags @@ -1422,7 +1421,11 @@ void WorldObject::UpdateGroundPositionZ(float x, float y, float &z) const { float new_z = GetMapHeight(x, y, z); if (new_z > INVALID_HEIGHT) - z = new_z + (isType(TYPEMASK_UNIT) ? static_cast(this)->GetHoverOffset() : 0.0f); + { + z = new_z; + if (Unit const* unit = ToUnit()) + z += unit->GetHoverOffset(); + } } void WorldObject::UpdateAllowedPositionZ(float x, float y, float &z, float* groundZ) const @@ -3421,7 +3424,7 @@ void WorldObject::DestroyForNearbyPlayers() if (!player->HaveAtClient(this)) continue; - if (isType(TYPEMASK_UNIT) && ToUnit()->GetCharmerGUID() == player->GetGUID()) /// @todo this is for puppet + if (Unit const* unit = ToUnit(); unit && unit->GetCharmerGUID() == player->GetGUID()) /// @todo this is for puppet continue; if (GetTypeId() == TYPEID_UNIT) @@ -3546,9 +3549,15 @@ float WorldObject::GetFloorZ() const float WorldObject::GetMapWaterOrGroundLevel(float x, float y, float z, float* ground/* = nullptr*/) const { - return GetMap()->GetWaterOrGroundLevel(GetPhaseMask(), x, y, z, ground, - isType(TYPEMASK_UNIT) ? !static_cast(this)->HasAuraType(SPELL_AURA_WATER_WALK) : false, - GetCollisionHeight()); + bool swimming = [&]() + { + if (Unit const* unit = ToUnit()) + return !unit->HasAuraType(SPELL_AURA_WATER_WALK); + + return false; + }(); + + return GetMap()->GetWaterOrGroundLevel(GetPhaseMask(), x, y, z, ground, swimming, GetCollisionHeight()); } float WorldObject::GetMapHeight(float x, float y, float z, bool vmap/* = true*/, float distanceToSearch/* = DEFAULT_HEIGHT_SEARCH*/) const diff --git a/src/server/game/Entities/Object/Object.h b/src/server/game/Entities/Object/Object.h index c0a1a2b265..b129f5129c 100644 --- a/src/server/game/Entities/Object/Object.h +++ b/src/server/game/Entities/Object/Object.h @@ -42,6 +42,7 @@ class CreatureAI; class DynamicObject; class GameObject; class InstanceScript; +class Item; class Map; class Player; class Spell; @@ -163,6 +164,18 @@ class TC_GAME_API Object // FG: some hacky helpers void ForceValuesUpdateAtIndex(uint32); + inline bool IsWorldObject() const { return isType(TYPEMASK_WORLDOBJECT); } + static WorldObject* ToWorldObject(Object* o) { return o ? o->ToWorldObject() : nullptr; } + static WorldObject const* ToWorldObject(Object const* o) { return o ? o->ToWorldObject() : nullptr; } + WorldObject* ToWorldObject() { if (IsUnit()) return reinterpret_cast(this); else return nullptr; } + WorldObject const* ToWorldObject() const { if (IsUnit()) return reinterpret_cast(this); else return nullptr; } + + inline bool IsItem() const { return isType(TYPEMASK_ITEM); } + static Item* ToItem(Object* o) { return o ? o->ToItem() : nullptr; } + static Item const* ToItem(Object const* o) { return o ? o->ToItem() : nullptr; } + Item* ToItem() { if (IsItem()) return reinterpret_cast(this); else return nullptr; } + Item const* ToItem() const { if (IsItem()) return reinterpret_cast(this); else return nullptr; } + inline bool IsPlayer() const { return GetTypeId() == TYPEID_PLAYER; } static Player* ToPlayer(Object* o) { return o ? o->ToPlayer() : nullptr; } static Player const* ToPlayer(Object const* o) { return o ? o->ToPlayer() : nullptr; } diff --git a/src/server/game/Entities/Object/ObjectGuid.h b/src/server/game/Entities/Object/ObjectGuid.h index cc720effc9..9c09e75c56 100644 --- a/src/server/game/Entities/Object/ObjectGuid.h +++ b/src/server/game/Entities/Object/ObjectGuid.h @@ -26,8 +26,8 @@ #include #include #include -#include #include +#include enum TypeID { @@ -47,13 +47,15 @@ enum TypeMask { TYPEMASK_OBJECT = 0x0001, TYPEMASK_ITEM = 0x0002, - TYPEMASK_CONTAINER = 0x0006, // TYPEMASK_ITEM | 0x0004 + TYPEMASK_CONTAINER = 0x0004, // TYPEMASK_ITEM | 0x0004 TYPEMASK_UNIT = 0x0008, // creature TYPEMASK_PLAYER = 0x0010, TYPEMASK_GAMEOBJECT = 0x0020, TYPEMASK_DYNAMICOBJECT = 0x0040, TYPEMASK_CORPSE = 0x0080, - TYPEMASK_SEER = TYPEMASK_PLAYER | TYPEMASK_UNIT | TYPEMASK_DYNAMICOBJECT + + TYPEMASK_SEER = TYPEMASK_UNIT | TYPEMASK_DYNAMICOBJECT, + TYPEMASK_WORLDOBJECT = TYPEMASK_UNIT | TYPEMASK_GAMEOBJECT | TYPEMASK_DYNAMICOBJECT | TYPEMASK_CORPSE }; enum class HighGuid diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp index b4c0139c76..aca4f18335 100644 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -15173,7 +15173,7 @@ void Player::RewardQuest(Quest const* quest, uint32 reward, Object* questGiver, if (quest->GetRewSpellCast() > 0) { SpellInfo const* spellInfo = ASSERT_NOTNULL(sSpellMgr->GetSpellInfo(quest->GetRewSpellCast())); - if (questGiver->isType(TYPEMASK_UNIT) && !spellInfo->HasEffect(SPELL_EFFECT_LEARN_SPELL) && !spellInfo->HasEffect(SPELL_EFFECT_CREATE_ITEM) && !spellInfo->IsSelfCast()) + if (questGiver->IsUnit() && !spellInfo->HasEffect(SPELL_EFFECT_LEARN_SPELL) && !spellInfo->HasEffect(SPELL_EFFECT_CREATE_ITEM) && !spellInfo->IsSelfCast()) { if (Creature* creature = GetMap()->GetCreature(questGiver->GetGUID())) creature->CastSpell(this, quest->GetRewSpellCast(), true); @@ -15184,7 +15184,7 @@ void Player::RewardQuest(Quest const* quest, uint32 reward, Object* questGiver, else if (quest->GetRewSpell() > 0) { SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(quest->GetRewSpell()); - if (questGiver->isType(TYPEMASK_UNIT) && !spellInfo->HasEffect(SPELL_EFFECT_LEARN_SPELL) && !spellInfo->HasEffect(SPELL_EFFECT_CREATE_ITEM) && !spellInfo->IsSelfCast()) + if (questGiver->IsUnit() && !spellInfo->HasEffect(SPELL_EFFECT_LEARN_SPELL) && !spellInfo->HasEffect(SPELL_EFFECT_CREATE_ITEM) && !spellInfo->IsSelfCast()) { if (Creature* creature = GetMap()->GetCreature(questGiver->GetGUID())) creature->CastSpell(this, quest->GetRewSpell(), true); @@ -22393,7 +22393,7 @@ void Player::UpdateVisibilityOf(WorldObject* target) // target aura duration for caster show only if target exist at caster client // send data at target visibility change (adding to client) - if (target->isType(TYPEMASK_UNIT)) + if (target->IsUnit()) SendInitialVisiblePackets(static_cast(target)); } } @@ -24308,14 +24308,11 @@ bool ItemPosCount::isContainedIn(std::vector const& vec) const void Player::StopCastingBindSight() const { - if (WorldObject* target = GetViewpoint()) + if (Unit* target = Object::ToUnit(GetViewpoint())) { - if (target->isType(TYPEMASK_UNIT)) - { - static_cast(target)->RemoveAurasByType(SPELL_AURA_BIND_SIGHT, GetGUID()); - static_cast(target)->RemoveAurasByType(SPELL_AURA_MOD_POSSESS, GetGUID()); - static_cast(target)->RemoveAurasByType(SPELL_AURA_MOD_POSSESS_PET, GetGUID()); - } + target->RemoveAurasByType(SPELL_AURA_BIND_SIGHT, GetGUID()); + target->RemoveAurasByType(SPELL_AURA_MOD_POSSESS, GetGUID()); + target->RemoveAurasByType(SPELL_AURA_MOD_POSSESS_PET, GetGUID()); } } @@ -24335,8 +24332,8 @@ void Player::SetViewpoint(WorldObject* target, bool apply) // farsight dynobj or puppet may be very far away UpdateVisibilityOf(target); - if (target->isType(TYPEMASK_UNIT) && target != GetVehicleBase()) - static_cast(target)->AddPlayerToVision(this); + if (Unit* targetUnit = target->ToUnit(); targetUnit && targetUnit != GetVehicleBase()) + targetUnit->AddPlayerToVision(this); SetSeer(target); } else @@ -24349,8 +24346,8 @@ void Player::SetViewpoint(WorldObject* target, bool apply) return; } - if (target->isType(TYPEMASK_UNIT) && target != GetVehicleBase()) - static_cast(target)->RemovePlayerFromVision(this); + if (Unit* targetUnit = target->ToUnit(); targetUnit && targetUnit != GetVehicleBase()) + targetUnit->RemovePlayerFromVision(this); //must immediately set seer back otherwise may crash SetSeer(this); diff --git a/src/server/game/Maps/MapScripts.cpp b/src/server/game/Maps/MapScripts.cpp index 8c22fe3d87..9972c3f4a2 100644 --- a/src/server/game/Maps/MapScripts.cpp +++ b/src/server/game/Maps/MapScripts.cpp @@ -42,7 +42,7 @@ void Map::ScriptsStart(std::map> const // prepare static data ObjectGuid sourceGUID = source ? source->GetGUID() : ObjectGuid::Empty; //some script commands doesn't have source ObjectGuid targetGUID = target ? target->GetGUID() : ObjectGuid::Empty; - ObjectGuid ownerGUID = (source && source->GetTypeId() == TYPEID_ITEM) ? ((Item*)source)->GetOwnerGUID() : ObjectGuid::Empty; + ObjectGuid ownerGUID = [&] { if (Item* item = Object::ToItem(source)) return item->GetOwnerGUID(); return ObjectGuid::Empty; }(); ///- Schedule script execution for all scripts in the script map ScriptMap const* s2 = &(s->second); @@ -77,7 +77,7 @@ void Map::ScriptCommandStart(ScriptInfo const& script, uint32 delay, Object* sou // prepare static data ObjectGuid sourceGUID = source ? source->GetGUID() : ObjectGuid::Empty; ObjectGuid targetGUID = target ? target->GetGUID() : ObjectGuid::Empty; - ObjectGuid ownerGUID = (source && source->GetTypeId() == TYPEID_ITEM) ? ((Item*)source)->GetOwnerGUID() : ObjectGuid::Empty; + ObjectGuid ownerGUID = [&] { if (Item* item = Object::ToItem(source)) return item->GetOwnerGUID(); return ObjectGuid::Empty; }(); ScriptAction sa; sa.sourceGUID = sourceGUID; @@ -192,7 +192,7 @@ inline Unit* Map::_GetScriptUnit(Object* obj, bool isSource, ScriptInfo const* s Unit* unit = nullptr; if (!obj) TC_LOG_ERROR("scripts", "{} {} object is NULL.", scriptInfo->GetDebugInfo(), isSource ? "source" : "target"); - else if (!obj->isType(TYPEMASK_UNIT)) + else if (!obj->IsUnit()) TC_LOG_ERROR("scripts", "{} {} object is not unit {}, skipping.", scriptInfo->GetDebugInfo(), isSource ? "source" : "target", obj->GetGUID().ToString()); else @@ -268,7 +268,7 @@ inline void Map::_ScriptProcessDoor(Object* source, Object* target, ScriptInfo c TC_LOG_ERROR("scripts", "{} door guid is not specified.", scriptInfo->GetDebugInfo()); else if (!source) TC_LOG_ERROR("scripts", "{} source object is NULL.", scriptInfo->GetDebugInfo()); - else if (!source->isType(TYPEMASK_UNIT)) + else if (!source->IsUnit()) TC_LOG_ERROR("scripts", "{} source object is not unit {}, skipping.", scriptInfo->GetDebugInfo(), source->GetGUID().ToString()); else @@ -289,9 +289,8 @@ inline void Map::_ScriptProcessDoor(Object* source, Object* target, ScriptInfo c { pDoor->UseDoorOrButton(nTimeToToggle); - if (target && target->isType(TYPEMASK_GAMEOBJECT)) + if (GameObject* goTarget = Object::ToGameObject(target)) { - GameObject* goTarget = target->ToGameObject(); if (goTarget && goTarget->GetGoType() == GAMEOBJECT_TYPE_BUTTON) goTarget->UseDoorOrButton(nTimeToToggle); } diff --git a/src/server/game/Spells/Auras/SpellAuras.cpp b/src/server/game/Spells/Auras/SpellAuras.cpp index c987893f2b..7458e62ec9 100644 --- a/src/server/game/Spells/Auras/SpellAuras.cpp +++ b/src/server/game/Spells/Auras/SpellAuras.cpp @@ -374,10 +374,10 @@ Aura* Aura::Create(AuraCreateInfo& createInfo) createInfo.CasterGUID = createInfo.Caster->GetGUID(); // check if aura can be owned by owner - if (createInfo._owner->isType(TYPEMASK_UNIT)) - if (!createInfo._owner->IsInWorld() || createInfo._owner->ToUnit()->IsDuringRemoveFromWorld()) + if (Unit* ownerUnit = createInfo._owner->ToUnit()) + if (!ownerUnit->IsInWorld() || ownerUnit->IsDuringRemoveFromWorld()) // owner not in world so don't allow to own not self cast single target auras - if (createInfo.CasterGUID != createInfo._owner->GetGUID() && createInfo._spellInfo->IsSingleTarget()) + if (createInfo.CasterGUID != ownerUnit->GetGUID() && createInfo._spellInfo->IsSingleTarget()) return nullptr; Aura* aura = nullptr; diff --git a/src/server/game/Spells/Spell.cpp b/src/server/game/Spells/Spell.cpp index 22b2b3a4c1..9518904791 100644 --- a/src/server/game/Spells/Spell.cpp +++ b/src/server/game/Spells/Spell.cpp @@ -596,7 +596,8 @@ m_caster((info->HasAttribute(SPELL_ATTR6_CAST_BY_CHARMER) && caster->GetCharmerO // Determine if spell can be reflected back to the caster // Patch 1.2 notes: Spell Reflection no longer reflects abilities - m_canReflect = caster->isType(TYPEMASK_UNIT) && m_spellInfo->DmgClass == SPELL_DAMAGE_CLASS_MAGIC && !m_spellInfo->HasAttribute(SPELL_ATTR0_ABILITY) + m_canReflect = caster->IsUnit() + && m_spellInfo->DmgClass == SPELL_DAMAGE_CLASS_MAGIC && !m_spellInfo->HasAttribute(SPELL_ATTR0_ABILITY) && !m_spellInfo->HasAttribute(SPELL_ATTR1_CANT_BE_REFLECTED) && !m_spellInfo->HasAttribute(SPELL_ATTR0_UNAFFECTED_BY_INVULNERABILITY) && !m_spellInfo->IsPassive(); diff --git a/src/server/scripts/Outland/zone_blades_edge_mountains.cpp b/src/server/scripts/Outland/zone_blades_edge_mountains.cpp index 71fba09e87..f6a31d4ba6 100644 --- a/src/server/scripts/Outland/zone_blades_edge_mountains.cpp +++ b/src/server/scripts/Outland/zone_blades_edge_mountains.cpp @@ -956,7 +956,7 @@ class npc_oscillating_frequency_scanner_master_bunny : public CreatureScript void IsSummonedBy(WorldObject* summoner) override { - if (summoner->isType(TYPEMASK_PLAYER)) + if (summoner->IsPlayer()) playerGuid = summoner->GetGUID(); } From 303ecbbf4e9cf91da8108bbc8a5ff1ab7b3ca2c2 Mon Sep 17 00:00:00 2001 From: Shauren Date: Thu, 14 Mar 2024 19:28:49 +0100 Subject: [PATCH 16/19] Core/Objects: Cook the copied pasta (cherry picked from commit 6224036efd9e6173f4650d7b7c0a31319a3dad7a) --- src/server/game/Entities/Object/Object.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/server/game/Entities/Object/Object.h b/src/server/game/Entities/Object/Object.h index b129f5129c..9dca2efa02 100644 --- a/src/server/game/Entities/Object/Object.h +++ b/src/server/game/Entities/Object/Object.h @@ -167,8 +167,8 @@ class TC_GAME_API Object inline bool IsWorldObject() const { return isType(TYPEMASK_WORLDOBJECT); } static WorldObject* ToWorldObject(Object* o) { return o ? o->ToWorldObject() : nullptr; } static WorldObject const* ToWorldObject(Object const* o) { return o ? o->ToWorldObject() : nullptr; } - WorldObject* ToWorldObject() { if (IsUnit()) return reinterpret_cast(this); else return nullptr; } - WorldObject const* ToWorldObject() const { if (IsUnit()) return reinterpret_cast(this); else return nullptr; } + WorldObject* ToWorldObject() { if (IsWorldObject()) return reinterpret_cast(this); else return nullptr; } + WorldObject const* ToWorldObject() const { if (IsWorldObject()) return reinterpret_cast(this); else return nullptr; } inline bool IsItem() const { return isType(TYPEMASK_ITEM); } static Item* ToItem(Object* o) { return o ? o->ToItem() : nullptr; } From 4e54a4ffb9fba004d0843f9dec945998acb561a3 Mon Sep 17 00:00:00 2001 From: Shauren Date: Thu, 14 Mar 2024 20:32:03 +0100 Subject: [PATCH 17/19] Core/Scripts: Removed script calls from constructors and destructors (cherry picked from commit 783f9c0ea38da35c328affa27ac4cf6b7bfd8bd8) --- src/server/game/Maps/Map.cpp | 6 ------ src/server/game/Maps/MapInstanced.cpp | 11 +++++++++++ src/server/game/Maps/MapManager.cpp | 7 +++++++ 3 files changed, 18 insertions(+), 6 deletions(-) diff --git a/src/server/game/Maps/Map.cpp b/src/server/game/Maps/Map.cpp index ded02362b1..7c49e8d5ad 100644 --- a/src/server/game/Maps/Map.cpp +++ b/src/server/game/Maps/Map.cpp @@ -86,10 +86,6 @@ struct RespawnInfoWithHandle : RespawnInfo Map::~Map() { - // UnloadAll must be called before deleting the map - - sScriptMgr->OnDestroyMap(this); - // Delete all waiting spawns, else there will be a memory leak // This doesn't delete from database. UnloadAllRespawnInfos(); @@ -300,8 +296,6 @@ i_scriptLock(false), _respawnTimes(std::make_unique()), _r _weatherUpdateTimer.SetInterval(time_t(1 * IN_MILLISECONDS)); MMAP::MMapFactory::createOrGetMMapManager()->loadMapInstance(sWorld->GetDataPath(), GetId(), GetInstanceId()); - - sScriptMgr->OnCreateMap(this); } void Map::InitVisibilityDistance() diff --git a/src/server/game/Maps/MapInstanced.cpp b/src/server/game/Maps/MapInstanced.cpp index ccd2d96215..66a51466e7 100644 --- a/src/server/game/Maps/MapInstanced.cpp +++ b/src/server/game/Maps/MapInstanced.cpp @@ -25,6 +25,7 @@ #include "MMapFactory.h" #include "ObjectMgr.h" #include "Player.h" +#include "ScriptMgr.h" #include "VMapFactory.h" #include "VMapManager2.h" #include "World.h" @@ -95,8 +96,12 @@ void MapInstanced::UnloadAll() { // Unload instanced maps for (InstancedMaps::iterator i = m_InstancedMaps.begin(); i != m_InstancedMaps.end(); ++i) + { i->second->UnloadAll(); + sScriptMgr->OnDestroyMap(i->second.get()); + } + m_InstancedMaps.clear(); // Unload own grids (just dummy(placeholder) grids, neccesary to unload GridMaps!) @@ -236,6 +241,8 @@ InstanceMap* MapInstanced::CreateInstance(uint32 InstanceId, InstanceSave* save, Trinity::unique_trackable_ptr& ptr = m_InstancedMaps[InstanceId]; ptr.reset(map); map->SetWeakPtr(ptr); + + sScriptMgr->OnCreateMap(map); return map; } @@ -263,6 +270,8 @@ BattlegroundMap* MapInstanced::CreateBattleground(uint32 InstanceId, Battlegroun Trinity::unique_trackable_ptr& ptr = m_InstancedMaps[InstanceId]; ptr.reset(map); map->SetWeakPtr(ptr); + + sScriptMgr->OnCreateMap(map); return map; } @@ -287,6 +296,8 @@ bool MapInstanced::DestroyInstance(InstancedMaps::iterator &itr) Map::UnloadAll(); } + sScriptMgr->OnDestroyMap(itr->second.get()); + // Free up the instance id and allow it to be reused for bgs and arenas (other instances are handled in the InstanceSaveMgr) if (itr->second->IsBattlegroundOrArena()) sMapMgr->FreeInstanceId(itr->second->GetInstanceId()); diff --git a/src/server/game/Maps/MapManager.cpp b/src/server/game/Maps/MapManager.cpp index d340a85e4d..d1ffc63a4c 100644 --- a/src/server/game/Maps/MapManager.cpp +++ b/src/server/game/Maps/MapManager.cpp @@ -33,6 +33,7 @@ #include "Player.h" #include "WorldSession.h" #include "Opcodes.h" +#include "ScriptMgr.h" #include MapManager::MapManager() @@ -89,6 +90,8 @@ Map* MapManager::CreateBaseMap(uint32 id) Trinity::unique_trackable_ptr& ptr = i_maps[id]; ptr.reset(map); map->SetWeakPtr(ptr); + + sScriptMgr->OnCreateMap(map); } ASSERT(map); @@ -260,8 +263,12 @@ void MapManager::UnloadAll() { // first unload maps for (auto iter = i_maps.begin(); iter != i_maps.end(); ++iter) + { iter->second->UnloadAll(); + sScriptMgr->OnDestroyMap(iter->second.get()); + } + // then delete them i_maps.clear(); From 37e220dc933264ed21a217fb2173b9b07ab835a3 Mon Sep 17 00:00:00 2001 From: CraftedRO <24683355+CraftedRO@users.noreply.github.com> Date: Thu, 14 Mar 2024 23:19:29 +0200 Subject: [PATCH 18/19] Core/Player: fix incorrect Warrior Block Value calculations (#29767) --- src/server/game/Entities/Player/Player.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp index aca4f18335..4641566482 100644 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -5092,7 +5092,7 @@ void Player::ApplyBaseModPctValue(BaseModGroup modGroup, float pct) return; } - AddPct(m_auraBasePctMod[modGroup], pct); + m_auraBasePctMod[modGroup] += CalculatePct(1.0f, pct); UpdateBaseModGroup(modGroup); } From 0d1c26237dcf01032c7badafa3043dfe11a811a3 Mon Sep 17 00:00:00 2001 From: Aokromes Date: Thu, 14 Mar 2024 23:40:27 +0100 Subject: [PATCH 19/19] DB: Add one missing trinity_string from master closes #29807 by CraftedRO --- sql/updates/world/3.3.5/2024_03_14_03_world.sql | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 sql/updates/world/3.3.5/2024_03_14_03_world.sql diff --git a/sql/updates/world/3.3.5/2024_03_14_03_world.sql b/sql/updates/world/3.3.5/2024_03_14_03_world.sql new file mode 100644 index 0000000000..4130b69747 --- /dev/null +++ b/sql/updates/world/3.3.5/2024_03_14_03_world.sql @@ -0,0 +1,4 @@ +-- +DELETE FROM `trinity_string` WHERE `entry`=1517; +INSERT INTO `trinity_string` (`entry`, `content_default`, `content_loc1`, `content_loc2`, `content_loc3`, `content_loc4`, `content_loc5`, `content_loc6`, `content_loc7`, `content_loc8`) VALUES +(1517, 'Quest ID %u does not exist.', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);