From db384331b6a23630fa67ef72ebea64f13c4863df Mon Sep 17 00:00:00 2001
From: samicrusader <hi@samicrusader.me>
Date: Wed, 14 Dec 2022 17:44:14 -0500
Subject: [PATCH] independent build

---
 CMakeLists.txt                                |   20 +
 Main.cpp                                      |    2 +-
 cmake/EnsureVersion.cmake                     |   73 +
 cmake/FindDL.cmake                            |   41 +
 cmake/FindMySQL.cmake                         |  110 ++
 cmake/GenRevision.cmake                       |   81 +
 cmake/MangosParams.cmake                      |    5 +
 cmake/PCHSupport.cmake                        |   99 ++
 cmake/SetDefinitions.cmake                    |  190 +++
 cmake/StatusInfo.cmake                        |   46 +
 cmake/win/VersionInfo.h.in                    |   55 +
 cmake/win/VersionInfo.rc                      |   35 +
 shared/.gitignore                             |   13 +
 shared/Auth/ARC4.cpp                          |   58 +
 shared/Auth/ARC4.h                            |   44 +
 shared/Auth/AuthCrypt.cpp                     |   94 ++
 shared/Auth/AuthCrypt.h                       |   92 ++
 shared/Auth/BigNumber.cpp                     |  234 +++
 shared/Auth/BigNumber.h                       |  262 ++++
 shared/Auth/HMACSHA1.cpp                      |   87 ++
 shared/Auth/HMACSHA1.h                        |   56 +
 shared/Auth/Sha1.cpp                          |   72 +
 shared/Auth/Sha1.h                            |  101 ++
 shared/Auth/WardenKeyGeneration.h             |   88 ++
 shared/Auth/md5.c                             |  383 +++++
 shared/Auth/md5.h                             |   91 ++
 shared/CMakeLists.txt                         |  239 +++
 shared/Common/Common.cpp                      |   63 +
 shared/Common/Common.h                        |  292 ++++
 shared/Common/GitRevision.cpp                 |  163 ++
 shared/Common/GitRevision.h                   |   69 +
 shared/Common/ServerDefines.h                 |   59 +
 shared/Config/Config.cpp                      |  130 ++
 shared/Config/Config.h                        |  114 ++
 shared/DataStores/DBCFileLoader.cpp           |  335 ++++
 shared/DataStores/DBCFileLoader.h             |  219 +++
 shared/DataStores/DBCStore.h                  |  221 +++
 shared/Database/Database.cpp                  |  783 ++++++++++
 shared/Database/Database.h                    |  826 ++++++++++
 shared/Database/DatabaseEnv.h                 |   51 +
 shared/Database/DatabaseImpl.h                |  366 +++++
 shared/Database/DatabaseMysql.cpp             |  548 +++++++
 shared/Database/DatabaseMysql.h               |  270 ++++
 shared/Database/Field.cpp                     |   25 +
 shared/Database/Field.h                       |  218 +++
 shared/Database/QueryResult.h                 |  192 +++
 shared/Database/QueryResultMysql.cpp          |  113 ++
 shared/Database/QueryResultMysql.h            |   87 ++
 shared/Database/SQLStorage.cpp                |  249 +++
 shared/Database/SQLStorage.h                  |  783 ++++++++++
 shared/Database/SQLStorageImpl.h              |  414 +++++
 shared/Database/SqlDelayThread.cpp            |   84 +
 shared/Database/SqlDelayThread.h              |   93 ++
 shared/Database/SqlOperations.cpp             |  249 +++
 shared/Database/SqlOperations.h               |  330 ++++
 shared/Database/SqlPreparedStatement.cpp      |  172 +++
 shared/Database/SqlPreparedStatement.h        |  832 ++++++++++
 shared/Dynamic/FactoryHolder.h                |  114 ++
 shared/Dynamic/ObjectRegistry.h               |  166 ++
 shared/GameSystem/Grid.h                      |  136 ++
 shared/GameSystem/GridLoader.h                |   95 ++
 shared/GameSystem/GridRefManager.h            |   92 ++
 shared/GameSystem/GridReference.h             |  105 ++
 shared/GameSystem/NGrid.h                     |  436 ++++++
 shared/GameSystem/TypeContainer.h             |  201 +++
 shared/GameSystem/TypeContainerVisitor.h      |   54 +
 shared/Linux/PosixDaemon.cpp                  |  153 ++
 shared/Linux/PosixDaemon.h                    |   43 +
 shared/LockedQueue/LockedQueue.h              |  136 ++
 shared/Log/Log.cpp                            | 1373 +++++++++++++++++
 shared/Log/Log.h                              |  605 ++++++++
 shared/Platform/CompilerDefs.h                |   69 +
 shared/Platform/Define.h                      |  180 +++
 shared/Policies/CreationPolicy.h              |  189 +++
 shared/Policies/ObjectLifeTime.cpp            |   39 +
 shared/Policies/ObjectLifeTime.h              |   83 +
 shared/Policies/Singleton.h                   |  161 ++
 shared/Policies/ThreadingModel.h              |  270 ++++
 shared/SystemConfig.h.in                      |   71 +
 shared/Threading/DelayExecutor.cpp            |  126 ++
 shared/Threading/DelayExecutor.h              |   59 +
 shared/Threading/Threading.cpp                |  242 +++
 shared/Threading/Threading.h                  |  215 +++
 shared/Utilities/ByteBuffer.cpp               |  135 ++
 shared/Utilities/ByteBuffer.h                 |  951 ++++++++++++
 shared/Utilities/ByteConverter.h              |  131 ++
 shared/Utilities/Callback.h                   | 1105 +++++++++++++
 shared/Utilities/Duration.h                   |   51 +
 shared/Utilities/Errors.h                     |   75 +
 shared/Utilities/EventProcessor.cpp           |  112 ++
 shared/Utilities/EventProcessor.h             |  148 ++
 shared/Utilities/LinkedList.h                 |  554 +++++++
 shared/Utilities/LinkedReference/RefManager.h |  125 ++
 shared/Utilities/LinkedReference/Reference.h  |  215 +++
 shared/Utilities/ProgressBar.cpp              |  134 ++
 shared/Utilities/ProgressBar.h                |   79 +
 shared/Utilities/RNGen.h                      |   79 +
 shared/Utilities/Timer.h                      |  228 +++
 shared/Utilities/TypeList.h                   |   30 +
 shared/Utilities/UnorderedMapSet.h            |   37 +
 shared/Utilities/Util.cpp                     |  835 ++++++++++
 shared/Utilities/Util.h                       |  886 +++++++++++
 shared/Utilities/WorldPacket.h                |   99 ++
 shared/Win/ServiceWin32.cpp                   |  302 ++++
 shared/Win/ServiceWin32.h                     |   35 +
 shared/Win/WheatyExceptionReport.cpp          |  989 ++++++++++++
 shared/Win/WheatyExceptionReport.h            |  141 ++
 shared/revision_data.h.in                     |   57 +
 108 files changed, 23966 insertions(+), 1 deletion(-)
 create mode 100644 cmake/EnsureVersion.cmake
 create mode 100644 cmake/FindDL.cmake
 create mode 100644 cmake/FindMySQL.cmake
 create mode 100644 cmake/GenRevision.cmake
 create mode 100644 cmake/MangosParams.cmake
 create mode 100644 cmake/PCHSupport.cmake
 create mode 100644 cmake/SetDefinitions.cmake
 create mode 100644 cmake/StatusInfo.cmake
 create mode 100644 cmake/win/VersionInfo.h.in
 create mode 100644 cmake/win/VersionInfo.rc
 create mode 100644 shared/.gitignore
 create mode 100644 shared/Auth/ARC4.cpp
 create mode 100644 shared/Auth/ARC4.h
 create mode 100644 shared/Auth/AuthCrypt.cpp
 create mode 100644 shared/Auth/AuthCrypt.h
 create mode 100644 shared/Auth/BigNumber.cpp
 create mode 100644 shared/Auth/BigNumber.h
 create mode 100644 shared/Auth/HMACSHA1.cpp
 create mode 100644 shared/Auth/HMACSHA1.h
 create mode 100644 shared/Auth/Sha1.cpp
 create mode 100644 shared/Auth/Sha1.h
 create mode 100644 shared/Auth/WardenKeyGeneration.h
 create mode 100644 shared/Auth/md5.c
 create mode 100644 shared/Auth/md5.h
 create mode 100644 shared/CMakeLists.txt
 create mode 100644 shared/Common/Common.cpp
 create mode 100644 shared/Common/Common.h
 create mode 100644 shared/Common/GitRevision.cpp
 create mode 100644 shared/Common/GitRevision.h
 create mode 100644 shared/Common/ServerDefines.h
 create mode 100644 shared/Config/Config.cpp
 create mode 100644 shared/Config/Config.h
 create mode 100644 shared/DataStores/DBCFileLoader.cpp
 create mode 100644 shared/DataStores/DBCFileLoader.h
 create mode 100644 shared/DataStores/DBCStore.h
 create mode 100644 shared/Database/Database.cpp
 create mode 100644 shared/Database/Database.h
 create mode 100644 shared/Database/DatabaseEnv.h
 create mode 100644 shared/Database/DatabaseImpl.h
 create mode 100644 shared/Database/DatabaseMysql.cpp
 create mode 100644 shared/Database/DatabaseMysql.h
 create mode 100644 shared/Database/Field.cpp
 create mode 100644 shared/Database/Field.h
 create mode 100644 shared/Database/QueryResult.h
 create mode 100644 shared/Database/QueryResultMysql.cpp
 create mode 100644 shared/Database/QueryResultMysql.h
 create mode 100644 shared/Database/SQLStorage.cpp
 create mode 100644 shared/Database/SQLStorage.h
 create mode 100644 shared/Database/SQLStorageImpl.h
 create mode 100644 shared/Database/SqlDelayThread.cpp
 create mode 100644 shared/Database/SqlDelayThread.h
 create mode 100644 shared/Database/SqlOperations.cpp
 create mode 100644 shared/Database/SqlOperations.h
 create mode 100644 shared/Database/SqlPreparedStatement.cpp
 create mode 100644 shared/Database/SqlPreparedStatement.h
 create mode 100644 shared/Dynamic/FactoryHolder.h
 create mode 100644 shared/Dynamic/ObjectRegistry.h
 create mode 100644 shared/GameSystem/Grid.h
 create mode 100644 shared/GameSystem/GridLoader.h
 create mode 100644 shared/GameSystem/GridRefManager.h
 create mode 100644 shared/GameSystem/GridReference.h
 create mode 100644 shared/GameSystem/NGrid.h
 create mode 100644 shared/GameSystem/TypeContainer.h
 create mode 100644 shared/GameSystem/TypeContainerVisitor.h
 create mode 100644 shared/Linux/PosixDaemon.cpp
 create mode 100644 shared/Linux/PosixDaemon.h
 create mode 100644 shared/LockedQueue/LockedQueue.h
 create mode 100644 shared/Log/Log.cpp
 create mode 100644 shared/Log/Log.h
 create mode 100644 shared/Platform/CompilerDefs.h
 create mode 100644 shared/Platform/Define.h
 create mode 100644 shared/Policies/CreationPolicy.h
 create mode 100644 shared/Policies/ObjectLifeTime.cpp
 create mode 100644 shared/Policies/ObjectLifeTime.h
 create mode 100644 shared/Policies/Singleton.h
 create mode 100644 shared/Policies/ThreadingModel.h
 create mode 100644 shared/SystemConfig.h.in
 create mode 100644 shared/Threading/DelayExecutor.cpp
 create mode 100644 shared/Threading/DelayExecutor.h
 create mode 100644 shared/Threading/Threading.cpp
 create mode 100644 shared/Threading/Threading.h
 create mode 100644 shared/Utilities/ByteBuffer.cpp
 create mode 100644 shared/Utilities/ByteBuffer.h
 create mode 100644 shared/Utilities/ByteConverter.h
 create mode 100644 shared/Utilities/Callback.h
 create mode 100644 shared/Utilities/Duration.h
 create mode 100644 shared/Utilities/Errors.h
 create mode 100644 shared/Utilities/EventProcessor.cpp
 create mode 100644 shared/Utilities/EventProcessor.h
 create mode 100644 shared/Utilities/LinkedList.h
 create mode 100644 shared/Utilities/LinkedReference/RefManager.h
 create mode 100644 shared/Utilities/LinkedReference/Reference.h
 create mode 100644 shared/Utilities/ProgressBar.cpp
 create mode 100644 shared/Utilities/ProgressBar.h
 create mode 100644 shared/Utilities/RNGen.h
 create mode 100644 shared/Utilities/Timer.h
 create mode 100644 shared/Utilities/TypeList.h
 create mode 100644 shared/Utilities/UnorderedMapSet.h
 create mode 100644 shared/Utilities/Util.cpp
 create mode 100644 shared/Utilities/Util.h
 create mode 100644 shared/Utilities/WorldPacket.h
 create mode 100644 shared/Win/ServiceWin32.cpp
 create mode 100644 shared/Win/ServiceWin32.h
 create mode 100644 shared/Win/WheatyExceptionReport.cpp
 create mode 100644 shared/Win/WheatyExceptionReport.h
 create mode 100644 shared/revision_data.h.in

diff --git a/CMakeLists.txt b/CMakeLists.txt
index fcbc142..8585f1a 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -22,6 +22,25 @@
 # * and lore are copyrighted by Blizzard Entertainment, Inc.
 # */
 
+cmake_minimum_required(VERSION 3.12 FATAL_ERROR)
+cmake_policy(SET CMP0048 NEW)
+project(MaNGOS VERSION 0.22.0)
+list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake")
+
+set(OPENSSL_INCLUDE_DIR /usr/include/openssl-1.1)
+set(OPENSSL_SSL_LIBRARY /usr/lib/openssl-1.1/libssl.so)
+set(OPENSSL_CRYPTO_LIBRARY /usr/lib/openssl-1.1/libcrypto.so)
+
+find_package(OpenSSL 1.1.1 REQUIRED)
+find_package(Threads REQUIRED)
+find_package(MySQL   REQUIRED)
+find_package(DL      REQUIRED)
+
+add_subdirectory(dep)
+add_subdirectory(shared)
+
+set(MANGOS_REALM_VER 2021010100)
+
 #Auth Files
 file(GLOB_RECURSE SRC_GRP_AUTH Auth/*.cpp Auth/*.h)
 source_group("Authentication" FILES ${SRC_GRP_AUTH})
@@ -81,6 +100,7 @@ install(
 
 install(
     FILES ${CMAKE_CURRENT_BINARY_DIR}/realmd.conf.dist
+    TYPE SYSCONF
     DESTINATION ${CONF_INSTALL_DIR}
 )
 
diff --git a/Main.cpp b/Main.cpp
index 0b69aa0..789b369 100644
--- a/Main.cpp
+++ b/Main.cpp
@@ -210,7 +210,7 @@ extern int main(int argc, char** argv)
 
     ///- Check the version of the configuration file
     uint32 confVersion = sConfig.GetIntDefault("ConfVersion", 0);
-    if (confVersion < REALMD_CONFIG_VERSION)
+    if (confVersion < 2021010100)
     {
         sLog.outError("*****************************************************************************");
         sLog.outError(" WARNING: Your realmd.conf version indicates your conf file is out of date!");
diff --git a/cmake/EnsureVersion.cmake b/cmake/EnsureVersion.cmake
new file mode 100644
index 0000000..ee228e6
--- /dev/null
+++ b/cmake/EnsureVersion.cmake
@@ -0,0 +1,73 @@
+# MaNGOS is a full featured server for World of Warcraft, supporting
+# the following clients: 1.12.x, 2.4.3, 3.3.5a, 4.3.4a and 5.4.8
+#
+# Copyright (C) 2005-2022 MaNGOS <https://getmangos.eu>
+#
+# 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, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+MACRO(NORMALIZE_VERSION _requested_version _normalized_version)
+    STRING(REGEX MATCH "[^0-9]*[0-9]+\\.[0-9]+\\.[0-9]+.*" _threePartMatch "${_requested_version}")
+    if(_threePartMatch)
+    # parse the parts of the version string
+        STRING(REGEX REPLACE "[^0-9]*([0-9]+)\\.[0-9]+\\.[0-9]+.*" "\\1" _major_vers "${_requested_version}")
+        STRING(REGEX REPLACE "[^0-9]*[0-9]+\\.([0-9]+)\\.[0-9]+.*" "\\1" _minor_vers "${_requested_version}")
+        STRING(REGEX REPLACE "[^0-9]*[0-9]+\\.[0-9]+\\.([0-9]+).*" "\\1" _patch_vers "${_requested_version}")
+    else(_threePartMatch)
+        STRING(REGEX REPLACE "([0-9]+)\\.[0-9]+" "\\1" _major_vers "${_requested_version}")
+        STRING(REGEX REPLACE "[0-9]+\\.([0-9]+)" "\\1" _minor_vers "${_requested_version}")
+        set(_patch_vers "0")
+    endif(_threePartMatch)
+
+    # compute an overall version number which can be compared at once
+    MATH(EXPR ${_normalized_version} "${_major_vers}*10000 + ${_minor_vers}*100 + ${_patch_vers}")
+ENDMACRO(NORMALIZE_VERSION)
+
+MACRO(CHECK_RANGE_INCLUSIVE_LOWER _lower_limit _value _upper_limit _ok)
+   if(${_value} LESS ${_lower_limit})
+      set(${_ok} FALSE)
+  elseif(${_value} EQUAL ${_lower_limit})
+      set(${_ok} TRUE)
+  elseif(${_value} EQUAL ${_upper_limit})
+      set(${_ok} FALSE)
+  elseif(${_value} GREATER ${_upper_limit})
+      set(${_ok} FALSE)
+  else(${_value} LESS ${_lower_limit})
+      set(${_ok} TRUE)
+  endif(${_value} LESS ${_lower_limit})
+ENDMACRO(CHECK_RANGE_INCLUSIVE_LOWER)
+
+MACRO(ENSURE_VERSION requested_version found_version var_too_old)
+    NORMALIZE_VERSION(${requested_version} req_vers_num)
+    NORMALIZE_VERSION(${found_version} found_vers_num)
+
+    if(found_vers_num LESS req_vers_num)
+        set(${var_too_old} FALSE)
+    else(found_vers_num LESS req_vers_num)
+        set(${var_too_old} TRUE)
+    endif(found_vers_num LESS req_vers_num)
+
+ENDMACRO(ENSURE_VERSION)
+
+MACRO(ENSURE_VERSION2 requested_version2 found_version2 var_too_old2)
+    ENSURE_VERSION(${requested_version2} ${found_version2} ${var_too_old2})
+ENDMACRO(ENSURE_VERSION2)
+
+MACRO(ENSURE_VERSION_RANGE min_version found_version max_version var_ok)
+    NORMALIZE_VERSION(${min_version} req_vers_num)
+    NORMALIZE_VERSION(${found_version} found_vers_num)
+    NORMALIZE_VERSION(${max_version} max_vers_num)
+
+    CHECK_RANGE_INCLUSIVE_LOWER(${req_vers_num} ${found_vers_num} ${max_vers_num} ${var_ok})
+ENDMACRO(ENSURE_VERSION_RANGE)
diff --git a/cmake/FindDL.cmake b/cmake/FindDL.cmake
new file mode 100644
index 0000000..633e8a5
--- /dev/null
+++ b/cmake/FindDL.cmake
@@ -0,0 +1,41 @@
+# - find where dlopen and friends are located.
+# DL_FOUND - system has dynamic linking interface available
+# DL_INCLUDE_DIR - where dlfcn.h is located.
+# DL_LIBRARY - libraries needed to use dlopen
+
+include(CheckFunctionExists)
+
+find_path(DL_INCLUDE_DIR NAMES dlfcn.h)
+find_library(DL_LIBRARY NAMES dl)
+if(DL_LIBRARY)
+  set(DL_FOUND TRUE)
+else(DL_LIBRARY)
+  check_function_exists(dlopen DL_FOUND)
+  # If dlopen can be found without linking in dl then dlopen is part
+  # of libc, so don't need to link extra libs.
+  set(DL_LIBRARY "")
+endif(DL_LIBRARY)
+
+if(DL_FOUND)
+include(FindPackageHandleStandardArgs)
+find_package_handle_standard_args(DL
+    FOUND_VAR
+        DL_FOUND
+    REQUIRED_VARS
+        DL_INCLUDE_DIR
+)
+
+mark_as_advanced(DL_INCLUDE_DIR DL_LIBRARY)
+endif()
+
+if(NOT TARGET DL::DL)
+  add_library(DL::DL INTERFACE IMPORTED)
+  if(DL_FOUND)
+      if (DL_LIBRARY)
+        set_target_properties(DL::DL PROPERTIES
+            INTERFACE_LINK_LIBRARIES "${DL_LIBRARY}")
+      endif()
+      set_target_properties(DL::DL PROPERTIES
+            INTERFACE_INCLUDE_DIRECTORIES "${DL_INCLUDE_DIR}")
+  endif()
+endif()
diff --git a/cmake/FindMySQL.cmake b/cmake/FindMySQL.cmake
new file mode 100644
index 0000000..c2f5370
--- /dev/null
+++ b/cmake/FindMySQL.cmake
@@ -0,0 +1,110 @@
+#[==[
+Provides the following variables:
+
+  * `MySQL_INCLUDE_DIRS`: Include directories necessary to use MySQL.
+  * `MySQL_LIBRARIES`: Libraries necessary to use MySQL.
+  * A `MySQL::MySQL` imported target.
+#]==]
+
+set(MySQL_FOUND 0)
+
+# No .pc files are shipped with MySQL on Windows.
+set(_MYSQL_USE_PKGCONFIG 0)
+if (NOT WIN32)
+  find_package(PkgConfig)
+  if (PkgConfig_FOUND)
+    set(_MYSQL_USE_PKGCONFIG 1)
+  endif ()
+endif ()
+
+if (_MYSQL_USE_PKGCONFIG)
+  pkg_check_modules(_mariadb "mariadb" QUIET IMPORTED_TARGET)
+  unset(_mysql_target)
+  if (NOT _mariadb_FOUND)
+    pkg_check_modules(_mysql "mysql" QUIET IMPORTED_TARGET)
+    if (_mysql_FOUND)
+      set(_mysql_target "_mysql")
+    endif ()
+  else ()
+    set(_mysql_target "_mariadb")
+    if (_mariadb_VERSION VERSION_LESS 10.4)
+      get_property(_include_dirs
+        TARGET    "PkgConfig::_mariadb"
+        PROPERTY  "INTERFACE_INCLUDE_DIRECTORIES")
+      # Remove "${prefix}/mariadb/.." from the interface since it breaks other
+      # projects.
+      list(FILTER _include_dirs EXCLUDE REGEX "\\.\\.")
+      set_property(TARGET "PkgConfig::_mariadb"
+        PROPERTY
+          "INTERFACE_INCLUDE_DIRECTORIES" "${_include_dirs}")
+      unset(_include_dirs)
+    endif ()
+  endif ()
+  if (_mysql_target)
+    set(MySQL_FOUND 1)
+    add_library(MySQL::MySQL INTERFACE IMPORTED)
+    target_link_libraries(MySQL::MySQL
+      INTERFACE "PkgConfig::${_mysql_target}")
+    set(MySQL_INCLUDE_DIRS ${${_mysql_target}_INCLUDE_DIRS})
+    set(MySQL_LIBRARIES ${${_mysql_target}_LINK_LIBRARIES})
+  endif ()
+  unset(_mysql_target)
+endif ()
+
+if(NOT MySQL_FOUND)
+  set(_MySQL_mariadb_versions 10.1 10.2 10.3 10.4 10.5 10.6)
+  set(_MySQL_versions 5.4 5.5 5.6 5.7 8.0)
+  set(_MySQL_paths)
+  foreach (_MySQL_version IN LISTS _MySQL_mariadb_versions)
+    list(APPEND _MySQL_paths
+      "[HKEY_LOCAL_MACHINE\\SOFTWARE\\MariaDB ${_MySQL_version};INSTALLDIR]"
+      "[HKEY_LOCAL_MACHINE\\SOFTWARE\\MariaDB ${_MySQL_version} (x64);INSTALLDIR]")
+  endforeach ()
+  foreach (_MySQL_version IN LISTS _MySQL_versions)
+    list(APPEND _MySQL_paths
+      "C:/Program Files/MySQL/MySQL Server ${_MySQL_version}/lib/opt"
+      "[HKEY_LOCAL_MACHINE\\SOFTWARE\\MySQL AB\\MySQL Server ${_MySQL_version};Location]"
+      "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Wow6432Node\\MySQL AB\\MySQL Server ${_MySQL_version};Location]")
+  endforeach ()
+  unset(_MySQL_version)
+  unset(_MySQL_versions)
+  unset(_MySQL_mariadb_versions)
+
+  find_path(MySQL_INCLUDE_DIR
+    NAMES mysql.h
+    PATHS
+      "C:/Program Files/MySQL/include"
+      "C:/MySQL/include"
+      ${_MySQL_paths}
+      /usr
+      /usr/include
+    PATH_SUFFIXES include include/mysql
+    DOC "Location of mysql.h")
+  mark_as_advanced(MySQL_INCLUDE_DIR)
+  find_library(MySQL_LIBRARY
+    NAMES libmariadb mysql libmysql mysqlclient
+    PATHS
+      "C:/Program Files/MySQL/lib"
+      "C:/MySQL/lib/debug"
+      ${_MySQL_paths}
+      /usr
+      /usr/local/
+    PATH_SUFFIXES lib lib/opt lib/mysql
+    DOC "Location of the mysql library")
+  mark_as_advanced(MySQL_LIBRARY)
+
+  include(FindPackageHandleStandardArgs)
+  find_package_handle_standard_args(MySQL
+    REQUIRED_VARS MySQL_INCLUDE_DIR MySQL_LIBRARY)
+
+  if (MySQL_FOUND)
+    add_library(MySQL::MySQL UNKNOWN IMPORTED)
+    set_target_properties(MySQL::MySQL PROPERTIES
+      IMPORTED_LOCATION "${MySQL_LIBRARY}"
+      INTERFACE_INCLUDE_DIRECTORIES "${MySQL_INCLUDE_DIR}")
+    set(MySQL_INCLUDE_DIRS "${MySQL_INCLUDE_DIR}")
+    set(MySQL_LIBRARIES "${MySQL_LIBRARY}")
+  endif ()
+endif ()
+unset(_MYSQL_USE_PKGCONFIG)
+
diff --git a/cmake/GenRevision.cmake b/cmake/GenRevision.cmake
new file mode 100644
index 0000000..484a111
--- /dev/null
+++ b/cmake/GenRevision.cmake
@@ -0,0 +1,81 @@
+
+if(NOT BUILDDIR)
+  # Workaround for funny MSVC behaviour - this segment is only used when using cmake gui
+  set(BUILDDIR ${CMAKE_BINARY_DIR})
+endif()
+
+if(WITHOUT_GIT)
+  set(rev_date "1970-01-01 00:00:00 +0000")
+  set(rev_hash "unknown")
+  set(rev_branch "Archived")
+  
+  # No valid git commit date, use compiled date
+  string(TIMESTAMP rev_date_fallback "%Y-%m-%d %H:%M:%S" UTC)
+else()
+  if(GIT_EXECUTABLE)
+    # Create a revision-string that we can use
+    execute_process(
+      COMMAND "${GIT_EXECUTABLE}" describe --long --match init --dirty=+ --abbrev=12 --always
+      WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}"
+      OUTPUT_VARIABLE rev_info
+      OUTPUT_STRIP_TRAILING_WHITESPACE
+      ERROR_QUIET
+    )
+
+    # And grab the commits timestamp
+    execute_process(
+      COMMAND "${GIT_EXECUTABLE}" show -s --format=%ci
+      WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}"
+      OUTPUT_VARIABLE rev_date
+      OUTPUT_STRIP_TRAILING_WHITESPACE
+      ERROR_QUIET
+    )
+
+    # Also retrieve branch name
+    execute_process(
+      COMMAND "${GIT_EXECUTABLE}" rev-parse --abbrev-ref HEAD
+      WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}"
+      OUTPUT_VARIABLE rev_branch
+      OUTPUT_STRIP_TRAILING_WHITESPACE
+      ERROR_QUIET
+    )
+  endif()
+
+  # Last minute check - ensure that we have a proper revision
+  # If everything above fails (means the user has erased the git revision control directory or removed the origin/HEAD tag)
+  if(NOT rev_info)
+    # No valid ways available to find/set the revision/hash, so let's force some defaults
+    message(STATUS "
+    Could not find a proper repository signature (hash) - you may need to pull tags with git fetch -t
+    Continuing anyway - note that the versionstring will be set to \"unknown 1970-01-01 00:00:00 (Archived)\"")
+    set(rev_date "1970-01-01 00:00:00 +0000")
+    set(rev_hash "unknown")
+    set(rev_branch "Archived")
+
+    # No valid git commit date, use compiled date
+    string(TIMESTAMP rev_date_fallback "%Y-%m-%d %H:%M:%S" UTC)
+  else()
+    # We have valid date from git commit, use it
+    set(rev_date_fallback ${rev_date})
+
+    # Extract information required to build a proper versionstring
+    string(REGEX REPLACE init-|[0-9]+-g "" rev_hash ${rev_info})
+  endif()
+endif()
+
+# For package / copyright information we always need proper date
+string(REGEX MATCH "([0-9]+)-([0-9]+)-([0-9]+)" rev_date_fallback_match ${rev_date_fallback})
+set(rev_year ${CMAKE_MATCH_1})
+set(rev_month ${CMAKE_MATCH_2})
+set(rev_day ${CMAKE_MATCH_3})
+
+# Create the actual revision_data.h file from the above params
+if(NOT "${rev_hash_cached}" MATCHES "${rev_hash}" OR NOT "${rev_branch_cached}" MATCHES "${rev_branch}" OR NOT EXISTS "${CMAKE_CURRENT_BINARY_DIR}/src/shared/revision_data.h")
+  configure_file(
+    "${CMAKE_SOURCE_DIR}/src/shared/revision_data.h.in"
+    "${CMAKE_CURRENT_BINARY_DIR}/src/shared/revision_data.h"
+    @ONLY
+  )
+  set(rev_hash_cached "${rev_hash}" CACHE INTERNAL "Cached commit-hash")
+  set(rev_branch_cached "${rev_branch}" CACHE INTERNAL "Cached branch name")
+endif()
diff --git a/cmake/MangosParams.cmake b/cmake/MangosParams.cmake
new file mode 100644
index 0000000..918153e
--- /dev/null
+++ b/cmake/MangosParams.cmake
@@ -0,0 +1,5 @@
+set(MANGOS_EXP "CLASSIC")
+set(MANGOS_PKG "Mangos Zero")
+set(MANGOS_WORLD_VER 2022031600)
+set(MANGOS_REALM_VER 2021010100)
+set(MANGOS_AHBOT_VER 2021010100)
diff --git a/cmake/PCHSupport.cmake b/cmake/PCHSupport.cmake
new file mode 100644
index 0000000..7b1f6c7
--- /dev/null
+++ b/cmake/PCHSupport.cmake
@@ -0,0 +1,99 @@
+# CMake precompiled header macro
+# Distributed under the MIT Software License
+# Copyright (c) 2015-2017 Borislav Stanimirov
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy of 
+# this software and associated documentation files (the "Software"), to deal in 
+# the Software without restriction, including without limitation the rights to 
+# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 
+# of the Software, and to permit persons to whom the Software is furnished to do 
+# so, subject to the following conditions:
+# The above copyright notice and this permission notice shall be included in all 
+# copies or substantial portions of the Software.
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 
+# SOFTWARE.
+#
+# ADD_CXX_PCH(TARGET_NAME PRECOMPILED_HEADER PRECOMPILED_SOURCE)
+#
+# Sets a precompiled header for a given target
+#
+# TARGET_NAME - Name of the target. Only valid after add_library or add_executable
+# PRECOMPILED_HEADER - Header file to precompile
+# PRECOMPILED_SOURCE - MSVC specific source to do the actual precompilation. Ignored on other platforms
+#
+
+function(ADD_CXX_PCH TARGET_NAME PRECOMPILED_HEADER PRECOMPILED_SOURCE)
+    get_filename_component(PRECOMPILED_HEADER_NAME ${PRECOMPILED_HEADER} NAME)
+
+    if(MSVC)
+        target_compile_options(${TARGET_NAME}
+            PRIVATE
+                /FI${PRECOMPILED_HEADER_NAME}
+                /Yu${PRECOMPILED_HEADER_NAME}
+        )
+        SET_SOURCE_FILES_PROPERTIES(${PRECOMPILED_SOURCE}
+            PROPERTIES
+                COMPILE_FLAGS /Yc${PRECOMPILED_HEADER_NAME}
+        )
+    elseif(CMAKE_GENERATOR STREQUAL Xcode)
+        set_target_properties(
+            ${TARGET_NAME}
+            PROPERTIES
+                XCODE_ATTRIBUTE_GCC_PREFIX_HEADER "${PRECOMPILED_HEADER}"
+                XCODE_ATTRIBUTE_GCC_PRECOMPILE_PREFIX_HEADER "YES"
+            )
+    elseif(CMAKE_COMPILER_IS_GNUCC OR CMAKE_CXX_COMPILER_ID MATCHES "Clang")
+        if(CMAKE_COMPILER_IS_GNUCC)
+            set(SFX gch)
+        else()
+            set(SFX pch)
+        endif()
+
+        # Create and set output directory.
+        set(OUTPUT_DIR "${CMAKE_CURRENT_BINARY_DIR}/${TARGET_NAME}_${SFX}")
+        set(OUTPUT_NAME "${OUTPUT_DIR}/${PRECOMPILED_HEADER_NAME}.${SFX}")
+
+        make_directory(${OUTPUT_DIR})
+
+        # Export compiler flags via a generator to a response file
+        set(PCH_FLAGS_FILE "${OUTPUT_DIR}/${PRECOMPILED_HEADER_NAME}.rsp")
+        set(_include_directories "$<TARGET_PROPERTY:${TARGET_NAME},INCLUDE_DIRECTORIES>")
+        set(_compile_definitions "$<TARGET_PROPERTY:${TARGET_NAME},COMPILE_DEFINITIONS>")
+        set(_compile_flags "$<TARGET_PROPERTY:${TARGET_NAME},COMPILE_FLAGS>")
+        set(_compile_options "$<TARGET_PROPERTY:${TARGET_NAME},COMPILE_OPTIONS>")
+        set(_include_directories "$<$<BOOL:${_include_directories}>:-I$<JOIN:${_include_directories},\n-I>\n>")
+        set(_compile_definitions "$<$<BOOL:${_compile_definitions}>:-D$<JOIN:${_compile_definitions},\n-D>\n>")
+        set(_compile_flags "$<$<BOOL:${_compile_flags}>:$<JOIN:${_compile_flags},\n>\n>")
+        set(_compile_options "$<$<BOOL:${_compile_options}>:$<JOIN:${_compile_options},\n>\n>")
+
+        file(GENERATE OUTPUT ${PCH_FLAGS_FILE} CONTENT "${_compile_definitions}${_include_directories}${_compile_flags}${_compile_options}\n")
+        file(GENERATE OUTPUT ${OUTPUT_DIR}/${PRECOMPILED_HEADER_NAME} CONTENT "")
+
+        # Gather global compiler options, definitions, etc.
+        string(TOUPPER "CMAKE_CXX_FLAGS_${CMAKE_BUILD_TYPE}" CXX_FLAGS)
+        set(COMPILER_FLAGS "${${CXX_FLAGS}} ${CMAKE_CXX_FLAGS}")
+        separate_arguments(COMPILER_FLAGS)
+
+        set(CXX_STD c++11)
+
+        add_custom_command(
+            OUTPUT ${OUTPUT_NAME}
+            COMMAND ${CMAKE_CXX_COMPILER} @${PCH_FLAGS_FILE} ${COMPILER_FLAGS} -x c++-header -std=${CXX_STD} -o ${OUTPUT_NAME} ${PRECOMPILED_HEADER}
+            DEPENDS ${PRECOMPILED_HEADER} ${PRECOMPILED_SOURCE}
+        )
+
+        add_custom_target(${TARGET_NAME}_${SFX} DEPENDS ${OUTPUT_NAME} ${PRECOMPILED_HEADER})
+        add_dependencies(${TARGET_NAME} ${TARGET_NAME}_${SFX})
+
+        target_compile_options(${TARGET_NAME}
+            PRIVATE
+                -include ${OUTPUT_DIR}/${PRECOMPILED_HEADER_NAME}
+                -Winvalid-pch
+        )
+    endif()
+endfunction()
diff --git a/cmake/SetDefinitions.cmake b/cmake/SetDefinitions.cmake
new file mode 100644
index 0000000..b8c3c0f
--- /dev/null
+++ b/cmake/SetDefinitions.cmake
@@ -0,0 +1,190 @@
+#
+# This code is part of MaNGOS. Contributor & Copyright details are in AUTHORS/THANKS.
+#
+# 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, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+#
+
+if(CMAKE_SIZEOF_VOID_P MATCHES 8)
+    set(PLATFORM 64)
+else()
+    set(PLATFORM 32)
+endif()
+
+if(XCODE)
+  # Here we add a check for ARM32, as they can't leverage SSE/SSE2
+  if(PLATFORM MATCHES 32 AND ${CMAKE_SYSTEM_PROCESSOR} MATCHES "^arm")
+    set(CMAKE_OSX_ARCHITECTURES ARM32)
+  # Default for 32-bit left as i386
+  elseif(PLATFORM MATCHES 32)
+    set(CMAKE_OSX_ARCHITECTURES i386)
+  # Check for ARM64
+  elseif(PLATFORM MATCHES 64 AND ${CMAKE_SYSTEM_PROCESSOR} MATCHES "^arm") 
+    set(CMAKE_OSX_ARCHITECTURES ARM64)
+  # Default for 64-bit left as x86_64
+  else()
+    set(CMAKE_OSX_ARCHITECTURES x86_64)
+  endif()
+endif()
+
+#
+# Compile definitions
+#
+set(DEFAULT_COMPILE_DEFS)
+
+# MSVC compiler
+if ("${CMAKE_CXX_COMPILER_ID}" MATCHES "MSVC")
+    set(DEFAULT_COMPILE_DEFS ${DEFAULT_COMPILE_DEFS}
+        /D_SCL_SECURE_NO_WARNINGS
+        /D_CRT_SECURE_NO_WARNINGS
+        /D_WINSOCK_DEPRECATED_NO_WARNINGS
+        /D_CRT_NONSTDC_NO_DEPRECATE
+        $<$<EQUAL:${PLATFORM},64>: /D_WIN64>
+    )
+endif()
+
+# MINGW
+if (MINGW)
+    set(DEFAULT_COMPILE_DEFS ${DEFAULT_COMPILE_DEFS}
+        -DWINVER=0x0600
+        -D_WIN32_WINNT=0x0600
+        $<$<EQUAL:${PLATFORM},32>:
+            -DHAVE_SSE2
+            -D__SSE2__
+        >
+        $<$<EQUAL:${PLATFORM},64>: -D_WIN64>
+    )
+endif()
+
+
+#
+# Compile options
+#
+set(DEFAULT_COMPILE_OPTS)
+
+# MSVC compiler options
+if ("${CMAKE_CXX_COMPILER_ID}" MATCHES "MSVC")
+    set(DEFAULT_COMPILE_OPTS ${DEFAULT_COMPILE_OPTS}
+        /MP           #multiple processes
+        /W4           #warning level 4
+
+        $<$<EQUAL:${PLATFORM},32>:/arch:SSE2>
+
+        $<$<CONFIG:Release>:
+        /Gw           #whole program global optimization
+        /GS-          #no buffer security check
+        /GF           #string pooling
+        >
+        $<$<CONFIG:Debug>:
+        /bigobj
+        >
+
+        /wd4996
+        /wd4267
+        /wd4244
+        /wd4245
+        /wd4458
+        /wd4581
+        /wd4589
+        /wd4131
+        /wd4311
+        /wd4456
+        /wd4127
+        /wd4100
+        /wd4389
+        /wd4189
+        /wd4701
+        /wd4706
+        /wd4703
+        /wd4702
+        /wd4302
+        /wd4305
+        /wd4018
+        /wd4840
+        /wd4101
+    )
+endif ()
+
+# GCC compiler options
+if ("${CMAKE_CXX_COMPILER_ID}" MATCHES "GNU")
+    set(DEFAULT_COMPILE_OPTS ${DEFAULT_COMPILE_OPTS}
+    # Enhanced 32-bit check, now we can use the arch to specify flags
+    $<$<STREQUAL:${CMAKE_OSX_ARCHITECTURES},"i386">:
+            -msse2
+            -mfpmath=sse
+        >
+    $<$<STREQUAL:${CMAKE_OSX_ARCHITECTURES},"ARM32">:
+    # explicit space for compiler flags
+    >
+        $<$<STREQUAL:${CMAKE_OSX_ARCHITECTURES},"ARM64">:
+        # explicit space for compiler flags
+        >
+        $<$<CONFIG:Debug>:
+          -W
+          -Wall
+          -Wextra
+          -Winit-self
+          -Wfatal-errors
+          -Winvalid-pch
+          -g3
+        >
+
+        $<$<CONFIG:Release>:
+          --no-warnings
+      # Suppress compiler note on parameter passing.  See the following
+      # GCC BZ for more info:  https://gcc.gnu.org/bugzilla/show_bug.cgi?id=77728
+      -Wno-psabi
+        >
+    )
+endif ()
+
+#Clang compiler options
+if("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang")
+    set(DEFAULT_COMPILE_OPTS ${DEFAULT_COMPILE_OPTS}
+        $<$<CONFIG:Release>:
+            -Wno-c++11-narrowing
+            -Wno-inconsistent-missing-override
+            -Wno-deprecated-register
+            -Wno-switch
+        >
+        $<$<CONFIG:Debug>:
+            -W
+            -Wall
+            -Wextra
+            -Winit-self
+            -Wfatal-errors
+            -Woverloaded-virtual
+            -glldb
+            -gline-tables-only
+        >
+    )
+endif()
+
+separate_arguments(DEFAULT_COMPILE_DEFS)
+separate_arguments(DEFAULT_COMPILE_OPTS)
+
+set_property(DIRECTORY
+    PROPERTY COMPILE_DEFINITIONS ${DEFAULT_COMPILE_DEFS}
+    PROPERTY COMPILE_OPTIONS     ${DEFAULT_COMPILE_OPTS}
+)
+
+unset(DEFAULT_COMPILE_DEFS)
+unset(DEFAULT_COMPILE_OPTS)
+
+#
+# Misc settings
+#
+if(MSVC)
+    set(CMAKE_VS_INCLUDE_INSTALL_TO_DEFAULT_BUILD ON)
+endif()
diff --git a/cmake/StatusInfo.cmake b/cmake/StatusInfo.cmake
new file mode 100644
index 0000000..1841d33
--- /dev/null
+++ b/cmake/StatusInfo.cmake
@@ -0,0 +1,46 @@
+message("===================================================")
+message("Mangos revision       : ${rev_hash} ${rev_date} (${rev_branch} branch)")
+message("Build type            : ${CMAKE_BUILD_TYPE}")
+message("Install server(s) to  : ${BIN_DIR}")
+message("Install configs to    : ${CONF_INSTALL_DIR}")
+
+message("")
+message("Detailed Information")
+message("+-- opeating system   : ${CMAKE_HOST_SYSTEM}")
+message("+-- cmake version     : ${CMAKE_VERSION}")
+message("")
+
+if(BUILD_MANGOSD)
+    message("Build main server     : Yes (default)")
+    if(SCRIPT_LIB_ELUNA)
+        message("+-- with Eluna script engine")
+    endif()
+    if(SCRIPT_LIB_SD3)
+        message("+-- with SD3 script engine")
+    endif()
+    if(PLAYERBOTS)
+        message("+-- with PlayerBots")
+    endif()
+else()
+    message("Build main server     : No")
+endif()
+
+if(BUILD_REALMD)
+    message("Build login server    : Yes (default)")
+else()
+    message("Build login server    : No")
+endif()
+
+if(SOAP)
+    message("Support for SOAP      : Yes")
+else()
+    message("Support for SOAP      : No (default)")
+endif()
+
+if(BUILD_TOOLS)
+    message("Build tools           : Yes (default)")
+else()
+    message("Build tools           : No")
+endif()
+message("")
+message("===================================================")
diff --git a/cmake/win/VersionInfo.h.in b/cmake/win/VersionInfo.h.in
new file mode 100644
index 0000000..057d8ef
--- /dev/null
+++ b/cmake/win/VersionInfo.h.in
@@ -0,0 +1,55 @@
+#pragma once
+
+#ifndef PRODUCT_VERSION_MAJOR
+#define PRODUCT_VERSION_MAJOR @PROJECT_VERSION_MAJOR@
+#endif
+
+#ifndef PRODUCT_VERSION_MINOR
+#define PRODUCT_VERSION_MINOR @PROJECT_VERSION_MINOR@
+#endif
+
+#ifndef PRODUCT_VERSION_PATCH
+#define PRODUCT_VERSION_PATCH @PROJECT_VERSION_PATCH@
+#endif
+
+
+#ifndef FILE_VERSION_MAJOR
+#define FILE_VERSION_MAJOR PRODUCT_VERSION_MAJOR
+#endif
+
+#ifndef FILE_VERSION_MINOR
+#define FILE_VERSION_MINOR PRODUCT_VERSION_MINOR
+#endif
+
+#ifndef FILE_VERSION_PATCH
+#define FILE_VERSION_PATCH PRODUCT_VERSION_PATCH
+#endif
+
+#ifndef __TO_STRING
+#define __TO_STRING_IMPL(x) #x
+#define __TO_STRING(x) __TO_STRING_IMPL(x)
+#endif
+
+#define PRODUCT_VERSION_MAJOR_MINOR_STR        __TO_STRING(PRODUCT_VERSION_MAJOR) "." __TO_STRING(PRODUCT_VERSION_MINOR)
+#define PRODUCT_VERSION_MAJOR_MINOR_PATCH_STR  PRODUCT_VERSION_MAJOR_MINOR_STR "." __TO_STRING(PRODUCT_VERSION_PATCH)
+#define PRODUCT_VERSION_FULL_STR               PRODUCT_VERSION_MAJOR_MINOR_PATCH_STR
+#define PRODUCT_VERSION_RESOURCE               PRODUCT_VERSION_MAJOR,PRODUCT_VERSION_MINOR,PRODUCT_VERSION_PATCH
+#define PRODUCT_VERSION_RESOURCE_STR           PRODUCT_VERSION_FULL_STR "\0"
+
+#define FILE_VERSION_MAJOR_MINOR_STR        __TO_STRING(FILE_VERSION_MAJOR) "." __TO_STRING(FILE_VERSION_MINOR)
+#define FILE_VERSION_MAJOR_MINOR_PATCH_STR  FILE_VERSION_MAJOR_MINOR_STR "." __TO_STRING(FILE_VERSION_PATCH)
+#define FILE_VERSION_FULL_STR               FILE_VERSION_MAJOR_MINOR_PATCH_STR
+#define FILE_VERSION_RESOURCE               FILE_VERSION_MAJOR,FILE_VERSION_MINOR,FILE_VERSION_PATCH
+#define FILE_VERSION_RESOURCE_STR           FILE_VERSION_FULL_STR "\0"
+
+#ifndef PRODUCT_ICON
+#define PRODUCT_ICON "@PRODUCT_ICON@"
+#endif
+
+#ifndef PRODUCT_FILE_DESCRIPTION
+#define PRODUCT_FILE_DESCRIPTION   "@PRODUCT_DESCRIPTION@\0"
+#endif
+
+#ifndef PRODUCT_BUNDLE
+#define PRODUCT_BUNDLE             "@PRODUCT_NAME@\0"
+#endif
\ No newline at end of file
diff --git a/cmake/win/VersionInfo.rc b/cmake/win/VersionInfo.rc
new file mode 100644
index 0000000..3226476
--- /dev/null
+++ b/cmake/win/VersionInfo.rc
@@ -0,0 +1,35 @@
+#include "winres.h"
+#include "VersionInfo.h"
+
+IDI_ICON1               ICON                    PRODUCT_ICON
+
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
+
+VS_VERSION_INFO VERSIONINFO
+    FILEVERSION FILE_VERSION_RESOURCE
+    PRODUCTVERSION PRODUCT_VERSION_RESOURCE
+    FILEFLAGSMASK 0x3fL
+#ifdef _DEBUG
+    FILEFLAGS 0x1L
+#else
+    FILEFLAGS 0x0L
+#endif
+    FILEOS 0x4L
+    FILETYPE 0x1L
+    FILESUBTYPE 0x0L
+BEGIN
+    BLOCK "StringFileInfo"
+    BEGIN
+        BLOCK "040904b0"
+        BEGIN
+            VALUE "ProductName", PRODUCT_BUNDLE
+            VALUE "ProductVersion", PRODUCT_VERSION_RESOURCE_STR
+            VALUE "FileDescription", PRODUCT_FILE_DESCRIPTION
+            VALUE "LegalCopyright", "Copyright (C) 2005-2022 MaNGOS"
+        END
+    END
+    BLOCK "VarFileInfo"
+    BEGIN
+        VALUE "Translation", 0x409, 1200
+    END
+END
\ No newline at end of file
diff --git a/shared/.gitignore b/shared/.gitignore
new file mode 100644
index 0000000..1c62b5c
--- /dev/null
+++ b/shared/.gitignore
@@ -0,0 +1,13 @@
+#
+# NOTE! Don't add files that are generated in specific
+# subdirectories here. Add them in the ".gitignore" file
+# in that subdirectory instead.
+#
+# NOTE! Please use 'git-ls-files -i --exclude-standard'
+# command after changing this file, to see if there are
+# any tracked files which get ignored after the change.
+#
+# MaNGOS generated files
+#
+
+SystemConfig.h
diff --git a/shared/Auth/ARC4.cpp b/shared/Auth/ARC4.cpp
new file mode 100644
index 0000000..fb059ef
--- /dev/null
+++ b/shared/Auth/ARC4.cpp
@@ -0,0 +1,58 @@
+/**
+ * MaNGOS is a full featured server for World of Warcraft, supporting
+ * the following clients: 1.12.x, 2.4.3, 3.3.5a, 4.3.4a and 5.4.8
+ *
+ * Copyright (C) 2005-2022 MaNGOS <https://getmangos.eu>
+ * Copyright (C) 2008-2015 TrinityCore <http://www.trinitycore.org/>
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * World of Warcraft, and all World of Warcraft or Warcraft art, images,
+ * and lore are copyrighted by Blizzard Entertainment, Inc.
+ */
+
+#include "ARC4.h"
+
+ARC4::ARC4(uint8 len) : m_ctx()
+{
+    m_ctx = EVP_CIPHER_CTX_new();
+    EVP_EncryptInit_ex(m_ctx, EVP_rc4(), NULL, NULL, NULL);
+    EVP_CIPHER_CTX_set_key_length(m_ctx, len);
+}
+
+ARC4::ARC4(uint8 *seed, uint8 len) : m_ctx()
+{
+    m_ctx = EVP_CIPHER_CTX_new();
+    EVP_EncryptInit_ex(m_ctx, EVP_rc4(), NULL, NULL, NULL);
+    EVP_CIPHER_CTX_set_key_length(m_ctx, len);
+    EVP_EncryptInit_ex(m_ctx, NULL, NULL, seed, NULL);
+}
+
+ARC4::~ARC4()
+{
+    EVP_CIPHER_CTX_free(m_ctx);
+}
+
+void ARC4::Init(uint8 *seed)
+{
+    EVP_EncryptInit_ex(m_ctx, NULL, NULL, seed, NULL);
+}
+
+void ARC4::UpdateData(int len, uint8 *data)
+{
+    int outlen = 0;
+    EVP_EncryptUpdate(m_ctx, data, &outlen, data, len);
+    EVP_EncryptFinal_ex(m_ctx, data, &outlen);
+}
diff --git a/shared/Auth/ARC4.h b/shared/Auth/ARC4.h
new file mode 100644
index 0000000..015c13a
--- /dev/null
+++ b/shared/Auth/ARC4.h
@@ -0,0 +1,44 @@
+/**
+ * MaNGOS is a full featured server for World of Warcraft, supporting
+ * the following clients: 1.12.x, 2.4.3, 3.3.5a, 4.3.4a and 5.4.8
+ *
+ * Copyright (C) 2005-2022 MaNGOS <https://getmangos.eu>
+ * Copyright (C) 2008-2015 TrinityCore <http://www.trinitycore.org/>
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * World of Warcraft, and all World of Warcraft or Warcraft art, images,
+ * and lore are copyrighted by Blizzard Entertainment, Inc.
+ */
+
+#ifndef _AUTH_SARC4_H
+#define _AUTH_SARC4_H
+
+#include <openssl/evp.h>
+#include "Common/Common.h"
+
+class ARC4
+{
+    public:
+        ARC4(uint8 len);
+        ARC4(uint8 *seed, uint8 len);
+        ~ARC4();
+        void Init(uint8 *seed);
+        void UpdateData(int len, uint8 *data);
+    private:
+        EVP_CIPHER_CTX* m_ctx;
+};
+
+#endif
diff --git a/shared/Auth/AuthCrypt.cpp b/shared/Auth/AuthCrypt.cpp
new file mode 100644
index 0000000..8753ee7
--- /dev/null
+++ b/shared/Auth/AuthCrypt.cpp
@@ -0,0 +1,94 @@
+/**
+ * MaNGOS is a full featured server for World of Warcraft, supporting
+ * the following clients: 1.12.x, 2.4.3, 3.3.5a, 4.3.4a and 5.4.8
+ *
+ * Copyright (C) 2005-2022 MaNGOS <https://getmangos.eu>
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * World of Warcraft, and all World of Warcraft or Warcraft art, images,
+ * and lore are copyrighted by Blizzard Entertainment, Inc.
+ */
+
+#include "AuthCrypt.h"
+#include "HMACSHA1.h"
+#include "Log/Log.h"
+#include "BigNumber.h"
+
+const static size_t CRYPTED_SEND_LEN = 4;
+const static size_t CRYPTED_RECV_LEN = 6;
+
+AuthCrypt::AuthCrypt()
+{
+    _initialized = false;
+}
+
+void AuthCrypt::DecryptRecv(uint8* data, size_t len)
+{
+    if (!_initialized)
+    {
+        return;
+    }
+    if (len < CRYPTED_RECV_LEN)
+    {
+        return;
+    }
+
+    for (size_t t = 0; t < CRYPTED_RECV_LEN; t++)
+    {
+        _recv_i %= _key.size();
+        uint8 x = (data[t] - _recv_j) ^ _key[_recv_i];
+        ++_recv_i;
+        _recv_j = data[t];
+        data[t] = x;
+    }
+}
+
+void AuthCrypt::EncryptSend(uint8* data, size_t len)
+{
+    if (!_initialized)
+    {
+        return;
+    }
+
+    if (len < CRYPTED_SEND_LEN)
+    {
+        return;
+    }
+
+    for (size_t t = 0; t < CRYPTED_SEND_LEN; t++)
+    {
+        _send_i %= _key.size();
+        uint8 x = (data[t] ^ _key[_send_i]) + _send_j;
+        ++_send_i;
+        data[t] = _send_j = x;
+    }
+}
+
+void AuthCrypt::Init()
+{
+    _send_i = _send_j = _recv_i = _recv_j = 0;
+    _initialized = true;
+}
+
+void AuthCrypt::SetKey(uint8* key, size_t len)
+{
+    _key.resize(len);
+    std::copy(key, key + len, _key.begin());
+}
+
+AuthCrypt::~AuthCrypt()
+{
+}
diff --git a/shared/Auth/AuthCrypt.h b/shared/Auth/AuthCrypt.h
new file mode 100644
index 0000000..eb43052
--- /dev/null
+++ b/shared/Auth/AuthCrypt.h
@@ -0,0 +1,92 @@
+/**
+ * MaNGOS is a full featured server for World of Warcraft, supporting
+ * the following clients: 1.12.x, 2.4.3, 3.3.5a, 4.3.4a and 5.4.8
+ *
+ * Copyright (C) 2005-2022 MaNGOS <https://getmangos.eu>
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * World of Warcraft, and all World of Warcraft or Warcraft art, images,
+ * and lore are copyrighted by Blizzard Entertainment, Inc.
+ */
+
+#ifndef MANGOS_H_AUTHCRYPT
+#define MANGOS_H_AUTHCRYPT
+
+#include "Common/Common.h"
+#include <vector>
+
+class BigNumber;
+
+/**
+ * @brief
+ *
+ */
+class AuthCrypt
+{
+    public:
+        /**
+         * @brief
+         *
+         */
+        AuthCrypt();
+        /**
+         * @brief
+         *
+         */
+        ~AuthCrypt();
+
+        /**
+         * @brief
+         *
+         */
+        void Init();
+
+        /**
+        * @brief
+        *
+        * @param key
+        * @param len
+        */
+        void SetKey(uint8* key, size_t len);
+
+        /**
+         * @brief
+         *
+         * @param
+         * @param size_t
+         */
+        void DecryptRecv(uint8*, size_t);
+        /**
+         * @brief
+         *
+         * @param
+         * @param size_t
+         */
+        void EncryptSend(uint8*, size_t);
+
+        /**
+         * @brief
+         *
+         * @return bool
+         */
+        bool IsInitialized() { return _initialized; }
+
+    private:
+        std::vector<uint8> _key; /**< TODO */
+        uint8 _send_i, _send_j, _recv_i, _recv_j; /**< TODO */
+        bool _initialized; /**< TODO */
+};
+#endif
diff --git a/shared/Auth/BigNumber.cpp b/shared/Auth/BigNumber.cpp
new file mode 100644
index 0000000..994961c
--- /dev/null
+++ b/shared/Auth/BigNumber.cpp
@@ -0,0 +1,234 @@
+/**
+ * MaNGOS is a full featured server for World of Warcraft, supporting
+ * the following clients: 1.12.x, 2.4.3, 3.3.5a, 4.3.4a and 5.4.8
+ *
+ * Copyright (C) 2005-2022 MaNGOS <https://getmangos.eu>
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * World of Warcraft, and all World of Warcraft or Warcraft art, images,
+ * and lore are copyrighted by Blizzard Entertainment, Inc.
+ */
+
+#include "Auth/BigNumber.h"
+#include <openssl/bn.h>
+#include <algorithm>
+
+BigNumber::BigNumber()
+{
+    _bn = BN_new();
+    _array = NULL;
+}
+
+BigNumber::BigNumber(const BigNumber& bn)
+{
+    _bn = BN_dup(bn._bn);
+    _array = NULL;
+}
+
+BigNumber::BigNumber(uint32 val)
+{
+    _bn = BN_new();
+    BN_set_word(_bn, val);
+    _array = NULL;
+}
+
+BigNumber::~BigNumber()
+{
+    BN_free(_bn);
+    if (_array)
+    {
+        delete[] _array;
+    }
+}
+
+void BigNumber::SetDword(uint32 val)
+{
+    BN_set_word(_bn, val);
+}
+
+void BigNumber::SetQword(uint64 val)
+{
+    BN_add_word(_bn, (uint32)(val >> 32));
+    BN_lshift(_bn, _bn, 32);
+    BN_add_word(_bn, (uint32)(val & 0xFFFFFFFF));
+}
+
+void BigNumber::SetBinary(const uint8* bytes, int len)
+{
+    uint8 t[1000];
+    for (int i = 0; i < len; ++i)
+    {
+        t[i] = bytes[len - 1 - i];
+    }
+    BN_bin2bn(t, len, _bn);
+}
+
+void BigNumber::SetHexStr(const char* str)
+{
+    BN_hex2bn(&_bn, str);
+}
+
+void BigNumber::SetRand(int numbits)
+{
+    BN_rand(_bn, numbits, 0, 1);
+}
+
+BigNumber BigNumber::operator=(const BigNumber& bn)
+{
+    BN_copy(_bn, bn._bn);
+    return *this;
+}
+
+BigNumber BigNumber::operator+=(const BigNumber& bn)
+{
+    BN_add(_bn, _bn, bn._bn);
+    return *this;
+}
+
+BigNumber BigNumber::operator-=(const BigNumber& bn)
+{
+    BN_sub(_bn, _bn, bn._bn);
+    return *this;
+}
+
+BigNumber BigNumber::operator*=(const BigNumber& bn)
+{
+    BN_CTX* bnctx;
+
+    bnctx = BN_CTX_new();
+    BN_mul(_bn, _bn, bn._bn, bnctx);
+    BN_CTX_free(bnctx);
+
+    return *this;
+}
+
+BigNumber BigNumber::operator/=(const BigNumber& bn)
+{
+    BN_CTX* bnctx;
+
+    bnctx = BN_CTX_new();
+    BN_div(_bn, NULL, _bn, bn._bn, bnctx);
+    BN_CTX_free(bnctx);
+
+    return *this;
+}
+
+BigNumber BigNumber::operator%=(const BigNumber& bn)
+{
+    BN_CTX* bnctx;
+
+    bnctx = BN_CTX_new();
+    BN_mod(_bn, _bn, bn._bn, bnctx);
+    BN_CTX_free(bnctx);
+
+    return *this;
+}
+
+BigNumber BigNumber::Exp(const BigNumber& bn)
+{
+    BigNumber ret;
+    BN_CTX* bnctx;
+
+    bnctx = BN_CTX_new();
+    BN_exp(ret._bn, _bn, bn._bn, bnctx);
+    BN_CTX_free(bnctx);
+
+    return ret;
+}
+
+BigNumber BigNumber::ModExp(const BigNumber& bn1, const BigNumber& bn2)
+{
+    BigNumber ret;
+    BN_CTX* bnctx;
+
+    bnctx = BN_CTX_new();
+    BN_mod_exp(ret._bn, _bn, bn1._bn, bn2._bn, bnctx);
+    BN_CTX_free(bnctx);
+
+    return ret;
+}
+
+int BigNumber::GetNumBytes(void)
+{
+    return BN_num_bytes(_bn);
+}
+
+uint32 BigNumber::AsDword()
+{
+    return (uint32)BN_get_word(_bn);
+}
+
+bool BigNumber::isZero() const
+{
+    return BN_is_zero(_bn) != 0;
+}
+
+uint8* BigNumber::AsByteArray(int minSize)
+{
+    int length = (minSize >= GetNumBytes()) ? minSize : GetNumBytes();
+
+    delete[] _array;
+    _array = new uint8[length];
+
+    // If we need more bytes than length of BigNumber set the rest to 0
+    if (length > GetNumBytes())
+    {
+        memset((void*)_array, 0, length);
+    }
+
+    BN_bn2bin(_bn, (unsigned char*)_array);
+
+    std::reverse(_array, _array + length);
+
+    return _array;
+}
+
+uint8 *BigNumber::AsByteArray(int minSize, bool reverse)
+{
+    int length = (minSize >= GetNumBytes()) ? minSize : GetNumBytes();
+
+    if (_array)
+    {
+        delete[] _array;
+        _array = NULL;
+    }
+    _array = new uint8[length];
+
+    // If we need more bytes than length of BigNumber set the rest to 0
+    if (length > GetNumBytes())
+    {
+        memset((void*)_array, 0, length);
+    }
+
+    BN_bn2bin(_bn, (unsigned char *)_array);
+
+    if (reverse)
+    {
+        std::reverse(_array, _array + length);
+    }
+
+    return _array;
+}
+
+const char* BigNumber::AsHexStr()
+{
+    return BN_bn2hex(_bn);
+}
+
+const char* BigNumber::AsDecStr()
+{
+    return BN_bn2dec(_bn);
+}
diff --git a/shared/Auth/BigNumber.h b/shared/Auth/BigNumber.h
new file mode 100644
index 0000000..d51233b
--- /dev/null
+++ b/shared/Auth/BigNumber.h
@@ -0,0 +1,262 @@
+/**
+ * MaNGOS is a full featured server for World of Warcraft, supporting
+ * the following clients: 1.12.x, 2.4.3, 3.3.5a, 4.3.4a and 5.4.8
+ *
+ * Copyright (C) 2005-2022 MaNGOS <https://getmangos.eu>
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * World of Warcraft, and all World of Warcraft or Warcraft art, images,
+ * and lore are copyrighted by Blizzard Entertainment, Inc.
+ */
+
+#ifndef MANGOS_H_AUTH_BIGNUMBER
+#define MANGOS_H_AUTH_BIGNUMBER
+
+#include "Common/Common.h"
+
+struct bignum_st;
+
+/**
+ * @brief
+ *
+ */
+class BigNumber
+{
+    public:
+        /**
+         * @brief
+         *
+         */
+        BigNumber();
+        /**
+         * @brief
+         *
+         * @param bn
+         */
+        BigNumber(const BigNumber& bn);
+        /**
+         * @brief
+         *
+         * @param uint32
+         */
+        BigNumber(uint32);
+        /**
+         * @brief
+         *
+         */
+        ~BigNumber();
+
+        /**
+         * @brief
+         *
+         * @param uint32
+         */
+        void SetDword(uint32);
+        /**
+         * @brief
+         *
+         * @param uint64
+         */
+        void SetQword(uint64);
+        /**
+         * @brief
+         *
+         * @param bytes
+         * @param len
+         */
+        void SetBinary(const uint8* bytes, int len);
+        /**
+         * @brief
+         *
+         * @param str
+         */
+        void SetHexStr(const char* str);
+
+        /**
+         * @brief
+         *
+         * @param numbits
+         */
+        void SetRand(int numbits);
+
+        /**
+         * @brief
+         *
+         * @param bn
+         * @return BigNumber operator
+         */
+        BigNumber operator=(const BigNumber& bn);
+
+        /**
+         * @brief
+         *
+         * @param bn
+         * @return BigNumber operator
+         */
+        BigNumber operator+=(const BigNumber& bn);
+        /**
+         * @brief
+         *
+         * @param bn
+         * @return BigNumber operator
+         */
+        BigNumber operator+(const BigNumber& bn)
+        {
+            BigNumber t(*this);
+            return t += bn;
+        }
+        /**
+         * @brief
+         *
+         * @param bn
+         * @return BigNumber operator
+         */
+        BigNumber operator-=(const BigNumber& bn);
+        /**
+         * @brief
+         *
+         * @param bn
+         * @return BigNumber operator
+         */
+        BigNumber operator-(const BigNumber& bn)
+        {
+            BigNumber t(*this);
+            return t -= bn;
+        }
+        /**
+         * @brief
+         *
+         * @param bn
+         * @return BigNumber operator
+         */
+        BigNumber operator*=(const BigNumber& bn);
+        /**
+         * @brief
+         *
+         * @param bn
+         * @return BigNumber operator
+         */
+        BigNumber operator*(const BigNumber& bn)
+        {
+            BigNumber t(*this);
+            return t *= bn;
+        }
+        /**
+         * @brief
+         *
+         * @param bn
+         * @return BigNumber operator
+         */
+        BigNumber operator/=(const BigNumber& bn);
+        /**
+         * @brief
+         *
+         * @param bn
+         * @return BigNumber operator
+         */
+        BigNumber operator/(const BigNumber& bn)
+        {
+            BigNumber t(*this);
+            return t /= bn;
+        }
+        /**
+         * @brief
+         *
+         * @param bn
+         * @return BigNumber operator
+         */
+        BigNumber operator%=(const BigNumber& bn);
+        /**
+         * @brief
+         *
+         * @param bn
+         * @return BigNumber operator
+         */
+        BigNumber operator%(const BigNumber& bn)
+        {
+            BigNumber t(*this);
+            return t %= bn;
+        }
+
+        /**
+         * @brief
+         *
+         * @return bool
+         */
+        bool isZero() const;
+
+        /**
+         * @brief
+         *
+         * @param bn1
+         * @param bn2
+         * @return BigNumber
+         */
+        BigNumber ModExp(const BigNumber& bn1, const BigNumber& bn2);
+        /**
+         * @brief
+         *
+         * @param
+         * @return BigNumber
+         */
+        BigNumber Exp(const BigNumber&);
+
+        /**
+         * @brief
+         *
+         * @return int
+         */
+        int GetNumBytes(void);
+
+        /**
+         * @brief
+         *
+         * @return bignum_st
+         */
+        struct bignum_st* BN() { return _bn; }
+
+        /**
+         * @brief
+         *
+         * @return uint32
+         */
+        uint32 AsDword();
+        /**
+         * @brief
+         *
+         * @param minSize
+         * @return uint8
+         */
+        uint8* AsByteArray(int minSize = 0);
+        uint8* AsByteArray(int minSize, bool reverse);
+        /**
+         * @brief
+         *
+         * @return const char
+         */
+        const char* AsHexStr();
+        /**
+         * @brief
+         *
+         * @return const char
+         */
+        const char* AsDecStr();
+
+    private:
+        struct bignum_st* _bn; /**< TODO */
+        uint8* _array; /**< TODO */
+};
+#endif
diff --git a/shared/Auth/HMACSHA1.cpp b/shared/Auth/HMACSHA1.cpp
new file mode 100644
index 0000000..282e6f0
--- /dev/null
+++ b/shared/Auth/HMACSHA1.cpp
@@ -0,0 +1,87 @@
+/**
+ * MaNGOS is a full featured server for World of Warcraft, supporting
+ * the following clients: 1.12.x, 2.4.3, 3.3.5a, 4.3.4a and 5.4.8
+ *
+ * Copyright (C) 2005-2022 MaNGOS <https://getmangos.eu>
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * World of Warcraft, and all World of Warcraft or Warcraft art, images,
+ * and lore are copyrighted by Blizzard Entertainment, Inc.
+ */
+
+#include "Auth/HMACSHA1.h"
+#include "BigNumber.h"
+
+HMACSHA1::HMACSHA1(uint32 len, uint8 *seed)
+{
+#if OPENSSL_VERSION_NUMBER < 0x10100000L
+    HMAC_CTX_init(&m_ctx);
+    HMAC_Init_ex(&m_ctx, seed, len, EVP_sha1(), NULL);
+#else
+    m_ctx = HMAC_CTX_new();
+    HMAC_Init_ex(m_ctx, seed, len, EVP_sha1(), NULL);
+#endif
+}
+
+HMACSHA1::~HMACSHA1()
+{
+#if OPENSSL_VERSION_NUMBER < 0x10100000L
+    HMAC_CTX_cleanup(&m_ctx);
+#else
+    HMAC_CTX_free(m_ctx);
+#endif
+}
+
+void HMACSHA1::UpdateBigNumber(BigNumber *bn)
+{
+    UpdateData(bn->AsByteArray(), bn->GetNumBytes());
+}
+
+void HMACSHA1::UpdateData(const uint8 *data, int length)
+{
+#if OPENSSL_VERSION_NUMBER < 0x10100000L
+    HMAC_Update(&m_ctx, data, length);
+#else
+    HMAC_Update(m_ctx, data, length);
+#endif
+}
+
+void HMACSHA1::UpdateData(const std::string &str)
+{
+    UpdateData((uint8 const*)str.c_str(), str.length());
+}
+
+void HMACSHA1::Finalize()
+{
+    uint32 length = 0;
+#if OPENSSL_VERSION_NUMBER < 0x10100000L
+    HMAC_Final(&m_ctx, (uint8*)m_digest, &length);
+#else
+    HMAC_Final(m_ctx, (uint8*)m_digest, &length);
+#endif
+    MANGOS_ASSERT(length == SHA_DIGEST_LENGTH);
+}
+
+uint8 *HMACSHA1::ComputeHash(BigNumber *bn)
+{
+#if OPENSSL_VERSION_NUMBER < 0x10100000L
+    HMAC_Update(&m_ctx, bn->AsByteArray(), bn->GetNumBytes());
+#else
+    HMAC_Update(m_ctx, bn->AsByteArray(), bn->GetNumBytes());
+#endif
+    Finalize();
+    return (uint8*)m_digest;
+}
diff --git a/shared/Auth/HMACSHA1.h b/shared/Auth/HMACSHA1.h
new file mode 100644
index 0000000..016cdd8
--- /dev/null
+++ b/shared/Auth/HMACSHA1.h
@@ -0,0 +1,56 @@
+/**
+ * MaNGOS is a full featured server for World of Warcraft, supporting
+ * the following clients: 1.12.x, 2.4.3, 3.3.5a, 4.3.4a and 5.4.8
+ *
+ * Copyright (C) 2005-2022 MaNGOS <https://getmangos.eu>
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * World of Warcraft, and all World of Warcraft or Warcraft art, images,
+ * and lore are copyrighted by Blizzard Entertainment, Inc.
+ */
+
+#ifndef _AUTH_HMACSHA1_H
+#define _AUTH_HMACSHA1_H
+
+#include "Common/Common.h"
+#include <openssl/hmac.h>
+#include <openssl/sha.h>
+
+class BigNumber;
+
+#define SEED_KEY_SIZE 16
+
+class HMACSHA1
+{
+public:
+    HMACSHA1(uint32 len, uint8 *seed);
+    ~HMACSHA1();
+    void UpdateBigNumber(BigNumber *bn);
+    void UpdateData(const uint8 *data, int length);
+    void UpdateData(const std::string &str);
+    void Finalize();
+    uint8 *ComputeHash(BigNumber *bn);
+    uint8 *GetDigest() { return (uint8*)m_digest; }
+    int GetLength() { return SHA_DIGEST_LENGTH; }
+private:
+#if OPENSSL_VERSION_NUMBER < 0x10100000L
+    HMAC_CTX m_ctx;
+#else
+    HMAC_CTX* m_ctx;
+#endif
+    uint8 m_digest[SHA_DIGEST_LENGTH];
+};
+#endif
diff --git a/shared/Auth/Sha1.cpp b/shared/Auth/Sha1.cpp
new file mode 100644
index 0000000..bdacaf4
--- /dev/null
+++ b/shared/Auth/Sha1.cpp
@@ -0,0 +1,72 @@
+/**
+ * MaNGOS is a full featured server for World of Warcraft, supporting
+ * the following clients: 1.12.x, 2.4.3, 3.3.5a, 4.3.4a and 5.4.8
+ *
+ * Copyright (C) 2005-2022 MaNGOS <https://getmangos.eu>
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * World of Warcraft, and all World of Warcraft or Warcraft art, images,
+ * and lore are copyrighted by Blizzard Entertainment, Inc.
+ */
+
+#include "Auth/Sha1.h"
+#include "Auth/BigNumber.h"
+#include <stdarg.h>
+
+Sha1Hash::Sha1Hash()
+{
+    SHA1_Init(&mC);
+}
+
+Sha1Hash::~Sha1Hash()
+{
+    SHA1_Init(&mC);
+}
+
+void Sha1Hash::UpdateData(const uint8* dta, int len)
+{
+    SHA1_Update(&mC, dta, len);
+}
+
+void Sha1Hash::UpdateData(const std::string& str)
+{
+    UpdateData((uint8 const*)str.c_str(), str.length());
+}
+
+void Sha1Hash::UpdateBigNumbers(BigNumber* bn0, ...)
+{
+    va_list v;
+    BigNumber* bn;
+
+    va_start(v, bn0);
+    bn = bn0;
+    while (bn)
+    {
+        UpdateData(bn->AsByteArray(), bn->GetNumBytes());
+        bn = va_arg(v, BigNumber*);
+    }
+    va_end(v);
+}
+
+void Sha1Hash::Initialize()
+{
+    SHA1_Init(&mC);
+}
+
+void Sha1Hash::Finalize(void)
+{
+    SHA1_Final(mDigest, &mC);
+}
diff --git a/shared/Auth/Sha1.h b/shared/Auth/Sha1.h
new file mode 100644
index 0000000..ec4633b
--- /dev/null
+++ b/shared/Auth/Sha1.h
@@ -0,0 +1,101 @@
+/**
+ * MaNGOS is a full featured server for World of Warcraft, supporting
+ * the following clients: 1.12.x, 2.4.3, 3.3.5a, 4.3.4a and 5.4.8
+ *
+ * Copyright (C) 2005-2022 MaNGOS <https://getmangos.eu>
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * World of Warcraft, and all World of Warcraft or Warcraft art, images,
+ * and lore are copyrighted by Blizzard Entertainment, Inc.
+ */
+
+#ifndef _AUTH_SHA1_H
+#define _AUTH_SHA1_H
+
+#include "Common/Common.h"
+#include <openssl/sha.h>
+#include <openssl/crypto.h>
+
+class BigNumber;
+
+/**
+ * @brief
+ *
+ */
+class Sha1Hash
+{
+    public:
+        /**
+         * @brief
+         *
+         */
+        Sha1Hash();
+        /**
+         * @brief
+         *
+         */
+        ~Sha1Hash();
+
+        /**
+         * @brief
+         *
+         * @param bn0...
+         */
+        void UpdateBigNumbers(BigNumber* bn0, ...);
+
+        /**
+         * @brief
+         *
+         * @param dta
+         * @param len
+         */
+        void UpdateData(const uint8* dta, int len);
+        /**
+         * @brief
+         *
+         * @param str
+         */
+        void UpdateData(const std::string& str);
+
+        /**
+         * @brief
+         *
+         */
+        void Initialize();
+        /**
+         * @brief
+         *
+         */
+        void Finalize();
+
+        /**
+         * @brief
+         *
+         * @return uint8
+         */
+        uint8* GetDigest(void) { return mDigest; };
+        /**
+         * @brief
+         *
+         * @return int
+         */
+        int GetLength(void) { return SHA_DIGEST_LENGTH; };
+
+    private:
+        SHA_CTX mC; /**< TODO */
+        uint8 mDigest[SHA_DIGEST_LENGTH]; /**< TODO */
+};
+#endif
diff --git a/shared/Auth/WardenKeyGeneration.h b/shared/Auth/WardenKeyGeneration.h
new file mode 100644
index 0000000..46a92e3
--- /dev/null
+++ b/shared/Auth/WardenKeyGeneration.h
@@ -0,0 +1,88 @@
+/**
+ * MaNGOS is a full featured server for World of Warcraft, supporting
+ * the following clients: 1.12.x, 2.4.3, 3.3.5a, 4.3.4a and 5.4.8
+ *
+ * Copyright (C) 2005-2022 MaNGOS <https://getmangos.eu>
+ * Copyright (C) 2008-2015 TrinityCore <http://www.trinitycore.org/>
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * World of Warcraft, and all World of Warcraft or Warcraft art, images,
+ * and lore are copyrighted by Blizzard Entertainment, Inc.
+ */
+
+#include "Auth/Sha1.h"
+
+#ifndef _WARDEN_KEY_GENERATION_H
+#define _WARDEN_KEY_GENERATION_H
+
+class SHA1Randx
+{
+public:
+    SHA1Randx(uint8* buff, uint32 size)
+    {
+        uint32 taken = size/2;
+
+        sh.Initialize();
+        sh.UpdateData(buff, taken);
+        sh.Finalize();
+
+        memcpy(o1, sh.GetDigest(), 20);
+
+        sh.Initialize();
+        sh.UpdateData(buff + taken, size - taken);
+        sh.Finalize();
+
+        memcpy(o2, sh.GetDigest(), 20);
+
+        memset(o0, 0x00, 20);
+
+        FillUp();
+    }
+
+    void Generate(uint8* buf, uint32 sz)
+    {
+        for (uint32 i = 0; i < sz; ++i)
+        {
+            if (taken == 20)
+            {
+                FillUp();
+            }
+
+            buf[i] = o0[taken];
+            taken++;
+        }
+    }
+
+private:
+    void FillUp()
+    {
+        sh.Initialize();
+        sh.UpdateData(o1, 20);
+        sh.UpdateData(o0, 20);
+        sh.UpdateData(o2, 20);
+        sh.Finalize();
+
+        memcpy(o0, sh.GetDigest(), 20);
+
+        taken = 0;
+    }
+
+    Sha1Hash sh;
+    uint32 taken;
+    uint8 o0[20], o1[20], o2[20];
+};
+
+#endif
diff --git a/shared/Auth/md5.c b/shared/Auth/md5.c
new file mode 100644
index 0000000..be38b8a
--- /dev/null
+++ b/shared/Auth/md5.c
@@ -0,0 +1,383 @@
+/*
+  Copyright (C) 1999, 2000, 2002 Aladdin Enterprises.  All rights reserved.
+
+  This software is provided 'as-is', without any express or implied
+  warranty.  In no event will the authors be held liable for any damages
+  arising from the use of this software.
+
+  Permission is granted to anyone to use this software for any purpose,
+  including commercial applications, and to alter it and redistribute it
+  freely, subject to the following restrictions:
+
+1. The origin of this software must not be misrepresented; you must not
+claim that you wrote the original software. If you use this software
+in a product, an acknowledgment in the product documentation would be
+appreciated but is not required.
+2. Altered source versions must be plainly marked as such, and must not be
+misrepresented as being the original software.
+3. This notice may not be removed or altered from any source distribution.
+
+L. Peter Deutsch
+ghost@aladdin.com
+
+*/
+/* $Id: md5.c,v 1.6 2002/04/13 19:20:28 lpd Exp $ */
+/*
+  Independent implementation of MD5 (RFC 1321).
+
+  This code implements the MD5 Algorithm defined in RFC 1321, whose
+  text is available at
+    http://www.ietf.org/rfc/rfc1321.txt
+  The code is derived from the text of the RFC, including the test suite
+  (section A.5) but excluding the rest of Appendix A.  It does not include
+  any code or documentation that is identified in the RFC as being
+  copyrighted.
+
+The original and principal author of md5.c is L. Peter Deutsch
+<ghost@aladdin.com>.  Other authors are noted in the change history
+that follows (in reverse chronological order):
+
+2002-04-13 lpd Clarified derivation from RFC 1321; now handles byte order
+either statically or dynamically; added missing #include <string.h>
+in library.
+2002-03-11 lpd Corrected argument list for main(), and added int return
+type, in test program and T value program.
+2002-02-21 lpd Added missing #include <stdio.h> in test program.
+2000-07-03 lpd Patched to eliminate warnings about "constant is
+unsigned in ANSI C, signed in traditional"; made test program
+self-checking.
+1999-11-04 lpd Edited comments slightly for automatic TOC extraction.
+1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5).
+1999-05-03 lpd Original version.
+*/
+
+#include "md5.h"
+#include <string.h>
+
+#undef BYTE_ORDER                                           /* 1 = big-endian, -1 = little-endian, 0 = unknown */
+#ifdef ARCH_IS_BIG_ENDIAN
+#  define BYTE_ORDER (ARCH_IS_BIG_ENDIAN ? 1 : -1)
+#else
+#  define BYTE_ORDER 0
+#endif
+
+#define T_MASK ((md5_word_t)~0)
+#define T1 /* 0xd76aa478 */ (T_MASK ^ 0x28955b87)
+#define T2 /* 0xe8c7b756 */ (T_MASK ^ 0x173848a9)
+#define T3    0x242070db
+#define T4 /* 0xc1bdceee */ (T_MASK ^ 0x3e423111)
+#define T5 /* 0xf57c0faf */ (T_MASK ^ 0x0a83f050)
+#define T6    0x4787c62a
+#define T7 /* 0xa8304613 */ (T_MASK ^ 0x57cfb9ec)
+#define T8 /* 0xfd469501 */ (T_MASK ^ 0x02b96afe)
+#define T9    0x698098d8
+#define T10 /* 0x8b44f7af */ (T_MASK ^ 0x74bb0850)
+#define T11 /* 0xffff5bb1 */ (T_MASK ^ 0x0000a44e)
+#define T12 /* 0x895cd7be */ (T_MASK ^ 0x76a32841)
+#define T13    0x6b901122
+#define T14 /* 0xfd987193 */ (T_MASK ^ 0x02678e6c)
+#define T15 /* 0xa679438e */ (T_MASK ^ 0x5986bc71)
+#define T16    0x49b40821
+#define T17 /* 0xf61e2562 */ (T_MASK ^ 0x09e1da9d)
+#define T18 /* 0xc040b340 */ (T_MASK ^ 0x3fbf4cbf)
+#define T19    0x265e5a51
+#define T20 /* 0xe9b6c7aa */ (T_MASK ^ 0x16493855)
+#define T21 /* 0xd62f105d */ (T_MASK ^ 0x29d0efa2)
+#define T22    0x02441453
+#define T23 /* 0xd8a1e681 */ (T_MASK ^ 0x275e197e)
+#define T24 /* 0xe7d3fbc8 */ (T_MASK ^ 0x182c0437)
+#define T25    0x21e1cde6
+#define T26 /* 0xc33707d6 */ (T_MASK ^ 0x3cc8f829)
+#define T27 /* 0xf4d50d87 */ (T_MASK ^ 0x0b2af278)
+#define T28    0x455a14ed
+#define T29 /* 0xa9e3e905 */ (T_MASK ^ 0x561c16fa)
+#define T30 /* 0xfcefa3f8 */ (T_MASK ^ 0x03105c07)
+#define T31    0x676f02d9
+#define T32 /* 0x8d2a4c8a */ (T_MASK ^ 0x72d5b375)
+#define T33 /* 0xfffa3942 */ (T_MASK ^ 0x0005c6bd)
+#define T34 /* 0x8771f681 */ (T_MASK ^ 0x788e097e)
+#define T35    0x6d9d6122
+#define T36 /* 0xfde5380c */ (T_MASK ^ 0x021ac7f3)
+#define T37 /* 0xa4beea44 */ (T_MASK ^ 0x5b4115bb)
+#define T38    0x4bdecfa9
+#define T39 /* 0xf6bb4b60 */ (T_MASK ^ 0x0944b49f)
+#define T40 /* 0xbebfbc70 */ (T_MASK ^ 0x4140438f)
+#define T41    0x289b7ec6
+#define T42 /* 0xeaa127fa */ (T_MASK ^ 0x155ed805)
+#define T43 /* 0xd4ef3085 */ (T_MASK ^ 0x2b10cf7a)
+#define T44    0x04881d05
+#define T45 /* 0xd9d4d039 */ (T_MASK ^ 0x262b2fc6)
+#define T46 /* 0xe6db99e5 */ (T_MASK ^ 0x1924661a)
+#define T47    0x1fa27cf8
+#define T48 /* 0xc4ac5665 */ (T_MASK ^ 0x3b53a99a)
+#define T49 /* 0xf4292244 */ (T_MASK ^ 0x0bd6ddbb)
+#define T50    0x432aff97
+#define T51 /* 0xab9423a7 */ (T_MASK ^ 0x546bdc58)
+#define T52 /* 0xfc93a039 */ (T_MASK ^ 0x036c5fc6)
+#define T53    0x655b59c3
+#define T54 /* 0x8f0ccc92 */ (T_MASK ^ 0x70f3336d)
+#define T55 /* 0xffeff47d */ (T_MASK ^ 0x00100b82)
+#define T56 /* 0x85845dd1 */ (T_MASK ^ 0x7a7ba22e)
+#define T57    0x6fa87e4f
+#define T58 /* 0xfe2ce6e0 */ (T_MASK ^ 0x01d3191f)
+#define T59 /* 0xa3014314 */ (T_MASK ^ 0x5cfebceb)
+#define T60    0x4e0811a1
+#define T61 /* 0xf7537e82 */ (T_MASK ^ 0x08ac817d)
+#define T62 /* 0xbd3af235 */ (T_MASK ^ 0x42c50dca)
+#define T63    0x2ad7d2bb
+#define T64 /* 0xeb86d391 */ (T_MASK ^ 0x14792c6e)
+
+static void
+md5_process(md5_state_t *pms, const md5_byte_t *data /*[64]*/)
+{
+    md5_word_t
+        a = pms->abcd[0], b = pms->abcd[1],
+        c = pms->abcd[2], d = pms->abcd[3];
+    md5_word_t t;
+    #if BYTE_ORDER > 0
+    /* Define storage only for big-endian CPUs. */
+    md5_word_t X[16];
+    #else
+    /* Define storage for little-endian or both types of CPUs. */
+    md5_word_t xbuf[16];
+    const md5_word_t *X;
+    #endif
+
+    {
+        #if BYTE_ORDER == 0
+        /*
+         * Determine dynamically whether this is a big-endian or
+         * little-endian machine, since we can use a more efficient
+         * algorithm on the latter.
+         */
+        static const int w = 1;
+
+        if (*((const md5_byte_t *)&w))                      /* dynamic little-endian */
+        #endif
+        #if BYTE_ORDER <= 0                                 /* little-endian */
+        {
+            /*
+             * On little-endian machines, we can process properly aligned
+             * data without copying it.
+             */
+            if (!((data - (const md5_byte_t *)0) & 3))
+            {
+                /* data are properly aligned */
+                X = (const md5_word_t *)data;
+            }
+            else
+            {
+                /* not aligned */
+                memcpy(xbuf, data, 64);
+                X = xbuf;
+            }
+        }
+        #endif
+        #if BYTE_ORDER == 0
+        else                                                /* dynamic big-endian */
+        #endif
+        #if BYTE_ORDER >= 0                                 /* big-endian */
+        {
+            /*
+             * On big-endian machines, we must arrange the bytes in the
+             * right order.
+             */
+            const md5_byte_t *xp = data;
+            int i;
+
+            #  if BYTE_ORDER == 0
+            X = xbuf;                                       /* (dynamic only) */
+            #  else
+            #    define xbuf X                              /* (static only) */
+            #  endif
+            for (i = 0; i < 16; ++i, xp += 4)
+                xbuf[i] = xp[0] + (xp[1] << 8) + (xp[2] << 16) + (xp[3] << 24);
+        }
+        #endif
+    }
+
+    #define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32 - (n))))
+
+    /* Round 1. */
+    /* Let [abcd k s i] denote the operation
+       a = b + ((a + F(b,c,d) + X[k] + T[i]) <<< s). */
+    #define F(x, y, z) (((x) & (y)) | (~(x) & (z)))
+    #define SET(a, b, c, d, k, s, Ti)\
+        t = a + F(b,c,d) + X[k] + Ti;\
+        a = ROTATE_LEFT(t, s) + b
+    /* Do the following 16 operations. */
+    SET(a, b, c, d,  0,  7,  T1);
+    SET(d, a, b, c,  1, 12,  T2);
+    SET(c, d, a, b,  2, 17,  T3);
+    SET(b, c, d, a,  3, 22,  T4);
+    SET(a, b, c, d,  4,  7,  T5);
+    SET(d, a, b, c,  5, 12,  T6);
+    SET(c, d, a, b,  6, 17,  T7);
+    SET(b, c, d, a,  7, 22,  T8);
+    SET(a, b, c, d,  8,  7,  T9);
+    SET(d, a, b, c,  9, 12, T10);
+    SET(c, d, a, b, 10, 17, T11);
+    SET(b, c, d, a, 11, 22, T12);
+    SET(a, b, c, d, 12,  7, T13);
+    SET(d, a, b, c, 13, 12, T14);
+    SET(c, d, a, b, 14, 17, T15);
+    SET(b, c, d, a, 15, 22, T16);
+    #undef SET
+
+    /* Round 2. */
+    /* Let [abcd k s i] denote the operation
+         a = b + ((a + G(b,c,d) + X[k] + T[i]) <<< s). */
+    #define G(x, y, z) (((x) & (z)) | ((y) & ~(z)))
+    #define SET(a, b, c, d, k, s, Ti)\
+        t = a + G(b,c,d) + X[k] + Ti;\
+        a = ROTATE_LEFT(t, s) + b
+    /* Do the following 16 operations. */
+    SET(a, b, c, d,  1,  5, T17);
+    SET(d, a, b, c,  6,  9, T18);
+    SET(c, d, a, b, 11, 14, T19);
+    SET(b, c, d, a,  0, 20, T20);
+    SET(a, b, c, d,  5,  5, T21);
+    SET(d, a, b, c, 10,  9, T22);
+    SET(c, d, a, b, 15, 14, T23);
+    SET(b, c, d, a,  4, 20, T24);
+    SET(a, b, c, d,  9,  5, T25);
+    SET(d, a, b, c, 14,  9, T26);
+    SET(c, d, a, b,  3, 14, T27);
+    SET(b, c, d, a,  8, 20, T28);
+    SET(a, b, c, d, 13,  5, T29);
+    SET(d, a, b, c,  2,  9, T30);
+    SET(c, d, a, b,  7, 14, T31);
+    SET(b, c, d, a, 12, 20, T32);
+    #undef SET
+
+    /* Round 3. */
+    /* Let [abcd k s t] denote the operation
+         a = b + ((a + H(b,c,d) + X[k] + T[i]) <<< s). */
+    #define H(x, y, z) ((x) ^ (y) ^ (z))
+    #define SET(a, b, c, d, k, s, Ti)\
+        t = a + H(b,c,d) + X[k] + Ti;\
+        a = ROTATE_LEFT(t, s) + b
+    /* Do the following 16 operations. */
+    SET(a, b, c, d,  5,  4, T33);
+    SET(d, a, b, c,  8, 11, T34);
+    SET(c, d, a, b, 11, 16, T35);
+    SET(b, c, d, a, 14, 23, T36);
+    SET(a, b, c, d,  1,  4, T37);
+    SET(d, a, b, c,  4, 11, T38);
+    SET(c, d, a, b,  7, 16, T39);
+    SET(b, c, d, a, 10, 23, T40);
+    SET(a, b, c, d, 13,  4, T41);
+    SET(d, a, b, c,  0, 11, T42);
+    SET(c, d, a, b,  3, 16, T43);
+    SET(b, c, d, a,  6, 23, T44);
+    SET(a, b, c, d,  9,  4, T45);
+    SET(d, a, b, c, 12, 11, T46);
+    SET(c, d, a, b, 15, 16, T47);
+    SET(b, c, d, a,  2, 23, T48);
+    #undef SET
+
+    /* Round 4. */
+    /* Let [abcd k s t] denote the operation
+         a = b + ((a + I(b,c,d) + X[k] + T[i]) <<< s). */
+    #define I(x, y, z) ((y) ^ ((x) | ~(z)))
+    #define SET(a, b, c, d, k, s, Ti)\
+        t = a + I(b,c,d) + X[k] + Ti;\
+        a = ROTATE_LEFT(t, s) + b
+    /* Do the following 16 operations. */
+    SET(a, b, c, d,  0,  6, T49);
+    SET(d, a, b, c,  7, 10, T50);
+    SET(c, d, a, b, 14, 15, T51);
+    SET(b, c, d, a,  5, 21, T52);
+    SET(a, b, c, d, 12,  6, T53);
+    SET(d, a, b, c,  3, 10, T54);
+    SET(c, d, a, b, 10, 15, T55);
+    SET(b, c, d, a,  1, 21, T56);
+    SET(a, b, c, d,  8,  6, T57);
+    SET(d, a, b, c, 15, 10, T58);
+    SET(c, d, a, b,  6, 15, T59);
+    SET(b, c, d, a, 13, 21, T60);
+    SET(a, b, c, d,  4,  6, T61);
+    SET(d, a, b, c, 11, 10, T62);
+    SET(c, d, a, b,  2, 15, T63);
+    SET(b, c, d, a,  9, 21, T64);
+    #undef SET
+
+    /* Then perform the following additions. (That is increment each
+       of the four registers by the value it had before this block
+       was started.) */
+    pms->abcd[0] += a;
+    pms->abcd[1] += b;
+    pms->abcd[2] += c;
+    pms->abcd[3] += d;
+}
+
+void mangos_md5_init(md5_state_t *pms)
+{
+    pms->count[0] = pms->count[1] = 0;
+    pms->abcd[0] = 0x67452301;
+    pms->abcd[1] = /*0xefcdab89*/ T_MASK ^ 0x10325476;
+    pms->abcd[2] = /*0x98badcfe*/ T_MASK ^ 0x67452301;
+    pms->abcd[3] = 0x10325476;
+}
+
+void md5_append(md5_state_t *pms, const md5_byte_t *data, int nbytes)
+{
+    const md5_byte_t *p = data;
+    int left = nbytes;
+    int offset = (pms->count[0] >> 3) & 63;
+    md5_word_t nbits = (md5_word_t)(nbytes << 3);
+
+    if (nbytes <= 0)
+        return;
+
+    /* Update the message length. */
+    pms->count[1] += nbytes >> 29;
+    pms->count[0] += nbits;
+    if (pms->count[0] < nbits)
+        ++pms->count[1];
+
+    /* Process an initial partial block. */
+    if (offset)
+    {
+        int copy = (offset + nbytes > 64 ? 64 - offset : nbytes);
+
+        memcpy(pms->buf + offset, p, copy);
+        if (offset + copy < 64)
+            return;
+        p += copy;
+        left -= copy;
+        md5_process(pms, pms->buf);
+    }
+
+    /* Process full blocks. */
+    for (; left >= 64; p += 64, left -= 64)
+        md5_process(pms, p);
+
+    /* Process a final partial block. */
+    if (left)
+        memcpy(pms->buf, p, left);
+}
+
+void
+md5_finish(md5_state_t *pms, md5_byte_t digest[16])
+{
+    static const md5_byte_t pad[64] =
+    {
+        0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+    };
+    md5_byte_t data[8];
+    int i;
+
+    /* Save the length before padding. */
+    for (i = 0; i < 8; ++i)
+        data[i] = (md5_byte_t)(pms->count[i >> 2] >> ((i & 3) << 3));
+    /* Pad to 56 bytes mod 64. */
+    md5_append(pms, pad, ((55 - (pms->count[0] >> 3)) & 63) + 1);
+    /* Append the length. */
+    md5_append(pms, data, 8);
+    for (i = 0; i < 16; ++i)
+        digest[i] = (md5_byte_t)(pms->abcd[i >> 2] >> ((i & 3) << 3));
+}
diff --git a/shared/Auth/md5.h b/shared/Auth/md5.h
new file mode 100644
index 0000000..68fe383
--- /dev/null
+++ b/shared/Auth/md5.h
@@ -0,0 +1,91 @@
+/*
+  Copyright (C) 1999, 2002 Aladdin Enterprises.  All rights reserved.
+
+  This software is provided 'as-is', without any express or implied
+  warranty.  In no event will the authors be held liable for any damages
+  arising from the use of this software.
+
+  Permission is granted to anyone to use this software for any purpose,
+  including commercial applications, and to alter it and redistribute it
+  freely, subject to the following restrictions:
+
+1. The origin of this software must not be misrepresented; you must not
+claim that you wrote the original software. If you use this software
+in a product, an acknowledgment in the product documentation would be
+appreciated but is not required.
+2. Altered source versions must be plainly marked as such, and must not be
+misrepresented as being the original software.
+3. This notice may not be removed or altered from any source distribution.
+
+L. Peter Deutsch
+ghost@aladdin.com
+
+*/
+/* $Id: md5.h,v 1.4 2002/04/13 19:20:28 lpd Exp $ */
+/*
+  Independent implementation of MD5 (RFC 1321).
+
+  This code implements the MD5 Algorithm defined in RFC 1321, whose
+  text is available at
+    http://www.ietf.org/rfc/rfc1321.txt
+  The code is derived from the text of the RFC, including the test suite
+  (section A.5) but excluding the rest of Appendix A.  It does not include
+  any code or documentation that is identified in the RFC as being
+  copyrighted.
+
+The original and principal author of md5.h is L. Peter Deutsch
+<ghost@aladdin.com>.  Other authors are noted in the change history
+that follows (in reverse chronological order):
+
+2002-04-13 lpd Removed support for non-ANSI compilers; removed
+references to Ghostscript; clarified derivation from RFC 1321;
+now handles byte order either statically or dynamically.
+1999-11-04 lpd Edited comments slightly for automatic TOC extraction.
+1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5);
+added conditionalization for C++ compilation from Martin
+Purschke <purschke@bnl.gov>.
+1999-05-03 lpd Original version.
+*/
+
+#ifndef md5_INCLUDED
+#  define md5_INCLUDED
+
+/*
+ * This package supports both compile-time and run-time determination of CPU
+ * byte order.  If ARCH_IS_BIG_ENDIAN is defined as 0, the code will be
+ * compiled to run only on little-endian CPUs; if ARCH_IS_BIG_ENDIAN is
+ * defined as non-zero, the code will be compiled to run only on big-endian
+ * CPUs; if ARCH_IS_BIG_ENDIAN is not defined, the code will be compiled to
+ * run on either big- or little-endian CPUs, but will run slightly less
+ * efficiently on either one than if ARCH_IS_BIG_ENDIAN is defined.
+ */
+
+typedef unsigned char md5_byte_t;                           /* 8-bit byte */
+typedef unsigned int md5_word_t;                            /* 32-bit word */
+
+/* Define the state of the MD5 Algorithm. */
+typedef struct md5_state_s
+{
+    md5_word_t count[2];                                    /* message length in bits, lsw first */
+    md5_word_t abcd[4];                                     /* digest buffer */
+    md5_byte_t buf[64];                                     /* accumulate block */
+} md5_state_t;
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+    /* Initialize the algorithm. */
+    void mangos_md5_init(md5_state_t* pms);
+
+    /* Append a string to the message. */
+    void md5_append(md5_state_t* pms, const md5_byte_t* data, int nbytes);
+
+    /* Finish the message and return the digest. */
+    void md5_finish(md5_state_t* pms, md5_byte_t digest[16]);
+
+#ifdef __cplusplus
+}                                                           /* end extern "C" */
+#endif
+#endif                                                      /* md5_INCLUDED */
diff --git a/shared/CMakeLists.txt b/shared/CMakeLists.txt
new file mode 100644
index 0000000..37d96e0
--- /dev/null
+++ b/shared/CMakeLists.txt
@@ -0,0 +1,239 @@
+# MaNGOS is a full featured server for World of Warcraft, supporting
+# the following clients: 1.12.x, 2.4.3, 3.3.5a, 4.3.4a and 5.4.8
+#
+# Copyright (C) 2005-2022 MaNGOS <https://getmangos.eu>
+#
+# 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, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+include(TestBigEndian)
+
+set(SRC_GRP_AUTH
+  Auth/ARC4.cpp
+  Auth/ARC4.h
+  Auth/AuthCrypt.cpp
+  Auth/AuthCrypt.h
+  Auth/BigNumber.cpp
+  Auth/BigNumber.h
+  Auth/HMACSHA1.cpp
+  Auth/HMACSHA1.h
+  Auth/Sha1.cpp
+  Auth/Sha1.h
+  Auth/WardenKeyGeneration.h
+  Auth/md5.c
+  Auth/md5.h
+)
+source_group("Auth" FILES ${SRC_GRP_AUTH})
+
+set(SRC_GRP_COMMON
+  Common/Common.cpp
+  Common/Common.h
+  Common/ServerDefines.h
+  Common/GitRevision.cpp
+  Common/GitRevision.h
+)
+source_group("Common" FILES ${SRC_GRP_COMMON})
+
+set(SRC_GRP_CONFIG
+  Config/Config.cpp
+  Config/Config.h
+)
+source_group("Config" FILES ${SRC_GRP_CONFIG})
+
+set(SRC_GRP_DATASTORE
+  DataStores/DBCFileLoader.cpp
+  DataStores/DBCFileLoader.h
+  DataStores/DBCStore.h
+)
+source_group("DataStores" FILES ${SRC_GRP_DATASTORE})
+
+set(SRC_GRP_DATABASE
+  Database/Database.cpp
+  Database/Database.h
+  Database/DatabaseEnv.h
+  Database/DatabaseImpl.h
+  Database/DatabaseMysql.cpp
+  Database/DatabaseMysql.h
+  Database/Field.cpp
+  Database/Field.h
+  Database/QueryResult.h
+  Database/QueryResultMysql.cpp
+  Database/QueryResultMysql.h
+  Database/SQLStorage.cpp
+  Database/SQLStorage.h
+  Database/SQLStorageImpl.h
+  Database/SqlDelayThread.cpp
+  Database/SqlDelayThread.h
+  Database/SqlOperations.cpp
+  Database/SqlOperations.h
+  Database/SqlPreparedStatement.cpp
+  Database/SqlPreparedStatement.h
+)
+source_group("Database" FILES ${SRC_GRP_DATABASE})
+
+set(SRC_GRP_DYNAMIC
+  Dynamic/FactoryHolder.h
+  Dynamic/ObjectRegistry.h
+)
+source_group("Dynamic" FILES ${SRC_GRP_DYNAMIC})
+
+set(SRC_GRP_GAMESYSTEM
+  GameSystem/Grid.h
+  GameSystem/GridLoader.h
+  GameSystem/GridRefManager.h
+  GameSystem/GridReference.h
+  GameSystem/NGrid.h
+  GameSystem/TypeContainer.h
+  GameSystem/TypeContainerVisitor.h
+)
+source_group("GameSystem" FILES ${SRC_GRP_GAMESYSTEM})
+
+set(SRC_GRP_LOCKQ
+  LockedQueue/LockedQueue.h
+)
+source_group("LockedQueue" FILES ${SRC_GRP_LOCKQ})
+
+set(SRC_GRP_LOG
+  Log/Log.cpp
+  Log/Log.h
+)
+source_group("Log" FILES ${SRC_GRP_LOG})
+
+set(SRC_GRP_THREAD
+  Threading/DelayExecutor.cpp
+  Threading/DelayExecutor.h
+  Threading/Threading.cpp
+  Threading/Threading.h
+)
+source_group("Threading" FILES ${SRC_GRP_THREAD})
+
+set(SRC_GRP_PLATFORM
+  Platform/CompilerDefs.h
+  Platform/Define.h
+)
+source_group("Platform" FILES ${SRC_GRP_PLATFORM})
+
+set(SRC_GRP_POLICIES
+  Policies/CreationPolicy.h
+  Policies/ObjectLifeTime.cpp
+  Policies/ObjectLifeTime.h
+  Policies/Singleton.h
+  Policies/ThreadingModel.h
+)
+source_group("Policies" FILES ${SRC_GRP_POLICIES})
+
+if(WIN32)
+    set(SRC_GRP_SVC
+      Win/ServiceWin32.cpp
+      Win/ServiceWin32.h
+    )
+else()
+    set(SRC_GRP_SVC
+      Linux/PosixDaemon.cpp
+      Linux/PosixDaemon.h
+    )
+endif()
+source_group("Services" FILES ${SRC_GRP_SVC})
+
+set(SRC_GRP_UTILITIES
+  Utilities/ByteBuffer.cpp
+  Utilities/ByteBuffer.h
+  Utilities/Errors.h
+  Utilities/ProgressBar.cpp
+  Utilities/ProgressBar.h
+  Utilities/RNGen.h
+  Utilities/Timer.h
+  Utilities/Util.cpp
+  Utilities/Util.h
+  Utilities/WorldPacket.h
+  Utilities/ByteConverter.h
+  Utilities/Callback.h
+  Utilities/EventProcessor.cpp
+  Utilities/EventProcessor.h
+  Utilities/LinkedList.h
+  Utilities/LinkedReference/RefManager.h
+  Utilities/LinkedReference/Reference.h
+  Utilities/TypeList.h
+  Utilities/UnorderedMapSet.h
+)
+source_group("Utilities" FILES ${SRC_GRP_UTILITIES})
+
+set(TGT_INCL
+  Auth
+  Common
+  Config
+  DataStores
+  Database
+  Linux
+  LockedQueue
+  Log
+  Threading
+  Utilities
+  Utilities/LinkedReference
+  Win
+  Dynamic
+  GameSystem
+  Platform
+  Policies
+)
+
+configure_file(revision_data.h.in ${CMAKE_CURRENT_BINARY_DIR}/revision_data.h)
+configure_file(SystemConfig.h.in ${CMAKE_CURRENT_BINARY_DIR}/SystemConfig.h)
+
+TEST_BIG_ENDIAN(ENDIAN_VALUE)
+
+add_library(shared STATIC
+    ${SRC_GRP_AUTH}
+    ${SRC_GRP_COMMON}
+    ${SRC_GRP_CONFIG}
+    ${SRC_GRP_DATASTORE}
+    ${SRC_GRP_DATABASE}
+    ${SRC_GRP_DYNAMIC}
+    ${SRC_GRP_GAMESYSTEM}
+    ${SRC_GRP_LOCKQ}
+    ${SRC_GRP_LOG}
+    ${SRC_GRP_THREAD}
+    ${SRC_GRP_PLATFORM}
+    ${SRC_GRP_POLICIES}
+    ${SRC_GRP_SVC}
+    ${SRC_GRP_UTILITIES}
+    ${CMAKE_CURRENT_BINARY_DIR/revision_data.h}
+    ${CMAKE_CURRENT_BINARY_DIR/SystemConfig.h}
+)
+
+target_include_directories(shared
+    PUBLIC
+        ${CMAKE_CURRENT_SOURCE_DIR}
+        ${CMAKE_CURRENT_BINARY_DIR}
+        ${OPENSSL_INCLUDE_DIR}
+        ${TGT_INCL}
+)
+
+target_compile_definitions(shared
+    PUBLIC
+        ${MANGOS_EXP}
+        $<$<CONFIG:Debug>:MANGOS_DEBUG>
+        MANGOS_ENDIAN=${ENDIAN_VALUE}
+        $<$<BOOL:${ENDIAN_VALUE}>:ARCH_IS_BIG_ENDIAN>
+        $<$<BOOL:${SCRIPT_LIB_ELUNA}>:ENABLE_ELUNA>
+)
+
+target_link_libraries(shared
+    PUBLIC
+        ace
+        utf8
+        MySQL::MySQL
+        DL::DL
+        ${OPENSSL_LIBRARIES}
+)
diff --git a/shared/Common/Common.cpp b/shared/Common/Common.cpp
new file mode 100644
index 0000000..58c0ab9
--- /dev/null
+++ b/shared/Common/Common.cpp
@@ -0,0 +1,63 @@
+/**
+ * MaNGOS is a full featured server for World of Warcraft, supporting
+ * the following clients: 1.12.x, 2.4.3, 3.3.5a, 4.3.4a and 5.4.8
+ *
+ * Copyright (C) 2005-2022 MaNGOS <https://getmangos.eu>
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * World of Warcraft, and all World of Warcraft or Warcraft art, images,
+ * and lore are copyrighted by Blizzard Entertainment, Inc.
+ */
+
+#include "Common.h"
+
+char const* localeNames[MAX_LOCALE] =
+{
+    "enUS",                                                 // also enGB
+    "koKR",
+    "frFR",
+    "deDE",
+    "zhCN",
+    "zhTW",
+    "esES",
+    "esMX",
+};
+
+// used for search by name or iterate all names
+LocaleNameStr const fullLocaleNameList[] =
+{
+    { "enUS", LOCALE_enUS },
+    { "enGB", LOCALE_enUS },
+    { "koKR", LOCALE_koKR },
+    { "frFR", LOCALE_frFR },
+    { "deDE", LOCALE_deDE },
+    { "zhCN", LOCALE_zhCN },
+    { "zhTW", LOCALE_zhTW },
+    { "esES", LOCALE_esES },
+    { "esMX", LOCALE_esMX },
+    { NULL,   LOCALE_enUS }
+};
+
+LocaleConstant GetLocaleByName(const std::string& name)
+{
+    for (LocaleNameStr const* itr = &fullLocaleNameList[0]; itr->name; ++itr)
+        if (name == itr->name)
+        {
+            return itr->locale;
+        }
+
+    return LOCALE_enUS;                                     // including enGB case
+}
diff --git a/shared/Common/Common.h b/shared/Common/Common.h
new file mode 100644
index 0000000..b894228
--- /dev/null
+++ b/shared/Common/Common.h
@@ -0,0 +1,292 @@
+/**
+ * MaNGOS is a full featured server for World of Warcraft, supporting
+ * the following clients: 1.12.x, 2.4.3, 3.3.5a, 4.3.4a and 5.4.8
+ *
+ * Copyright (C) 2005-2022 MaNGOS <https://getmangos.eu>
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * World of Warcraft, and all World of Warcraft or Warcraft art, images,
+ * and lore are copyrighted by Blizzard Entertainment, Inc.
+ */
+
+#ifndef MANGOSSERVER_COMMON_H
+#define MANGOSSERVER_COMMON_H
+
+// config.h needs to be included 1st
+#ifdef HAVE_CONFIG_H
+#ifdef PACKAGE
+#undef PACKAGE
+#endif // PACKAGE
+
+#ifdef PACKAGE_BUGREPORT
+#undef PACKAGE_BUGREPORT
+#endif // PACKAGE_BUGREPORT
+
+#ifdef PACKAGE_NAME
+#undef PACKAGE_NAME
+#endif // PACKAGE_NAME
+
+#ifdef PACKAGE_STRING
+#undef PACKAGE_STRING
+#endif // PACKAGE_STRING
+
+#ifdef PACKAGE_TARNAME
+#undef PACKAGE_TARNAME
+#endif // PACKAGE_TARNAME
+
+#ifdef PACKAGE_VERSION
+#undef PACKAGE_VERSION
+#endif // PACKAGE_VERSION
+
+#ifdef VERSION
+#undef VERSION
+#endif // VERSION
+
+#undef PACKAGE
+#undef PACKAGE_BUGREPORT
+#undef PACKAGE_NAME
+#undef PACKAGE_STRING
+#undef PACKAGE_TARNAME
+#undef PACKAGE_VERSION
+#undef VERSION
+#endif // HAVE_CONFIG_H
+
+#include "Platform/Define.h"
+
+#if COMPILER == COMPILER_MICROSOFT
+#  pragma warning(disable:4996)                             // 'function': was declared deprecated
+#ifndef __SHOW_STUPID_WARNINGS__
+#  pragma warning(disable:4244)                             // 'argument' : conversion from 'type1' to 'type2', possible loss of data
+#  pragma warning(disable:4355)                             // 'this' : used in base member initializer list
+#endif                                                      // __SHOW_STUPID_WARNINGS__
+
+#endif                                                      // __GNUC__
+
+#include "Utilities/UnorderedMapSet.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <math.h>
+#include <errno.h>
+#include <signal.h>
+#include <assert.h>
+#include "ServerDefines.h"
+
+#if defined(__sun__)
+#include <ieeefp.h> // finite() on Solaris
+#endif
+
+#include <set>
+#include <list>
+#include <string>
+#include <map>
+#include <queue>
+#include <sstream>
+#include <algorithm>
+
+#include "Utilities/Errors.h"
+#include "LockedQueue/LockedQueue.h"
+#include "Threading/Threading.h"
+
+#include <ace/Basic_Types.h>
+#include <ace/Guard_T.h>
+#include <ace/RW_Thread_Mutex.h>
+#include <ace/Thread_Mutex.h>
+#include <ace/OS_NS_arpa_inet.h>
+
+// Old ACE versions (pre-ACE-5.5.4) not have this type (add for allow use at Unix side external old ACE versions)
+#if PLATFORM != PLATFORM_WINDOWS
+#  ifndef ACE_OFF_T
+/**
+ * @brief
+ *
+ */
+typedef off_t ACE_OFF_T;
+#  endif
+#endif
+
+#if PLATFORM == PLATFORM_WINDOWS
+#  if !defined (FD_SETSIZE)
+#    define FD_SETSIZE 4096
+#  endif
+#  include <ace/config-all.h>
+#  include <ws2tcpip.h>
+#else
+#  include <sys/types.h>
+#  include <sys/ioctl.h>
+#  include <sys/socket.h>
+#  include <netinet/in.h>
+#  include <unistd.h>
+#  include <netdb.h>
+#endif
+
+#if COMPILER == COMPILER_MICROSOFT
+
+#  include <float.h>
+
+#  define I32FMT "%08I32X"
+#  define I64FMT "%016I64X"
+#
+#  define vsnprintf _vsnprintf
+#  define finite(X) _finite(X)
+
+#else
+
+#  define stricmp strcasecmp
+#  define strnicmp strncasecmp
+
+#  define I32FMT "%08X"
+#  if ACE_SIZEOF_LONG == 8
+#    define I64FMT "%016lX"
+#  else
+#    define I64FMT "%016llX"
+#  endif /* ACE_SIZEOF_LONG == 8 */
+
+#endif
+
+#if defined(__APPLE__)
+#  ifdef I64FMT
+#    undef I64FMT
+#  endif
+#  define I64FMT "%016llX"
+#  define UI64FMTD "%llu"
+#else
+#  define UI64FMTD ACE_UINT64_FORMAT_SPECIFIER
+#endif
+
+#define UI64LIT(N) ACE_UINT64_LITERAL(N)
+
+#define SI64FMTD ACE_INT64_FORMAT_SPECIFIER
+#define SI64LIT(N) ACE_INT64_LITERAL(N)
+
+#define SIZEFMTD ACE_SIZE_T_FORMAT_SPECIFIER
+
+/**
+ * @brief
+ *
+ * @param f
+ * @return float
+ */
+inline float finiteAlways(float f) { return finite(f) ? f : 0.0f; }
+
+#define atol(a) strtoul( a, NULL, 10)
+
+#define STRINGIZE(a) #a
+
+// used for creating values for respawn for example
+#define MAKE_PAIR64(l, h)  uint64( uint32(l) | ( uint64(h) << 32 ) )
+#define PAIR64_HIPART(x)   (uint32)((uint64(x) >> 32) & UI64LIT(0x00000000FFFFFFFF))
+#define PAIR64_LOPART(x)   (uint32)(uint64(x)         & UI64LIT(0x00000000FFFFFFFF))
+
+#define MAKE_PAIR32(l, h)  uint32( uint16(l) | ( uint32(h) << 16 ) )
+#define PAIR32_HIPART(x)   (uint16)((uint32(x) >> 16) & 0x0000FFFF)
+#define PAIR32_LOPART(x)   (uint16)(uint32(x)         & 0x0000FFFF)
+
+/**
+ * @brief
+ *
+ */
+enum TimeConstants
+{
+    MINUTE = 60,
+    HOUR   = MINUTE * 60,
+    DAY    = HOUR * 24,
+    WEEK   = DAY * 7,
+    MONTH  = DAY * 30,
+    YEAR   = MONTH * 12,
+    IN_MILLISECONDS = 1000
+};
+
+/**
+ * @brief
+ *
+ */
+enum LocaleConstant
+{
+    LOCALE_enUS = 0,                                        // also enGB
+    LOCALE_koKR = 1,
+    LOCALE_frFR = 2,
+    LOCALE_deDE = 3,
+    LOCALE_zhCN = 4,
+    LOCALE_zhTW = 5,
+    LOCALE_esES = 6,
+    LOCALE_esMX = 7,
+
+};
+
+#define MAX_LOCALE 8
+#define DEFAULT_LOCALE LOCALE_enUS
+
+/**
+ * @brief
+ *
+ * @param name
+ * @return LocaleConstant
+ */
+LocaleConstant GetLocaleByName(const std::string& name);
+
+typedef std::vector<std::string> StringVector;
+
+extern char const* localeNames[MAX_LOCALE]; /**< TODO */
+
+/**
+ * @brief
+ *
+ */
+struct LocaleNameStr
+{
+    char const* name; /**< TODO */
+    LocaleConstant locale; /**< TODO */
+};
+
+extern LocaleNameStr const fullLocaleNameList[]; /**< used for iterate all names including alternative */
+
+/**
+ * @brief operator new[] based version of strdup() function! Release memory by using operator delete[] !
+ *
+ * @param source
+ * @return char
+ */
+inline char* mangos_strdup(const char* source)
+{
+    char* dest = new char[strlen(source) + 1];
+    strcpy(dest, source);
+    return dest;
+}
+
+// we always use stdlibc++ std::max/std::min, undefine some not C++ standard defines (Win API and some pother platforms)
+#ifdef max
+#  undef max
+#endif
+
+#ifdef min
+#  undef min
+#endif
+
+#ifndef M_PI
+#  define M_PI          3.14159265358979323846
+#endif
+
+#ifndef M_PI_F
+#  define M_PI_F        float(M_PI)
+#endif
+
+#ifndef countof
+#define countof(array) (sizeof(array) / sizeof((array)[0]))
+#endif
+
+#endif
diff --git a/shared/Common/GitRevision.cpp b/shared/Common/GitRevision.cpp
new file mode 100644
index 0000000..c84d802
--- /dev/null
+++ b/shared/Common/GitRevision.cpp
@@ -0,0 +1,163 @@
+/**
+ * MaNGOS is a full featured server for World of Warcraft, supporting
+ * the following clients: 1.12.x, 2.4.3, 3.3.5a, 4.3.4a and 5.4.8
+ *
+ * Copyright (C) 2005-2022 MaNGOS <https://getmangos.eu>
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * World of Warcraft, and all World of Warcraft or Warcraft art, images,
+ * and lore are copyrighted by Blizzard Entertainment, Inc.
+ */
+
+#include "GitRevision.h"
+
+char const* GitRevision::GetHash()
+{
+    return REVISION_HASH;
+}
+
+char const* GitRevision::GetDate()
+{
+    return REVISION_DATE;
+}
+
+char const* GitRevision::GetBranch()
+{
+    return REVISION_BRANCH;
+}
+
+char const* GitRevision::GetCMakeVersion()
+{
+    return CMAKE_VERSION;
+}
+
+char const* GitRevision::GetHostOSVersion()
+{
+    return "Compiled on: " CMAKE_HOST_SYSTEM;
+}
+
+// Platform Define
+#if PLATFORM == PLATFORM_WINDOWS
+    #ifdef _WIN64
+        #define MANGOS_PLATFORM_STR "Win64"
+    #else
+        #define MANGOS_PLATFORM_STR "Win32"
+    #endif
+#elif PLATFORM == PLATFORM_APPLE
+    #define MANGOS_PLATFORM_STR "MacOSX"
+#elif PLATFORM == PLATFORM_INTEL
+    #define MANGOS_PLATFORM_STR "Intel"
+#elif PLATFORM == PLATFORM_UNIX
+    #define MANGOS_PLATFORM_STR "Linux"
+#else
+    #define MANGOS_PLATFORM_STR "Unknown System"
+#endif
+
+// Database Revision
+char const* GitRevision::GetProjectRevision()
+{
+    return PROJECT_REVISION_NR;
+}
+
+char const* GitRevision::GetRealmDBVersion()
+{
+    return REALMD_DB_VERSION_NR;
+}
+
+char const* GitRevision::GetRealmDBStructure()
+{
+    return REALMD_DB_STRUCTURE_NR;
+}
+
+char const* GitRevision::GetRealmDBContent()
+{
+    return REALMD_DB_CONTENT_NR;
+}
+
+char const* GitRevision::GetRealmDBUpdateDescription()
+{
+    return REALMD_DB_UPDATE_DESCRIPT;
+}
+
+char const* GitRevision::GetCharDBVersion()
+{
+    return CHAR_DB_VERSION_NR;
+}
+
+char const* GitRevision::GetCharDBStructure()
+{
+    return CHAR_DB_STRUCTURE_NR;
+}
+
+char const* GitRevision::GetCharDBContent()
+{
+    return CHAR_DB_CONTENT_NR;
+}
+
+char const* GitRevision::GetCharDBUpdateDescription()
+{
+    return CHAR_DB_UPDATE_DESCRIPT;
+}
+
+char const* GitRevision::GetWorldDBVersion()
+{
+    return WORLD_DB_VERSION_NR;
+}
+
+char const* GitRevision::GetWorldDBStructure()
+{
+    return WORLD_DB_STRUCTURE_NR;
+}
+
+char const* GitRevision::GetWorldDBContent()
+{
+    return WORLD_DB_CONTENT_NR;
+}
+
+char const* GitRevision::GetWorldDBUpdateDescription()
+{
+    return WORLD_DB_UPDATE_DESCRIPT;
+}
+
+char const* GitRevision::GetFullRevision()
+{
+    return "Mangos revision: " VER_PRODUCTVERSION_STR;
+}
+
+char const* GitRevision::GetRunningSystem()
+{
+    return "Running on: " CMAKE_HOST_SYSTEM;
+}
+
+char const* GitRevision::GetCompanyNameStr()
+{
+    return VER_COMPANY_NAME_STR;
+}
+
+char const* GitRevision::GetLegalCopyrightStr()
+{
+    return VER_LEGALCOPYRIGHT_STR;
+}
+
+char const* GitRevision::GetFileVersionStr()
+{
+    return VER_FILEVERSION_STR;
+}
+
+char const* GitRevision::GetProductVersionStr()
+{
+    return VER_PRODUCTVERSION_STR;
+}
diff --git a/shared/Common/GitRevision.h b/shared/Common/GitRevision.h
new file mode 100644
index 0000000..cde0e67
--- /dev/null
+++ b/shared/Common/GitRevision.h
@@ -0,0 +1,69 @@
+/**
+ * MaNGOS is a full featured server for World of Warcraft, supporting
+ * the following clients: 1.12.x, 2.4.3, 3.3.5a, 4.3.4a and 5.4.8
+ *
+ * Copyright (C) 2005-2022 MaNGOS <https://getmangos.eu>
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * World of Warcraft, and all World of Warcraft or Warcraft art, images,
+ * and lore are copyrighted by Blizzard Entertainment, Inc.
+ */
+
+#ifndef GITREVISION_H
+#define GITREVISION_H
+
+#include "Define.h"
+
+#include "revision_data.h"
+
+namespace GitRevision
+{
+    // github data
+    char const* GetHash();
+    char const* GetDate();
+    char const* GetBranch();
+
+    // system data
+    char const* GetCMakeVersion();
+    char const* GetHostOSVersion();
+    char const* GetRunningSystem();
+
+    // database data
+    char const* GetProjectRevision();
+    char const* GetRealmDBVersion();
+    char const* GetRealmDBStructure();
+    char const* GetRealmDBContent();
+    char const* GetRealmDBUpdateDescription();
+
+    char const* GetCharDBVersion();
+    char const* GetCharDBStructure();
+    char const* GetCharDBContent();
+    char const* GetCharDBUpdateDescription();
+
+    char const* GetWorldDBVersion();
+    char const* GetWorldDBStructure();
+    char const* GetWorldDBContent();
+    char const* GetWorldDBUpdateDescription();
+
+    // application data
+    char const* GetFullRevision();
+    char const* GetCompanyNameStr();
+    char const* GetLegalCopyrightStr();
+    char const* GetFileVersionStr();
+    char const* GetProductVersionStr();
+}
+
+#endif
diff --git a/shared/Common/ServerDefines.h b/shared/Common/ServerDefines.h
new file mode 100644
index 0000000..343e830
--- /dev/null
+++ b/shared/Common/ServerDefines.h
@@ -0,0 +1,59 @@
+/**
+ * MaNGOS is a full featured server for World of Warcraft, supporting
+ * the following clients: 1.12.x, 2.4.3, 3.3.5a, 4.3.4a and 5.4.8
+ *
+ * Copyright (C) 2005-2022 MaNGOS <https://getmangos.eu>
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * World of Warcraft, and all World of Warcraft or Warcraft art, images,
+ * and lore are copyrighted by Blizzard Entertainment, Inc.
+ */
+
+#ifndef MANGOSSERVER_SERVERDEFINES_H
+#define MANGOSSERVER_SERVERDEFINES_H
+
+/**
+ * @brief
+ *
+ */
+enum AccountTypes
+{
+    SEC_PLAYER         = 0,
+    SEC_MODERATOR      = 1,
+    SEC_GAMEMASTER     = 2,
+    SEC_ADMINISTRATOR  = 3,
+    SEC_CONSOLE        = 4                                  // must be always last in list, accounts must have less security level always also
+};
+
+/**
+ * @brief Used in mangosd/realmd
+ *
+ */
+enum RealmFlags
+{
+    REALM_FLAG_NONE         = 0x00,
+    REALM_FLAG_INVALID      = 0x01,
+    REALM_FLAG_OFFLINE      = 0x02,
+    REALM_FLAG_SPECIFYBUILD = 0x04,                         // client will show realm version in RealmList screen in form "RealmName (major.minor.revision.build)"
+    REALM_FLAG_UNK1         = 0x08,
+    REALM_FLAG_UNK2         = 0x10,
+    REALM_FLAG_NEW_PLAYERS  = 0x20,
+    REALM_FLAG_RECOMMENDED  = 0x40,
+    REALM_FLAG_FULL         = 0x80
+};
+
+
+#endif
diff --git a/shared/Config/Config.cpp b/shared/Config/Config.cpp
new file mode 100644
index 0000000..54360ae
--- /dev/null
+++ b/shared/Config/Config.cpp
@@ -0,0 +1,130 @@
+/**
+ * MaNGOS is a full featured server for World of Warcraft, supporting
+ * the following clients: 1.12.x, 2.4.3, 3.3.5a, 4.3.4a and 5.4.8
+ *
+ * Copyright (C) 2005-2022 MaNGOS <https://getmangos.eu>
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * World of Warcraft, and all World of Warcraft or Warcraft art, images,
+ * and lore are copyrighted by Blizzard Entertainment, Inc.
+ */
+
+#include "Config.h"
+#include <ace/Configuration_Import_Export.h>
+
+#include "Policies/Singleton.h"
+
+INSTANTIATE_SINGLETON_1(Config);
+
+static bool GetValueHelper(ACE_Configuration_Heap* mConf, const char* name, ACE_TString& result)
+{
+    if (!mConf)
+    {
+        return false;
+    }
+
+    ACE_TString section_name;
+    ACE_Configuration_Section_Key section_key;
+    ACE_Configuration_Section_Key root_key = mConf->root_section();
+
+    int i = 0;
+    while (mConf->enumerate_sections(root_key, i, section_name) == 0)
+    {
+        mConf->open_section(root_key, section_name.c_str(), 0, section_key);
+        if (mConf->get_string_value(section_key, name, result) == 0)
+        {
+            return true;
+        }
+        ++i;
+    }
+
+    return false;
+}
+
+Config::Config()
+    : mConf(NULL)
+{
+}
+
+Config::~Config()
+{
+    delete mConf;
+}
+
+bool Config::SetSource(const char* file)
+{
+    mFilename = file;
+
+    return Reload();
+}
+
+bool Config::Reload()
+{
+    delete mConf;
+    mConf = new ACE_Configuration_Heap;
+
+    if (mConf->open() == 0)
+    {
+        ACE_Ini_ImpExp config_importer(*mConf);
+        if (config_importer.import_config(mFilename.c_str()) == 0)
+        {
+            return true;
+        }
+    }
+
+    delete mConf;
+    mConf = NULL;
+    return false;
+}
+
+std::string Config::GetStringDefault(const char* name, const char* def)
+{
+    ACE_TString val;
+    return GetValueHelper(mConf, name, val) ? val.c_str() : def;
+}
+
+bool Config::GetBoolDefault(const char* name, bool def)
+{
+    ACE_TString val;
+    if (!GetValueHelper(mConf, name, val))
+    {
+        return def;
+    }
+
+    const char* str = val.c_str();
+    if (strcmp(str, "true") == 0 || strcmp(str, "TRUE") == 0 ||
+        strcmp(str, "yes") == 0 || strcmp(str, "YES") == 0 ||
+        strcmp(str, "1") == 0)
+    {
+        return true;
+    }
+    else
+    {
+        return false;
+    }
+}
+
+int32 Config::GetIntDefault(const char* name, int32 def)
+{
+    ACE_TString val;
+    return GetValueHelper(mConf, name, val) ? atoi(val.c_str()) : def;
+}
+
+float Config::GetFloatDefault(const char* name, float def)
+{
+    ACE_TString val;
+    return GetValueHelper(mConf, name, val) ? (float)atof(val.c_str()) : def;
+}
diff --git a/shared/Config/Config.h b/shared/Config/Config.h
new file mode 100644
index 0000000..57006ae
--- /dev/null
+++ b/shared/Config/Config.h
@@ -0,0 +1,114 @@
+/**
+ * MaNGOS is a full featured server for World of Warcraft, supporting
+ * the following clients: 1.12.x, 2.4.3, 3.3.5a, 4.3.4a and 5.4.8
+ *
+ * Copyright (C) 2005-2022 MaNGOS <https://getmangos.eu>
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * World of Warcraft, and all World of Warcraft or Warcraft art, images,
+ * and lore are copyrighted by Blizzard Entertainment, Inc.
+ */
+
+#ifndef CONFIG_H
+#define CONFIG_H
+
+#include "Common/Common.h"
+#include <Policies/Singleton.h>
+#include "Platform/Define.h"
+
+class ACE_Configuration_Heap;
+
+/**
+ * @brief
+ *
+ */
+class Config
+{
+    public:
+        /**
+         * @brief
+         *
+         */
+        Config();
+        /**
+         * @brief
+         *
+         */
+        ~Config();
+
+        /**
+         * @brief
+         *
+         * @param file
+         * @return bool
+         */
+        bool SetSource(const char* file);
+        /**
+         * @brief
+         *
+         * @return bool
+         */
+        bool Reload();
+
+        /**
+         * @brief
+         *
+         * @param name
+         * @param def
+         * @return std::string
+         */
+        std::string GetStringDefault(const char* name, const char* def);
+        /**
+         * @brief
+         *
+         * @param name
+         * @param def
+         * @return bool
+         */
+        bool GetBoolDefault(const char* name, const bool def = false);
+        /**
+         * @brief
+         *
+         * @param name
+         * @param def
+         * @return int32
+         */
+        int32 GetIntDefault(const char* name, const int32 def);
+        /**
+         * @brief
+         *
+         * @param name
+         * @param def
+         * @return float
+         */
+        float GetFloatDefault(const char* name, const float def);
+
+        /**
+         * @brief
+         *
+         * @return std::string
+         */
+        std::string GetFilename() const { return mFilename; }
+
+    private:
+
+        std::string mFilename; /**< TODO */
+        ACE_Configuration_Heap* mConf; /**< TODO */
+};
+
+#define sConfig MaNGOS::Singleton<Config>::Instance()
+
+#endif
diff --git a/shared/DataStores/DBCFileLoader.cpp b/shared/DataStores/DBCFileLoader.cpp
new file mode 100644
index 0000000..5ff3923
--- /dev/null
+++ b/shared/DataStores/DBCFileLoader.cpp
@@ -0,0 +1,335 @@
+/**
+ * MaNGOS is a full featured server for World of Warcraft, supporting
+ * the following clients: 1.12.x, 2.4.3, 3.3.5a, 4.3.4a and 5.4.8
+ *
+ * Copyright (C) 2005-2022 MaNGOS <https://getmangos.eu>
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * World of Warcraft, and all World of Warcraft or Warcraft art, images,
+ * and lore are copyrighted by Blizzard Entertainment, Inc.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "DBCFileLoader.h"
+
+DBCFileLoader::DBCFileLoader()
+{
+    data = NULL;
+    fieldsOffset = NULL;
+}
+
+bool DBCFileLoader::Load(const char* filename, const char* fmt)
+{
+    uint32 header;
+    delete[] data;
+
+    FILE* f = fopen(filename, "rb");
+    if (!f)
+    {
+        return false;
+    }
+
+    if (fread(&header, 4, 1, f) != 1)                       // Number of records
+    {
+        fclose(f);
+        return false;
+    }
+
+    EndianConvert(header);
+    if (header != 0x43424457)                               //'WDBC'
+    {
+        fclose(f);
+        return false;
+    }
+
+    if (fread(&recordCount, 4, 1, f) != 1)                  // Number of records
+    {
+        fclose(f);
+        return false;
+    }
+
+    EndianConvert(recordCount);
+
+    if (fread(&fieldCount, 4, 1, f) != 1)                   // Number of fields
+    {
+        fclose(f);
+        return false;
+    }
+
+    EndianConvert(fieldCount);
+
+    if (fread(&recordSize, 4, 1, f) != 1)                   // Size of a record
+    {
+        fclose(f);
+        return false;
+    }
+
+    EndianConvert(recordSize);
+
+    if (fread(&stringSize, 4, 1, f) != 1)                   // String size
+    {
+        fclose(f);
+        return false;
+    }
+
+    EndianConvert(stringSize);
+
+    fieldsOffset = new uint32[fieldCount];
+    fieldsOffset[0] = 0;
+    for (uint32 i = 1; i < fieldCount; ++i)
+    {
+        fieldsOffset[i] = fieldsOffset[i - 1];
+        if (fmt[i - 1] == 'b' || fmt[i - 1] == 'X')         // byte fields
+        {
+            fieldsOffset[i] += 1;
+        }
+        else                                                // 4 byte fields (int32/float/strings)
+        {
+            fieldsOffset[i] += 4;
+        }
+    }
+
+    data = new unsigned char[recordSize * recordCount + stringSize];
+    stringTable = data + recordSize * recordCount;
+
+    if (fread(data, recordSize * recordCount + stringSize, 1, f) != 1)
+    {
+        fclose(f);
+        return false;
+    }
+
+    fclose(f);
+    return true;
+}
+
+DBCFileLoader::~DBCFileLoader()
+{
+    delete[] data;
+    delete[] fieldsOffset;
+}
+
+DBCFileLoader::Record DBCFileLoader::getRecord(size_t id)
+{
+    assert(data);
+    return Record(*this, data + id * recordSize);
+}
+
+uint32 DBCFileLoader::GetFormatRecordSize(const char* format, int32* index_pos)
+{
+    uint32 recordsize = 0;
+    int32 i = -1;
+    for (uint32 x = 0; format[x]; ++ x)
+    {
+        switch (format[x])
+        {
+            case DBC_FF_FLOAT:
+                recordsize += sizeof(float);
+                break;
+            case DBC_FF_INT:
+                recordsize += sizeof(uint32);
+                break;
+            case DBC_FF_STRING:
+                recordsize += sizeof(char*);
+                break;
+            case DBC_FF_SORT:
+                i = x;
+                break;
+            case DBC_FF_IND:
+                i = x;
+                recordsize += sizeof(uint32);
+                break;
+            case DBC_FF_BYTE:
+                recordsize += sizeof(uint8);
+                break;
+            case DBC_FF_LOGIC:
+                assert(false && "Attempted to load DBC files that do not have field types that match what is in the core. Check DBCfmt.h or your DBC files.");
+                break;
+            case DBC_FF_NA:
+            case DBC_FF_NA_BYTE:
+                break;
+            default:
+                assert(false && "Unknown field format character in DBCfmt.h");
+                break;
+        }
+    }
+
+    if (index_pos)
+    {
+        *index_pos = i;
+    }
+
+    return recordsize;
+}
+
+char* DBCFileLoader::AutoProduceData(const char* format, uint32& records, char**& indexTable)
+{
+    /*
+    format STRING, NA, FLOAT,NA,INT <=>
+    struct{
+    char* field0,
+    float field1,
+    int field2
+    }entry;
+
+    this func will generate  entry[rows] data;
+    */
+
+    typedef char* ptr;
+    if (strlen(format) != fieldCount)
+    {
+        return NULL;
+    }
+
+    // get struct size and index pos
+    int32 i;
+    uint32 recordsize = GetFormatRecordSize(format, &i);
+
+    if (i >= 0)
+    {
+        uint32 maxi = 0;
+        // find max index
+        for (uint32 y = 0; y < recordCount; ++y)
+        {
+            uint32 ind = getRecord(y).getUInt(i);
+            if (ind > maxi)
+            {
+                maxi = ind;
+            }
+        }
+
+        ++maxi;
+        records = maxi;
+        indexTable = new ptr[maxi];
+        memset(indexTable, 0, maxi * sizeof(ptr));
+    }
+    else
+    {
+        records = recordCount;
+        indexTable = new ptr[recordCount];
+    }
+
+    char* dataTable = new char[recordCount * recordsize];
+
+    uint32 offset = 0;
+
+    for (uint32 y = 0; y < recordCount; ++y)
+    {
+        if (i >= 0)
+        {
+            indexTable[getRecord(y).getUInt(i)] = &dataTable[offset];
+        }
+        else
+        {
+            indexTable[y] = &dataTable[offset];
+        }
+
+        for (uint32 x = 0; x < fieldCount; ++x)
+        {
+            switch (format[x])
+            {
+                case DBC_FF_FLOAT:
+                    *((float*)(&dataTable[offset])) = getRecord(y).getFloat(x);
+                    offset += sizeof(float);
+                    break;
+                case DBC_FF_IND:
+                case DBC_FF_INT:
+                    *((uint32*)(&dataTable[offset])) = getRecord(y).getUInt(x);
+                    offset += sizeof(uint32);
+                    break;
+                case DBC_FF_BYTE:
+                    *((uint8*)(&dataTable[offset])) = getRecord(y).getUInt8(x);
+                    offset += sizeof(uint8);
+                    break;
+                case DBC_FF_STRING:
+                    *((char**)(&dataTable[offset])) = NULL; // will replace non-empty or "" strings in AutoProduceStrings
+                    offset += sizeof(char*);
+                    break;
+                case DBC_FF_LOGIC:
+                    assert(false && "Attempted to load DBC files that do not have field types that match what is in the core. Check DBCfmt.h or your DBC files.");
+                    break;
+                case DBC_FF_NA:
+                case DBC_FF_NA_BYTE:
+                case DBC_FF_SORT:
+                    break;
+                default:
+                    assert(false && "Unknown field format character in DBCfmt.h");
+                    break;
+            }
+        }
+    }
+
+    return dataTable;
+}
+
+char* DBCFileLoader::AutoProduceStrings(const char* format, char* dataTable)
+{
+    if (strlen(format) != fieldCount)
+    {
+        return NULL;
+    }
+
+    char* stringPool = new char[stringSize];
+    memcpy(stringPool, stringTable, stringSize);
+
+    uint32 offset = 0;
+
+    for (uint32 y = 0; y < recordCount; ++y)
+    {
+        for (uint32 x = 0; x < fieldCount; ++x)
+        {
+            switch (format[x])
+            {
+                case DBC_FF_FLOAT:
+                    offset += sizeof(float);
+                    break;
+                case DBC_FF_IND:
+                case DBC_FF_INT:
+                    offset += sizeof(uint32);
+                    break;
+                case DBC_FF_BYTE:
+                    offset += sizeof(uint8);
+                    break;
+                case DBC_FF_STRING:
+                {
+                    // fill only not filled entries
+                    char** slot = (char**)(&dataTable[offset]);
+                    if (!*slot || !** slot)
+                    {
+                        const char* st = getRecord(y).getString(x);
+                        *slot = stringPool + (st - (const char*)stringTable);
+                    }
+                    offset += sizeof(char*);
+                    break;
+                }
+                case DBC_FF_LOGIC:
+                    assert(false && "Attempted to load DBC files that does not have field types that match what is in the core. Check DBCfmt.h or your DBC files.");
+                    break;
+                case DBC_FF_NA:
+                case DBC_FF_NA_BYTE:
+                case DBC_FF_SORT:
+                    break;
+                default:
+                    assert(false && "Unknown field format character in DBCfmt.h");
+                    break;
+            }
+        }
+    }
+
+    return stringPool;
+}
diff --git a/shared/DataStores/DBCFileLoader.h b/shared/DataStores/DBCFileLoader.h
new file mode 100644
index 0000000..c492f1b
--- /dev/null
+++ b/shared/DataStores/DBCFileLoader.h
@@ -0,0 +1,219 @@
+/**
+ * MaNGOS is a full featured server for World of Warcraft, supporting
+ * the following clients: 1.12.x, 2.4.3, 3.3.5a, 4.3.4a and 5.4.8
+ *
+ * Copyright (C) 2005-2022 MaNGOS <https://getmangos.eu>
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * World of Warcraft, and all World of Warcraft or Warcraft art, images,
+ * and lore are copyrighted by Blizzard Entertainment, Inc.
+ */
+
+#ifndef DBC_FILE_LOADER_H
+#define DBC_FILE_LOADER_H
+
+#include "Platform/Define.h"
+#include "Utilities/ByteConverter.h"
+#include <cassert>
+
+/**
+ * @brief
+ *
+ */
+enum FieldFormat
+{
+    DBC_FF_NA = 'x',                                        // ignore/ default, 4 byte size, in Source String means field is ignored, in Dest String means field is filled with default value
+    DBC_FF_NA_BYTE = 'X',                                   // ignore/ default, 1 byte size, see above
+    DBC_FF_NA_FLOAT = 'F',                                  // ignore/ default,  float size, see above
+    DBC_FF_NA_POINTER = 'p',                                // fill default value into dest, pointer size, Use this only with static data (otherwise mem-leak)
+    DBC_FF_STRING = 's',                                    // char*
+    DBC_FF_FLOAT = 'f',                                     // float
+    DBC_FF_INT = 'i',                                       // uint32
+    DBC_FF_BYTE = 'b',                                      // uint8
+    DBC_FF_SORT = 'd',                                      // sorted by this field, field is not included
+    DBC_FF_IND = 'n',                                       // the same,but parsed to data
+    DBC_FF_LOGIC = 'l'                                          // Logical (boolean)
+};
+
+/**
+ * @brief
+ *
+ */
+class DBCFileLoader
+{
+    public:
+        /**
+         * @brief
+         *
+         */
+        DBCFileLoader();
+        /**
+         * @brief
+         *
+         */
+        ~DBCFileLoader();
+
+        /**
+         * @brief
+         *
+         * @param filename
+         * @param fmt
+         * @return bool
+         */
+        bool Load(const char* filename, const char* fmt);
+
+        /**
+         * @brief
+         *
+         */
+        class Record
+        {
+            public:
+                /**
+                 * @brief
+                 *
+                 * @param field
+                 * @return float
+                 */
+                float getFloat(size_t field) const
+                {
+                    assert(field < file.fieldCount);
+                    float val = *reinterpret_cast<float*>(offset + file.GetOffset(field));
+                    EndianConvert(val);
+                    return val;
+                }
+                /**
+                 * @brief
+                 *
+                 * @param field
+                 * @return uint32
+                 */
+                uint32 getUInt(size_t field) const
+                {
+                    assert(field < file.fieldCount);
+                    uint32 val = *reinterpret_cast<uint32*>(offset + file.GetOffset(field));
+                    EndianConvert(val);
+                    return val;
+                }
+                /**
+                 * @brief
+                 *
+                 * @param field
+                 * @return uint8
+                 */
+                uint8 getUInt8(size_t field) const
+                {
+                    assert(field < file.fieldCount);
+                    return *reinterpret_cast<uint8*>(offset + file.GetOffset(field));
+                }
+
+                /**
+                 * @brief
+                 *
+                 * @param field
+                 * @return const char
+                 */
+                const char* getString(size_t field) const
+                {
+                    assert(field < file.fieldCount);
+                    size_t stringOffset = getUInt(field);
+                    assert(stringOffset < file.stringSize);
+                    return reinterpret_cast<char*>(file.stringTable + stringOffset);
+                }
+
+            private:
+                /**
+                 * @brief
+                 *
+                 * @param file_
+                 * @param offset_
+                 */
+                Record(DBCFileLoader& file_, unsigned char* offset_): offset(offset_), file(file_) {}
+                unsigned char* offset; /**< TODO */
+                DBCFileLoader& file; /**< TODO */
+
+                friend class DBCFileLoader;
+        };
+
+        /**
+         * @brief Get record by id
+         *
+         * @param id
+         * @return Record
+         */
+        Record getRecord(size_t id);
+
+        /**
+         * @brief Get begin iterator over records
+         *
+         * @return uint32
+         */
+        uint32 GetNumRows() const { return recordCount;}
+        /**
+         * @brief
+         *
+         * @return uint32
+         */
+        uint32 GetCols() const { return fieldCount; }
+        /**
+         * @brief
+         *
+         * @param id
+         * @return uint32
+         */
+        uint32 GetOffset(size_t id) const { return (fieldsOffset != NULL && id < fieldCount) ? fieldsOffset[id] : 0; }
+        /**
+         * @brief
+         *
+         * @return bool
+         */
+        bool IsLoaded() const {return (data != NULL);}
+        /**
+         * @brief
+         *
+         * @param fmt
+         * @param count
+         * @param indexTable
+         * @return char
+         */
+        char* AutoProduceData(const char* fmt, uint32& count, char**& indexTable);
+        /**
+         * @brief
+         *
+         * @param fmt
+         * @param dataTable
+         * @return char
+         */
+        char* AutoProduceStrings(const char* fmt, char* dataTable);
+        /**
+         * Calculate and return the total amount of memory required by the types specified within the format string
+         *
+         * @param format the format string passed to it (see DBCfmt.h)
+         * @param index_pos
+         * @return uint32 the total amount of memory required for all the data types
+         */
+        static uint32 GetFormatRecordSize(const char* format, int32* index_pos = NULL);
+    private:
+
+        uint32 recordSize; /**< TODO */
+        uint32 recordCount; /**< TODO */
+        uint32 fieldCount; /**< TODO */
+        uint32 stringSize; /**< TODO */
+        uint32* fieldsOffset; /**< TODO */
+        unsigned char* data; /**< TODO */
+        unsigned char* stringTable; /**< TODO */
+};
+#endif
diff --git a/shared/DataStores/DBCStore.h b/shared/DataStores/DBCStore.h
new file mode 100644
index 0000000..47b0801
--- /dev/null
+++ b/shared/DataStores/DBCStore.h
@@ -0,0 +1,221 @@
+/**
+ * MaNGOS is a full featured server for World of Warcraft, supporting
+ * the following clients: 1.12.x, 2.4.3, 3.3.5a, 4.3.4a and 5.4.8
+ *
+ * Copyright (C) 2005-2022 MaNGOS <https://getmangos.eu>
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * World of Warcraft, and all World of Warcraft or Warcraft art, images,
+ * and lore are copyrighted by Blizzard Entertainment, Inc.
+ */
+
+#ifndef DBCSTORE_H
+#define DBCSTORE_H
+
+#include "DBCFileLoader.h"
+
+template<class T>
+/**
+ * @brief
+ *
+ */
+class DBCStorage
+{
+        /**
+         * @brief
+         *
+         */
+        typedef std::list<char*> StringPoolList;
+    public:
+        /**
+         * @brief
+         *
+         * @param f
+         */
+        explicit DBCStorage(const char* f) : nCount(0), fieldCount(0), fmt(f), indexTable(NULL), m_dataTable(NULL) { }
+        /**
+         * @brief
+         *
+         */
+        ~DBCStorage() { Clear(); }
+
+        /**
+        * @brief
+        *
+        * @return uint32
+        */
+        //uint32  GetNumRows() const { return nCount; }
+        uint32  GetNumRows() const { return loaded ? data.size() : nCount; }
+        /**
+         * @brief
+         *
+         * @return const char
+         */
+        char const* GetFormat() const { return fmt; }
+        /**
+         * @brief
+         *
+         * @return uint32
+         */
+        uint32 GetFieldCount() const { return fieldCount; }
+
+        /**
+        * @brief
+        *
+        * @param id
+        * @return const T
+        */
+        //T const* LookupEntry(uint32 id) const { return (id >= nCount) ? NULL : indexTable[id]; }
+        T const* LookupEntry(uint32 id) const
+        {
+            if (loaded)
+            {
+                typename std::map<uint32, T const*>::const_iterator it = data.find(id);
+                if (it != data.end())
+                {
+                    return it->second;
+                }
+            }
+            return (id >= nCount) ? NULL : indexTable[id];
+        }
+        /**
+         * @brief
+         *
+         * @param fn
+         * @return bool
+         */
+        bool Load(char const* fn)
+        {
+            DBCFileLoader dbc;
+            // Check if load was sucessful, only then continue
+            if (!dbc.Load(fn, fmt))
+            {
+                return false;
+            }
+
+            fieldCount = dbc.GetCols();
+
+            // load raw non-string data
+            m_dataTable = (T*)dbc.AutoProduceData(fmt, nCount, (char**&)indexTable);
+
+            // load strings from dbc data
+            m_stringPoolList.push_back(dbc.AutoProduceStrings(fmt, (char*)m_dataTable));
+
+            // error in dbc file at loading if NULL
+            return indexTable != NULL;
+        }
+
+        void SetEntry(uint32 id, T* t) // Cryptic they say..
+        {
+            if (!loaded)
+            {
+                for (uint32 i = 0; i < nCount; ++i)
+                {
+                    T const* node = LookupEntry(i);
+                    if (!node)
+                    {
+                        continue;
+                    }
+                    data[i] = node;
+                }
+                loaded = true;
+            }
+            data[id] = t;
+        }
+
+        /**
+         * @brief
+         *
+         * @param fn
+         * @return bool
+         */
+        bool LoadStringsFrom(char const* fn)
+        {
+            // DBC must be already loaded using Load
+            if (!indexTable)
+            {
+                return false;
+            }
+
+            DBCFileLoader dbc;
+            // Check if load was successful, only then continue
+            if (!dbc.Load(fn, fmt))
+            {
+                return false;
+            }
+
+            // load strings from another locale dbc data
+            m_stringPoolList.push_back(dbc.AutoProduceStrings(fmt, (char*)m_dataTable));
+
+            return true;
+        }
+
+        /**
+         * @brief
+         *
+         */
+        void Clear()
+        {
+            if (loaded)
+            {
+                data.clear();
+                loaded = false;
+            }
+
+            if (!indexTable)
+            {
+                return;
+            }
+
+            delete[]((char*)indexTable);
+            indexTable = NULL;
+            delete[]((char*)m_dataTable);
+            m_dataTable = NULL;
+
+            while (!m_stringPoolList.empty())
+            {
+                delete[] m_stringPoolList.front();
+                m_stringPoolList.pop_front();
+            }
+            nCount = 0;
+        }
+
+        /**
+         * @brief
+         *
+         * @param id
+         */
+        void EraseEntry(uint32 id) { assert(id < nCount && "Entry to be erased must be in bounds!") ; indexTable[id] = NULL; }
+        /**
+         * @brief
+         *
+         * @param entry
+         * @param id
+         */
+        void InsertEntry(T* entry, uint32 id) { assert(id < nCount && "Entry to be inserted must be in bounds!"); indexTable[id] = entry; }
+
+    private:
+        uint32 nCount; /**< TODO */
+        uint32 fieldCount; /**< TODO */
+        char const* fmt; /**< TODO */
+        T** indexTable; /**< TODO */
+        T* m_dataTable; /**< TODO */
+        std::map<uint32, T const*> data;
+        bool loaded;
+        StringPoolList m_stringPoolList; /**< TODO */
+};
+
+#endif
diff --git a/shared/Database/Database.cpp b/shared/Database/Database.cpp
new file mode 100644
index 0000000..df00c81
--- /dev/null
+++ b/shared/Database/Database.cpp
@@ -0,0 +1,783 @@
+/**
+ * MaNGOS is a full featured server for World of Warcraft, supporting
+ * the following clients: 1.12.x, 2.4.3, 3.3.5a, 4.3.4a and 5.4.8
+ *
+ * Copyright (C) 2005-2022 MaNGOS <https://getmangos.eu>
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * World of Warcraft, and all World of Warcraft or Warcraft art, images,
+ * and lore are copyrighted by Blizzard Entertainment, Inc.
+ */
+
+#include "DatabaseEnv.h"
+#include "Config/Config.h"
+#include "Database/SqlOperations.h"
+#include "GitRevision.h"
+
+#include <ctime>
+#include <iostream>
+#include <fstream>
+#include <memory>
+
+#define MIN_CONNECTION_POOL_SIZE 1
+#define MAX_CONNECTION_POOL_SIZE 16
+
+struct DBVersion
+{
+    std::string dbname;
+    std::string expected_version;
+    std::string expected_structure;
+    std::string minimal_expected_content; // Minimal because core can starts with some missing contents
+    std::string description;
+};
+
+const DBVersion databaseVersions[COUNT_DATABASES] = {
+    { "World", GitRevision::GetWorldDBVersion(), GitRevision::GetWorldDBStructure(), GitRevision::GetWorldDBContent(), GitRevision::GetWorldDBUpdateDescription() }, // DATABASE_WORLD
+    { "Realmd", GitRevision::GetRealmDBVersion(), GitRevision::GetRealmDBStructure(), GitRevision::GetRealmDBContent(), GitRevision::GetRealmDBUpdateDescription() }, // DATABASE_REALMD
+    { "Character", GitRevision::GetCharDBVersion(), GitRevision::GetCharDBStructure(), GitRevision::GetCharDBContent(), GitRevision::GetCharDBUpdateDescription() }, // DATABASE_CHARACTER
+};
+
+//////////////////////////////////////////////////////////////////////////
+SqlPreparedStatement* SqlConnection::CreateStatement(const std::string& fmt)
+{
+    return new SqlPlainPreparedStatement(fmt, *this);
+}
+
+void SqlConnection::FreePreparedStatements()
+{
+    SqlConnection::Lock guard(this);
+
+    size_t nStmts = m_holder.size();
+    for (size_t i = 0; i < nStmts; ++i)
+    {
+        delete m_holder[i];
+    }
+
+    m_holder.clear();
+}
+
+SqlPreparedStatement* SqlConnection::GetStmt(uint32 nIndex)
+{
+    // resize stmt container
+    if (m_holder.size() <= nIndex)
+    {
+        m_holder.resize(nIndex + 1, NULL);
+    }
+
+    SqlPreparedStatement* pStmt = NULL;
+
+    // create stmt if needed
+    if (m_holder[nIndex] == NULL)
+    {
+        // obtain SQL request string
+        std::string fmt = m_db.GetStmtString(nIndex);
+        MANGOS_ASSERT(fmt.length());
+        // allocate SQlPreparedStatement object
+        pStmt = CreateStatement(fmt);
+        // prepare statement
+        if (!pStmt->prepare())
+        {
+            MANGOS_ASSERT(false && "Unable to prepare SQL statement");
+            return NULL;
+        }
+
+        // save statement in internal registry
+        m_holder[nIndex] = pStmt;
+    }
+    else
+    {
+        pStmt = m_holder[nIndex];
+    }
+
+    return pStmt;
+}
+
+bool SqlConnection::ExecuteStmt(int nIndex, const SqlStmtParameters& id)
+{
+    if (nIndex == -1)
+    {
+        return false;
+    }
+
+    // get prepared statement object
+    SqlPreparedStatement* pStmt = GetStmt(nIndex);
+    // bind parameters
+    pStmt->bind(id);
+    // execute statement
+    return pStmt->execute();
+}
+
+//////////////////////////////////////////////////////////////////////////
+Database::~Database()
+{
+    StopServer();
+}
+
+bool Database::Initialize(const char* infoString, int nConns /*= 1*/)
+{
+    // Enable logging of SQL commands (usually only GM commands)
+    // (See method: PExecuteLog)
+    m_logSQL = sConfig.GetBoolDefault("LogSQL", false);
+    m_logsDir = sConfig.GetStringDefault("LogsDir", "");
+    if (!m_logsDir.empty())
+    {
+        if ((m_logsDir.at(m_logsDir.length() - 1) != '/') && (m_logsDir.at(m_logsDir.length() - 1) != '\\'))
+        {
+            m_logsDir.append("/");
+        }
+    }
+
+    m_pingIntervallms = sConfig.GetIntDefault("MaxPingTime", 30) * (MINUTE * 1000);
+
+    // create DB connections
+
+    // setup connection pool size
+    if (nConns < MIN_CONNECTION_POOL_SIZE)
+    {
+        m_nQueryConnPoolSize = MIN_CONNECTION_POOL_SIZE;
+    }
+    else if (nConns > MAX_CONNECTION_POOL_SIZE)
+    {
+        m_nQueryConnPoolSize = MAX_CONNECTION_POOL_SIZE;
+    }
+    else
+    {
+        m_nQueryConnPoolSize = nConns;
+    }
+
+    // create connection pool for sync requests
+    for (int i = 0; i < m_nQueryConnPoolSize; ++i)
+    {
+        SqlConnection* pConn = CreateConnection();
+        if (!pConn->Initialize(infoString))
+        {
+            delete pConn;
+            return false;
+        }
+
+        m_pQueryConnections.push_back(pConn);
+    }
+
+    // create and initialize connection for async requests
+    m_pAsyncConn = CreateConnection();
+    if (!m_pAsyncConn->Initialize(infoString))
+    {
+        return false;
+    }
+
+    m_pResultQueue = new SqlResultQueue;
+
+    InitDelayThread();
+    return true;
+}
+
+void Database::StopServer()
+{
+    HaltDelayThread();
+
+    delete m_pResultQueue;
+    delete m_pAsyncConn;
+
+    m_pResultQueue = NULL;
+    m_pAsyncConn = NULL;
+
+    for (size_t i = 0; i < m_pQueryConnections.size(); ++i)
+    {
+        delete m_pQueryConnections[i];
+    }
+
+    m_pQueryConnections.clear();
+}
+
+SqlDelayThread* Database::CreateDelayThread()
+{
+    assert(m_pAsyncConn);
+    return new SqlDelayThread(this, m_pAsyncConn);
+}
+
+void Database::InitDelayThread()
+{
+    assert(!m_delayThread);
+
+    // New delay thread for delay execute
+    m_threadBody = CreateDelayThread();              // will deleted at m_delayThread delete
+    m_TransStorage = new ACE_TSS<Database::TransHelper>();
+    m_delayThread = new ACE_Based::Thread(m_threadBody);
+}
+
+void Database::HaltDelayThread()
+{
+    if (!m_threadBody || !m_delayThread)
+    {
+        return;
+    }
+
+    m_threadBody->Stop();                                   // Stop event
+    m_delayThread->wait();                                  // Wait for flush to DB
+    delete m_TransStorage;
+    delete m_delayThread;                                   // This also deletes m_threadBody
+    m_delayThread = NULL;
+    m_threadBody = NULL;
+    m_TransStorage=NULL;
+}
+
+void Database::ThreadStart()
+{
+}
+
+void Database::ThreadEnd()
+{
+}
+
+void Database::ProcessResultQueue()
+{
+    if (m_pResultQueue)
+    {
+        m_pResultQueue->Update();
+    }
+}
+
+void Database::escape_string(std::string& str)
+{
+    if (str.empty())
+    {
+        return;
+    }
+
+    char* buf = new char[str.size() * 2 + 1];
+    // we don't care what connection to use - escape string will be the same
+    m_pQueryConnections[0]->escape_string(buf, str.c_str(), str.size());
+    str = buf;
+    delete[] buf;
+}
+
+SqlConnection* Database::getQueryConnection()
+{
+    int nCount = 0;
+
+    if (m_nQueryCounter == long(1 << 31))
+    {
+        m_nQueryCounter = 0;
+    }
+    else
+    {
+        nCount = ++m_nQueryCounter;
+    }
+
+    return m_pQueryConnections[nCount % m_nQueryConnPoolSize];
+}
+
+void Database::Ping()
+{
+    const char* sql = "SELECT 1";
+
+    {
+        SqlConnection::Lock guard(m_pAsyncConn);
+        delete guard->Query(sql);
+    }
+
+    for (int i = 0; i < m_nQueryConnPoolSize; ++i)
+    {
+        SqlConnection::Lock guard(m_pQueryConnections[i]);
+        delete guard->Query(sql);
+    }
+}
+
+bool Database::PExecuteLog(const char* format, ...)
+{
+    if (!format)
+    {
+        return false;
+    }
+
+    va_list ap;
+    char szQuery [MAX_QUERY_LEN];
+    va_start(ap, format);
+    int res = vsnprintf(szQuery, MAX_QUERY_LEN, format, ap);
+    va_end(ap);
+
+    if (res == -1)
+    {
+        sLog.outError("SQL Query truncated (and not execute) for format: %s", format);
+        return false;
+    }
+
+    if (m_logSQL)
+    {
+        time_t curr;
+        tm local;
+        time(&curr);                                        // get current time_t value
+        local = *(localtime(&curr));                        // dereference and assign
+        char fName[128];
+        sprintf(fName, "%04d-%02d-%02d_logSQL.sql", local.tm_year + 1900, local.tm_mon + 1, local.tm_mday);
+
+        FILE* log_file;
+        std::string logsDir_fname = m_logsDir + fName;
+        log_file = fopen(logsDir_fname.c_str(), "a");
+        if (log_file)
+        {
+            fprintf(log_file, "%s;\n", szQuery);
+            fclose(log_file);
+        }
+        else
+        {
+            // The file could not be opened
+            sLog.outError("SQL-Logging is disabled - Log file for the SQL commands could not be openend: %s", fName);
+        }
+    }
+
+    return Execute(szQuery);
+}
+
+QueryResult* Database::PQuery(const char* format, ...)
+{
+    if (!format)
+    {
+        return NULL;
+    }
+
+    va_list ap;
+    char szQuery [MAX_QUERY_LEN];
+    va_start(ap, format);
+    int res = vsnprintf(szQuery, MAX_QUERY_LEN, format, ap);
+    va_end(ap);
+
+    if (res == -1)
+    {
+        sLog.outError("SQL Query truncated (and not execute) for format: %s", format);
+        return NULL;
+    }
+
+    return Query(szQuery);
+}
+
+QueryNamedResult* Database::PQueryNamed(const char* format, ...)
+{
+    if (!format)
+    {
+        return NULL;
+    }
+
+    va_list ap;
+    char szQuery [MAX_QUERY_LEN];
+    va_start(ap, format);
+    int res = vsnprintf(szQuery, MAX_QUERY_LEN, format, ap);
+    va_end(ap);
+
+    if (res == -1)
+    {
+        sLog.outError("SQL Query truncated (and not execute) for format: %s", format);
+        return NULL;
+    }
+
+    return QueryNamed(szQuery);
+}
+
+bool Database::Execute(const char* sql)
+{
+    if (!m_pAsyncConn)
+    {
+        return false;
+    }
+
+    SqlTransaction* pTrans = (*m_TransStorage)->get();
+    if (pTrans)
+    {
+        // add SQL request to trans queue
+        pTrans->DelayExecute(new SqlPlainRequest(sql));
+    }
+    else
+    {
+        // if async execution is not available
+        if (!m_bAllowAsyncTransactions)
+        {
+            return DirectExecute(sql);
+        }
+
+        // Simple sql statement
+        m_threadBody->Delay(new SqlPlainRequest(sql));
+    }
+
+    return true;
+}
+
+bool Database::PExecute(const char* format, ...)
+{
+    if (!format)
+    {
+        return false;
+    }
+
+    va_list ap;
+    char szQuery [MAX_QUERY_LEN];
+    va_start(ap, format);
+    int res = vsnprintf(szQuery, MAX_QUERY_LEN, format, ap);
+    va_end(ap);
+
+    if (res == -1)
+    {
+        sLog.outError("SQL Query truncated (and not execute) for format: %s", format);
+        return false;
+    }
+
+    return Execute(szQuery);
+}
+
+bool Database::DirectPExecute(const char* format, ...)
+{
+    if (!format)
+    {
+        return false;
+    }
+
+    va_list ap;
+    char szQuery [MAX_QUERY_LEN];
+    va_start(ap, format);
+    int res = vsnprintf(szQuery, MAX_QUERY_LEN, format, ap);
+    va_end(ap);
+
+    if (res == -1)
+    {
+        sLog.outError("SQL Query truncated (and not execute) for format: %s", format);
+        return false;
+    }
+
+    return DirectExecute(szQuery);
+}
+
+bool Database::BeginTransaction()
+{
+    if (!m_pAsyncConn)
+    {
+        return false;
+    }
+
+    // initiate transaction on current thread
+    // currently we do not support queued transactions
+    (*m_TransStorage)->init();
+    return true;
+}
+
+bool Database::CommitTransaction()
+{
+    if (!m_pAsyncConn)
+    {
+        return false;
+    }
+
+    // check if we have pending transaction
+    if (!(*m_TransStorage)->get())
+    {
+        return false;
+    }
+
+    // if async execution is not available
+    if (!m_bAllowAsyncTransactions)
+    {
+        return CommitTransactionDirect();
+    }
+
+    // add SqlTransaction to the async queue
+    m_threadBody->Delay((*m_TransStorage)->detach());
+    return true;
+}
+
+bool Database::CommitTransactionDirect()
+{
+    if (!m_pAsyncConn)
+    {
+        return false;
+    }
+
+    // check if we have pending transaction
+    if (!(*m_TransStorage)->get())
+    {
+        return false;
+    }
+
+    // directly execute SqlTransaction
+    SqlTransaction* pTrans = (*m_TransStorage)->detach();
+    pTrans->Execute(m_pAsyncConn);
+    delete pTrans;
+
+    return true;
+}
+
+bool Database::RollbackTransaction()
+{
+    if (!m_pAsyncConn)
+    {
+        return false;
+    }
+
+    if (!(*m_TransStorage)->get())
+    {
+        return false;
+    }
+
+    // remove scheduled transaction
+    (*m_TransStorage)->reset();
+
+    return true;
+}
+
+void PrintNormalYouHaveDatabaseVersion(std::string current_db_version, std::string current_db_structure, std::string current_db_content, std::string description)
+{
+    sLog.outString("  [A] You have database Version: %s", current_db_version.c_str());
+    sLog.outString("                      Structure: %s", current_db_structure.c_str());
+    sLog.outString("                        Content: %s", current_db_content.c_str());
+    sLog.outString("                    Description: %s", description.c_str());
+}
+
+void PrintErrorYouHaveDatabaseVersion(std::string current_db_version, std::string current_db_structure, std::string current_db_content, std::string description)
+{
+    sLog.outErrorDb("  [A] You have database Version: %s", current_db_version.c_str());
+    sLog.outErrorDb("                      Structure: %s", current_db_structure.c_str());
+    sLog.outErrorDb("                        Content: %s", current_db_content.c_str());
+    sLog.outErrorDb("                    Description: %s", description.c_str());
+}
+
+void PrintNormalDatabaseVersionReferencedByCore(const DBVersion& core_db_requirements)
+{
+    sLog.outString("  [B] The core references last database Version: %s", core_db_requirements.expected_version.c_str());
+    sLog.outString("                                      Structure: %s", core_db_requirements.expected_structure.c_str());
+    sLog.outString("                                        Content: %s", core_db_requirements.minimal_expected_content.c_str());
+    sLog.outString("                                    Description: %s", core_db_requirements.description.c_str());
+}
+
+void PrintErrorYouNeedDatabaseVersionExpectedByCore(const DBVersion& core_db_requirements)
+{
+    sLog.outErrorDb("  [B] The core needs database Version: %s", core_db_requirements.expected_version.c_str());
+    sLog.outErrorDb("                            Structure: %s", core_db_requirements.expected_structure.c_str());
+    sLog.outErrorDb("                              Content: %s", core_db_requirements.minimal_expected_content.c_str());
+    sLog.outErrorDb("                          Description: %s", core_db_requirements.description.c_str());
+}
+
+bool Database::CheckDatabaseVersion(DatabaseTypes database)
+{
+    const DBVersion& core_db_requirements = databaseVersions[database];
+
+    // Fetch the database version table information
+    QueryResult* result = Query("SELECT `version`, `structure`, `content`, `description` FROM `db_version` ORDER BY `version` DESC, `structure` DESC, `content` DESC LIMIT 1");
+
+    // db_version table does not exist or is empty
+    if (!result)
+    {
+        sLog.outErrorDb("The table `db_version` in your [%s] database is missing or corrupt.", core_db_requirements.dbname.c_str());
+        sLog.outErrorDb();
+        sLog.outErrorDb("  [A] You have database Version: MaNGOS can not verify your database version or its existence!");
+        sLog.outErrorDb();
+        PrintErrorYouNeedDatabaseVersionExpectedByCore(core_db_requirements);
+        sLog.outErrorDb();
+        sLog.outErrorDb("Please verify your database location or your database integrity.");
+
+        // The core loading will no go further :
+        return false;
+    }
+
+    Field* fields = result->Fetch();
+    std::string current_db_version = fields[0].GetCppString();
+    std::string current_db_structure = fields[1].GetCppString();
+    std::string current_db_content = fields[2].GetCppString();
+    std::string description = fields[3].GetCppString();
+
+    delete result;
+
+    // Structure does not match the required version
+    if (current_db_version != core_db_requirements.expected_version || current_db_structure != core_db_requirements.expected_structure)
+    {
+        sLog.outErrorDb("The table `db_version` indicates that your [%s] database does not match the expected structure!", core_db_requirements.dbname.c_str());
+        sLog.outErrorDb();
+        PrintErrorYouHaveDatabaseVersion(current_db_version, current_db_structure, current_db_content, description);
+        sLog.outErrorDb();
+        PrintErrorYouNeedDatabaseVersionExpectedByCore(core_db_requirements);
+        sLog.outErrorDb();
+        sLog.outErrorDb("You must apply all updates after [A] to [B] to use MaNGOS with this database.");
+        sLog.outErrorDb("These updates are included in the database/%s/Updates folder.", core_db_requirements.dbname.c_str());
+        return false;
+    }
+
+    bool db_vs_core_content_version_mismatch = false;
+
+    // DB is not up to date, but structure is correct.
+    // The 'content' version in the 'db_version' table can be < from the one required by the core
+    // See  enum values for :
+    //  WORLD_DB_CONTENT_NR
+    //  CHAR_DB_CONTENT_NR
+    //  REALMD_DB_CONTENT_NR
+    // for more information.
+    if (current_db_content < core_db_requirements.minimal_expected_content)
+    {
+        // TODO : Should not display with error color but warning (e.g YELLOW) => Create a sLog.outWarningDb() and sLog.outWarning()
+        sLog.outErrorDb("You have not updated the core for few DB [%s] updates!", core_db_requirements.dbname.c_str());
+        sLog.outErrorDb("Current DB content is %s, core expects %s", current_db_content.c_str(), core_db_requirements.minimal_expected_content.c_str());
+        sLog.outErrorDb("It is recommended to run ALL database updates up to the required core version.");
+        sLog.outErrorDb("These updates are included in the database/%s/Updates folder.", core_db_requirements.dbname.c_str());
+        sLog.outErrorDb("This is ok for now but should not last long.");
+        db_vs_core_content_version_mismatch = true;
+    }
+
+    // Do not alert if current_db_content > core_db_requirements.minimal_expected_content it can mislead newcomers !
+
+    // In anys cases if there are differences in content : output a recap of the differences :
+    if (db_vs_core_content_version_mismatch)
+    {
+        // TODO : Should not display with error color but warning (e.g YELLOW) => Create a sLog.outWarningDb() and sLog.outWarning()
+        sLog.outErrorDb("The table `db_version` indicates that your [%s] database does not match the expected version!", core_db_requirements.dbname.c_str());
+        sLog.outErrorDb();
+        PrintErrorYouHaveDatabaseVersion(current_db_version, current_db_structure, current_db_content, description);
+        sLog.outErrorDb();
+        PrintErrorYouNeedDatabaseVersionExpectedByCore(core_db_requirements);
+    }
+    else
+    {
+        if (current_db_version == core_db_requirements.expected_version && current_db_structure == core_db_requirements.expected_structure)
+        {
+            sLog.outString("The table `db_version` indicates that your [%s] database has the same version as the core requirements.", core_db_requirements.dbname.c_str());
+            sLog.outString();
+        }
+        else
+        {
+            sLog.outString("The table `db_version` indicates that your [%s] database has a higher version than the one referenced by the core."
+                "\nYou have probably applied DB updates, and that's a good thing to keep your server up to date.", core_db_requirements.dbname.c_str());
+            sLog.outString();
+            PrintNormalYouHaveDatabaseVersion(current_db_version, current_db_structure, current_db_content, description);
+            sLog.outString();
+            PrintNormalDatabaseVersionReferencedByCore(core_db_requirements);
+            sLog.outString();
+            sLog.outString("You can run the core without any problem like that.");
+            sLog.outString();
+        }
+    }
+
+    return true;
+}
+
+bool Database::ExecuteStmt(const SqlStatementID& id, SqlStmtParameters* params)
+{
+    if (!m_pAsyncConn)
+    {
+        return false;
+    }
+
+    SqlTransaction* pTrans = (*m_TransStorage)->get();
+    if (pTrans)
+    {
+        // add SQL request to trans queue
+        pTrans->DelayExecute(new SqlPreparedRequest(id.ID(), params));
+    }
+    else
+    {
+        // if async execution is not available
+        if (!m_bAllowAsyncTransactions)
+        {
+            return DirectExecuteStmt(id, params);
+        }
+
+        // Simple sql statement
+        m_threadBody->Delay(new SqlPreparedRequest(id.ID(), params));
+    }
+
+    return true;
+}
+
+bool Database::DirectExecuteStmt(const SqlStatementID& id, SqlStmtParameters* params)
+{
+    MANGOS_ASSERT(params);
+    std::shared_ptr<SqlStmtParameters> p(params);
+    // execute statement
+    SqlConnection::Lock _guard(getAsyncConnection());
+    return _guard->ExecuteStmt(id.ID(), *params);
+}
+
+SqlStatement Database::CreateStatement(SqlStatementID& index, const char* fmt)
+{
+    int nId = -1;
+    // check if statement ID is initialized
+    if (!index.initialized())
+    {
+        // convert to lower register
+        std::string szFmt(fmt);
+        // count input parameters
+        int nParams = std::count(szFmt.begin(), szFmt.end(), '?');
+        // find existing or add a new record in registry
+        LOCK_GUARD _guard(m_stmtGuard);
+        MANGOS_ASSERT(_guard.locked());
+        PreparedStmtRegistry::const_iterator iter = m_stmtRegistry.find(szFmt);
+        if (iter == m_stmtRegistry.end())
+        {
+            nId = ++m_iStmtIndex;
+            m_stmtRegistry[szFmt] = nId;
+        }
+        else
+        {
+            nId = iter->second;
+        }
+
+        // save initialized statement index info
+        index.init(nId, nParams);
+    }
+
+    return SqlStatement(index, *this);
+}
+
+std::string Database::GetStmtString(const int stmtId) const
+{
+    if (stmtId == -1 || stmtId > m_iStmtIndex)
+    {
+        return std::string();
+    }
+
+    LOCK_GUARD _guard(m_stmtGuard);
+    if (_guard.locked())
+    {
+        PreparedStmtRegistry::const_iterator iter_last = m_stmtRegistry.end();
+        for (PreparedStmtRegistry::const_iterator iter = m_stmtRegistry.begin(); iter != iter_last; ++iter)
+        {
+            if (iter->second == stmtId)
+            {
+                return iter->first;
+            }
+        }
+    }
+    return std::string();
+}
+
+// HELPER CLASSES AND FUNCTIONS
+Database::TransHelper::~TransHelper()
+{
+    reset();
+}
+
+SqlTransaction* Database::TransHelper::init()
+{
+    MANGOS_ASSERT(!m_pTrans);   // if we will get a nested transaction request - we MUST fix code!!!
+    m_pTrans = new SqlTransaction;
+    return m_pTrans;
+}
+
+SqlTransaction* Database::TransHelper::detach()
+{
+    SqlTransaction* pRes = m_pTrans;
+    m_pTrans = NULL;
+    return pRes;
+}
+
+void Database::TransHelper::reset()
+{
+    delete m_pTrans;
+    m_pTrans = NULL;
+}
diff --git a/shared/Database/Database.h b/shared/Database/Database.h
new file mode 100644
index 0000000..bd2c46b
--- /dev/null
+++ b/shared/Database/Database.h
@@ -0,0 +1,826 @@
+/**
+ * MaNGOS is a full featured server for World of Warcraft, supporting
+ * the following clients: 1.12.x, 2.4.3, 3.3.5a, 4.3.4a and 5.4.8
+ *
+ * Copyright (C) 2005-2022 MaNGOS <https://getmangos.eu>
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * World of Warcraft, and all World of Warcraft or Warcraft art, images,
+ * and lore are copyrighted by Blizzard Entertainment, Inc.
+ */
+
+#ifndef DATABASE_H
+#define DATABASE_H
+
+#include "Threading/Threading.h"
+#include "Utilities/UnorderedMapSet.h"
+#include "Database/SqlDelayThread.h"
+#include <ace/Recursive_Thread_Mutex.h>
+#include "Policies/ThreadingModel.h"
+#include <ace/TSS_T.h>
+#include <ace/Atomic_Op.h>
+#include "SqlPreparedStatement.h"
+
+class SqlTransaction;
+class SqlResultQueue;
+class SqlQueryHolder;
+class SqlStmtParameters;
+class SqlParamBinder;
+class Database;
+
+#define MAX_QUERY_LEN   (32*1024)
+
+enum DatabaseTypes
+{
+    DATABASE_WORLD,
+    DATABASE_REALMD,
+    DATABASE_CHARACTER,
+    COUNT_DATABASES,
+};
+
+/**
+ * @brief
+ *
+ */
+class SqlConnection
+{
+    public:
+        /**
+         * @brief
+         *
+         */
+        virtual ~SqlConnection() {}
+
+        /**
+         * @brief method for initializing DB connection
+         *
+         * @param infoString
+         * @return bool
+         */
+        virtual bool Initialize(const char* infoString) = 0;
+        /**
+         * @brief public methods for making queries
+         *
+         * @param sql
+         * @return QueryResult
+         */
+        virtual QueryResult* Query(const char* sql) = 0;
+        /**
+         * @brief
+         *
+         * @param sql
+         * @return QueryNamedResult
+         */
+        virtual QueryNamedResult* QueryNamed(const char* sql) = 0;
+
+        /**
+         * @brief public methods for making requests
+         *
+         * @param sql
+         * @return bool
+         */
+        virtual bool Execute(const char* sql) = 0;
+
+        /**
+         * @brief escape string generation
+         *
+         * @param to
+         * @param from
+         * @param length
+         * @return unsigned long
+         */
+        virtual unsigned long escape_string(char* to, const char* from, unsigned long length) { strncpy(to, from, length); return length; }
+
+        /**
+         * @brief nothing do if DB not support transactions
+         *
+         * @return bool
+         */
+        virtual bool BeginTransaction() { return true; }
+        /**
+         * @brief
+         *
+         * @return bool
+         */
+        virtual bool CommitTransaction() { return true; }
+        /**
+         * @brief can't rollback without transaction support
+         *
+         * @return bool
+         */
+        virtual bool RollbackTransaction() { return true; }
+
+        /**
+         * @brief methods to work with prepared statements
+         *
+         * @param nIndex
+         * @param id
+         * @return bool
+         */
+        bool ExecuteStmt(int nIndex, const SqlStmtParameters& id);
+
+        /**
+         * @brief SqlConnection object lock
+         *
+         */
+        class Lock
+        {
+            public:
+                /**
+                 * @brief
+                 *
+                 * @param conn
+                 */
+                Lock(SqlConnection* conn) : m_pConn(conn) { m_pConn->m_mutex.acquire(); }
+                /**
+                 * @brief
+                 *
+                 */
+                ~Lock() { m_pConn->m_mutex.release(); }
+
+                /**
+                 * @brief
+                 *
+                 * @return SqlConnection *operator ->
+                 */
+                SqlConnection* operator->() const { return m_pConn; }
+
+            private:
+                SqlConnection* const m_pConn; /**< TODO */
+        };
+
+        /**
+         * @brief get DB object
+         *
+         * @return Database
+         */
+        Database& DB() { return m_db; }
+
+    protected:
+        /**
+         * @brief
+         *
+         * @param db
+         */
+        SqlConnection(Database& db) : m_db(db) {}
+
+        /**
+         * @brief
+         *
+         * @param fmt
+         * @return SqlPreparedStatement
+         */
+        virtual SqlPreparedStatement* CreateStatement(const std::string& fmt);
+        /**
+         * @brief allocate prepared statement and return statement ID
+         *
+         * @param nIndex
+         * @return SqlPreparedStatement
+         */
+        SqlPreparedStatement* GetStmt(uint32 nIndex);
+
+        Database& m_db; /**< TODO */
+
+        /**
+         * @brief free prepared statements objects
+         *
+         */
+        void FreePreparedStatements();
+
+    private:
+        /**
+         * @brief
+         *
+         */
+        typedef ACE_Recursive_Thread_Mutex LOCK_TYPE;
+        LOCK_TYPE m_mutex; /**< TODO */
+
+        /**
+         * @brief
+         *
+         */
+        typedef std::vector<SqlPreparedStatement* > StmtHolder;
+        StmtHolder m_holder; /**< TODO */
+};
+
+/**
+ * @brief
+ *
+ */
+class Database
+{
+    public:
+        /**
+         * @brief
+         *
+         */
+        virtual ~Database();
+
+        /**
+         * @brief
+         *
+         * @param infoString
+         * @param nConns
+         * @return bool
+         */
+        virtual bool Initialize(const char* infoString, int nConns = 1);
+        /**
+         * @brief start worker thread for async DB request execution
+         *
+         */
+        virtual void InitDelayThread();
+        /**
+         * @brief stop worker thread
+         *
+         */
+        virtual void HaltDelayThread();
+
+        /**
+         * @brief Synchronous DB queries
+         *
+         * @param sql
+         * @return QueryResult
+         */
+        inline QueryResult* Query(const char* sql)
+        {
+            SqlConnection::Lock guard(getQueryConnection());
+            return guard->Query(sql);
+        }
+
+        /**
+         * @brief
+         *
+         * @param sql
+         * @return QueryNamedResult
+         */
+        inline QueryNamedResult* QueryNamed(const char* sql)
+        {
+            SqlConnection::Lock guard(getQueryConnection());
+            return guard->QueryNamed(sql);
+        }
+
+        /**
+         * @brief
+         *
+         * @param format...
+         * @return QueryResult
+         */
+        QueryResult* PQuery(const char* format, ...) ATTR_PRINTF(2, 3);
+        /**
+         * @brief
+         *
+         * @param format...
+         * @return QueryNamedResult
+         */
+        QueryNamedResult* PQueryNamed(const char* format, ...) ATTR_PRINTF(2, 3);
+
+        /**
+         * @brief
+         *
+         * @param sql
+         * @return bool
+         */
+        inline bool DirectExecute(const char* sql)
+        {
+            if (!m_pAsyncConn)
+            {
+                return false;
+            }
+
+            SqlConnection::Lock guard(m_pAsyncConn);
+            return guard->Execute(sql);
+        }
+
+        /**
+         * @brief
+         *
+         * @param format...
+         * @return bool
+         */
+        bool DirectPExecute(const char* format, ...) ATTR_PRINTF(2, 3);
+
+        /// Async queries and query holders, implemented in DatabaseImpl.h
+
+        // Query / member
+        template<class Class>
+        /**
+         * @brief
+         *
+         * @param object
+         * @param )
+         * @param sql
+         * @return bool
+         */
+        bool AsyncQuery(Class* object, void (Class::*method)(QueryResult*), const char* sql);
+        template<class Class, typename ParamType1>
+        /**
+         * @brief
+         *
+         * @param object
+         * @param
+         * @param ParamType1)
+         * @param param1
+         * @param sql
+         * @return bool
+         */
+        bool AsyncQuery(Class* object, void (Class::*method)(QueryResult*, ParamType1), ParamType1 param1, const char* sql);
+        template<class Class, typename ParamType1, typename ParamType2>
+        /**
+         * @brief
+         *
+         * @param object
+         * @param
+         * @param ParamType1
+         * @param ParamType2)
+         * @param param1
+         * @param param2
+         * @param sql
+         * @return bool
+         */
+        bool AsyncQuery(Class* object, void (Class::*method)(QueryResult*, ParamType1, ParamType2), ParamType1 param1, ParamType2 param2, const char* sql);
+        template<class Class, typename ParamType1, typename ParamType2, typename ParamType3>
+        /**
+         * @brief
+         *
+         * @param object
+         * @param
+         * @param ParamType1
+         * @param ParamType2
+         * @param ParamType3)
+         * @param param1
+         * @param param2
+         * @param param3
+         * @param sql
+         * @return bool
+         */
+        bool AsyncQuery(Class* object, void (Class::*method)(QueryResult*, ParamType1, ParamType2, ParamType3), ParamType1 param1, ParamType2 param2, ParamType3 param3, const char* sql);
+        // Query / static
+        template<typename ParamType1>
+        /**
+         * @brief
+         *
+         * @param
+         * @param ParamType1)
+         * @param param1
+         * @param sql
+         * @return bool
+         */
+        bool AsyncQuery(void (*method)(QueryResult*, ParamType1), ParamType1 param1, const char* sql);
+        template<typename ParamType1, typename ParamType2>
+        /**
+         * @brief
+         *
+         * @param
+         * @param ParamType1
+         * @param ParamType2)
+         * @param param1
+         * @param param2
+         * @param sql
+         * @return bool
+         */
+        bool AsyncQuery(void (*method)(QueryResult*, ParamType1, ParamType2), ParamType1 param1, ParamType2 param2, const char* sql);
+        template<typename ParamType1, typename ParamType2, typename ParamType3>
+        /**
+         * @brief
+         *
+         * @param
+         * @param ParamType1
+         * @param ParamType2
+         * @param ParamType3)
+         * @param param1
+         * @param param2
+         * @param param3
+         * @param sql
+         * @return bool
+         */
+        bool AsyncQuery(void (*method)(QueryResult*, ParamType1, ParamType2, ParamType3), ParamType1 param1, ParamType2 param2, ParamType3 param3, const char* sql);
+        // PQuery / member
+        template<class Class>
+        /**
+         * @brief
+         *
+         * @param object
+         * @param )
+         * @param format...
+         * @return bool
+         */
+        bool AsyncPQuery(Class* object, void (Class::*method)(QueryResult*), const char* format, ...) ATTR_PRINTF(4, 5);
+        template<class Class, typename ParamType1>
+        /**
+         * @brief
+         *
+         * @param object
+         * @param
+         * @param ParamType1)
+         * @param param1
+         * @param format...
+         * @return bool
+         */
+        bool AsyncPQuery(Class* object, void (Class::*method)(QueryResult*, ParamType1), ParamType1 param1, const char* format, ...) ATTR_PRINTF(5, 6);
+        template<class Class, typename ParamType1, typename ParamType2>
+        /**
+         * @brief
+         *
+         * @param object
+         * @param
+         * @param ParamType1
+         * @param ParamType2)
+         * @param param1
+         * @param param2
+         * @param format...
+         * @return bool
+         */
+        bool AsyncPQuery(Class* object, void (Class::*method)(QueryResult*, ParamType1, ParamType2), ParamType1 param1, ParamType2 param2, const char* format, ...) ATTR_PRINTF(6, 7);
+        template<class Class, typename ParamType1, typename ParamType2, typename ParamType3>
+        /**
+         * @brief
+         *
+         * @param object
+         * @param
+         * @param ParamType1
+         * @param ParamType2
+         * @param ParamType3)
+         * @param param1
+         * @param param2
+         * @param param3
+         * @param format...
+         * @return bool
+         */
+        bool AsyncPQuery(Class* object, void (Class::*method)(QueryResult*, ParamType1, ParamType2, ParamType3), ParamType1 param1, ParamType2 param2, ParamType3 param3, const char* format, ...) ATTR_PRINTF(7, 8);
+        // PQuery / static
+        template<typename ParamType1>
+        /**
+         * @brief
+         *
+         * @param
+         * @param ParamType1)
+         * @param param1
+         * @param format...
+         * @return bool
+         */
+        bool AsyncPQuery(void (*method)(QueryResult*, ParamType1), ParamType1 param1, const char* format, ...) ATTR_PRINTF(4, 5);
+        template<typename ParamType1, typename ParamType2>
+        /**
+         * @brief
+         *
+         * @param
+         * @param ParamType1
+         * @param ParamType2)
+         * @param param1
+         * @param param2
+         * @param format...
+         * @return bool
+         */
+        bool AsyncPQuery(void (*method)(QueryResult*, ParamType1, ParamType2), ParamType1 param1, ParamType2 param2, const char* format, ...) ATTR_PRINTF(5, 6);
+        template<typename ParamType1, typename ParamType2, typename ParamType3>
+        /**
+         * @brief
+         *
+         * @param
+         * @param ParamType1
+         * @param ParamType2
+         * @param ParamType3)
+         * @param param1
+         * @param param2
+         * @param param3
+         * @param format...
+         * @return bool
+         */
+        bool AsyncPQuery(void (*method)(QueryResult*, ParamType1, ParamType2, ParamType3), ParamType1 param1, ParamType2 param2, ParamType3 param3, const char* format, ...) ATTR_PRINTF(6, 7);
+        template<class Class>
+        // QueryHolder
+        /**
+         * @brief
+         *
+         * @param object
+         * @param
+         * @param )
+         * @param holder
+         * @return bool
+         */
+        bool DelayQueryHolder(Class* object, void (Class::*method)(QueryResult*, SqlQueryHolder*), SqlQueryHolder* holder);
+        template<class Class, typename ParamType1>
+        /**
+         * @brief
+         *
+         * @param object
+         * @param
+         * @param
+         * @param ParamType1)
+         * @param holder
+         * @param param1
+         * @return bool
+         */
+        bool DelayQueryHolder(Class* object, void (Class::*method)(QueryResult*, SqlQueryHolder*, ParamType1), SqlQueryHolder* holder, ParamType1 param1);
+
+        /**
+         * @brief
+         *
+         * @param sql
+         * @return bool
+         */
+        bool Execute(const char* sql);
+        /**
+         * @brief
+         *
+         * @param format...
+         * @return bool
+         */
+        bool PExecute(const char* format, ...) ATTR_PRINTF(2, 3);
+
+        /**
+         * @brief Writes SQL commands to a LOG file (see mangosd.conf "LogSQL")
+         *
+         * @param format...
+         * @return bool
+         */
+        bool PExecuteLog(const char* format, ...) ATTR_PRINTF(2, 3);
+
+        /**
+         * @brief
+         *
+         * @return bool
+         */
+        bool BeginTransaction();
+        /**
+         * @brief
+         *
+         * @return bool
+         */
+        bool CommitTransaction();
+        /**
+         * @brief
+         *
+         * @return bool
+         */
+        bool RollbackTransaction();
+        /**
+         * @brief for sync transaction execution
+         *
+         * @return bool
+         */
+        bool CommitTransactionDirect();
+
+        // PREPARED STATEMENT API
+        /**
+         * @brief allocate index for prepared statement with SQL request 'fmt'
+         *
+         * @param index
+         * @param fmt
+         * @return SqlStatement
+         */
+        SqlStatement CreateStatement(SqlStatementID& index, const char* fmt);
+        /**
+         * @brief get prepared statement format string
+         *
+         * @param stmtId
+         * @return std::string
+         */
+        std::string GetStmtString(const int stmtId) const;
+
+        /**
+         * @brief
+         *
+         * @return operator
+         */
+        operator bool () const { return m_pQueryConnections.size() && m_pAsyncConn != 0; }
+
+        /**
+         * @brief escape string generation
+         *
+         * @param str
+         */
+        void escape_string(std::string& str);
+
+        /**
+         * @brief must be called before first query in thread (one time for thread using one from existing Database objects)
+         *
+         */
+        virtual void ThreadStart();
+        /**
+         * @brief must be called before finish thread run (one time for thread using one from existing Database objects)
+         *
+         */
+        virtual void ThreadEnd();
+
+        /**
+         * @brief set database-wide result queue. also we should use object-bases and not thread-based result queues
+         *
+         */
+        void ProcessResultQueue();
+
+        /**
+        * @brief Function to check that the database version matches expected core version
+        *
+        * @param DatabaseTypes
+        * @return bool
+        */
+        bool CheckDatabaseVersion(DatabaseTypes database);
+        /**
+         * @brief
+         *
+         * @return uint32
+         */
+        uint32 GetPingIntervall() { return m_pingIntervallms; }
+
+        /**
+         * @brief function to ping database connections
+         *
+         */
+        void Ping();
+
+        /**
+         * @brief set this to allow async transactions
+         *
+         * you should call it explicitly after your server successfully started
+         * up.
+         * NO ASYNC TRANSACTIONS DURING SERVER STARTUP - ONLY DURING RUNTIME!!!
+         *
+         */
+        void AllowAsyncTransactions() { m_bAllowAsyncTransactions = true; }
+
+    protected:
+        /**
+         * @brief
+         *
+         */
+        Database() :
+            m_TransStorage(NULL),m_nQueryConnPoolSize(1), m_pAsyncConn(NULL), m_pResultQueue(NULL),
+            m_threadBody(NULL), m_delayThread(NULL), m_bAllowAsyncTransactions(false),
+            m_iStmtIndex(-1), m_logSQL(false), m_pingIntervallms(0)
+        {
+            m_nQueryCounter = -1;
+        }
+
+        /**
+         * @brief
+         *
+         */
+        void StopServer();
+
+        /**
+         * @brief factory method to create SqlConnection objects
+         *
+         * @return SqlConnection
+         */
+        virtual SqlConnection* CreateConnection() = 0;
+        /**
+         * @brief factory method to create SqlDelayThread objects
+         *
+         * @return SqlDelayThread
+         */
+        virtual SqlDelayThread* CreateDelayThread();
+
+        /**
+         * @brief
+         *
+         */
+        class TransHelper
+        {
+            public:
+                /**
+                 * @brief
+                 *
+                 */
+                TransHelper() : m_pTrans(NULL) {}
+                /**
+                 * @brief
+                 *
+                 */
+                ~TransHelper();
+
+                /**
+                 * @brief initializes new SqlTransaction object
+                 *
+                 * @return SqlTransaction
+                 */
+                SqlTransaction* init();
+                /**
+                 * @brief gets pointer on current transaction object. Returns NULL if transaction was not initiated
+                 *
+                 * @return SqlTransaction
+                 */
+                SqlTransaction* get() const { return m_pTrans; }
+
+                /**
+                 * @brief detaches SqlTransaction object allocated by init() function
+                 *
+                 * next call to get() function will return NULL!
+                 * do not forget to destroy obtained SqlTransaction object!
+                 *
+                 * @return SqlTransaction
+                 */
+                SqlTransaction* detach();
+                /**
+                 * @brief destroyes SqlTransaction allocated by init() function
+                 *
+                 */
+                void reset();
+
+            private:
+                SqlTransaction* m_pTrans; /**< TODO */
+        };
+
+        /**
+         * @brief per-thread based storage for SqlTransaction object initialization - no locking is required
+         *
+         */
+        typedef ACE_TSS<Database::TransHelper> DBTransHelperTSS;
+        Database::DBTransHelperTSS *m_TransStorage; /**< TODO */
+
+        ///< DB connections
+        /**
+         * @brief round-robin connection selection
+         *
+         * @return SqlConnection
+         */
+        SqlConnection* getQueryConnection();
+        /**
+         * @brief for now return one single connection for async requests
+         *
+         * @return SqlConnection
+         */
+        SqlConnection* getAsyncConnection() const { return m_pAsyncConn; }
+
+        friend class SqlStatement;
+        // PREPARED STATEMENT API
+        /**
+         * @brief query function for prepared statements
+         *
+         * @param id
+         * @param params
+         * @return bool
+         */
+        bool ExecuteStmt(const SqlStatementID& id, SqlStmtParameters* params);
+        /**
+         * @brief
+         *
+         * @param id
+         * @param params
+         * @return bool
+         */
+        bool DirectExecuteStmt(const SqlStatementID& id, SqlStmtParameters* params);
+
+        // connection helper counters
+        int m_nQueryConnPoolSize;                               /**< current size of query connection pool */
+        ACE_Atomic_Op<ACE_Thread_Mutex, long> m_nQueryCounter;  /**< counter for connection selection */
+
+        /**
+         * @brief lets use pool of connections for sync queries
+         *
+         */
+        typedef std::vector< SqlConnection* > SqlConnectionContainer;
+        SqlConnectionContainer m_pQueryConnections; /**< TODO */
+
+        // only one single DB connection for transactions
+        SqlConnection* m_pAsyncConn; /**< TODO */
+
+        SqlResultQueue*     m_pResultQueue;                 /**< Transaction queues from diff. threads */
+        SqlDelayThread*     m_threadBody;                   /**< Pointer to delay sql executer (owned by m_delayThread) */
+        ACE_Based::Thread*  m_delayThread;                  /**< Pointer to executer thread */
+
+        bool m_bAllowAsyncTransactions;                     /**< flag which specifies if async transactions are enabled */
+
+        // PREPARED STATEMENT REGISTRY
+        /**
+         * @brief
+         *
+         */
+        typedef ACE_Thread_Mutex LOCK_TYPE;
+        /**
+         * @brief
+         *
+         */
+        typedef ACE_Guard<LOCK_TYPE> LOCK_GUARD;
+
+        mutable LOCK_TYPE m_stmtGuard; /**< TODO */
+
+        /**
+         * @brief
+         *
+         */
+        typedef UNORDERED_MAP<std::string, int> PreparedStmtRegistry;
+        PreparedStmtRegistry m_stmtRegistry;                ///< /**< TODO */
+
+        int m_iStmtIndex; /**< TODO */
+
+    private:
+
+        bool m_logSQL; /**< TODO */
+        std::string m_logsDir; /**< TODO */
+        uint32 m_pingIntervallms; /**< TODO */
+};
+#endif
diff --git a/shared/Database/DatabaseEnv.h b/shared/Database/DatabaseEnv.h
new file mode 100644
index 0000000..952559a
--- /dev/null
+++ b/shared/Database/DatabaseEnv.h
@@ -0,0 +1,51 @@
+/**
+ * MaNGOS is a full featured server for World of Warcraft, supporting
+ * the following clients: 1.12.x, 2.4.3, 3.3.5a, 4.3.4a and 5.4.8
+ *
+ * Copyright (C) 2005-2022 MaNGOS <https://getmangos.eu>
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * World of Warcraft, and all World of Warcraft or Warcraft art, images,
+ * and lore are copyrighted by Blizzard Entertainment, Inc.
+ */
+
+#if !defined(DATABASEENV_H)
+#define DATABASEENV_H
+
+#include "Common/Common.h"
+#include "Log/Log.h"
+#include "Utilities/Errors.h"
+
+#include "Database/Field.h"
+#include "Database/QueryResult.h"
+
+#include "Database/QueryResultMysql.h"
+#include "Database/Database.h"
+#include "Database/DatabaseMysql.h"
+/**
+ * @brief
+ *
+ */
+typedef DatabaseMysql DatabaseType;
+#define _LIKE_           "LIKE"
+#define _CONCAT3_(A,B,C) "CONCAT( " A " , " B " , " C " )"
+#define _OFFSET_         "LIMIT %d,1"
+
+extern DatabaseType WorldDatabase; /**< TODO */
+extern DatabaseType CharacterDatabase; /**< TODO */
+extern DatabaseType LoginDatabase; /**< TODO */
+
+#endif
diff --git a/shared/Database/DatabaseImpl.h b/shared/Database/DatabaseImpl.h
new file mode 100644
index 0000000..28fbb54
--- /dev/null
+++ b/shared/Database/DatabaseImpl.h
@@ -0,0 +1,366 @@
+/**
+ * MaNGOS is a full featured server for World of Warcraft, supporting
+ * the following clients: 1.12.x, 2.4.3, 3.3.5a, 4.3.4a and 5.4.8
+ *
+ * Copyright (C) 2005-2022 MaNGOS <https://getmangos.eu>
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * World of Warcraft, and all World of Warcraft or Warcraft art, images,
+ * and lore are copyrighted by Blizzard Entertainment, Inc.
+ */
+
+#if !defined(DATABASEIMPL_H)
+#define DATABASEIMPL_H
+#include "Database/Database.h"
+#include "Database/SqlOperations.h"
+
+/// Function body definitions for the template function members of the Database class
+
+#define ASYNC_QUERY_BODY(sql) if (!sql || !m_pResultQueue) return false;
+#define ASYNC_DELAYHOLDER_BODY(holder) if (!holder || !m_pResultQueue) return false;
+
+#define ASYNC_PQUERY_BODY(format, szQuery) \
+    if(!format) return false; \
+    \
+    char szQuery [MAX_QUERY_LEN]; \
+    \
+    { \
+        va_list ap; \
+        \
+        va_start(ap, format); \
+        int res = vsnprintf( szQuery, MAX_QUERY_LEN, format, ap ); \
+        va_end(ap); \
+        \
+        if(res==-1) \
+        { \
+            sLog.outError("SQL Query truncated (and not execute) for format: %s",format); \
+            return false; \
+        } \
+    }
+
+// -- Query / member --
+
+template<class Class>
+bool
+/**
+ * @brief
+ *
+ * @param object
+ * @param )
+ * @param sql
+ * @return bool
+ */
+Database::AsyncQuery(Class* object, void (Class::*method)(QueryResult*), const char* sql)
+{
+    ASYNC_QUERY_BODY(sql)
+    return m_threadBody->Delay(new SqlQuery(sql, new MaNGOS::QueryCallback<Class>(object, method), m_pResultQueue));
+}
+
+template<class Class, typename ParamType1>
+bool
+/**
+ * @brief
+ *
+ * @param object
+ * @param
+ * @param ParamType1)
+ * @param param1
+ * @param sql
+ * @return bool
+ */
+Database::AsyncQuery(Class* object, void (Class::*method)(QueryResult*, ParamType1), ParamType1 param1, const char* sql)
+{
+    ASYNC_QUERY_BODY(sql)
+    return m_threadBody->Delay(new SqlQuery(sql, new MaNGOS::QueryCallback<Class, ParamType1>(object, method, (QueryResult*)NULL, param1), m_pResultQueue));
+}
+
+template<class Class, typename ParamType1, typename ParamType2>
+bool
+/**
+ * @brief
+ *
+ * @param object
+ * @param
+ * @param ParamType1
+ * @param ParamType2)
+ * @param param1
+ * @param param2
+ * @param sql
+ * @return bool
+ */
+Database::AsyncQuery(Class* object, void (Class::*method)(QueryResult*, ParamType1, ParamType2), ParamType1 param1, ParamType2 param2, const char* sql)
+{
+    ASYNC_QUERY_BODY(sql)
+    return m_threadBody->Delay(new SqlQuery(sql, new MaNGOS::QueryCallback<Class, ParamType1, ParamType2>(object, method, (QueryResult*)NULL, param1, param2), m_pResultQueue));
+}
+
+template<class Class, typename ParamType1, typename ParamType2, typename ParamType3>
+bool
+/**
+ * @brief
+ *
+ * @param object
+ * @param
+ * @param ParamType1
+ * @param ParamType2
+ * @param ParamType3)
+ * @param param1
+ * @param param2
+ * @param param3
+ * @param sql
+ * @return bool
+ */
+Database::AsyncQuery(Class* object, void (Class::*method)(QueryResult*, ParamType1, ParamType2, ParamType3), ParamType1 param1, ParamType2 param2, ParamType3 param3, const char* sql)
+{
+    ASYNC_QUERY_BODY(sql)
+    return m_threadBody->Delay(new SqlQuery(sql, new MaNGOS::QueryCallback<Class, ParamType1, ParamType2, ParamType3>(object, method, (QueryResult*)NULL, param1, param2, param3), m_pResultQueue));
+}
+
+// -- Query / static --
+template<typename ParamType1>
+bool
+/**
+ * @brief
+ *
+ * @param
+ * @param ParamType1)
+ * @param param1
+ * @param sql
+ * @return bool
+ */
+Database::AsyncQuery(void (*method)(QueryResult*, ParamType1), ParamType1 param1, const char* sql)
+{
+    ASYNC_QUERY_BODY(sql)
+    return m_threadBody->Delay(new SqlQuery(sql, new MaNGOS::SQueryCallback<ParamType1>(method, (QueryResult*)NULL, param1), m_pResultQueue));
+}
+
+template<typename ParamType1, typename ParamType2>
+bool
+/**
+ * @brief
+ *
+ * @param
+ * @param ParamType1
+ * @param ParamType2)
+ * @param param1
+ * @param param2
+ * @param sql
+ * @return bool
+ */
+Database::AsyncQuery(void (*method)(QueryResult*, ParamType1, ParamType2), ParamType1 param1, ParamType2 param2, const char* sql)
+{
+    ASYNC_QUERY_BODY(sql)
+    return m_threadBody->Delay(new SqlQuery(sql, new MaNGOS::SQueryCallback<ParamType1, ParamType2>(method, (QueryResult*)NULL, param1, param2), m_pResultQueue));
+}
+
+template<typename ParamType1, typename ParamType2, typename ParamType3>
+bool
+/**
+ * @brief
+ *
+ * @param
+ * @param ParamType1
+ * @param ParamType2
+ * @param ParamType3)
+ * @param param1
+ * @param param2
+ * @param param3
+ * @param sql
+ * @return bool
+ */
+Database::AsyncQuery(void (*method)(QueryResult*, ParamType1, ParamType2, ParamType3), ParamType1 param1, ParamType2 param2, ParamType3 param3, const char* sql)
+{
+    ASYNC_QUERY_BODY(sql)
+    return m_threadBody->Delay(new SqlQuery(sql, new MaNGOS::SQueryCallback<ParamType1, ParamType2, ParamType3>(method, (QueryResult*)NULL, param1, param2, param3), m_pResultQueue));
+}
+
+// -- PQuery / member --
+template<class Class>
+bool
+/**
+ * @brief
+ *
+ * @param object
+ * @param )
+ * @param format...
+ * @return bool
+ */
+Database::AsyncPQuery(Class* object, void (Class::*method)(QueryResult*), const char* format, ...)
+{
+    ASYNC_PQUERY_BODY(format, szQuery)
+    return AsyncQuery(object, method, szQuery);
+}
+
+template<class Class, typename ParamType1>
+bool
+/**
+ * @brief
+ *
+ * @param object
+ * @param
+ * @param ParamType1)
+ * @param param1
+ * @param format...
+ * @return bool
+ */
+Database::AsyncPQuery(Class* object, void (Class::*method)(QueryResult*, ParamType1), ParamType1 param1, const char* format, ...)
+{
+    ASYNC_PQUERY_BODY(format, szQuery)
+    return AsyncQuery(object, method, param1, szQuery);
+}
+
+template<class Class, typename ParamType1, typename ParamType2>
+bool
+/**
+ * @brief
+ *
+ * @param object
+ * @param
+ * @param ParamType1
+ * @param ParamType2)
+ * @param param1
+ * @param param2
+ * @param format...
+ * @return bool
+ */
+Database::AsyncPQuery(Class* object, void (Class::*method)(QueryResult*, ParamType1, ParamType2), ParamType1 param1, ParamType2 param2, const char* format, ...)
+{
+    ASYNC_PQUERY_BODY(format, szQuery)
+    return AsyncQuery(object, method, param1, param2, szQuery);
+}
+
+template<class Class, typename ParamType1, typename ParamType2, typename ParamType3>
+bool
+/**
+ * @brief
+ *
+ * @param object
+ * @param
+ * @param ParamType1
+ * @param ParamType2
+ * @param ParamType3)
+ * @param param1
+ * @param param2
+ * @param param3
+ * @param format...
+ * @return bool
+ */
+Database::AsyncPQuery(Class* object, void (Class::*method)(QueryResult*, ParamType1, ParamType2, ParamType3), ParamType1 param1, ParamType2 param2, ParamType3 param3, const char* format, ...)
+{
+    ASYNC_PQUERY_BODY(format, szQuery)
+    return AsyncQuery(object, method, param1, param2, param3, szQuery);
+}
+
+// -- PQuery / static --
+template<typename ParamType1>
+bool
+/**
+ * @brief
+ *
+ * @param
+ * @param ParamType1)
+ * @param param1
+ * @param format...
+ * @return bool
+ */
+Database::AsyncPQuery(void (*method)(QueryResult*, ParamType1), ParamType1 param1, const char* format, ...)
+{
+    ASYNC_PQUERY_BODY(format, szQuery)
+    return AsyncQuery(method, param1, szQuery);
+}
+
+template<typename ParamType1, typename ParamType2>
+bool
+/**
+ * @brief
+ *
+ * @param
+ * @param ParamType1
+ * @param ParamType2)
+ * @param param1
+ * @param param2
+ * @param format...
+ * @return bool
+ */
+Database::AsyncPQuery(void (*method)(QueryResult*, ParamType1, ParamType2), ParamType1 param1, ParamType2 param2, const char* format, ...)
+{
+    ASYNC_PQUERY_BODY(format, szQuery)
+    return AsyncQuery(method, param1, param2, szQuery);
+}
+
+template<typename ParamType1, typename ParamType2, typename ParamType3>
+bool
+/**
+ * @brief
+ *
+ * @param
+ * @param ParamType1
+ * @param ParamType2
+ * @param ParamType3)
+ * @param param1
+ * @param param2
+ * @param param3
+ * @param format...
+ * @return bool
+ */
+Database::AsyncPQuery(void (*method)(QueryResult*, ParamType1, ParamType2, ParamType3), ParamType1 param1, ParamType2 param2, ParamType3 param3, const char* format, ...)
+{
+    ASYNC_PQUERY_BODY(format, szQuery)
+    return AsyncQuery(method, param1, param2, param3, szQuery);
+}
+
+// -- QueryHolder --
+template<class Class>
+bool
+/**
+ * @brief
+ *
+ * @param object
+ * @param
+ * @param )
+ * @param holder
+ * @return bool
+ */
+Database::DelayQueryHolder(Class* object, void (Class::*method)(QueryResult*, SqlQueryHolder*), SqlQueryHolder* holder)
+{
+    ASYNC_DELAYHOLDER_BODY(holder)
+    return holder->Execute(new MaNGOS::QueryCallback<Class, SqlQueryHolder*>(object, method, (QueryResult*)NULL, holder), m_threadBody, m_pResultQueue);
+}
+
+template<class Class, typename ParamType1>
+bool
+/**
+ * @brief
+ *
+ * @param object
+ * @param
+ * @param
+ * @param ParamType1)
+ * @param holder
+ * @param param1
+ * @return bool
+ */
+Database::DelayQueryHolder(Class* object, void (Class::*method)(QueryResult*, SqlQueryHolder*, ParamType1), SqlQueryHolder* holder, ParamType1 param1)
+{
+    ASYNC_DELAYHOLDER_BODY(holder)
+    return holder->Execute(new MaNGOS::QueryCallback<Class, SqlQueryHolder*, ParamType1>(object, method, (QueryResult*)NULL, holder, param1), m_threadBody, m_pResultQueue);
+}
+
+#undef ASYNC_QUERY_BODY
+#undef ASYNC_PQUERY_BODY
+#undef ASYNC_DELAYHOLDER_BODY
+
+#endif
\ No newline at end of file
diff --git a/shared/Database/DatabaseMysql.cpp b/shared/Database/DatabaseMysql.cpp
new file mode 100644
index 0000000..40cb50e
--- /dev/null
+++ b/shared/Database/DatabaseMysql.cpp
@@ -0,0 +1,548 @@
+/**
+ * MaNGOS is a full featured server for World of Warcraft, supporting
+ * the following clients: 1.12.x, 2.4.3, 3.3.5a, 4.3.4a and 5.4.8
+ *
+ * Copyright (C) 2005-2022 MaNGOS <https://getmangos.eu>
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * World of Warcraft, and all World of Warcraft or Warcraft art, images,
+ * and lore are copyrighted by Blizzard Entertainment, Inc.
+ */
+
+#ifndef DO_POSTGRESQL
+
+#include "Utilities/Util.h"
+#include "Policies/Singleton.h"
+#include "Platform/Define.h"
+#include "Threading/Threading.h"
+#include "DatabaseEnv.h"
+#include "Utilities/Timer.h"
+
+size_t DatabaseMysql::db_count = 0;
+
+void DatabaseMysql::ThreadStart()
+{
+    mysql_thread_init();
+}
+
+void DatabaseMysql::ThreadEnd()
+{
+    mysql_thread_end();
+}
+
+DatabaseMysql::DatabaseMysql()
+{
+    // before first connection
+    if (db_count++ == 0)
+    {
+        // Mysql Library Init
+        if(mysql_library_init(-1, NULL, NULL))
+        {
+            sLog.outError("Could not initialize MySQL client library\n");
+            ACE_OS::exit();
+        }
+        if (!mysql_thread_safe())
+        {
+            sLog.outError("FATAL ERROR: Used MySQL library isn't thread-safe.");
+            Log::WaitBeforeContinueIfNeed();
+            ACE_OS::exit();
+        }
+    }
+}
+
+DatabaseMysql::~DatabaseMysql()
+{
+    StopServer();
+
+    // Free Mysql library pointers for last ~DB
+    if (--db_count == 0)
+    {
+        mysql_library_end();
+    }
+}
+
+SqlConnection* DatabaseMysql::CreateConnection()
+{
+    return new MySQLConnection(*this);
+}
+
+MySQLConnection::~MySQLConnection()
+{
+    FreePreparedStatements();
+    mysql_close(mMysql);
+}
+
+bool MySQLConnection::Initialize(const char* infoString)
+{
+    MYSQL* mysqlInit = mysql_init(NULL);
+    if (!mysqlInit)
+    {
+        sLog.outError("Could not initialize Mysql connection");
+        return false;
+    }
+
+    Tokens tokens = StrSplit(infoString, ";");
+
+    Tokens::iterator iter;
+
+    std::string host, port_or_socket, user, password, database;
+    int port;
+    char const* unix_socket;
+
+    iter = tokens.begin();
+
+    if (iter != tokens.end())
+    {
+        host = *iter++;
+    }
+    if (iter != tokens.end())
+    {
+        port_or_socket = *iter++;
+    }
+    if (iter != tokens.end())
+    {
+        user = *iter++;
+    }
+    if (iter != tokens.end())
+    {
+        password = *iter++;
+    }
+    if (iter != tokens.end())
+    {
+        database = *iter++;
+    }
+
+    mysql_options(mysqlInit, MYSQL_SET_CHARSET_NAME, "utf8");
+    mysql_options(mysqlInit, MYSQL_OPT_RECONNECT, "1");
+#ifdef WIN32
+    if (host == ".")                                        // named pipe use option (Windows)
+    {
+        unsigned int opt = MYSQL_PROTOCOL_PIPE;
+        mysql_options(mysqlInit, MYSQL_OPT_PROTOCOL, (char const*)&opt);
+        port = 0;
+        unix_socket = 0;
+    }
+    else                                                    // generic case
+    {
+        port = atoi(port_or_socket.c_str());
+        unix_socket = 0;
+    }
+#else
+    if (host == ".")                                        // socket use option (Unix/Linux)
+    {
+        unsigned int opt = MYSQL_PROTOCOL_SOCKET;
+        mysql_options(mysqlInit, MYSQL_OPT_PROTOCOL, (char const*)&opt);
+        host = "localhost";
+        port = 0;
+        unix_socket = port_or_socket.c_str();
+    }
+    else                                                    // generic case
+    {
+        port = atoi(port_or_socket.c_str());
+        unix_socket = 0;
+    }
+#endif
+
+    mMysql = mysql_real_connect(mysqlInit, host.c_str(), user.c_str(),
+                                password.c_str(), database.c_str(), port, unix_socket, 0);
+
+    if (!mMysql)
+    {
+        sLog.outError("Could not connect to MySQL database at %s: %s\n",
+                      host.c_str(), mysql_error(mysqlInit));
+        mysql_close(mysqlInit);
+        return false;
+    }
+
+    DETAIL_LOG("Connected to MySQL database %s@%s:%s/%s", user.c_str(), host.c_str(), port_or_socket.c_str(), database.c_str());
+    sLog.outString("MySQL client library: %s", mysql_get_client_info());
+    sLog.outString("MySQL server ver: %s ", mysql_get_server_info(mMysql));
+
+    /*----------SET AUTOCOMMIT ON---------*/
+    // It seems mysql 5.0.x have enabled this feature
+    // by default. In crash case you can lose data!!!
+    // So better to turn this off
+    // ---
+    // This is wrong since mangos use transactions,
+    // autocommit is turned of during it.
+    // Setting it to on makes atomic updates work
+    // ---
+    // LEAVE 'AUTOCOMMIT' MODE ALWAYS ENABLED!!!
+    // W/O IT EVEN 'SELECT' QUERIES WOULD REQUIRE TO BE WRAPPED INTO 'START TRANSACTION'<>'COMMIT' CLAUSES!!!
+    if (!mysql_autocommit(mMysql, 1))
+    {
+        DETAIL_LOG("AUTOCOMMIT SUCCESSFULLY SET TO 1");
+    }
+    else
+    {
+        DETAIL_LOG("AUTOCOMMIT NOT SET TO 1");
+    }
+    /*-------------------------------------*/
+
+    // set connection properties to UTF8 to properly handle locales for different
+    // server configs - core sends data in UTF8, so MySQL must expect UTF8 too
+    Execute("SET NAMES `utf8`");
+    Execute("SET CHARACTER SET `utf8`");
+
+    return true;
+}
+
+bool MySQLConnection::_Query(const char* sql, MYSQL_RES** pResult, MYSQL_FIELD** pFields, uint64* pRowCount, uint32* pFieldCount)
+{
+    if (!mMysql)
+    {
+        return 0;
+    }
+
+    uint32 _s = getMSTime();
+
+    if (mysql_query(mMysql, sql))
+    {
+        sLog.outErrorDb("SQL: %s", sql);
+        sLog.outErrorDb("query ERROR: %s", mysql_error(mMysql));
+        return false;
+    }
+    else
+    {
+        DEBUG_FILTER_LOG(LOG_FILTER_SQL_TEXT, "[%u ms] SQL: %s", getMSTimeDiff(_s, getMSTime()), sql);
+    }
+
+    *pResult = mysql_store_result(mMysql);
+    *pRowCount = mysql_affected_rows(mMysql);
+    *pFieldCount = mysql_field_count(mMysql);
+
+    if (!*pResult)
+    {
+        return false;
+    }
+
+    if (!*pRowCount)
+    {
+        mysql_free_result(*pResult);
+        return false;
+    }
+
+    *pFields = mysql_fetch_fields(*pResult);
+    return true;
+}
+
+QueryResult* MySQLConnection::Query(const char* sql)
+{
+    MYSQL_RES* result = NULL;
+    MYSQL_FIELD* fields = NULL;
+    uint64 rowCount = 0;
+    uint32 fieldCount = 0;
+
+    if (!_Query(sql, &result, &fields, &rowCount, &fieldCount))
+    {
+        return NULL;
+    }
+
+    QueryResultMysql* queryResult = new QueryResultMysql(result, fields, rowCount, fieldCount);
+
+    queryResult->NextRow();
+    return queryResult;
+}
+
+QueryNamedResult* MySQLConnection::QueryNamed(const char* sql)
+{
+    MYSQL_RES* result = NULL;
+    MYSQL_FIELD* fields = NULL;
+    uint64 rowCount = 0;
+    uint32 fieldCount = 0;
+
+    if (!_Query(sql, &result, &fields, &rowCount, &fieldCount))
+    {
+        return NULL;
+    }
+
+    QueryFieldNames names(fieldCount);
+    for (uint32 i = 0; i < fieldCount; ++i)
+    {
+        names[i] = fields[i].name;
+    }
+
+    QueryResultMysql* queryResult = new QueryResultMysql(result, fields, rowCount, fieldCount);
+
+    queryResult->NextRow();
+    return new QueryNamedResult(queryResult, names);
+}
+
+bool MySQLConnection::Execute(const char* sql)
+{
+    if (!mMysql)
+    {
+        return false;
+    }
+
+    {
+        uint32 _s = getMSTime();
+
+        if (mysql_query(mMysql, sql))
+        {
+            sLog.outErrorDb("SQL: %s", sql);
+            sLog.outErrorDb("SQL ERROR: %s", mysql_error(mMysql));
+            return false;
+        }
+        else
+        {
+            DEBUG_FILTER_LOG(LOG_FILTER_SQL_TEXT, "[%u ms] SQL: %s", getMSTimeDiff(_s, getMSTime()), sql);
+        }
+        // end guarded block
+    }
+
+    return true;
+}
+
+bool MySQLConnection::_TransactionCmd(const char* sql)
+{
+    if (mysql_query(mMysql, sql))
+    {
+        sLog.outError("SQL: %s", sql);
+        sLog.outError("SQL ERROR: %s", mysql_error(mMysql));
+        return false;
+    }
+    else
+    {
+        DEBUG_FILTER_LOG(LOG_FILTER_SQL_TEXT, "SQL: %s", sql);
+    }
+    return true;
+}
+
+bool MySQLConnection::BeginTransaction()
+{
+    return _TransactionCmd("START TRANSACTION");
+}
+
+bool MySQLConnection::CommitTransaction()
+{
+    return _TransactionCmd("COMMIT");
+}
+
+bool MySQLConnection::RollbackTransaction()
+{
+    return _TransactionCmd("ROLLBACK");
+}
+
+unsigned long MySQLConnection::escape_string(char* to, const char* from, unsigned long length)
+{
+    if (!mMysql || !to || !from || !length)
+    {
+        return 0;
+    }
+
+    return(mysql_real_escape_string(mMysql, to, from, length));
+}
+
+//////////////////////////////////////////////////////////////////////////
+SqlPreparedStatement* MySQLConnection::CreateStatement(const std::string& fmt)
+{
+    return new MySqlPreparedStatement(fmt, *this, mMysql);
+}
+
+//////////////////////////////////////////////////////////////////////////
+MySqlPreparedStatement::MySqlPreparedStatement(const std::string& fmt, SqlConnection& conn, MYSQL* mysql) : SqlPreparedStatement(fmt, conn),
+    m_pMySQLConn(mysql), m_stmt(NULL), m_pInputArgs(NULL), m_pResult(NULL), m_pResultMetadata(NULL)
+{
+}
+
+MySqlPreparedStatement::~MySqlPreparedStatement()
+{
+    RemoveBinds();
+}
+
+bool MySqlPreparedStatement::prepare()
+{
+    if (isPrepared())
+    {
+        return true;
+    }
+
+    // remove old binds
+    RemoveBinds();
+
+    // create statement object
+    m_stmt = mysql_stmt_init(m_pMySQLConn);
+    if (!m_stmt)
+    {
+        sLog.outError("SQL: mysql_stmt_init() failed ");
+        return false;
+    }
+
+    // prepare statement
+    if (mysql_stmt_prepare(m_stmt, m_szFmt.c_str(), m_szFmt.length()))
+    {
+        sLog.outError("SQL: mysql_stmt_prepare() failed for '%s'", m_szFmt.c_str());
+        sLog.outError("SQL ERROR: %s", mysql_stmt_error(m_stmt));
+        return false;
+    }
+
+    /* Get the parameter count from the statement */
+    m_nParams = mysql_stmt_param_count(m_stmt);
+
+    /* Fetch result set meta information */
+    m_pResultMetadata = mysql_stmt_result_metadata(m_stmt);
+    // if we do not have result metadata
+    if (!m_pResultMetadata && strnicmp(m_szFmt.c_str(), "select", 6) == 0)
+    {
+        sLog.outError("SQL: no meta information for '%s'", m_szFmt.c_str());
+        sLog.outError("SQL ERROR: %s", mysql_stmt_error(m_stmt));
+        return false;
+    }
+
+    // bind input buffers
+    if (m_nParams)
+    {
+        m_pInputArgs = new MYSQL_BIND[m_nParams];
+        memset(m_pInputArgs, 0, sizeof(MYSQL_BIND) * m_nParams);
+    }
+
+    // check if we have a statement which returns result sets
+    if (m_pResultMetadata)
+    {
+        // our statement is query
+        m_bIsQuery = true;
+        /* Get total columns in the query */
+        m_nColumns = mysql_num_fields(m_pResultMetadata);
+
+        // bind output buffers
+    }
+
+    m_bPrepared = true;
+    return true;
+}
+
+void MySqlPreparedStatement::bind(const SqlStmtParameters& holder)
+{
+    if (!isPrepared())
+    {
+        MANGOS_ASSERT(false);
+        return;
+    }
+
+    // finalize adding params
+    if (!m_pInputArgs)
+    {
+        return;
+    }
+
+    // verify if we bound all needed input parameters
+    if (m_nParams != holder.boundParams())
+    {
+        MANGOS_ASSERT(false);
+        return;
+    }
+
+    unsigned int nIndex = 0;
+    SqlStmtParameters::ParameterContainer const& _args = holder.params();
+
+    SqlStmtParameters::ParameterContainer::const_iterator iter_last = _args.end();
+    for (SqlStmtParameters::ParameterContainer::const_iterator iter = _args.begin(); iter != iter_last; ++iter)
+    {
+        // bind parameter
+        addParam(nIndex++, (*iter));
+    }
+
+    // bind input arguments
+    if (mysql_stmt_bind_param(m_stmt, m_pInputArgs))
+    {
+        sLog.outError("SQL ERROR: mysql_stmt_bind_param() failed\n");
+        sLog.outError("SQL ERROR: %s", mysql_stmt_error(m_stmt));
+    }
+}
+
+void MySqlPreparedStatement::addParam(unsigned int nIndex, const SqlStmtFieldData& data)
+{
+    MANGOS_ASSERT(m_pInputArgs);
+    MANGOS_ASSERT(nIndex < m_nParams);
+
+    MYSQL_BIND& pData = m_pInputArgs[nIndex];
+
+    bool bUnsigned = 0;
+    enum_field_types dataType = ToMySQLType(data, bUnsigned);
+
+    // setup MYSQL_BIND structure
+    pData.buffer_type = dataType;
+    pData.is_unsigned = bUnsigned;
+    pData.buffer = data.buff();
+    pData.length = 0;
+    pData.buffer_length = data.type() == FIELD_STRING ? data.size() : 0;
+}
+
+void MySqlPreparedStatement::RemoveBinds()
+{
+    if (!m_stmt)
+    {
+        return;
+    }
+
+    delete[] m_pInputArgs;
+    delete[] m_pResult;
+
+    mysql_free_result(m_pResultMetadata);
+    mysql_stmt_close(m_stmt);
+
+    m_stmt = NULL;
+    m_pResultMetadata = NULL;
+    m_pResult = NULL;
+    m_pInputArgs = NULL;
+
+    m_bPrepared = false;
+}
+
+bool MySqlPreparedStatement::execute()
+{
+    if (!isPrepared())
+    {
+        return false;
+    }
+
+    if (mysql_stmt_execute(m_stmt))
+    {
+        sLog.outError("SQL: can not execute '%s'", m_szFmt.c_str());
+        sLog.outError("SQL ERROR: %s", mysql_stmt_error(m_stmt));
+        return false;
+    }
+
+    return true;
+}
+
+enum_field_types MySqlPreparedStatement::ToMySQLType(const SqlStmtFieldData& data, bool& bUnsigned)
+{
+    bUnsigned = 0;
+    enum_field_types dataType = MYSQL_TYPE_NULL;
+
+    switch (data.type())
+    {
+        case FIELD_NONE:    dataType = MYSQL_TYPE_NULL;                     break;
+            // MySQL does not support MYSQL_TYPE_BIT as input type
+        case FIELD_BOOL:    // dataType = MYSQL_TYPE_BIT;      bUnsigned = 1;  break;
+        case FIELD_UI8:     dataType = MYSQL_TYPE_TINY;     bUnsigned = 1;  break;
+        case FIELD_I8:      dataType = MYSQL_TYPE_TINY;                     break;
+        case FIELD_I16:     dataType = MYSQL_TYPE_SHORT;                    break;
+        case FIELD_UI16:    dataType = MYSQL_TYPE_SHORT;    bUnsigned = 1;  break;
+        case FIELD_I32:     dataType = MYSQL_TYPE_LONG;                     break;
+        case FIELD_UI32:    dataType = MYSQL_TYPE_LONG;     bUnsigned = 1;  break;
+        case FIELD_I64:     dataType = MYSQL_TYPE_LONGLONG;                 break;
+        case FIELD_UI64:    dataType = MYSQL_TYPE_LONGLONG; bUnsigned = 1;  break;
+        case FIELD_FLOAT:   dataType = MYSQL_TYPE_FLOAT;                    break;
+        case FIELD_DOUBLE:  dataType = MYSQL_TYPE_DOUBLE;                   break;
+        case FIELD_STRING:  dataType = MYSQL_TYPE_STRING;                   break;
+    }
+
+    return dataType;
+}
+#endif
diff --git a/shared/Database/DatabaseMysql.h b/shared/Database/DatabaseMysql.h
new file mode 100644
index 0000000..d7b380f
--- /dev/null
+++ b/shared/Database/DatabaseMysql.h
@@ -0,0 +1,270 @@
+/**
+ * MaNGOS is a full featured server for World of Warcraft, supporting
+ * the following clients: 1.12.x, 2.4.3, 3.3.5a, 4.3.4a and 5.4.8
+ *
+ * Copyright (C) 2005-2022 MaNGOS <https://getmangos.eu>
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * World of Warcraft, and all World of Warcraft or Warcraft art, images,
+ * and lore are copyrighted by Blizzard Entertainment, Inc.
+ */
+
+#ifndef DO_POSTGRESQL
+
+#ifndef MANGOS_H_DATABASEMYSQL
+#define MANGOS_H_DATABASEMYSQL
+
+//#include "Common.h"
+#include "Database.h"
+#include "Policies/Singleton.h"
+#include <ace/Thread_Mutex.h>
+#include <ace/Guard_T.h>
+#include <mysql.h>
+
+#ifdef WIN32
+#include <winsock2.h>
+#endif
+
+/**
+ * @brief MySQL prepared statement class
+ *
+ */
+class MySqlPreparedStatement : public SqlPreparedStatement
+{
+    public:
+        /**
+         * @brief
+         *
+         * @param fmt
+         * @param conn
+         * @param mysql
+         */
+        MySqlPreparedStatement(const std::string& fmt, SqlConnection& conn, MYSQL* mysql);
+        /**
+         * @brief
+         *
+         */
+        ~MySqlPreparedStatement();
+
+        /**
+         * @brief prepare statement
+         *
+         * @return bool
+         */
+        virtual bool prepare() override;
+
+        /**
+         * @brief bind input parameters
+         *
+         * @param holder
+         */
+        virtual void bind(const SqlStmtParameters& holder) override;
+
+        /**
+         * @brief execute DML statement
+         *
+         * @return bool
+         */
+        virtual bool execute() override;
+
+    protected:
+        /**
+         * @brief bind parameters
+         *
+         * @param nIndex
+         * @param data
+         */
+        void addParam(unsigned int nIndex, const SqlStmtFieldData& data);
+
+        /**
+         * @brief
+         *
+         * @param data
+         * @param bUnsigned
+         * @return enum_field_types
+         */
+        static enum_field_types ToMySQLType(const SqlStmtFieldData& data, bool& bUnsigned);
+
+    private:
+        /**
+         * @brief
+         *
+         */
+        void RemoveBinds();
+
+        MYSQL* m_pMySQLConn; /**< TODO */
+        MYSQL_STMT* m_stmt; /**< TODO */
+        MYSQL_BIND* m_pInputArgs; /**< TODO */
+        MYSQL_BIND* m_pResult; /**< TODO */
+        MYSQL_RES* m_pResultMetadata; /**< TODO */
+};
+
+/**
+ * @brief
+ *
+ */
+class MySQLConnection : public SqlConnection
+{
+    public:
+        /**
+         * @brief
+         *
+         * @param db
+         */
+        MySQLConnection(Database& db) : SqlConnection(db), mMysql(NULL) {}
+        /**
+         * @brief
+         *
+         */
+        ~MySQLConnection();
+
+        /**
+         * @brief Initializes Mysql and connects to a server.
+         *
+         * @param infoString infoString should be formated like hostname;username;password;database
+         * @return bool
+         */
+        bool Initialize(const char* infoString) override;
+
+        /**
+         * @brief
+         *
+         * @param sql
+         * @return QueryResult
+         */
+        QueryResult* Query(const char* sql) override;
+        /**
+         * @brief
+         *
+         * @param sql
+         * @return QueryNamedResult
+         */
+        QueryNamedResult* QueryNamed(const char* sql) override;
+        /**
+         * @brief
+         *
+         * @param sql
+         * @return bool
+         */
+        bool Execute(const char* sql) override;
+
+        /**
+         * @brief
+         *
+         * @param to
+         * @param from
+         * @param length
+         * @return unsigned long
+         */
+        unsigned long escape_string(char* to, const char* from, unsigned long length) override;
+
+        /**
+         * @brief
+         *
+         * @return bool
+         */
+        bool BeginTransaction() override;
+        /**
+         * @brief
+         *
+         * @return bool
+         */
+        bool CommitTransaction() override;
+        /**
+         * @brief
+         *
+         * @return bool
+         */
+        bool RollbackTransaction() override;
+
+    protected:
+        /**
+         * @brief
+         *
+         * @param fmt
+         * @return SqlPreparedStatement
+         */
+        SqlPreparedStatement* CreateStatement(const std::string& fmt) override;
+
+    private:
+        /**
+         * @brief
+         *
+         * @param sql
+         * @return bool
+         */
+        bool _TransactionCmd(const char* sql);
+        /**
+         * @brief
+         *
+         * @param sql
+         * @param pResult
+         * @param pFields
+         * @param pRowCount
+         * @param pFieldCount
+         * @return bool
+         */
+        bool _Query(const char* sql, MYSQL_RES** pResult, MYSQL_FIELD** pFields, uint64* pRowCount, uint32* pFieldCount);
+
+        MYSQL* mMysql; /**< TODO */
+};
+
+/**
+ * @brief
+ *
+ */
+class DatabaseMysql : public Database
+{
+        friend class MaNGOS::OperatorNew<DatabaseMysql>;
+
+    public:
+        /**
+         * @brief
+         *
+         */
+        DatabaseMysql();
+        /**
+         * @brief
+         *
+         */
+        ~DatabaseMysql();
+
+        /**
+         * @brief must be call before first query in thread
+         *
+         */
+        void ThreadStart() override;
+        /**
+         * @brief must be call before finish thread run
+         *
+         */
+        void ThreadEnd() override;
+
+    protected:
+        /**
+         * @brief
+         *
+         * @return SqlConnection
+         */
+        virtual SqlConnection* CreateConnection() override;
+
+    private:
+        static size_t db_count; /**< TODO */
+};
+
+#endif
+
+#endif
diff --git a/shared/Database/Field.cpp b/shared/Database/Field.cpp
new file mode 100644
index 0000000..070fb0f
--- /dev/null
+++ b/shared/Database/Field.cpp
@@ -0,0 +1,25 @@
+/**
+ * MaNGOS is a full featured server for World of Warcraft, supporting
+ * the following clients: 1.12.x, 2.4.3, 3.3.5a, 4.3.4a and 5.4.8
+ *
+ * Copyright (C) 2005-2022 MaNGOS <https://getmangos.eu>
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * World of Warcraft, and all World of Warcraft or Warcraft art, images,
+ * and lore are copyrighted by Blizzard Entertainment, Inc.
+ */
+
+//#include "DatabaseEnv.h"
diff --git a/shared/Database/Field.h b/shared/Database/Field.h
new file mode 100644
index 0000000..3e4b891
--- /dev/null
+++ b/shared/Database/Field.h
@@ -0,0 +1,218 @@
+/**
+ * MaNGOS is a full featured server for World of Warcraft, supporting
+ * the following clients: 1.12.x, 2.4.3, 3.3.5a, 4.3.4a and 5.4.8
+ *
+ * Copyright (C) 2005-2022 MaNGOS <https://getmangos.eu>
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * World of Warcraft, and all World of Warcraft or Warcraft art, images,
+ * and lore are copyrighted by Blizzard Entertainment, Inc.
+ */
+
+#ifndef FIELD_H
+#define FIELD_H
+
+#include "Common/Common.h"
+#include <mysql.h>
+
+/**
+ * @brief
+ *
+ */
+class Field
+{
+    public:
+
+        /**
+         * @brief
+         *
+         */
+        enum SimpleDataTypes
+        {
+            DB_TYPE_UNKNOWN = 0x00,
+            DB_TYPE_STRING  = 0x01,
+            DB_TYPE_INTEGER = 0x02,
+            DB_TYPE_FLOAT   = 0x03,
+            DB_TYPE_BOOL    = 0x04
+        };
+
+        /**
+         * @brief
+         *
+         */
+        Field() : mValue(NULL), mType(MYSQL_TYPE_NULL) {}
+        /**
+         * @brief
+         *
+         * @param value
+         * @param type
+         */
+        Field(const char* value, enum_field_types type) : mValue(value), mType(type) {}
+
+        /**
+         * @brief
+         *
+         */
+        ~Field() {}
+
+        /**
+         * @brief
+         *
+         * @return enum_field_type
+         */
+        enum enum_field_types GetType() const { return mType; }
+        /**
+         * @brief
+         *
+         * @return bool
+         */
+        bool IsNULL() const { return mValue == NULL; }
+
+        /**
+         * @brief
+         *
+         * @return const char
+         */
+        const char* GetString() const { return mValue; }
+        /**
+         * @brief
+         *
+         * @return std::string
+         */
+        std::string GetCppString() const
+        {
+            return mValue ? mValue : "";                    // std::string s = 0 have undefine result in C++
+        }
+        /**
+         * @brief
+         *
+         * @return float
+         */
+        float GetFloat() const { return mValue ? static_cast<float>(atof(mValue)) : 0.0f; }
+        /**
+         * @brief
+         *
+         * @return bool
+         */
+        bool GetBool() const { return mValue ? atoi(mValue) > 0 : false; }
+        /**
+        * @brief
+        *
+        * @return double
+        */
+        double GetDouble() const { return mValue ? static_cast<double>(atof(mValue)) : 0.0f; }
+        /**
+        * @brief
+        *
+        * @return int8
+        */
+        int8 GetInt8() const { return mValue ? static_cast<int8>(atol(mValue)) : int8(0); }
+        /**
+         * @brief
+         *
+         * @return int32
+         */
+        int32 GetInt32() const { return mValue ? static_cast<int32>(atol(mValue)) : int32(0); }
+        /**
+         * @brief
+         *
+         * @return uint8
+         */
+        uint8 GetUInt8() const { return mValue ? static_cast<uint8>(atol(mValue)) : uint8(0); }
+        /**
+         * @brief
+         *
+         * @return uint16
+         */
+        uint16 GetUInt16() const { return mValue ? static_cast<uint16>(atol(mValue)) : uint16(0); }
+        /**
+         * @brief
+         *
+         * @return int16
+         */
+        int16 GetInt16() const { return mValue ? static_cast<int16>(atol(mValue)) : int16(0); }
+        /**
+         * @brief
+         *
+         * @return uint32
+         */
+        uint32 GetUInt32() const { return mValue ? static_cast<uint32>(atol(mValue)) : uint32(0); }
+        /**
+         * @brief
+         *
+         * @return uint64
+         */
+        uint64 GetUInt64() const
+        {
+            uint64 value = 0;
+            if (!mValue || sscanf(mValue, UI64FMTD, &value) == -1)
+            {
+                return 0;
+            }
+
+            return value;
+        }
+        /**
+        * @brief
+        *
+        * @return int64
+        */
+        uint64 GetInt64() const
+        {
+            int64 value = 0;
+            if (!mValue || sscanf(mValue, SI64FMTD, &value) == -1)
+            {
+                return 0;
+            }
+
+            return value;
+        }
+
+        /**
+         * @brief
+         *
+         * @param type
+         */
+        void SetType(enum enum_field_types type) { mType = type; }
+
+        /**
+         * @brief no need for memory allocations to store resultset field strings
+         *
+         * all we need is to cache pointers returned by different DBMS APIs
+         *
+         * @param value
+         */
+        void SetValue(const char* value) { mValue = value; }
+
+    private:
+        /**
+         * @brief
+         *
+         * @param
+         */
+        Field(Field const&);
+        /**
+         * @brief
+         *
+         * @param
+         * @return Field &operator
+         */
+        Field& operator=(Field const&);
+
+        const char* mValue; /**< TODO */
+        enum_field_types mType; /**< TODO */
+};
+#endif
diff --git a/shared/Database/QueryResult.h b/shared/Database/QueryResult.h
new file mode 100644
index 0000000..df530cc
--- /dev/null
+++ b/shared/Database/QueryResult.h
@@ -0,0 +1,192 @@
+/**
+ * MaNGOS is a full featured server for World of Warcraft, supporting
+ * the following clients: 1.12.x, 2.4.3, 3.3.5a, 4.3.4a and 5.4.8
+ *
+ * Copyright (C) 2005-2022 MaNGOS <https://getmangos.eu>
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * World of Warcraft, and all World of Warcraft or Warcraft art, images,
+ * and lore are copyrighted by Blizzard Entertainment, Inc.
+ */
+
+#ifndef QUERYRESULT_H
+#define QUERYRESULT_H
+
+#include "Common/Common.h"
+#include "Utilities/Errors.h"
+#include "Field.h"
+
+/**
+ * @brief
+ *
+ */
+class QueryResult
+{
+    public:
+        /**
+         * @brief
+         *
+         * @param rowCount
+         * @param fieldCount
+         */
+        QueryResult(uint64 rowCount, uint32 fieldCount)
+            : mFieldCount(fieldCount), mRowCount(rowCount) {}
+
+        /**
+         * @brief
+         *
+         */
+        virtual ~QueryResult() {}
+
+        /**
+         * @brief
+         *
+         * @return bool
+         */
+        virtual bool NextRow() = 0;
+
+        /**
+         * @brief
+         *
+         * @return Field
+         */
+        Field* Fetch() const { return mCurrentRow; }
+
+        /**
+         * @brief
+         *
+         * @param index
+         * @return const Field &operator
+         */
+        const Field& operator [](int index) const { return mCurrentRow[index]; }
+
+        /**
+         * @brief
+         *
+         * @return uint32
+         */
+        uint32 GetFieldCount() const { return mFieldCount; }
+        /**
+         * @brief
+         *
+         * @return uint64
+         */
+        uint64 GetRowCount() const { return mRowCount; }
+
+    protected:
+        Field* mCurrentRow; /**< TODO */
+        uint32 mFieldCount; /**< TODO */
+        uint64 mRowCount; /**< TODO */
+};
+
+/**
+ * @brief
+ *
+ */
+typedef std::vector<std::string> QueryFieldNames;
+
+/**
+ * @brief
+ *
+ */
+class QueryNamedResult
+{
+    public:
+        /**
+         * @brief
+         *
+         * @param query
+         * @param names
+         */
+        explicit QueryNamedResult(QueryResult* query, QueryFieldNames const& names) : mQuery(query), mFieldNames(names) {}
+        /**
+         * @brief
+         *
+         */
+        ~QueryNamedResult() { delete mQuery; }
+
+        // compatible interface with QueryResult
+        /**
+         * @brief
+         *
+         * @return bool
+         */
+        bool NextRow() { return mQuery->NextRow(); }
+        /**
+         * @brief
+         *
+         * @return Field
+         */
+        Field* Fetch() const { return mQuery->Fetch(); }
+        /**
+         * @brief
+         *
+         * @return uint32
+         */
+        uint32 GetFieldCount() const { return mQuery->GetFieldCount(); }
+        /**
+         * @brief
+         *
+         * @return uint64
+         */
+        uint64 GetRowCount() const { return mQuery->GetRowCount(); }
+        /**
+         * @brief
+         *
+         * @param index
+         * @return const Field &operator
+         */
+        Field const& operator[](int index) const { return (*mQuery)[index]; }
+
+        /**
+         * @brief named access
+         *
+         * @param name
+         * @return const Field &operator
+         */
+        Field const& operator[](const std::string& name) const { return mQuery->Fetch()[GetField_idx(name)]; }
+        /**
+         * @brief
+         *
+         * @return const QueryFieldNames
+         */
+        QueryFieldNames const& GetFieldNames() const { return mFieldNames; }
+
+        /**
+         * @brief
+         *
+         * @param name
+         * @return uint32
+         */
+        uint32 GetField_idx(const std::string& name) const
+        {
+            for (size_t idx = 0; idx < mFieldNames.size(); ++idx)
+            {
+                if (mFieldNames[idx] == name)
+                {
+                    return idx;
+                }
+            }
+            MANGOS_ASSERT(false && "unknown field name");
+            return uint32(-1);
+        }
+
+    protected:
+        QueryResult* mQuery; /**< TODO */
+        QueryFieldNames mFieldNames; /**< TODO */
+};
+
+#endif
diff --git a/shared/Database/QueryResultMysql.cpp b/shared/Database/QueryResultMysql.cpp
new file mode 100644
index 0000000..36c7edc
--- /dev/null
+++ b/shared/Database/QueryResultMysql.cpp
@@ -0,0 +1,113 @@
+/**
+ * MaNGOS is a full featured server for World of Warcraft, supporting
+ * the following clients: 1.12.x, 2.4.3, 3.3.5a, 4.3.4a and 5.4.8
+ *
+ * Copyright (C) 2005-2022 MaNGOS <https://getmangos.eu>
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * World of Warcraft, and all World of Warcraft or Warcraft art, images,
+ * and lore are copyrighted by Blizzard Entertainment, Inc.
+ */
+
+#ifndef DO_POSTGRESQL
+
+#include "DatabaseEnv.h"
+#include "Utilities/Errors.h"
+
+QueryResultMysql::QueryResultMysql(MYSQL_RES* result, MYSQL_FIELD* fields, uint64 rowCount, uint32 fieldCount) :
+    QueryResult(rowCount, fieldCount), mResult(result)
+{
+    mCurrentRow = new Field[mFieldCount];
+    MANGOS_ASSERT(mCurrentRow);
+
+    for (uint32 i = 0; i < mFieldCount; ++i)
+    {
+        mCurrentRow[i].SetType(fields[i].type);
+    }
+}
+
+QueryResultMysql::~QueryResultMysql()
+{
+    EndQuery();
+}
+
+bool QueryResultMysql::NextRow()
+{
+    MYSQL_ROW row;
+
+    if (!mResult)
+    {
+        return false;
+    }
+
+    row = mysql_fetch_row(mResult);
+    if (!row)
+    {
+        EndQuery();
+        return false;
+    }
+
+    for (uint32 i = 0; i < mFieldCount; ++i)
+    {
+        mCurrentRow[i].SetValue(row[i]);
+    }
+
+    return true;
+}
+
+void QueryResultMysql::EndQuery()
+{
+    delete[] mCurrentRow;
+    mCurrentRow = 0;
+
+    if (mResult)
+    {
+        mysql_free_result(mResult);
+        mResult = 0;
+    }
+}
+
+Field::SimpleDataTypes QueryResultMysql::GetSimpleType(enum_field_types type)
+{
+    switch (type)
+    {
+        case FIELD_TYPE_TIMESTAMP:
+        case FIELD_TYPE_DATE:
+        case FIELD_TYPE_TIME:
+        case FIELD_TYPE_DATETIME:
+        case FIELD_TYPE_YEAR:
+        case FIELD_TYPE_STRING:
+        case FIELD_TYPE_VAR_STRING:
+        case FIELD_TYPE_BLOB:
+        case FIELD_TYPE_SET:
+        case FIELD_TYPE_NULL:
+            return Field::DB_TYPE_STRING;
+        case FIELD_TYPE_TINY:
+        case FIELD_TYPE_SHORT:
+        case FIELD_TYPE_LONG:
+        case FIELD_TYPE_INT24:
+        case FIELD_TYPE_LONGLONG:
+        case FIELD_TYPE_ENUM:
+            return Field::DB_TYPE_INTEGER;
+        case FIELD_TYPE_DECIMAL:
+        case FIELD_TYPE_FLOAT:
+        case FIELD_TYPE_DOUBLE:
+            return Field::DB_TYPE_FLOAT;
+        default:
+            return Field::DB_TYPE_UNKNOWN;
+    }
+}
+#endif
diff --git a/shared/Database/QueryResultMysql.h b/shared/Database/QueryResultMysql.h
new file mode 100644
index 0000000..0ec0065
--- /dev/null
+++ b/shared/Database/QueryResultMysql.h
@@ -0,0 +1,87 @@
+/**
+ * MaNGOS is a full featured server for World of Warcraft, supporting
+ * the following clients: 1.12.x, 2.4.3, 3.3.5a, 4.3.4a and 5.4.8
+ *
+ * Copyright (C) 2005-2022 MaNGOS <https://getmangos.eu>
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * World of Warcraft, and all World of Warcraft or Warcraft art, images,
+ * and lore are copyrighted by Blizzard Entertainment, Inc.
+ */
+
+#ifndef DO_POSTGRESQL
+
+#if !defined(QUERYRESULTMYSQL_H)
+#define QUERYRESULTMYSQL_H
+
+#include "Common/Common.h"
+
+#ifdef WIN32
+#include <winsock2.h>
+#endif
+
+#include <mysql.h>
+
+/**
+ * @brief
+ *
+ */
+class QueryResultMysql : public QueryResult
+{
+    public:
+        /**
+         * @brief
+         *
+         * @param result
+         * @param fields
+         * @param rowCount
+         * @param fieldCount
+         */
+        QueryResultMysql(MYSQL_RES* result, MYSQL_FIELD* fields, uint64 rowCount, uint32 fieldCount);
+
+        /**
+         * @brief
+         *
+         */
+        ~QueryResultMysql();
+
+        /**
+         * @brief
+         *
+         * @return bool
+         */
+        bool NextRow() override;
+
+        /**
+         * @brief
+         *
+         * @param type
+         * @return Field::SimpleDataTypes
+         */
+        static Field::SimpleDataTypes GetSimpleType(enum_field_types type);
+
+    private:
+        /**
+         * @brief
+         *
+         */
+        void EndQuery();
+
+        MYSQL_RES* mResult; /**< TODO */
+};
+#endif
+
+#endif
diff --git a/shared/Database/SQLStorage.cpp b/shared/Database/SQLStorage.cpp
new file mode 100644
index 0000000..d8bf3b7
--- /dev/null
+++ b/shared/Database/SQLStorage.cpp
@@ -0,0 +1,249 @@
+/**
+ * MaNGOS is a full featured server for World of Warcraft, supporting
+ * the following clients: 1.12.x, 2.4.3, 3.3.5a, 4.3.4a and 5.4.8
+ *
+ * Copyright (C) 2005-2022 MaNGOS <https://getmangos.eu>
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * World of Warcraft, and all World of Warcraft or Warcraft art, images,
+ * and lore are copyrighted by Blizzard Entertainment, Inc.
+ */
+
+#include "SQLStorage.h"
+
+// -----------------------------------  SQLStorageBase  ---------------------------------------- //
+
+SQLStorageBase::SQLStorageBase() :
+    m_tableName(NULL),
+    m_entry_field(NULL),
+    m_src_format(NULL),
+    m_dst_format(NULL),
+    m_dstFieldCount(0),
+    m_srcFieldCount(0),
+    m_recordCount(0),
+    m_maxEntry(0),
+    m_recordSize(0),
+    m_data(NULL)
+{}
+
+void SQLStorageBase::Initialize(const char* tableName, const char* entry_field, const char* src_format, const char* dst_format)
+{
+    m_tableName = tableName;
+    m_entry_field = entry_field;
+    m_src_format = src_format;
+    m_dst_format = dst_format;
+
+    m_srcFieldCount = strlen(m_src_format);
+    m_dstFieldCount = strlen(m_dst_format);
+}
+
+char* SQLStorageBase::createRecord(uint32 recordId)
+{
+    char* newRecord = &m_data[m_recordCount * m_recordSize];
+    ++m_recordCount;
+
+    JustCreatedRecord(recordId, newRecord);
+    return newRecord;
+}
+
+void SQLStorageBase::prepareToLoad(uint32 maxEntry, uint32 recordCount, uint32 recordSize)
+{
+    m_maxEntry = maxEntry;
+    m_recordSize = recordSize;
+
+    delete[] m_data;
+    m_data = new char[recordCount * m_recordSize];
+    memset(m_data, 0, recordCount * m_recordSize);
+
+    m_recordCount = 0;
+}
+
+// Function to delete the data
+void SQLStorageBase::Free()
+{
+    if (!m_data)
+    {
+        return;
+    }
+
+    uint32 offset = 0;
+    for (uint32 x = 0; x < m_dstFieldCount; ++x)
+    {
+        switch (m_dst_format[x])
+        {
+            case DBC_FF_LOGIC:
+                offset += sizeof(bool);
+                break;
+            case DBC_FF_STRING:
+            {
+                for (uint32 recordItr = 0; recordItr < m_recordCount; ++recordItr)
+                {
+                    delete[] *(char**)((char*)(m_data + (recordItr * m_recordSize)) + offset);
+                }
+
+                offset += sizeof(char*);
+                break;
+            }
+            case DBC_FF_NA:
+            case DBC_FF_INT:
+                offset += sizeof(uint32);
+                break;
+            case DBC_FF_BYTE:
+            case DBC_FF_NA_BYTE:
+                offset += sizeof(char);
+                break;
+            case DBC_FF_FLOAT:
+            case DBC_FF_NA_FLOAT:
+                offset += sizeof(float);
+                break;
+            case DBC_FF_NA_POINTER:
+                // TODO- possible (and small) memleak here possible
+                offset += sizeof(char*);
+                break;
+            case DBC_FF_IND:
+            case DBC_FF_SORT:
+                assert(false && "SQL storage not have sort field types");
+                break;
+            default:
+                assert(false && "unknown format character");
+                break;
+        }
+    }
+    delete[] m_data;
+    m_data = NULL;
+    m_recordCount = 0;
+}
+
+// -----------------------------------  SQLStorage  -------------------------------------------- //
+
+void SQLStorage::EraseEntry(uint32 id)
+{
+    m_Index[id] = NULL;
+}
+
+void SQLStorage::Free()
+{
+    SQLStorageBase::Free();
+    delete[] m_Index;
+    m_Index = NULL;
+}
+
+void SQLStorage::Load(bool error_at_empty /*= true*/)
+{
+    SQLStorageLoader loader;
+    loader.Load(*this, error_at_empty);
+}
+
+SQLStorage::SQLStorage(const char* fmt, const char* _entry_field, const char* sqlname)
+{
+    Initialize(sqlname, _entry_field, fmt, fmt);
+    m_Index = NULL;
+}
+
+SQLStorage::SQLStorage(const char* src_fmt, const char* dst_fmt, const char* _entry_field, const char* sqlname)
+{
+    Initialize(sqlname, _entry_field, src_fmt, dst_fmt);
+    m_Index = NULL;
+}
+
+void SQLStorage::prepareToLoad(uint32 maxRecordId, uint32 recordCount, uint32 recordSize)
+{
+    // Clear (possible) old data and old index array
+    Free();
+
+    // Set index array
+    m_Index = new char*[maxRecordId];
+    memset(m_Index, 0, maxRecordId * sizeof(char*));
+
+    SQLStorageBase::prepareToLoad(maxRecordId, recordCount, recordSize);
+}
+
+// -----------------------------------  SQLHashStorage  ---------------------------------------- //
+void SQLHashStorage::Load()
+{
+    SQLHashStorageLoader loader;
+    loader.Load(*this);
+}
+
+void SQLHashStorage::Free()
+{
+    SQLStorageBase::Free();
+    m_indexMap.clear();
+}
+
+void SQLHashStorage::prepareToLoad(uint32 maxRecordId, uint32 recordCount, uint32 recordSize)
+{
+    // Clear (possible) old data and old index array
+    Free();
+
+    SQLStorageBase::prepareToLoad(maxRecordId, recordCount, recordSize);
+}
+
+void SQLHashStorage::EraseEntry(uint32 id)
+{
+    // do not erase from m_records
+    RecordMap::iterator find = m_indexMap.find(id);
+    if (find != m_indexMap.end())
+    {
+        find->second = NULL;
+    }
+}
+
+SQLHashStorage::SQLHashStorage(const char* fmt, const char* _entry_field, const char* sqlname)
+{
+    Initialize(sqlname, _entry_field, fmt, fmt);
+}
+
+SQLHashStorage::SQLHashStorage(const char* src_fmt, const char* dst_fmt, const char* _entry_field, const char* sqlname)
+{
+    Initialize(sqlname, _entry_field, src_fmt, dst_fmt);
+}
+
+// -----------------------------------  SQLMultiStorage  --------------------------------------- //
+void SQLMultiStorage::Load()
+{
+    SQLMultiStorageLoader loader;
+    loader.Load(*this);
+}
+
+void SQLMultiStorage::Free()
+{
+    SQLStorageBase::Free();
+    m_indexMultiMap.clear();
+}
+
+void SQLMultiStorage::prepareToLoad(uint32 maxRecordId, uint32 recordCount, uint32 recordSize)
+{
+    // Clear (possible) old data and old index array
+    Free();
+
+    SQLStorageBase::prepareToLoad(maxRecordId, recordCount, recordSize);
+}
+
+void SQLMultiStorage::EraseEntry(uint32 id)
+{
+    m_indexMultiMap.erase(id);
+}
+
+SQLMultiStorage::SQLMultiStorage(const char* fmt, const char* _entry_field, const char* sqlname)
+{
+    Initialize(sqlname, _entry_field, fmt, fmt);
+}
+
+SQLMultiStorage::SQLMultiStorage(const char* src_fmt, const char* dst_fmt, const char* _entry_field, const char* sqlname)
+{
+    Initialize(sqlname, _entry_field, src_fmt, dst_fmt);
+}
diff --git a/shared/Database/SQLStorage.h b/shared/Database/SQLStorage.h
new file mode 100644
index 0000000..34d7eb3
--- /dev/null
+++ b/shared/Database/SQLStorage.h
@@ -0,0 +1,783 @@
+/**
+ * MaNGOS is a full featured server for World of Warcraft, supporting
+ * the following clients: 1.12.x, 2.4.3, 3.3.5a, 4.3.4a and 5.4.8
+ *
+ * Copyright (C) 2005-2022 MaNGOS <https://getmangos.eu>
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * World of Warcraft, and all World of Warcraft or Warcraft art, images,
+ * and lore are copyrighted by Blizzard Entertainment, Inc.
+ */
+
+#ifndef SQLSTORAGE_H
+#define SQLSTORAGE_H
+
+#include "Common/Common.h"
+#include "Database/DatabaseEnv.h"
+#include "DataStores/DBCFileLoader.h"
+
+/**
+ * @brief
+ *
+ */
+class SQLStorageBase
+{
+        template<class DerivedLoader, class StorageClass> friend class SQLStorageLoaderBase;
+
+    public:
+        /**
+         * @brief
+         *
+         * @return const char
+         */
+        char const* GetTableName() const { return m_tableName; }
+        /**
+         * @brief
+         *
+         * @return const char
+         */
+        char const* EntryFieldName() const { return m_entry_field; }
+
+        /**
+         * @brief
+         *
+         * @param idx
+         * @return FieldFormat
+         */
+        FieldFormat GetDstFormat(uint32 idx) const { return (FieldFormat)m_dst_format[idx]; }
+        /**
+         * @brief
+         *
+         * @return const char
+         */
+        const char* GetDstFormat() const { return m_dst_format; }
+        /**
+         * @brief
+         *
+         * @param idx
+         * @return FieldFormat
+         */
+        FieldFormat GetSrcFormat(uint32 idx) const { return (FieldFormat)m_src_format[idx]; }
+        /**
+         * @brief
+         *
+         * @return const char
+         */
+        const char* GetSrcFormat() const { return m_src_format; }
+
+        /**
+         * @brief
+         *
+         * @return uint32
+         */
+        uint32 GetMaxEntry() const { return m_maxEntry; }
+        /**
+         * @brief
+         *
+         * @return uint32
+         */
+        uint32 GetRecordCount() const { return m_recordCount; }
+
+        template<typename T>
+        /**
+         * @brief
+         *
+         */
+        class SQLSIterator
+        {
+                friend class SQLStorageBase;
+
+            public:
+                /**
+                 * @brief
+                 *
+                 * @return const T
+                 */
+                T const* getValue() const { return reinterpret_cast<T const*>(pointer); }
+
+                /**
+                 * @brief
+                 *
+                 */
+                void operator ++() { pointer += recordSize; }
+                /**
+                 * @brief
+                 *
+                 * @return const T *operator
+                 */
+                T const* operator *() const { return getValue(); }
+                /**
+                 * @brief
+                 *
+                 * @return const T *operator ->
+                 */
+                T const* operator ->() const { return getValue(); }
+                /**
+                 * @brief
+                 *
+                 * @param r
+                 * @return bool operator
+                 */
+                bool operator <(const SQLSIterator& r) const { return pointer < r.pointer; }
+                /**
+                 * @brief
+                 *
+                 * @param r
+                 */
+                void operator =(const SQLSIterator& r) { pointer = r.pointer; recordSize = r.recordSize; }
+
+            private:
+                /**
+                 * @brief
+                 *
+                 * @param ptr
+                 * @param _recordSize
+                 */
+                SQLSIterator(char* ptr, uint32 _recordSize) : pointer(ptr), recordSize(_recordSize) {}
+                char* pointer; /**< TODO */
+                uint32 recordSize; /**< TODO */
+        };
+
+        template<typename T>
+        /**
+         * @brief
+         *
+         * @return SQLSIterator<T>
+         */
+        SQLSIterator<T> getDataBegin() const { return SQLSIterator<T>(m_data, m_recordSize); }
+        template<typename T>
+        /**
+         * @brief
+         *
+         * @return SQLSIterator<T>
+         */
+        SQLSIterator<T> getDataEnd() const { return SQLSIterator<T>(m_data + m_recordCount * m_recordSize, m_recordSize); }
+
+    protected:
+        /**
+         * @brief
+         *
+         */
+        SQLStorageBase();
+        /**
+         * @brief
+         *
+         */
+        virtual ~SQLStorageBase() { Free(); }
+
+        /**
+         * @brief
+         *
+         * @param tableName
+         * @param entry_field
+         * @param src_format
+         * @param dst_format
+         */
+        void Initialize(const char* tableName, const char* entry_field, const char* src_format, const char* dst_format);
+
+        /**
+         * @brief
+         *
+         * @return uint32
+         */
+        uint32 GetDstFieldCount() const { return m_dstFieldCount; }
+        /**
+         * @brief
+         *
+         * @return uint32
+         */
+        uint32 GetSrcFieldCount() const { return m_srcFieldCount; }
+        /**
+         * @brief
+         *
+         * @return uint32
+         */
+        uint32 GetRecordSize() const { return m_recordSize; }
+
+        /**
+         * @brief
+         *
+         * @param maxRecordId
+         * @param recordCount
+         * @param recordSize
+         */
+        virtual void prepareToLoad(uint32 maxRecordId, uint32 recordCount, uint32 recordSize);
+        /**
+         * @brief
+         *
+         * @param recordId
+         * @param record
+         */
+        virtual void JustCreatedRecord(uint32 recordId, char* record) = 0;
+        /**
+         * @brief
+         *
+         */
+        virtual void Free();
+
+    private:
+        /**
+         * @brief
+         *
+         * @param recordId
+         * @return char
+         */
+        char* createRecord(uint32 recordId);
+
+        // Information about the table
+        const char* m_tableName; /**< TODO */
+        const char* m_entry_field; /**< TODO */
+        const char* m_src_format; /**< TODO */
+        const char* m_dst_format; /**< TODO */
+
+        // Information about the records
+        uint32 m_dstFieldCount; /**< TODO */
+        uint32 m_srcFieldCount; /**< TODO */
+        uint32 m_recordCount; /**< TODO */
+        uint32 m_maxEntry; /**< TODO */
+        uint32 m_recordSize; /**< TODO */
+
+        // Data Storage
+        char* m_data; /**< TODO */
+};
+
+/**
+ * @brief
+ *
+ */
+class SQLStorage : public SQLStorageBase
+{
+        template<class DerivedLoader, class StorageClass> friend class SQLStorageLoaderBase;
+
+    public:
+        /**
+         * @brief
+         *
+         * @param fmt
+         * @param _entry_field
+         * @param sqlname
+         */
+        SQLStorage(const char* fmt, const char* _entry_field, const char* sqlname);
+
+        /**
+         * @brief
+         *
+         * @param src_fmt
+         * @param dst_fmt
+         * @param _entry_field
+         * @param sqlname
+         */
+        SQLStorage(const char* src_fmt, const char* dst_fmt, const char* _entry_field, const char* sqlname);
+
+        /**
+         * @brief
+         *
+         */
+        ~SQLStorage() { Free(); }
+
+        template<class T>
+        /**
+         * @brief
+         *
+         * @param id
+         * @return const T
+         */
+        T const* LookupEntry(uint32 id) const
+        {
+            if (id >= GetMaxEntry())
+            {
+                return NULL;
+            }
+            return reinterpret_cast<T const*>(m_Index[id]);
+        }
+
+        /**
+         * @brief
+         *
+         * @param error_at_empty
+         */
+        void Load(bool error_at_empty = true);
+
+        /**
+         * @brief
+         *
+         * @param id
+         */
+        void EraseEntry(uint32 id);
+
+    protected:
+        /**
+         * @brief
+         *
+         * @param maxRecordId
+         * @param recordCount
+         * @param recordSize
+         */
+        void prepareToLoad(uint32 maxRecordId, uint32 recordCount, uint32 recordSize) override;
+        /**
+         * @brief
+         *
+         * @param recordId
+         * @param record
+         */
+        void JustCreatedRecord(uint32 recordId, char* record) override
+        {
+            m_Index[recordId] = record;
+        }
+
+        /**
+         * @brief
+         *
+         */
+        void Free() override;
+
+    private:
+        char** m_Index; /**< Lookup access */
+};
+
+/**
+ * @brief
+ *
+ */
+class SQLHashStorage : public SQLStorageBase
+{
+        template<class DerivedLoader, class StorageClass> friend class SQLStorageLoaderBase;
+
+    public:
+        /**
+         * @brief
+         *
+         * @param fmt
+         * @param _entry_field
+         * @param sqlname
+         */
+        SQLHashStorage(const char* fmt, const char* _entry_field, const char* sqlname);
+        /**
+         * @brief
+         *
+         * @param src_fmt
+         * @param dst_fmt
+         * @param _entry_field
+         * @param sqlname
+         */
+        SQLHashStorage(const char* src_fmt, const char* dst_fmt, const char* _entry_field, const char* sqlname);
+
+        /**
+         * @brief
+         *
+         */
+        ~SQLHashStorage() { Free(); }
+
+        template<class T>
+        /**
+         * @brief
+         *
+         * @param id
+         * @return const T
+         */
+        T const* LookupEntry(uint32 id) const
+        {
+            RecordMap::const_iterator find = m_indexMap.find(id);
+            if (find != m_indexMap.end())
+            {
+                return reinterpret_cast<T const*>(find->second);
+            }
+            return NULL;
+        }
+
+        /**
+         * @brief
+         *
+         */
+        void Load();
+
+        /**
+         * @brief
+         *
+         * @param id
+         */
+        void EraseEntry(uint32 id);
+
+    protected:
+        /**
+         * @brief
+         *
+         * @param maxRecordId
+         * @param recordCount
+         * @param recordSize
+         */
+        void prepareToLoad(uint32 maxRecordId, uint32 recordCount, uint32 recordSize) override;
+        /**
+         * @brief
+         *
+         * @param recordId
+         * @param record
+         */
+        void JustCreatedRecord(uint32 recordId, char* record) override
+        {
+            m_indexMap[recordId] = record;
+        }
+
+        /**
+         * @brief
+         *
+         */
+        void Free() override;
+
+    private:
+        /**
+         * @brief
+         *
+         */
+        typedef UNORDERED_MAP < uint32 /*recordId*/, char* /*record*/ > RecordMap;
+        RecordMap m_indexMap; /**< TODO */
+};
+
+/**
+ * @brief
+ *
+ */
+class SQLMultiStorage : public SQLStorageBase
+{
+        template<class DerivedLoader, class StorageClass> friend class SQLStorageLoaderBase;
+        template<typename T> friend class SQLMultiSIterator;
+        template<typename T> friend class SQLMSIteratorBounds;
+
+    private:
+        /**
+         * @brief
+         *
+         */
+        typedef std::multimap < uint32 /*recordId*/, char* /*record*/ > RecordMultiMap;
+
+    public:
+        /**
+         * @brief
+         *
+         * @param fmt
+         * @param _entry_field
+         * @param sqlname
+         */
+        SQLMultiStorage(const char* fmt, const char* _entry_field, const char* sqlname);
+        /**
+         * @brief
+         *
+         * @param src_fmt
+         * @param dst_fmt
+         * @param _entry_field
+         * @param sqlname
+         */
+        SQLMultiStorage(const char* src_fmt, const char* dst_fmt, const char* _entry_field, const char* sqlname);
+
+        /**
+         * @brief
+         *
+         */
+        ~SQLMultiStorage() { Free(); }
+
+        // forward declaration
+        template<typename T> class SQLMSIteratorBounds;
+
+        template<typename T>
+        /**
+         * @brief
+         *
+         */
+        class SQLMultiSIterator
+        {
+                friend class SQLMultiStorage;
+                friend class SQLMSIteratorBounds<T>;
+
+            public:
+                /**
+                 * @brief
+                 *
+                 * @return const T
+                 */
+                T const* getValue() const { return reinterpret_cast<T const*>(citerator->second); }
+                /**
+                 * @brief
+                 *
+                 * @return uint32
+                 */
+                uint32 getKey() const { return citerator->first; }
+
+                /**
+                 * @brief
+                 *
+                 */
+                void operator ++() { ++citerator; }
+                /**
+                 * @brief
+                 *
+                 * @return const T *operator
+                 */
+                T const* operator *() const { return getValue(); }
+                /**
+                 * @brief
+                 *
+                 * @return const T *operator ->
+                 */
+                T const* operator ->() const { return getValue(); }
+                /**
+                 * @brief
+                 *
+                 * @param r
+                 * @return bool operator
+                 */
+                bool operator !=(const SQLMultiSIterator& r) const { return citerator != r.citerator; }
+                /**
+                 * @brief
+                 *
+                 * @param r
+                 * @return bool operator
+                 */
+                bool operator ==(const SQLMultiSIterator& r) const { return citerator == r.citerator; }
+
+            private:
+                /**
+                 * @brief
+                 *
+                 * @param _itr
+                 */
+                SQLMultiSIterator(RecordMultiMap::const_iterator _itr) : citerator(_itr) {}
+                RecordMultiMap::const_iterator citerator; /**< TODO */
+        };
+
+        template<typename T>
+        /**
+         * @brief
+         *
+         */
+        class SQLMSIteratorBounds
+        {
+                friend class SQLMultiStorage;
+
+            public:
+                const SQLMultiSIterator<T> first; /**< TODO */
+                const SQLMultiSIterator<T> second; /**< TODO */
+
+            private:
+                /**
+                 * @brief
+                 *
+                 * @param std::pair<RecordMultiMap::const_iterator
+                 * @param pair
+                 */
+                SQLMSIteratorBounds(std::pair<RecordMultiMap::const_iterator, RecordMultiMap::const_iterator> pair) : first(pair.first), second(pair.second) {}
+        };
+
+        template<typename T>
+        /**
+         * @brief
+         *
+         * @param key
+         * @return SQLMSIteratorBounds<T>
+         */
+        SQLMSIteratorBounds<T> getBounds(uint32 key) const { return SQLMSIteratorBounds<T>(m_indexMultiMap.equal_range(key)); }
+
+        /**
+         * @brief
+         *
+         */
+        void Load();
+
+        /**
+         * @brief
+         *
+         * @param id
+         */
+        void EraseEntry(uint32 id);
+
+    protected:
+        /**
+         * @brief
+         *
+         * @param maxRecordId
+         * @param recordCount
+         * @param recordSize
+         */
+        void prepareToLoad(uint32 maxRecordId, uint32 recordCount, uint32 recordSize) override;
+        /**
+         * @brief
+         *
+         * @param recordId
+         * @param record
+         */
+        void JustCreatedRecord(uint32 recordId, char* record) override
+        {
+            m_indexMultiMap.insert(RecordMultiMap::value_type(recordId, record));
+        }
+
+        /**
+         * @brief
+         *
+         */
+        void Free() override;
+
+    private:
+        RecordMultiMap m_indexMultiMap; /**< TODO */
+};
+
+template <class DerivedLoader, class StorageClass>
+/**
+ * @brief
+ *
+ */
+class SQLStorageLoaderBase
+{
+    public:
+        /**
+         * @brief
+         *
+         * @param storage
+         * @param error_at_empty
+         */
+        void Load(StorageClass& storage, bool error_at_empty = true);
+
+        template<class S, class D>
+        /**
+         * @brief
+         *
+         * @param field_pos
+         * @param src
+         * @param dst
+         */
+        void convert(uint32 field_pos, S src, D& dst);
+        template<class S>
+        /**
+         * @brief
+         *
+         * @param field_pos
+         * @param src
+         * @param dst
+         */
+        void convert_to_str(uint32 field_pos, S src, char*& dst);
+        template<class D>
+        /**
+         * @brief
+         *
+         * @param field_pos
+         * @param src
+         * @param dst
+         */
+        void convert_from_str(uint32 field_pos, char const* src, D& dst);
+        /**
+         * @brief
+         *
+         * @param field_pos
+         * @param src
+         * @param dst
+         */
+        void convert_str_to_str(uint32 field_pos, char const* src, char*& dst);
+        template<class S, class D>
+        /**
+         * @brief
+         *
+         * @param field_pos
+         * @param src
+         * @param dst
+         */
+        void default_fill(uint32 field_pos, S src, D& dst);
+        /**
+         * @brief
+         *
+         * @param field_pos
+         * @param src
+         * @param dst
+         */
+        void default_fill_to_str(uint32 field_pos, char const* src, char*& dst);
+
+        template<class D>
+        /**
+         * @brief trap, no body
+         *
+         * @param field_pos
+         * @param src
+         * @param dst
+         */
+        void convert_from_str(uint32 field_pos, char* src, D& dst);
+        /**
+         * @brief
+         *
+         * @param field_pos
+         * @param src
+         * @param dst
+         */
+        void convert_str_to_str(uint32 field_pos, char* src, char*& dst);
+
+    private:
+        template<class V>
+        /**
+         * @brief
+         *
+         * @param value
+         * @param store
+         * @param record
+         * @param field_pos
+         * @param offset
+         */
+        void storeValue(V value, StorageClass& store, char* record, uint32 field_pos, uint32& offset);
+        /**
+         * @brief
+         *
+         * @param value
+         * @param store
+         * @param record
+         * @param field_pos
+         * @param offset
+         */
+        void storeValue(char const* value, StorageClass& store, char* record, uint32 field_pos, uint32& offset);
+
+        /**
+         * @brief trap, no body
+         *
+         * @param value
+         * @param store
+         * @param record
+         * @param field_pos
+         * @param offset
+         */
+        void storeValue(char* value, StorageClass& store, char* record, uint32 field_pos, uint32& offset);
+};
+
+/**
+ * @brief
+ *
+ */
+class SQLStorageLoader : public SQLStorageLoaderBase<SQLStorageLoader, SQLStorage>
+{
+};
+
+/**
+ * @brief
+ *
+ */
+class SQLHashStorageLoader : public SQLStorageLoaderBase<SQLHashStorageLoader, SQLHashStorage>
+{
+};
+
+/**
+ * @brief
+ *
+ */
+class SQLMultiStorageLoader : public SQLStorageLoaderBase<SQLMultiStorageLoader, SQLMultiStorage>
+{
+};
+
+#include "SQLStorageImpl.h"
+
+#endif
diff --git a/shared/Database/SQLStorageImpl.h b/shared/Database/SQLStorageImpl.h
new file mode 100644
index 0000000..a75b551
--- /dev/null
+++ b/shared/Database/SQLStorageImpl.h
@@ -0,0 +1,414 @@
+/**
+ * MaNGOS is a full featured server for World of Warcraft, supporting
+ * the following clients: 1.12.x, 2.4.3, 3.3.5a, 4.3.4a and 5.4.8
+ *
+ * Copyright (C) 2005-2022 MaNGOS <https://getmangos.eu>
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * World of Warcraft, and all World of Warcraft or Warcraft art, images,
+ * and lore are copyrighted by Blizzard Entertainment, Inc.
+ */
+
+#ifndef SQLSTORAGE_IMPL_H
+#define SQLSTORAGE_IMPL_H
+
+#include "Utilities/ProgressBar.h"
+#include "Log/Log.h"
+#include "DataStores/DBCFileLoader.h"
+
+template<class DerivedLoader, class StorageClass>
+template<class S, class D>
+/**
+ * @brief S source-type, D destination-type
+ *
+ * @param uint32
+ * @param src
+ * @param dst
+ */
+void SQLStorageLoaderBase<DerivedLoader, StorageClass>::convert(uint32 /*field_pos*/, S src, D& dst)
+{
+#if defined(__arm__)
+    if (((unsigned) &dst) % sizeof(D)) {
+        //The address is not aligned. Use memcpy to avoid ARM unaligned trap
+       D converted(src);
+       memcpy((void*) &dst, (void*) &converted, sizeof(D));
+    }
+    else
+#endif
+
+    dst = D(src);
+}
+
+template<class DerivedLoader, class StorageClass>
+/**
+ * @brief
+ *
+ * @param uint32
+ * @param src
+ * @param dst
+ */
+void SQLStorageLoaderBase<DerivedLoader, StorageClass>::convert_str_to_str(uint32 /*field_pos*/, char const* src, char*& dst)
+{
+    if (!src)
+    {
+        dst = new char[1];
+        *dst = 0;
+    }
+    else
+    {
+        uint32 l = strlen(src) + 1;
+        dst = new char[l];
+        memcpy(dst, src, l);
+    }
+}
+
+template<class DerivedLoader, class StorageClass>
+template<class S>
+/**
+ * @brief S source-type
+ *
+ * @param uint32
+ * @param S
+ * @param dst
+ */
+void SQLStorageLoaderBase<DerivedLoader, StorageClass>::convert_to_str(uint32 /*field_pos*/, S /*src*/, char*& dst)
+{
+    dst = new char[1];
+    *dst = 0;
+}
+
+template<class DerivedLoader, class StorageClass>
+template<class D>
+/**
+ * @brief D destination-type
+ *
+ * @param uint32
+ * @param
+ * @param dst
+ */
+void SQLStorageLoaderBase<DerivedLoader, StorageClass>::convert_from_str(uint32 /*field_pos*/, char const* /*src*/, D& dst)
+{
+#if defined(__arm__)
+    if (((unsigned) &dst) % sizeof(D)) {
+       //The address is not aligned. Use memcpy to avoid ARM unaligned trap
+       D converted(0);
+       memcpy((void*) &dst, (void*) &converted, sizeof(D));
+    }
+    else
+#endif
+
+    dst = 0;
+}
+
+template<class DerivedLoader, class StorageClass>
+template<class S, class D>
+/**
+ * @brief S source-type, D destination-type
+ *
+ * @param uint32
+ * @param src
+ * @param dst
+ */
+void SQLStorageLoaderBase<DerivedLoader, StorageClass>::default_fill(uint32 /*field_pos*/, S src, D& dst)
+{
+#if defined(__arm__)
+    if (((unsigned) &dst) % sizeof(D)) {
+       //The address is not aligned. Use memcpy to avoid ARM unaligned trap
+       D converted(src);
+       memcpy((void*) &dst, (void*) &converted, sizeof(D));
+    }
+    else
+#endif
+
+    dst = D(src);
+}
+
+template<class DerivedLoader, class StorageClass>
+/**
+ * @brief
+ *
+ * @param uint32
+ * @param
+ * @param dst
+ */
+void SQLStorageLoaderBase<DerivedLoader, StorageClass>::default_fill_to_str(uint32 /*field_pos*/, char const* /*src*/, char*& dst)
+{
+    dst = new char[1];
+    *dst = 0;
+}
+
+template<class DerivedLoader, class StorageClass>
+template<class V>
+/**
+ * @brief V value-type
+ *
+ * @param value
+ * @param store
+ * @param p
+ * @param x
+ * @param offset
+ */
+void SQLStorageLoaderBase<DerivedLoader, StorageClass>::storeValue(V value, StorageClass& store, char* p, uint32 x, uint32& offset)
+{
+    DerivedLoader* subclass = (static_cast<DerivedLoader*>(this));
+    switch (store.GetDstFormat(x))
+    {
+        case DBC_FF_LOGIC:
+            subclass->convert(x, value, *((bool*)(&p[offset])));
+            offset += sizeof(bool);
+            break;
+        case DBC_FF_BYTE:
+            subclass->convert(x, value, *((char*)(&p[offset])));
+            offset += sizeof(char);
+            break;
+        case DBC_FF_INT:
+            subclass->convert(x, value, *((uint32*)(&p[offset])));
+            offset += sizeof(uint32);
+            break;
+        case DBC_FF_FLOAT:
+            subclass->convert(x, value, *((float*)(&p[offset])));
+            offset += sizeof(float);
+            break;
+        case DBC_FF_STRING:
+            subclass->convert_to_str(x, value, *((char**)(&p[offset])));
+            offset += sizeof(char*);
+            break;
+        case DBC_FF_NA:
+            subclass->default_fill(x, value, *((uint32*)(&p[offset])));
+            offset += sizeof(uint32);
+            break;
+        case DBC_FF_NA_BYTE:
+            subclass->default_fill(x, value, *((char*)(&p[offset])));
+            offset += sizeof(char);
+            break;
+        case DBC_FF_NA_FLOAT:
+            subclass->default_fill(x, value, *((float*)(&p[offset])));
+            offset += sizeof(float);
+            break;
+        case DBC_FF_IND:
+        case DBC_FF_SORT:
+            assert(false && "SQL storage does not have sort field types");
+            break;
+        default:
+            assert(false && "unknown format character");
+            break;
+    }
+}
+
+template<class DerivedLoader, class StorageClass>
+/**
+ * @brief
+ *
+ * @param value
+ * @param store
+ * @param p
+ * @param x
+ * @param offset
+ */
+void SQLStorageLoaderBase<DerivedLoader, StorageClass>::storeValue(char const* value, StorageClass& store, char* p, uint32 x, uint32& offset)
+{
+    DerivedLoader* subclass = (static_cast<DerivedLoader*>(this));
+    switch (store.GetDstFormat(x))
+    {
+        case DBC_FF_LOGIC:
+            subclass->convert_from_str(x, value, *((bool*)(&p[offset])));
+            offset += sizeof(bool);
+            break;
+        case DBC_FF_BYTE:
+            subclass->convert_from_str(x, value, *((char*)(&p[offset])));
+            offset += sizeof(char);
+            break;
+        case DBC_FF_INT:
+            subclass->convert_from_str(x, value, *((uint32*)(&p[offset])));
+            offset += sizeof(uint32);
+            break;
+        case DBC_FF_FLOAT:
+            subclass->convert_from_str(x, value, *((float*)(&p[offset])));
+            offset += sizeof(float);
+            break;
+        case DBC_FF_STRING:
+            subclass->convert_str_to_str(x, value, *((char**)(&p[offset])));
+            offset += sizeof(char*);
+            break;
+        case DBC_FF_NA_POINTER:
+            subclass->default_fill_to_str(x, value, *((char**)(&p[offset])));
+            offset += sizeof(char*);
+            break;
+        case DBC_FF_IND:
+        case DBC_FF_SORT:
+            assert(false && "SQL storage does not have sort field types");
+            break;
+        default:
+            assert(false && "unknown format character");
+            break;
+    }
+}
+
+template<class DerivedLoader, class StorageClass>
+/**
+ * @brief
+ *
+ * @param store
+ * @param error_at_empty
+ */
+void SQLStorageLoaderBase<DerivedLoader, StorageClass>::Load(StorageClass& store, bool error_at_empty /*= true*/)
+{
+    Field* fields = NULL;
+    QueryResult* result  = WorldDatabase.PQuery("SELECT MAX(`%s`) FROM `%s`", store.EntryFieldName(), store.GetTableName());
+    if (!result)
+    {
+        sLog.outError("Error loading %s table (not exist?)\n", store.GetTableName());
+        Log::WaitBeforeContinueIfNeed();
+        exit(1);                                            // Stop server at loading non existent table or inaccessible table
+    }
+
+    uint32 maxRecordId = (*result)[0].GetUInt32() + 1;
+    uint32 recordCount = 0;
+    uint32 recordsize = 0;
+    delete result;
+
+    result = WorldDatabase.PQuery("SELECT COUNT(*) FROM `%s`", store.GetTableName());
+    if (result)
+    {
+        fields = result->Fetch();
+        recordCount = fields[0].GetUInt32();
+        delete result;
+    }
+
+    result = WorldDatabase.PQuery("SELECT * FROM `%s`", store.GetTableName());
+
+    if (!result)
+    {
+        if (error_at_empty)
+        {
+            sLog.outError("%s table is empty!\n", store.GetTableName());
+        }
+        else
+        {
+            sLog.outString("%s table is empty!\n", store.GetTableName());
+        }
+
+        recordCount = 0;
+        return;
+    }
+
+    if (store.GetSrcFieldCount() != result->GetFieldCount())
+    {
+        recordCount = 0;
+        sLog.outError("Error in %s table.Perhaps the table structure was changed. There should be %d fields in the table.\n", store.GetTableName(), store.GetSrcFieldCount());
+        delete result;
+        Log::WaitBeforeContinueIfNeed();
+        exit(1);                                            // Stop server at loading broken or non-compatible table.
+    }
+
+    // get struct size
+    uint32 offset = 0;
+    for (uint32 x = 0; x < store.GetDstFieldCount(); ++x)
+    {
+        switch (store.GetDstFormat(x))
+        {
+            case DBC_FF_LOGIC:
+                recordsize += sizeof(bool);   break;
+            case DBC_FF_BYTE:
+                recordsize += sizeof(char);   break;
+            case DBC_FF_INT:
+                recordsize += sizeof(uint32); break;
+            case DBC_FF_FLOAT:
+                recordsize += sizeof(float);  break;
+            case DBC_FF_STRING:
+                recordsize += sizeof(char*);  break;
+            case DBC_FF_NA:
+                recordsize += sizeof(uint32); break;
+            case DBC_FF_NA_BYTE:
+                recordsize += sizeof(char);   break;
+            case DBC_FF_NA_FLOAT:
+                recordsize += sizeof(float);  break;
+            case DBC_FF_NA_POINTER:
+                recordsize += sizeof(char*);  break;
+            case DBC_FF_IND:
+            case DBC_FF_SORT:
+                assert(false && "SQL storage not have sort field types");
+                break;
+            default:
+                assert(false && "unknown format character");
+                break;
+        }
+    }
+
+    // Prepare data storage and lookup storage
+    store.prepareToLoad(maxRecordId, recordCount, recordsize);
+
+    BarGoLink bar(recordCount);
+    do
+    {
+        fields = result->Fetch();
+        bar.step();
+
+        char* record = store.createRecord(fields[0].GetUInt32());
+        offset = 0;
+
+        // dependend on dest-size
+        // iterate two indexes: x over dest, y over source
+        //                      y++ If and only If x != FT_NA*
+        //                      x++ If and only If a value is stored
+        for (uint32 x = 0, y = 0; x < store.GetDstFieldCount();)
+        {
+            switch (store.GetDstFormat(x))
+            {
+                // For default fill continue and do not increase y
+                case DBC_FF_NA:         storeValue((uint32)0, store, record, x, offset);         ++x; continue;
+                case DBC_FF_NA_BYTE:    storeValue((char)0, store, record, x, offset);           ++x; continue;
+                case DBC_FF_NA_FLOAT:   storeValue((float)0.0f, store, record, x, offset);       ++x; continue;
+                case DBC_FF_NA_POINTER: storeValue((char const*)NULL, store, record, x, offset); ++x; continue;
+                default:
+                    break;
+            }
+
+            // It is required that the input has at least as many columns set as the output requires
+            if (y >= store.GetSrcFieldCount())
+            {
+                assert(false && "SQL storage has too few columns!");
+            }
+
+            switch (store.GetSrcFormat(y))
+            {
+                case DBC_FF_LOGIC:  storeValue((bool)(fields[y].GetUInt32() > 0), store, record, x, offset);  ++x; break;
+                case DBC_FF_BYTE:   storeValue((char)fields[y].GetUInt8(), store, record, x, offset);         ++x; break;
+                case DBC_FF_INT:    storeValue((uint32)fields[y].GetUInt32(), store, record, x, offset);      ++x; break;
+                case DBC_FF_FLOAT:  storeValue((float)fields[y].GetFloat(), store, record, x, offset);        ++x; break;
+                case DBC_FF_STRING: storeValue((char const*)fields[y].GetString(), store, record, x, offset); ++x; break;
+                case DBC_FF_NA:
+                case DBC_FF_NA_BYTE:
+                case DBC_FF_NA_FLOAT:
+                    // Do Not increase x
+                    break;
+                case DBC_FF_IND:
+                case DBC_FF_SORT:
+                case DBC_FF_NA_POINTER:
+                    assert(false && "SQL storage not have sort or pointer field types");
+                    break;
+                default:
+                    assert(false && "unknown format character");
+            }
+            ++y;
+        }
+    }
+    while (result->NextRow());
+
+    delete result;
+}
+
+#endif
diff --git a/shared/Database/SqlDelayThread.cpp b/shared/Database/SqlDelayThread.cpp
new file mode 100644
index 0000000..4df599e
--- /dev/null
+++ b/shared/Database/SqlDelayThread.cpp
@@ -0,0 +1,84 @@
+/**
+ * MaNGOS is a full featured server for World of Warcraft, supporting
+ * the following clients: 1.12.x, 2.4.3, 3.3.5a, 4.3.4a and 5.4.8
+ *
+ * Copyright (C) 2005-2022 MaNGOS <https://getmangos.eu>
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * World of Warcraft, and all World of Warcraft or Warcraft art, images,
+ * and lore are copyrighted by Blizzard Entertainment, Inc.
+ */
+
+#include "Database/SqlDelayThread.h"
+#include "Database/SqlOperations.h"
+#include "DatabaseEnv.h"
+
+SqlDelayThread::SqlDelayThread(Database* db, SqlConnection* conn) : m_dbEngine(db), m_dbConnection(conn), m_running(true)
+{
+}
+
+SqlDelayThread::~SqlDelayThread()
+{
+    // process all requests which might have been queued while thread was stopping
+    ProcessRequests();
+}
+
+void SqlDelayThread::run()
+{
+#ifndef DO_POSTGRESQL
+    mysql_thread_init();
+#endif
+
+    const uint32 loopSleepms = 10;
+
+    const uint32 pingEveryLoop = m_dbEngine->GetPingIntervall() / loopSleepms;
+
+    uint32 loopCounter = 0;
+    while (m_running)
+    {
+        // if the running state gets turned off while sleeping
+        // empty the queue before exiting
+        ACE_Based::Thread::Sleep(loopSleepms);
+
+        ProcessRequests();
+
+        if ((loopCounter++) >= pingEveryLoop)
+        {
+            loopCounter = 0;
+            m_dbEngine->Ping();
+        }
+    }
+
+#ifndef DO_POSTGRESQL
+    mysql_thread_end();
+#endif
+
+}
+
+void SqlDelayThread::Stop()
+{
+    m_running = false;
+}
+
+void SqlDelayThread::ProcessRequests()
+{
+    SqlOperation* s = NULL;
+    while (m_sqlQueue.next(s))
+    {
+        s->Execute(m_dbConnection);
+        delete s;
+    }
+}
diff --git a/shared/Database/SqlDelayThread.h b/shared/Database/SqlDelayThread.h
new file mode 100644
index 0000000..01e8ebd
--- /dev/null
+++ b/shared/Database/SqlDelayThread.h
@@ -0,0 +1,93 @@
+/**
+ * MaNGOS is a full featured server for World of Warcraft, supporting
+ * the following clients: 1.12.x, 2.4.3, 3.3.5a, 4.3.4a and 5.4.8
+ *
+ * Copyright (C) 2005-2022 MaNGOS <https://getmangos.eu>
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * World of Warcraft, and all World of Warcraft or Warcraft art, images,
+ * and lore are copyrighted by Blizzard Entertainment, Inc.
+ */
+
+#ifndef MANGOS_H_SQLDELAYTHREAD
+#define MANGOS_H_SQLDELAYTHREAD
+
+#include <ace/Thread_Mutex.h>
+#include "LockedQueue/LockedQueue.h"
+#include "Threading/Threading.h"
+
+class Database;
+class SqlOperation;
+class SqlConnection;
+
+/**
+ * @brief
+ *
+ */
+class SqlDelayThread : public ACE_Based::Runnable
+{
+        /**
+         * @brief
+         *
+         */
+        typedef ACE_Based::LockedQueue<SqlOperation*, ACE_Thread_Mutex> SqlQueue;
+
+    private:
+        SqlQueue m_sqlQueue;                                /**< Queue of SQL statements */
+        Database* m_dbEngine;                               /**< Pointer to used Database engine */
+        SqlConnection* m_dbConnection;                      /**< Pointer to DB connection */
+        volatile bool m_running; /**< TODO */
+
+        /**
+         * @brief process all enqueued requests
+         *
+         */
+        void ProcessRequests();
+
+    public:
+        /**
+         * @brief
+         *
+         * @param db
+         * @param conn
+         */
+        SqlDelayThread(Database* db, SqlConnection* conn);
+        /**
+         * @brief
+         *
+         */
+        ~SqlDelayThread();
+
+        /**
+         * @brief Put sql statement to delay queue
+         *
+         * @param sql
+         * @return bool
+         */
+        bool Delay(SqlOperation* sql) { m_sqlQueue.add(sql); return true; }
+
+        /**
+         * @brief Stop event
+         *
+         */
+        virtual void Stop();
+        /**
+         * @brief Main Thread loop
+         *
+         */
+        virtual void run();
+};
+#endif                                                      //__SQLDELAYTHREAD_H
diff --git a/shared/Database/SqlOperations.cpp b/shared/Database/SqlOperations.cpp
new file mode 100644
index 0000000..76d1e85
--- /dev/null
+++ b/shared/Database/SqlOperations.cpp
@@ -0,0 +1,249 @@
+/**
+ * MaNGOS is a full featured server for World of Warcraft, supporting
+ * the following clients: 1.12.x, 2.4.3, 3.3.5a, 4.3.4a and 5.4.8
+ *
+ * Copyright (C) 2005-2022 MaNGOS <https://getmangos.eu>
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * World of Warcraft, and all World of Warcraft or Warcraft art, images,
+ * and lore are copyrighted by Blizzard Entertainment, Inc.
+ */
+
+#include "SqlOperations.h"
+#include "SqlDelayThread.h"
+#include "DatabaseEnv.h"
+#include "DatabaseImpl.h"
+
+#define LOCK_DB_CONN(conn) SqlConnection::Lock guard(conn)
+
+/// ---- ASYNC STATEMENTS / TRANSACTIONS ----
+
+bool SqlPlainRequest::Execute(SqlConnection* conn)
+{
+    /// just do it
+    LOCK_DB_CONN(conn);
+    return conn->Execute(m_sql);
+}
+
+SqlTransaction::~SqlTransaction()
+{
+    while (!m_queue.empty())
+    {
+        delete m_queue.back();
+        m_queue.pop_back();
+    }
+}
+
+bool SqlTransaction::Execute(SqlConnection* conn)
+{
+    if (m_queue.empty())
+    {
+        return true;
+    }
+
+    LOCK_DB_CONN(conn);
+
+    conn->BeginTransaction();
+
+    const int nItems = m_queue.size();
+    for (int i = 0; i < nItems; ++i)
+    {
+        SqlOperation* pStmt = m_queue[i];
+
+        if (!pStmt->Execute(conn))
+        {
+            conn->RollbackTransaction();
+            return false;
+        }
+    }
+
+    return conn->CommitTransaction();
+}
+
+SqlPreparedRequest::SqlPreparedRequest(int nIndex, SqlStmtParameters* arg) : m_nIndex(nIndex), m_param(arg)
+{
+}
+
+SqlPreparedRequest::~SqlPreparedRequest()
+{
+    delete m_param;
+}
+
+bool SqlPreparedRequest::Execute(SqlConnection* conn)
+{
+    LOCK_DB_CONN(conn);
+    return conn->ExecuteStmt(m_nIndex, *m_param);
+}
+
+/// ---- ASYNC QUERIES ----
+
+bool SqlQuery::Execute(SqlConnection* conn)
+{
+    if (!m_callback || !m_queue)
+    {
+        return false;
+    }
+
+    LOCK_DB_CONN(conn);
+    /// execute the query and store the result in the callback
+    m_callback->SetResult(conn->Query(m_sql));
+    /// add the callback to the sql result queue of the thread it originated from
+    m_queue->add(m_callback);
+
+    return true;
+}
+
+void SqlResultQueue::Update()
+{
+    /// execute the callbacks waiting in the synchronization queue
+    MaNGOS::IQueryCallback* callback = NULL;
+    while (next(callback))
+    {
+        callback->Execute();
+        delete callback;
+    }
+}
+
+bool SqlQueryHolder::Execute(MaNGOS::IQueryCallback* callback, SqlDelayThread* thread, SqlResultQueue* queue)
+{
+    if (!callback || !thread || !queue)
+    {
+        return false;
+    }
+
+    /// delay the execution of the queries, sync them with the delay thread
+    /// which will in turn resync on execution (via the queue) and call back
+    SqlQueryHolderEx* holderEx = new SqlQueryHolderEx(this, callback, queue);
+    thread->Delay(holderEx);
+    return true;
+}
+
+bool SqlQueryHolder::SetQuery(size_t index, const char* sql)
+{
+    if (m_queries.size() <= index)
+    {
+        sLog.outError("Query index (" SIZEFMTD ") out of range (size: " SIZEFMTD ") for query: %s", index, m_queries.size(), sql);
+        return false;
+    }
+
+    if (m_queries[index].first != NULL)
+    {
+        sLog.outError("Attempt assign query to holder index (" SIZEFMTD ") where other query stored (Old: [%s] New: [%s])",
+                      index, m_queries[index].first, sql);
+        return false;
+    }
+
+    /// not executed yet, just stored (it's not called a holder for nothing)
+    m_queries[index] = SqlResultPair(mangos_strdup(sql), (QueryResult*)NULL);
+    return true;
+}
+
+bool SqlQueryHolder::SetPQuery(size_t index, const char* format, ...)
+{
+    if (!format)
+    {
+        sLog.outError("Query (index: " SIZEFMTD ") is empty.", index);
+        return false;
+    }
+
+    va_list ap;
+    char szQuery [MAX_QUERY_LEN];
+    va_start(ap, format);
+    int res = vsnprintf(szQuery, MAX_QUERY_LEN, format, ap);
+    va_end(ap);
+
+    if (res == -1)
+    {
+        sLog.outError("SQL Query truncated (and not execute) for format: %s", format);
+        return false;
+    }
+
+    return SetQuery(index, szQuery);
+}
+
+QueryResult* SqlQueryHolder::GetResult(size_t index)
+{
+    if (index < m_queries.size())
+    {
+        /// the query strings are freed on the first GetResult or in the destructor
+        if (m_queries[index].first != NULL)
+        {
+            delete[](const_cast<char*>(m_queries[index].first));
+            m_queries[index].first = NULL;
+        }
+        /// when you get a result aways remember to delete it!
+        return m_queries[index].second;
+    }
+    else
+    {
+        return NULL;
+    }
+}
+
+void SqlQueryHolder::SetResult(size_t index, QueryResult* result)
+{
+    /// store the result in the holder
+    if (index < m_queries.size())
+    {
+        m_queries[index].second = result;
+    }
+}
+
+SqlQueryHolder::~SqlQueryHolder()
+{
+    for (size_t i = 0; i < m_queries.size(); ++i)
+    {
+        /// if the result was never used, free the resources
+        /// results used already (getresult called) are expected to be deleted
+        if (m_queries[i].first != NULL)
+        {
+            delete[](const_cast<char*>(m_queries[i].first));
+            delete m_queries[i].second;
+        }
+    }
+}
+
+void SqlQueryHolder::SetSize(size_t size)
+{
+    /// to optimize push_back, reserve the number of queries about to be executed
+    m_queries.resize(size);
+}
+
+bool SqlQueryHolderEx::Execute(SqlConnection* conn)
+{
+    if (!m_holder || !m_callback || !m_queue)
+    {
+        return false;
+    }
+
+    LOCK_DB_CONN(conn);
+    /// we can do this, we are friends
+    std::vector<SqlQueryHolder::SqlResultPair>& queries = m_holder->m_queries;
+    for (size_t i = 0; i < queries.size(); ++i)
+    {
+        /// execute all queries in the holder and pass the results
+        char const* sql = queries[i].first;
+        if (sql)
+        {
+            m_holder->SetResult(i, conn->Query(sql));
+        }
+    }
+
+    /// sync with the caller thread
+    m_queue->add(m_callback);
+
+    return true;
+}
diff --git a/shared/Database/SqlOperations.h b/shared/Database/SqlOperations.h
new file mode 100644
index 0000000..40e72af
--- /dev/null
+++ b/shared/Database/SqlOperations.h
@@ -0,0 +1,330 @@
+/**
+ * MaNGOS is a full featured server for World of Warcraft, supporting
+ * the following clients: 1.12.x, 2.4.3, 3.3.5a, 4.3.4a and 5.4.8
+ *
+ * Copyright (C) 2005-2022 MaNGOS <https://getmangos.eu>
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * World of Warcraft, and all World of Warcraft or Warcraft art, images,
+ * and lore are copyrighted by Blizzard Entertainment, Inc.
+ */
+
+#ifndef MANGOS_H_SQLOPERATIONS
+#define MANGOS_H_SQLOPERATIONS
+
+#include "Common/Common.h"
+
+#include <ace/Thread_Mutex.h>
+#include "LockedQueue/LockedQueue.h"
+#include <queue>
+#include "Utilities/Callback.h"
+
+/// ---- BASE ---
+
+class Database;
+class SqlConnection;
+class SqlDelayThread;
+class SqlStmtParameters;
+
+/**
+ * @brief
+ *
+ */
+class SqlOperation
+{
+    public:
+        /**
+         * @brief
+         *
+         */
+        virtual void OnRemove() { delete this; }
+        /**
+         * @brief
+         *
+         * @param conn
+         * @return bool
+         */
+        virtual bool Execute(SqlConnection* conn) = 0;
+        /**
+         * @brief
+         *
+         */
+        virtual ~SqlOperation() {}
+};
+
+/// ---- ASYNC STATEMENTS / TRANSACTIONS ----
+
+/**
+ * @brief
+ *
+ */
+class SqlPlainRequest : public SqlOperation
+{
+    private:
+        const char* m_sql; /**< TODO */
+    public:
+        /**
+         * @brief
+         *
+         * @param sql
+         */
+        SqlPlainRequest(const char* sql) : m_sql(mangos_strdup(sql)) {}
+        /**
+         * @brief
+         *
+         */
+        ~SqlPlainRequest() { char* tofree = const_cast<char*>(m_sql); delete[] tofree; }
+        /**
+         * @brief
+         *
+         * @param conn
+         * @return bool
+         */
+        bool Execute(SqlConnection* conn) override;
+};
+
+/**
+ * @brief
+ *
+ */
+class SqlTransaction : public SqlOperation
+{
+    private:
+        std::vector<SqlOperation* > m_queue; /**< TODO */
+
+    public:
+        /**
+         * @brief
+         *
+         */
+        SqlTransaction() {}
+        /**
+         * @brief
+         *
+         */
+        ~SqlTransaction();
+
+        /**
+         * @brief
+         *
+         * @param sql
+         */
+        void DelayExecute(SqlOperation* sql) { m_queue.push_back(sql); }
+
+        /**
+         * @brief
+         *
+         * @param conn
+         * @return bool
+         */
+        bool Execute(SqlConnection* conn) override;
+};
+
+/**
+ * @brief
+ *
+ */
+class SqlPreparedRequest : public SqlOperation
+{
+    public:
+        /**
+         * @brief
+         *
+         * @param nIndex
+         * @param arg
+         */
+        SqlPreparedRequest(int nIndex, SqlStmtParameters* arg);
+        /**
+         * @brief
+         *
+         */
+        ~SqlPreparedRequest();
+
+        /**
+         * @brief
+         *
+         * @param conn
+         * @return bool
+         */
+        bool Execute(SqlConnection* conn) override;
+
+    private:
+        const int m_nIndex; /**< TODO */
+        SqlStmtParameters* m_param; /**< TODO */
+};
+
+/// ---- ASYNC QUERIES ----
+
+class SqlQuery;                                             /// contains a single async query
+class QueryResult;                                          /// the result of one
+class SqlResultQueue;                                       /// queue for thread sync
+class SqlQueryHolder;                                       /// groups several async quries
+class SqlQueryHolderEx;                                     /// points to a holder, added to the delay thread
+
+/**
+ * @brief
+ *
+ */
+class SqlResultQueue : public ACE_Based::LockedQueue<MaNGOS::IQueryCallback* , ACE_Thread_Mutex>
+{
+    public:
+        /**
+         * @brief
+         *
+         */
+        SqlResultQueue() {}
+        /**
+         * @brief
+         *
+         */
+        void Update();
+};
+
+/**
+ * @brief
+ *
+ */
+class SqlQuery : public SqlOperation
+{
+    private:
+        const char* m_sql; /**< TODO */
+        MaNGOS::IQueryCallback* m_callback; /**< TODO */
+        SqlResultQueue* m_queue; /**< TODO */
+    public:
+        /**
+         * @brief
+         *
+         * @param sql
+         * @param callback
+         * @param queue
+         */
+        SqlQuery(const char* sql, MaNGOS::IQueryCallback* callback, SqlResultQueue* queue)
+            : m_sql(mangos_strdup(sql)), m_callback(callback), m_queue(queue) {}
+        /**
+         * @brief
+         *
+         */
+        ~SqlQuery() { char* tofree = const_cast<char*>(m_sql); delete[] tofree; }
+        /**
+         * @brief
+         *
+         * @param conn
+         * @return bool
+         */
+        bool Execute(SqlConnection* conn) override;
+};
+
+/**
+ * @brief
+ *
+ */
+class SqlQueryHolder
+{
+        friend class SqlQueryHolderEx;
+    private:
+        /**
+         * @brief
+         *
+         */
+        typedef std::pair<const char*, QueryResult*> SqlResultPair;
+        std::vector<SqlResultPair> m_queries; /**< TODO */
+    public:
+        /**
+         * @brief
+         *
+         */
+        SqlQueryHolder() {}
+        /**
+         * @brief
+         *
+         */
+        ~SqlQueryHolder();
+        /**
+         * @brief
+         *
+         * @param index
+         * @param sql
+         * @return bool
+         */
+        bool SetQuery(size_t index, const char* sql);
+        /**
+         * @brief
+         *
+         * @param index
+         * @param format...
+         * @return bool
+         */
+        bool SetPQuery(size_t index, const char* format, ...) ATTR_PRINTF(3, 4);
+        /**
+         * @brief
+         *
+         * @param size
+         */
+        void SetSize(size_t size);
+        /**
+         * @brief
+         *
+         * @param index
+         * @return QueryResult
+         */
+        QueryResult* GetResult(size_t index);
+        /**
+         * @brief
+         *
+         * @param index
+         * @param result
+         */
+        void SetResult(size_t index, QueryResult* result);
+        /**
+         * @brief
+         *
+         * @param callback
+         * @param thread
+         * @param queue
+         * @return bool
+         */
+        bool Execute(MaNGOS::IQueryCallback* callback, SqlDelayThread* thread, SqlResultQueue* queue);
+};
+
+/**
+ * @brief
+ *
+ */
+class SqlQueryHolderEx : public SqlOperation
+{
+    private:
+        SqlQueryHolder* m_holder; /**< TODO */
+        MaNGOS::IQueryCallback* m_callback; /**< TODO */
+        SqlResultQueue* m_queue; /**< TODO */
+    public:
+        /**
+         * @brief
+         *
+         * @param holder
+         * @param callback
+         * @param queue
+         */
+        SqlQueryHolderEx(SqlQueryHolder* holder, MaNGOS::IQueryCallback* callback, SqlResultQueue* queue)
+            : m_holder(holder), m_callback(callback), m_queue(queue) {}
+        /**
+         * @brief
+         *
+         * @param conn
+         * @return bool
+         */
+        bool Execute(SqlConnection* conn) override;
+};
+#endif                                                      //__SQLOPERATIONS_H
diff --git a/shared/Database/SqlPreparedStatement.cpp b/shared/Database/SqlPreparedStatement.cpp
new file mode 100644
index 0000000..2afba8b
--- /dev/null
+++ b/shared/Database/SqlPreparedStatement.cpp
@@ -0,0 +1,172 @@
+/**
+ * MaNGOS is a full featured server for World of Warcraft, supporting
+ * the following clients: 1.12.x, 2.4.3, 3.3.5a, 4.3.4a and 5.4.8
+ *
+ * Copyright (C) 2005-2022 MaNGOS <https://getmangos.eu>
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * World of Warcraft, and all World of Warcraft or Warcraft art, images,
+ * and lore are copyrighted by Blizzard Entertainment, Inc.
+ */
+
+#include "DatabaseEnv.h"
+
+SqlStmtParameters::SqlStmtParameters(uint32 nParams)
+{
+    // reserve memory if needed
+    if (nParams > 0)
+    {
+        m_params.reserve(nParams);
+    }
+}
+
+void SqlStmtParameters::reset(const SqlStatement& stmt)
+{
+    m_params.clear();
+    // reserve memory if needed
+    if (stmt.arguments() > 0)
+    {
+        m_params.reserve(stmt.arguments());
+    }
+}
+
+//////////////////////////////////////////////////////////////////////////
+SqlStatement& SqlStatement::operator=(const SqlStatement& index)
+{
+    if (this != &index)
+    {
+        m_index = index.m_index;
+        m_pDB = index.m_pDB;
+
+        delete m_pParams;
+        m_pParams = NULL;
+
+        if (index.m_pParams)
+        {
+            m_pParams = new SqlStmtParameters(*(index.m_pParams));
+        }
+    }
+
+    return *this;
+}
+
+bool SqlStatement::Execute()
+{
+    SqlStmtParameters* args = detach();
+    // verify amount of bound parameters
+    if (args->boundParams() != arguments())
+    {
+        sLog.outError("SQL ERROR: wrong amount of parameters (%i instead of %i)", args->boundParams(), arguments());
+        sLog.outError("SQL ERROR: statement: %s", m_pDB->GetStmtString(ID()).c_str());
+        MANGOS_ASSERT(false);
+        return false;
+    }
+
+    return m_pDB->ExecuteStmt(m_index, args);
+}
+
+bool SqlStatement::DirectExecute()
+{
+    SqlStmtParameters* args = detach();
+    // verify amount of bound parameters
+    if (args->boundParams() != arguments())
+    {
+        sLog.outError("SQL ERROR: wrong amount of parameters (%i instead of %i)", args->boundParams(), arguments());
+        sLog.outError("SQL ERROR: statement: %s", m_pDB->GetStmtString(ID()).c_str());
+        MANGOS_ASSERT(false);
+        return false;
+    }
+
+    return m_pDB->DirectExecuteStmt(m_index, args);
+}
+
+//////////////////////////////////////////////////////////////////////////
+SqlPlainPreparedStatement::SqlPlainPreparedStatement(const std::string& fmt, SqlConnection& conn) : SqlPreparedStatement(fmt, conn)
+{
+    m_bPrepared = true;
+    m_nParams = std::count(m_szFmt.begin(), m_szFmt.end(), '?');
+    m_bIsQuery = strnicmp(m_szFmt.c_str(), "select", 6) == 0;
+}
+
+void SqlPlainPreparedStatement::bind(const SqlStmtParameters& holder)
+{
+    // verify if we bound all needed input parameters
+    if (m_nParams != holder.boundParams())
+    {
+        MANGOS_ASSERT(false);
+        return;
+    }
+
+    // reset resulting plain SQL request
+    m_szPlainRequest = m_szFmt;
+    size_t nLastPos = 0;
+
+    SqlStmtParameters::ParameterContainer const& _args = holder.params();
+
+    SqlStmtParameters::ParameterContainer::const_iterator iter_last = _args.end();
+    for (SqlStmtParameters::ParameterContainer::const_iterator iter = _args.begin(); iter != iter_last; ++iter)
+    {
+        // bind parameter
+        const SqlStmtFieldData& data = (*iter);
+
+        std::ostringstream fmt;
+        DataToString(data, fmt);
+
+        nLastPos = m_szPlainRequest.find('?', nLastPos);
+        if (nLastPos != std::string::npos)
+        {
+            std::string tmp = fmt.str();
+            m_szPlainRequest.replace(nLastPos, 1, tmp);
+            nLastPos += tmp.length();
+        }
+    }
+}
+
+bool SqlPlainPreparedStatement::execute()
+{
+    if (m_szPlainRequest.empty())
+    {
+        return false;
+    }
+
+    return m_pConn.Execute(m_szPlainRequest.c_str());
+}
+
+void SqlPlainPreparedStatement::DataToString(const SqlStmtFieldData& data, std::ostringstream& fmt)
+{
+    switch (data.type())
+    {
+        case FIELD_BOOL:    fmt << "'" << uint32(data.toBool()) << "'";     break;
+        case FIELD_UI8:     fmt << "'" << uint32(data.toUint8()) << "'";    break;
+        case FIELD_UI16:    fmt << "'" << uint32(data.toUint16()) << "'";   break;
+        case FIELD_UI32:    fmt << "'" << data.toUint32() << "'";           break;
+        case FIELD_UI64:    fmt << "'" << data.toUint64() << "'";           break;
+        case FIELD_I8:      fmt << "'" << int32(data.toInt8()) << "'";      break;
+        case FIELD_I16:     fmt << "'" << int32(data.toInt16()) << "'";     break;
+        case FIELD_I32:     fmt << "'" << data.toInt32() << "'";            break;
+        case FIELD_I64:     fmt << "'" << data.toInt64() << "'";            break;
+        case FIELD_FLOAT:   fmt << "'" << data.toFloat() << "'";            break;
+        case FIELD_DOUBLE:  fmt << "'" << data.toDouble() << "'";           break;
+        case FIELD_STRING:
+        {
+            std::string tmp = data.toStr();
+            m_pConn.DB().escape_string(tmp);
+            fmt << "'" << tmp << "'";
+            break;
+        }
+        case FIELD_NONE:                                                    break;
+    }
+}
diff --git a/shared/Database/SqlPreparedStatement.h b/shared/Database/SqlPreparedStatement.h
new file mode 100644
index 0000000..2d93190
--- /dev/null
+++ b/shared/Database/SqlPreparedStatement.h
@@ -0,0 +1,832 @@
+/**
+ * MaNGOS is a full featured server for World of Warcraft, supporting
+ * the following clients: 1.12.x, 2.4.3, 3.3.5a, 4.3.4a and 5.4.8
+ *
+ * Copyright (C) 2005-2022 MaNGOS <https://getmangos.eu>
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * World of Warcraft, and all World of Warcraft or Warcraft art, images,
+ * and lore are copyrighted by Blizzard Entertainment, Inc.
+ */
+
+#ifndef SQLPREPAREDSTATEMENTS_H
+#define SQLPREPAREDSTATEMENTS_H
+
+#include "Common/Common.h"
+#include "Utilities/Errors.h"
+#include <ace/TSS_T.h>
+#include <vector>
+#include <stdexcept>
+
+class Database;
+class SqlConnection;
+class QueryResult;
+
+/**
+ * @brief
+ *
+ */
+union SqlStmtField
+{
+    bool boolean; /**< TODO */
+    uint8 ui8; /**< TODO */
+    int8 i8; /**< TODO */
+    uint16 ui16; /**< TODO */
+    int16 i16; /**< TODO */
+    uint32 ui32; /**< TODO */
+    int32 i32; /**< TODO */
+    uint64 ui64; /**< TODO */
+    int64 i64; /**< TODO */
+    float f; /**< TODO */
+    double d; /**< TODO */
+};
+
+/**
+ * @brief
+ *
+ */
+enum SqlStmtFieldType
+{
+    FIELD_BOOL,
+    FIELD_UI8,
+    FIELD_UI16,
+    FIELD_UI32,
+    FIELD_UI64,
+    FIELD_I8,
+    FIELD_I16,
+    FIELD_I32,
+    FIELD_I64,
+    FIELD_FLOAT,
+    FIELD_DOUBLE,
+    FIELD_STRING,
+    FIELD_NONE
+};
+
+/**
+ * @brief templates might be the best choice here
+ *
+ */
+class SqlStmtFieldData
+{
+    public:
+        /**
+         * @brief
+         *
+         */
+        SqlStmtFieldData() : m_type(FIELD_NONE) { m_binaryData.ui64 = 0; }
+        /**
+         * @brief
+         *
+         */
+        ~SqlStmtFieldData() {}
+
+        template<typename T>
+        /**
+         * @brief
+         *
+         * @param param
+         */
+        SqlStmtFieldData(T param) { set(param); }
+
+        template<typename T1>
+        /**
+         * @brief
+         *
+         * @param param1
+         */
+        void set(T1 param1);
+
+        /**
+         * @brief getter
+         *
+         * @return bool
+         */
+        bool toBool() const { MANGOS_ASSERT(m_type == FIELD_BOOL); return static_cast<bool>(m_binaryData.ui8); }
+        /**
+         * @brief getter
+         *
+         * @return uint8
+         */
+        uint8 toUint8() const { MANGOS_ASSERT(m_type == FIELD_UI8); return m_binaryData.ui8; }
+        /**
+         * @brief getter
+         *
+         * @return int8
+         */
+        int8 toInt8() const { MANGOS_ASSERT(m_type == FIELD_I8); return m_binaryData.i8; }
+        /**
+         * @brief getter
+         *
+         * @return uint16
+         */
+        uint16 toUint16() const { MANGOS_ASSERT(m_type == FIELD_UI16); return m_binaryData.ui16; }
+        /**
+         * @brief getter
+         *
+         * @return int16
+         */
+        int16 toInt16() const { MANGOS_ASSERT(m_type == FIELD_I16); return m_binaryData.i16; }
+        /**
+         * @brief getter
+         *
+         * @return uint32
+         */
+        uint32 toUint32() const { MANGOS_ASSERT(m_type == FIELD_UI32); return m_binaryData.ui32; }
+        /**
+         * @brief getter
+         *
+         * @return int32
+         */
+        int32 toInt32() const { MANGOS_ASSERT(m_type == FIELD_I32); return m_binaryData.i32; }
+        /**
+         * @brief getter
+         *
+         * @return uint64
+         */
+        uint64 toUint64() const { MANGOS_ASSERT(m_type == FIELD_UI64); return m_binaryData.ui64; }
+        /**
+         * @brief getter
+         *
+         * @return int64
+         */
+        int64 toInt64() const { MANGOS_ASSERT(m_type == FIELD_I64); return m_binaryData.i64; }
+        /**
+         * @brief getter
+         *
+         * @return float
+         */
+        float toFloat() const { MANGOS_ASSERT(m_type == FIELD_FLOAT); return m_binaryData.f; }
+        /**
+         * @brief getter
+         *
+         * @return double
+         */
+        double toDouble() const { MANGOS_ASSERT(m_type == FIELD_DOUBLE); return m_binaryData.d; }
+        /**
+         * @brief getter
+         *
+         * @return const char
+         */
+        const char* toStr() const { MANGOS_ASSERT(m_type == FIELD_STRING); return m_szStringData.c_str(); }
+
+        /**
+         * @brief get type of data
+         *
+         * @return SqlStmtFieldType
+         */
+        SqlStmtFieldType type() const { return m_type; }
+        /**
+         * @brief get underlying buffer type
+         *
+         */
+        void* buff() const { return m_type == FIELD_STRING ? (void*)m_szStringData.c_str() : (void*)&m_binaryData; }
+
+        /**
+         * @brief get size of data
+         *
+         * @return size_t
+         */
+        size_t size() const
+        {
+            switch (m_type)
+            {
+                case FIELD_NONE:    return 0;
+                case FIELD_BOOL:    // return sizeof(bool);
+                case FIELD_UI8:     return sizeof(uint8);
+                case FIELD_UI16:    return sizeof(uint16);
+                case FIELD_UI32:    return sizeof(uint32);
+                case FIELD_UI64:    return sizeof(uint64);
+                case FIELD_I8:      return sizeof(int8);
+                case FIELD_I16:     return sizeof(int16);
+                case FIELD_I32:     return sizeof(int32);
+                case FIELD_I64:     return sizeof(int64);
+                case FIELD_FLOAT:   return sizeof(float);
+                case FIELD_DOUBLE:  return sizeof(double);
+                case FIELD_STRING:  return m_szStringData.length();
+
+                default:
+                    throw std::runtime_error("unrecognized type of SqlStmtFieldType obtained");
+            }
+        }
+
+    private:
+        SqlStmtFieldType m_type; /**< TODO */
+        SqlStmtField m_binaryData; /**< TODO */
+        std::string m_szStringData; /**< TODO */
+};
+
+// template specialization
+/**
+ * @brief
+ *
+ * @param val
+ */
+template<> inline void SqlStmtFieldData::set(bool val) { m_type = FIELD_BOOL; m_binaryData.ui8 = val; }
+/**
+ * @brief
+ *
+ * @param val
+ */
+template<> inline void SqlStmtFieldData::set(uint8 val) { m_type = FIELD_UI8; m_binaryData.ui8 = val; }
+/**
+ * @brief
+ *
+ * @param val
+ */
+template<> inline void SqlStmtFieldData::set(int8 val) { m_type = FIELD_I8; m_binaryData.i8 = val; }
+/**
+ * @brief
+ *
+ * @param val
+ */
+template<> inline void SqlStmtFieldData::set(uint16 val) { m_type = FIELD_UI16; m_binaryData.ui16 = val; }
+/**
+ * @brief
+ *
+ * @param val
+ */
+template<> inline void SqlStmtFieldData::set(int16 val) { m_type = FIELD_I16; m_binaryData.i16 = val; }
+/**
+ * @brief
+ *
+ * @param val
+ */
+template<> inline void SqlStmtFieldData::set(uint32 val) { m_type = FIELD_UI32; m_binaryData.ui32 = val; }
+/**
+ * @brief
+ *
+ * @param val
+ */
+template<> inline void SqlStmtFieldData::set(int32 val) { m_type = FIELD_I32; m_binaryData.i32 = val; }
+/**
+ * @brief
+ *
+ * @param val
+ */
+template<> inline void SqlStmtFieldData::set(uint64 val) { m_type = FIELD_UI64; m_binaryData.ui64 = val; }
+/**
+ * @brief
+ *
+ * @param val
+ */
+template<> inline void SqlStmtFieldData::set(int64 val) { m_type = FIELD_I64; m_binaryData.i64 = val; }
+/**
+ * @brief
+ *
+ * @param val
+ */
+template<> inline void SqlStmtFieldData::set(float val) { m_type = FIELD_FLOAT; m_binaryData.f = val; }
+/**
+ * @brief
+ *
+ * @param val
+ */
+template<> inline void SqlStmtFieldData::set(double val) { m_type = FIELD_DOUBLE; m_binaryData.d = val; }
+/**
+ * @brief
+ *
+ * @param val
+ */
+template<> inline void SqlStmtFieldData::set(const char* val) { m_type = FIELD_STRING; m_szStringData = val; }
+
+class SqlStatement;
+// prepared statement executor
+/**
+ * @brief
+ *
+ */
+class SqlStmtParameters
+{
+    public:
+        /**
+         * @brief
+         *
+         */
+        typedef std::vector<SqlStmtFieldData> ParameterContainer;
+
+        /**
+         * @brief reserve memory to contain all input parameters of stmt
+         *
+         * @param nParams
+         */
+        explicit SqlStmtParameters(uint32 nParams);
+
+        /**
+         * @brief
+         *
+         */
+        ~SqlStmtParameters() {}
+
+        /**
+         * @brief get amount of bound parameters
+         *
+         * @return uint32
+         */
+        uint32 boundParams() const { return m_params.size(); }
+
+        /**
+         * @brief add parameter
+         *
+         * @param data
+         */
+        void addParam(const SqlStmtFieldData& data) { m_params.push_back(data); }
+
+        /**
+         * @brief empty SQL statement parameters.
+         *
+         * In case nParams > 1 - reserve memory for parameters should help to
+         * reuse the same object with batched SQL requests
+         *
+         * @param stmt
+         */
+        void reset(const SqlStatement& stmt);
+        /**
+         * @brief swaps contents of internal param container
+         *
+         * @param obj
+         */
+        void swap(SqlStmtParameters& obj);
+        /**
+         * @brief get bound parameters
+         *
+         * @return const ParameterContainer
+         */
+        const ParameterContainer& params() const { return m_params; }
+
+    private:
+        /**
+         * @brief
+         *
+         * @param obj
+         * @return SqlStmtParameters &operator
+         */
+        SqlStmtParameters& operator=(const SqlStmtParameters& obj);
+
+        ParameterContainer m_params; /**< statement parameter holder */
+};
+
+/**
+ * @brief statement ID encapsulation logic
+ *
+ */
+class SqlStatementID
+{
+    public:
+        /**
+         * @brief
+         *
+         */
+        SqlStatementID() : m_bInitialized(false) {}
+
+        /**
+         * @brief
+         *
+         * @return int
+         */
+        int ID() const { return m_nIndex; }
+        /**
+         * @brief
+         *
+         * @return uint32
+         */
+        uint32 arguments() const { return m_nArguments; }
+        /**
+         * @brief
+         *
+         * @return bool
+         */
+        bool initialized() const { return m_bInitialized; }
+
+    private:
+        friend class Database;
+        /**
+         * @brief
+         *
+         * @param nID
+         * @param nArgs
+         */
+        void init(int nID, uint32 nArgs) { m_nIndex = nID; m_nArguments = nArgs; m_bInitialized = true; }
+
+        int m_nIndex; /**< TODO */
+        uint32 m_nArguments; /**< TODO */
+        bool m_bInitialized; /**< TODO */
+};
+
+/**
+ * @brief statement index
+ *
+ */
+class SqlStatement
+{
+    public:
+        /**
+         * @brief
+         *
+         */
+        ~SqlStatement() { delete m_pParams; }
+
+        /**
+         * @brief
+         *
+         * @param index
+         */
+        SqlStatement(const SqlStatement& index) : m_index(index.m_index), m_pDB(index.m_pDB), m_pParams(NULL)
+        {
+            if (index.m_pParams)
+            {
+                m_pParams = new SqlStmtParameters(*(index.m_pParams));
+            }
+        }
+
+        /**
+         * @brief
+         *
+         * @param index
+         * @return SqlStatement &operator
+         */
+        SqlStatement& operator=(const SqlStatement& index);
+
+        /**
+         * @brief
+         *
+         * @return int
+         */
+        int ID() const { return m_index.ID(); }
+        /**
+         * @brief
+         *
+         * @return uint32
+         */
+        uint32 arguments() const { return m_index.arguments(); }
+
+        /**
+         * @brief
+         *
+         * @return bool
+         */
+        bool Execute();
+        /**
+         * @brief
+         *
+         * @return bool
+         */
+        bool DirectExecute();
+
+        // templates to simplify 1-4 parameter bindings
+        template<typename ParamType1>
+        /**
+         * @brief
+         *
+         * @param param1
+         * @return bool
+         */
+        bool PExecute(ParamType1 param1)
+        {
+            arg(param1);
+            return Execute();
+        }
+
+        template<typename ParamType1, typename ParamType2>
+        /**
+         * @brief
+         *
+         * @param param1
+         * @param param2
+         * @return bool
+         */
+        bool PExecute(ParamType1 param1, ParamType2 param2)
+        {
+            arg(param1);
+            arg(param2);
+            return Execute();
+        }
+
+        template<typename ParamType1, typename ParamType2, typename ParamType3>
+        /**
+         * @brief
+         *
+         * @param param1
+         * @param param2
+         * @param param3
+         * @return bool
+         */
+        bool PExecute(ParamType1 param1, ParamType2 param2, ParamType3 param3)
+        {
+            arg(param1);
+            arg(param2);
+            arg(param3);
+            return Execute();
+        }
+
+        template<typename ParamType1, typename ParamType2, typename ParamType3, typename ParamType4>
+        /**
+         * @brief
+         *
+         * @param param1
+         * @param param2
+         * @param param3
+         * @param param4
+         * @return bool
+         */
+        bool PExecute(ParamType1 param1, ParamType2 param2, ParamType3 param3, ParamType4 param4)
+        {
+            arg(param1);
+            arg(param2);
+            arg(param3);
+            arg(param4);
+            return Execute();
+        }
+
+        // bind parameters with specified type
+        /**
+         * @brief
+         *
+         * @param var
+         */
+        void addBool(bool var) { arg(var); }
+        /**
+         * @brief
+         *
+         * @param var
+         */
+        void addUInt8(uint8 var) { arg(var); }
+        /**
+         * @brief
+         *
+         * @param var
+         */
+        void addInt8(int8 var) { arg(var); }
+        /**
+         * @brief
+         *
+         * @param var
+         */
+        void addUInt16(uint16 var) { arg(var); }
+        /**
+         * @brief
+         *
+         * @param var
+         */
+        void addInt16(int16 var) { arg(var); }
+        /**
+         * @brief
+         *
+         * @param var
+         */
+        void addUInt32(uint32 var) { arg(var); }
+        /**
+         * @brief
+         *
+         * @param var
+         */
+        void addInt32(int32 var) { arg(var); }
+        /**
+         * @brief
+         *
+         * @param var
+         */
+        void addUInt64(uint64 var) { arg(var); }
+        /**
+         * @brief
+         *
+         * @param var
+         */
+        void addInt64(int64 var) { arg(var); }
+        /**
+         * @brief
+         *
+         * @param var
+         */
+        void addFloat(float var) { arg(var); }
+        /**
+         * @brief
+         *
+         * @param var
+         */
+        void addDouble(double var) { arg(var); }
+        /**
+         * @brief
+         *
+         * @param var
+         */
+        void addString(const char* var) { arg(var); }
+        /**
+         * @brief
+         *
+         * @param var
+         */
+        void addString(const std::string& var) { arg(var.c_str()); }
+        /**
+         * @brief
+         *
+         * @param ss
+         */
+        void addString(std::ostringstream& ss) { arg(ss.str().c_str()); ss.str(std::string()); }
+
+    protected:
+        // don't allow anyone except Database class to create static SqlStatement objects
+        friend class Database;
+        /**
+         * @brief
+         *
+         * @param index
+         * @param db
+         */
+        SqlStatement(const SqlStatementID& index, Database& db) : m_index(index), m_pDB(&db), m_pParams(NULL) {}
+
+    private:
+
+        /**
+         * @brief
+         *
+         * @return SqlStmtParameters
+         */
+        SqlStmtParameters* get()
+        {
+            if (!m_pParams)
+            {
+                m_pParams = new SqlStmtParameters(arguments());
+            }
+
+            return m_pParams;
+        }
+
+        /**
+         * @brief
+         *
+         * @return SqlStmtParameters
+         */
+        SqlStmtParameters* detach()
+        {
+            SqlStmtParameters* p = m_pParams ? m_pParams : new SqlStmtParameters(0);
+            m_pParams = NULL;
+            return p;
+        }
+
+        // helper function
+        // use appropriate add* functions to bind specific data type
+        template<typename ParamType>
+        /**
+         * @brief
+         *
+         * @param val
+         */
+        void arg(ParamType val)
+        {
+            SqlStmtParameters* p = get();
+            p->addParam(SqlStmtFieldData(val));
+        }
+
+        SqlStatementID m_index; /**< TODO */
+        Database* m_pDB; /**< TODO */
+        SqlStmtParameters* m_pParams; /**< TODO */
+};
+
+/**
+ * @brief base prepared statement class
+ *
+ */
+class SqlPreparedStatement
+{
+    public:
+        /**
+         * @brief
+         *
+         */
+        virtual ~SqlPreparedStatement() {}
+
+        /**
+         * @brief
+         *
+         * @return bool
+         */
+        bool isPrepared() const { return m_bPrepared; }
+        /**
+         * @brief
+         *
+         * @return bool
+         */
+        bool isQuery() const { return m_bIsQuery; }
+
+        /**
+         * @brief
+         *
+         * @return uint32
+         */
+        uint32 params() const { return m_nParams; }
+        /**
+         * @brief
+         *
+         * @return uint32
+         */
+        uint32 columns() const { return isQuery() ? m_nColumns : 0; }
+
+        /**
+         * @brief initialize internal structures of prepared statement
+         *
+         * upon success m_bPrepared should be true
+         *
+         * @return bool
+         */
+        virtual bool prepare() = 0;
+        /**
+         * @brief bind parameters for prepared statement from parameter placeholder
+         *
+         * @param holder
+         */
+        virtual void bind(const SqlStmtParameters& holder) = 0;
+
+        /**
+         * @brief execute statement w/o result set
+         *
+         * @return bool
+         */
+        virtual bool execute() = 0;
+
+    protected:
+        /**
+         * @brief
+         *
+         * @param fmt
+         * @param conn
+         */
+        SqlPreparedStatement(const std::string& fmt, SqlConnection& conn) :
+            m_nParams(0), m_nColumns(0), m_bIsQuery(false),
+            m_bPrepared(false), m_szFmt(fmt), m_pConn(conn)
+        {}
+
+        uint32 m_nParams; /**< TODO */
+        uint32 m_nColumns; /**< TODO */
+        bool m_bIsQuery; /**< TODO */
+        bool m_bPrepared; /**< TODO */
+        std::string m_szFmt; /**< TODO */
+        SqlConnection& m_pConn; /**< TODO */
+};
+
+/**
+ * @brief prepared statements via plain SQL string requests
+ *
+ */
+class SqlPlainPreparedStatement : public SqlPreparedStatement
+{
+    public:
+        /**
+         * @brief
+         *
+         * @param fmt
+         * @param conn
+         */
+        SqlPlainPreparedStatement(const std::string& fmt, SqlConnection& conn);
+        /**
+         * @brief
+         *
+         */
+        ~SqlPlainPreparedStatement() {}
+
+        /**
+         * @brief this statement is always prepared
+         *
+         * @return bool
+         */
+        virtual bool prepare() override { return true; }
+
+        /**
+         * @brief we should replace all '?' symbols with substrings with proper format
+         *
+         * @param holder
+         */
+        virtual void bind(const SqlStmtParameters& holder) override;
+
+        /**
+         * @brief
+         *
+         * @return bool
+         */
+        virtual bool execute() override;
+
+    protected:
+        /**
+         * @brief
+         *
+         * @param data
+         * @param fmt
+         */
+        void DataToString(const SqlStmtFieldData& data, std::ostringstream& fmt);
+
+        std::string m_szPlainRequest; /**< TODO */
+};
+
+#endif
diff --git a/shared/Dynamic/FactoryHolder.h b/shared/Dynamic/FactoryHolder.h
new file mode 100644
index 0000000..9be4334
--- /dev/null
+++ b/shared/Dynamic/FactoryHolder.h
@@ -0,0 +1,114 @@
+/**
+ * MaNGOS is a full featured server for World of Warcraft, supporting
+ * the following clients: 1.12.x, 2.4.3, 3.3.5a, 4.3.4a and 5.4.8
+ *
+ * Copyright (C) 2005-2022 MaNGOS <https://getmangos.eu>
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * World of Warcraft, and all World of Warcraft or Warcraft art, images,
+ * and lore are copyrighted by Blizzard Entertainment, Inc.
+ */
+
+#ifndef MANGOS_FACTORY_HOLDER
+#define MANGOS_FACTORY_HOLDER
+
+#include "Platform/Define.h"
+#include "Utilities/TypeList.h"
+#include "ObjectRegistry.h"
+#include "Policies/Singleton.h"
+
+template < class T, class Key = std::string >
+/**
+ * @brief FactoryHolder holds a factory object of a specific type
+ *
+ */
+class FactoryHolder
+{
+    public:
+        /**
+         * @brief
+         *
+         */
+        typedef ObjectRegistry<FactoryHolder<T, Key >, Key > FactoryHolderRegistry;
+        /**
+         * @brief
+         *
+         */
+        typedef MaNGOS::Singleton<FactoryHolderRegistry > FactoryHolderRepository;
+
+        /**
+         * @brief
+         *
+         * @param k
+         */
+        FactoryHolder(Key k) : i_key(k) {}
+        /**
+         * @brief
+         *
+         */
+        virtual ~FactoryHolder() {}
+        /**
+         * @brief
+         *
+         * @return Key
+         */
+        inline Key key() const { return i_key; }
+
+        /**
+         * @brief
+         *
+         */
+        void RegisterSelf(void) { FactoryHolderRepository::Instance().InsertItem(this, i_key); }
+        /**
+         * @brief
+         *
+         */
+        void DeregisterSelf(void) { FactoryHolderRepository::Instance().RemoveItem(this, false); }
+
+        /**
+         * @brief Abstract Factory create method
+         *
+         * @param data
+         * @return T
+         */
+        virtual T* Create(void* data = NULL) const = 0;
+    private:
+        Key i_key; /**< TODO */
+};
+
+template<class T>
+/**
+ * @brief Permissible is a classic way of letting the object decide whether how good they handle things.
+ *
+ * This is not retricted to factory selectors.
+ */
+class Permissible
+{
+    public:
+        /**
+         * @brief
+         *
+         */
+        virtual ~Permissible() {}
+        /**
+         * @brief
+         *
+         * @param
+         * @return int
+         */
+        virtual int Permit(const T*) const = 0;
+};
+#endif
diff --git a/shared/Dynamic/ObjectRegistry.h b/shared/Dynamic/ObjectRegistry.h
new file mode 100644
index 0000000..414b393
--- /dev/null
+++ b/shared/Dynamic/ObjectRegistry.h
@@ -0,0 +1,166 @@
+/**
+ * MaNGOS is a full featured server for World of Warcraft, supporting
+ * the following clients: 1.12.x, 2.4.3, 3.3.5a, 4.3.4a and 5.4.8
+ *
+ * Copyright (C) 2005-2022 MaNGOS <https://getmangos.eu>
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * World of Warcraft, and all World of Warcraft or Warcraft art, images,
+ * and lore are copyrighted by Blizzard Entertainment, Inc.
+ */
+
+#ifndef MANGOS_OBJECTREGISTRY_H
+#define MANGOS_OBJECTREGISTRY_H
+
+#include "Platform/Define.h"
+#include "Utilities/UnorderedMapSet.h"
+#include "Policies/Singleton.h"
+
+#include <string>
+#include <vector>
+#include <map>
+
+template < class T, class Key = std::string >
+/**
+ * @brief ObjectRegistry holds all registry item of the same type
+ *
+ */
+class ObjectRegistry
+{
+    public:
+        /**
+         * @brief
+         *
+         */
+        typedef std::map<Key, T*> RegistryMapType;
+
+        /**
+         * @brief Returns a registry item
+         *
+         * @param key
+         * @return const T
+         */
+        const T* GetRegistryItem(Key key) const
+        {
+            typename RegistryMapType::const_iterator iter = i_registeredObjects.find(key);
+            return(iter == i_registeredObjects.end() ? NULL : iter->second);
+        }
+
+        /**
+         * @brief Inserts a registry item
+         *
+         * @param obj
+         * @param key
+         * @param replace
+         * @return bool
+         */
+        bool InsertItem(T* obj, Key key, bool replace = false)
+        {
+            typename RegistryMapType::iterator iter = i_registeredObjects.find(key);
+            if (iter != i_registeredObjects.end())
+            {
+                if (!replace)
+                {
+                    return false;
+                }
+                delete iter->second;
+                i_registeredObjects.erase(iter);
+            }
+
+            i_registeredObjects[key] = obj;
+            return true;
+        }
+
+        /**
+         * @brief Removes a registry item
+         *
+         * @param key
+         * @param delete_object
+         */
+        void RemoveItem(Key key, bool delete_object = true)
+        {
+            typename RegistryMapType::iterator iter = i_registeredObjects.find(key);
+            if (iter != i_registeredObjects.end())
+            {
+                if (delete_object)
+                {
+                    delete iter->second;
+                }
+                i_registeredObjects.erase(iter);
+            }
+        }
+
+        /**
+         * @brief Returns true if registry contains an item
+         *
+         * @param key
+         * @return bool
+         */
+        bool HasItem(Key key) const
+        {
+            return (i_registeredObjects.find(key) != i_registeredObjects.end());
+        }
+
+        /**
+         * @brief Inefficiently return a vector of registered items
+         *
+         * @param l
+         * @return unsigned int
+         */
+        unsigned int GetRegisteredItems(std::vector<Key>& l) const
+        {
+            unsigned int sz = l.size();
+            l.resize(sz + i_registeredObjects.size());
+            for (typename RegistryMapType::const_iterator iter = i_registeredObjects.begin(); iter != i_registeredObjects.end(); ++iter)
+            {
+                l[sz++] = iter->first;
+            }
+            return i_registeredObjects.size();
+        }
+
+        /**
+         * @brief Return the map of registered items
+         *
+         * @return const RegistryMapType
+         */
+        RegistryMapType const& GetRegisteredItems() const
+        {
+            return i_registeredObjects;
+        }
+
+    private:
+        RegistryMapType i_registeredObjects; /**< TODO */
+        friend class MaNGOS::OperatorNew<ObjectRegistry<T, Key> >;
+
+        /**
+         * @brief protected for friend use since it should be a singleton
+         *
+         */
+        ObjectRegistry() {}
+        /**
+         * @brief
+         *
+         */
+        ~ObjectRegistry()
+        {
+            for (typename RegistryMapType::iterator iter = i_registeredObjects.begin(); iter != i_registeredObjects.end(); ++iter)
+            {
+                delete iter->second;
+            }
+            i_registeredObjects.clear();
+        }
+};
+#endif
diff --git a/shared/GameSystem/Grid.h b/shared/GameSystem/Grid.h
new file mode 100644
index 0000000..4e47038
--- /dev/null
+++ b/shared/GameSystem/Grid.h
@@ -0,0 +1,136 @@
+/**
+ * MaNGOS is a full featured server for World of Warcraft, supporting
+ * the following clients: 1.12.x, 2.4.3, 3.3.5a, 4.3.4a and 5.4.8
+ *
+ * Copyright (C) 2005-2022 MaNGOS <https://getmangos.eu>
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * World of Warcraft, and all World of Warcraft or Warcraft art, images,
+ * and lore are copyrighted by Blizzard Entertainment, Inc.
+ */
+
+#ifndef MANGOS_GRID_H
+#define MANGOS_GRID_H
+
+#include "Platform/Define.h"
+#include "Policies/ThreadingModel.h"
+#include "TypeContainer.h"
+#include "TypeContainerVisitor.h"
+
+// forward declaration
+template<class A, class T, class O> class GridLoader;
+
+/**
+ * @brief Grid is a logical segment of the game world represented inside MaNGOS.
+ *
+ * Grid is bind at compile time to a particular type of object which
+ * we call it the object of interest.  There are many types of loader,
+ * specially, dynamic loader, static loader, or on-demand loader.  There's
+ * a subtle difference between dynamic loader and on-demand loader but
+ * this is implementation specific to the loader class.  From the
+ * Grid's perspective, the loader meets its API requirement is suffice.
+ */
+
+template <typename ACTIVE_OBJECT, typename WORLD_CONTAINER, typename GRID_CONTAINER>
+class Grid
+{
+        // allows the GridLoader to access its internals
+        template<class A, class T, class O> friend class GridLoader;
+
+    public:
+
+        template<class SPECIFIC_OBJECT>
+        /**
+         * @brief an object of interested enters the grid
+         *
+         * @param obj
+         * @return bool
+         */
+        bool AddWorldObject(SPECIFIC_OBJECT* obj)
+        {
+            return i_worldContainer.template insert<SPECIFIC_OBJECT>(obj);
+        }
+
+        template<class SPECIFIC_OBJECT>
+        /**
+         * @brief an object of interested exits the grid
+         *
+         * @param obj
+         * @return bool
+         */
+        bool RemoveWorldObject(SPECIFIC_OBJECT* obj)
+        {
+            return i_worldContainer.template remove<SPECIFIC_OBJECT>(obj);
+        }
+
+        template<class SPECIFIC_OBJECT>
+        /**
+         * @brief Inserts a container type object into the grid.
+         *
+         * @param obj
+         * @return bool
+         */
+        bool AddGridObject(SPECIFIC_OBJECT* obj)
+        {
+            if (obj->IsActiveObject())
+            {
+                m_activeGridObjects.insert(obj);
+            }
+
+            return i_gridContainer.template insert<SPECIFIC_OBJECT>(obj);
+        }
+
+        template<class SPECIFIC_OBJECT>
+        /**
+         * @brief Removes a container type object from the grid
+         *
+         * @param obj
+         * @return bool
+         */
+        bool RemoveGridObject(SPECIFIC_OBJECT* obj)
+        {
+            if (obj->IsActiveObject())
+            {
+                m_activeGridObjects.erase(obj);
+            }
+
+            return i_gridContainer.template remove<SPECIFIC_OBJECT>(obj);
+        }
+
+        template<class T>
+        void Visit(TypeContainerVisitor<T, GRID_CONTAINER>& visitor)
+        {
+            visitor.Visit(i_gridContainer);
+        }
+
+        template<class T>
+        void Visit(TypeContainerVisitor<T, WORLD_CONTAINER>& visitor)
+        {
+            visitor.Visit(i_worldContainer);
+        }
+
+        size_t ActiveObjectsInGrid() const
+        {
+            return m_activeGridObjects.size() + i_worldContainer.template count<ACTIVE_OBJECT>(nullptr);
+        }
+
+    private:
+        GRID_CONTAINER  i_gridContainer;
+        WORLD_CONTAINER i_worldContainer;
+        std::set<void*> m_activeGridObjects;
+};
+
+#endif
diff --git a/shared/GameSystem/GridLoader.h b/shared/GameSystem/GridLoader.h
new file mode 100644
index 0000000..7144d88
--- /dev/null
+++ b/shared/GameSystem/GridLoader.h
@@ -0,0 +1,95 @@
+/**
+ * MaNGOS is a full featured server for World of Warcraft, supporting
+ * the following clients: 1.12.x, 2.4.3, 3.3.5a, 4.3.4a and 5.4.8
+ *
+ * Copyright (C) 2005-2022 MaNGOS <https://getmangos.eu>
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * World of Warcraft, and all World of Warcraft or Warcraft art, images,
+ * and lore are copyrighted by Blizzard Entertainment, Inc.
+ */
+
+#ifndef MANGOS_GRIDLOADER_H
+#define MANGOS_GRIDLOADER_H
+
+#include "Platform/Define.h"
+#include "Grid.h"
+#include "TypeContainerVisitor.h"
+
+template
+<
+class ACTIVE_OBJECT,
+      class WORLD_OBJECT_TYPES,
+      class GRID_OBJECT_TYPES
+      >
+/**
+ * @brief The GridLoader is working in conjuction with the Grid and responsible
+ *        for loading and unloading object-types (one or more) when objects
+ *        enters a grid.
+ * Unloading is scheduled and might be canceled if an interested object re-enters.
+ * GridLoader does not do the actual loading and unloading but implements as a
+ * template pattern that delegates its loading and unloading for the actually
+ * loader and unloader. GridLoader manages the grid (both local and remote).
+ *
+ */
+class GridLoader
+{
+    public:
+
+        template<class LOADER>
+        /**
+         * @brief Loads the grid
+         *
+         * @param Grid<ACTIVE_OBJECT
+         * @param WORLD_OBJECT_TYPES
+         * @param grid
+         * @param loader
+         */
+        void Load(Grid<ACTIVE_OBJECT, WORLD_OBJECT_TYPES, GRID_OBJECT_TYPES>& grid, LOADER& loader)
+        {
+            loader.Load(grid);
+        }
+
+        template<class STOPER>
+        /**
+         * @brief Stop the grid
+         *
+         * @param Grid<ACTIVE_OBJECT
+         * @param WORLD_OBJECT_TYPES
+         * @param grid
+         * @param stoper
+         */
+        void Stop(Grid<ACTIVE_OBJECT, WORLD_OBJECT_TYPES, GRID_OBJECT_TYPES>& grid, STOPER& stoper)
+        {
+            stoper.Stop(grid);
+        }
+
+        template<class UNLOADER>
+        /**
+         * @brief Unloads the grid
+         *
+         * @param Grid<ACTIVE_OBJECT
+         * @param WORLD_OBJECT_TYPES
+         * @param grid
+         * @param unloader
+         */
+        void Unload(Grid<ACTIVE_OBJECT, WORLD_OBJECT_TYPES, GRID_OBJECT_TYPES>& grid, UNLOADER& unloader)
+        {
+            unloader.Unload(grid);
+        }
+};
+
+#endif
diff --git a/shared/GameSystem/GridRefManager.h b/shared/GameSystem/GridRefManager.h
new file mode 100644
index 0000000..a2c76bc
--- /dev/null
+++ b/shared/GameSystem/GridRefManager.h
@@ -0,0 +1,92 @@
+/**
+ * MaNGOS is a full featured server for World of Warcraft, supporting
+ * the following clients: 1.12.x, 2.4.3, 3.3.5a, 4.3.4a and 5.4.8
+ *
+ * Copyright (C) 2005-2022 MaNGOS <https://getmangos.eu>
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * World of Warcraft, and all World of Warcraft or Warcraft art, images,
+ * and lore are copyrighted by Blizzard Entertainment, Inc.
+ */
+
+#ifndef _GRIDREFMANAGER
+#define _GRIDREFMANAGER
+
+#include "Utilities/LinkedReference/RefManager.h"
+
+template<class OBJECT> class GridReference;
+
+template<class OBJECT>
+/**
+ * @brief
+ *
+ */
+class GridRefManager : public RefManager<GridRefManager<OBJECT>, OBJECT>
+{
+    public:
+
+        /**
+         * @brief
+         *
+         */
+        typedef LinkedListHead::Iterator< GridReference<OBJECT> > iterator;
+
+        /**
+         * @brief
+         *
+         * @return GridReference<OBJECT>
+         */
+        GridReference<OBJECT>* getFirst()
+        {
+            return (GridReference<OBJECT>*)RefManager<GridRefManager<OBJECT>, OBJECT>::getFirst();
+        }
+
+        /**
+         * @brief
+         *
+         * @return GridReference<OBJECT>
+         */
+        GridReference<OBJECT>* getLast()
+        {
+            return (GridReference<OBJECT>*)RefManager<GridRefManager<OBJECT>, OBJECT>::getLast();
+        }
+
+        /**
+         * @brief
+         *
+         * @return iterator
+         */
+        iterator begin() { return iterator(getFirst()); }
+        /**
+         * @brief
+         *
+         * @return iterator
+         */
+        iterator end() { return iterator(nullptr); }
+        /**
+         * @brief
+         *
+         * @return iterator
+         */
+        iterator rbegin() { return iterator(getLast()); }
+        /**
+         * @brief
+         *
+         * @return iterator
+         */
+        iterator rend() { return iterator(nullptr); }
+};
+#endif
diff --git a/shared/GameSystem/GridReference.h b/shared/GameSystem/GridReference.h
new file mode 100644
index 0000000..5553676
--- /dev/null
+++ b/shared/GameSystem/GridReference.h
@@ -0,0 +1,105 @@
+/**
+ * MaNGOS is a full featured server for World of Warcraft, supporting
+ * the following clients: 1.12.x, 2.4.3, 3.3.5a, 4.3.4a and 5.4.8
+ *
+ * Copyright (C) 2005-2022 MaNGOS <https://getmangos.eu>
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * World of Warcraft, and all World of Warcraft or Warcraft art, images,
+ * and lore are copyrighted by Blizzard Entertainment, Inc.
+ */
+
+#ifndef MANGOS_H_GRIDREFERENCE
+#define MANGOS_H_GRIDREFERENCE
+
+#include "Utilities/LinkedReference/Reference.h"
+
+template<class OBJECT> class GridRefManager;
+
+template<class OBJECT>
+/**
+ * @brief
+ *
+ */
+class GridReference : public Reference<GridRefManager<OBJECT>, OBJECT>
+{
+    protected:
+
+        /**
+         * @brief
+         *
+         */
+        void targetObjectBuildLink() override
+        {
+            // called from link()
+            this->getTarget()->insertFirst(this);
+            this->getTarget()->incSize();
+        }
+
+        /**
+         * @brief
+         *
+         */
+        void targetObjectDestroyLink() override
+        {
+            // called from unlink()
+            if (this->isValid())
+            {
+                this->getTarget()->decSize();
+            }
+        }
+
+        /**
+         * @brief
+         *
+         */
+        void sourceObjectDestroyLink() override
+        {
+            // called from invalidate()
+            this->getTarget()->decSize();
+        }
+
+    public:
+        /**
+         * @brief
+         *
+         */
+        GridReference()
+            : Reference<GridRefManager<OBJECT>, OBJECT>()
+        {
+        }
+
+        /**
+         * @brief
+         *
+         */
+        ~GridReference()
+        {
+            this->unlink();
+        }
+
+        /**
+         * @brief
+         *
+         * @return GridReference
+         */
+        GridReference* next()
+        {
+            return (GridReference*)Reference<GridRefManager<OBJECT>, OBJECT>::next();
+        }
+};
+
+#endif
diff --git a/shared/GameSystem/NGrid.h b/shared/GameSystem/NGrid.h
new file mode 100644
index 0000000..28cbf31
--- /dev/null
+++ b/shared/GameSystem/NGrid.h
@@ -0,0 +1,436 @@
+/**
+ * MaNGOS is a full featured server for World of Warcraft, supporting
+ * the following clients: 1.12.x, 2.4.3, 3.3.5a, 4.3.4a and 5.4.8
+ *
+ * Copyright (C) 2005-2022 MaNGOS <https://getmangos.eu>
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * World of Warcraft, and all World of Warcraft or Warcraft art, images,
+ * and lore are copyrighted by Blizzard Entertainment, Inc.
+ */
+
+#ifndef MANGOS_NGRID_H
+#define MANGOS_NGRID_H
+
+#include "GameSystem/Grid.h"
+#include "GameSystem/GridReference.h"
+#include "Timer.h"
+
+#include <cassert>
+
+/**
+ * @brief NGrid is nothing more than a wrapper of the Grid with an NxN cells
+ *
+ */
+class GridInfo
+{
+    public:
+
+        /**
+         * @brief
+         *
+         */
+        GridInfo()
+            : i_timer(0), i_unloadActiveLockCount(0), i_unloadExplicitLock(false)
+        {
+        }
+
+        /**
+         * @brief
+         *
+         * @param expiry
+         * @param unload
+         */
+        GridInfo(time_t expiry, bool unload = true)
+            : i_timer(expiry), i_unloadActiveLockCount(0), i_unloadExplicitLock(!unload)
+        {
+        }
+
+        /**
+         * @brief
+         *
+         * @return const TimeTracker
+         */
+        const TimeTracker& getTimeTracker() const { return i_timer; }
+
+        /**
+         * @brief
+         *
+         * @return bool
+         */
+        bool getUnloadLock() const
+        {
+            return i_unloadActiveLockCount || i_unloadExplicitLock;
+        }
+
+        /**
+         * @brief
+         *
+         * @param on
+         */
+        void setUnloadExplicitLock(bool on) { i_unloadExplicitLock = on; }
+        /**
+         * @brief
+         *
+         */
+        void incUnloadActiveLock() { ++i_unloadActiveLockCount; }
+        /**
+         * @brief
+         *
+         */
+        void decUnloadActiveLock() { if (i_unloadActiveLockCount) { --i_unloadActiveLockCount; } }
+
+        /**
+         * @brief
+         *
+         * @param pTimer
+         */
+        void setTimer(const TimeTracker& pTimer) { i_timer = pTimer; }
+        /**
+         * @brief
+         *
+         * @param interval
+         */
+        void ResetTimeTracker(time_t interval) { i_timer.Reset(interval); }
+        /**
+         * @brief
+         *
+         * @param diff
+         */
+        void UpdateTimeTracker(time_t diff) { i_timer.Update(diff); }
+
+    private:
+
+        TimeTracker i_timer;                                /**< TODO */
+        uint16 i_unloadActiveLockCount : 16;                /**< lock from active object spawn points (prevent clone loading) */
+        bool i_unloadExplicitLock      : 1;                 /**< explicit manual lock or config setting */
+};
+
+/**
+ * @brief
+ *
+ */
+typedef enum
+{
+    GRID_STATE_INVALID = 0,
+    GRID_STATE_ACTIVE = 1,
+    GRID_STATE_IDLE = 2,
+    GRID_STATE_REMOVAL = 3,
+    MAX_GRID_STATE = 4
+} grid_state_t;
+
+template
+<
+uint32 N,
+       class ACTIVE_OBJECT,
+       class WORLD_OBJECT_TYPES,
+       class GRID_OBJECT_TYPES
+       >
+/**
+ * @brief
+ *
+ */
+class NGrid
+{
+    public:
+
+        /**
+         * @brief
+         *
+         */
+        using GridType = Grid<ACTIVE_OBJECT, WORLD_OBJECT_TYPES, GRID_OBJECT_TYPES>;
+
+        /**
+         * @brief
+         *
+         * @param id
+         * @param x
+         * @param y
+         * @param expiry
+         * @param unload
+         */
+        NGrid(uint32 id, uint32 x, uint32 y, time_t expiry, bool unload = true)
+            : i_gridId(id), i_x(x), i_y(y), i_cellstate(GRID_STATE_INVALID), i_GridObjectDataLoaded(false)
+        {
+            i_GridInfo = GridInfo(expiry, unload);
+        }
+
+        /**
+         * @brief
+         *
+         * @param x
+         * @param y
+         * @return const GridType &operator
+         */
+        const GridType& operator()(uint32 x, uint32 y) const
+        {
+            assert(x < N);
+            assert(y < N);
+            return i_cells[x][y];
+        }
+
+        /**
+         * @brief
+         *
+         * @param x
+         * @param y
+         * @return GridType &operator
+         */
+        GridType& operator()(uint32 x, uint32 y)
+        {
+            assert(x < N);
+            assert(y < N);
+            return i_cells[x][y];
+        }
+
+        /**
+         * @brief
+         *
+         * @return const uint32
+         */
+        const uint32& GetGridId() const { return i_gridId; }
+        /**
+         * @brief
+         *
+         * @param id
+         */
+        void SetGridId(const uint32 id) { i_gridId = id; }
+        /**
+         * @brief
+         *
+         * @return grid_state_t
+         */
+        grid_state_t GetGridState() const { return i_cellstate; }
+        /**
+         * @brief
+         *
+         * @param s
+         */
+        void SetGridState(grid_state_t s) { i_cellstate = s; }
+        /**
+         * @brief
+         *
+         * @return uint32
+         */
+        uint32 getX() const { return i_x; }
+        /**
+         * @brief
+         *
+         * @return uint32
+         */
+        uint32 getY() const { return i_y; }
+
+        /**
+         * @brief
+         *
+         * @param GridRefManager<NGrid<N
+         * @param ACTIVE_OBJECT
+         * @param WORLD_OBJECT_TYPES
+         * @param pTo
+         */
+        void link(GridRefManager<NGrid<N, ACTIVE_OBJECT, WORLD_OBJECT_TYPES, GRID_OBJECT_TYPES> >* pTo)
+        {
+            i_Reference.link(pTo, this);
+        }
+
+        /**
+         * @brief
+         *
+         * @return bool
+         */
+        bool isGridObjectDataLoaded() const { return i_GridObjectDataLoaded; }
+        /**
+         * @brief
+         *
+         * @param pLoaded
+         */
+        void setGridObjectDataLoaded(bool pLoaded) { i_GridObjectDataLoaded = pLoaded; }
+
+        /**
+         * @brief
+         *
+         * @return GridInfo
+         */
+        GridInfo* getGridInfoRef() { return &i_GridInfo; }
+        /**
+         * @brief
+         *
+         * @return const TimeTracker
+         */
+        const TimeTracker& getTimeTracker() const { return i_GridInfo.getTimeTracker(); }
+        /**
+         * @brief
+         *
+         * @return bool
+         */
+        bool getUnloadLock() const { return i_GridInfo.getUnloadLock(); }
+        /**
+         * @brief
+         *
+         * @param on
+         */
+        void setUnloadExplicitLock(bool on) { i_GridInfo.setUnloadExplicitLock(on); }
+        /**
+         * @brief
+         *
+         */
+        void incUnloadActiveLock() { i_GridInfo.incUnloadActiveLock(); }
+        /**
+         * @brief
+         *
+         */
+        void decUnloadActiveLock() { i_GridInfo.decUnloadActiveLock(); }
+        /**
+         * @brief
+         *
+         * @param interval
+         */
+        void ResetTimeTracker(time_t interval) { i_GridInfo.ResetTimeTracker(interval); }
+        /**
+         * @brief
+         *
+         * @param diff
+         */
+        void UpdateTimeTracker(time_t diff) { i_GridInfo.UpdateTimeTracker(diff); }
+
+        template<class SPECIFIC_OBJECT>
+        /**
+         * @brief
+         *
+         * @param x
+         * @param y
+         * @param obj
+         */
+        void AddWorldObject(const uint32 x, const uint32 y, SPECIFIC_OBJECT* obj)
+        {
+            getGridType(x, y).AddWorldObject(obj);
+        }
+
+        template<class SPECIFIC_OBJECT>
+        /**
+         * @brief
+         *
+         * @param x
+         * @param y
+         * @param obj
+         */
+        void RemoveWorldObject(const uint32 x, const uint32 y, SPECIFIC_OBJECT* obj)
+        {
+            getGridType(x, y).RemoveWorldObject(obj);
+        }
+
+        template<class T, class TT>
+        /**
+         * @brief
+         *
+         * @param TypeContainerVisitor<T
+         * @param visitor
+         */
+        void Visit(TypeContainerVisitor<T, TT>& visitor)
+        {
+            for (uint32 x = 0; x < N; ++x)
+                for (uint32 y = 0; y < N; ++y)
+                {
+                    i_cells[x][y].Visit(visitor);
+                }
+        }
+
+        template<class T, class TT>
+        /**
+         * @brief
+         *
+         * @param x
+         * @param y
+         * @param TypeContainerVisitor<T
+         * @param visitor
+         */
+        void Visit(const uint32& x, const uint32& y, TypeContainerVisitor<T, TT>& visitor)
+        {
+            getGridType(x, y).Visit(visitor);
+        }
+
+        /**
+         * @brief
+         *
+         * @return uint32
+         */
+        uint32 ActiveObjectsInGrid() const
+        {
+            uint32 count = 0;
+            for (uint32 x = 0; x < N; ++x)
+                for (uint32 y = 0; y < N; ++y)
+                {
+                    count += i_cells[x][y].ActiveObjectsInGrid();
+                }
+
+            return count;
+        }
+
+        template<class SPECIFIC_OBJECT>
+        /**
+         * @brief
+         *
+         * @param x
+         * @param y
+         * @param obj
+         * @return bool
+         */
+        bool AddGridObject(const uint32 x, const uint32 y, SPECIFIC_OBJECT* obj)
+        {
+            return getGridType(x, y).AddGridObject(obj);
+        }
+
+        template<class SPECIFIC_OBJECT>
+        /**
+         * @brief
+         *
+         * @param x
+         * @param y
+         * @param obj
+         * @return bool
+         */
+        bool RemoveGridObject(const uint32 x, const uint32 y, SPECIFIC_OBJECT* obj)
+        {
+            return getGridType(x, y).RemoveGridObject(obj);
+        }
+
+    private:
+
+        /**
+         * @brief
+         *
+         * @param x
+         * @param y
+         * @return GridType
+         */
+        GridType& getGridType(const uint32& x, const uint32& y)
+        {
+            assert(x < N);
+            assert(y < N);
+            return i_cells[x][y];
+        }
+
+        uint32 i_gridId; /**< TODO */
+        GridInfo i_GridInfo; /**< TODO */
+        GridReference<NGrid<N, ACTIVE_OBJECT, WORLD_OBJECT_TYPES, GRID_OBJECT_TYPES> > i_Reference; /**< TODO */
+        uint32 i_x; /**< TODO */
+        uint32 i_y; /**< TODO */
+        grid_state_t i_cellstate; /**< TODO */
+        GridType i_cells[N][N]; /**< TODO */
+        bool i_GridObjectDataLoaded; /**< TODO */
+};
+
+#endif
diff --git a/shared/GameSystem/TypeContainer.h b/shared/GameSystem/TypeContainer.h
new file mode 100644
index 0000000..c4319f5
--- /dev/null
+++ b/shared/GameSystem/TypeContainer.h
@@ -0,0 +1,201 @@
+/**
+ * MaNGOS is a full featured server for World of Warcraft, supporting
+ * the following clients: 1.12.x, 2.4.3, 3.3.5a, 4.3.4a and 5.4.8
+ *
+ * Copyright (C) 2005-2022 MaNGOS <https://getmangos.eu>
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * World of Warcraft, and all World of Warcraft or Warcraft art, images,
+ * and lore are copyrighted by Blizzard Entertainment, Inc.
+ */
+
+#ifndef MANGOS_TYPECONTAINER_H
+#define MANGOS_TYPECONTAINER_H
+
+/*
+ * Here, you'll find a series of containers that allow you to hold multiple
+ * types of object at the same time.
+ *
+ * Refactored for C++11 by H0zen
+ */
+
+#include <cstddef>
+#include <tuple>
+#include <unordered_map>
+#include "GameSystem/GridRefManager.h"
+
+
+// various metaprogramming primitives
+namespace Meta
+{
+  // Gets the index of specified type T in a std::tuple
+  template <class T, class Tuple> struct IndexOf;
+
+  template <class T, class... Types> struct IndexOf<T, std::tuple<T, Types...>>
+  {
+    static const std::size_t value = 0;
+  };
+
+  template <class T, class U, class... Types> struct IndexOf<T, std::tuple<U, Types...>>
+  {
+    static const std::size_t value = 1 + IndexOf<T, std::tuple<Types...>>::value;
+  };
+  //----------------------------------------------------------------------------------------
+
+  // apply a transformation on each element of a tuple
+  template<template<class...> class F, class L> struct Transform_Impl;
+
+  template<template<class...> class F, template<class...> class L, class... T>
+  struct Transform_Impl<F, L<T...>>
+  {
+    using type = L<F<T>...>;
+  };
+
+  template<template<class...> class F, class L>
+  using Transform = typename Transform_Impl<F, L>::type;
+  //----------------------------------------------------------------------------------------
+
+  // convert a tuple A into another tuple B
+  template<class A, template<class...> class B> struct Rename_Impl;
+
+  template<template<class...> class A, class... T, template<class...> class B>
+  struct Rename_Impl<A<T...>, B>
+  {
+    using type = B<T...>;
+  };
+
+  template<class A, template<class...> class B>
+  using Rename = typename Rename_Impl<A, B>::type;
+  //----------------------------------------------------------------------------------------
+
+  //tuple iteration
+  template<size_t index, typename F, typename... Ts>
+  struct iterate_tuple {
+     void operator() (std::tuple<Ts...>&& t, F&& callback) {
+         iterate_tuple<index - 1, F, Ts...>{}(std::forward<std::tuple<Ts...>>(t), std::forward<F>(callback));
+         callback.Visit(std::get<index>(t));
+     }
+  };
+
+  template<typename F, typename... Ts>
+  struct iterate_tuple<0, F, Ts...> {
+     void operator() (std::tuple<Ts...>&& t, F&& callback) {
+         callback.Visit(std::get<0>(t));
+     }
+  };
+
+  template<typename F, typename... Ts>
+  void for_each(std::tuple<Ts...>&& t, F&& callback) {
+     iterate_tuple<std::tuple_size<std::tuple<Ts...>>::value - 1, F, Ts...> it;
+     it(std::forward<std::tuple<Ts...>>(t), std::forward<F>(callback));
+  }
+
+} //Meta namespace end
+
+
+template<typename KEY_TYPE, typename TYPE_LIST>
+class TypeUnorderedMapContainer
+{
+    using Tuple = Meta::Rename<TYPE_LIST,std::tuple>;
+    template <typename T> using add_pointer = T*;
+    template <typename T> using add_wrap = std::unordered_map<KEY_TYPE, T>;
+
+    using Container = Meta::Transform<add_wrap , Meta::Transform<add_pointer, Tuple>>;
+
+    public:
+        template <typename T>
+        bool insert(KEY_TYPE handle, T* object)
+        {
+            auto&& _element = std::get<Meta::IndexOf<T,Tuple>::value>(i_container);
+            if (_element.end() == _element.find(handle))
+            {
+                _element[handle] = object;
+                return true;
+            }
+            else
+            {
+                assert(_element[handle] == object && "Object with certain key already in but objects are different!");
+                return false;
+            }
+        }
+        template <typename T>
+        bool erase(KEY_TYPE handle, T*)
+        {
+            std::get<Meta::IndexOf<T,Tuple>::value>(i_container).erase(handle);
+            return true;
+        }
+
+        template <typename T>
+        T* find (KEY_TYPE handle, T*)
+        {
+            auto&& _element = std::get<Meta::IndexOf<T,Tuple>::value>(i_container);
+            auto&& iter = _element.find(handle);
+            if (iter == _element.end())
+            {
+                return nullptr;
+            }
+            else
+            {
+                return iter->second;
+            }
+        }
+
+    private:
+      Container i_container;
+};
+
+//TypeMapContainer
+
+template<typename TYPE_LIST>
+class TypeMapContainer
+{
+    using Tuple = Meta::Rename<TYPE_LIST,std::tuple>;
+    template <typename T> using add_wrap = GridRefManager<T>;
+
+    using Container = Meta::Transform<add_wrap, Tuple>;
+
+    public:
+        template <typename T>
+        size_t count(T*) const
+        {
+            return std::get<Meta::IndexOf<T,Tuple>::value>(i_container).getSize();
+        }
+
+        template <typename T>
+        T* insert(T* obj)
+        {
+            obj->GetGridRef().link(&std::get<Meta::IndexOf<T,Tuple>::value>(i_container), obj);
+            return obj;
+        }
+
+        template <typename T>
+        T* remove(T* obj)
+        {
+            obj->GetGridRef().unlink();
+            return obj;
+        }
+
+        template <typename Visitor>
+        void accept(Visitor&& v)
+        {
+            Meta::for_each(std::forward<Container>(i_container), std::forward<Visitor>(v));
+        }
+
+    private:
+      Container i_container;
+};
+
+#endif
diff --git a/shared/GameSystem/TypeContainerVisitor.h b/shared/GameSystem/TypeContainerVisitor.h
new file mode 100644
index 0000000..685f684
--- /dev/null
+++ b/shared/GameSystem/TypeContainerVisitor.h
@@ -0,0 +1,54 @@
+/**
+ * MaNGOS is a full featured server for World of Warcraft, supporting
+ * the following clients: 1.12.x, 2.4.3, 3.3.5a, 4.3.4a and 5.4.8
+ *
+ * Copyright (C) 2005-2022 MaNGOS <https://getmangos.eu>
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * World of Warcraft, and all World of Warcraft or Warcraft art, images,
+ * and lore are copyrighted by Blizzard Entertainment, Inc.
+ */
+
+
+#ifndef MANGOS_TYPECONTAINERVISITOR_H
+#define MANGOS_TYPECONTAINERVISITOR_H
+
+/*
+ * @class TypeContainerVisitor is implemented as a visitor pattern.  It is
+ * a visitor to the TypeMapContainer or ContainerMapList.  The visitor has
+ * to overload its types as a visit method is called.
+ */
+
+#include "TypeContainer.h"
+
+template<class VISITOR, class CONTAINER>
+class TypeContainerVisitor
+{
+    public:
+        TypeContainerVisitor(VISITOR& v) : i_visitor(v){}
+        void Visit(CONTAINER& c)
+        {
+            c.template accept<VISITOR>(std::forward<VISITOR>(i_visitor));
+        }
+        void Visit(const CONTAINER& c) const
+        {
+            c.template accept<VISITOR>(std::forward<VISITOR>(i_visitor));
+        }
+    private:
+        VISITOR& i_visitor;
+};
+
+#endif
diff --git a/shared/Linux/PosixDaemon.cpp b/shared/Linux/PosixDaemon.cpp
new file mode 100644
index 0000000..19d0ceb
--- /dev/null
+++ b/shared/Linux/PosixDaemon.cpp
@@ -0,0 +1,153 @@
+/**
+ * MaNGOS is a full featured server for World of Warcraft, supporting
+ * the following clients: 1.12.x, 2.4.3, 3.3.5a, 4.3.4a and 5.4.8
+ *
+ * Copyright (C) 2005-2022 MaNGOS <https://getmangos.eu>
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * World of Warcraft, and all World of Warcraft or Warcraft art, images,
+ * and lore are copyrighted by Blizzard Entertainment, Inc.
+ */
+
+#include "Config/Config.h"
+#include "PosixDaemon.h"
+#include <cstdio>
+#include <iostream>
+#include <fstream>
+
+pid_t parent_pid = 0, sid = 0;
+
+void daemonSignal(int s)
+{
+
+    if (getpid() != parent_pid)
+    {
+        return;
+    }
+
+    if (s == SIGUSR1)
+    {
+        exit(EXIT_SUCCESS);
+    }
+
+    if (sid)
+    {
+        kill(sid, s);
+    }
+
+    exit(EXIT_FAILURE);
+}
+
+void startDaemon(uint32_t timeout)
+{
+    parent_pid = getpid();
+    pid_t pid;
+
+    signal(SIGUSR1, daemonSignal);
+    signal(SIGINT, daemonSignal);
+    signal(SIGTERM, daemonSignal);
+    signal(SIGALRM, daemonSignal);
+
+    sid = pid = fork();
+
+    if (pid < 0)
+    {
+        exit(EXIT_FAILURE);
+    }
+
+    if (pid > 0)
+    {
+        alarm(timeout);
+        pause();
+        exit(EXIT_FAILURE);
+    }
+
+    umask(0);
+
+    sid = setsid();
+
+    if (sid < 0)
+    {
+        exit(EXIT_FAILURE);
+    }
+
+    if ((chdir("/")) < 0)
+    {
+        exit(EXIT_FAILURE);
+    }
+
+    if (!freopen("/dev/null", "rt", stdin))
+    {
+        exit(EXIT_FAILURE);
+    }
+    if (!freopen("/dev/null", "wt", stdout))
+    {
+        exit(EXIT_FAILURE);
+    }
+    if (!freopen("/dev/null", "wt", stderr))
+    {
+        exit(EXIT_FAILURE);
+    }
+}
+
+void stopDaemon()
+{
+    std::string pidfile = sConfig.GetStringDefault("PidFile", "");
+    if (!pidfile.empty())
+    {
+        std::fstream pf(pidfile.c_str(), std::ios::in);
+        uint32_t pid = 0;
+        pf >> pid;
+        if (kill(pid, SIGINT) < 0)
+        {
+            std::cerr << "Unable to stop daemon" << std::endl;
+            exit(EXIT_FAILURE);
+        }
+        pf.close();
+    }
+    else
+    {
+        std::cerr << "No pid file specified" << std::endl;
+    }
+
+    exit(EXIT_SUCCESS);
+}
+
+void detachDaemon()
+{
+    if (parent_pid)
+    {
+        kill(parent_pid, SIGUSR1);
+    }
+}
+
+void exitDaemon()
+{
+    if (parent_pid && parent_pid != getpid())
+    {
+        kill(parent_pid, SIGTERM);
+    }
+}
+
+struct WatchDog
+{
+    ~WatchDog()
+    {
+        exitDaemon();
+    }
+};
+
+WatchDog dog;
diff --git a/shared/Linux/PosixDaemon.h b/shared/Linux/PosixDaemon.h
new file mode 100644
index 0000000..a8d1902
--- /dev/null
+++ b/shared/Linux/PosixDaemon.h
@@ -0,0 +1,43 @@
+/**
+ * MaNGOS is a full featured server for World of Warcraft, supporting
+ * the following clients: 1.12.x, 2.4.3, 3.3.5a, 4.3.4a and 5.4.8
+ *
+ * Copyright (C) 2005-2022 MaNGOS <https://getmangos.eu>
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * World of Warcraft, and all World of Warcraft or Warcraft art, images,
+ * and lore are copyrighted by Blizzard Entertainment, Inc.
+ */
+
+#include "Common/Common.h"
+#include "Log/Log.h"
+
+/**
+ * @brief
+ *
+ * @param timeout
+ */
+void startDaemon(uint32_t timeout = 10);
+/**
+ * @brief
+ *
+ */
+void stopDaemon();
+/**
+ * @brief
+ *
+ */
+void detachDaemon();
diff --git a/shared/LockedQueue/LockedQueue.h b/shared/LockedQueue/LockedQueue.h
new file mode 100644
index 0000000..3bd5bcc
--- /dev/null
+++ b/shared/LockedQueue/LockedQueue.h
@@ -0,0 +1,136 @@
+/**
+ * MaNGOS is a full featured server for World of Warcraft, supporting
+ * the following clients: 1.12.x, 2.4.3, 3.3.5a, 4.3.4a and 5.4.8
+ *
+ * Copyright (C) 2005-2022 MaNGOS <https://getmangos.eu>
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * World of Warcraft, and all World of Warcraft or Warcraft art, images,
+ * and lore are copyrighted by Blizzard Entertainment, Inc.
+ */
+
+#ifndef LOCKEDQUEUE_H
+#define LOCKEDQUEUE_H
+
+#include <ace/Guard_T.h>
+#include <ace/Thread_Mutex.h>
+#include <deque>
+#include <assert.h>
+#include "Utilities/Errors.h"
+
+namespace ACE_Based
+{
+    template < class T, class LockType, typename StorageType = std::deque<T> >
+    /**
+     * @brief
+     *
+     */
+    class LockedQueue
+    {
+            LockType _lock; /**< Lock access to the queue. */
+            StorageType _queue; /**< Storage backing the queue. */
+
+        public:
+
+            /**
+             * @brief Create a LockedQueue.
+             *
+             */
+            LockedQueue() : _lock(), _queue()
+            {
+            }
+
+            /**
+             * @brief Destroy a LockedQueue.
+             *
+             */
+            virtual ~LockedQueue()
+            {
+            }
+
+            /**
+             * @brief Adds an item to the queue.
+             *
+             * @param item
+             */
+            void add(const T& item)
+            {
+                ACE_GUARD (LockType, g, this->_lock);
+                _queue.push_back(item);
+            }
+
+            /**
+             * @brief Gets the next result in the queue, if any.
+             *
+             * @param result
+             * @return bool
+             */
+            bool next(T& result)
+            {
+                ACE_GUARD_RETURN(LockType, g, this->_lock, false);
+
+                if (_queue.empty())
+                {
+                    return false;
+                }
+
+                result = _queue.front();
+                _queue.pop_front();
+
+                return true;
+            }
+
+            template<class Checker>
+            /**
+             * @brief
+             *
+             * @param result
+             * @param check
+             * @return bool
+             */
+            bool next(T& result, Checker& check)
+            {
+                ACE_GUARD_RETURN(LockType, g, this->_lock, false);
+
+                if (_queue.empty())
+                {
+                    return false;
+                }
+
+                result = _queue.front();
+                if (!check.Process(result))
+                {
+                    return false;
+                }
+
+                _queue.pop_front();
+                return true;
+            }
+
+
+            /**
+             * @brief Checks if we're empty or not with locks held
+             *
+             * @return bool
+             */
+            bool empty()
+            {
+                ACE_GUARD_RETURN (LockType, g, this->_lock, false);
+                return _queue.empty();
+            }
+    };
+}
+#endif
diff --git a/shared/Log/Log.cpp b/shared/Log/Log.cpp
new file mode 100644
index 0000000..e253cff
--- /dev/null
+++ b/shared/Log/Log.cpp
@@ -0,0 +1,1373 @@
+/**
+ * MaNGOS is a full featured server for World of Warcraft, supporting
+ * the following clients: 1.12.x, 2.4.3, 3.3.5a, 4.3.4a and 5.4.8
+ *
+ * Copyright (C) 2005-2022 MaNGOS <https://getmangos.eu>
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * World of Warcraft, and all World of Warcraft or Warcraft art, images,
+ * and lore are copyrighted by Blizzard Entertainment, Inc.
+ */
+
+#include "Common/Common.h"
+#include "Log.h"
+#include "Policies/Singleton.h"
+#include "Config/Config.h"
+#include "Utilities/Util.h"
+#include "Utilities/ByteBuffer.h"
+#include "Utilities/ProgressBar.h"
+
+#include <stdarg.h>
+#include <fstream>
+#include <iostream>
+
+#include <ace/OS_NS_unistd.h>
+
+INSTANTIATE_SINGLETON_1(Log);
+
+LogFilterData logFilterData[LOG_FILTER_COUNT] =
+{
+    { "transport_moves",     "LogFilter_TransportMoves",     true  },
+    { "creature_moves",      "LogFilter_CreatureMoves",      true  },
+    { "visibility_changes",  "LogFilter_VisibilityChanges",  true  },
+    { "",                    "",                             true  },
+    { "weather",             "LogFilter_Weather",            true  },
+    { "player_stats",        "LogFilter_PlayerStats",        false },
+    { "sql_text",            "LogFilter_SQLText",            true  },
+    { "player_moves",        "LogFilter_PlayerMoves",        true  },
+    { "periodic_effects",    "LogFilter_PeriodicAffects",    false },
+    { "ai_and_movegens",     "LogFilter_AIAndMovegens",      false },
+    { "damage",              "LogFilter_Damage",             false },
+    { "combat",              "LogFilter_Combat",             false },
+    { "spell_cast",          "LogFilter_SpellCast",          false },
+    { "db_stricted_check",   "LogFilter_DbStrictedCheck",    true  },
+    { "ahbot_seller",        "LogFilter_AhbotSeller",        true  },
+    { "ahbot_buyer",         "LogFilter_AhbotBuyer",         true  },
+    { "pathfinding",         "LogFilter_Pathfinding",        true  },
+    { "map_loading",         "LogFilter_MapLoading",         true  },
+    { "event_ai_dev",        "LogFilter_EventAiDev",         true  },
+};
+
+enum LogType
+{
+    LogNormal = 0,
+    LogDetails,
+    LogDebug,
+    LogError
+};
+
+const int LogType_count = int(LogError) + 1;
+
+Log::Log() :
+    raLogfile(NULL), logfile(NULL), gmLogfile(NULL), charLogfile(NULL), dberLogfile(NULL),
+#ifdef ENABLE_ELUNA
+    elunaErrLogfile(NULL),
+#endif /* ENABLE_ELUNA */
+
+    eventAiErLogfile(NULL), scriptErrLogFile(NULL), worldLogfile(NULL), wardenLogfile(NULL), m_colored(false),
+    m_includeTime(false), m_gmlog_per_account(false), m_scriptLibName(NULL)
+{
+    Initialize();
+}
+
+void Log::InitColors(const std::string& str)
+{
+    if (str.empty())
+    {
+        m_colored = false;
+        return;
+    }
+
+    int color[4];
+
+    std::istringstream ss(str);
+
+    for (int i = 0; i < LogType_count; ++i)
+    {
+        ss >> color[i];
+
+        if (!ss)
+        {
+            return;
+        }
+
+        if (color[i] < 0 || color[i] >= Color_count)
+        {
+            return;
+        }
+    }
+
+    for (int i = 0; i < LogType_count; ++i)
+    {
+        m_colors[i] = Color(color[i]);
+    }
+
+    m_colored = true;
+}
+
+void Log::SetColor(bool stdout_stream, Color color)
+{
+#if PLATFORM == PLATFORM_WINDOWS
+
+    static WORD WinColorFG[Color_count] =
+    {
+        0,                                                                         // BLACK
+        FOREGROUND_RED,                                                            // RED
+        FOREGROUND_GREEN,                                                          // GREEN
+        FOREGROUND_RED | FOREGROUND_GREEN,                                         // BROWN
+        FOREGROUND_BLUE,                                                           // BLUE
+        FOREGROUND_RED |                    FOREGROUND_BLUE,                       // MAGENTA
+        FOREGROUND_GREEN | FOREGROUND_BLUE,                                        // CYAN
+        FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE,                       // WHITE
+        FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_INTENSITY,                  // YELLOW
+        FOREGROUND_RED | FOREGROUND_INTENSITY,                                     // RED_BOLD
+        FOREGROUND_GREEN | FOREGROUND_INTENSITY,                                   // GREEN_BOLD
+        FOREGROUND_BLUE | FOREGROUND_INTENSITY,                                    // BLUE_BOLD
+        FOREGROUND_RED | FOREGROUND_BLUE | FOREGROUND_INTENSITY,                   // MAGENTA_BOLD
+        FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY,                 // CYAN_BOLD
+        FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY // WHITE_BOLD
+    };
+
+    HANDLE hConsole = GetStdHandle(stdout_stream ? STD_OUTPUT_HANDLE : STD_ERROR_HANDLE);
+    SetConsoleTextAttribute(hConsole, WinColorFG[color]);
+#else
+
+    enum ANSITextAttr
+    {
+        TA_NORMAL = 0,
+        TA_BOLD = 1,
+        TA_BLINK = 5,
+        TA_REVERSE = 7
+    };
+
+    enum ANSIFgTextAttr
+    {
+        FG_BLACK = 30, FG_RED,  FG_GREEN, FG_BROWN, FG_BLUE,
+        FG_MAGENTA,  FG_CYAN, FG_WHITE, FG_YELLOW
+    };
+
+    enum ANSIBgTextAttr
+    {
+        BG_BLACK = 40, BG_RED,  BG_GREEN, BG_BROWN, BG_BLUE,
+        BG_MAGENTA,  BG_CYAN, BG_WHITE
+    };
+
+    static uint8 UnixColorFG[Color_count] =
+    {
+        FG_BLACK,                                           // BLACK
+        FG_RED,                                             // RED
+        FG_GREEN,                                           // GREEN
+        FG_BROWN,                                           // BROWN
+        FG_BLUE,                                            // BLUE
+        FG_MAGENTA,                                         // MAGENTA
+        FG_CYAN,                                            // CYAN
+        FG_WHITE,                                           // WHITE
+        FG_YELLOW,                                          // YELLOW
+        FG_RED,                                             // LRED
+        FG_GREEN,                                           // LGREEN
+        FG_BLUE,                                            // LBLUE
+        FG_MAGENTA,                                         // LMAGENTA
+        FG_CYAN,                                            // LCYAN
+        FG_WHITE                                            // LWHITE
+    };
+
+    fprintf((stdout_stream ? stdout : stderr), "\x1b[%d%sm", UnixColorFG[color], (color >= YELLOW && color < Color_count ? ";1" : ""));
+#endif
+
+}
+
+void Log::ResetColor(bool stdout_stream)
+{
+#if PLATFORM == PLATFORM_WINDOWS
+    HANDLE hConsole = GetStdHandle(stdout_stream ? STD_OUTPUT_HANDLE : STD_ERROR_HANDLE);
+    SetConsoleTextAttribute(hConsole, FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED);
+#else
+    fprintf((stdout_stream ? stdout : stderr), "\x1b[0m");
+#endif
+
+}
+
+void Log::SetLogLevel(char* level)
+{
+    int32 newLevel = atoi((char*)level);
+
+    if (newLevel < LOG_LVL_MINIMAL)
+    {
+        newLevel = LOG_LVL_MINIMAL;
+    }
+    else if (newLevel > LOG_LVL_DEBUG)
+    {
+        newLevel = LOG_LVL_DEBUG;
+    }
+
+    m_logLevel = LogLevel(newLevel);
+
+    printf("LogLevel is %u\n", m_logLevel);
+}
+
+void Log::SetLogFileLevel(char* level)
+{
+    int32 newLevel = atoi((char*)level);
+
+    if (newLevel < LOG_LVL_MINIMAL)
+    {
+        newLevel = LOG_LVL_MINIMAL;
+    }
+    else if (newLevel > LOG_LVL_DEBUG)
+    {
+        newLevel = LOG_LVL_DEBUG;
+    }
+
+    m_logFileLevel = LogLevel(newLevel);
+
+    printf("LogFileLevel is %u\n", m_logFileLevel);
+}
+
+void Log::Initialize()
+{
+    /// Common log files data
+    m_logsDir = sConfig.GetStringDefault("LogsDir", "");
+    if (!m_logsDir.empty())
+    {
+        if ((m_logsDir.at(m_logsDir.length() - 1) != '/') && (m_logsDir.at(m_logsDir.length() - 1) != '\\'))
+        {
+            m_logsDir.append("/");
+        }
+    }
+
+    m_logsTimestamp = "_" + GetTimestampStr();
+
+    /// Open specific log files
+    logfile = openLogFile("LogFile", "LogTimestamp", "w");
+
+    m_gmlog_per_account = sConfig.GetBoolDefault("GmLogPerAccount", false);
+    if (!m_gmlog_per_account)
+    {
+        gmLogfile = openLogFile("GMLogFile", "GmLogTimestamp", "a");
+    }
+    else
+    {
+        // GM log settings for per account case
+        m_gmlog_filename_format = sConfig.GetStringDefault("GMLogFile", "");
+        if (!m_gmlog_filename_format.empty())
+        {
+            bool m_gmlog_timestamp = sConfig.GetBoolDefault("GmLogTimestamp", false);
+
+            size_t dot_pos = m_gmlog_filename_format.find_last_of(".");
+            if (dot_pos != m_gmlog_filename_format.npos)
+            {
+                if (m_gmlog_timestamp)
+                {
+                    m_gmlog_filename_format.insert(dot_pos, m_logsTimestamp);
+                }
+
+                m_gmlog_filename_format.insert(dot_pos, "_#%u");
+            }
+            else
+            {
+                m_gmlog_filename_format += "_#%u";
+
+                if (m_gmlog_timestamp)
+                {
+                    m_gmlog_filename_format += m_logsTimestamp;
+                }
+            }
+
+            m_gmlog_filename_format = m_logsDir + m_gmlog_filename_format;
+        }
+    }
+
+    charLogfile = openLogFile("CharLogFile", "CharLogTimestamp", "a");
+    dberLogfile = openLogFile("DBErrorLogFile", NULL, "a");
+#ifdef ENABLE_ELUNA
+    elunaErrLogfile = openLogFile("ElunaErrorLogFile", NULL, "a");
+#endif /* ENABLE_ELUNA */
+
+    eventAiErLogfile = openLogFile("EventAIErrorLogFile", NULL, "a");
+    raLogfile = openLogFile("RaLogFile", NULL, "a");
+    worldLogfile = openLogFile("WorldLogFile", "WorldLogTimestamp", "a");
+    wardenLogfile = openLogFile("WardenLogFile", "WardenLogTimestamp", "a");
+
+    // Main log file settings
+    m_includeTime  = sConfig.GetBoolDefault("LogTime", false);
+    m_logLevel     = LogLevel(sConfig.GetIntDefault("LogLevel", 0));
+    m_logFileLevel = LogLevel(sConfig.GetIntDefault("LogFileLevel", 0));
+    InitColors(sConfig.GetStringDefault("LogColors", ""));
+
+    m_logFilter = 0;
+    for (int i = 0; i < LOG_FILTER_COUNT; ++i)
+        if (*logFilterData[i].name)
+            if (sConfig.GetBoolDefault(logFilterData[i].configName, logFilterData[i].defaultState))
+            {
+                m_logFilter |= (1 << i);
+            }
+
+    // Char log settings
+    m_charLog_Dump = sConfig.GetBoolDefault("CharLogDump", false);
+}
+
+FILE* Log::openLogFile(char const* configFileName, char const* configTimeStampFlag, char const* mode)
+{
+    std::string logfn = sConfig.GetStringDefault(configFileName, "");
+    if (logfn.empty())
+    {
+        return NULL;
+    }
+
+    if (configTimeStampFlag && sConfig.GetBoolDefault(configTimeStampFlag, false))
+    {
+        size_t dot_pos = logfn.find_last_of(".");
+        if (dot_pos != logfn.npos)
+        {
+            logfn.insert(dot_pos, m_logsTimestamp);
+        }
+        else
+        {
+            logfn += m_logsTimestamp;
+        }
+    }
+
+    return fopen((m_logsDir + logfn).c_str(), mode);
+}
+
+FILE* Log::openGmlogPerAccount(uint32 account)
+{
+    if (m_gmlog_filename_format.empty())
+    {
+        return NULL;
+    }
+
+    char namebuf[MANGOS_PATH_MAX];
+    snprintf(namebuf, MANGOS_PATH_MAX, m_gmlog_filename_format.c_str(), account);
+    return fopen(namebuf, "a");
+}
+
+void Log::outTimestamp(FILE* file)
+{
+    time_t tt = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());
+    std::tm aTm = localtime_r(tt);
+
+    //       YYYY   year
+    //       MM     month (2 digits 01-12)
+    //       DD     day (2 digits 01-31)
+    //       HH     hour (2 digits 00-23)
+    //       MM     minutes (2 digits 00-59)
+    //       SS     seconds (2 digits 00-59)
+    fprintf(file, "%-4d-%02d-%02d %02d:%02d:%02d ", aTm.tm_year + 1900, aTm.tm_mon + 1, aTm.tm_mday, aTm.tm_hour, aTm.tm_min, aTm.tm_sec);
+}
+
+void Log::outTime()
+{
+    time_t tt = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());
+    std::tm aTm = localtime_r(tt);
+
+    //       YYYY   year
+    //       MM     month (2 digits 01-12)
+    //       DD     day (2 digits 01-31)
+    //       HH     hour (2 digits 00-23)
+    //       MM     minutes (2 digits 00-59)
+    //       SS     seconds (2 digits 00-59)
+    printf("%02d:%02d:%02d ", aTm.tm_hour, aTm.tm_min, aTm.tm_sec);
+}
+
+std::string Log::GetTimestampStr()
+{
+    time_t tt = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());
+    std::tm aTm = localtime_r(tt);
+
+    //       YYYY   year
+    //       MM     month (2 digits 01-12)
+    //       DD     day (2 digits 01-31)
+    //       HH     hour (2 digits 00-23)
+    //       MM     minutes (2 digits 00-59)
+    //       SS     seconds (2 digits 00-59)
+    char buf[20];
+    snprintf(buf, 20, "%04d-%02d-%02d_%02d-%02d-%02d", aTm.tm_year + 1900, aTm.tm_mon + 1, aTm.tm_mday, aTm.tm_hour, aTm.tm_min, aTm.tm_sec);
+    return std::string(buf);
+}
+
+void Log::outString()
+{
+    if (m_includeTime)
+    {
+        outTime();
+    }
+    printf("\n");
+    if (logfile)
+    {
+        outTimestamp(logfile);
+        fprintf(logfile, "\n");
+        fflush(logfile);
+    }
+
+    fflush(stdout);
+}
+
+void Log::outString(const char* str, ...)
+{
+    if (!str)
+    {
+        return;
+    }
+
+    if (m_colored)
+    {
+        SetColor(true, m_colors[LogNormal]);
+    }
+
+    if (m_includeTime)
+    {
+        outTime();
+    }
+
+    va_list ap;
+
+    va_start(ap, str);
+    vutf8printf(stdout, str, &ap);
+    va_end(ap);
+
+    if (m_colored)
+    {
+        ResetColor(true);
+    }
+
+    printf("\n");
+
+    if (logfile)
+    {
+        outTimestamp(logfile);
+
+        va_start(ap, str);
+        vfprintf(logfile, str, ap);
+        fprintf(logfile, "\n");
+        va_end(ap);
+
+        fflush(logfile);
+    }
+
+    fflush(stdout);
+}
+
+void Log::outError(const char* err, ...)
+{
+    if (!err)
+    {
+        return;
+    }
+
+    if (m_colored)
+    {
+        SetColor(false, m_colors[LogError]);
+    }
+
+    if (m_includeTime)
+    {
+        outTime();
+    }
+
+    va_list ap;
+
+    va_start(ap, err);
+    vutf8printf(stderr, err, &ap);
+    va_end(ap);
+
+    if (m_colored)
+    {
+        ResetColor(false);
+    }
+
+    fprintf(stderr, "\n");
+    if (logfile)
+    {
+        outTimestamp(logfile);
+        fprintf(logfile, "ERROR:");
+
+        va_start(ap, err);
+        vfprintf(logfile, err, ap);
+        va_end(ap);
+
+        fprintf(logfile, "\n");
+        fflush(logfile);
+    }
+
+    fflush(stderr);
+}
+
+void Log::outErrorDb()
+{
+    if (m_includeTime)
+    {
+        outTime();
+    }
+
+    fprintf(stderr, "\n");
+
+    if (logfile)
+    {
+        outTimestamp(logfile);
+        fprintf(logfile, "ERROR:\n");
+        fflush(logfile);
+    }
+
+    if (dberLogfile)
+    {
+        outTimestamp(dberLogfile);
+        fprintf(dberLogfile, "\n");
+        fflush(dberLogfile);
+    }
+
+    fflush(stderr);
+}
+
+void Log::outErrorDb(const char* err, ...)
+{
+    if (!err)
+    {
+        return;
+    }
+
+    if (m_colored)
+    {
+        SetColor(false, m_colors[LogError]);
+    }
+
+    if (m_includeTime)
+    {
+        outTime();
+    }
+
+    va_list ap;
+
+    va_start(ap, err);
+    vutf8printf(stderr, err, &ap);
+    va_end(ap);
+
+    if (m_colored)
+    {
+        ResetColor(false);
+    }
+
+    fprintf(stderr, "\n");
+
+    if (logfile)
+    {
+        outTimestamp(logfile);
+        fprintf(logfile, "ERROR:");
+
+        va_start(ap, err);
+        vfprintf(logfile, err, ap);
+        va_end(ap);
+
+        fprintf(logfile, "\n");
+        fflush(logfile);
+    }
+
+    if (dberLogfile)
+    {
+        outTimestamp(dberLogfile);
+
+        va_list ap;
+        va_start(ap, err);
+        vfprintf(dberLogfile, err, ap);
+        va_end(ap);
+
+        fprintf(dberLogfile, "\n");
+        fflush(dberLogfile);
+    }
+
+    fflush(stderr);
+}
+
+#ifdef ENABLE_ELUNA
+void Log::outErrorEluna()
+{
+    if (m_includeTime)
+    {
+        outTime();
+    }
+
+    fprintf(stderr, "\n");
+
+    if (logfile)
+    {
+        outTimestamp(logfile);
+        fprintf(logfile, "ERROR Eluna\n");
+        fflush(logfile);
+    }
+
+    if (elunaErrLogfile)
+    {
+        outTimestamp(elunaErrLogfile);
+        fprintf(elunaErrLogfile, "\n");
+        fflush(elunaErrLogfile);
+    }
+
+    fflush(stderr);
+}
+#else
+/* This is made to not fiddle with the eluna code in LuaEngine/ at all */
+void Log::outErrorEluna() {}
+#endif /* ENABLE_ELUNA */
+
+#ifdef ENABLE_ELUNA
+void Log::outErrorEluna(const char* err, ...)
+{
+    if (!err)
+    {
+        return;
+    }
+
+    if (m_colored)
+    {
+        SetColor(false, m_colors[LogError]);
+    }
+
+    if (m_includeTime)
+    {
+        outTime();
+    }
+
+    va_list ap;
+
+    va_start(ap, err);
+    vutf8printf(stderr, err, &ap);
+    va_end(ap);
+
+    if (m_colored)
+    {
+        ResetColor(false);
+    }
+
+    fprintf(stderr, "\n");
+
+    if (logfile)
+    {
+        outTimestamp(logfile);
+        fprintf(logfile, "ERROR Eluna: ");
+
+        va_start(ap, err);
+        vfprintf(logfile, err, ap);
+        va_end(ap);
+
+        fprintf(logfile, "\n");
+        fflush(logfile);
+    }
+
+    if (elunaErrLogfile)
+    {
+        outTimestamp(elunaErrLogfile);
+
+        va_list ap;
+        va_start(ap, err);
+        vfprintf(elunaErrLogfile, err, ap);
+        va_end(ap);
+
+        fprintf(elunaErrLogfile, "\n");
+        fflush(elunaErrLogfile);
+    }
+
+    fflush(stderr);
+}
+#else
+/* This is made to not fiddle with the eluna code in LuaEngine/ at all */
+void Log::outErrorEluna(const char* err, ...) {}
+#endif /* ENABLE_ELUNA */
+
+void Log::outErrorEventAI()
+{
+    if (m_includeTime)
+    {
+        outTime();
+    }
+
+    fprintf(stderr, "\n");
+
+    if (logfile)
+    {
+        outTimestamp(logfile);
+        fprintf(logfile, "ERROR CreatureEventAI\n");
+        fflush(logfile);
+    }
+
+    if (eventAiErLogfile)
+    {
+        outTimestamp(eventAiErLogfile);
+        fprintf(eventAiErLogfile, "\n");
+        fflush(eventAiErLogfile);
+    }
+
+    fflush(stderr);
+}
+
+void Log::outErrorEventAI(const char* err, ...)
+{
+    if (!err)
+    {
+        return;
+    }
+
+    if (m_colored)
+    {
+        SetColor(false, m_colors[LogError]);
+    }
+
+    if (m_includeTime)
+    {
+        outTime();
+    }
+
+    va_list ap;
+
+    va_start(ap, err);
+    vutf8printf(stderr, err, &ap);
+    va_end(ap);
+
+    if (m_colored)
+    {
+        ResetColor(false);
+    }
+
+    fprintf(stderr, "\n");
+
+    if (logfile)
+    {
+        outTimestamp(logfile);
+        fprintf(logfile, "ERROR CreatureEventAI: ");
+
+        va_start(ap, err);
+        vfprintf(logfile, err, ap);
+        va_end(ap);
+
+        fprintf(logfile, "\n");
+        fflush(logfile);
+    }
+
+    if (eventAiErLogfile)
+    {
+        outTimestamp(eventAiErLogfile);
+
+        va_list ap;
+        va_start(ap, err);
+        vfprintf(eventAiErLogfile, err, ap);
+        va_end(ap);
+
+        fprintf(eventAiErLogfile, "\n");
+        fflush(eventAiErLogfile);
+    }
+
+    fflush(stderr);
+}
+
+void Log::outBasic(const char* str, ...)
+{
+    if (!str)
+    {
+        return;
+    }
+
+    if (m_logLevel >= LOG_LVL_BASIC)
+    {
+        if (m_colored)
+        {
+            SetColor(true, m_colors[LogDetails]);
+        }
+
+        if (m_includeTime)
+        {
+            outTime();
+        }
+
+        va_list ap;
+        va_start(ap, str);
+        vutf8printf(stdout, str, &ap);
+        va_end(ap);
+
+        if (m_colored)
+        {
+            ResetColor(true);
+        }
+
+        printf("\n");
+    }
+
+    if (logfile && m_logFileLevel >= LOG_LVL_BASIC)
+    {
+        va_list ap;
+        outTimestamp(logfile);
+        va_start(ap, str);
+        vfprintf(logfile, str, ap);
+        fprintf(logfile, "\n");
+        va_end(ap);
+        fflush(logfile);
+    }
+
+    fflush(stdout);
+}
+
+void Log::outDetail(const char* str, ...)
+{
+    if (!str)
+    {
+        return;
+    }
+
+    if (m_logLevel >= LOG_LVL_DETAIL)
+    {
+        if (m_colored)
+        {
+            SetColor(true, m_colors[LogDetails]);
+        }
+
+        if (m_includeTime)
+        {
+            outTime();
+        }
+
+        va_list ap;
+        va_start(ap, str);
+        vutf8printf(stdout, str, &ap);
+        va_end(ap);
+
+        if (m_colored)
+        {
+            ResetColor(true);
+        }
+
+        printf("\n");
+    }
+
+    if (logfile && m_logFileLevel >= LOG_LVL_DETAIL)
+    {
+        outTimestamp(logfile);
+
+        va_list ap;
+        va_start(ap, str);
+        vfprintf(logfile, str, ap);
+        va_end(ap);
+
+        fprintf(logfile, "\n");
+        fflush(logfile);
+    }
+
+    fflush(stdout);
+}
+
+void Log::outDebug(const char* str, ...)
+{
+    if (!str)
+    {
+        return;
+    }
+
+    if (m_logLevel >= LOG_LVL_DEBUG)
+    {
+        if (m_colored)
+        {
+            SetColor(true, m_colors[LogDebug]);
+        }
+
+        if (m_includeTime)
+        {
+            outTime();
+        }
+
+        va_list ap;
+        va_start(ap, str);
+        vutf8printf(stdout, str, &ap);
+        va_end(ap);
+
+        if (m_colored)
+        {
+            ResetColor(true);
+        }
+
+        printf("\n");
+    }
+
+    if (logfile && m_logFileLevel >= LOG_LVL_DEBUG)
+    {
+        outTimestamp(logfile);
+
+        va_list ap;
+        va_start(ap, str);
+        vfprintf(logfile, str, ap);
+        va_end(ap);
+
+        fprintf(logfile, "\n");
+        fflush(logfile);
+    }
+
+    fflush(stdout);
+}
+
+void Log::outCommand(uint32 account, const char* str, ...)
+{
+    if (!str)
+    {
+        return;
+    }
+
+    if (m_logLevel >= LOG_LVL_DETAIL)
+    {
+        if (m_colored)
+        {
+            SetColor(true, m_colors[LogDetails]);
+        }
+
+        if (m_includeTime)
+        {
+            outTime();
+        }
+
+        va_list ap;
+        va_start(ap, str);
+        vutf8printf(stdout, str, &ap);
+        va_end(ap);
+
+        if (m_colored)
+        {
+            ResetColor(true);
+        }
+
+        printf("\n");
+    }
+
+    if (logfile && m_logFileLevel >= LOG_LVL_DETAIL)
+    {
+        va_list ap;
+        outTimestamp(logfile);
+        va_start(ap, str);
+        vfprintf(logfile, str, ap);
+        fprintf(logfile, "\n");
+        va_end(ap);
+        fflush(logfile);
+    }
+
+    if (m_gmlog_per_account)
+    {
+        if (FILE* per_file = openGmlogPerAccount(account))
+        {
+            va_list ap;
+            outTimestamp(per_file);
+            va_start(ap, str);
+            vfprintf(per_file, str, ap);
+            fprintf(per_file, "\n");
+            va_end(ap);
+            fclose(per_file);
+        }
+    }
+    else if (gmLogfile)
+    {
+        va_list ap;
+        outTimestamp(gmLogfile);
+        va_start(ap, str);
+        vfprintf(gmLogfile, str, ap);
+        fprintf(gmLogfile, "\n");
+        va_end(ap);
+        fflush(gmLogfile);
+    }
+
+    fflush(stdout);
+}
+
+void Log::outWarden()
+{
+    if (m_includeTime)
+    {
+        outTime();
+    }
+    printf("\n");
+    if (wardenLogfile)
+    {
+        outTimestamp(wardenLogfile);
+        fprintf(wardenLogfile, "\n");
+        fflush(wardenLogfile);
+    }
+
+    fflush(stdout);
+}
+
+void Log::outWarden(const char* str, ...)
+{
+    if (!str)
+    {
+        return;
+    }
+    if (m_logLevel >= LOG_LVL_DETAIL)
+    {
+        if (m_colored)
+        {
+            SetColor(true, m_colors[LogNormal]);
+        }
+
+        if (m_includeTime)
+        {
+            outTime();
+        }
+
+        va_list ap;
+
+        va_start(ap, str);
+        vutf8printf(stdout, str, &ap);
+        va_end(ap);
+
+        if (m_colored)
+        {
+            ResetColor(true);
+        }
+
+        printf("\n");
+    }
+
+    if (wardenLogfile && m_logFileLevel >= LOG_LVL_DETAIL)
+    {
+        va_list ap;
+
+        outTimestamp(wardenLogfile);
+        fprintf(wardenLogfile, "[Warden]: ");
+
+        va_start(ap, str);
+        vfprintf(wardenLogfile, str, ap);
+        fprintf(wardenLogfile, "\n");
+        va_end(ap);
+
+        fflush(wardenLogfile);
+    }
+
+    fflush(stdout);
+}
+
+void Log::outChar(const char* str, ...)
+{
+    if (!str)
+    {
+        return;
+    }
+
+    if (charLogfile)
+    {
+        va_list ap;
+        outTimestamp(charLogfile);
+        va_start(ap, str);
+        vfprintf(charLogfile, str, ap);
+        fprintf(charLogfile, "\n");
+        va_end(ap);
+        fflush(charLogfile);
+    }
+}
+
+void Log::outErrorScriptLib()
+{
+    if (m_includeTime)
+    {
+        outTime();
+    }
+
+    fprintf(stderr, "\n");
+
+    if (logfile)
+    {
+        outTimestamp(logfile);
+        if (m_scriptLibName)
+        {
+            fprintf(logfile, "<%s ERROR:> ", m_scriptLibName);
+        }
+        else
+        {
+            fprintf(logfile, "<Scripting Library ERROR>: ");
+        }
+        fflush(logfile);
+    }
+
+    if (scriptErrLogFile)
+    {
+        outTimestamp(scriptErrLogFile);
+        fprintf(scriptErrLogFile, "\n");
+        fflush(scriptErrLogFile);
+    }
+
+    fflush(stderr);
+}
+
+void Log::outErrorScriptLib(const char* err, ...)
+{
+    if (!err)
+    {
+        return;
+    }
+
+    if (m_colored)
+    {
+        SetColor(false, m_colors[LogError]);
+    }
+
+    if (m_includeTime)
+    {
+        outTime();
+    }
+
+    va_list ap;
+
+    va_start(ap, err);
+    vutf8printf(stderr, err, &ap);
+    va_end(ap);
+
+    if (m_colored)
+    {
+        ResetColor(false);
+    }
+
+    fprintf(stderr, "\n");
+
+    if (logfile)
+    {
+        outTimestamp(logfile);
+        if (m_scriptLibName)
+        {
+            fprintf(logfile, "<%s ERROR>: ", m_scriptLibName);
+        }
+        else
+        {
+            fprintf(logfile, "<Scripting Library ERROR>: ");
+        }
+
+        va_start(ap, err);
+        vfprintf(logfile, err, ap);
+        va_end(ap);
+
+        fprintf(logfile, "\n");
+        fflush(logfile);
+    }
+
+    if (scriptErrLogFile)
+    {
+        outTimestamp(scriptErrLogFile);
+
+        va_list ap;
+        va_start(ap, err);
+        vfprintf(scriptErrLogFile, err, ap);
+        va_end(ap);
+
+        fprintf(scriptErrLogFile, "\n");
+        fflush(scriptErrLogFile);
+    }
+
+    fflush(stderr);
+}
+
+void Log::outWorldPacketDump(uint32 socket, uint32 opcode, char const* opcodeName, ByteBuffer const* packet, bool incoming)
+{
+    if (!worldLogfile)
+    {
+        return;
+    }
+
+    ACE_GUARD(ACE_Thread_Mutex, GuardObj, m_worldLogMtx);
+
+    outTimestamp(worldLogfile);
+
+    fprintf(worldLogfile, "\n%s:\nSOCKET: %u\nLENGTH: " SIZEFMTD "\nOPCODE: %s (0x%.4X)\nDATA:\n",
+            incoming ? "CLIENT" : "SERVER",
+            socket, packet->size(), opcodeName, opcode);
+
+    size_t p = 0;
+    while (p < packet->size())
+    {
+        for (size_t j = 0; j < 16 && p < packet->size(); ++j)
+        {
+            fprintf(worldLogfile, "%.2X ", (*packet)[p++]);
+        }
+
+        fprintf(worldLogfile, "\n");
+    }
+
+    fprintf(worldLogfile, "\n\n");
+    fflush(worldLogfile);
+}
+
+void Log::outCharDump(const char* str, uint32 account_id, uint32 guid, const char* name)
+{
+    if (charLogfile)
+    {
+        fprintf(charLogfile, "== START DUMP == (account: %u guid: %u name: %s )\n%s\n== END DUMP ==\n", account_id, guid, name, str);
+        fflush(charLogfile);
+    }
+}
+
+void Log::outRALog(const char* str, ...)
+{
+    if (!str)
+    {
+        return;
+    }
+
+    if (raLogfile)
+    {
+        va_list ap;
+        outTimestamp(raLogfile);
+        va_start(ap, str);
+        vfprintf(raLogfile, str, ap);
+        fprintf(raLogfile, "\n");
+        va_end(ap);
+        fflush(raLogfile);
+    }
+
+    fflush(stdout);
+}
+
+void Log::WaitBeforeContinueIfNeed()
+{
+    int mode = sConfig.GetIntDefault("WaitAtStartupError", 0);
+
+    if (mode < 0)
+    {
+        printf("\nPress <Enter> for continue\n");
+
+        std::string line;
+        std::getline(std::cin, line);
+    }
+    else if (mode > 0)
+    {
+        printf("\nWait %u secs for continue.\n", mode);
+        BarGoLink bar(mode);
+        for (int i = 0; i < mode; ++i)
+        {
+            bar.step();
+            ACE_OS::sleep(1);
+        }
+    }
+}
+
+void Log::setScriptLibraryErrorFile(char const* fname, char const* libName)
+{
+    m_scriptLibName = libName;
+
+    if (scriptErrLogFile)
+    {
+        fclose(scriptErrLogFile);
+    }
+
+    if (!fname)
+    {
+        scriptErrLogFile = NULL;
+        return;
+    }
+
+    std::string fileName = m_logsDir;
+    fileName.append(fname);
+    scriptErrLogFile = fopen(fileName.c_str(), "a");
+}
+
+void outstring_log(const char* str, ...)
+{
+    if (!str)
+    {
+        return;
+    }
+
+    char buf[256];
+    va_list ap;
+    va_start(ap, str);
+    vsnprintf(buf, 256, str, ap);
+    va_end(ap);
+
+    sLog.outString("%s", buf);
+}
+
+void detail_log(const char* str, ...)
+{
+    if (!str)
+    {
+        return;
+    }
+
+    char buf[256];
+    va_list ap;
+    va_start(ap, str);
+    vsnprintf(buf, 256, str, ap);
+    va_end(ap);
+
+    sLog.outDetail("%s", buf);
+}
+
+void debug_log(const char* str, ...)
+{
+    if (!str)
+    {
+        return;
+    }
+
+    char buf[256];
+    va_list ap;
+    va_start(ap, str);
+    vsnprintf(buf, 256, str, ap);
+    va_end(ap);
+
+    DEBUG_LOG("%s", buf);
+}
+
+void error_log(const char* str, ...)
+{
+    if (!str)
+    {
+        return;
+    }
+
+    char buf[256];
+    va_list ap;
+    va_start(ap, str);
+    vsnprintf(buf, 256, str, ap);
+    va_end(ap);
+
+    sLog.outError("%s", buf);
+}
+
+void error_db_log(const char* str, ...)
+{
+    if (!str)
+    {
+        return;
+    }
+
+    char buf[256];
+    va_list ap;
+    va_start(ap, str);
+    vsnprintf(buf, 256, str, ap);
+    va_end(ap);
+
+    sLog.outErrorDb("%s", buf);
+}
+
+void setScriptLibraryErrorFile(char const* fname, char const* libName)
+{
+    sLog.setScriptLibraryErrorFile(fname, libName);
+}
+
+void script_error_log(const char* str, ...)
+{
+    if (!str)
+    {
+        return;
+    }
+
+    char buf[256];
+    va_list ap;
+    va_start(ap, str);
+    vsnprintf(buf, 256, str, ap);
+    va_end(ap);
+
+    sLog.outErrorScriptLib("%s", buf);
+}
diff --git a/shared/Log/Log.h b/shared/Log/Log.h
new file mode 100644
index 0000000..78a4be5
--- /dev/null
+++ b/shared/Log/Log.h
@@ -0,0 +1,605 @@
+/**
+ * MaNGOS is a full featured server for World of Warcraft, supporting
+ * the following clients: 1.12.x, 2.4.3, 3.3.5a, 4.3.4a and 5.4.8
+ *
+ * Copyright (C) 2005-2022 MaNGOS <https://getmangos.eu>
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * World of Warcraft, and all World of Warcraft or Warcraft art, images,
+ * and lore are copyrighted by Blizzard Entertainment, Inc.
+ */
+
+#ifndef MANGOSSERVER_LOG_H
+#define MANGOSSERVER_LOG_H
+
+#include "Common/Common.h"
+#include "Policies/Singleton.h"
+
+class Config;
+class ByteBuffer;
+
+/**
+ * @brief various levels for logging
+ *
+ */
+enum LogLevel
+{
+    LOG_LVL_MINIMAL = 0,
+    LOG_LVL_BASIC   = 1,
+    LOG_LVL_DETAIL  = 2,
+    LOG_LVL_DEBUG   = 3
+};
+
+/**
+ * @brief bitmask (not forgot update logFilterData content)
+ *
+ */
+enum LogFilters
+{
+    LOG_FILTER_TRANSPORT_MOVES    = 0x000001,               //  0 any related to transport moves
+    LOG_FILTER_CREATURE_MOVES     = 0x000002,               //  1 creature move by cells
+    LOG_FILTER_VISIBILITY_CHANGES = 0x000004,               //  2 update visibility for diff objects and players
+    // reserved for future version
+    LOG_FILTER_WEATHER            = 0x000010,               //  4 weather changes
+    LOG_FILTER_PLAYER_STATS       = 0x000020,               //  5 player save data
+    LOG_FILTER_SQL_TEXT           = 0x000040,               //  6 raw SQL text send to DB engine
+    LOG_FILTER_PLAYER_MOVES       = 0x000080,               //  7 player moves by grid/cell
+    LOG_FILTER_PERIODIC_AFFECTS   = 0x000100,               //  8 DoT/HoT apply trace
+    LOG_FILTER_AI_AND_MOVEGENSS   = 0x000200,               //  9 AI/movement generators debug output
+    LOG_FILTER_DAMAGE             = 0x000400,               // 10 Direct/Area damage trace
+    LOG_FILTER_COMBAT             = 0x000800,               // 11 attack states/roll attack results/etc
+    LOG_FILTER_SPELL_CAST         = 0x001000,               // 12 spell cast/aura apply/spell proc events
+    LOG_FILTER_DB_STRICTED_CHECK  = 0x002000,               // 13 stricted DB data checks output (with possible false reports) for DB devs
+    LOG_FILTER_AHBOT_SELLER       = 0x004000,               // 14 Auction House Bot seller part
+    LOG_FILTER_AHBOT_BUYER        = 0x008000,               // 15 Auction House Bot buyer part
+    LOG_FILTER_PATHFINDING        = 0x010000,               // 16 Pathfinding
+    LOG_FILTER_MAP_LOADING        = 0x020000,               // 17 Map loading/unloading (MAP, VMAPS, MMAP)
+    LOG_FILTER_EVENT_AI_DEV       = 0x040000,               // 18 Event AI actions
+};
+
+#define LOG_FILTER_COUNT            19
+
+/**
+ * @brief
+ *
+ */
+struct LogFilterData
+{
+    char const* name; /**< TODO */
+    char const* configName; /**< TODO */
+    bool defaultState; /**< TODO */
+};
+
+extern LogFilterData logFilterData[LOG_FILTER_COUNT]; /**< TODO */
+
+/**
+ * @brief
+ *
+ */
+enum Color
+{
+    BLACK,
+    RED,
+    GREEN,
+    BROWN,
+    BLUE,
+    MAGENTA,
+    CYAN,
+    GREY,
+    YELLOW,
+    LRED,
+    LGREEN,
+    LBLUE,
+    LMAGENTA,
+    LCYAN,
+    WHITE
+};
+
+const int Color_count = int(WHITE) + 1; /**< TODO */
+
+/**
+ * @brief
+ *
+ */
+class Log : public MaNGOS::Singleton<Log, MaNGOS::ClassLevelLockable<Log, ACE_Thread_Mutex> >
+{
+        friend class MaNGOS::OperatorNew<Log>;
+        /**
+         * @brief
+         *
+         */
+        Log();
+
+        /**
+         * @brief
+         *
+         */
+        ~Log()
+        {
+            if (logfile != NULL)
+            {
+                fclose(logfile);
+            }
+            logfile = NULL;
+
+            if (gmLogfile != NULL)
+            {
+                fclose(gmLogfile);
+            }
+            gmLogfile = NULL;
+
+            if (charLogfile != NULL)
+            {
+                fclose(charLogfile);
+            }
+            charLogfile = NULL;
+
+            if (dberLogfile != NULL)
+            {
+                fclose(dberLogfile);
+            }
+            dberLogfile = NULL;
+
+#ifdef ENABLE_ELUNA
+            if (elunaErrLogfile != NULL)
+            {
+                fclose(elunaErrLogfile);
+            }
+            elunaErrLogfile = NULL;
+#endif /* ENABLE_ELUNA */
+
+            if (eventAiErLogfile != NULL)
+            {
+                fclose(eventAiErLogfile);
+            }
+            eventAiErLogfile = NULL;
+
+            if (scriptErrLogFile != NULL)
+            {
+                fclose(scriptErrLogFile);
+            }
+            scriptErrLogFile = NULL;
+
+            if (raLogfile != NULL)
+            {
+                fclose(raLogfile);
+            }
+            raLogfile = NULL;
+
+            if (worldLogfile != NULL)
+            {
+                fclose(worldLogfile);
+            }
+            worldLogfile = NULL;
+
+            if (wardenLogfile != NULL)
+            {
+                fclose(wardenLogfile);
+            }
+            wardenLogfile = NULL;
+        }
+    public:
+        /**
+         * @brief
+         *
+         */
+        void Initialize();
+        /**
+         * @brief
+         *
+         * @param init_str
+         */
+        void InitColors(const std::string& init_str);
+
+        /**
+         * @brief
+         *
+         * @param account
+         * @param str...
+         */
+        void outCommand(uint32 account, const char* str, ...) ATTR_PRINTF(3, 4);
+        /**
+         * @brief any log level
+         *
+         */
+        void outString();
+        /**
+         * @brief any log level
+         *
+         * @param str...
+         */
+        void outString(const char* str, ...)      ATTR_PRINTF(2, 3);
+        /**
+         * @brief any log level
+         *
+         * @param err...
+         */
+        void outError(const char* err, ...)       ATTR_PRINTF(2, 3);
+        /**
+         * @brief log level >= 1
+         *
+         * @param str...
+         */
+        void outBasic(const char* str, ...)       ATTR_PRINTF(2, 3);
+        /**
+         * @brief log level >= 2
+         *
+         * @param str...
+         */
+        void outDetail(const char* str, ...)      ATTR_PRINTF(2, 3);
+        /**
+         * @brief log level >= 3
+         *
+         * @param str...
+         */
+        void outDebug(const char* str, ...)       ATTR_PRINTF(2, 3);
+        /**
+         * @brief any log level
+         *
+         */
+        void outErrorDb();
+        /**
+         * @brief any log level
+         *
+         * @param str...
+         */
+        void outErrorDb(const char* str, ...)     ATTR_PRINTF(2, 3);
+        /**
+         * @brief any log level
+         *
+         * @param str...
+         */
+        void outChar(const char* str, ...)        ATTR_PRINTF(2, 3);
+        /**
+         * @brief any log level
+         *
+         * @param str...
+         */
+        void outErrorEluna();
+        /**
+         * @brief any log level
+         *
+         * @param str...
+         */
+        void outErrorEluna(const char* str, ...)        ATTR_PRINTF(2, 3);
+        /**
+         * @brief any log level
+         *
+         */
+        void outErrorEventAI();
+        /**
+         * @brief any log level
+         *
+         * @param str...
+         */
+        void outErrorEventAI(const char* str, ...)      ATTR_PRINTF(2, 3);
+
+        /**
+         * @brief any log level
+         *
+         */
+        void outErrorScriptLib();
+        /**
+         * @brief any log level
+         *
+         * @param str...
+         */
+        void outErrorScriptLib(const char* str, ...)     ATTR_PRINTF(2, 3);
+
+        /**
+         * @brief any log level
+         *
+         * @param socket
+         * @param opcode
+         * @param opcodeName
+         * @param packet
+         * @param incoming
+         */
+        void outWorldPacketDump(uint32 socket, uint32 opcode, char const* opcodeName, ByteBuffer const* packet, bool incoming);
+        /**
+         * @brief any log level
+         *
+         * @param str
+         * @param account_id
+         * @param guid
+         * @param name
+         */
+        void outCharDump(const char* str, uint32 account_id, uint32 guid, const char* name);
+        /**
+         * @brief
+         *
+         * @param str...
+         */
+        void outRALog(const char* str, ...)       ATTR_PRINTF(2, 3);
+        /**
+        * @brief any log level
+        *
+        */
+        void outWarden();
+        /**
+        * @brief any log level
+        *
+        * @param str...
+        */
+        void outWarden(const char* str, ...)      ATTR_PRINTF(2, 3);
+        /**
+         * @brief
+         *
+         * @return uint32
+         */
+        uint32 GetLogLevel() const { return m_logLevel; }
+        /**
+         * @brief
+         *
+         * @param Level
+         */
+        void SetLogLevel(char* Level);
+        /**
+         * @brief
+         *
+         * @param Level
+         */
+        void SetLogFileLevel(char* Level);
+        /**
+         * @brief
+         *
+         * @param stdout_stream
+         * @param color
+         */
+        void SetColor(bool stdout_stream, Color color);
+        /**
+         * @brief
+         *
+         * @param stdout_stream
+         */
+        void ResetColor(bool stdout_stream);
+        /**
+         * @brief
+         *
+         */
+        void outTime();
+        /**
+         * @brief
+         *
+         * @param file
+         */
+        static void outTimestamp(FILE* file);
+        /**
+         * @brief
+         *
+         * @return std::string
+         */
+        static std::string GetTimestampStr();
+        /**
+         * @brief
+         *
+         * @param filter
+         * @return bool
+         */
+        bool HasLogFilter(uint32 filter) const { return m_logFilter & filter; }
+        /**
+         * @brief
+         *
+         * @param filter
+         * @param on
+         */
+        void SetLogFilter(LogFilters filter, bool on) { if (on) { m_logFilter |= filter; } else { m_logFilter &= ~filter; } }
+        /**
+         * @brief
+         *
+         * @param loglvl
+         * @return bool
+         */
+        bool HasLogLevelOrHigher(LogLevel loglvl) const { return m_logLevel >= loglvl || (m_logFileLevel >= loglvl && logfile); }
+        /**
+         * @brief
+         *
+         * @return bool
+         */
+        bool IsOutCharDump() const { return m_charLog_Dump; }
+        /**
+         * @brief
+         *
+         * @return bool
+         */
+        bool IsIncludeTime() const { return m_includeTime; }
+
+        /**
+         * @brief
+         *
+         */
+        static void WaitBeforeContinueIfNeed();
+
+        /**
+         * @brief Set filename for scriptlibrary error output
+         *
+         * @param fname
+         * @param libName
+         */
+        void setScriptLibraryErrorFile(char const* fname, char const* libName);
+
+    private:
+        /**
+         * @brief
+         *
+         * @param configFileName
+         * @param configTimeStampFlag
+         * @param mode
+         * @return FILE
+         */
+        FILE* openLogFile(char const* configFileName, char const* configTimeStampFlag, char const* mode);
+        /**
+         * @brief
+         *
+         * @param account
+         * @return FILE
+         */
+        FILE* openGmlogPerAccount(uint32 account);
+
+        FILE* raLogfile; /**< TODO */
+        FILE* logfile; /**< TODO */
+        FILE* gmLogfile; /**< TODO */
+        FILE* charLogfile; /**< TODO */
+        FILE* dberLogfile; /**< TODO */
+#ifdef ENABLE_ELUNA
+        FILE* elunaErrLogfile; /**< TODO */
+#endif /* ENABLE_ELUNA */
+
+        FILE* eventAiErLogfile; /**< TODO */
+        FILE* scriptErrLogFile; /**< TODO */
+        FILE* worldLogfile; /**< TODO */
+        FILE* wardenLogfile; /**< TODO */
+        ACE_Thread_Mutex m_worldLogMtx; /**< TODO */
+
+        LogLevel m_logLevel; /**< log/console control */
+        LogLevel m_logFileLevel; /**< TODO */
+        bool m_colored; /**< TODO */
+        bool m_includeTime; /**< TODO */
+        Color m_colors[4]; /**< TODO */
+        uint32 m_logFilter; /**< TODO */
+
+        // cache values for after initilization use (like gm log per account case)
+        std::string m_logsDir; /**< TODO */
+        std::string m_logsTimestamp; /**< TODO */
+
+        // char log control
+        bool m_charLog_Dump; /**< TODO */
+
+        // gm log control
+        bool m_gmlog_per_account; /**< TODO */
+        std::string m_gmlog_filename_format; /**< TODO */
+
+        char const* m_scriptLibName; /**< TODO */
+};
+
+#define sLog MaNGOS::Singleton<Log>::Instance()
+
+#define BASIC_LOG(...)                                  \
+    do                                                  \
+    {                                                   \
+        if (sLog.HasLogLevelOrHigher(LOG_LVL_BASIC))    \
+        {                                               \
+            sLog.outBasic(__VA_ARGS__);                 \
+        }                                               \
+    } while(0)
+
+#define BASIC_FILTER_LOG(F,...)                         \
+    do                                                  \
+    {                                                   \
+        if (sLog.HasLogLevelOrHigher(LOG_LVL_BASIC) && !sLog.HasLogFilter(F)) \
+        {                                               \
+            sLog.outBasic(__VA_ARGS__);                 \
+        }                                               \
+    } while(0)
+
+#define DETAIL_LOG(...)                                 \
+    do                                                  \
+    {                                                   \
+        if (sLog.HasLogLevelOrHigher(LOG_LVL_DETAIL))   \
+        {                                               \
+            sLog.outDetail(__VA_ARGS__);                \
+        }                                               \
+    }                                                   \
+    while(0)
+
+#define DETAIL_FILTER_LOG(F,...)                        \
+    do                                                  \
+    {                                                   \
+        if (sLog.HasLogLevelOrHigher(LOG_LVL_DETAIL) && !sLog.HasLogFilter(F)) \
+        {                                               \
+            sLog.outDetail(__VA_ARGS__);                \
+        }                                               \
+    }                                                   \
+    while(0)
+
+#define DEBUG_LOG(...)                                  \
+    do                                                  \
+    {                                                   \
+        if (sLog.HasLogLevelOrHigher(LOG_LVL_DEBUG))    \
+        {                                               \
+            sLog.outDebug(__VA_ARGS__);                 \
+        }                                               \
+    }                                                   \
+    while(0)
+
+#define DEBUG_FILTER_LOG(F,...)                         \
+    do                                                  \
+    {                                                   \
+        if (sLog.HasLogLevelOrHigher(LOG_LVL_DEBUG) && !sLog.HasLogFilter(F)) \
+        {                                               \
+            sLog.outDebug(__VA_ARGS__);                 \
+        }                                               \
+    }                                                   \
+    while(0)
+
+#define ERROR_DB_FILTER_LOG(F,...)                      \
+    do                                                  \
+    {                                                   \
+        if (!sLog.HasLogFilter(F))                      \
+        {                                               \
+            sLog.outErrorDb(__VA_ARGS__);               \
+        }                                               \
+    }                                                   \
+    while(0)
+
+#define ERROR_DB_STRICT_LOG(...) \
+    ERROR_DB_FILTER_LOG(LOG_FILTER_DB_STRICTED_CHECK, __VA_ARGS__)
+
+/**
+ * @brief primary for script library
+ *
+ * @param str...
+ */
+void  outstring_log(const char* str, ...) ATTR_PRINTF(1, 2);
+/**
+ * @brief
+ *
+ * @param str...
+ */
+void  detail_log(const char* str, ...) ATTR_PRINTF(1, 2);
+/**
+ * @brief
+ *
+ * @param str...
+ */
+void  debug_log(const char* str, ...) ATTR_PRINTF(1, 2);
+/**
+ * @brief
+ *
+ * @param str...
+ */
+void  error_log(const char* str, ...) ATTR_PRINTF(1, 2);
+/**
+ * @brief
+ *
+ * @param str...
+ */
+void  error_db_log(const char* str, ...) ATTR_PRINTF(1, 2);
+/**
+ * @brief
+ *
+ * @param fname
+ * @param libName
+ */
+void  setScriptLibraryErrorFile(char const* fname, char const* libName);
+/**
+ * @brief
+ *
+ * @param str...
+ */
+void  script_error_log(const char* str, ...) ATTR_PRINTF(1, 2);
+
+#endif
diff --git a/shared/Platform/CompilerDefs.h b/shared/Platform/CompilerDefs.h
new file mode 100644
index 0000000..e241279
--- /dev/null
+++ b/shared/Platform/CompilerDefs.h
@@ -0,0 +1,69 @@
+/**
+ * MaNGOS is a full featured server for World of Warcraft, supporting
+ * the following clients: 1.12.x, 2.4.3, 3.3.5a, 4.3.4a and 5.4.8
+ *
+ * Copyright (C) 2005-2022 MaNGOS <https://getmangos.eu>
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * World of Warcraft, and all World of Warcraft or Warcraft art, images,
+ * and lore are copyrighted by Blizzard Entertainment, Inc.
+ */
+
+#ifndef MANGOS_COMPILERDEFS_H
+#define MANGOS_COMPILERDEFS_H
+
+#define PLATFORM_WINDOWS 0
+#define PLATFORM_UNIX    1
+#define PLATFORM_APPLE   2
+#define PLATFORM_INTEL   3
+
+// must be first (win 64 also define WIN32)
+#if defined( _WIN64 )
+#  define PLATFORM PLATFORM_WINDOWS
+#elif defined( __WIN32__ ) || defined( WIN32 ) || defined( _WIN32 )
+#  define PLATFORM PLATFORM_WINDOWS
+#  define WIN_X86
+#elif defined( __APPLE_CC__ )
+#  define PLATFORM PLATFORM_APPLE
+#elif defined( __INTEL_COMPILER )
+#  define PLATFORM PLATFORM_INTEL
+#else
+#  define PLATFORM PLATFORM_UNIX
+#endif
+
+#define COMPILER_MICROSOFT  0
+#define COMPILER_GNU        1
+#define COMPILER_BORLAND    2
+#define COMPILER_INTEL      3
+#define COMPILER_CLANG      4
+
+#ifdef _MSC_VER
+#  define COMPILER COMPILER_MICROSOFT
+#elif defined( __BORLANDC__ )
+#  define COMPILER COMPILER_BORLAND
+#elif defined( __INTEL_COMPILER )
+#  define COMPILER COMPILER_INTEL
+#elif defined(__clang__)
+#  define COMPILER COMPILER_CLANG
+#elif defined( __GNUC__ ) && !defined(__clang__)
+#  define COMPILER COMPILER_GNU
+#else
+#  pragma error "FATAL ERROR: Unknown compiler."
+#endif
+
+#define COMPILER_HAS_CPP11_SUPPORT 1
+
+#endif
diff --git a/shared/Platform/Define.h b/shared/Platform/Define.h
new file mode 100644
index 0000000..ef6f041
--- /dev/null
+++ b/shared/Platform/Define.h
@@ -0,0 +1,180 @@
+/**
+ * MaNGOS is a full featured server for World of Warcraft, supporting
+ * the following clients: 1.12.x, 2.4.3, 3.3.5a, 4.3.4a and 5.4.8
+ *
+ * Copyright (C) 2005-2022 MaNGOS <https://getmangos.eu>
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * World of Warcraft, and all World of Warcraft or Warcraft art, images,
+ * and lore are copyrighted by Blizzard Entertainment, Inc.
+ */
+
+#ifndef MANGOS_DEFINE_H
+#define MANGOS_DEFINE_H
+
+#include <sys/types.h>
+
+#include <ace/Basic_Types.h>
+#include <ace/Default_Constants.h>
+#include <ace/OS_NS_dlfcn.h>
+#include <ace/ACE_export.h>
+
+#include "Platform/CompilerDefs.h"
+
+#define MANGOS_LITTLEENDIAN 0
+#define MANGOS_BIGENDIAN    1
+
+#if !defined(MANGOS_ENDIAN)
+#  if defined (ACE_BIG_ENDIAN)
+#    define MANGOS_ENDIAN MANGOS_BIGENDIAN
+#  else // ACE_BYTE_ORDER != ACE_BIG_ENDIAN
+#    define MANGOS_ENDIAN MANGOS_LITTLEENDIAN
+#  endif // ACE_BYTE_ORDER
+#endif // MANGOS_ENDIAN
+
+/**
+ * @brief
+ *
+ */
+typedef ACE_SHLIB_HANDLE MANGOS_LIBRARY_HANDLE;
+
+#define MANGOS_PATH_MAX PATH_MAX                            // ace/os_include/os_limits.h -> ace/Basic_Types.h
+
+#if PLATFORM == PLATFORM_WINDOWS
+#  define MANGOS_EXPORT __declspec(dllexport)
+#  define MANGOS_IMPORT __cdecl
+#else // PLATFORM != PLATFORM_WINDOWS
+#  define MANGOS_EXPORT export
+#  if defined(__APPLE_CC__) && defined(BIG_ENDIAN)
+#    if (defined(__ppc__) || defined(__powerpc__))
+#      define MANGOS_IMPORT __attribute__ ((longcall))
+#    else
+#      define MANGOS_IMPORT
+#    endif
+#  elif defined(__x86_64__)
+#    define MANGOS_IMPORT
+#  else
+#    define MANGOS_IMPORT __attribute__ ((cdecl))
+#  endif //__APPLE_CC__ && BIG_ENDIAN
+#endif // PLATFORM
+
+#if PLATFORM == PLATFORM_WINDOWS
+#  define MANGOS_DLL_SPEC __declspec(dllexport)
+#  ifndef DECLSPEC_NORETURN
+#    define DECLSPEC_NORETURN __declspec(noreturn)
+#  endif // DECLSPEC_NORETURN
+#else // PLATFORM != PLATFORM_WINDOWS
+#  define MANGOS_DLL_SPEC
+#  define DECLSPEC_NORETURN
+#endif // PLATFORM
+
+#if COMPILER == COMPILER_GNU || COMPILER == COMPILER_CLANG
+#  define ATTR_NORETURN __attribute__((noreturn))
+#  define ATTR_PRINTF(F, V) __attribute__ ((format (printf, F, V)))
+#  define ATTR_DEPRECATED __attribute__((deprecated))
+#else //COMPILER != COMPILER_GNU
+#  define ATTR_NORETURN
+#  define ATTR_PRINTF(F, V)
+#  define ATTR_DEPRECATED
+#endif //COMPILER == COMPILER_GNU
+
+#define OVERRIDE override
+#define FINAL final
+
+/**
+ * @brief A signed integer of 64 bits
+ *
+ */
+typedef ACE_INT64 int64;
+/**
+ * @brief A signed integer of 32 bits
+ *
+ */
+typedef ACE_INT32 int32;
+/**
+ * @brief A signed integer of 16 bits
+ *
+ */
+typedef ACE_INT16 int16;
+/**
+ * @brief A signed integer of 8 bits
+ *
+ */
+typedef ACE_INT8 int8;
+/**
+ * @brief An unsigned integer of 64 bits
+ *
+ */
+typedef ACE_UINT64 uint64;
+/**
+ * @brief An unsigned integer of 32 bits
+ *
+ */
+typedef ACE_UINT32 uint32;
+/**
+ * @brief An unsigned integer of 16 bits
+ *
+ */
+typedef ACE_UINT16 uint16;
+/**
+ * @brief An unsigned integer of 8 bits
+ *
+ */
+typedef ACE_UINT8 uint8;
+
+#if COMPILER != COMPILER_MICROSOFT
+/**
+ * @brief An unsigned integer of 16 bits, only for Win
+ *
+ */
+typedef uint16      WORD;
+/**
+ * @brief An unsigned integer of 32 bits, only for Win
+ *
+ */
+typedef uint32      DWORD;
+#endif // COMPILER
+
+#define CONCAT(x, y) CONCAT1(x, y)
+#define CONCAT1(x, y) x##y
+#define STATIC_ASSERT_WORKAROUND(expr, msg) typedef char CONCAT(static_assert_failed_at_line_, __LINE__) [(expr) ? 1 : -1]
+
+#ifndef COMPILER_HAS_CPP11_SUPPORT
+#if COMPILER == COMPILER_GNU
+#  if !defined(__GXX_EXPERIMENTAL_CXX0X__) || (__GNUC__ < 4) || (__GNUC__ == 4) && (__GNUC_MINOR__ < 7)
+#    define override
+#    define static_assert(a, b) STATIC_ASSERT_WORKAROUND(a, b)
+#  endif
+#elif COMPILER == COMPILER_CLANG
+#  ifndef __cxx_static_assert
+#    define override
+#    define static_assert(a, b) STATIC_ASSERT_WORKAROUND(a, b)
+#  endif
+#elif COMPILER == COMPILER_MICROSOFT
+#  if _MSC_VER < 1600
+#    define static_assert(a, b) STATIC_ASSERT_WORKAROUND(a, b)
+#  endif
+#endif
+
+#endif
+
+/**
+ * @brief
+ *
+ */
+typedef uint64 OBJECT_HANDLE;
+
+#endif // MANGOS_DEFINE_H
diff --git a/shared/Policies/CreationPolicy.h b/shared/Policies/CreationPolicy.h
new file mode 100644
index 0000000..8cc97ec
--- /dev/null
+++ b/shared/Policies/CreationPolicy.h
@@ -0,0 +1,189 @@
+/**
+ * MaNGOS is a full featured server for World of Warcraft, supporting
+ * the following clients: 1.12.x, 2.4.3, 3.3.5a, 4.3.4a and 5.4.8
+ *
+ * Copyright (C) 2005-2022 MaNGOS <https://getmangos.eu>
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * World of Warcraft, and all World of Warcraft or Warcraft art, images,
+ * and lore are copyrighted by Blizzard Entertainment, Inc.
+ */
+
+#ifndef MANGOS_CREATIONPOLICY_H
+#define MANGOS_CREATIONPOLICY_H
+
+#include <stdlib.h>
+#include "Platform/Define.h"
+
+namespace MaNGOS
+{
+    template<class T>
+    /**
+     * @brief OperatorNew policy creates an object on the heap using new.
+     *
+     */
+    class OperatorNew
+    {
+        public:
+
+            /**
+             * @brief
+             *
+             * @return T
+             */
+            static T* Create()
+            {
+                return (new T);
+            }
+
+            /**
+             * @brief
+             *
+             * @param obj
+             */
+            static void Destroy(T* obj)
+            {
+                delete obj;
+            }
+    };
+
+    template<class T>
+    /**
+     * @brief LocalStaticCreation policy creates an object on the stack the first time call Create.
+     *
+     */
+    class LocalStaticCreation
+    {
+            /**
+             * @brief
+             *
+             */
+            union MaxAlign
+            {
+                char t_[sizeof(T)]; /**< TODO */
+                short int shortInt_; /**< TODO */
+                int int_; /**< TODO */
+                long int longInt_; /**< TODO */
+                float float_; /**< TODO */
+                double double_; /**< TODO */
+                long double longDouble_; /**< TODO */
+                struct Test;
+                int Test::* pMember_; /**< TODO */
+                /**
+                 * @brief
+                 *
+                 * @param Test::pMemberFn_)(int
+                 * @return int
+                 */
+                int (Test::*pMemberFn_)(int);
+            };
+
+        public:
+
+            /**
+             * @brief
+             *
+             * @return T
+             */
+            static T* Create()
+            {
+                static MaxAlign si_localStatic;
+                return new(&si_localStatic) T;
+            }
+
+            /**
+             * @brief
+             *
+             * @param obj
+             */
+            static void Destroy(T* obj)
+            {
+                obj->~T();
+            }
+    };
+
+    /**
+     * CreateUsingMalloc by pass the memory manger.
+     */
+    template<class T>
+    /**
+     * @brief
+     *
+     */
+    class CreateUsingMalloc
+    {
+        public:
+
+            /**
+             * @brief
+             *
+             * @return T
+             */
+            static T* Create()
+            {
+                void* p = malloc(sizeof(T));
+
+                if (!p)
+                {
+                    return NULL;
+                }
+
+                return new(p) T;
+            }
+
+            /**
+             * @brief
+             *
+             * @param p
+             */
+            static void Destroy(T* p)
+            {
+                p->~T();
+                free(p);
+            }
+    };
+
+    template<class T, class CALL_BACK>
+    /**
+     * @brief CreateOnCallBack creates the object base on the call back.
+     *
+     */
+    class CreateOnCallBack
+    {
+        public:
+            /**
+             * @brief
+             *
+             * @return T
+             */
+            static T* Create()
+            {
+                return CALL_BACK::createCallBack();
+            }
+
+            /**
+             * @brief
+             *
+             * @param p
+             */
+            static void Destroy(T* p)
+            {
+                CALL_BACK::destroyCallBack(p);
+            }
+    };
+}
+
+#endif
diff --git a/shared/Policies/ObjectLifeTime.cpp b/shared/Policies/ObjectLifeTime.cpp
new file mode 100644
index 0000000..d8452bb
--- /dev/null
+++ b/shared/Policies/ObjectLifeTime.cpp
@@ -0,0 +1,39 @@
+/**
+ * MaNGOS is a full featured server for World of Warcraft, supporting
+ * the following clients: 1.12.x, 2.4.3, 3.3.5a, 4.3.4a and 5.4.8
+ *
+ * Copyright (C) 2005-2022 MaNGOS <https://getmangos.eu>
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * World of Warcraft, and all World of Warcraft or Warcraft art, images,
+ * and lore are copyrighted by Blizzard Entertainment, Inc.
+ */
+
+#include <cstdlib>
+#include "ObjectLifeTime.h"
+
+namespace MaNGOS
+{
+    extern "C" void external_wrapper(void* p)
+    {
+        std::atexit((void (*)())p);
+    }
+
+    void  at_exit(void (*func)())
+    {
+        external_wrapper((void*)func);
+    }
+}
diff --git a/shared/Policies/ObjectLifeTime.h b/shared/Policies/ObjectLifeTime.h
new file mode 100644
index 0000000..6c16a4d
--- /dev/null
+++ b/shared/Policies/ObjectLifeTime.h
@@ -0,0 +1,83 @@
+/**
+ * MaNGOS is a full featured server for World of Warcraft, supporting
+ * the following clients: 1.12.x, 2.4.3, 3.3.5a, 4.3.4a and 5.4.8
+ *
+ * Copyright (C) 2005-2022 MaNGOS <https://getmangos.eu>
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * World of Warcraft, and all World of Warcraft or Warcraft art, images,
+ * and lore are copyrighted by Blizzard Entertainment, Inc.
+ */
+
+#ifndef MANGOS_OBJECTLIFETIME_H
+#define MANGOS_OBJECTLIFETIME_H
+
+#include <stdexcept>
+#include "Platform/Define.h"
+
+/**
+ * @brief
+ *
+ */
+typedef void (* Destroyer)(void);
+
+namespace MaNGOS
+{
+    /**
+     * @brief
+     *
+     * @param (func)()
+     */
+    void  at_exit(void (*func)());
+
+    template<class T>
+    /**
+     * @brief
+     *
+     */
+    class ObjectLifeTime
+    {
+        public:
+
+            /**
+             * @brief
+             *
+             * @param (destroyer)()
+             */
+            static void ScheduleCall(void (*destroyer)())
+            {
+                at_exit(destroyer);
+            }
+
+            /**
+             * @brief
+             *
+             */
+            DECLSPEC_NORETURN static void OnDeadReference() ATTR_NORETURN;
+    };
+
+    template <class T>
+    /**
+     * @brief We don't handle Dead Reference for now
+     *
+     */
+    void ObjectLifeTime<T>::OnDeadReference()           // We don't handle Dead Reference for now
+    {
+        throw std::runtime_error("Dead Reference");
+    }
+}
+
+#endif
diff --git a/shared/Policies/Singleton.h b/shared/Policies/Singleton.h
new file mode 100644
index 0000000..65b1006
--- /dev/null
+++ b/shared/Policies/Singleton.h
@@ -0,0 +1,161 @@
+/**
+ * MaNGOS is a full featured server for World of Warcraft, supporting
+ * the following clients: 1.12.x, 2.4.3, 3.3.5a, 4.3.4a and 5.4.8
+ *
+ * Copyright (C) 2005-2022 MaNGOS <https://getmangos.eu>
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * World of Warcraft, and all World of Warcraft or Warcraft art, images,
+ * and lore are copyrighted by Blizzard Entertainment, Inc.
+ */
+
+#ifndef MANGOS_SINGLETON_H
+#define MANGOS_SINGLETON_H
+
+/**
+ * @brief class Singleton
+ */
+
+#include "CreationPolicy.h"
+#include "ThreadingModel.h"
+#include "ObjectLifeTime.h"
+
+namespace MaNGOS
+{
+    template
+    <
+    typename T,
+             class ThreadingModel = MaNGOS::SingleThreaded<T>,
+             class CreatePolicy = MaNGOS::OperatorNew<T>,
+             class LifeTimePolicy = MaNGOS::ObjectLifeTime<T>
+             >
+    /**
+     * @brief
+     *
+     */
+    class Singleton
+    {
+        public:
+
+            /**
+             * @brief
+             *
+             * @return T
+             */
+            static T& Instance();
+
+        protected:
+
+            /**
+             * @brief
+             *
+             */
+            Singleton()
+            {
+            }
+
+        private:
+
+            /**
+             * @brief Prohibited actions...this does not prevent hijacking.
+             *
+             * @param
+             */
+            Singleton(const Singleton&);
+            /**
+             * @brief
+             *
+             * @param
+             * @return Singleton &operator
+             */
+            Singleton& operator=(const Singleton&);
+
+            /**
+             * @brief Singleton Helpers
+             *
+             */
+            static void DestroySingleton();
+
+            /**
+             * @brief data structure
+             *
+             */
+            typedef typename ThreadingModel::Lock Guard;
+            static T* si_instance; /**< TODO */
+            static bool si_destroyed; /**< TODO */
+    };
+
+    template<typename T, class ThreadingModel, class CreatePolicy, class LifeTimePolicy>
+    T* Singleton<T, ThreadingModel, CreatePolicy, LifeTimePolicy>::si_instance = NULL; /**< TODO */
+
+    template<typename T, class ThreadingModel, class CreatePolicy, class LifeTimePolicy>
+    bool Singleton<T, ThreadingModel, CreatePolicy, LifeTimePolicy>::si_destroyed = false; /**< TODO */
+
+    template<typename T, class ThreadingModel, class CreatePolicy, class LifeTimePolicy>
+    /**
+     * @brief
+     *
+     * @return T &MaNGOS::Singleton<T, ThreadingModel, CreatePolicy, LifeTimePolicy>
+     */
+    T& MaNGOS::Singleton<T, ThreadingModel, CreatePolicy, LifeTimePolicy>::Instance()
+    {
+        if (!si_instance)
+        {
+            // double-checked Locking pattern
+            Guard();
+
+            if (!si_instance)
+            {
+                if (si_destroyed)
+                {
+                    si_destroyed = false;
+                    LifeTimePolicy::OnDeadReference();
+                }
+
+                si_instance = CreatePolicy::Create();
+                LifeTimePolicy::ScheduleCall(&DestroySingleton);
+            }
+        }
+
+        return *si_instance;
+    }
+
+    template<typename T, class ThreadingModel, class CreatePolicy, class LifeTimePolicy>
+    /**
+     * @brief
+     *
+     */
+    void MaNGOS::Singleton<T, ThreadingModel, CreatePolicy, LifeTimePolicy>::DestroySingleton()
+    {
+        CreatePolicy::Destroy(si_instance);
+        si_instance = NULL;
+        si_destroyed = true;
+    }
+}
+
+#define INSTANTIATE_SINGLETON_1(TYPE) \
+    template class MaNGOS::Singleton<TYPE, MaNGOS::SingleThreaded<TYPE>, MaNGOS::OperatorNew<TYPE>, MaNGOS::ObjectLifeTime<TYPE> >;
+
+#define INSTANTIATE_SINGLETON_2(TYPE, THREADINGMODEL) \
+    template class MaNGOS::Singleton<TYPE, THREADINGMODEL, MaNGOS::OperatorNew<TYPE>, MaNGOS::ObjectLifeTime<TYPE> >;
+
+#define INSTANTIATE_SINGLETON_3(TYPE, THREADINGMODEL, CREATIONPOLICY ) \
+    template class MaNGOS::Singleton<TYPE, THREADINGMODEL, CREATIONPOLICY, MaNGOS::ObjectLifeTime<TYPE> >;
+
+#define INSTANTIATE_SINGLETON_4(TYPE, THREADINGMODEL, CREATIONPOLICY, OBJECTLIFETIME) \
+    template class MaNGOS::Singleton<TYPE, THREADINGMODEL, CREATIONPOLICY, OBJECTLIFETIME >;
+
+#endif
diff --git a/shared/Policies/ThreadingModel.h b/shared/Policies/ThreadingModel.h
new file mode 100644
index 0000000..b4b6586
--- /dev/null
+++ b/shared/Policies/ThreadingModel.h
@@ -0,0 +1,270 @@
+/**
+ * MaNGOS is a full featured server for World of Warcraft, supporting
+ * the following clients: 1.12.x, 2.4.3, 3.3.5a, 4.3.4a and 5.4.8
+ *
+ * Copyright (C) 2005-2022 MaNGOS <https://getmangos.eu>
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * World of Warcraft, and all World of Warcraft or Warcraft art, images,
+ * and lore are copyrighted by Blizzard Entertainment, Inc.
+ */
+
+#ifndef MANGOS_THREADINGMODEL_H
+#define MANGOS_THREADINGMODEL_H
+
+/**
+ * @class ThreadingModel<T>
+ *
+ */
+
+#include "Platform/Define.h"
+
+namespace MaNGOS
+{
+    template<typename MUTEX>
+    /**
+     * @brief
+     *
+     */
+    class GeneralLock
+    {
+        public:
+
+            /**
+             * @brief
+             *
+             * @param m
+             */
+            GeneralLock(MUTEX& m)
+                : i_mutex(m)
+            {
+                i_mutex.acquire();
+            }
+
+            /**
+             * @brief
+             *
+             */
+            ~GeneralLock()
+            {
+                i_mutex.release();
+            }
+
+        private:
+
+            /**
+             * @brief
+             *
+             * @param
+             */
+            GeneralLock(const GeneralLock&);
+            /**
+             * @brief
+             *
+             * @param
+             * @return GeneralLock &operator
+             */
+            GeneralLock& operator=(const GeneralLock&);
+            MUTEX& i_mutex; /**< TODO */
+    };
+
+    template<class T>
+    /**
+     * @brief
+     *
+     */
+    class SingleThreaded
+    {
+        public:
+
+            /**
+             * @brief empty object
+             *
+             */
+            struct Lock
+            {
+                /**
+                 * @brief
+                 *
+                 */
+                Lock()
+                {
+                }
+                /**
+                 * @brief
+                 *
+                 * @param
+                 */
+                Lock(const T&)
+                {
+                }
+
+                /**
+                 * @brief for single threaded we ignore this
+                 *
+                 * @param
+                 */
+                Lock(const SingleThreaded<T>&)
+                {
+                }
+            };
+    };
+
+    template<class T, class MUTEX>
+    /**
+     * @brief
+     *
+     */
+    class ObjectLevelLockable
+    {
+        public:
+
+            /**
+             * @brief
+             *
+             */
+            ObjectLevelLockable()
+                : i_mtx()
+            {
+            }
+
+            friend class Lock;
+
+            /**
+             * @brief
+             *
+             */
+            class Lock
+            {
+                public:
+
+                    /**
+                     * @brief
+                     *
+                     * @param ObjectLevelLockable<T
+                     * @param host
+                     */
+                    Lock(ObjectLevelLockable<T, MUTEX>& host)
+                        : i_lock(host.i_mtx)
+                    {
+                    }
+
+                private:
+
+                    GeneralLock<MUTEX> i_lock; /**< TODO */
+            };
+
+        private:
+
+            /**
+             * @brief prevent the compiler creating a copy construct
+             *
+             * @param ObjectLevelLockable<T
+             * @param
+             */
+            ObjectLevelLockable(const ObjectLevelLockable<T, MUTEX>&);
+            /**
+             * @brief
+             *
+             * @param ObjectLevelLockable<T
+             * @param
+             * @return ObjectLevelLockable<T, MUTEX>
+             */
+            ObjectLevelLockable<T, MUTEX>& operator=(const ObjectLevelLockable<T, MUTEX>&);
+
+            MUTEX i_mtx; /**< TODO */
+    };
+
+    template<class T, class MUTEX>
+    /**
+     * @brief
+     *
+     */
+    class ClassLevelLockable
+    {
+        public:
+
+            /**
+             * @brief
+             *
+             */
+            ClassLevelLockable()
+            {
+            }
+
+            friend class Lock;
+
+            /**
+             * @brief
+             *
+             */
+            class Lock
+            {
+                public:
+
+                    /**
+                     * @brief
+                     *
+                     * @param
+                     */
+                    Lock(const T& /*host*/)
+                    {
+                        ClassLevelLockable<T, MUTEX>::si_mtx.acquire();
+                    }
+
+                    /**
+                     * @brief
+                     *
+                     * @param ClassLevelLockable<T
+                     * @param
+                     */
+                    Lock(const ClassLevelLockable<T, MUTEX>&)
+                    {
+                        ClassLevelLockable<T, MUTEX>::si_mtx.acquire();
+                    }
+
+                    /**
+                     * @brief
+                     *
+                     */
+                    Lock()
+                    {
+                        ClassLevelLockable<T, MUTEX>::si_mtx.acquire();
+                    }
+
+                    /**
+                     * @brief
+                     *
+                     */
+                    ~Lock()
+                    {
+                        ClassLevelLockable<T, MUTEX>::si_mtx.release();
+                    }
+            };
+
+        private:
+
+            static MUTEX si_mtx; /**< TODO */
+    };
+
+}
+
+template<class T, class MUTEX> MUTEX MaNGOS::ClassLevelLockable<T, MUTEX>::si_mtx; /**< TODO */
+
+#define INSTANTIATE_CLASS_MUTEX(CTYPE, MUTEX) \
+    template class MaNGOS::ClassLevelLockable<CTYPE, MUTEX>
+
+#endif
diff --git a/shared/SystemConfig.h.in b/shared/SystemConfig.h.in
new file mode 100644
index 0000000..63e0e0b
--- /dev/null
+++ b/shared/SystemConfig.h.in
@@ -0,0 +1,71 @@
+/**
+ * MaNGOS is a full featured server for World of Warcraft, supporting
+ * the following clients: 1.12.x, 2.4.3, 3.3.5a, 4.3.4a and 5.4.8
+ *
+ * Copyright (C) 2005-2022 MaNGOS <https://getmangos.eu>
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * World of Warcraft, and all World of Warcraft or Warcraft art, images,
+ * and lore are copyrighted by Blizzard Entertainment, Inc.
+ */
+
+#ifndef MANGOS_SYSTEMCONFIG_H
+#define MANGOS_SYSTEMCONFIG_H
+
+#include "Platform/Define.h"
+
+#ifndef MANGOS_PACKAGENAME
+#define MANGOS_PACKAGENAME "@MANGOS_PKG@"
+#endif
+
+#ifndef MANGOS_VERSION
+# define MANGOS_VERSION(REVD,REVT,REVN,REVH) "@PROJECT_VERSION@" " (" REVD " " REVT " Revision " REVN " - " REVH ")"
+#endif
+
+// Format is YYYYMMDDRR where RR is the change in the conf file
+// for that day.
+#ifndef MANGOSD_CONFIG_VERSION
+# define MANGOSD_CONFIG_VERSION @MANGOS_WORLD_VER@
+#endif
+
+#ifndef REALMD_CONFIG_VERSION
+# define REALMD_CONFIG_VERSION @MANGOS_REALM_VER@
+#endif
+
+#ifndef AHBOT_CONFIG_VERSION
+# define AHBOT_CONFIG_VERSION @MANGOS_AHBOT_VER@
+#endif
+
+#if MANGOS_ENDIAN == MANGOS_BIGENDIAN
+# define MANGOS_ENDIAN_STRING "big-endian"
+#else
+# define MANGOS_ENDIAN_STRING "little-endian"
+#endif
+
+#define SYSCONFDIR "/etc/mangos/"
+
+#define REALMD_CONFIG_NAME             "realmd.conf"
+#define MANGOSD_CONFIG_NAME            "mangosd.conf"
+#define AUCTIONHOUSEBOT_CONFIG_NAME    "ahbot.conf"
+
+#define MANGOSD_CONFIG_LOCATION         SYSCONFDIR MANGOSD_CONFIG_NAME
+#define REALMD_CONFIG_LOCATION          SYSCONFDIR REALMD_CONFIG_NAME
+#define AUCTIONHOUSEBOT_CONFIG_LOCATION SYSCONFDIR AUCTIONHOUSEBOT_CONFIG_NAME
+
+#define DEFAULT_PLAYER_LIMIT 100
+#define DEFAULT_WORLDSERVER_PORT 8085                       //8129
+#define DEFAULT_REALMSERVER_PORT 3724
+#endif
\ No newline at end of file
diff --git a/shared/Threading/DelayExecutor.cpp b/shared/Threading/DelayExecutor.cpp
new file mode 100644
index 0000000..932677a
--- /dev/null
+++ b/shared/Threading/DelayExecutor.cpp
@@ -0,0 +1,126 @@
+/**
+ * MaNGOS is a full featured server for World of Warcraft, supporting
+ * the following clients: 1.12.x, 2.4.3, 3.3.5a, 4.3.4a and 5.4.8
+ *
+ * Copyright (C) 2005-2022 MaNGOS <https://getmangos.eu>
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * World of Warcraft, and all World of Warcraft or Warcraft art, images,
+ * and lore are copyrighted by Blizzard Entertainment, Inc.
+ */
+
+#include <ace/Singleton.h>
+#include <ace/Thread_Mutex.h>
+#include <ace/Log_Msg.h>
+
+#include "DelayExecutor.h"
+
+DelayExecutor* DelayExecutor::instance()
+{
+    return ACE_Singleton<DelayExecutor, ACE_Thread_Mutex>::instance();
+}
+
+DelayExecutor::DelayExecutor()
+    : activated_(false)
+{
+}
+
+DelayExecutor::~DelayExecutor()
+{
+    deactivate();
+}
+
+int DelayExecutor::deactivate()
+{
+    if (!activated())
+    {
+        return -1;
+    }
+
+    activated(false);
+    queue_.queue()->deactivate();
+    wait();
+
+    return 0;
+}
+
+int DelayExecutor::svc()
+{
+    for (;;)
+    {
+        ACE_Method_Request* rq = queue_.dequeue();
+
+        if (!rq)
+        {
+            break;
+        }
+
+        rq->call();
+        delete rq;
+    }
+
+    return 0;
+}
+
+int DelayExecutor::_activate(int num_threads)
+{
+    if (activated())
+    {
+        return -1;
+    }
+
+    if (num_threads < 1)
+    {
+        return -1;
+    }
+
+    queue_.queue()->activate();
+
+    if (ACE_Task_Base::activate(THR_NEW_LWP | THR_JOINABLE | THR_INHERIT_SCHED, num_threads) == -1)
+    {
+        return -1;
+    }
+
+    activated(true);
+
+    return true;
+}
+
+int DelayExecutor::execute(ACE_Method_Request* new_req)
+{
+    if (new_req == NULL)
+    {
+        return -1;
+    }
+
+    if (queue_.enqueue(new_req, (ACE_Time_Value*)&ACE_Time_Value::zero) == -1)
+    {
+        delete new_req;
+        ACE_ERROR_RETURN((LM_ERROR, ACE_TEXT("(%t) %p\n"), ACE_TEXT("DelayExecutor::execute enqueue")), -1);
+    }
+
+    return 0;
+}
+
+bool DelayExecutor::activated()
+{
+    return activated_;
+}
+
+void DelayExecutor::activated(bool s)
+{
+    activated_ = s;
+}
diff --git a/shared/Threading/DelayExecutor.h b/shared/Threading/DelayExecutor.h
new file mode 100644
index 0000000..ccffc96
--- /dev/null
+++ b/shared/Threading/DelayExecutor.h
@@ -0,0 +1,59 @@
+/**
+ * MaNGOS is a full featured server for World of Warcraft, supporting
+ * the following clients: 1.12.x, 2.4.3, 3.3.5a, 4.3.4a and 5.4.8
+ *
+ * Copyright (C) 2005-2022 MaNGOS <https://getmangos.eu>
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * World of Warcraft, and all World of Warcraft or Warcraft art, images,
+ * and lore are copyrighted by Blizzard Entertainment, Inc.
+ */
+
+#ifndef _M_DELAY_EXECUTOR_H
+#define _M_DELAY_EXECUTOR_H
+
+#include <ace/Task.h>
+#include <ace/Activation_Queue.h>
+#include <ace/Method_Request.h>
+
+class DelayExecutor : protected ACE_Task_Base
+{
+    public:
+
+        DelayExecutor();
+        virtual ~DelayExecutor();
+
+        static DelayExecutor* instance();
+
+        int execute(ACE_Method_Request* new_req);
+
+        int _activate(int num_threads = 1);
+
+        int deactivate();
+
+        bool activated();
+
+        virtual int svc();
+
+    private:
+
+        ACE_Activation_Queue queue_;
+        bool activated_;
+
+        void activated(bool s);
+};
+
+#endif // _M_DELAY_EXECUTOR_H
\ No newline at end of file
diff --git a/shared/Threading/Threading.cpp b/shared/Threading/Threading.cpp
new file mode 100644
index 0000000..050aae1
--- /dev/null
+++ b/shared/Threading/Threading.cpp
@@ -0,0 +1,242 @@
+/**
+ * MaNGOS is a full featured server for World of Warcraft, supporting
+ * the following clients: 1.12.x, 2.4.3, 3.3.5a, 4.3.4a and 5.4.8
+ *
+ * Copyright (C) 2005-2022 MaNGOS <https://getmangos.eu>
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * World of Warcraft, and all World of Warcraft or Warcraft art, images,
+ * and lore are copyrighted by Blizzard Entertainment, Inc.
+ */
+
+#include "Threading.h"
+#include "Utilities/Errors.h"
+#include <ace/OS_NS_unistd.h>
+#include <ace/Sched_Params.h>
+#include <vector>
+
+using namespace ACE_Based;
+
+ThreadPriority::ThreadPriority()
+{
+    for (int i = Idle; i < MAXPRIORITYNUM; ++i)
+    {
+        m_priority[i] = ACE_THR_PRI_OTHER_DEF;
+    }
+
+    m_priority[Idle] = ACE_Sched_Params::priority_min(ACE_SCHED_OTHER);
+    m_priority[Realtime] = ACE_Sched_Params::priority_max(ACE_SCHED_OTHER);
+
+    std::vector<int> _tmp;
+
+    ACE_Sched_Params::Policy _policy = ACE_SCHED_OTHER;
+    ACE_Sched_Priority_Iterator pr_iter(_policy);
+
+    while (pr_iter.more())
+    {
+        _tmp.push_back(pr_iter.priority());
+        pr_iter.next();
+    }
+
+    MANGOS_ASSERT(!_tmp.empty());
+
+    if (_tmp.size() >= MAXPRIORITYNUM)
+    {
+        const size_t max_pos = _tmp.size();
+        size_t min_pos = 1;
+        size_t norm_pos = 0;
+        for (size_t i = 0; i < max_pos; ++i)
+        {
+            if (_tmp[i] == ACE_THR_PRI_OTHER_DEF)
+            {
+                norm_pos = i + 1;
+                break;
+            }
+        }
+
+        // since we have only 7(seven) values in enum Priority
+        // and 3 we know already (Idle, Normal, Realtime) so
+        // we need to split each list [Idle...Normal] and [Normal...Realtime]
+        // into pieces
+        const size_t _divider = 4;
+        size_t _div = (norm_pos - min_pos) / _divider;
+        if (_div == 0)
+        {
+            _div = 1;
+        }
+
+        min_pos = (norm_pos - 1);
+
+        m_priority[Low] = _tmp[min_pos -= _div];
+        m_priority[Lowest] = _tmp[min_pos -= _div ];
+
+        _div = (max_pos - norm_pos) / _divider;
+        if (_div == 0)
+        {
+            _div = 1;
+        }
+
+        min_pos = norm_pos - 1;
+
+        m_priority[High] = _tmp[min_pos += _div];
+        m_priority[Highest] = _tmp[min_pos += _div];
+    }
+}
+
+int ThreadPriority::getPriority(Priority p) const
+{
+    if (p < Idle)
+    {
+        p = Idle;
+    }
+
+    if (p > Realtime)
+    {
+        p = Realtime;
+    }
+
+    return m_priority[p];
+}
+
+#ifndef __sun__
+# define THREADFLAG (THR_NEW_LWP | THR_JOINABLE | THR_SCHED_DEFAULT)
+#else
+# define THREADFLAG (THR_NEW_LWP | THR_JOINABLE)
+#endif
+
+Thread::Thread() : m_iThreadId(0), m_hThreadHandle(0), m_task(0)
+{
+}
+
+Thread::Thread(Runnable* instance) : m_iThreadId(0), m_hThreadHandle(0), m_task(instance)
+{
+    // register reference to m_task to prevent it deeltion until destructor
+    if (m_task)
+    {
+        m_task->incReference();
+    }
+
+    bool _start = start();
+    MANGOS_ASSERT(_start);
+}
+
+Thread::~Thread()
+{
+    // Wait();
+
+    // deleted runnable object (if no other references)
+    if (m_task)
+    {
+        m_task->decReference();
+    }
+}
+
+// initialize Thread's class static member
+ThreadPriority Thread::m_TpEnum;
+
+bool Thread::start()
+{
+    if (m_task == 0 || m_iThreadId != 0)
+    {
+        return false;
+    }
+
+    // incRef before spawing the thread, otherwise Thread::ThreadTask() might call decRef and delete m_task
+    m_task->incReference();
+
+    bool res = (ACE_Thread::spawn(&Thread::ThreadTask, (void*)m_task, THREADFLAG, &m_iThreadId, &m_hThreadHandle) == 0);
+
+    if (res)
+    {
+        m_task->decReference();
+    }
+
+    return res;
+}
+
+bool Thread::wait()
+{
+    if (!m_hThreadHandle || !m_task)
+    {
+        return false;
+    }
+
+    ACE_THR_FUNC_RETURN _value = ACE_THR_FUNC_RETURN(-1);
+    int _res = ACE_Thread::join(m_hThreadHandle, &_value);
+
+    m_iThreadId = 0;
+    m_hThreadHandle = 0;
+
+    return (_res == 0);
+}
+
+void Thread::destroy()
+{
+    if (!m_iThreadId || !m_task)
+    {
+        return;
+    }
+
+    if (ACE_Thread::kill(m_iThreadId, -1) != 0)
+    {
+        return;
+    }
+
+    m_iThreadId = 0;
+    m_hThreadHandle = 0;
+
+    // reference set at ACE_Thread::spawn
+    m_task->decReference();
+}
+
+void Thread::suspend()
+{
+    ACE_Thread::suspend(m_hThreadHandle);
+}
+
+void Thread::resume()
+{
+    ACE_Thread::resume(m_hThreadHandle);
+}
+
+ACE_THR_FUNC_RETURN Thread::ThreadTask(void* param)
+{
+    Runnable* _task = static_cast<Runnable*>(param);
+    _task->incReference();
+
+    _task->run();
+
+    // task execution complete, free referecne added at
+    _task->decReference();
+
+    return (ACE_THR_FUNC_RETURN)0;
+}
+
+void Thread::setPriority(Priority type)
+{
+#ifndef __sun__
+    int _priority = m_TpEnum.getPriority(type);
+    int _ok = ACE_Thread::setprio(m_hThreadHandle, _priority);
+    // remove this ASSERT in case you don't want to know is thread priority change was successful or not
+    MANGOS_ASSERT(_ok == 0);
+#endif
+
+}
+
+void Thread::Sleep(unsigned long msecs)
+{
+    ACE_OS::sleep(ACE_Time_Value(0, 1000 * msecs));
+}
diff --git a/shared/Threading/Threading.h b/shared/Threading/Threading.h
new file mode 100644
index 0000000..14b57d1
--- /dev/null
+++ b/shared/Threading/Threading.h
@@ -0,0 +1,215 @@
+/**
+ * MaNGOS is a full featured server for World of Warcraft, supporting
+ * the following clients: 1.12.x, 2.4.3, 3.3.5a, 4.3.4a and 5.4.8
+ *
+ * Copyright (C) 2005-2022 MaNGOS <https://getmangos.eu>
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * World of Warcraft, and all World of Warcraft or Warcraft art, images,
+ * and lore are copyrighted by Blizzard Entertainment, Inc.
+ */
+
+#ifndef THREADING_H
+#define THREADING_H
+
+#include <ace/Thread.h>
+#include <ace/TSS_T.h>
+#include <ace/Atomic_Op.h>
+#include <assert.h>
+
+namespace ACE_Based
+{
+    /**
+     * @brief
+     *
+     */
+    class Runnable
+    {
+        public:
+            /**
+             * @brief
+             *
+             */
+            virtual ~Runnable() {}
+            /**
+             * @brief
+             *
+             */
+            virtual void run() = 0;
+
+            /**
+             * @brief
+             *
+             */
+            void incReference() { ++m_refs; }
+            /**
+             * @brief
+             *
+             */
+            void decReference()
+            {
+                if (!--m_refs)
+                {
+                    delete this;
+                }
+            }
+        private:
+            ACE_Atomic_Op<ACE_Thread_Mutex, long> m_refs; /**< TODO */
+    };
+
+    /**
+     * @brief
+     *
+     */
+    enum Priority
+    {
+        Idle,
+        Lowest,
+        Low,
+        Normal,
+        High,
+        Highest,
+        Realtime
+    };
+
+#define MAXPRIORITYNUM (Realtime + 1)
+
+    /**
+     * @brief
+     *
+     */
+    class ThreadPriority
+    {
+        public:
+            /**
+             * @brief
+             *
+             */
+            ThreadPriority();
+            /**
+             * @brief
+             *
+             * @param p
+             * @return int
+             */
+            int getPriority(Priority p) const;
+
+        private:
+            int m_priority[MAXPRIORITYNUM]; /**< TODO */
+    };
+
+    /**
+     * @brief
+     *
+     */
+    class Thread
+    {
+        public:
+            /**
+             * @brief
+             *
+             */
+            Thread();
+            /**
+             * @brief
+             *
+             * @param instance
+             */
+            explicit Thread(Runnable* instance);
+            /**
+             * @brief
+             *
+             */
+            ~Thread();
+
+            /**
+             * @brief
+             *
+             * @return bool
+             */
+            bool start();
+            /**
+             * @brief
+             *
+             * @return bool
+             */
+            bool wait();
+            /**
+             * @brief
+             *
+             */
+            void destroy();
+
+            /**
+             * @brief
+             *
+             */
+            void suspend();
+            /**
+             * @brief
+             *
+             */
+            void resume();
+
+            /**
+             * @brief
+             *
+             * @param type
+             */
+            void setPriority(Priority type);
+
+            /**
+             * @brief
+             *
+             * @param msecs
+             */
+            static void Sleep(unsigned long msecs);
+
+        private:
+            /**
+             * @brief
+             *
+             * @param
+             */
+            Thread(const Thread&);
+            /**
+             * @brief
+             *
+             * @param
+             * @return Thread &operator
+             */
+            Thread& operator=(const Thread&);
+
+            /**
+             * @brief
+             *
+             * @param param
+             * @return ACE_THR_FUNC_RETURN
+             */
+            static ACE_THR_FUNC_RETURN ThreadTask(void* param);
+
+            ACE_thread_t m_iThreadId; /**< TODO */
+            ACE_hthread_t m_hThreadHandle; /**< TODO */
+            Runnable* m_task; /**< TODO */
+
+            /**
+             * @brief
+             *
+             */
+            static ThreadPriority m_TpEnum; /**< use this object to determine current OS thread priority values mapped to enum Priority{} */
+    };
+}
+#endif
diff --git a/shared/Utilities/ByteBuffer.cpp b/shared/Utilities/ByteBuffer.cpp
new file mode 100644
index 0000000..73a1a41
--- /dev/null
+++ b/shared/Utilities/ByteBuffer.cpp
@@ -0,0 +1,135 @@
+/**
+ * MaNGOS is a full featured server for World of Warcraft, supporting
+ * the following clients: 1.12.x, 2.4.3, 3.3.5a, 4.3.4a and 5.4.8
+ *
+ * Copyright (C) 2005-2022 MaNGOS <https://getmangos.eu>
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * World of Warcraft, and all World of Warcraft or Warcraft art, images,
+ * and lore are copyrighted by Blizzard Entertainment, Inc.
+ */
+
+#include "ByteBuffer.h"
+#include "Log/Log.h"
+
+void ByteBufferException::PrintPosError() const
+{
+    char const* traceStr;
+
+#ifdef HAVE_ACE_STACK_TRACE_H
+    ACE_Stack_Trace trace;
+    traceStr = trace.c_str();
+#else
+    traceStr = NULL;
+#endif
+
+    sLog.outError(
+        "Attempted to %s in ByteBuffer (pos: " SIZEFMTD " size: " SIZEFMTD ") "
+        "value with size: " SIZEFMTD "%s%s",
+        (add ? "put" : "get"), pos, size, esize,
+        traceStr ? "\n" : "", traceStr ? traceStr : "");
+}
+
+void ByteBuffer::print_storage() const
+{
+    if (!sLog.HasLogLevelOrHigher(LOG_LVL_DEBUG))   // optimize disabled debug output
+    {
+        return;
+    }
+
+    std::ostringstream ss;
+    ss <<  "STORAGE_SIZE: " << size() << "\n";
+
+    if (sLog.IsIncludeTime())
+    {
+        ss << "         ";
+    }
+
+    for (size_t i = 0; i < size(); ++i)
+    {
+        ss << uint32(read<uint8>(i)) << " - ";
+    }
+
+    sLog.outDebug("%s", ss.str().c_str());
+}
+
+void ByteBuffer::textlike() const
+{
+    if (!sLog.HasLogLevelOrHigher(LOG_LVL_DEBUG))   // optimize disabled debug output
+    {
+        return;
+    }
+
+    std::ostringstream ss;
+    ss <<  "STORAGE_SIZE: " << size() << "\n";
+
+    if (sLog.IsIncludeTime())
+    {
+        ss << "         ";
+    }
+
+    for (size_t i = 0; i < size(); ++i)
+    {
+        ss << read<uint8>(i);
+    }
+
+    sLog.outDebug("%s", ss.str().c_str());
+}
+
+void ByteBuffer::hexlike() const
+{
+    if (!sLog.HasLogLevelOrHigher(LOG_LVL_DEBUG))   // optimize disabled debug output
+    {
+        return;
+    }
+
+    std::ostringstream ss;
+    ss <<  "STORAGE_SIZE: " << size() << "\n";
+
+    if (sLog.IsIncludeTime())
+    {
+        ss << "         ";
+    }
+
+    size_t j = 1, k = 1;
+
+    for (size_t i = 0; i < size(); ++i)
+    {
+        if ((i == (j * 8)) && ((i != (k * 16))))
+        {
+            ss << "| ";
+            ++j;
+        }
+        else if (i == (k * 16))
+        {
+            ss << "\n";
+
+            if (sLog.IsIncludeTime())
+            {
+                ss << "         ";
+            }
+
+            ++k;
+            ++j;
+        }
+
+        char buf[4];
+        snprintf(buf, 4, "%02X", read<uint8>(i));
+        ss << buf << " ";
+    }
+
+    sLog.outDebug("%s", ss.str().c_str());
+}
diff --git a/shared/Utilities/ByteBuffer.h b/shared/Utilities/ByteBuffer.h
new file mode 100644
index 0000000..7d2f4c9
--- /dev/null
+++ b/shared/Utilities/ByteBuffer.h
@@ -0,0 +1,951 @@
+/**
+ * MaNGOS is a full featured server for World of Warcraft, supporting
+ * the following clients: 1.12.x, 2.4.3, 3.3.5a, 4.3.4a and 5.4.8
+ *
+ * Copyright (C) 2005-2022 MaNGOS <https://getmangos.eu>
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * World of Warcraft, and all World of Warcraft or Warcraft art, images,
+ * and lore are copyrighted by Blizzard Entertainment, Inc.
+ */
+
+#ifndef MANGOS_H_BYTEBUFFER
+#define MANGOS_H_BYTEBUFFER
+
+#include "Common/Common.h"
+#include "Utilities/ByteConverter.h"
+#include "Utilities/Errors.h"
+
+/**
+ * @brief
+ *
+ */
+class ByteBufferException
+{
+    public:
+    /**
+     * @brief
+     *
+     * @param _add
+     * @param _pos
+     * @param _esize
+     * @param _size
+     */
+        ByteBufferException(bool _add, size_t _pos, size_t _esize, size_t _size)
+            : add(_add), pos(_pos), esize(_esize), size(_size)
+        {
+            PrintPosError();
+        }
+
+        /**
+         * @brief
+         *
+         */
+        void PrintPosError() const;
+    private:
+        bool add; /**< TODO */
+        size_t pos; /**< TODO */
+        size_t esize; /**< TODO */
+        size_t size; /**< TODO */
+};
+
+template<class T>
+/**
+ * @brief
+ *
+ */
+struct Unused
+{
+/**
+ * @brief
+ *
+ */
+    Unused() {}
+};
+
+/**
+ * @brief
+ *
+ */
+class ByteBuffer
+{
+    public:
+        const static size_t DEFAULT_SIZE = 0x1000; /**< TODO */
+
+        /**
+         * @brief constructor
+         *
+         */
+        ByteBuffer(): _rpos(0), _wpos(0)
+        {
+            _storage.reserve(DEFAULT_SIZE);
+        }
+
+        /**
+         * @brief constructor
+         *
+         * @param res
+         */
+        ByteBuffer(size_t res): _rpos(0), _wpos(0)
+        {
+            _storage.reserve(res);
+        }
+
+        /**
+         * @brief copy constructor
+         *
+         * @param buf
+         */
+        ByteBuffer(const ByteBuffer& buf): _rpos(buf._rpos), _wpos(buf._wpos), _storage(buf._storage) { }
+
+        /**
+         * @brief
+         *
+         */
+        void clear()
+        {
+            _storage.clear();
+            _rpos = _wpos = 0;
+        }
+
+        /**
+         * @brief
+         *
+         * @param pos
+         * @param value
+         */
+        template <typename T> void put(size_t pos, T value)
+        {
+            EndianConvert(value);
+            put(pos, (uint8*)&value, sizeof(value));
+        }
+
+        /**
+         * @brief
+         *
+         * @param value
+         * @return ByteBuffer &operator
+         */
+        ByteBuffer& operator<<(uint8 value)
+        {
+            append<uint8>(value);
+            return *this;
+        }
+
+        /**
+         * @brief
+         *
+         * @param value
+         * @return ByteBuffer &operator
+         */
+        ByteBuffer& operator<<(uint16 value)
+        {
+            append<uint16>(value);
+            return *this;
+        }
+
+        /**
+         * @brief
+         *
+         * @param value
+         * @return ByteBuffer &operator
+         */
+        ByteBuffer& operator<<(uint32 value)
+        {
+            append<uint32>(value);
+            return *this;
+        }
+
+        /**
+         * @brief
+         *
+         * @param value
+         * @return ByteBuffer &operator
+         */
+        ByteBuffer& operator<<(uint64 value)
+        {
+            append<uint64>(value);
+            return *this;
+        }
+
+        /**
+         * @brief signed as in 2e complement
+         *
+         * @param value
+         * @return ByteBuffer &operator
+         */
+        ByteBuffer& operator<<(int8 value)
+        {
+            append<int8>(value);
+            return *this;
+        }
+
+        /**
+         * @brief
+         *
+         * @param value
+         * @return ByteBuffer &operator
+         */
+        ByteBuffer& operator<<(int16 value)
+        {
+            append<int16>(value);
+            return *this;
+        }
+
+        /**
+         * @brief
+         *
+         * @param value
+         * @return ByteBuffer &operator
+         */
+        ByteBuffer& operator<<(int32 value)
+        {
+            append<int32>(value);
+            return *this;
+        }
+
+        /**
+         * @brief
+         *
+         * @param value
+         * @return ByteBuffer &operator
+         */
+        ByteBuffer& operator<<(int64 value)
+        {
+            append<int64>(value);
+            return *this;
+        }
+
+        /**
+         * @brief floating points
+         *
+         * @param value
+         * @return ByteBuffer &operator
+         */
+        ByteBuffer& operator<<(float value)
+        {
+            append<float>(value);
+            return *this;
+        }
+
+        /**
+         * @brief
+         *
+         * @param value
+         * @return ByteBuffer &operator
+         */
+        ByteBuffer& operator<<(double value)
+        {
+            append<double>(value);
+            return *this;
+        }
+
+        /**
+         * @brief
+         *
+         * @param value
+         * @return ByteBuffer &operator
+         */
+        ByteBuffer& operator<<(const std::string& value)
+        {
+            append((uint8 const*)value.c_str(), value.length());
+            append((uint8)0);
+            return *this;
+        }
+
+        /**
+         * @brief
+         *
+         * @param str
+         * @return ByteBuffer &operator
+         */
+        ByteBuffer& operator<<(const char* str)
+        {
+            append((uint8 const*)str, str ? strlen(str) : 0);
+            append((uint8)0);
+            return *this;
+        }
+
+        /**
+         * @brief
+         *
+         * @param value
+         * @return ByteBuffer &operator >>
+         */
+        ByteBuffer& operator>>(bool& value)
+        {
+            value = read<char>() > 0 ? true : false;
+            return *this;
+        }
+
+        /**
+         * @brief
+         *
+         * @param value
+         * @return ByteBuffer &operator >>
+         */
+        ByteBuffer& operator>>(uint8& value)
+        {
+            value = read<uint8>();
+            return *this;
+        }
+
+        /**
+         * @brief
+         *
+         * @param value
+         * @return ByteBuffer &operator >>
+         */
+        ByteBuffer& operator>>(uint16& value)
+        {
+            value = read<uint16>();
+            return *this;
+        }
+
+        /**
+         * @brief
+         *
+         * @param value
+         * @return ByteBuffer &operator >>
+         */
+        ByteBuffer& operator>>(uint32& value)
+        {
+            value = read<uint32>();
+            return *this;
+        }
+
+        /**
+         * @brief
+         *
+         * @param value
+         * @return ByteBuffer &operator >>
+         */
+        ByteBuffer& operator>>(uint64& value)
+        {
+            value = read<uint64>();
+            return *this;
+        }
+
+        /**
+         * @brief signed as in 2e complement
+         *
+         * @param value
+         * @return ByteBuffer &operator >>
+         */
+        ByteBuffer& operator>>(int8& value)
+        {
+            value = read<int8>();
+            return *this;
+        }
+
+        /**
+         * @brief
+         *
+         * @param value
+         * @return ByteBuffer &operator >>
+         */
+        ByteBuffer& operator>>(int16& value)
+        {
+            value = read<int16>();
+            return *this;
+        }
+
+        /**
+         * @brief
+         *
+         * @param value
+         * @return ByteBuffer &operator >>
+         */
+        ByteBuffer& operator>>(int32& value)
+        {
+            value = read<int32>();
+            return *this;
+        }
+
+        /**
+         * @brief
+         *
+         * @param value
+         * @return ByteBuffer &operator >>
+         */
+        ByteBuffer& operator>>(int64& value)
+        {
+            value = read<int64>();
+            return *this;
+        }
+
+        /**
+         * @brief
+         *
+         * @param value
+         * @return ByteBuffer &operator >>
+         */
+        ByteBuffer& operator>>(float& value)
+        {
+            value = read<float>();
+            return *this;
+        }
+
+        /**
+         * @brief
+         *
+         * @param value
+         * @return ByteBuffer &operator >>
+         */
+        ByteBuffer& operator>>(double& value)
+        {
+            value = read<double>();
+            return *this;
+        }
+
+        /**
+         * @brief
+         *
+         * @param value
+         * @return ByteBuffer &operator >>
+         */
+        ByteBuffer& operator>>(std::string& value)
+        {
+            value.clear();
+            while (rpos() < size())                         // prevent crash at wrong string format in packet
+            {
+                char c = read<char>();
+                if (c == 0)
+                {
+                    break;
+                }
+                value += c;
+            }
+            return *this;
+        }
+
+        template<class T>
+        /**
+         * @brief
+         *
+         * @param
+         * @return ByteBuffer &operator >>
+         */
+        ByteBuffer& operator>>(Unused<T> const&)
+        {
+            read_skip<T>();
+            return *this;
+        }
+
+
+        /**
+         * @brief
+         *
+         * @param pos
+         * @return uint8 operator
+         */
+        uint8 operator[](size_t pos) const
+        {
+            return read<uint8>(pos);
+        }
+
+        /**
+         * @brief
+         *
+         * @return size_t
+         */
+        size_t rpos() const { return _rpos; }
+
+        /**
+         * @brief
+         *
+         * @param rpos_
+         * @return size_t
+         */
+        size_t rpos(size_t rpos_)
+        {
+            _rpos = rpos_;
+            return _rpos;
+        }
+
+        /**
+         * @brief
+         *
+         * @return size_t
+         */
+        size_t wpos() const { return _wpos; }
+
+        /**
+         * @brief
+         *
+         * @param wpos_
+         * @return size_t
+         */
+        size_t wpos(size_t wpos_)
+        {
+            _wpos = wpos_;
+            return _wpos;
+        }
+
+        template<typename T>
+        /**
+         * @brief
+         *
+         */
+        void read_skip() { read_skip(sizeof(T)); }
+
+        /**
+         * @brief
+         *
+         * @param skip
+         */
+        void read_skip(size_t skip)
+        {
+            if (_rpos + skip > size())
+            {
+                throw ByteBufferException(false, _rpos, skip, size());
+            }
+            _rpos += skip;
+        }
+
+        /**
+         * @brief
+         *
+         * @return T
+         */
+        template <typename T> T read()
+        {
+            T r = read<T>(_rpos);
+            _rpos += sizeof(T);
+            return r;
+        }
+
+        /**
+         * @brief
+         *
+         * @param pos
+         * @return T
+         */
+        template <typename T> T read(size_t pos) const
+        {
+            if (pos + sizeof(T) > size())
+            {
+                throw ByteBufferException(false, pos, sizeof(T), size());
+            }
+#if defined(__arm__)
+            // ARM has alignment issues, we need to use memcpy to avoid them
+            T val;
+            memcpy((void*)&val, (void*)&_storage[pos], sizeof(T));
+#else
+            T val = *((T const*)&_storage[pos]);
+#endif
+
+            EndianConvert(val);
+            return val;
+        }
+
+        /**
+         * @brief
+         *
+         * @param dest
+         * @param len
+         */
+        void read(uint8* dest, size_t len)
+        {
+            if (_rpos  + len > size())
+            {
+                throw ByteBufferException(false, _rpos, len, size());
+            }
+            memcpy(dest, &_storage[_rpos], len);
+            _rpos += len;
+        }
+
+        /**
+         * @brief
+         *
+         * @return uint64
+         */
+        uint64 readPackGUID()
+        {
+            uint64 guid = 0;
+            uint8 guidmark = 0;
+            (*this) >> guidmark;
+
+            for (int i = 0; i < 8; ++i)
+            {
+                if (guidmark & (uint8(1) << i))
+                {
+                    uint8 bit;
+                    (*this) >> bit;
+                    guid |= (uint64(bit) << (i * 8));
+                }
+            }
+
+            return guid;
+        }
+
+        /**
+         * @brief
+         *
+         * @return const uint8
+         */
+        const uint8* contents() const { return &_storage[0]; }
+
+        /**
+         * @brief
+         *
+         * @return size_t
+         */
+        size_t size() const { return _storage.size(); }
+        /**
+         * @brief
+         *
+         * @return bool
+         */
+        bool empty() const { return _storage.empty(); }
+
+        /**
+         * @brief
+         *
+         * @param newsize
+         */
+        void resize(size_t newsize)
+        {
+            _storage.resize(newsize);
+            _rpos = 0;
+            _wpos = size();
+        }
+
+        /**
+         * @brief
+         *
+         * @param ressize
+         */
+        void reserve(size_t ressize)
+        {
+            if (ressize > size())
+            {
+                _storage.reserve(ressize);
+            }
+        }
+
+        /**
+         * @brief
+         *
+         * @param str
+         */
+        void append(const std::string& str)
+        {
+            append((uint8 const*)str.c_str(), str.size() + 1);
+        }
+
+        /**
+         * @brief
+         *
+         * @param src
+         * @param cnt
+         */
+        void append(const char* src, size_t cnt)
+        {
+            return append((const uint8*)src, cnt);
+        }
+
+        /**
+         * @brief
+         *
+         * @param src
+         * @param cnt
+         */
+        template<class T> void append(const T* src, size_t cnt)
+        {
+            return append((const uint8*)src, cnt * sizeof(T));
+        }
+
+        /**
+         * @brief
+         *
+         * @param src
+         * @param cnt
+         */
+        void append(const uint8* src, size_t cnt)
+        {
+            if (!cnt)
+            {
+                return;
+            }
+
+            MANGOS_ASSERT(size() < 10000000);
+
+            if (_storage.size() < _wpos + cnt)
+            {
+                _storage.resize(_wpos + cnt);
+            }
+            memcpy(&_storage[_wpos], src, cnt);
+            _wpos += cnt;
+        }
+
+        /**
+         * @brief
+         *
+         * @param buffer
+         */
+        void append(const ByteBuffer& buffer)
+        {
+            if (buffer.wpos())
+            {
+                append(buffer.contents(), buffer.wpos());
+            }
+        }
+
+        /**
+         * @brief can be used in SMSG_MONSTER_MOVE opcode
+         *
+         * @param x
+         * @param y
+         * @param z
+         */
+        void appendPackXYZ(float x, float y, float z)
+        {
+            uint32 packed = 0;
+            packed |= ((int)(x / 0.25f) & 0x7FF);
+            packed |= ((int)(y / 0.25f) & 0x7FF) << 11;
+            packed |= ((int)(z / 0.25f) & 0x3FF) << 22;
+            *this << packed;
+        }
+
+        /**
+         * @brief
+         *
+         * @param guid
+         */
+        void appendPackGUID(uint64 guid)
+        {
+            uint8 packGUID[8 + 1];
+            packGUID[0] = 0;
+            size_t size = 1;
+            for (uint8 i = 0; guid != 0; ++i)
+            {
+                if (guid & 0xFF)
+                {
+                    packGUID[0] |= uint8(1 << i);
+                    packGUID[size] =  uint8(guid & 0xFF);
+                    ++size;
+                }
+
+                guid >>= 8;
+            }
+
+            append(packGUID, size);
+        }
+
+        /**
+         * @brief
+         *
+         * @param pos
+         * @param src
+         * @param cnt
+         */
+        void put(size_t pos, const uint8* src, size_t cnt)
+        {
+            if (pos + cnt > size())
+            {
+                throw ByteBufferException(true, pos, cnt, size());
+            }
+            memcpy(&_storage[pos], src, cnt);
+        }
+
+        /**
+         * @brief
+         *
+         */
+        void print_storage() const;
+        /**
+         * @brief
+         *
+         */
+        void textlike() const;
+        /**
+         * @brief
+         *
+         */
+        void hexlike() const;
+
+    private:
+        /**
+         * @brief limited for internal use because can "append" any unexpected type (like pointer and etc) with hard detection problem
+         *
+         * @param value
+         */
+        template <typename T> void append(T value)
+        {
+            EndianConvert(value);
+            append((uint8*)&value, sizeof(value));
+        }
+
+    protected:
+        size_t _rpos, _wpos; /**< TODO */
+        std::vector<uint8> _storage; /**< TODO */
+};
+
+template <typename T>
+/**
+ * @brief
+ *
+ * @param b
+ * @param v
+ * @return ByteBuffer &operator
+ */
+inline ByteBuffer& operator<<(ByteBuffer& b, std::vector<T> const& v)
+{
+    b << (uint32)v.size();
+    for (typename std::vector<T>::iterator i = v.begin(); i != v.end(); ++i)
+    {
+        b << *i;
+    }
+    return b;
+}
+
+template <typename T>
+/**
+ * @brief
+ *
+ * @param b
+ * @param v
+ * @return ByteBuffer &operator >>
+ */
+inline ByteBuffer& operator>>(ByteBuffer& b, std::vector<T>& v)
+{
+    uint32 vsize;
+    b >> vsize;
+    v.clear();
+    while (vsize--)
+    {
+        T t;
+        b >> t;
+        v.push_back(t);
+    }
+    return b;
+}
+
+template <typename T>
+/**
+ * @brief
+ *
+ * @param b
+ * @param v
+ * @return ByteBuffer &operator
+ */
+inline ByteBuffer& operator<<(ByteBuffer& b, std::list<T> const& v)
+{
+    b << (uint32)v.size();
+    for (typename std::list<T>::iterator i = v.begin(); i != v.end(); ++i)
+    {
+        b << *i;
+    }
+    return b;
+}
+
+template <typename T>
+/**
+ * @brief
+ *
+ * @param b
+ * @param v
+ * @return ByteBuffer &operator >>
+ */
+inline ByteBuffer& operator>>(ByteBuffer& b, std::list<T>& v)
+{
+    uint32 vsize;
+    b >> vsize;
+    v.clear();
+    while (vsize--)
+    {
+        T t;
+        b >> t;
+        v.push_back(t);
+    }
+    return b;
+}
+
+template <typename K, typename V>
+/**
+ * @brief
+ *
+ * @param b
+ * @param std::map<K
+ * @param m
+ * @return ByteBuffer &operator
+ */
+inline ByteBuffer& operator<<(ByteBuffer& b, std::map<K, V>& m)
+{
+    b << (uint32)m.size();
+    for (typename std::map<K, V>::iterator i = m.begin(); i != m.end(); ++i)
+    {
+        b << i->first << i->second;
+    }
+    return b;
+}
+
+template <typename K, typename V>
+/**
+ * @brief
+ *
+ * @param b
+ * @param std::map<K
+ * @param m
+ * @return ByteBuffer &operator >>
+ */
+inline ByteBuffer& operator>>(ByteBuffer& b, std::map<K, V>& m)
+{
+    uint32 msize;
+    b >> msize;
+    m.clear();
+    while (msize--)
+    {
+        K k;
+        V v;
+        b >> k >> v;
+        m.insert(make_pair(k, v));
+    }
+    return b;
+}
+
+template<>
+/**
+ * @brief
+ *
+ */
+inline void ByteBuffer::read_skip<char*>()
+{
+    std::string temp;
+    *this >> temp;
+}
+
+template<>
+/**
+ * @brief
+ *
+ */
+inline void ByteBuffer::read_skip<char const*>()
+{
+    read_skip<char*>();
+}
+
+template<>
+/**
+ * @brief
+ *
+ */
+inline void ByteBuffer::read_skip<std::string>()
+{
+    read_skip<char*>();
+}
+#endif
diff --git a/shared/Utilities/ByteConverter.h b/shared/Utilities/ByteConverter.h
new file mode 100644
index 0000000..75de0b1
--- /dev/null
+++ b/shared/Utilities/ByteConverter.h
@@ -0,0 +1,131 @@
+/**
+ * MaNGOS is a full featured server for World of Warcraft, supporting
+ * the following clients: 1.12.x, 2.4.3, 3.3.5a, 4.3.4a and 5.4.8
+ *
+ * Copyright (C) 2005-2022 MaNGOS <https://getmangos.eu>
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * World of Warcraft, and all World of Warcraft or Warcraft art, images,
+ * and lore are copyrighted by Blizzard Entertainment, Inc.
+ */
+
+#ifndef MANGOS_BYTECONVERTER_H
+#define MANGOS_BYTECONVERTER_H
+
+/**
+ * ByteConverter reverse your byte order. This is used for cross platform
+ * where they have different endians.
+ */
+
+#include "Platform/Define.h"
+#include <algorithm>
+
+namespace ByteConverter
+{
+    template<size_t T>
+    /**
+     * @brief
+     *
+     * @param val
+     */
+    inline void convert(char* val)
+    {
+        std::swap(*val, *(val + T - 1));
+        convert < T - 2 > (val + 1);
+    }
+
+    /**
+     * @brief
+     *
+     * @param
+     */
+    template<> inline void convert<0>(char*) {}
+    /**
+     * @brief ignore central byte
+     *
+     * @param
+     */
+    template<> inline void convert<1>(char*) {}
+
+    template<typename T>
+    /**
+     * @brief
+     *
+     * @param val
+     */
+    inline void apply(T* val)
+    {
+        convert<sizeof(T)>((char*)(val));
+    }
+}
+
+#if MANGOS_ENDIAN == MANGOS_BIGENDIAN
+/**
+ * @brief
+ *
+ * @param val
+ */
+template<typename T> inline void EndianConvert(T& val) { ByteConverter::apply<T>(&val); }
+/**
+ * @brief
+ *
+ * @param
+ */
+template<typename T> inline void EndianConvertReverse(T&) { }
+#else
+template<typename T> inline void EndianConvert(T&) { }
+template<typename T> inline void EndianConvertReverse(T& val) { ByteConverter::apply<T>(&val); }
+#endif
+
+/**
+ * @brief will generate link error
+ *
+ * @param
+ */
+template<typename T> void EndianConvert(T*);
+/**
+ * @brief will generate link error
+ *
+ * @param
+ */
+template<typename T> void EndianConvertReverse(T*);
+
+/**
+ * @brief
+ *
+ * @param
+ */
+inline void EndianConvert(uint8&) { }
+/**
+ * @brief
+ *
+ * @param
+ */
+inline void EndianConvert(int8&)  { }
+/**
+ * @brief
+ *
+ * @param
+ */
+inline void EndianConvertReverse(uint8&) { }
+/**
+ * @brief
+ *
+ * @param
+ */
+inline void EndianConvertReverse(int8&) { }
+
+#endif
diff --git a/shared/Utilities/Callback.h b/shared/Utilities/Callback.h
new file mode 100644
index 0000000..6ae3caf
--- /dev/null
+++ b/shared/Utilities/Callback.h
@@ -0,0 +1,1105 @@
+/**
+ * MaNGOS is a full featured server for World of Warcraft, supporting
+ * the following clients: 1.12.x, 2.4.3, 3.3.5a, 4.3.4a and 5.4.8
+ *
+ * Copyright (C) 2005-2022 MaNGOS <https://getmangos.eu>
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * World of Warcraft, and all World of Warcraft or Warcraft art, images,
+ * and lore are copyrighted by Blizzard Entertainment, Inc.
+ */
+
+#ifndef MANGOS_CALLBACK_H
+#define MANGOS_CALLBACK_H
+
+// defines to simplify multi param templates code and readablity
+#define TYPENAMES_1 typename T1
+#define TYPENAMES_2 TYPENAMES_1, typename T2
+#define TYPENAMES_3 TYPENAMES_2, typename T3
+#define TYPENAMES_4 TYPENAMES_3, typename T4
+#define TYPENAMES_5 TYPENAMES_4, typename T5
+#define TYPENAMES_6 TYPENAMES_5, typename T6
+#define TYPENAMES_7 TYPENAMES_6, typename T7
+#define TYPENAMES_8 TYPENAMES_7, typename T8
+#define TYPENAMES_9 TYPENAMES_8, typename T9
+#define TYPENAMES_10 TYPENAMES_9, typename T10
+
+#define PARAMS_1 T1 param1
+#define PARAMS_2 PARAMS_1, T2 param2
+#define PARAMS_3 PARAMS_2, T3 param3
+#define PARAMS_4 PARAMS_3, T4 param4
+#define PARAMS_5 PARAMS_4, T5 param5
+#define PARAMS_6 PARAMS_5, T6 param6
+#define PARAMS_7 PARAMS_6, T7 param7
+#define PARAMS_8 PARAMS_7, T8 param8
+#define PARAMS_9 PARAMS_8, T9 param9
+#define PARAMS_10 PARAMS_9, T10 param10
+
+/**
+ * @brief empty struct to use in templates instead of void type
+ *
+ */
+struct null { null() {} };
+/// ------------ BASE CLASSES ------------
+
+namespace MaNGOS
+{
+    template < class Class, typename ParamType1 = void, typename ParamType2 = void, typename ParamType3 = void, typename ParamType4 = void >
+    /**
+     * @brief
+     *
+     */
+    class _Callback
+    {
+        protected:
+
+            /**
+             * @brief
+             *
+             */
+            typedef void (Class::*Method)(ParamType1, ParamType2, ParamType3, ParamType4);
+            Class* m_object; /**< TODO */
+            Method m_method; /**< TODO */
+            ParamType1 m_param1; /**< TODO */
+            ParamType2 m_param2; /**< TODO */
+            ParamType3 m_param3; /**< TODO */
+            ParamType4 m_param4; /**< TODO */
+            /**
+             * @brief
+             *
+             */
+            void _Execute() { (m_object->*m_method)(m_param1, m_param2, m_param3, m_param4); }
+
+        public:
+
+            /**
+             * @brief
+             *
+             * @param object
+             * @param method
+             * @param param1
+             * @param param2
+             * @param param3
+             * @param param4
+             */
+            _Callback(Class* object, Method method, ParamType1 param1, ParamType2 param2, ParamType3 param3, ParamType4 param4)
+                : m_object(object), m_method(method),
+                  m_param1(param1), m_param2(param2), m_param3(param3), m_param4(param4)
+            {
+            }
+
+            /**
+             * @brief
+             *
+             * @param const_Callback<Class
+             * @param ParamType1
+             * @param ParamType2
+             * @param ParamType3
+             * @param cb
+             */
+            _Callback(_Callback<Class, ParamType1, ParamType2, ParamType3, ParamType4> const& cb)
+                : m_object(cb.m_object), m_method(cb.m_method),
+                  m_param1(cb.m_param1), m_param2(cb.m_param2), m_param3(cb.m_param3), m_param4(cb.m_param4)
+            {
+            }
+    };
+
+    template<class Class, typename ParamType1, typename ParamType2, typename ParamType3>
+    /**
+     * @brief
+     *
+     */
+    class _Callback<Class, ParamType1, ParamType2, ParamType3>
+    {
+        protected:
+
+            /**
+             * @brief
+             *
+             */
+            typedef void (Class::*Method)(ParamType1, ParamType2, ParamType3);
+            Class* m_object; /**< TODO */
+            Method m_method; /**< TODO */
+            ParamType1 m_param1; /**< TODO */
+            ParamType2 m_param2; /**< TODO */
+            ParamType3 m_param3; /**< TODO */
+            /**
+             * @brief
+             *
+             */
+            void _Execute() { (m_object->*m_method)(m_param1, m_param2, m_param3); }
+
+        public:
+            /**
+             * @brief
+             *
+             * @param object
+             * @param method
+             * @param param1
+             * @param param2
+             * @param param3
+             */
+            _Callback(Class* object, Method method, ParamType1 param1, ParamType2 param2, ParamType3 param3)
+                : m_object(object), m_method(method),
+                  m_param1(param1), m_param2(param2), m_param3(param3)
+            {
+            }
+
+            /**
+             * @brief
+             *
+             * @param const_Callback<Class
+             * @param ParamType1
+             * @param ParamType2
+             * @param cb
+             */
+            _Callback(_Callback<Class, ParamType1, ParamType2, ParamType3> const& cb)
+                : m_object(cb.m_object), m_method(cb.m_method),
+                  m_param1(cb.m_param1), m_param2(cb.m_param2), m_param3(cb.m_param3)
+            {
+            }
+    };
+
+    template<class Class, typename ParamType1, typename ParamType2>
+    /**
+     * @brief
+     *
+     */
+    class _Callback<Class, ParamType1, ParamType2>
+    {
+        protected:
+
+            /**
+             * @brief
+             *
+             */
+            typedef void (Class::*Method)(ParamType1, ParamType2);
+            Class* m_object; /**< TODO */
+            Method m_method; /**< TODO */
+            ParamType1 m_param1; /**< TODO */
+            ParamType2 m_param2; /**< TODO */
+            /**
+             * @brief
+             *
+             */
+            void _Execute() { (m_object->*m_method)(m_param1, m_param2); }
+
+        public:
+
+            /**
+             * @brief
+             *
+             * @param object
+             * @param method
+             * @param param1
+             * @param param2
+             */
+            _Callback(Class* object, Method method, ParamType1 param1, ParamType2 param2)
+                : m_object(object), m_method(method),
+                  m_param1(param1), m_param2(param2)
+            {
+            }
+
+            /**
+             * @brief
+             *
+             * @param const_Callback<Class
+             * @param ParamType1
+             * @param cb
+             */
+            _Callback(_Callback<Class, ParamType1, ParamType2> const& cb)
+                : m_object(cb.m_object), m_method(cb.m_method),
+                  m_param1(cb.m_param1), m_param2(cb.m_param2)
+            {
+            }
+    };
+
+    template<class Class, typename ParamType1>
+    /**
+     * @brief
+     *
+     */
+    class _Callback<Class, ParamType1>
+    {
+        protected:
+
+            /**
+             * @brief
+             *
+             */
+            typedef void (Class::*Method)(ParamType1);
+            Class* m_object; /**< TODO */
+            Method m_method; /**< TODO */
+            ParamType1 m_param1; /**< TODO */
+            /**
+             * @brief
+             *
+             */
+            void _Execute() { (m_object->*m_method)(m_param1); }
+
+        public:
+
+            /**
+             * @brief
+             *
+             * @param object
+             * @param method
+             * @param param1
+             */
+            _Callback(Class* object, Method method, ParamType1 param1)
+                : m_object(object), m_method(method),
+                  m_param1(param1)
+            {
+            }
+
+            /**
+             * @brief
+             *
+             * @param const_Callback<Class
+             * @param cb
+             */
+            _Callback(_Callback<Class, ParamType1> const& cb)
+                : m_object(cb.m_object), m_method(cb.m_method),
+                  m_param1(cb.m_param1)
+            {
+            }
+    };
+
+    template<class Class>
+    /**
+     * @brief
+     *
+     */
+    class _Callback<Class>
+    {
+        protected:
+
+            /**
+             * @brief
+             *
+             */
+            typedef void (Class::*Method)();
+            Class* m_object; /**< TODO */
+            Method m_method; /**< TODO */
+            /**
+             * @brief
+             *
+             */
+            void _Execute() { (m_object->*m_method)(); }
+
+        public:
+            /**
+             * @brief
+             *
+             * @param object
+             * @param method
+             */
+            _Callback(Class* object, Method method)
+                : m_object(object), m_method(method)
+            {
+            }
+            /**
+             * @brief
+             *
+             * @param cb
+             */
+            _Callback(_Callback<Class> const& cb)
+                : m_object(cb.m_object), m_method(cb.m_method)
+            {
+            }
+    };
+
+    /// ---- Statics ----
+
+    template < typename ParamType1 = void, typename ParamType2 = void, typename ParamType3 = void, typename ParamType4 = void >
+    /**
+     * @brief
+     *
+     */
+    class _SCallback
+    {
+        protected:
+
+            /**
+             * @brief
+             *
+             */
+            typedef void (*Method)(ParamType1, ParamType2, ParamType3, ParamType4);
+            Method m_method; /**< TODO */
+            ParamType1 m_param1; /**< TODO */
+            ParamType2 m_param2; /**< TODO */
+            ParamType3 m_param3; /**< TODO */
+            ParamType4 m_param4; /**< TODO */
+            /**
+             * @brief
+             *
+             */
+            void _Execute() { (*m_method)(m_param1, m_param2, m_param3, m_param4); }
+
+        public:
+
+            /**
+             * @brief
+             *
+             * @param method
+             * @param param1
+             * @param param2
+             * @param param3
+             * @param param4
+             */
+            _SCallback(Method method, ParamType1 param1, ParamType2 param2, ParamType3 param3, ParamType4 param4)
+                : m_method(method),
+                  m_param1(param1), m_param2(param2), m_param3(param3), m_param4(param4)
+            {
+            }
+
+            /**
+             * @brief
+             *
+             * @param const_SCallback<ParamType1
+             * @param ParamType2
+             * @param ParamType3
+             * @param cb
+             */
+            _SCallback(_SCallback<ParamType1, ParamType2, ParamType3, ParamType4> const& cb)
+                : m_method(cb.m_method),
+                  m_param1(cb.m_param1), m_param2(cb.m_param2), m_param3(cb.m_param3), m_param4(cb.m_param4)
+            {
+            }
+    };
+
+    template<typename ParamType1, typename ParamType2, typename ParamType3>
+    /**
+     * @brief
+     *
+     */
+    class _SCallback<ParamType1, ParamType2, ParamType3>
+    {
+        protected:
+
+            /**
+             * @brief
+             *
+             */
+            typedef void (*Method)(ParamType1, ParamType2, ParamType3);
+            Method m_method; /**< TODO */
+            ParamType1 m_param1; /**< TODO */
+            ParamType2 m_param2; /**< TODO */
+            ParamType3 m_param3; /**< TODO */
+            /**
+             * @brief
+             *
+             */
+            void _Execute() { (*m_method)(m_param1, m_param2, m_param3); }
+
+        public:
+            /**
+             * @brief
+             *
+             * @param method
+             * @param param1
+             * @param param2
+             * @param param3
+             */
+            _SCallback(Method method, ParamType1 param1, ParamType2 param2, ParamType3 param3)
+                : m_method(method),
+                  m_param1(param1), m_param2(param2), m_param3(param3)
+            {
+            }
+            /**
+             * @brief
+             *
+             * @param const_SCallback<ParamType1
+             * @param ParamType2
+             * @param cb
+             */
+            _SCallback(_SCallback<ParamType1, ParamType2, ParamType3> const& cb)
+                : m_method(cb.m_method),
+                  m_param1(cb.m_param1), m_param2(cb.m_param2), m_param3(cb.m_param3)
+            {
+            }
+    };
+
+    template<typename ParamType1, typename ParamType2>
+    /**
+     * @brief
+     *
+     */
+    class _SCallback<ParamType1, ParamType2>
+    {
+        protected:
+
+            /**
+             * @brief
+             *
+             */
+            typedef void (*Method)(ParamType1, ParamType2);
+            Method m_method; /**< TODO */
+            ParamType1 m_param1; /**< TODO */
+            ParamType2 m_param2; /**< TODO */
+            /**
+             * @brief
+             *
+             */
+            void _Execute() { (*m_method)(m_param1, m_param2); }
+
+        public:
+            /**
+             * @brief
+             *
+             * @param method
+             * @param param1
+             * @param param2
+             */
+            _SCallback(Method method, ParamType1 param1, ParamType2 param2)
+                : m_method(method),
+                  m_param1(param1), m_param2(param2)
+            {
+            }
+
+            /**
+             * @brief
+             *
+             * @param const_SCallback<ParamType1
+             * @param cb
+             */
+            _SCallback(_SCallback<ParamType1, ParamType2> const& cb)
+                : m_method(cb.m_method),
+                  m_param1(cb.m_param1), m_param2(cb.m_param2)
+            {
+            }
+    };
+
+    template<typename ParamType1>
+    /**
+     * @brief
+     *
+     */
+    class _SCallback<ParamType1>
+    {
+        protected:
+
+            /**
+             * @brief
+             *
+             */
+            typedef void (*Method)(ParamType1);
+            Method m_method; /**< TODO */
+            ParamType1 m_param1; /**< TODO */
+            /**
+             * @brief
+             *
+             */
+            void _Execute() { (*m_method)(m_param1); }
+
+        public:
+            /**
+             * @brief
+             *
+             * @param method
+             * @param param1
+             */
+            _SCallback(Method method, ParamType1 param1)
+                : m_method(method),
+                  m_param1(param1)
+            {
+            }
+
+            /**
+             * @brief
+             *
+             * @param cb
+             */
+            _SCallback(_SCallback<ParamType1> const& cb)
+                : m_method(cb.m_method),
+                  m_param1(cb.m_param1)
+            {
+            }
+    };
+
+    template<>
+    /**
+     * @brief
+     *
+     */
+    class _SCallback<>
+    {
+        protected:
+
+            /**
+             * @brief
+             *
+             */
+            typedef void (*Method)();
+            Method m_method; /**< TODO */
+            /**
+             * @brief
+             *
+             */
+            void _Execute() { (*m_method)(); }
+
+        public:
+
+            /**
+             * @brief
+             *
+             * @param method
+             */
+            _SCallback(Method method)
+                : m_method(method)
+            {
+            }
+
+            /**
+             * @brief
+             *
+             * @param cb
+             */
+            _SCallback(_SCallback<> const& cb)
+                : m_method(cb.m_method)
+            {
+            }
+    };
+}
+
+/// --------- GENERIC CALLBACKS ----------
+
+namespace MaNGOS
+{
+    /**
+     * @brief
+     *
+     */
+    class ICallback
+    {
+        public:
+
+            /**
+             * @brief
+             *
+             */
+            virtual void Execute() = 0;
+            /**
+             * @brief
+             *
+             */
+            virtual ~ICallback() {}
+    };
+
+    template<class CB>
+    /**
+     * @brief
+     *
+     */
+    class _ICallback : public CB, public ICallback
+    {
+        public:
+
+            /**
+             * @brief
+             *
+             * @param cb
+             */
+            _ICallback(CB const& cb) : CB(cb)
+            {
+            }
+
+            /**
+             * @brief
+             *
+             */
+            void Execute() { CB::_Execute(); }
+    };
+
+    template < class Class, typename ParamType1 = void, typename ParamType2 = void, typename ParamType3 = void, typename ParamType4 = void >
+    /**
+     * @brief
+     *
+     */
+    class Callback : public _ICallback<_Callback<Class, ParamType1, ParamType2, ParamType3, ParamType4> >
+    {
+        private:
+
+            /**
+             * @brief
+             *
+             */
+            typedef _Callback<Class, ParamType1, ParamType2, ParamType3, ParamType4> C4;
+        public:
+
+            /**
+             * @brief
+             *
+             * @param object
+             * @param method
+             * @param param1
+             * @param param2
+             * @param param3
+             * @param param4
+             */
+            Callback(Class* object, typename C4::Method method, ParamType1 param1, ParamType2 param2, ParamType3 param3, ParamType4 param4)
+                : _ICallback<C4>(C4(object, method, param1, param2, param3, param4))
+            {
+            }
+    };
+
+    template<class Class, typename ParamType1, typename ParamType2, typename ParamType3>
+    /**
+     * @brief
+     *
+     */
+    class Callback<Class, ParamType1, ParamType2, ParamType3> : public _ICallback<_Callback<Class, ParamType1, ParamType2, ParamType3> >
+    {
+        private:
+
+            /**
+             * @brief
+             *
+             */
+            typedef _Callback<Class, ParamType1, ParamType2, ParamType3> C3;
+        public:
+
+            /**
+             * @brief
+             *
+             * @param object
+             * @param method
+             * @param param1
+             * @param param2
+             * @param param3
+             */
+            Callback(Class* object, typename C3::Method method, ParamType1 param1, ParamType2 param2, ParamType3 param3)
+                : _ICallback<C3>(C3(object, method, param1, param2, param3))
+            {
+            }
+    };
+
+    template<class Class, typename ParamType1, typename ParamType2>
+    /**
+     * @brief
+     *
+     */
+    class Callback<Class, ParamType1, ParamType2> : public _ICallback<_Callback<Class, ParamType1, ParamType2> >
+    {
+        private:
+
+            /**
+             * @brief
+             *
+             */
+            typedef _Callback<Class, ParamType1, ParamType2> C2;
+
+        public:
+            /**
+             * @brief
+             *
+             * @param object
+             * @param method
+             * @param param1
+             * @param param2
+             */
+            Callback(Class* object, typename C2::Method method, ParamType1 param1, ParamType2 param2)
+                : _ICallback<C2>(C2(object, method, param1, param2))
+            {
+            }
+    };
+
+    template<class Class, typename ParamType1>
+    /**
+     * @brief
+     *
+     */
+    class Callback<Class, ParamType1> : public _ICallback<_Callback<Class, ParamType1> >
+    {
+        private:
+
+            /**
+             * @brief
+             *
+             */
+            typedef _Callback<Class, ParamType1> C1;
+
+        public:
+
+            /**
+             * @brief
+             *
+             * @param object
+             * @param method
+             * @param param1
+             */
+            Callback(Class* object, typename C1::Method method, ParamType1 param1)
+                : _ICallback<C1>(C1(object, method, param1))
+            {
+            }
+    };
+
+    template<class Class>
+    /**
+     * @brief
+     *
+     */
+    class Callback<Class> : public _ICallback<_Callback<Class> >
+    {
+        private:
+
+            /**
+             * @brief
+             *
+             */
+            typedef _Callback<Class> C0;
+
+        public:
+
+            /**
+             * @brief
+             *
+             * @param object
+             * @param method
+             */
+            Callback(Class* object, typename C0::Method method)
+                : _ICallback<C0>(C0(object, method))
+            {
+            }
+    };
+}
+
+/// ---------- QUERY CALLBACKS -----------
+
+class QueryResult;
+
+namespace MaNGOS
+{
+    /**
+     * @brief
+     *
+     */
+    class IQueryCallback
+    {
+        public:
+
+            /**
+             * @brief
+             *
+             */
+            virtual void Execute() = 0;
+            /**
+             * @brief
+             *
+             */
+            virtual ~IQueryCallback() {}
+            /**
+             * @brief
+             *
+             * @param result
+             */
+            virtual void SetResult(QueryResult* result) = 0;
+            /**
+             * @brief
+             *
+             * @return QueryResult
+             */
+            virtual QueryResult* GetResult() = 0;
+    };
+
+    template<class CB>
+    /**
+     * @brief
+     *
+     */
+    class _IQueryCallback : public CB, public IQueryCallback
+    {
+        public:
+
+            /**
+             * @brief
+             *
+             * @param cb
+             */
+            _IQueryCallback(CB const& cb) : CB(cb)
+            {
+            }
+
+            /**
+             * @brief
+             *
+             */
+            void Execute() { CB::_Execute(); }
+            /**
+             * @brief
+             *
+             * @param result
+             */
+            void SetResult(QueryResult* result) { CB::m_param1 = result; }
+            /**
+             * @brief
+             *
+             * @return QueryResult
+             */
+            QueryResult* GetResult() { return CB::m_param1; }
+    };
+
+    template < class Class, typename ParamType1 = void, typename ParamType2 = void, typename ParamType3 = void >
+    /**
+     * @brief
+     *
+     */
+    class QueryCallback : public _IQueryCallback<_Callback<Class, QueryResult*, ParamType1, ParamType2, ParamType3> >
+    {
+        private:
+
+            /**
+             * @brief
+             *
+             */
+            typedef _Callback<Class, QueryResult*, ParamType1, ParamType2, ParamType3> QC3;
+
+        public:
+
+            /**
+             * @brief
+             *
+             * @param object
+             * @param method
+             * @param result
+             * @param param1
+             * @param param2
+             * @param param3
+             */
+            QueryCallback(Class* object, typename QC3::Method method, QueryResult* result, ParamType1 param1, ParamType2 param2, ParamType3 param3)
+                : _IQueryCallback<QC3>(QC3(object, method, result, param1, param2, param3))
+            {
+            }
+    };
+
+    template<class Class, typename ParamType1, typename ParamType2>
+    /**
+     * @brief
+     *
+     */
+    class QueryCallback<Class, ParamType1, ParamType2> : public _IQueryCallback<_Callback<Class, QueryResult*, ParamType1, ParamType2> >
+    {
+        private:
+
+            /**
+             * @brief
+             *
+             */
+            typedef _Callback<Class, QueryResult*, ParamType1, ParamType2> QC2;
+
+        public:
+
+            /**
+             * @brief
+             *
+             * @param object
+             * @param method
+             * @param result
+             * @param param1
+             * @param param2
+             */
+            QueryCallback(Class* object, typename QC2::Method method, QueryResult* result, ParamType1 param1, ParamType2 param2)
+                : _IQueryCallback<QC2>(QC2(object, method, result, param1, param2))
+            {
+            }
+    };
+
+    template<class Class, typename ParamType1>
+    /**
+     * @brief
+     *
+     */
+    class QueryCallback<Class, ParamType1> : public _IQueryCallback<_Callback<Class, QueryResult*, ParamType1> >
+    {
+        private:
+
+            /**
+             * @brief
+             *
+             */
+            typedef _Callback<Class, QueryResult*, ParamType1> QC1;
+
+        public:
+
+            /**
+             * @brief
+             *
+             * @param object
+             * @param method
+             * @param result
+             * @param param1
+             */
+            QueryCallback(Class* object, typename QC1::Method method, QueryResult* result, ParamType1 param1)
+                : _IQueryCallback<QC1>(QC1(object, method, result, param1))
+            {
+            }
+    };
+
+    template<class Class>
+    /**
+     * @brief
+     *
+     */
+    class QueryCallback<Class> : public _IQueryCallback<_Callback<Class, QueryResult*> >
+    {
+        private:
+
+            /**
+             * @brief
+             *
+             */
+            typedef _Callback<Class, QueryResult*> QC0;
+
+        public:
+            /**
+             * @brief
+             *
+             * @param object
+             * @param method
+             * @param result
+             */
+            QueryCallback(Class* object, typename QC0::Method method, QueryResult* result)
+                : _IQueryCallback<QC0>(QC0(object, method, result))
+            {
+            }
+    };
+
+    /// ---- Statics ----
+
+    template < typename ParamType1 = void, typename ParamType2 = void, typename ParamType3 = void >
+    /**
+     * @brief
+     *
+     */
+    class SQueryCallback : public _IQueryCallback<_SCallback<QueryResult*, ParamType1, ParamType2, ParamType3> >
+    {
+        private:
+
+            /**
+             * @brief
+             *
+             */
+            typedef _SCallback<QueryResult*, ParamType1, ParamType2, ParamType3> QC3;
+
+        public:
+
+            /**
+             * @brief
+             *
+             * @param method
+             * @param result
+             * @param param1
+             * @param param2
+             * @param param3
+             */
+            SQueryCallback(typename QC3::Method method, QueryResult* result, ParamType1 param1, ParamType2 param2, ParamType3 param3)
+                : _IQueryCallback<QC3>(QC3(method, result, param1, param2, param3))
+            {
+            }
+    };
+
+    template<typename ParamType1, typename ParamType2>
+    /**
+     * @brief
+     *
+     */
+    class SQueryCallback < ParamType1, ParamType2 > : public _IQueryCallback<_SCallback<QueryResult*, ParamType1, ParamType2> >
+    {
+        private:
+
+            /**
+             * @brief
+             *
+             */
+            typedef _SCallback<QueryResult*, ParamType1, ParamType2> QC2;
+
+        public:
+
+            /**
+             * @brief
+             *
+             * @param method
+             * @param result
+             * @param param1
+             * @param param2
+             */
+            SQueryCallback(typename QC2::Method method, QueryResult* result, ParamType1 param1, ParamType2 param2)
+                : _IQueryCallback<QC2>(QC2(method, result, param1, param2))
+            {
+            }
+    };
+
+    template<typename ParamType1>
+    /**
+     * @brief
+     *
+     */
+    class SQueryCallback<ParamType1> : public _IQueryCallback<_SCallback<QueryResult*, ParamType1> >
+    {
+        private:
+
+            /**
+             * @brief
+             *
+             */
+            typedef _SCallback<QueryResult*, ParamType1> QC1;
+
+        public:
+
+            /**
+             * @brief
+             *
+             * @param method
+             * @param result
+             * @param param1
+             */
+            SQueryCallback(typename QC1::Method method, QueryResult* result, ParamType1 param1)
+                : _IQueryCallback<QC1>(QC1(method, result, param1))
+            {
+            }
+    };
+
+    template<>
+    /**
+     * @brief
+     *
+     */
+    class SQueryCallback<> : public _IQueryCallback<_SCallback<QueryResult*> >
+    {
+        private:
+
+            /**
+             * @brief
+             *
+             */
+            typedef _SCallback<QueryResult*> QC0;
+
+        public:
+
+            /**
+             * @brief
+             *
+             * @param method
+             * @param result
+             */
+            SQueryCallback(QC0::Method method, QueryResult* result)
+                : _IQueryCallback<QC0>(QC0(method, result))
+            {
+            }
+    };
+}
+
+#endif
diff --git a/shared/Utilities/Duration.h b/shared/Utilities/Duration.h
new file mode 100644
index 0000000..0953db3
--- /dev/null
+++ b/shared/Utilities/Duration.h
@@ -0,0 +1,51 @@
+/**
+ * MaNGOS is a full featured server for World of Warcraft, supporting
+ * the following clients: 1.12.x, 2.4.3, 3.3.5a, 4.3.4a and 5.4.8
+ *
+ * Copyright (C) 2005-2022 MaNGOS <https://getmangos.eu>
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * World of Warcraft, and all World of Warcraft or Warcraft art, images,
+ * and lore are copyrighted by Blizzard Entertainment, Inc.
+ */
+
+#ifndef DURATION_H
+#define DURATION_H
+
+#include <chrono>
+
+ /// Milliseconds shorthand typedef.
+typedef std::chrono::milliseconds Milliseconds;
+
+/// Seconds shorthand typedef.
+typedef std::chrono::seconds Seconds;
+
+/// Minutes shorthand typedef.
+typedef std::chrono::minutes Minutes;
+
+/// Hours shorthand typedef.
+typedef std::chrono::hours Hours;
+
+/// time_point shorthand typedefs
+typedef std::chrono::steady_clock::time_point TimePoint;
+typedef std::chrono::system_clock::time_point SystemTimePoint;
+
+constexpr std::chrono::hours operator "" _days(unsigned long long days)
+{
+    return std::chrono::hours(days * Hours(24));
+}
+
+#endif
diff --git a/shared/Utilities/Errors.h b/shared/Utilities/Errors.h
new file mode 100644
index 0000000..8afbd63
--- /dev/null
+++ b/shared/Utilities/Errors.h
@@ -0,0 +1,75 @@
+/**
+ * MaNGOS is a full featured server for World of Warcraft, supporting
+ * the following clients: 1.12.x, 2.4.3, 3.3.5a, 4.3.4a and 5.4.8
+ *
+ * Copyright (C) 2005-2022 MaNGOS <https://getmangos.eu>
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * World of Warcraft, and all World of Warcraft or Warcraft art, images,
+ * and lore are copyrighted by Blizzard Entertainment, Inc.
+ */
+
+#ifndef MANGOSSERVER_ERRORS_H
+#define MANGOSSERVER_ERRORS_H
+
+#include "Common/Common.h"
+
+
+#ifdef HAVE_ACE_STACK_TRACE_H
+#  include <ace/Stack_Trace.h>
+#endif
+
+#ifdef HAVE_ACE_STACK_TRACE_H
+// Normal assert.
+#define WPError(CONDITION) \
+    if (!(CONDITION)) \
+    { \
+        ACE_Stack_Trace st; \
+        printf("%s:%i: Error: Assertion in %s failed: %s\nStack Trace:\n%s", \
+               __FILE__, __LINE__, __FUNCTION__, STRINGIZE(CONDITION), st.c_str()); \
+        assert(STRINGIZE(CONDITION) && 0); \
+    }
+
+// Just warn.
+#define WPWarning(CONDITION) \
+    if (!(CONDITION)) \
+    { \
+        ACE_Stack_Trace st; \
+        printf("%s:%i: Warning: Assertion in %s failed: %s\nStack Trace:\n%s",\
+               __FILE__, __LINE__, __FUNCTION__, STRINGIZE(CONDITION), st.c_str()); \
+    }
+#else
+// Normal assert.
+#define WPError(CONDITION) \
+    if (!(CONDITION)) \
+    { \
+        printf("%s:%i: Error: Assertion in %s failed: %s", \
+               __FILE__, __LINE__, __FUNCTION__, STRINGIZE(CONDITION)); \
+        assert(STRINGIZE(CONDITION) && 0); \
+    }
+
+// Just warn.
+#define WPWarning(CONDITION) \
+    if (!(CONDITION)) \
+    { \
+        printf("%s:%i: Warning: Assertion in %s failed: %s",\
+               __FILE__, __LINE__, __FUNCTION__, STRINGIZE(CONDITION)); \
+    }
+#endif
+
+#define MANGOS_ASSERT WPError                             // Error even if in release mode.
+
+#endif
diff --git a/shared/Utilities/EventProcessor.cpp b/shared/Utilities/EventProcessor.cpp
new file mode 100644
index 0000000..10068eb
--- /dev/null
+++ b/shared/Utilities/EventProcessor.cpp
@@ -0,0 +1,112 @@
+/**
+ * MaNGOS is a full featured server for World of Warcraft, supporting
+ * the following clients: 1.12.x, 2.4.3, 3.3.5a, 4.3.4a and 5.4.8
+ *
+ * Copyright (C) 2005-2022 MaNGOS <https://getmangos.eu>
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * World of Warcraft, and all World of Warcraft or Warcraft art, images,
+ * and lore are copyrighted by Blizzard Entertainment, Inc.
+ */
+
+#include "EventProcessor.h"
+
+EventProcessor::EventProcessor()
+{
+    m_time = 0;
+    m_aborting = false;
+}
+
+EventProcessor::~EventProcessor()
+{
+    KillAllEvents(true);
+}
+
+void EventProcessor::Update(uint32 p_time)
+{
+    // update time
+    m_time += p_time;
+
+    // main event loop
+    EventList::iterator i;
+    while (((i = m_events.begin()) != m_events.end()) && i->first <= m_time)
+    {
+        // get and remove event from queue
+        BasicEvent* Event = i->second;
+        m_events.erase(i);
+
+        if (!Event->to_Abort)
+        {
+            if (Event->Execute(m_time, p_time))
+            {
+                // completely destroy event if it is not re-added
+                delete Event;
+            }
+        }
+        else
+        {
+            Event->Abort(m_time);
+            delete Event;
+        }
+    }
+}
+
+void EventProcessor::KillAllEvents(bool force)
+{
+    // prevent event insertions
+    m_aborting = true;
+
+    // first, abort all existing events
+    for (EventList::iterator i = m_events.begin(); i != m_events.end();)
+    {
+        EventList::iterator i_old = i;
+        ++i;
+
+        i_old->second->to_Abort = true;
+        i_old->second->Abort(m_time);
+        if (force || i_old->second->IsDeletable())
+        {
+            delete i_old->second;
+
+            if (!force)                                     // need per-element cleanup
+            {
+                m_events.erase(i_old);
+            }
+        }
+    }
+
+    // fast clear event list (in force case)
+    if (force)
+    {
+        m_events.clear();
+    }
+}
+
+void EventProcessor::AddEvent(BasicEvent* Event, uint64 e_time, bool set_addtime)
+{
+    if (set_addtime)
+    {
+        Event->m_addTime = m_time;
+    }
+
+    Event->m_execTime = e_time;
+    m_events.insert(std::pair<uint64, BasicEvent*>(e_time, Event));
+}
+
+uint64 EventProcessor::CalculateTime(uint64 t_offset)
+{
+    return m_time + t_offset;
+}
diff --git a/shared/Utilities/EventProcessor.h b/shared/Utilities/EventProcessor.h
new file mode 100644
index 0000000..66f33fe
--- /dev/null
+++ b/shared/Utilities/EventProcessor.h
@@ -0,0 +1,148 @@
+/**
+ * MaNGOS is a full featured server for World of Warcraft, supporting
+ * the following clients: 1.12.x, 2.4.3, 3.3.5a, 4.3.4a and 5.4.8
+ *
+ * Copyright (C) 2005-2022 MaNGOS <https://getmangos.eu>
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * World of Warcraft, and all World of Warcraft or Warcraft art, images,
+ * and lore are copyrighted by Blizzard Entertainment, Inc.
+ */
+
+#ifndef MANGOS_H_EVENTPROCESSOR
+#define MANGOS_H_EVENTPROCESSOR
+
+#include "Platform/Define.h"
+
+#include <map>
+
+/**
+ * @brief Note. All times are in milliseconds here.
+ *
+ */
+class BasicEvent
+{
+    public:
+
+        /**
+         * @brief
+         *
+         */
+        BasicEvent()
+            : to_Abort(false)
+        {
+        }
+
+        /**
+         * @brief override destructor to perform some actions on event removal
+         *
+         */
+        virtual ~BasicEvent()
+        {
+        };
+
+
+        /**
+         * @brief this method executes when the event is triggered
+         *
+         * @param uint64 e_time is execution time
+         * @param uint32 p_time is update interval
+         * @return bool return false if event does not want to be deleted
+         */
+        virtual bool Execute(uint64 /*e_time*/, uint32 /*p_time*/) { return true; }
+
+        /**
+         * @brief this event can be safely deleted
+         *
+         * @return bool
+         */
+        virtual bool IsDeletable() const { return true; }
+
+        /**
+         * @brief this method executes when the event is aborted
+         *
+         * @param uint64
+         */
+        virtual void Abort(uint64 /*e_time*/) {}
+
+        bool to_Abort;                                      /**< set by externals when the event is aborted, aborted events don't execute and get Abort call when deleted */
+
+        // these can be used for time offset control
+        uint64 m_addTime;                                   /**< time when the event was added to queue, filled by event handler */
+        uint64 m_execTime;                                  /**< planned time of next execution, filled by event handler */
+};
+
+/**
+ * @brief
+ *
+ */
+typedef std::multimap<uint64, BasicEvent*> EventList;
+
+/**
+ * @brief
+ *
+ */
+class EventProcessor
+{
+    public:
+
+        /**
+         * @brief
+         *
+         */
+        EventProcessor();
+        /**
+         * @brief
+         *
+         */
+        ~EventProcessor();
+
+        /**
+         * @brief
+         *
+         * @param p_time
+         */
+        void Update(uint32 p_time);
+        /**
+         * @brief
+         *
+         * @param force
+         */
+        void KillAllEvents(bool force);
+        /**
+         * @brief
+         *
+         * @param Event
+         * @param e_time
+         * @param set_addtime
+         */
+        void AddEvent(BasicEvent* Event, uint64 e_time, bool set_addtime = true);
+        /**
+         * @brief
+         *
+         * @param t_offset
+         * @return uint64
+         */
+        uint64 CalculateTime(uint64 t_offset);
+
+    protected:
+
+        uint64 m_time; /**< TODO */
+        EventList m_events; /**< TODO */
+        bool m_aborting; /**< TODO */
+};
+
+#endif
diff --git a/shared/Utilities/LinkedList.h b/shared/Utilities/LinkedList.h
new file mode 100644
index 0000000..19b1c95
--- /dev/null
+++ b/shared/Utilities/LinkedList.h
@@ -0,0 +1,554 @@
+/**
+ * MaNGOS is a full featured server for World of Warcraft, supporting
+ * the following clients: 1.12.x, 2.4.3, 3.3.5a, 4.3.4a and 5.4.8
+ *
+ * Copyright (C) 2005-2022 MaNGOS <https://getmangos.eu>
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * World of Warcraft, and all World of Warcraft or Warcraft art, images,
+ * and lore are copyrighted by Blizzard Entertainment, Inc.
+ */
+
+#ifndef _LINKEDLIST
+#define _LINKEDLIST
+
+#include "Common.h"
+
+//============================================
+class LinkedListHead;
+
+/**
+ * @brief
+ *
+ */
+class LinkedListElement
+{
+    private:
+
+        friend class LinkedListHead;
+
+        LinkedListElement* iNext; /**< TODO */
+        LinkedListElement* iPrev; /**< TODO */
+
+    public:
+
+        /**
+         * @brief
+         *
+         */
+        LinkedListElement()  { iNext = NULL; iPrev = NULL; }
+        /**
+         * @brief
+         *
+         */
+        ~LinkedListElement() { delink(); }
+
+        /**
+         * @brief
+         *
+         * @return bool
+         */
+        bool hasNext() const  { return (iNext->iNext != NULL); }
+        /**
+         * @brief
+         *
+         * @return bool
+         */
+        bool hasPrev() const  { return (iPrev->iPrev != NULL); }
+        /**
+         * @brief
+         *
+         * @return bool
+         */
+        bool isInList() const { return (iNext != NULL && iPrev != NULL); }
+
+        /**
+         * @brief
+         *
+         * @return LinkedListElement
+         */
+        LinkedListElement*       next()       { return hasNext() ? iNext : NULL; }
+        /**
+         * @brief
+         *
+         * @return const LinkedListElement
+         */
+        LinkedListElement const* next() const { return hasNext() ? iNext : NULL; }
+        /**
+         * @brief
+         *
+         * @return LinkedListElement
+         */
+        LinkedListElement*       prev()       { return hasPrev() ? iPrev : NULL; }
+        /**
+         * @brief
+         *
+         * @return const LinkedListElement
+         */
+        LinkedListElement const* prev() const { return hasPrev() ? iPrev : NULL; }
+
+        /**
+         * @brief
+         *
+         * @return LinkedListElement
+         */
+        LinkedListElement*       nocheck_next()       { return iNext; }
+        /**
+         * @brief
+         *
+         * @return const LinkedListElement
+         */
+        LinkedListElement const* nocheck_next() const { return iNext; }
+        /**
+         * @brief
+         *
+         * @return LinkedListElement
+         */
+        LinkedListElement*       nocheck_prev()       { return iPrev; }
+        /**
+         * @brief
+         *
+         * @return const LinkedListElement
+         */
+        LinkedListElement const* nocheck_prev() const { return iPrev; }
+
+        /**
+         * @brief
+         *
+         */
+        void delink()
+        {
+            if (isInList())
+            {
+                iNext->iPrev = iPrev;
+                iPrev->iNext = iNext;
+                iNext = NULL;
+                iPrev = NULL;
+            }
+        }
+
+        /**
+         * @brief
+         *
+         * @param pElem
+         */
+        void insertBefore(LinkedListElement* pElem)
+        {
+            pElem->iNext = this;
+            pElem->iPrev = iPrev;
+            iPrev->iNext = pElem;
+            iPrev = pElem;
+        }
+
+        /**
+         * @brief
+         *
+         * @param pElem
+         */
+        void insertAfter(LinkedListElement* pElem)
+        {
+            pElem->iPrev = this;
+            pElem->iNext = iNext;
+            iNext->iPrev = pElem;
+            iNext = pElem;
+        }
+};
+
+//============================================
+
+/**
+ * @brief
+ *
+ */
+class LinkedListHead
+{
+    private:
+
+        LinkedListElement iFirst; /**< TODO */
+        LinkedListElement iLast; /**< TODO */
+        uint32 iSize; /**< TODO */
+
+    public:
+
+        /**
+         * @brief
+         *
+         */
+        LinkedListHead()
+        {
+            // create empty list
+
+            iFirst.iNext = &iLast;
+            iLast.iPrev = &iFirst;
+            iSize = 0;
+        }
+
+        /**
+         * @brief
+         *
+         * @return bool
+         */
+        bool isEmpty() const { return (!iFirst.iNext->isInList()); }
+
+        /**
+         * @brief
+         *
+         * @return LinkedListElement
+         */
+        LinkedListElement*       getFirst()       { return (isEmpty() ? NULL : iFirst.iNext); }
+        /**
+         * @brief
+         *
+         * @return const LinkedListElement
+         */
+        LinkedListElement const* getFirst() const { return (isEmpty() ? NULL : iFirst.iNext); }
+
+        /**
+         * @brief
+         *
+         * @return LinkedListElement
+         */
+        LinkedListElement*       getLast()        { return (isEmpty() ? NULL : iLast.iPrev); }
+        /**
+         * @brief
+         *
+         * @return const LinkedListElement
+         */
+        LinkedListElement const* getLast() const  { return (isEmpty() ? NULL : iLast.iPrev); }
+
+        /**
+         * @brief
+         *
+         * @param pElem
+         */
+        void insertFirst(LinkedListElement* pElem)
+        {
+            iFirst.insertAfter(pElem);
+        }
+
+        /**
+         * @brief
+         *
+         * @param pElem
+         */
+        void insertLast(LinkedListElement* pElem)
+        {
+            iLast.insertBefore(pElem);
+        }
+
+        /**
+         * @brief
+         *
+         * @return uint32
+         */
+        uint32 getSize() const
+        {
+            if (!iSize)
+            {
+                uint32 result = 0;
+                LinkedListElement const* e = getFirst();
+
+                while (e)
+                {
+                    ++result;
+                    e = e->next();
+                }
+
+                return result;
+            }
+            else
+            {
+                return iSize;
+            }
+        }
+
+        /**
+         * @brief
+         *
+         */
+        void incSize() { ++iSize; }
+        /**
+         * @brief
+         *
+         */
+        void decSize() { --iSize; }
+
+        template<class _Ty>
+        /**
+         * @brief
+         *
+         */
+        class Iterator
+        {
+            public:
+
+                /**
+                 * @brief
+                 *
+                 */
+                typedef std::bidirectional_iterator_tag iterator_category;
+                /**
+                 * @brief
+                 *
+                 */
+                typedef _Ty value_type;
+                /**
+                 * @brief
+                 *
+                 */
+                typedef ptrdiff_t difference_type;
+                /**
+                 * @brief
+                 *
+                 */
+                typedef ptrdiff_t distance_type;
+                /**
+                 * @brief
+                 *
+                 */
+                typedef _Ty* pointer;
+                /**
+                 * @brief
+                 *
+                 */
+                typedef _Ty const* const_pointer;
+                /**
+                 * @brief
+                 *
+                 */
+                typedef _Ty& reference;
+                /**
+                 * @brief
+                 *
+                 */
+                typedef _Ty const& const_reference;
+
+                /**
+                 * @brief
+                 *
+                 */
+                Iterator()
+                    : _Ptr(0)
+                {
+                    // construct with null node pointer
+                }
+
+                /**
+                 * @brief
+                 *
+                 * @param _Pnode
+                 */
+                Iterator(pointer _Pnode)
+                    : _Ptr(_Pnode)
+                {
+                    // construct with node pointer _Pnode
+                }
+
+                /**
+                 * @brief
+                 *
+                 * @param _Right
+                 * @return Iterator &operator
+                 */
+                Iterator& operator=(Iterator const& _Right)
+                {
+                    return (*this) = _Right._Ptr;
+                }
+
+                /**
+                 * @brief
+                 *
+                 * @param _Right
+                 * @return Iterator &operator
+                 */
+                Iterator& operator=(const_pointer const& _Right)
+                {
+                    _Ptr = (pointer)_Right;
+                    return (*this);
+                }
+
+                /**
+                 * @brief
+                 *
+                 * @return reference operator
+                 */
+                reference operator*()
+                {
+                    // return designated value
+                    return *_Ptr;
+                }
+
+                /**
+                 * @brief
+                 *
+                 * @return pointer operator ->
+                 */
+                pointer operator->()
+                {
+                    // return pointer to class object
+                    return _Ptr;
+                }
+
+                /**
+                 * @brief
+                 *
+                 * @return Iterator &operator
+                 */
+                Iterator& operator++()
+                {
+                    // preincrement
+                    _Ptr = _Ptr->next();
+                    return (*this);
+                }
+
+                /**
+                 * @brief
+                 *
+                 * @param int
+                 * @return Iterator operator
+                 */
+                Iterator operator++(int)
+                {
+                    // postincrement
+                    iterator _Tmp = *this;
+                    ++*this;
+                    return (_Tmp);
+                }
+
+                /**
+                 * @brief
+                 *
+                 * @return Iterator &operator
+                 */
+                Iterator& operator--()
+                {
+                    // predecrement
+                    _Ptr = _Ptr->prev();
+                    return (*this);
+                }
+
+                /**
+                 * @brief
+                 *
+                 * @param int
+                 * @return Iterator operator
+                 */
+                Iterator operator--(int)
+                {
+                    // postdecrement
+                    iterator _Tmp = *this;
+                    --*this;
+                    return (_Tmp);
+                }
+
+                /**
+                 * @brief
+                 *
+                 * @param _Right
+                 * @return bool operator
+                 */
+                bool operator==(Iterator const& _Right) const
+                {
+                    // test for iterator equality
+                    return (_Ptr == _Right._Ptr);
+                }
+
+                /**
+                 * @brief
+                 *
+                 * @param _Right
+                 * @return bool operator
+                 */
+                bool operator!=(Iterator const& _Right) const
+                {
+                    // test for iterator inequality
+                    return (!(*this == _Right));
+                }
+
+                /**
+                 * @brief
+                 *
+                 * @param _Right
+                 * @return bool operator
+                 */
+                bool operator==(pointer const& _Right) const
+                {
+                    // test for pointer equality
+                    return (_Ptr != _Right);
+                }
+
+                /**
+                 * @brief
+                 *
+                 * @param _Right
+                 * @return bool operator
+                 */
+                bool operator!=(pointer const& _Right) const
+                {
+                    // test for pointer equality
+                    return (!(*this == _Right));
+                }
+
+                /**
+                 * @brief
+                 *
+                 * @param _Right
+                 * @return bool operator
+                 */
+                bool operator==(const_reference _Right) const
+                {
+                    // test for reference equality
+                    return (_Ptr == &_Right);
+                }
+
+                /**
+                 * @brief
+                 *
+                 * @param _Right
+                 * @return bool operator
+                 */
+                bool operator!=(const_reference _Right) const
+                {
+                    // test for reference equality
+                    return (_Ptr != &_Right);
+                }
+
+                /**
+                 * @brief
+                 *
+                 * @return pointer
+                 */
+                pointer _Mynode()
+                {
+                    // return node pointer
+                    return (_Ptr);
+                }
+
+            protected:
+
+                pointer _Ptr;                               /**< pointer to node */
+        };
+
+        /**
+         * @brief
+         *
+         */
+        typedef Iterator<LinkedListElement> iterator;
+};
+
+//============================================
+
+#endif
diff --git a/shared/Utilities/LinkedReference/RefManager.h b/shared/Utilities/LinkedReference/RefManager.h
new file mode 100644
index 0000000..e03d770
--- /dev/null
+++ b/shared/Utilities/LinkedReference/RefManager.h
@@ -0,0 +1,125 @@
+/**
+ * MaNGOS is a full featured server for World of Warcraft, supporting
+ * the following clients: 1.12.x, 2.4.3, 3.3.5a, 4.3.4a and 5.4.8
+ *
+ * Copyright (C) 2005-2022 MaNGOS <https://getmangos.eu>
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * World of Warcraft, and all World of Warcraft or Warcraft art, images,
+ * and lore are copyrighted by Blizzard Entertainment, Inc.
+ */
+
+#ifndef MANGOS_H_REFMANAGER
+#define MANGOS_H_REFMANAGER
+
+//=====================================================
+
+#include "Utilities/LinkedList.h"
+#include "Utilities/LinkedReference/Reference.h"
+
+template <class TO, class FROM>
+/**
+ * @brief
+ *
+ */
+class RefManager : public LinkedListHead
+{
+    public:
+
+        /**
+         * @brief
+         *
+         */
+        typedef LinkedListHead::Iterator<Reference<TO, FROM> > iterator;
+        /**
+         * @brief
+         *
+         */
+        RefManager() {}
+        /**
+         * @brief
+         *
+         */
+        virtual ~RefManager() { clearReferences(); }
+
+        /**
+         * @brief
+         *
+         * @return Reference<TO, FROM>
+         */
+        Reference<TO, FROM>*       getFirst()       { return ((Reference<TO, FROM>*) LinkedListHead::getFirst()); }
+        /**
+         * @brief
+         *
+         * @return const Reference<TO, FROM>
+         */
+        Reference<TO, FROM> const* getFirst() const { return ((Reference<TO, FROM> const*) LinkedListHead::getFirst()); }
+        /**
+         * @brief
+         *
+         * @return Reference<TO, FROM>
+         */
+        Reference<TO, FROM>*       getLast()       { return ((Reference<TO, FROM>*) LinkedListHead::getLast()); }
+        /**
+         * @brief
+         *
+         * @return const Reference<TO, FROM>
+         */
+        Reference<TO, FROM> const* getLast() const { return ((Reference<TO, FROM> const*) LinkedListHead::getLast()); }
+
+        /**
+         * @brief
+         *
+         * @return iterator
+         */
+        iterator begin() { return iterator(getFirst()); }
+        /**
+         * @brief
+         *
+         * @return iterator
+         */
+        iterator end() { return iterator(NULL); }
+        /**
+         * @brief
+         *
+         * @return iterator
+         */
+        iterator rbegin() { return iterator(getLast()); }
+        /**
+         * @brief
+         *
+         * @return iterator
+         */
+        iterator rend() { return iterator(NULL); }
+
+        /**
+         * @brief
+         *
+         */
+        void clearReferences()
+        {
+            LinkedListElement* ref;
+            while ((ref = getFirst()) != NULL)
+            {
+                ((Reference<TO, FROM>*) ref)->invalidate();
+                ref->delink();                              // the delink might be already done by invalidate(), but doing it here again does not hurt and insures an empty list
+            }
+        }
+};
+
+//=====================================================
+
+#endif
diff --git a/shared/Utilities/LinkedReference/Reference.h b/shared/Utilities/LinkedReference/Reference.h
new file mode 100644
index 0000000..41244d6
--- /dev/null
+++ b/shared/Utilities/LinkedReference/Reference.h
@@ -0,0 +1,215 @@
+/**
+ * MaNGOS is a full featured server for World of Warcraft, supporting
+ * the following clients: 1.12.x, 2.4.3, 3.3.5a, 4.3.4a and 5.4.8
+ *
+ * Copyright (C) 2005-2022 MaNGOS <https://getmangos.eu>
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * World of Warcraft, and all World of Warcraft or Warcraft art, images,
+ * and lore are copyrighted by Blizzard Entertainment, Inc.
+ */
+
+#ifndef MANGOS_H_REFERENCE
+#define MANGOS_H_REFERENCE
+
+#include "Utilities/LinkedList.h"
+
+//=====================================================
+
+template<class TO, class FROM>
+/**
+ * @brief
+ *
+ */
+class Reference : public LinkedListElement
+{
+    private:
+
+        TO* iRefTo; /**< TODO */
+        FROM* iRefFrom; /**< TODO */
+
+    protected:
+
+        /**
+         * @brief Tell our refTo (target) object that we have a link
+         *
+         */
+        virtual void targetObjectBuildLink() = 0;
+
+        /**
+         * @brief Tell our refTo (taget) object, that the link is cut
+         *
+         */
+        virtual void targetObjectDestroyLink() = 0;
+
+        /**
+         * @brief Tell our refFrom (source) object, that the link is cut (Target destroyed)
+         *
+         */
+        virtual void sourceObjectDestroyLink() = 0;
+
+    public:
+
+        /**
+         * @brief
+         *
+         */
+        Reference()
+            : iRefTo(NULL), iRefFrom(NULL)
+        {
+        }
+
+        /**
+         * @brief
+         *
+         */
+        virtual ~Reference() {}
+
+        /**
+         * @brief Create new link
+         *
+         * @param toObj
+         * @param fromObj
+         */
+        void link(TO* toObj, FROM* fromObj)
+        {
+            assert(fromObj);                                // fromObj MUST not be NULL
+            if (isValid())
+            {
+                unlink();
+            }
+
+            if (toObj != NULL)
+            {
+                iRefTo = toObj;
+                iRefFrom = fromObj;
+                targetObjectBuildLink();
+            }
+        }
+
+        /**
+         * @brief We don't need the reference anymore.
+         *
+         * Call comes from the refFrom object. Tell our refTo object, that the
+         * link is cut.
+         *
+         */
+        void unlink()
+        {
+            targetObjectDestroyLink();
+            delink();
+            iRefTo = NULL;
+            iRefFrom = NULL;
+        }
+
+        /**
+         * @brief Link is invalid due to destruction of referenced target object.
+         *
+         * Call comes from the refTo object. Tell our refFrom object, that the
+         * link is cut.
+         *
+         */
+        void invalidate()                                   // the iRefFrom MUST remain!!
+        {
+            sourceObjectDestroyLink();
+            delink();
+            iRefTo = NULL;
+        }
+
+        /**
+         * @brief
+         *
+         * @return bool
+         */
+        bool isValid() const                                // Only check the iRefTo
+        {
+            return iRefTo != NULL;
+        }
+
+        /**
+         * @brief
+         *
+         * @return Reference<TO, FROM>
+         */
+        Reference<TO, FROM>*       next()       { return((Reference<TO, FROM>*) LinkedListElement::next()); }
+        /**
+         * @brief
+         *
+         * @return const Reference<TO, FROM>
+         */
+        Reference<TO, FROM> const* next() const { return((Reference<TO, FROM> const*) LinkedListElement::next()); }
+        /**
+         * @brief
+         *
+         * @return Reference<TO, FROM>
+         */
+        Reference<TO, FROM>*       prev()       { return((Reference<TO, FROM>*) LinkedListElement::prev()); }
+        /**
+         * @brief
+         *
+         * @return const Reference<TO, FROM>
+         */
+        Reference<TO, FROM> const* prev() const { return((Reference<TO, FROM> const*) LinkedListElement::prev()); }
+
+        /**
+         * @brief
+         *
+         * @return Reference<TO, FROM>
+         */
+        Reference<TO, FROM>*       nocheck_next()       { return((Reference<TO, FROM>*) LinkedListElement::nocheck_next()); }
+        /**
+         * @brief
+         *
+         * @return const Reference<TO, FROM>
+         */
+        Reference<TO, FROM> const* nocheck_next() const { return((Reference<TO, FROM> const*) LinkedListElement::nocheck_next()); }
+        /**
+         * @brief
+         *
+         * @return Reference<TO, FROM>
+         */
+        Reference<TO, FROM>*       nocheck_prev()       { return((Reference<TO, FROM>*) LinkedListElement::nocheck_prev()); }
+        /**
+         * @brief
+         *
+         * @return const Reference<TO, FROM>
+         */
+        Reference<TO, FROM> const* nocheck_prev() const { return((Reference<TO, FROM> const*) LinkedListElement::nocheck_prev()); }
+
+        /**
+         * @brief
+         *
+         * @return TO *operator ->
+         */
+        TO* operator->() const { return iRefTo; }
+        /**
+         * @brief
+         *
+         * @return TO
+         */
+        TO* getTarget() const { return iRefTo; }
+
+        /**
+         * @brief
+         *
+         * @return FROM
+         */
+        FROM* getSource() const { return iRefFrom; }
+};
+
+//=====================================================
+
+#endif
diff --git a/shared/Utilities/ProgressBar.cpp b/shared/Utilities/ProgressBar.cpp
new file mode 100644
index 0000000..073ab07
--- /dev/null
+++ b/shared/Utilities/ProgressBar.cpp
@@ -0,0 +1,134 @@
+/**
+ * MaNGOS is a full featured server for World of Warcraft, supporting
+ * the following clients: 1.12.x, 2.4.3, 3.3.5a, 4.3.4a and 5.4.8
+ *
+ * Copyright (C) 2005-2022 MaNGOS <https://getmangos.eu>
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * World of Warcraft, and all World of Warcraft or Warcraft art, images,
+ * and lore are copyrighted by Blizzard Entertainment, Inc.
+ */
+
+#include <stdio.h>
+
+#include "ProgressBar.h"
+#include "Errors.h"
+
+bool BarGoLink::m_showOutput = true;
+
+char const* const BarGoLink::empty = " ";
+#ifdef _WIN32
+char const* const BarGoLink::full  = "\x3D";
+#else
+char const* const BarGoLink::full  = "*";
+#endif
+
+BarGoLink::BarGoLink(int row_count)
+{
+    init(row_count);
+}
+
+BarGoLink::~BarGoLink()
+{
+    if (!m_showOutput)
+    {
+        return;
+    }
+
+    printf("\n");
+    fflush(stdout);
+}
+
+void BarGoLink::init(int row_count)
+{
+    rec_no    = 0;
+    rec_pos   = 0;
+    indic_len = 50;
+    num_rec   = row_count;
+
+    if (!m_showOutput)
+    {
+        return;
+    }
+
+#ifdef _WIN32
+    printf("\x3D");
+#else
+    printf("[");
+#endif
+
+    for (int i = 0; i < indic_len; ++i)
+    {
+        printf(empty);
+    }
+#ifdef _WIN32
+    printf("\x3D 0%%\r\x3D");
+#else
+    printf("] 0%%\r[");
+#endif
+
+    fflush(stdout);
+}
+
+void BarGoLink::step()
+{
+    if (!m_showOutput)
+    {
+        return;
+    }
+
+    int i, n;
+
+    if (num_rec == 0)
+    {
+        return;
+    }
+    ++rec_no;
+    n = rec_no * indic_len / num_rec;
+    if (n != rec_pos)
+    {
+#ifdef _WIN32
+        printf("\r\x3D");
+#else
+        printf("\r[");
+#endif
+
+        for (i = 0; i < n; ++i)
+        {
+            printf(full);
+        }
+        for (; i < indic_len; ++i)
+        {
+            printf(empty);
+        }
+        float percent = (((float)n / (float)indic_len) * 100);
+#ifdef _WIN32
+        printf("\x3D %i%%  \r\x3D", (int)percent);
+#else
+        printf("] %i%%  \r[", (int)percent);
+#endif
+
+        fflush(stdout);
+
+        rec_pos = n;
+    }
+}
+
+// avoid use inline version because linking problems with private static field
+void BarGoLink::SetOutputState(bool on)
+{
+    m_showOutput = on;
+}
diff --git a/shared/Utilities/ProgressBar.h b/shared/Utilities/ProgressBar.h
new file mode 100644
index 0000000..cbf4a18
--- /dev/null
+++ b/shared/Utilities/ProgressBar.h
@@ -0,0 +1,79 @@
+/**
+ * MaNGOS is a full featured server for World of Warcraft, supporting
+ * the following clients: 1.12.x, 2.4.3, 3.3.5a, 4.3.4a and 5.4.8
+ *
+ * Copyright (C) 2005-2022 MaNGOS <https://getmangos.eu>
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * World of Warcraft, and all World of Warcraft or Warcraft art, images,
+ * and lore are copyrighted by Blizzard Entertainment, Inc.
+ */
+
+#ifndef MANGOSSERVER_PROGRESSBAR_H
+#define MANGOSSERVER_PROGRESSBAR_H
+
+#include "Platform/Define.h"
+
+/**
+ * @brief
+ *
+ */
+class BarGoLink
+{
+    public:
+        /**
+         * @brief constructors
+         *
+         * @param row_count
+         */
+        explicit BarGoLink(int row_count);
+        /**
+         * @brief
+         *
+         */
+        ~BarGoLink();
+
+    public:
+        /**
+         * @brief modifiers
+         *
+         */
+        void step();
+
+        /**
+         * @brief
+         *
+         * @param on
+         */
+        static void SetOutputState(bool on);
+    private:
+        /**
+         * @brief
+         *
+         * @param row_count
+         */
+        void init(int row_count);
+
+        static bool m_showOutput; /**< not recommended change with existed active bar */
+        static char const* const empty; /**< TODO */
+        static char const* const full; /**< TODO */
+
+        int rec_no; /**< TODO */
+        int rec_pos; /**< TODO */
+        int num_rec; /**< TODO */
+        int indic_len; /**< TODO */
+};
+#endif
diff --git a/shared/Utilities/RNGen.h b/shared/Utilities/RNGen.h
new file mode 100644
index 0000000..b20a101
--- /dev/null
+++ b/shared/Utilities/RNGen.h
@@ -0,0 +1,79 @@
+/**
+ * MaNGOS is a full featured server for World of Warcraft, supporting
+ * the following clients: 1.12.x, 2.4.3, 3.3.5a, 4.3.4a and 5.4.8
+ *
+ * Copyright (C) 2005-2022 MaNGOS <https://getmangos.eu>
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * World of Warcraft, and all World of Warcraft or Warcraft art, images,
+ * and lore are copyrighted by Blizzard Entertainment, Inc.
+ */
+
+#ifndef MANGOS_RNG_H
+#define MANGOS_RNG_H
+
+#include <random>
+
+#include "ace/Singleton.h"
+#include "ace/Synch_Traits.h"
+#include "Platform/Define.h"
+
+class RNGen
+{
+public:
+    RNGen()
+    {
+        std::random_device rd;
+        gen_.seed(rd());
+    }
+
+    int32 rand_i(int32 min, int32 max)
+    {
+        std::uniform_int_distribution<int32> dist{min, max};
+        return dist(gen_);
+    }
+
+    uint32 rand_u(uint32 min, uint32 max)
+    {
+        std::uniform_int_distribution<uint32> dist{min, max};
+        return dist(gen_);
+    }
+
+    uint32 rand()
+    {
+        std::uniform_int_distribution<uint32> dist;
+        return dist(gen_);
+    }
+
+    float rand_f(float min, float max)
+    {
+        std::uniform_real_distribution<float> dist{min, max};
+        return dist(gen_);
+    }
+
+    double rand_d(double min, double max)
+    {
+        std::uniform_real_distribution<double> dist{min, max};
+        return dist(gen_);
+    }
+
+private:
+    std::mt19937 gen_;
+};
+
+typedef ACE_TSS_Singleton<RNGen, ACE_SYNCH_MUTEX> RNG;
+
+#endif
\ No newline at end of file
diff --git a/shared/Utilities/Timer.h b/shared/Utilities/Timer.h
new file mode 100644
index 0000000..aa3f875
--- /dev/null
+++ b/shared/Utilities/Timer.h
@@ -0,0 +1,228 @@
+/**
+ * MaNGOS is a full featured server for World of Warcraft, supporting
+ * the following clients: 1.12.x, 2.4.3, 3.3.5a, 4.3.4a and 5.4.8
+ *
+ * Copyright (C) 2005-2022 MaNGOS <https://getmangos.eu>
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * World of Warcraft, and all World of Warcraft or Warcraft art, images,
+ * and lore are copyrighted by Blizzard Entertainment, Inc.
+ */
+
+#ifndef MANGOS_TIMER_H
+#define MANGOS_TIMER_H
+
+#include "Common.h"
+#include "Duration.h"
+#include <ctime>
+
+// New Method
+inline std::chrono::steady_clock::time_point GetApplicationStartTime()
+{
+    using namespace std::chrono;
+
+    static const steady_clock::time_point ApplicationStartTime = steady_clock::now();
+
+    return ApplicationStartTime;
+}
+
+inline uint32 getMSTime()
+{
+    using namespace std::chrono;
+
+    return uint32(duration_cast<milliseconds>(steady_clock::now() - GetApplicationStartTime()).count());
+}
+
+inline uint32 getMSTimeDiff(uint32 oldMSTime, uint32 newMSTime)
+{
+    // getMSTime() have limited data range and this is case when it overflow in this tick
+    if (oldMSTime > newMSTime)
+    {
+        return (0xFFFFFFFF - oldMSTime) + newMSTime;
+    }
+    else
+    {
+        return newMSTime - oldMSTime;
+    }
+}
+
+inline uint32 getMSTimeDiff(uint32 oldMSTime, std::chrono::steady_clock::time_point newTime)
+{
+    using namespace std::chrono;
+
+    uint32 newMSTime = uint32(duration_cast<milliseconds>(newTime - GetApplicationStartTime()).count());
+
+    return getMSTimeDiff(oldMSTime, newMSTime);
+}
+
+inline uint32 GetMSTimeDiffToNow(uint32 oldMSTime)
+{
+    return getMSTimeDiff(oldMSTime, getMSTime());
+}
+
+inline uint32 GetUnixTimeStamp()
+{
+    time_t nowMS = std::time(nullptr);
+
+    return nowMS;
+}
+
+struct IntervalTimer
+{
+    public:
+        /**
+         * @brief
+         *
+         */
+        IntervalTimer() : _interval(0), _current(0) {}
+
+        /**
+         * @brief
+         *
+         * @param diff
+         */
+    void Update(time_t diff)
+    {
+        _current += diff;
+        if (_current < 0)
+        {
+            _current = 0;
+        }
+    }
+        /**
+         * @brief
+         *
+         * @return bool
+         */
+    bool Passed()
+    {
+        return _current >= _interval;
+    }
+        /**
+         * @brief
+         *
+         */
+    void Reset()
+    {
+        if (_current >= _interval)
+        {
+            _current %= _interval;
+        }
+    }
+
+    void SetCurrent(time_t current)
+    {
+        _current = current;
+    }
+
+    void SetInterval(time_t interval)
+    {
+        _interval = interval;
+    }
+
+    time_t GetInterval() const
+    {
+        return _interval;
+    }
+
+    time_t GetCurrent() const
+    {
+        return _current;
+    }
+
+    private:
+        time_t _interval; /**< TODO */
+        time_t _current; /**< TODO */
+};
+
+/**
+ * @brief
+ *
+ */
+struct TimeTracker
+{
+public:
+    TimeTracker(int32 expiry = 0) : _expiryTime(expiry) { }
+    TimeTracker(Milliseconds expiry) : _expiryTime(expiry) { }
+
+    void Update(int32 diff)
+    {
+        Update(Milliseconds(diff));
+    }
+
+    void Update(Milliseconds diff)
+    {
+        _expiryTime -= diff;
+    }
+
+    bool Passed() const
+    {
+        return _expiryTime <= Seconds(0);
+    }
+
+    void Reset(int32 expiry)
+    {
+        Reset(Milliseconds(expiry));
+    }
+
+    void Reset(Milliseconds expiry)
+    {
+        _expiryTime = expiry;
+    }
+
+    Milliseconds GetExpiry() const
+    {
+        return _expiryTime;
+    }
+
+private:
+    Milliseconds _expiryTime;
+};
+
+struct PeriodicTimer
+{
+public:
+    PeriodicTimer(int32 period, int32 start_time) :
+        i_period(period), i_expireTime(start_time) { }
+
+    bool Update(const uint32 diff)
+    {
+        if ((i_expireTime -= diff) > 0)
+        {
+            return false;
+        }
+
+        i_expireTime += i_period > int32(diff) ? i_period : diff;
+        return true;
+    }
+
+    void SetPeriodic(int32 period, int32 start_time)
+    {
+        i_expireTime = start_time;
+        i_period = period;
+    }
+
+    // Tracker interface
+    void TUpdate(int32 diff) { i_expireTime -= diff; }
+    bool TPassed() const { return i_expireTime <= 0; }
+    void TReset(int32 diff, int32 period) { i_expireTime += period > diff ? period : diff; }
+
+private:
+    int32 i_period;
+    int32 i_expireTime;
+};
+
+#endif
diff --git a/shared/Utilities/TypeList.h b/shared/Utilities/TypeList.h
new file mode 100644
index 0000000..011d3c8
--- /dev/null
+++ b/shared/Utilities/TypeList.h
@@ -0,0 +1,30 @@
+/**
+ * MaNGOS is a full featured server for World of Warcraft, supporting
+ * the following clients: 1.12.x, 2.4.3, 3.3.5a, 4.3.4a and 5.4.8
+ *
+ * Copyright (C) 2005-2022 MaNGOS <https://getmangos.eu>
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * World of Warcraft, and all World of Warcraft or Warcraft art, images,
+ * and lore are copyrighted by Blizzard Entertainment, Inc.
+ */
+
+#ifndef MANGOS_TYPELIST_H
+#define MANGOS_TYPELIST_H
+
+// marked for deletion
+
+#endif
diff --git a/shared/Utilities/UnorderedMapSet.h b/shared/Utilities/UnorderedMapSet.h
new file mode 100644
index 0000000..1f9a31e
--- /dev/null
+++ b/shared/Utilities/UnorderedMapSet.h
@@ -0,0 +1,37 @@
+/**
+ * MaNGOS is a full featured server for World of Warcraft, supporting
+ * the following clients: 1.12.x, 2.4.3, 3.3.5a, 4.3.4a and 5.4.8
+ *
+ * Copyright (C) 2005-2022 MaNGOS <https://getmangos.eu>
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * World of Warcraft, and all World of Warcraft or Warcraft art, images,
+ * and lore are copyrighted by Blizzard Entertainment, Inc.
+ */
+
+#ifndef MANGOS_UNORDERED_MAP_H
+#define MANGOS_UNORDERED_MAP_H
+
+#include <unordered_map>
+#include <unordered_set>
+
+#define UNORDERED_MAP std::unordered_map
+#define UNORDERED_SET std::unordered_set
+
+#define HASH_NAMESPACE_START namespace std {
+#define HASH_NAMESPACE_END }
+
+#endif
diff --git a/shared/Utilities/Util.cpp b/shared/Utilities/Util.cpp
new file mode 100644
index 0000000..a7a101f
--- /dev/null
+++ b/shared/Utilities/Util.cpp
@@ -0,0 +1,835 @@
+/**
+ * MaNGOS is a full featured server for World of Warcraft, supporting
+ * the following clients: 1.12.x, 2.4.3, 3.3.5a, 4.3.4a and 5.4.8
+ *
+ * Copyright (C) 2005-2022 MaNGOS <https://getmangos.eu>
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * World of Warcraft, and all World of Warcraft or Warcraft art, images,
+ * and lore are copyrighted by Blizzard Entertainment, Inc.
+ */
+
+#include "Util.h"
+#include "Timer.h"
+
+#include "utf8.h"
+#include "RNGen.h"
+#include "Log/Log.h"
+
+#include <iomanip>
+
+//////////////////////////////////////////////////////////////////////////
+int32 irand(int32 min, int32 max)
+{
+    return RNG::instance()->rand_i(min,max);
+}
+
+uint32 urand(uint32 min, uint32 max)
+{
+    return RNG::instance()->rand_u(min,max);
+}
+
+float frand(float min, float max)
+{
+    return RNG::instance()->rand_f(min, max);
+}
+
+uint32 rand32()
+{
+    return RNG::instance()->rand();
+}
+
+double rand_norm(void)
+{
+    return RNG::instance()->rand_d(0.0, 1.0);
+}
+
+float rand_norm_f(void)
+{
+    return RNG::instance()->rand_f(0.0, 1.0);
+}
+
+double rand_chance(void)
+{
+    return RNG::instance()->rand_d(0.0, 100.0);
+}
+
+float rand_chance_f(void)
+{
+    return RNG::instance()->rand_f(0.0, 100.0);
+}
+
+Tokens StrSplit(const std::string& src, const std::string& sep)
+{
+    Tokens r;
+    std::string s;
+    for (std::string::const_iterator i = src.begin(); i != src.end(); ++i)
+    {
+        if (sep.find(*i) != std::string::npos)
+        {
+            if (s.length())
+            {
+                r.push_back(s);
+            }
+            s = "";
+        }
+        else
+        {
+            s += *i;
+        }
+    }
+    if (s.length())
+    {
+        r.push_back(s);
+    }
+    return r;
+}
+
+uint32 GetUInt32ValueFromArray(Tokens const& data, uint16 index)
+{
+    if (index >= data.size())
+    {
+        return 0;
+    }
+
+    return (uint32)atoi(data[index].c_str());
+}
+
+float GetFloatValueFromArray(Tokens const& data, uint16 index)
+{
+    float result;
+    uint32 temp = GetUInt32ValueFromArray(data, index);
+    memcpy(&result, &temp, sizeof(result));
+
+    return result;
+}
+
+void stripLineInvisibleChars(std::string& str)
+{
+    static std::string invChars = " \t\7\n";
+
+    size_t wpos = 0;
+
+    bool space = false;
+    for (size_t pos = 0; pos < str.size(); ++pos)
+    {
+        if (invChars.find(str[pos]) != std::string::npos)
+        {
+            if (!space)
+            {
+                str[wpos++] = ' ';
+                space = true;
+            }
+        }
+        else
+        {
+            if (wpos != pos)
+            {
+                str[wpos++] = str[pos];
+            }
+            else
+            {
+                ++wpos;
+            }
+            space = false;
+        }
+    }
+
+    if (wpos < str.size())
+    {
+        str.erase(wpos, str.size());
+    }
+}
+
+std::tm localtime_r(const time_t& time)
+{
+    std::tm tm_snapshot;
+#if (defined(WIN32) || defined(_WIN32) || defined(__WIN32__))
+    localtime_s(&tm_snapshot, &time);
+#else
+    localtime_r(&time, &tm_snapshot); // POSIX
+#endif
+    return tm_snapshot;
+}
+
+std::string secsToTimeString(time_t timeInSecs, TimeFormat timeFormat, bool hoursOnly)
+{
+    time_t secs    = timeInSecs % MINUTE;
+    time_t minutes = timeInSecs % HOUR / MINUTE;
+    time_t hours   = timeInSecs % DAY  / HOUR;
+    time_t days    = timeInSecs / DAY;
+
+    std::ostringstream ss;
+    if (days)
+    {
+        ss << days;
+        if (timeFormat == TimeFormat::Numeric)
+        {
+            ss << ":";
+        }
+        else if (timeFormat == TimeFormat::ShortText)
+        {
+            ss << "d";
+        }
+        else // if (timeFormat == TimeFormat::FullText)
+        {
+            if (days == 1)
+            {
+                ss << " Day ";
+            }
+            else
+            {
+                ss << " Days ";
+            }
+        }
+    }
+
+    if (hours || hoursOnly)
+    {
+        ss << hours;
+        if (timeFormat == TimeFormat::Numeric)
+        {
+            ss << ":";
+        }
+        else if (timeFormat == TimeFormat::ShortText)
+        {
+            ss << "h";
+        }
+        else // if (timeFormat == TimeFormat::FullText)
+        {
+            if (hours <= 1)
+            {
+                ss << " Hour ";
+            }
+            else
+            {
+                ss << " Hours ";
+            }
+        }
+    }
+
+    if (!hoursOnly)
+    {
+        ss << minutes;
+        if (timeFormat == TimeFormat::Numeric)
+        {
+            ss << ":";
+        }
+        else if (timeFormat == TimeFormat::ShortText)
+        {
+            ss << "m";
+        }
+        else // if (timeFormat == TimeFormat::FullText)
+        {
+            if (minutes == 1)
+            {
+                ss << " Minute ";
+            }
+            else
+            {
+                ss << " Minutes ";
+            }
+        }
+    }
+    else
+    {
+        if (timeFormat == TimeFormat::Numeric)
+        {
+            ss << "0:";
+        }
+    }
+
+    if (secs || (!days && !hours && !minutes))
+    {
+        ss << std::setw(2) << std::setfill('0') << secs;
+        if (timeFormat == TimeFormat::ShortText)
+        {
+            ss << "s";
+        }
+        else if (timeFormat == TimeFormat::FullText)
+        {
+            if (secs <= 1)
+            {
+                ss << " Second.";
+            }
+            else
+            {
+                ss << " Seconds.";
+            }
+        }
+    }
+    else
+    {
+        if (timeFormat == TimeFormat::Numeric)
+        {
+            ss << "00";
+        }
+    }
+
+    return ss.str();
+}
+
+uint32 TimeStringToSecs(const std::string& timestring)
+{
+    uint32 secs       = 0;
+    uint32 buffer     = 0;
+    uint32 multiplier = 0;
+
+    for (std::string::const_iterator itr = timestring.begin(); itr != timestring.end(); ++itr)
+    {
+        if (isdigit(*itr))
+        {
+            buffer *= 10;
+            buffer += (*itr) - '0';
+        }
+        else
+        {
+            switch (*itr)
+            {
+                case 'd': multiplier = DAY;     break;
+                case 'h': multiplier = HOUR;    break;
+                case 'm': multiplier = MINUTE;  break;
+                case 's': multiplier = 1;       break;
+                default : return 0;                         // bad format
+            }
+            buffer *= multiplier;
+            secs += buffer;
+            buffer = 0;
+        }
+    }
+
+    return secs;
+}
+
+std::string TimeToTimestampStr(time_t t)
+{
+    tm aTm = localtime_r(t);
+    //       YYYY   year
+    //       MM     month (2 digits 01-12)
+    //       DD     day (2 digits 01-31)
+    //       HH     hour (2 digits 00-23)
+    //       MM     minutes (2 digits 00-59)
+    //       SS     seconds (2 digits 00-59)
+    char buf[20];
+    snprintf(buf, 20, "%04d-%02d-%02d_%02d-%02d-%02d", aTm.tm_year + 1900, aTm.tm_mon + 1, aTm.tm_mday, aTm.tm_hour, aTm.tm_min, aTm.tm_sec);
+    return std::string(buf);
+}
+
+/// Check if the string is a valid ip address representation
+bool IsIPAddress(char const* ipaddress)
+{
+    if (!ipaddress)
+    {
+        return false;
+    }
+
+    // Let the big boys do it.
+    // Drawback: all valid ip address formats are recognized e.g.: 12.23,121234,0xABCD)
+    return ACE_OS::inet_addr(ipaddress) != INADDR_NONE;
+}
+
+std::string GetAddressString(ACE_INET_Addr const& addr)
+{
+    char buf[ACE_MAX_FULLY_QUALIFIED_NAME_LEN + 16];
+    addr.addr_to_string(buf, ACE_MAX_FULLY_QUALIFIED_NAME_LEN + 16);
+    return buf;
+}
+
+bool IsIPAddrInNetwork(ACE_INET_Addr const& net, ACE_INET_Addr const& addr, ACE_INET_Addr const& subnetMask)
+{
+    uint32 mask = subnetMask.get_ip_address();
+    if ((net.get_ip_address() & mask) == (addr.get_ip_address() & mask))
+    {
+        return true;
+    }
+    return false;
+}
+
+/// create PID file
+uint32 CreatePIDFile(const std::string& filename)
+{
+    FILE* pid_file = fopen(filename.c_str(), "w");
+    if (pid_file == NULL)
+    {
+        return 0;
+    }
+
+#ifdef WIN32
+    DWORD pid = GetCurrentProcessId();
+#else
+    pid_t pid = getpid();
+#endif
+
+    fprintf(pid_file, "%d", pid);
+    fclose(pid_file);
+
+    return (uint32)pid;
+}
+
+size_t utf8length(std::string& utf8str)
+{
+    try
+    {
+        return utf8::distance(utf8str.c_str(), utf8str.c_str() + utf8str.size());
+    }
+    catch (std::exception)
+    {
+        utf8str = "";
+        return 0;
+    }
+}
+
+void utf8truncate(std::string& utf8str, size_t len)
+{
+    try
+    {
+        size_t wlen = utf8::distance(utf8str.c_str(), utf8str.c_str() + utf8str.size());
+        if (wlen <= len)
+        {
+            return;
+        }
+
+        std::wstring wstr;
+        wstr.resize(wlen);
+        utf8::utf8to16(utf8str.c_str(), utf8str.c_str() + utf8str.size(), &wstr[0]);
+        wstr.resize(len);
+        char* oend = utf8::utf16to8(wstr.c_str(), wstr.c_str() + wstr.size(), &utf8str[0]);
+        utf8str.resize(oend - (&utf8str[0]));               // remove unused tail
+    }
+    catch (std::exception)
+    {
+        utf8str = "";
+    }
+}
+
+bool Utf8ToUpperOnlyLatin(std::string& utf8String)
+{
+    std::wstring wstr;
+    if (!Utf8toWStr(utf8String, wstr))
+    {
+        return false;
+    }
+
+    std::transform(wstr.begin(), wstr.end(), wstr.begin(), wcharToUpperOnlyLatin);
+
+    return WStrToUtf8(wstr, utf8String);
+}
+
+size_t utf8limit(std::string& utf8str, size_t bytes)
+{
+    if (utf8str.size() > bytes)
+    {
+        try
+        {
+            auto end = (utf8str.cbegin() + bytes);
+            auto itr = utf8::find_invalid(utf8str.cbegin(), end);
+
+            // Fix UTF8 if it was corrupted by bytes truncated
+            if (itr != end)
+                bytes = std::distance(utf8str.cbegin(), itr);
+
+            utf8str.resize(bytes);
+            utf8str.shrink_to_fit();
+
+            return bytes;
+        }
+        catch (const std::exception&)
+        {
+            utf8str = "";
+        }
+    }
+
+    return 0;
+}
+
+bool Utf8toWStr(char const* utf8str, size_t csize, wchar_t* wstr, size_t& wsize)
+{
+    try
+    {
+        size_t len = utf8::distance(utf8str, utf8str + csize);
+        if (len > wsize)
+        {
+            if (wsize > 0)
+            {
+                wstr[0] = L'\0';
+            }
+            wsize = 0;
+            return false;
+        }
+
+        wsize = len;
+        utf8::utf8to16(utf8str, utf8str + csize, wstr);
+        wstr[len] = L'\0';
+    }
+    catch (std::exception)
+    {
+        if (wsize > 0)
+        {
+            wstr[0] = L'\0';
+        }
+        wsize = 0;
+        return false;
+    }
+
+    return true;
+}
+
+bool Utf8toWStr(const std::string& utf8str, std::wstring& wstr)
+{
+    try
+    {
+        size_t len = utf8::distance(utf8str.c_str(), utf8str.c_str() + utf8str.size());
+        wstr.resize(len);
+
+        if (len)
+        {
+            utf8::utf8to16(utf8str.c_str(), utf8str.c_str() + utf8str.size(), &wstr[0]);
+        }
+    }
+    catch (std::exception)
+    {
+        wstr = L"";
+        return false;
+    }
+
+    return true;
+}
+
+bool WStrToUtf8(wchar_t* wstr, size_t size, std::string& utf8str)
+{
+    try
+    {
+        std::string utf8str2;
+        utf8str2.resize(size * 4);                          // allocate for most long case
+
+        char* oend = utf8::utf16to8(wstr, wstr + size, &utf8str2[0]);
+        utf8str2.resize(oend - (&utf8str2[0]));             // remove unused tail
+        utf8str = utf8str2;
+    }
+    catch (std::exception)
+    {
+        utf8str = "";
+        return false;
+    }
+
+    return true;
+}
+
+bool WStrToUtf8(std::wstring wstr, std::string& utf8str)
+{
+    try
+    {
+        std::string utf8str2;
+        utf8str2.resize(wstr.size() * 4);                   // allocate for most long case
+
+        char* oend = utf8::utf16to8(wstr.c_str(), wstr.c_str() + wstr.size(), &utf8str2[0]);
+        utf8str2.resize(oend - (&utf8str2[0]));             // remove unused tail
+        utf8str = utf8str2;
+    }
+    catch (std::exception)
+    {
+        utf8str = "";
+        return false;
+    }
+
+    return true;
+}
+
+typedef wchar_t const* const* wstrlist;
+
+bool utf8ToConsole(const std::string& utf8str, std::string& conStr)
+{
+#if PLATFORM == PLATFORM_WINDOWS
+    std::wstring wstr;
+    if (!Utf8toWStr(utf8str, wstr))
+    {
+        return false;
+    }
+
+    conStr.resize(wstr.size());
+    CharToOemBuffW(&wstr[0], &conStr[0], wstr.size());
+#else
+    // not implemented yet
+    conStr = utf8str;
+#endif
+
+    return true;
+}
+
+bool consoleToUtf8(const std::string& conStr, std::string& utf8str)
+{
+#if PLATFORM == PLATFORM_WINDOWS
+    std::wstring wstr;
+    wstr.resize(conStr.size());
+    OemToCharBuffW(&conStr[0], &wstr[0], conStr.size());
+
+    return WStrToUtf8(wstr, utf8str);
+#else
+    // not implemented yet
+    utf8str = conStr;
+    return true;
+#endif
+
+}
+
+bool Utf8FitTo(const std::string& str, std::wstring search)
+{
+    std::wstring temp;
+
+    if (!Utf8toWStr(str, temp))
+    {
+        return false;
+    }
+
+    // converting to lower case
+    wstrToLower(temp);
+
+    if (temp.find(search) == std::wstring::npos)
+    {
+        return false;
+    }
+
+    return true;
+}
+
+void vutf8printf(FILE* out, const char* str, va_list* ap)
+{
+#if PLATFORM == PLATFORM_WINDOWS
+    char temp_buf[32 * 1024];
+    wchar_t wtemp_buf[32 * 1024];
+
+    size_t temp_len = vsnprintf(temp_buf, 32 * 1024, str, *ap);
+
+    size_t wtemp_len = 32 * 1024 - 1;
+    Utf8toWStr(temp_buf, temp_len, wtemp_buf, wtemp_len);
+
+    CharToOemBuffW(&wtemp_buf[0], &temp_buf[0], wtemp_len + 1);
+    fprintf(out, "%s", temp_buf);
+#else
+    vfprintf(out, str, *ap);
+#endif
+
+}
+
+void hexEncodeByteArray(uint8* bytes, uint32 arrayLen, std::string& result)
+{
+    std::ostringstream ss;
+    for (uint32 i = 0; i < arrayLen; ++i)
+    {
+        for (uint8 j = 0; j < 2; ++j)
+        {
+            unsigned char nibble = 0x0F & (bytes[i] >> ((1 - j) * 4));
+            char encodedNibble;
+            if (nibble < 0x0A)
+            {
+                encodedNibble = '0' + nibble;
+            }
+            else
+            {
+                encodedNibble = 'A' + nibble - 0x0A;
+            }
+            ss << encodedNibble;
+        }
+    }
+    result = ss.str();
+}
+
+std::string ByteArrayToHexStr(uint8 const* bytes, uint32 arrayLen, bool reverse /* = false */)
+{
+    int32 init = 0;
+    int32 end = arrayLen;
+    int8 op = 1;
+
+    if (reverse)
+    {
+        init = arrayLen - 1;
+        end = -1;
+        op = -1;
+    }
+
+    std::ostringstream ss;
+    for (int32 i = init; i != end; i += op)
+    {
+        char buffer[4];
+        sprintf(buffer, "%02X", bytes[i]);
+        ss << buffer;
+    }
+
+    return ss.str();
+}
+
+void HexStrToByteArray(std::string const& str, uint8* out, bool reverse /*= false*/)
+{
+    // string must have even number of characters
+    if (str.length() & 1)
+    {
+        return;
+    }
+
+    int32 init = 0;
+    int32 end = str.length();
+    int8 op = 1;
+
+    if (reverse)
+    {
+        init = str.length() - 2;
+        end = -2;
+        op = -1;
+    }
+
+    uint32 j = 0;
+    for (int32 i = init; i != end; i += 2 * op)
+    {
+        char buffer[3] = { str[i], str[i + 1], '\0' };
+        out[j++] = strtoul(buffer, NULL, 16);
+    }
+}
+
+void utf8print(void* /*arg*/, const char* str)
+{
+#if PLATFORM == PLATFORM_WINDOWS
+    wchar_t wtemp_buf[6000];
+    size_t wtemp_len = 6000 - 1;
+    if (!Utf8toWStr(str, strlen(str), wtemp_buf, wtemp_len))
+    {
+        return;
+    }
+
+    char temp_buf[6000];
+    CharToOemBuffW(&wtemp_buf[0], &temp_buf[0], wtemp_len + 1);
+    printf("%s", temp_buf);
+#else
+    printf("%s", str);
+#endif
+
+}
+
+void utf8printf(FILE* out, const char* str, ...)
+{
+    va_list ap;
+    va_start(ap, str);
+    vutf8printf(out, str, &ap);
+    va_end(ap);
+}
+
+int return_iCoreNumber()
+{
+
+#if defined(CLASSIC)
+    return 0;
+#elif defined(TBC)
+    return 1;
+#elif defined(WOTLK)
+    return 2;
+#elif defined(CATA)
+    return 3;
+#elif defined(MOP)
+    return 4;
+#elif defined(WOD)
+    return 5;
+#elif defined(LEGION)
+    return 6;
+#else
+    return -1;
+#endif
+
+}
+
+/// Print out the core banner
+void print_banner()
+{
+    int iCoreNumber = return_iCoreNumber();
+    switch (iCoreNumber)
+    {
+    case 0: // CLASSIC
+        sLog.outString("<Ctrl-C> to stop.\n"
+            "  __  __      _  _  ___  ___  ___        ____              \n"
+            " |  \\/  |__ _| \\| |/ __|/ _ \\/ __|      /_  /___ _ _ ___   \n"
+            " | |\\/| / _` | .` | (_ | (_) \\__ \\       / // -_) '_/ _ \\ \n"
+            " |_|  |_\\__,_|_|\\_|\\___|\\___/|___/      /___\\___|_| \\___/\n"
+            " Powered By MaNGOS Core\n"
+            "__________________________________________________________\n"
+            "\n"
+            "Website/Forum/Wiki/Issue Tracker: https://www.getmangos.eu\n"
+            "__________________________________________________________\n"
+            "\n");
+        break;
+    case 1: // TBC
+        sLog.outString("<Ctrl-C> to stop.\n"
+            "  __  __      _  _  ___  ___  ___         ___             \n"
+            " |  \\/  |__ _| \\| |/ __|/ _ \\/ __|       / _ \\ ___  ___  \n"
+            " | |\\/| / _` | .` | (_ | (_) \\__ \\      | (_) |   \\/ -_) \n"
+            " |_|  |_\\__,_|_|\\_|\\___|\\___/|___/       \\___/|_||_\\___|\n"
+            " Powered By MaNGOS Core\n"
+            " __________________________________________________________\n"
+            "\n"
+            " Website/Forum/Wiki/Issue Tracker: https://www.getmangos.eu\n"
+            " __________________________________________________________\n"
+            "\n");
+        break;
+    case 2: // WOTLK
+        sLog.outString("<Ctrl-C> to stop.\n"
+            "  __  __      _  _  ___  ___  ___       _____          \n"
+            " |  \\/  |__ _| \\| |/ __|/ _ \\/ __|     |_   _|_ __ _____\n"
+            " | |\\/| / _` | .` | (_ | (_) \\__ \\       | | \\ V  V / _ \\\n"
+            " |_|  |_\\__,_|_|\\_|\\___|\\___/|___/       |_|  \\_/\\_/\\___/ \n"
+            " Powered By MaNGOS Core\n"
+            " __________________________________________________________\n"
+            "\n"
+            " Website/Forum/Wiki/Issue Tracker: https://www.getmangos.eu\n"
+            " __________________________________________________________\n"
+            "\n");
+        break;
+    case 3: // CATA
+        sLog.outString("<Ctrl-C> to stop.\n"
+            "  __  __      _  _  ___  ___  ___   _____ _         \n"
+            " |  \\/  |__ _| \\| |/ __|/ _ \\/ __| |_   _| |_  _ _ ___ ___    \n"
+            " | |\\/| / _` | .` | (_ | (_) \\__ \\   | | | ' \\| '_/ -_) -_)  \n"
+            " |_|  |_\\__,_|_|\\_|\\___|\\___/|___/   |_| |_||_|_| \\___\\___| \n"
+            " Powered By MaNGOS Core\n"
+            " __________________________________________________________\n"
+            "\n"
+            " Website/Forum/Wiki/Issue Tracker: https://www.getmangos.eu\n"
+            " __________________________________________________________\n"
+            "\n");
+        break;
+    case 4: // MOP
+        sLog.outString("<Ctrl-C> to stop.\n"
+            "  __  __      _  _  ___  ___  ___     _____             \n"
+            " |  \\/  |__ _| \\| |/ __|/ _ \\/ __|    | __|__ _  _ _ _  \n"
+            " | |\\/| / _` | .` | (_ | (_) \\__ \\    | _/ _ \\ || | '_|\n"
+            " |_|  |_\\__,_|_|\\_|\\___|\\___/|___/    |_|\\___/\\_,_|_| \n"
+            " Powered By MaNGOS Core\n"
+            " __________________________________________________________\n"
+            "\n"
+            " Website/Forum/Wiki/Issue Tracker: https://www.getmangos.eu\n"
+            " __________________________________________________________\n"
+            "\n");
+        break;
+    default:
+        sLog.outString("<Ctrl-C> to stop.\n"
+            "  __  __      _  _  ___  ___  ___                                \n"
+            " |  \\/  |__ _| \\| |/ __|/ _ \\/ __|     We have a problem !   \n"
+            " | |\\/| / _` | .` | (_ | (_) \\__ \\   Your version of MaNGOS  \n"
+            " |_|  |_\\__,_|_|\\_|\\___|\\___/|___/   could not be detected   \n"
+            " __________________________________________________________\n"
+            "\n"
+            " Website/Forum/Wiki/Issue Tracker: https://www.getmangos.eu\n"
+            " __________________________________________________________\n"
+            "\n");
+        break;
+    }
+}
diff --git a/shared/Utilities/Util.h b/shared/Utilities/Util.h
new file mode 100644
index 0000000..55886fd
--- /dev/null
+++ b/shared/Utilities/Util.h
@@ -0,0 +1,886 @@
+/**
+ * MaNGOS is a full featured server for World of Warcraft, supporting
+ * the following clients: 1.12.x, 2.4.3, 3.3.5a, 4.3.4a and 5.4.8
+ *
+ * Copyright (C) 2005-2022 MaNGOS <https://getmangos.eu>
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * World of Warcraft, and all World of Warcraft or Warcraft art, images,
+ * and lore are copyrighted by Blizzard Entertainment, Inc.
+ */
+
+#ifndef MANGOS_H_UTIL
+#define MANGOS_H_UTIL
+
+#include "Common/Common.h"
+#include <ace/INET_Addr.h>
+
+#include <string>
+#include <vector>
+#include <algorithm>
+#include <cctype>
+#include <functional>
+
+enum class TimeFormat : uint8
+{
+    FullText,       // 1 Days 2 Hours 3 Minutes 4 Seconds
+    ShortText,      // 1d 2h 3m 4s
+    Numeric         // 1:2:3:4
+};
+
+/**
+ * @brief
+ *
+ */
+typedef std::vector<std::string> Tokens;
+
+/**
+ * @brief
+ *
+ * @param src
+ * @param sep
+ * @return Tokens
+ */
+Tokens StrSplit(const std::string& src, const std::string& sep);
+/**
+ * @brief
+ *
+ * @param data
+ * @param index
+ * @return uint32
+ */
+uint32 GetUInt32ValueFromArray(Tokens const& data, uint16 index);
+/**
+ * @brief
+ *
+ * @param data
+ * @param index
+ * @return float
+ */
+float GetFloatValueFromArray(Tokens const& data, uint16 index);
+
+/**
+ * @brief
+ *
+ * @param src
+ */
+void stripLineInvisibleChars(std::string& src);
+
+/**
+ * @brief
+ *
+ * @param localtime
+ */
+std::tm localtime_r(const time_t& time);
+
+/**
+ * @brief
+ *
+ * @param timeInSecs
+ * @param shortText
+ * @param hoursOnly
+ * @return std::string
+ */
+std::string secsToTimeString(time_t timeInSecs, TimeFormat timeFormat = TimeFormat::FullText, bool hoursOnly = false);
+/**
+ * @brief
+ *
+ * @param timestring
+ * @return uint32
+ */
+uint32 TimeStringToSecs(const std::string& timestring);
+/**
+ * @brief
+ *
+ * @param t
+ * @return std::string
+ */
+std::string TimeToTimestampStr(time_t t);
+
+/**
+ * @brief
+ *
+ * @param secs
+ * @return uint32
+ */
+inline uint32 secsToTimeBitFields(time_t secs)
+{
+    tm* lt = localtime(&secs);
+    return (lt->tm_year - 100) << 24 | lt->tm_mon  << 20 | (lt->tm_mday - 1) << 14 | lt->tm_wday << 11 | lt->tm_hour << 6 | lt->tm_min;
+}
+
+
+inline std::string& ltrim(std::string& s) {
+    s.erase(s.begin(), std::find_if(s.begin(), s.end(), [](unsigned char ch) {
+        return !std::isspace(ch);
+        }));
+    return s;
+}
+
+inline std::string& rtrim(std::string& s) {
+    s.erase(std::find_if(s.rbegin(), s.rend(), std::not1(std::ptr_fun<int, int>(std::isspace))).base(), s.end());
+    return s;
+}
+
+inline std::string& trim(std::string& s) {
+    return ltrim(rtrim(s));
+}
+
+/**
+ * @brief Return a random number in the range min..max; (max-min) must be smaller than 32768.
+ *
+ * @param min
+ * @param max
+ * @return int32
+ */
+ int32 irand(int32 min, int32 max);
+
+/**
+ * @brief Return a random number in the range min..max (inclusive).
+ *
+ * For reliable results, the difference between max and min should be less than
+ * RAND32_MAX.
+ *
+ * @param min
+ * @param max
+ * @return uint32
+ */
+ uint32 urand(uint32 min, uint32 max);
+
+/**
+ * @brief Return a random number in the range min..max (inclusive).
+ *
+ * @param min
+ * @param max
+ * @return float
+ */
+ float frand(float min, float max);
+
+/**
+ * @brief Return a random number in the range 0 .. RAND32_MAX.
+ *
+ * @return int32
+ */
+uint32 rand32();
+
+/**
+ * @brief Return a random double from 0.0 to 1.0 (exclusive).
+ *
+ * Floats support only 7 valid decimal digits. A double supports up to 15 valid
+ * decimaldigits and is used internally (RAND32_MAX has 10 digits). With an FPU
+ * there is usually no difference in performance between float and double.
+ *
+ * @return double
+ */
+ double rand_norm(void);
+
+/**
+ * @brief
+ *
+ * @return float
+ */
+ float rand_norm_f(void);
+
+/**
+ * @brief Return a random double from 0.0 to 99.9999999999999.
+ *
+ * Floats support only 7 valid decimal digits. A double supports up to 15 valid
+ * decimal digits and is used internaly (RAND32_MAX has 10 digits). With an FPU
+ * there is usually no difference in performance between float and double.
+ *
+ * @return double
+ */
+ double rand_chance(void);
+
+/**
+ * @brief
+ *
+ * @return float
+ */
+ float rand_chance_f(void);
+
+/**
+ * @brief Return true if a random roll gets above the given chance
+ *
+ * ie: if the given value is 0 the chance to succeed is also 0 which gives false
+ * as the return value at all cases. On the other hand, giving 100 as the chance
+ * will make sure that we always succeed
+ *
+ * @param chance How big the chance to succeed is. Value between 0.0f-100.0f
+ * @return bool Return true if a random roll fits in the specified chance (range 0-100).
+ */
+inline bool roll_chance_f(float chance)
+{
+    return chance > rand_chance();
+}
+
+/**
+ * @brief Return true if a random roll fits in the specified chance (range 0-100).
+ *
+ * @param chance
+ * @return bool
+ */
+inline bool roll_chance_i(int chance)
+{
+    return chance > irand(0, 99);
+}
+
+/**
+ * @brief
+ *
+ * @param var
+ * @param val
+ * @param apply
+ */
+inline void ApplyModUInt32Var(uint32& var, int32 val, bool apply)
+{
+    int32 cur = var;
+    cur += (apply ? val : -val);
+    if (cur < 0)
+    {
+        cur = 0;
+    }
+    var = cur;
+}
+
+/**
+ * @brief
+ *
+ * @param var
+ * @param val
+ * @param apply
+ */
+inline void ApplyModFloatVar(float& var, float  val, bool apply)
+{
+    var += (apply ? val : -val);
+    if (var < 0)
+    {
+        var = 0;
+    }
+}
+
+/**
+ * @brief
+ *
+ * @param var
+ * @param val
+ * @param apply
+ */
+inline void ApplyPercentModFloatVar(float& var, float val, bool apply)
+{
+    if (val == -100.0f)     // prevent set var to zero
+    {
+        val = -99.99f;
+    }
+    var *= (apply ? (100.0f + val) / 100.0f : 100.0f / (100.0f + val));
+}
+
+/**
+ * @brief
+ *
+ * @param utf8String
+ * @return bool
+ */
+bool Utf8ToUpperOnlyLatin(std::string& utf8String);
+
+/**
+ * @brief
+ *
+ * @param utf8str
+ * @param wstr
+ * @return bool
+ */
+bool Utf8toWStr(const std::string& utf8str, std::wstring& wstr);
+/**
+ * @brief
+ *
+ * @param utf8str
+ * @param csize
+ * @param wstr
+ * @param wsize
+ * @return bool
+ */
+bool Utf8toWStr(char const* utf8str, size_t csize, wchar_t* wstr, size_t& wsize);
+/**
+ * @brief
+ *
+ * @param utf8str
+ * @param wstr
+ * @param wsize
+ * @return bool
+ */
+inline bool Utf8toWStr(const std::string& utf8str, wchar_t* wstr, size_t& wsize)
+{
+    return Utf8toWStr(utf8str.c_str(), utf8str.size(), wstr, wsize);
+}
+
+/**
+ * @brief
+ *
+ * @param wstr
+ * @param utf8str
+ * @return bool
+ */
+bool WStrToUtf8(std::wstring wstr, std::string& utf8str);
+/**
+ * @brief
+ *
+ * @param wstr
+ * @param size
+ * @param utf8str
+ * @return bool
+ */
+bool WStrToUtf8(wchar_t* wstr, size_t size, std::string& utf8str);
+
+/**
+ * @brief
+ *
+ * @param utf8str
+ * @return size_t
+ */
+size_t utf8length(std::string& utf8str);                    // set string to "" if invalid utf8 sequence
+/**
+ * @brief
+ *
+ * @param utf8str
+ * @param len
+ */
+void utf8truncate(std::string& utf8str, size_t len);
+
+/**
+ * @brief
+ *
+ * @param utf8str
+ * @param bytes
+ */
+size_t utf8limit(std::string& utf8str, size_t bytes);
+
+/**
+ * @brief
+ *
+ * @param wchar
+ * @return bool
+ */
+inline bool isBasicLatinCharacter(wchar_t wchar)
+{
+    if (wchar >= L'a' && wchar <= L'z')                     // LATIN SMALL LETTER A - LATIN SMALL LETTER Z
+    {
+        return true;
+    }
+    if (wchar >= L'A' && wchar <= L'Z')                     // LATIN CAPITAL LETTER A - LATIN CAPITAL LETTER Z
+    {
+        return true;
+    }
+    return false;
+}
+
+/**
+ * @brief
+ *
+ * @param wchar
+ * @return bool
+ */
+inline bool isExtendedLatinCharacter(wchar_t wchar)
+{
+    if (isBasicLatinCharacter(wchar))
+    {
+        return true;
+    }
+    if (wchar >= 0x00C0 && wchar <= 0x00D6)                 // LATIN CAPITAL LETTER A WITH GRAVE - LATIN CAPITAL LETTER O WITH DIAERESIS
+    {
+        return true;
+    }
+    if (wchar >= 0x00D8 && wchar <= 0x00DF)                 // LATIN CAPITAL LETTER O WITH STROKE - LATIN CAPITAL LETTER THORN
+    {
+        return true;
+    }
+    if (wchar == 0x00DF)                                    // LATIN SMALL LETTER SHARP S
+    {
+        return true;
+    }
+    if (wchar >= 0x00E0 && wchar <= 0x00F6)                 // LATIN SMALL LETTER A WITH GRAVE - LATIN SMALL LETTER O WITH DIAERESIS
+    {
+        return true;
+    }
+    if (wchar >= 0x00F8 && wchar <= 0x00FE)                 // LATIN SMALL LETTER O WITH STROKE - LATIN SMALL LETTER THORN
+    {
+        return true;
+    }
+    if (wchar >= 0x0100 && wchar <= 0x012F)                 // LATIN CAPITAL LETTER A WITH MACRON - LATIN SMALL LETTER I WITH OGONEK
+    {
+        return true;
+    }
+    if (wchar == 0x1E9E)                                    // LATIN CAPITAL LETTER SHARP S
+    {
+        return true;
+    }
+    return false;
+}
+
+/**
+ * @brief
+ *
+ * @param wchar
+ * @return bool
+ */
+inline bool isCyrillicCharacter(wchar_t wchar)
+{
+    if (wchar >= 0x0410 && wchar <= 0x044F)                 // CYRILLIC CAPITAL LETTER A - CYRILLIC SMALL LETTER YA
+    {
+        return true;
+    }
+    if (wchar == 0x0401 || wchar == 0x0451)                 // CYRILLIC CAPITAL LETTER IO, CYRILLIC SMALL LETTER IO
+    {
+        return true;
+    }
+    return false;
+}
+
+/**
+ * @brief
+ *
+ * @param wchar
+ * @return bool
+ */
+inline bool isEastAsianCharacter(wchar_t wchar)
+{
+    if (wchar >= 0x1100 && wchar <= 0x11F9)                 // Hangul Jamo
+    {
+        return true;
+    }
+    if (wchar >= 0x3041 && wchar <= 0x30FF)                 // Hiragana + Katakana
+    {
+        return true;
+    }
+    if (wchar >= 0x3131 && wchar <= 0x318E)                 // Hangul Compatibility Jamo
+    {
+        return true;
+    }
+    if (wchar >= 0x31F0 && wchar <= 0x31FF)                 // Katakana Phonetic Ext.
+    {
+        return true;
+    }
+    if (wchar >= 0x3400 && wchar <= 0x4DB5)                 // CJK Ideographs Ext. A
+    {
+        return true;
+    }
+    if (wchar >= 0x4E00 && wchar <= 0x9FC3)                 // Unified CJK Ideographs
+    {
+        return true;
+    }
+    if (wchar >= 0xAC00 && wchar <= 0xD7A3)                 // Hangul Syllables
+    {
+        return true;
+    }
+    if (wchar >= 0xFF01 && wchar <= 0xFFEE)                 // Halfwidth forms
+    {
+        return true;
+    }
+    return false;
+}
+
+/**
+ * @brief
+ *
+ * @param c
+ * @return bool
+ */
+inline bool isWhiteSpace(char c)
+{
+    return ::isspace(int(c)) != 0;
+}
+
+/**
+ * @brief
+ *
+ * @param wchar
+ * @return bool
+ */
+inline bool isNumeric(wchar_t wchar)
+{
+    return (wchar >= L'0' && wchar <= L'9');
+}
+
+/**
+ * @brief
+ *
+ * @param c
+ * @return bool
+ */
+inline bool isNumeric(char c)
+{
+    return (c >= '0' && c <= '9');
+}
+
+/**
+ * @brief
+ *
+ * @param wchar
+ * @return bool
+ */
+inline bool isNumericOrSpace(wchar_t wchar)
+{
+    return isNumeric(wchar) || wchar == L' ';
+}
+
+/**
+ * @brief
+ *
+ * @param str
+ * @return bool
+ */
+inline bool isNumeric(char const* str)
+{
+    for (char const* c = str; *c; ++c)
+        if (!isNumeric(*c))
+        {
+            return false;
+        }
+
+    return true;
+}
+
+/**
+ * @brief
+ *
+ * @param str
+ * @return bool
+ */
+inline bool isNumeric(std::string const& str)
+{
+    for (std::string::const_iterator itr = str.begin(); itr != str.end(); ++itr)
+        if (!isNumeric(*itr))
+        {
+            return false;
+        }
+
+    return true;
+}
+
+/**
+ * @brief
+ *
+ * @param str
+ * @return bool
+ */
+inline bool isNumeric(std::wstring const& str)
+{
+    for (std::wstring::const_iterator itr = str.begin(); itr != str.end(); ++itr)
+        if (!isNumeric(*itr))
+        {
+            return false;
+        }
+
+    return true;
+}
+
+/**
+ * @brief
+ *
+ * @param wstr
+ * @param numericOrSpace
+ * @return bool
+ */
+inline bool isBasicLatinString(const std::wstring &wstr, bool numericOrSpace)
+{
+    for (size_t i = 0; i < wstr.size(); ++i)
+        if (!isBasicLatinCharacter(wstr[i]) && (!numericOrSpace || !isNumericOrSpace(wstr[i])))
+        {
+            return false;
+        }
+    return true;
+}
+
+/**
+ * @brief
+ *
+ * @param wstr
+ * @param numericOrSpace
+ * @return bool
+ */
+inline bool isExtendedLatinString(const std::wstring &wstr, bool numericOrSpace)
+{
+    for (size_t i = 0; i < wstr.size(); ++i)
+        if (!isExtendedLatinCharacter(wstr[i]) && (!numericOrSpace || !isNumericOrSpace(wstr[i])))
+        {
+            return false;
+        }
+    return true;
+}
+
+/**
+ * @brief
+ *
+ * @param wstr
+ * @param numericOrSpace
+ * @return bool
+ */
+inline bool isCyrillicString(const std::wstring &wstr, bool numericOrSpace)
+{
+    for (size_t i = 0; i < wstr.size(); ++i)
+        if (!isCyrillicCharacter(wstr[i]) && (!numericOrSpace || !isNumericOrSpace(wstr[i])))
+        {
+            return false;
+        }
+    return true;
+}
+
+/**
+ * @brief
+ *
+ * @param wstr
+ * @param numericOrSpace
+ * @return bool
+ */
+inline bool isEastAsianString(const std::wstring &wstr, bool numericOrSpace)
+{
+    for (size_t i = 0; i < wstr.size(); ++i)
+        if (!isEastAsianCharacter(wstr[i]) && (!numericOrSpace || !isNumericOrSpace(wstr[i])))
+        {
+            return false;
+        }
+    return true;
+}
+
+/**
+ * @brief
+ *
+ * @param str
+ */
+inline void strToUpper(std::string& str)
+{
+    std::transform(str.begin(), str.end(), str.begin(), [](unsigned char c) { return toupper(c); });
+}
+
+/**
+ * @brief
+ *
+ * @param str
+ */
+inline void strToLower(std::string& str)
+{
+    std::transform(str.begin(), str.end(), str.begin(), [](unsigned char c) { return tolower(c); });
+}
+
+/**
+ * @brief
+ *
+ * @param wchar
+ * @return wchar_t
+ */
+inline wchar_t wcharToUpper(wchar_t wchar)
+{
+    if (wchar >= L'a' && wchar <= L'z')                     // LATIN SMALL LETTER A - LATIN SMALL LETTER Z
+    {
+        return wchar_t(uint16(wchar) - 0x0020);
+    }
+    if (wchar == 0x00DF)                                    // LATIN SMALL LETTER SHARP S
+    {
+        return wchar_t(0x1E9E);
+    }
+    if (wchar >= 0x00E0 && wchar <= 0x00F6)                 // LATIN SMALL LETTER A WITH GRAVE - LATIN SMALL LETTER O WITH DIAERESIS
+    {
+        return wchar_t(uint16(wchar) - 0x0020);
+    }
+    if (wchar >= 0x00F8 && wchar <= 0x00FE)                 // LATIN SMALL LETTER O WITH STROKE - LATIN SMALL LETTER THORN
+    {
+        return wchar_t(uint16(wchar) - 0x0020);
+    }
+    if (wchar >= 0x0101 && wchar <= 0x012F)                 // LATIN SMALL LETTER A WITH MACRON - LATIN SMALL LETTER I WITH OGONEK (only %2=1)
+    {
+        if (wchar % 2 == 1)
+        {
+            return wchar_t(uint16(wchar) - 0x0001);
+        }
+    }
+    if (wchar >= 0x0430 && wchar <= 0x044F)                 // CYRILLIC SMALL LETTER A - CYRILLIC SMALL LETTER YA
+    {
+        return wchar_t(uint16(wchar) - 0x0020);
+    }
+    if (wchar == 0x0451)                                    // CYRILLIC SMALL LETTER IO
+    {
+        return wchar_t(0x0401);
+    }
+
+    return wchar;
+}
+
+/**
+ * @brief
+ *
+ * @param wchar
+ * @return wchar_t
+ */
+inline wchar_t wcharToUpperOnlyLatin(wchar_t wchar)
+{
+    return isBasicLatinCharacter(wchar) ? wcharToUpper(wchar) : wchar;
+}
+
+/**
+ * @brief
+ *
+ * @param wchar
+ * @return wchar_t
+ */
+inline wchar_t wcharToLower(wchar_t wchar)
+{
+    if (wchar >= L'A' && wchar <= L'Z')                     // LATIN CAPITAL LETTER A - LATIN CAPITAL LETTER Z
+    {
+        return wchar_t(uint16(wchar) + 0x0020);
+    }
+    if (wchar >= 0x00C0 && wchar <= 0x00D6)                 // LATIN CAPITAL LETTER A WITH GRAVE - LATIN CAPITAL LETTER O WITH DIAERESIS
+    {
+        return wchar_t(uint16(wchar) + 0x0020);
+    }
+    if (wchar >= 0x00D8 && wchar <= 0x00DE)                 // LATIN CAPITAL LETTER O WITH STROKE - LATIN CAPITAL LETTER THORN
+    {
+        return wchar_t(uint16(wchar) + 0x0020);
+    }
+    if (wchar >= 0x0100 && wchar <= 0x012E)                 // LATIN CAPITAL LETTER A WITH MACRON - LATIN CAPITAL LETTER I WITH OGONEK (only %2=0)
+    {
+        if (wchar % 2 == 0)
+        {
+            return wchar_t(uint16(wchar) + 0x0001);
+        }
+    }
+    if (wchar == 0x1E9E)                                    // LATIN CAPITAL LETTER SHARP S
+    {
+        return wchar_t(0x00DF);
+    }
+    if (wchar == 0x0401)                                    // CYRILLIC CAPITAL LETTER IO
+    {
+        return wchar_t(0x0451);
+    }
+    if (wchar >= 0x0410 && wchar <= 0x042F)                 // CYRILLIC CAPITAL LETTER A - CYRILLIC CAPITAL LETTER YA
+    {
+        return wchar_t(uint16(wchar) + 0x0020);
+    }
+
+    return wchar;
+}
+
+/**
+ * @brief
+ *
+ * @param str
+ */
+inline void wstrToUpper(std::wstring& str)
+{
+    std::transform(str.begin(), str.end(), str.begin(), [](wchar_t w) {return wcharToUpper(w); });
+}
+
+/**
+ * @brief
+ *
+ * @param str
+ */
+inline void wstrToLower(std::wstring& str)
+{
+    std::transform(str.begin(), str.end(), str.begin(), [](wchar_t w) {return wcharToLower(w); });
+}
+
+/**
+ * @brief
+ *
+ * @param utf8str
+ * @param conStr
+ * @return bool
+ */
+bool utf8ToConsole(const std::string& utf8str, std::string& conStr);
+/**
+ * @brief
+ *
+ * @param conStr
+ * @param utf8str
+ * @return bool
+ */
+bool consoleToUtf8(const std::string& conStr, std::string& utf8str);
+/**
+ * @brief
+ *
+ * @param str
+ * @param search
+ * @return bool
+ */
+bool Utf8FitTo(const std::string& str, std::wstring search);
+/**
+ * @brief
+ *
+ * @param out
+ * @param str...
+ */
+void utf8printf(FILE* out, const char* str, ...);
+/**
+ * @brief
+ *
+ * @param str
+ */
+void utf8print(void* /*arg*/, const char* str);
+/**
+ * @brief
+ *
+ * @param out
+ * @param str
+ * @param ap
+ */
+void vutf8printf(FILE* out, const char* str, va_list* ap);
+
+/**
+ * @brief
+ *
+ * @param ipaddress
+ * @return bool
+ */
+bool IsIPAddress(char const* ipaddress);
+
+/// Checks if address belongs to the a network with specified submask
+bool IsIPAddrInNetwork(ACE_INET_Addr const& net, ACE_INET_Addr const& addr, ACE_INET_Addr const& subnetMask);
+
+/// Transforms ACE_INET_Addr address into string format "dotted_ip:port"
+std::string GetAddressString(ACE_INET_Addr const& addr);
+
+/**
+ * @brief
+ *
+ * @param filename
+ * @return uint32
+ */
+uint32 CreatePIDFile(const std::string& filename);
+
+/**
+ * @brief
+ *
+ * @param bytes
+ * @param arrayLen
+ * @param result
+ */
+void hexEncodeByteArray(uint8* bytes, uint32 arrayLen, std::string& result);
+
+std::string ByteArrayToHexStr(uint8 const* bytes, uint32 length, bool reverse = false);
+void HexStrToByteArray(std::string const& str, uint8* out, bool reverse = false);
+
+/**
+* @brief Define iCoreNumber to be set for the currently defined core
+*
+* @return int
+*/
+int return_iCoreNumber();
+
+/**
+* @brief Display the startup banner
+*/
+void print_banner();
+#endif
diff --git a/shared/Utilities/WorldPacket.h b/shared/Utilities/WorldPacket.h
new file mode 100644
index 0000000..abf0b80
--- /dev/null
+++ b/shared/Utilities/WorldPacket.h
@@ -0,0 +1,99 @@
+/**
+ * MaNGOS is a full featured server for World of Warcraft, supporting
+ * the following clients: 1.12.x, 2.4.3, 3.3.5a, 4.3.4a and 5.4.8
+ *
+ * Copyright (C) 2005-2022 MaNGOS <https://getmangos.eu>
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * World of Warcraft, and all World of Warcraft or Warcraft art, images,
+ * and lore are copyrighted by Blizzard Entertainment, Inc.
+ */
+
+#ifndef MANGOSSERVER_WORLDPACKET_H
+#define MANGOSSERVER_WORLDPACKET_H
+
+#include "Common.h"
+#include "ByteBuffer.h"
+#include "Opcodes.h"
+
+// Note: m_opcode and size stored in platfom dependent format
+// ignore endianess until send, and converted at receive
+/**
+ * @brief
+ *
+ */
+class WorldPacket : public ByteBuffer
+{
+    public:
+        /**
+         * @brief just container for later use
+         *
+         */
+        WorldPacket() : ByteBuffer(0), m_opcode(MSG_NULL_ACTION)
+        {
+        }
+        /**
+         * @brief
+         *
+         * @param opcode
+         * @param res
+         */
+        explicit WorldPacket(uint16 opcode, size_t res = 200) : ByteBuffer(res), m_opcode(opcode) { }
+        /**
+         * @brief copy constructor
+         *
+         * @param packet
+         */
+        WorldPacket(const WorldPacket& packet) : ByteBuffer(packet), m_opcode(packet.m_opcode)
+        {
+        }
+
+        /**
+         * @brief
+         *
+         * @param opcode
+         * @param newres
+         */
+        void Initialize(uint16 opcode, size_t newres = 200)
+        {
+            clear();
+            _storage.reserve(newres);
+            m_opcode = opcode;
+        }
+
+        /**
+         * @brief
+         *
+         * @return uint16
+         */
+        uint16 GetOpcode() const { return m_opcode; }
+        /**
+         * @brief
+         *
+         * @param opcode
+         */
+        void SetOpcode(uint16 opcode) { m_opcode = opcode; }
+        /**
+         * @brief
+         *
+         * @return const char
+         */
+        inline const char* GetOpcodeName() const { return LookupOpcodeName(m_opcode); }
+
+    protected:
+        uint16 m_opcode; /**< TODO */
+};
+#endif
diff --git a/shared/Win/ServiceWin32.cpp b/shared/Win/ServiceWin32.cpp
new file mode 100644
index 0000000..fb1d4b8
--- /dev/null
+++ b/shared/Win/ServiceWin32.cpp
@@ -0,0 +1,302 @@
+/**
+ * MaNGOS is a full featured server for World of Warcraft, supporting
+ * the following clients: 1.12.x, 2.4.3, 3.3.5a, 4.3.4a and 5.4.8
+ *
+ * Copyright (C) 2005-2022 MaNGOS <https://getmangos.eu>
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * World of Warcraft, and all World of Warcraft or Warcraft art, images,
+ * and lore are copyrighted by Blizzard Entertainment, Inc.
+ */
+
+#ifdef WIN32
+
+#include "Common/Common.h"
+#include "Log/Log.h"
+#include <cstring>
+#include <windows.h>
+#include <winsvc.h>
+
+// stupid ACE define
+#ifdef main
+#undef main
+#endif
+
+#if !defined(WINADVAPI)
+#if !defined(_ADVAPI32_)
+#define WINADVAPI DECLSPEC_IMPORT
+#else
+#define WINADVAPI
+#endif
+
+#endif
+
+extern int main(int argc, char** argv);
+extern char serviceLongName[];
+extern char serviceName[];
+extern char serviceDescription[];
+
+extern int m_ServiceStatus;
+
+SERVICE_STATUS serviceStatus;
+
+SERVICE_STATUS_HANDLE serviceStatusHandle = 0;
+
+typedef WINADVAPI BOOL (WINAPI* CSD_T)(SC_HANDLE, DWORD, LPCVOID);
+
+bool WinServiceInstall()
+{
+    CSD_T ChangeService_Config2;
+    HMODULE advapi32;
+    SC_HANDLE serviceControlManager = OpenSCManager(0, 0, SC_MANAGER_CREATE_SERVICE);
+
+    if (!serviceControlManager)
+    {
+        sLog.outError("SERVICE: No access to service control manager.");
+        return false;
+    }
+
+    char path[_MAX_PATH + 10];
+    if (!GetModuleFileName(0, path, sizeof(path) / sizeof(path[0])))
+    {
+        CloseServiceHandle(serviceControlManager);
+        sLog.outError("SERVICE: Can't get service binary filename.");
+        return false;
+    }
+
+    std::strcat(path, " -s run");
+
+    SC_HANDLE service = CreateService(serviceControlManager,
+                                      serviceName,          // name of service
+                                      serviceLongName,      // service name to display
+                                      SERVICE_ALL_ACCESS,   // desired access
+                                      // service type
+                                      SERVICE_WIN32_OWN_PROCESS | SERVICE_INTERACTIVE_PROCESS,
+                                      SERVICE_AUTO_START,   // start type
+                                      SERVICE_ERROR_IGNORE, // error control type
+                                      path,                 // service's binary
+                                      0,                    // no load ordering group
+                                      0,                    // no tag identifier
+                                      0,                    // no dependencies
+                                      0,                    // LocalSystem account
+                                      0);                   // no password
+
+    if (!service)
+    {
+        CloseServiceHandle(serviceControlManager);
+        sLog.outError("SERVICE: Can't register service for: %s", path);
+        return false;
+    }
+
+    advapi32 = GetModuleHandle("ADVAPI32.DLL");
+    if (!advapi32)
+    {
+        sLog.outError("SERVICE: Can't access ADVAPI32.DLL");
+        CloseServiceHandle(service);
+        CloseServiceHandle(serviceControlManager);
+        return false;
+    }
+
+    ChangeService_Config2 = (CSD_T) GetProcAddress(advapi32, "ChangeServiceConfig2A");
+    if (!ChangeService_Config2)
+    {
+        sLog.outError("SERVICE: Can't access ChangeServiceConfig2A from ADVAPI32.DLL");
+        CloseServiceHandle(service);
+        CloseServiceHandle(serviceControlManager);
+        return false;
+    }
+
+    SERVICE_DESCRIPTION sdBuf;
+    sdBuf.lpDescription = serviceDescription;
+    ChangeService_Config2(
+        service,                                // handle to service
+        SERVICE_CONFIG_DESCRIPTION,             // change: description
+        &sdBuf);                                // new data
+
+    SC_ACTION _action[1];
+    _action[0].Type = SC_ACTION_RESTART;
+    _action[0].Delay = 10000;
+    SERVICE_FAILURE_ACTIONS sfa;
+    ZeroMemory(&sfa, sizeof(SERVICE_FAILURE_ACTIONS));
+    sfa.lpsaActions = _action;
+    sfa.cActions = 1;
+    sfa.dwResetPeriod = INFINITE;
+    ChangeService_Config2(
+        service,                                // handle to service
+        SERVICE_CONFIG_FAILURE_ACTIONS,         // information level
+        &sfa);                                  // new data
+
+    CloseServiceHandle(service);
+    CloseServiceHandle(serviceControlManager);
+    return true;
+}
+
+bool WinServiceUninstall()
+{
+    SC_HANDLE serviceControlManager = OpenSCManager(0, 0, SC_MANAGER_CONNECT);
+
+    if (!serviceControlManager)
+    {
+        sLog.outError("SERVICE: No access to service control manager.");
+        return false;
+    }
+
+    SC_HANDLE service = OpenService(serviceControlManager,
+                                    serviceName, SERVICE_QUERY_STATUS | DELETE);
+
+    if (!service)
+    {
+        CloseServiceHandle(serviceControlManager);
+        sLog.outError("SERVICE: Service not found: %s", serviceName);
+        return false;
+    }
+
+    SERVICE_STATUS serviceStatus2;
+    if (QueryServiceStatus(service, &serviceStatus2))
+    {
+        if (serviceStatus2.dwCurrentState == SERVICE_STOPPED)
+        {
+            DeleteService(service);
+        }
+    }
+
+    CloseServiceHandle(service);
+    CloseServiceHandle(serviceControlManager);
+    return true;
+}
+
+void WINAPI ServiceControlHandler(DWORD controlCode)
+{
+    switch (controlCode)
+    {
+        case SERVICE_CONTROL_INTERROGATE:
+            break;
+
+        case SERVICE_CONTROL_SHUTDOWN:
+        case SERVICE_CONTROL_STOP:
+            serviceStatus.dwCurrentState = SERVICE_STOP_PENDING;
+            SetServiceStatus(serviceStatusHandle, &serviceStatus);
+
+            m_ServiceStatus = 0;
+            return;
+
+        case SERVICE_CONTROL_PAUSE:
+            m_ServiceStatus = 2;
+            serviceStatus.dwCurrentState = SERVICE_PAUSED;
+            SetServiceStatus(serviceStatusHandle, &serviceStatus);
+            break;
+
+        case SERVICE_CONTROL_CONTINUE:
+            serviceStatus.dwCurrentState = SERVICE_RUNNING;
+            SetServiceStatus(serviceStatusHandle, &serviceStatus);
+            m_ServiceStatus = 1;
+            break;
+
+        default:
+            if (controlCode >= 128 && controlCode <= 255)
+                // user defined control code
+            {
+                break;
+            }
+            else
+                // unrecognized control code
+            {
+                break;
+            }
+    }
+
+    SetServiceStatus(serviceStatusHandle, &serviceStatus);
+}
+
+void WINAPI ServiceMain(DWORD argc, char* argv[])
+{
+    // initialise service status
+    serviceStatus.dwServiceType = SERVICE_WIN32;
+    serviceStatus.dwCurrentState = SERVICE_START_PENDING;
+    serviceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_PAUSE_CONTINUE;
+    serviceStatus.dwWin32ExitCode = NO_ERROR;
+    serviceStatus.dwServiceSpecificExitCode = NO_ERROR;
+    serviceStatus.dwCheckPoint = 0;
+    serviceStatus.dwWaitHint = 0;
+
+    serviceStatusHandle = RegisterServiceCtrlHandler(serviceName, ServiceControlHandler);
+
+    if (serviceStatusHandle)
+    {
+        char path[_MAX_PATH + 1];
+        unsigned int i, last_slash = 0;
+
+        GetModuleFileName(0, path, sizeof(path) / sizeof(path[0]));
+
+        for (i = 0; i < std::strlen(path); ++i)
+        {
+            if (path[i] == '\\')
+            {
+                last_slash = i;
+            }
+        }
+
+        path[last_slash] = 0;
+
+        // service is starting
+        serviceStatus.dwCurrentState = SERVICE_START_PENDING;
+        SetServiceStatus(serviceStatusHandle, &serviceStatus);
+
+        // do initialisation here
+        SetCurrentDirectory(path);
+
+        // running
+        serviceStatus.dwControlsAccepted |= (SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN);
+        serviceStatus.dwCurrentState = SERVICE_RUNNING;
+        SetServiceStatus(serviceStatusHandle, &serviceStatus);
+
+        ////////////////////////
+        // service main cycle //
+        ////////////////////////
+
+        m_ServiceStatus = 1;
+        argc = 1;
+        main(argc , argv);
+
+        // service was stopped
+        serviceStatus.dwCurrentState = SERVICE_STOP_PENDING;
+        SetServiceStatus(serviceStatusHandle, &serviceStatus);
+
+        // do cleanup here
+
+        // service is now stopped
+        serviceStatus.dwControlsAccepted &= ~(SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN);
+        serviceStatus.dwCurrentState = SERVICE_STOPPED;
+        SetServiceStatus(serviceStatusHandle, &serviceStatus);
+    }
+}
+
+bool WinServiceRun()
+{
+    SERVICE_TABLE_ENTRY serviceTable[] =
+    {
+        { serviceName, ServiceMain },
+        { 0, 0 }
+    };
+
+    if (!StartServiceCtrlDispatcher(serviceTable))
+    {
+        sLog.outError("StartService Failed. Error [%u]", ::GetLastError());
+        return false;
+    }
+    return true;
+}
+#endif
diff --git a/shared/Win/ServiceWin32.h b/shared/Win/ServiceWin32.h
new file mode 100644
index 0000000..793d1b3
--- /dev/null
+++ b/shared/Win/ServiceWin32.h
@@ -0,0 +1,35 @@
+/**
+ * MaNGOS is a full featured server for World of Warcraft, supporting
+ * the following clients: 1.12.x, 2.4.3, 3.3.5a, 4.3.4a and 5.4.8
+ *
+ * Copyright (C) 2005-2022 MaNGOS <https://getmangos.eu>
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * World of Warcraft, and all World of Warcraft or Warcraft art, images,
+ * and lore are copyrighted by Blizzard Entertainment, Inc.
+ */
+
+#ifdef WIN32
+#ifndef _WIN32_SERVICE_
+#define _WIN32_SERVICE_
+
+bool WinServiceInstall();
+bool WinServiceUninstall();
+bool WinServiceRun();
+
+#endif                                                      // _WIN32_SERVICE_
+
+#endif                                                      // WIN32
diff --git a/shared/Win/WheatyExceptionReport.cpp b/shared/Win/WheatyExceptionReport.cpp
new file mode 100644
index 0000000..d06653f
--- /dev/null
+++ b/shared/Win/WheatyExceptionReport.cpp
@@ -0,0 +1,989 @@
+//==========================================
+// Matt Pietrek
+// MSDN Magazine, 2002
+// FILE: WheatyExceptionReport.CPP
+//==========================================
+#define WIN32_LEAN_AND_MEAN
+#pragma warning(disable:4996)
+#pragma warning(disable:4312)
+#pragma warning(disable:4311)
+#include <windows.h>
+#include <tlhelp32.h>
+#include <stdio.h>
+#include <tchar.h>
+#define _NO_CVCONST_H
+#include <dbghelp.h>
+#include "WheatyExceptionReport.h"
+#include "GitRevision.h"
+#define CrashFolder _T("Crashes")
+//#pragma comment(linker, "/defaultlib:dbghelp.lib")
+
+inline LPTSTR ErrorMessage(DWORD dw)
+{
+    LPVOID lpMsgBuf;
+    FormatMessage(
+        FORMAT_MESSAGE_ALLOCATE_BUFFER |
+        FORMAT_MESSAGE_FROM_SYSTEM,
+        NULL,
+        dw,
+        MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
+        (LPTSTR) &lpMsgBuf,
+        0, NULL);
+    return (LPTSTR)lpMsgBuf;
+}
+
+//============================== Global Variables =============================
+
+//
+// Declare the static variables of the WheatyExceptionReport class
+//
+TCHAR WheatyExceptionReport::m_szLogFileName[MAX_PATH];
+LPTOP_LEVEL_EXCEPTION_FILTER WheatyExceptionReport::m_previousFilter;
+HANDLE WheatyExceptionReport::m_hReportFile;
+HANDLE WheatyExceptionReport::m_hProcess;
+
+// Declare global instance of class
+WheatyExceptionReport g_WheatyExceptionReport;
+
+//============================== Class Methods =============================
+
+WheatyExceptionReport::WheatyExceptionReport()              // Constructor
+{
+    // Install the unhandled exception filter function
+    m_previousFilter = SetUnhandledExceptionFilter(WheatyUnhandledExceptionFilter);
+    m_hProcess = GetCurrentProcess();
+}
+
+//============
+// Destructor
+//============
+WheatyExceptionReport::~WheatyExceptionReport()
+{
+    if (m_previousFilter)
+    {
+        SetUnhandledExceptionFilter(m_previousFilter);
+    }
+}
+
+//===========================================================
+// Entry point where control comes on an unhandled exception
+//===========================================================
+LONG WINAPI WheatyExceptionReport::WheatyUnhandledExceptionFilter(
+    PEXCEPTION_POINTERS pExceptionInfo)
+{
+    TCHAR module_folder_name[MAX_PATH];
+    GetModuleFileName(0, module_folder_name, MAX_PATH);
+    TCHAR* pos = _tcsrchr(module_folder_name, '\\');
+    if (!pos)
+    {
+        return 0;
+    }
+    pos[0] = '\0';
+    ++pos;
+
+    TCHAR crash_folder_path[MAX_PATH];
+    sprintf(crash_folder_path, "%s\\%s", module_folder_name, CrashFolder);
+    if (!CreateDirectory(crash_folder_path, NULL))
+    {
+        if (GetLastError() != ERROR_ALREADY_EXISTS)
+        {
+            return 0;
+        }
+    }
+
+    SYSTEMTIME systime;
+    GetLocalTime(&systime);
+    sprintf(m_szLogFileName, "%s\\%s_[%u-%u_%u-%u-%u].txt",
+            crash_folder_path, pos, systime.wDay, systime.wMonth, systime.wHour, systime.wMinute, systime.wSecond);
+
+    m_hReportFile = CreateFile(m_szLogFileName,
+                               GENERIC_WRITE,
+                               0,
+                               0,
+                               OPEN_ALWAYS,
+                               FILE_FLAG_WRITE_THROUGH,
+                               0);
+
+    if (m_hReportFile)
+    {
+        SetFilePointer(m_hReportFile, 0, 0, FILE_END);
+
+        GenerateExceptionReport(pExceptionInfo);
+
+        CloseHandle(m_hReportFile);
+        m_hReportFile = 0;
+    }
+
+    if (m_previousFilter)
+    {
+        return m_previousFilter(pExceptionInfo);
+    }
+    else
+    {
+        return EXCEPTION_EXECUTE_HANDLER/*EXCEPTION_CONTINUE_SEARCH*/;
+    }
+}
+
+BOOL WheatyExceptionReport::_GetProcessorName(TCHAR* sProcessorName, DWORD maxcount)
+{
+    if (!sProcessorName)
+    {
+        return FALSE;
+    }
+
+    HKEY hKey;
+    LONG lRet;
+    lRet = ::RegOpenKeyEx(HKEY_LOCAL_MACHINE, _T("HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0"),
+                          0, KEY_QUERY_VALUE, &hKey);
+    if (lRet != ERROR_SUCCESS)
+    {
+        return FALSE;
+    }
+    TCHAR szTmp[2048];
+    DWORD cntBytes = sizeof(szTmp);
+    lRet = ::RegQueryValueEx(hKey, _T("ProcessorNameString"), NULL, NULL,
+                             (LPBYTE)szTmp, &cntBytes);
+    if (lRet != ERROR_SUCCESS)
+    {
+        return FALSE;
+    }
+    ::RegCloseKey(hKey);
+    sProcessorName[0] = '\0';
+    // Skip spaces
+    TCHAR* psz = szTmp;
+    while (iswspace(*psz))
+    {
+        ++psz;
+    }
+    _tcsncpy(sProcessorName, psz, maxcount);
+    return TRUE;
+}
+
+BOOL WheatyExceptionReport::_GetWindowsVersion(TCHAR* szVersion, DWORD cntMax)
+{
+    // Try calling GetVersionEx using the OSVERSIONINFOEX structure.
+    // If that fails, try using the OSVERSIONINFO structure.
+    OSVERSIONINFOEX osvi = { 0 };
+    osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
+    BOOL bOsVersionInfoEx;
+    bOsVersionInfoEx = ::GetVersionEx((LPOSVERSIONINFO)(&osvi));
+    if (!bOsVersionInfoEx)
+    {
+        osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
+        if (!::GetVersionEx((OSVERSIONINFO*)&osvi))
+        {
+            return FALSE;
+        }
+    }
+    *szVersion = _T('\0');
+    TCHAR wszTmp[128];
+
+    // print version
+    switch (osvi.dwMajorVersion)
+    {
+        case 6:
+            switch (osvi.dwMinorVersion)
+            {
+                default: // 2
+                    if (osvi.wProductType == VER_NT_WORKSTATION)
+                    {
+                        _tcsncat(szVersion, _T("Windows 8 "), cntMax);
+                    }
+                    else
+                    {
+                        _tcsncat(szVersion, _T("Windows Server 2012 "), cntMax);
+                    }
+                    break;
+                case 1:
+                    if (osvi.wProductType == VER_NT_WORKSTATION)
+                    {
+                        _tcsncat(szVersion, _T("Windows 7 "), cntMax);
+                    }
+                    else
+                    {
+                        _tcsncat(szVersion, _T("Windows Server 2008 R2 "), cntMax);
+                    }
+                    break;
+                case 0:
+                    if (osvi.wProductType == VER_NT_WORKSTATION)
+                    {
+                        _tcsncat(szVersion, _T("Windows Vista "), cntMax);
+                    }
+                    else
+                    {
+                        _tcsncat(szVersion, _T("Windows Server 2008 "), cntMax);
+                    }
+                    break;
+            }
+            break;
+        case 5:
+            switch (osvi.dwMinorVersion)
+            {
+                default: // 2
+                    _tcsncat(szVersion, _T("Windows Server 2003 "), cntMax);
+                    break;
+                case 1:
+                    _tcsncat(szVersion, _T("Windows XP "), cntMax);
+                    break;
+                case 0:
+                    _tcsncat(szVersion, _T("Windows 2000 "), cntMax);
+                    break;
+            }
+            break;
+        default:
+            _tcsncat(szVersion, _T("Windows NT or lower "), cntMax);
+            break;
+    }
+
+    // print service pack if one is installed
+    if (_tcslen(osvi.szCSDVersion))
+        _stprintf(wszTmp, _T("%s (Version %d.%d, Build %d)"),
+                  osvi.szCSDVersion, osvi.dwMajorVersion, osvi.dwMinorVersion, osvi.dwBuildNumber & 0xFFFF);
+    else
+        _stprintf(wszTmp, _T("(Version %d.%d, Build %d)"),
+                  osvi.dwMajorVersion, osvi.dwMinorVersion, osvi.dwBuildNumber & 0xFFFF);
+
+    _tcsncat(szVersion, wszTmp, cntMax);
+
+    return TRUE;
+}
+
+void WheatyExceptionReport::PrintSystemInfo()
+{
+    SYSTEM_INFO SystemInfo;
+    ::GetSystemInfo(&SystemInfo);
+
+    MEMORYSTATUS MemoryStatus;
+    MemoryStatus.dwLength = sizeof(MEMORYSTATUS);
+    ::GlobalMemoryStatus(&MemoryStatus);
+    TCHAR sString[1024];
+    _tprintf(_T("//=====================================================\r\n"));
+    if (_GetProcessorName(sString, countof(sString)))
+        _tprintf(_T("*** Hardware ***\r\nProcessor: %s\r\nNumber Of Processors: %d\r\nPhysical Memory: %d KB (Available: %d KB)\r\nCommit Charge Limit: %d KB\r\n"),
+                 sString, SystemInfo.dwNumberOfProcessors, MemoryStatus.dwTotalPhys / 0x400, MemoryStatus.dwAvailPhys / 0x400, MemoryStatus.dwTotalPageFile / 0x400);
+    else
+        _tprintf(_T("*** Hardware ***\r\nProcessor: <unknown>\r\nNumber Of Processors: %d\r\nPhysical Memory: %d KB (Available: %d KB)\r\nCommit Charge Limit: %d KB\r\n"),
+                 SystemInfo.dwNumberOfProcessors, MemoryStatus.dwTotalPhys / 0x400, MemoryStatus.dwAvailPhys / 0x400, MemoryStatus.dwTotalPageFile / 0x400);
+
+    if (_GetWindowsVersion(sString, countof(sString)))
+    {
+        _tprintf(_T("\r\n*** Operation System ***\r\n%s\r\n"), sString);
+    }
+    else
+    {
+        _tprintf(_T("\r\n*** Operation System:\r\n<unknown>\r\n"));
+    }
+}
+
+//===========================================================================
+void WheatyExceptionReport::printTracesForAllThreads()
+{
+    HANDLE hThreadSnap = INVALID_HANDLE_VALUE;
+    THREADENTRY32 te32;
+
+    DWORD dwOwnerPID = GetCurrentProcessId();
+    m_hProcess = GetCurrentProcess();
+    // Take a snapshot of all running threads
+    hThreadSnap = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0);
+    if (hThreadSnap == INVALID_HANDLE_VALUE)
+    {
+        return;
+    }
+
+    // Fill in the size of the structure before using it.
+    te32.dwSize = sizeof(THREADENTRY32);
+
+    // Retrieve information about the first thread,
+    // and exit if unsuccessful
+    if (!Thread32First(hThreadSnap, &te32))
+    {
+        CloseHandle(hThreadSnap);      // Must clean up the
+        //   snapshot object!
+        return;
+    }
+
+    // Now walk the thread list of the system,
+    // and display information about each thread
+    // associated with the specified process
+    do
+    {
+        if (te32.th32OwnerProcessID == dwOwnerPID)
+        {
+            CONTEXT context;
+            context.ContextFlags = 0xffffffff;
+            HANDLE threadHandle = OpenThread(THREAD_GET_CONTEXT | THREAD_QUERY_INFORMATION, false, te32.th32ThreadID);
+            if (threadHandle && GetThreadContext(threadHandle, &context))
+            {
+                WriteStackDetails(&context, false, threadHandle);
+            }
+            CloseHandle(threadHandle);
+        }
+    }
+    while (Thread32Next(hThreadSnap, &te32));
+
+//  Don't forget to clean up the snapshot object.
+    CloseHandle(hThreadSnap);
+}
+
+//===========================================================================
+// Open the report file, and write the desired information to it.  Called by
+// WheatyUnhandledExceptionFilter
+//===========================================================================
+void WheatyExceptionReport::GenerateExceptionReport(
+    PEXCEPTION_POINTERS pExceptionInfo)
+{
+    SYSTEMTIME systime;
+    GetLocalTime(&systime);
+
+    // Start out with a banner
+    _tprintf(_T("Revision: %s\r\n"), GitRevision::GetProjectRevision());
+    _tprintf(_T("Date %u:%u:%u. Time %u:%u \r\n"), systime.wDay, systime.wMonth, systime.wYear, systime.wHour, systime.wMinute);
+    PEXCEPTION_RECORD pExceptionRecord = pExceptionInfo->ExceptionRecord;
+
+    PrintSystemInfo();
+    // First print information about the type of fault
+    _tprintf(_T("\r\n//=====================================================\r\n"));
+    _tprintf(_T("Exception code: %08X %s\r\n"),
+             pExceptionRecord->ExceptionCode,
+             GetExceptionString(pExceptionRecord->ExceptionCode));
+
+    // Now print information about where the fault occured
+    TCHAR szFaultingModule[MAX_PATH];
+    DWORD section;
+    DWORD_PTR offset;
+    GetLogicalAddress(pExceptionRecord->ExceptionAddress,
+                      szFaultingModule,
+                      sizeof(szFaultingModule),
+                      section, offset);
+
+#ifdef _M_IX86
+    _tprintf(_T("Fault address:  %08X %02X:%08X %s\r\n"),
+             pExceptionRecord->ExceptionAddress,
+             section, offset, szFaultingModule);
+#endif
+
+#ifdef _M_X64
+    _tprintf(_T("Fault address:  %016I64X %02X:%016I64X %s\r\n"),
+             pExceptionRecord->ExceptionAddress,
+             section, offset, szFaultingModule);
+#endif
+
+    PCONTEXT pCtx = pExceptionInfo->ContextRecord;
+
+    // Show the registers
+#ifdef _M_IX86                                          // X86 Only!
+    _tprintf(_T("\r\nRegisters:\r\n"));
+
+    _tprintf(_T("EAX:%08X\r\nEBX:%08X\r\nECX:%08X\r\nEDX:%08X\r\nESI:%08X\r\nEDI:%08X\r\n")
+             , pCtx->Eax, pCtx->Ebx, pCtx->Ecx, pCtx->Edx,
+             pCtx->Esi, pCtx->Edi);
+
+    _tprintf(_T("CS:EIP:%04X:%08X\r\n"), pCtx->SegCs, pCtx->Eip);
+    _tprintf(_T("SS:ESP:%04X:%08X  EBP:%08X\r\n"),
+             pCtx->SegSs, pCtx->Esp, pCtx->Ebp);
+    _tprintf(_T("DS:%04X  ES:%04X  FS:%04X  GS:%04X\r\n"),
+             pCtx->SegDs, pCtx->SegEs, pCtx->SegFs, pCtx->SegGs);
+    _tprintf(_T("Flags:%08X\r\n"), pCtx->EFlags);
+#endif
+
+#ifdef _M_X64
+    _tprintf(_T("\r\nRegisters:\r\n"));
+    _tprintf(_T("RAX:%016I64X\r\nRBX:%016I64X\r\nRCX:%016I64X\r\nRDX:%016I64X\r\nRSI:%016I64X\r\nRDI:%016I64X\r\n")
+             _T("R8: %016I64X\r\nR9: %016I64X\r\nR10:%016I64X\r\nR11:%016I64X\r\nR12:%016I64X\r\nR13:%016I64X\r\nR14:%016I64X\r\nR15:%016I64X\r\n")
+             , pCtx->Rax, pCtx->Rbx, pCtx->Rcx, pCtx->Rdx,
+             pCtx->Rsi, pCtx->Rdi , pCtx->R9, pCtx->R10, pCtx->R11, pCtx->R12, pCtx->R13, pCtx->R14, pCtx->R15);
+    _tprintf(_T("CS:RIP:%04X:%016I64X\r\n"), pCtx->SegCs, pCtx->Rip);
+    _tprintf(_T("SS:RSP:%04X:%016X  RBP:%08X\r\n"),
+             pCtx->SegSs, pCtx->Rsp, pCtx->Rbp);
+    _tprintf(_T("DS:%04X  ES:%04X  FS:%04X  GS:%04X\r\n"),
+             pCtx->SegDs, pCtx->SegEs, pCtx->SegFs, pCtx->SegGs);
+    _tprintf(_T("Flags:%08X\r\n"), pCtx->EFlags);
+#endif
+
+    SymSetOptions(SYMOPT_DEFERRED_LOADS);
+
+    // Initialize DbgHelp
+    if (!SymInitialize(GetCurrentProcess(), 0, TRUE))
+    {
+        _tprintf(_T("\n\rCRITICAL ERROR.\n\r Couldn't initialize the symbol handler for process.\n\rError [%s].\n\r\n\r"),
+                 ErrorMessage(GetLastError()));
+    }
+
+    CONTEXT trashableContext = *pCtx;
+
+    WriteStackDetails(&trashableContext, false, NULL);
+    printTracesForAllThreads();
+
+//    #ifdef _M_IX86                                        // X86 Only!
+
+    _tprintf(_T("========================\r\n"));
+    _tprintf(_T("Local Variables And Parameters\r\n"));
+
+    trashableContext = *pCtx;
+    WriteStackDetails(&trashableContext, true, NULL);
+
+    _tprintf(_T("========================\r\n"));
+    _tprintf(_T("Global Variables\r\n"));
+
+    SymEnumSymbols(GetCurrentProcess(),
+                   (DWORD64)GetModuleHandle(szFaultingModule),
+                   0, EnumerateSymbolsCallback, 0);
+    //  #endif                                              // X86 Only!
+
+    SymCleanup(GetCurrentProcess());
+
+    _tprintf(_T("\r\n"));
+}
+
+//======================================================================
+// Given an exception code, returns a pointer to a static string with a
+// description of the exception
+//======================================================================
+LPTSTR WheatyExceptionReport::GetExceptionString(DWORD dwCode)
+{
+#define EXCEPTION( x ) case EXCEPTION_##x: return _T(#x);
+
+    switch (dwCode)
+    {
+            EXCEPTION(ACCESS_VIOLATION)
+            EXCEPTION(DATATYPE_MISALIGNMENT)
+            EXCEPTION(BREAKPOINT)
+            EXCEPTION(SINGLE_STEP)
+            EXCEPTION(ARRAY_BOUNDS_EXCEEDED)
+            EXCEPTION(FLT_DENORMAL_OPERAND)
+            EXCEPTION(FLT_DIVIDE_BY_ZERO)
+            EXCEPTION(FLT_INEXACT_RESULT)
+            EXCEPTION(FLT_INVALID_OPERATION)
+            EXCEPTION(FLT_OVERFLOW)
+            EXCEPTION(FLT_STACK_CHECK)
+            EXCEPTION(FLT_UNDERFLOW)
+            EXCEPTION(INT_DIVIDE_BY_ZERO)
+            EXCEPTION(INT_OVERFLOW)
+            EXCEPTION(PRIV_INSTRUCTION)
+            EXCEPTION(IN_PAGE_ERROR)
+            EXCEPTION(ILLEGAL_INSTRUCTION)
+            EXCEPTION(NONCONTINUABLE_EXCEPTION)
+            EXCEPTION(STACK_OVERFLOW)
+            EXCEPTION(INVALID_DISPOSITION)
+            EXCEPTION(GUARD_PAGE)
+            EXCEPTION(INVALID_HANDLE)
+    }
+
+    // If not one of the "known" exceptions, try to get the string
+    // from NTDLL.DLL's message table.
+
+    static TCHAR szBuffer[512] = { 0 };
+
+    FormatMessage(FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_FROM_HMODULE,
+                  GetModuleHandle(_T("NTDLL.DLL")),
+                  dwCode, 0, szBuffer, sizeof(szBuffer), 0);
+
+    return szBuffer;
+}
+
+//=============================================================================
+// Given a linear address, locates the module, section, and offset containing
+// that address.
+//
+// Note: the szModule paramater buffer is an output buffer of length specified
+// by the len parameter (in characters!)
+//=============================================================================
+BOOL WheatyExceptionReport::GetLogicalAddress(
+    PVOID addr, PTSTR szModule, DWORD len, DWORD& section, DWORD_PTR& offset)
+{
+    MEMORY_BASIC_INFORMATION mbi;
+
+    if (!VirtualQuery(addr, &mbi, sizeof(mbi)))
+    {
+        return FALSE;
+    }
+
+    DWORD_PTR hMod = (DWORD_PTR)mbi.AllocationBase;
+
+    if (!GetModuleFileName((HMODULE)hMod, szModule, len))
+    {
+        return FALSE;
+    }
+
+    // Point to the DOS header in memory
+    PIMAGE_DOS_HEADER pDosHdr = (PIMAGE_DOS_HEADER)hMod;
+
+    // From the DOS header, find the NT (PE) header
+    PIMAGE_NT_HEADERS pNtHdr = (PIMAGE_NT_HEADERS)(hMod + DWORD_PTR(pDosHdr->e_lfanew));
+
+    PIMAGE_SECTION_HEADER pSection = IMAGE_FIRST_SECTION(pNtHdr);
+
+    DWORD_PTR rva = (DWORD_PTR)addr - hMod;                 // RVA is offset from module load address
+
+    // Iterate through the section table, looking for the one that encompasses
+    // the linear address.
+    for (unsigned i = 0; i < pNtHdr->FileHeader.NumberOfSections; ++i, ++pSection)
+    {
+        DWORD_PTR sectionStart = pSection->VirtualAddress;
+        DWORD_PTR sectionEnd = sectionStart
+                               + DWORD_PTR(max(pSection->SizeOfRawData, pSection->Misc.VirtualSize));
+
+        // Is the address in this section???
+        if ((rva >= sectionStart) && (rva <= sectionEnd))
+        {
+            // Yes, address is in the section.  Calculate section and offset,
+            // and store in the "section" & "offset" params, which were
+            // passed by reference.
+            section = i + 1;
+            offset = rva - sectionStart;
+            return TRUE;
+        }
+    }
+
+    return FALSE;                                           // Should never get here!
+}
+
+// It contains SYMBOL_INFO structure plus additional
+// space for the name of the symbol
+struct CSymbolInfoPackage : public SYMBOL_INFO_PACKAGE
+{
+    CSymbolInfoPackage()
+    {
+        si.SizeOfStruct = sizeof(SYMBOL_INFO);
+        si.MaxNameLen   = sizeof(name);
+    }
+};
+
+//============================================================
+// Walks the stack, and writes the results to the report file
+//============================================================
+void WheatyExceptionReport::WriteStackDetails(
+    PCONTEXT pContext,
+    bool bWriteVariables, HANDLE pThreadHandle)             // true if local/params should be output
+{
+    _tprintf(_T("\r\nCall stack:\r\n"));
+
+    _tprintf(_T("Address   Frame     Function      SourceFile\r\n"));
+
+    DWORD dwMachineType = 0;
+    // Could use SymSetOptions here to add the SYMOPT_DEFERRED_LOADS flag
+
+    STACKFRAME64 sf;
+    memset(&sf, 0, sizeof(sf));
+
+#ifdef _M_IX86
+    // Initialize the STACKFRAME structure for the first call.  This is only
+    // necessary for Intel CPUs, and isn't mentioned in the documentation.
+    sf.AddrPC.Offset       = pContext->Eip;
+    sf.AddrPC.Mode         = AddrModeFlat;
+    sf.AddrStack.Offset    = pContext->Esp;
+    sf.AddrStack.Mode      = AddrModeFlat;
+    sf.AddrFrame.Offset    = pContext->Ebp;
+    sf.AddrFrame.Mode      = AddrModeFlat;
+
+    dwMachineType = IMAGE_FILE_MACHINE_I386;
+#endif
+
+#ifdef _M_X64
+    sf.AddrPC.Offset    = pContext->Rip;
+    sf.AddrPC.Mode = AddrModeFlat;
+    sf.AddrStack.Offset    = pContext->Rsp;
+    sf.AddrStack.Mode      = AddrModeFlat;
+    sf.AddrFrame.Offset    = pContext->Rbp;
+    sf.AddrFrame.Mode      = AddrModeFlat;
+    dwMachineType = IMAGE_FILE_MACHINE_AMD64;
+#endif
+
+    while (1)
+    {
+        // Get the next stack frame
+        if (! StackWalk64(dwMachineType,
+                          m_hProcess,
+                          pThreadHandle != NULL ? pThreadHandle : GetCurrentThread(),
+                          &sf,
+                          pContext,
+                          0,
+                          SymFunctionTableAccess64,
+                          SymGetModuleBase64,
+                          0))
+        {
+            break;
+        }
+        if (0 == sf.AddrFrame.Offset)                       // Basic sanity check to make sure
+        {
+            break;                                           // the frame is OK.  Bail if not.
+        }
+#ifdef _M_IX86
+        _tprintf(_T("%08X  %08X  "), sf.AddrPC.Offset, sf.AddrFrame.Offset);
+#endif
+
+#ifdef _M_X64
+        _tprintf(_T("%016I64X  %016I64X  "), sf.AddrPC.Offset, sf.AddrFrame.Offset);
+#endif
+
+        DWORD64 symDisplacement = 0;                        // Displacement of the input address,
+        // relative to the start of the symbol
+
+        // Get the name of the function for this stack frame entry
+        CSymbolInfoPackage sip;
+        if (SymFromAddr(
+                m_hProcess,                             // Process handle of the current process
+                sf.AddrPC.Offset,                       // Symbol address
+                &symDisplacement,                       // Address of the variable that will receive the displacement
+                &sip.si))                               // Address of the SYMBOL_INFO structure (inside "sip" object)
+        {
+            _tprintf(_T("%hs+%I64X"), sip.si.Name, symDisplacement);
+        }
+        else                                                // No symbol found.  Print out the logical address instead.
+        {
+            TCHAR szModule[MAX_PATH] = _T("");
+            DWORD section = 0;
+            DWORD_PTR offset = 0;
+
+            GetLogicalAddress((PVOID)sf.AddrPC.Offset,
+                              szModule, sizeof(szModule), section, offset);
+#ifdef _M_IX86
+            _tprintf(_T("%04X:%08X %s"), section, offset, szModule);
+#endif
+
+#ifdef _M_X64
+            _tprintf(_T("%04X:%016I64X %s"), section, offset, szModule);
+#endif
+
+        }
+
+        // Get the source line for this stack frame entry
+        IMAGEHLP_LINE64 lineInfo = { sizeof(IMAGEHLP_LINE) };
+        DWORD dwLineDisplacement;
+        if (SymGetLineFromAddr64(m_hProcess, sf.AddrPC.Offset,
+                                 &dwLineDisplacement, &lineInfo))
+        {
+            _tprintf(_T("  %s line %u"), lineInfo.FileName, lineInfo.LineNumber);
+        }
+
+        _tprintf(_T("\r\n"));
+
+        // Write out the variables, if desired
+        if (bWriteVariables)
+        {
+            // Use SymSetContext to get just the locals/params for this frame
+            IMAGEHLP_STACK_FRAME imagehlpStackFrame;
+            imagehlpStackFrame.InstructionOffset = sf.AddrPC.Offset;
+            SymSetContext(m_hProcess, &imagehlpStackFrame, 0);
+
+            // Enumerate the locals/parameters
+            SymEnumSymbols(m_hProcess, 0, 0, EnumerateSymbolsCallback, &sf);
+
+            _tprintf(_T("\r\n"));
+        }
+    }
+}
+
+//////////////////////////////////////////////////////////////////////////////
+// The function invoked by SymEnumSymbols
+//////////////////////////////////////////////////////////////////////////////
+
+BOOL CALLBACK
+WheatyExceptionReport::EnumerateSymbolsCallback(
+    PSYMBOL_INFO  pSymInfo,
+    ULONG         SymbolSize,
+    PVOID         UserContext)
+{
+    char szBuffer[2048];
+
+    __try
+    {
+        if (FormatSymbolValue(pSymInfo, (STACKFRAME*)UserContext,
+        szBuffer, sizeof(szBuffer)))
+        {
+            _tprintf(_T("\t%s\r\n"), szBuffer);
+        }
+    }
+    __except(1)
+    {
+        _tprintf(_T("punting on symbol %s\r\n"), pSymInfo->Name);
+    }
+
+    return TRUE;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+// Given a SYMBOL_INFO representing a particular variable, displays its
+// contents.  If it's a user defined type, display the members and their
+// values.
+//////////////////////////////////////////////////////////////////////////////
+bool WheatyExceptionReport::FormatSymbolValue(
+    PSYMBOL_INFO pSym,
+    STACKFRAME* sf,
+    char* pszBuffer,
+    unsigned cbBuffer)
+{
+    char* pszCurrBuffer = pszBuffer;
+
+    // Indicate if the variable is a local or parameter
+    if (pSym->Flags & IMAGEHLP_SYMBOL_INFO_PARAMETER)
+    {
+        pszCurrBuffer += sprintf(pszCurrBuffer, "Parameter ");
+    }
+    else if (pSym->Flags & IMAGEHLP_SYMBOL_INFO_LOCAL)
+    {
+        pszCurrBuffer += sprintf(pszCurrBuffer, "Local ");
+    }
+
+    // If it's a function, don't do anything.
+    if (pSym->Tag == 5)                                     // SymTagFunction from CVCONST.H from the DIA SDK
+    {
+        return false;
+    }
+
+    DWORD_PTR pVariable = 0;                                // Will point to the variable's data in memory
+
+    if (pSym->Flags & IMAGEHLP_SYMBOL_INFO_REGRELATIVE)
+    {
+        // if ( pSym->Register == 8 )   // EBP is the value 8 (in DBGHELP 5.1)
+        {
+            //  This may change!!!
+            pVariable = sf->AddrFrame.Offset;
+            pVariable += (DWORD_PTR)pSym->Address;
+        }
+        // else
+        //  return false;
+    }
+    else if (pSym->Flags & IMAGEHLP_SYMBOL_INFO_REGISTER)
+    {
+        return false;                                       // Don't try to report register variable
+    }
+    else
+    {
+        pVariable = (DWORD_PTR)pSym->Address;               // It must be a global variable
+    }
+
+    // Determine if the variable is a user defined type (UDT).  IF so, bHandled
+    // will return true.
+    bool bHandled;
+    pszCurrBuffer = DumpTypeIndex(pszCurrBuffer, pSym->ModBase, pSym->TypeIndex,
+                                  0, pVariable, bHandled, pSym->Name);
+
+    if (!bHandled)
+    {
+        // The symbol wasn't a UDT, so do basic, stupid formatting of the
+        // variable.  Based on the size, we're assuming it's a char, WORD, or
+        // DWORD.
+        BasicType basicType = GetBasicType(pSym->TypeIndex, pSym->ModBase);
+        pszCurrBuffer += sprintf(pszCurrBuffer, rgBaseType[basicType]);
+
+        // Emit the variable name
+        pszCurrBuffer += sprintf(pszCurrBuffer, "\'%s\'", pSym->Name);
+
+        pszCurrBuffer = FormatOutputValue(pszCurrBuffer, basicType, pSym->Size,
+                                          (PVOID)pVariable);
+    }
+
+    return true;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+// If it's a user defined type (UDT), recurse through its members until we're
+// at fundamental types.  When he hit fundamental types, return
+// bHandled = false, so that FormatSymbolValue() will format them.
+//////////////////////////////////////////////////////////////////////////////
+char* WheatyExceptionReport::DumpTypeIndex(
+    char* pszCurrBuffer,
+    DWORD64 modBase,
+    DWORD dwTypeIndex,
+    unsigned nestingLevel,
+    DWORD_PTR offset,
+    bool& bHandled,
+    char* Name)
+{
+    bHandled = false;
+
+    // Get the name of the symbol.  This will either be a Type name (if a UDT),
+    // or the structure member name.
+    WCHAR* pwszTypeName;
+    if (SymGetTypeInfo(m_hProcess, modBase, dwTypeIndex, TI_GET_SYMNAME,
+                       &pwszTypeName))
+    {
+        pszCurrBuffer += sprintf(pszCurrBuffer, " %ls", pwszTypeName);
+        LocalFree(pwszTypeName);
+    }
+
+    // Determine how many children this type has.
+    DWORD dwChildrenCount = 0;
+    SymGetTypeInfo(m_hProcess, modBase, dwTypeIndex, TI_GET_CHILDRENCOUNT,
+                   &dwChildrenCount);
+
+    if (!dwChildrenCount)                                   // If no children, we're done
+    {
+        return pszCurrBuffer;
+    }
+
+    // Prepare to get an array of "TypeIds", representing each of the children.
+    // SymGetTypeInfo(TI_FINDCHILDREN) expects more memory than just a
+    // TI_FINDCHILDREN_PARAMS struct has.  Use derivation to accomplish this.
+    struct FINDCHILDREN : TI_FINDCHILDREN_PARAMS
+    {
+        ULONG   MoreChildIds[1024];
+        FINDCHILDREN() {Count = sizeof(MoreChildIds) / sizeof(MoreChildIds[0]);}
+    } children;
+
+    children.Count = dwChildrenCount;
+    children.Start = 0;
+
+    // Get the array of TypeIds, one for each child type
+    if (!SymGetTypeInfo(m_hProcess, modBase, dwTypeIndex, TI_FINDCHILDREN,
+                        &children))
+    {
+        return pszCurrBuffer;
+    }
+
+    // Append a line feed
+    pszCurrBuffer += sprintf(pszCurrBuffer, "\r\n");
+
+    // Iterate through each of the children
+    for (unsigned i = 0; i < dwChildrenCount; ++i)
+    {
+        // Add appropriate indentation level (since this routine is recursive)
+        for (unsigned j = 0; j <= nestingLevel + 1; ++j)
+        {
+            pszCurrBuffer += sprintf(pszCurrBuffer, "\t");
+        }
+
+        // Recurse for each of the child types
+        bool bHandled2;
+        BasicType basicType = GetBasicType(children.ChildId[i], modBase);
+        pszCurrBuffer += sprintf(pszCurrBuffer, rgBaseType[basicType]);
+
+        pszCurrBuffer = DumpTypeIndex(pszCurrBuffer, modBase,
+                                      children.ChildId[i], nestingLevel + 1,
+                                      offset, bHandled2, ""/*Name */);
+
+        // If the child wasn't a UDT, format it appropriately
+        if (!bHandled2)
+        {
+            // Get the offset of the child member, relative to its parent
+            DWORD dwMemberOffset;
+            SymGetTypeInfo(m_hProcess, modBase, children.ChildId[i],
+                           TI_GET_OFFSET, &dwMemberOffset);
+
+            // Get the real "TypeId" of the child.  We need this for the
+            // SymGetTypeInfo( TI_GET_TYPEID ) call below.
+            DWORD typeId;
+            SymGetTypeInfo(m_hProcess, modBase, children.ChildId[i],
+                           TI_GET_TYPEID, &typeId);
+
+            // Get the size of the child member
+            ULONG64 length;
+            SymGetTypeInfo(m_hProcess, modBase, typeId, TI_GET_LENGTH, &length);
+
+            // Calculate the address of the member
+            DWORD_PTR dwFinalOffset = offset + dwMemberOffset;
+
+            //             BasicType basicType = GetBasicType(children.ChildId[i], modBase );
+            //
+            //          pszCurrBuffer += sprintf( pszCurrBuffer, rgBaseType[basicType]);
+            //
+            // Emit the variable name
+            //          pszCurrBuffer += sprintf( pszCurrBuffer, "\'%s\'", Name );
+
+            pszCurrBuffer = FormatOutputValue(pszCurrBuffer, basicType,
+                                              length, (PVOID)dwFinalOffset);
+
+            pszCurrBuffer += sprintf(pszCurrBuffer, "\r\n");
+        }
+    }
+
+    bHandled = true;
+    return pszCurrBuffer;
+}
+
+char* WheatyExceptionReport::FormatOutputValue(char* pszCurrBuffer,
+        BasicType basicType,
+        DWORD64 length,
+        PVOID pAddress)
+{
+    // Format appropriately (assuming it's a 1, 2, or 4 bytes (!!!)
+    if (length == 1)
+    {
+        pszCurrBuffer += sprintf(pszCurrBuffer, " = %X", *(PBYTE)pAddress);
+    }
+    else if (length == 2)
+    {
+        pszCurrBuffer += sprintf(pszCurrBuffer, " = %X", *(PWORD)pAddress);
+    }
+    else if (length == 4)
+    {
+        if (basicType == btFloat)
+        {
+            pszCurrBuffer += sprintf(pszCurrBuffer, " = %f", *(PFLOAT)pAddress);
+        }
+        else if (basicType == btChar)
+        {
+            if (!IsBadStringPtr(*(PSTR*)pAddress, 32))
+            {
+                pszCurrBuffer += sprintf(pszCurrBuffer, " = \"%.31s\"",
+                                         *(PDWORD)pAddress);
+            }
+            else
+                pszCurrBuffer += sprintf(pszCurrBuffer, " = %X",
+                                         *(PDWORD)pAddress);
+        }
+        else
+        {
+            pszCurrBuffer += sprintf(pszCurrBuffer, " = %X", *(PDWORD)pAddress);
+        }
+    }
+    else if (length == 8)
+    {
+        if (basicType == btFloat)
+        {
+            pszCurrBuffer += sprintf(pszCurrBuffer, " = %lf",
+                                     *(double*)pAddress);
+        }
+        else
+            pszCurrBuffer += sprintf(pszCurrBuffer, " = %I64X",
+                                     *(DWORD64*)pAddress);
+    }
+
+    return pszCurrBuffer;
+}
+
+BasicType
+WheatyExceptionReport::GetBasicType(DWORD typeIndex, DWORD64 modBase)
+{
+    BasicType basicType;
+    if (SymGetTypeInfo(m_hProcess, modBase, typeIndex,
+                       TI_GET_BASETYPE, &basicType))
+    {
+        return basicType;
+    }
+
+    // Get the real "TypeId" of the child.  We need this for the
+    // SymGetTypeInfo( TI_GET_TYPEID ) call below.
+    DWORD typeId;
+    if (SymGetTypeInfo(m_hProcess, modBase, typeIndex, TI_GET_TYPEID, &typeId))
+    {
+        if (SymGetTypeInfo(m_hProcess, modBase, typeId, TI_GET_BASETYPE,
+                           &basicType))
+        {
+            return basicType;
+        }
+    }
+
+    return btNoType;
+}
+
+//============================================================================
+// Helper function that writes to the report file, and allows the user to use
+// printf style formating
+//============================================================================
+int __cdecl WheatyExceptionReport::_tprintf(const TCHAR* format, ...)
+{
+    TCHAR szBuff[1024];
+    int retValue;
+    DWORD cbWritten;
+    va_list argptr;
+
+    va_start(argptr, format);
+    retValue = vsprintf(szBuff, format, argptr);
+    va_end(argptr);
+
+    WriteFile(m_hReportFile, szBuff, retValue * sizeof(TCHAR), &cbWritten, 0);
+
+    return retValue;
+}
diff --git a/shared/Win/WheatyExceptionReport.h b/shared/Win/WheatyExceptionReport.h
new file mode 100644
index 0000000..166d26b
--- /dev/null
+++ b/shared/Win/WheatyExceptionReport.h
@@ -0,0 +1,141 @@
+/**
+ * MaNGOS is a full featured server for World of Warcraft, supporting
+ * the following clients: 1.12.x, 2.4.3, 3.3.5a, 4.3.4a and 5.4.8
+ *
+ * Copyright (C) 2005-2022 MaNGOS <https://getmangos.eu>
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * World of Warcraft, and all World of Warcraft or Warcraft art, images,
+ * and lore are copyrighted by Blizzard Entertainment, Inc.
+ */
+
+#ifndef _WHEATYEXCEPTIONREPORT_
+#define _WHEATYEXCEPTIONREPORT_
+
+#include <dbghelp.h>
+
+#if _MSC_VER < 1400
+#   define countof(array)   (sizeof(array) / sizeof(array[0]))
+#else
+#   include <stdlib.h>
+#   define countof  _countof
+#endif                                                      // _MSC_VER < 1400
+
+enum BasicType                                              // Stolen from CVCONST.H in the DIA 2.0 SDK
+{
+    btNoType = 0,
+    btVoid = 1,
+    btChar = 2,
+    btWChar = 3,
+    btInt = 6,
+    btUInt = 7,
+    btFloat = 8,
+    btBCD = 9,
+    btBool = 10,
+    btLong = 13,
+    btULong = 14,
+    btCurrency = 25,
+    btDate = 26,
+    btVariant = 27,
+    btComplex = 28,
+    btBit = 29,
+    btBSTR = 30,
+    btHresult = 31
+};
+
+const char* const rgBaseType[] =
+{
+    " <user defined> ",                                     // btNoType = 0,
+    " void ",                                               // btVoid = 1,
+    " char* ",                                              // btChar = 2,
+    " wchar_t* ",                                           // btWChar = 3,
+    " signed char ",
+    " unsigned char ",
+    " int ",                                                // btInt = 6,
+    " unsigned int ",                                       // btUInt = 7,
+    " float ",                                              // btFloat = 8,
+    " <BCD> ",                                              // btBCD = 9,
+    " bool ",                                               // btBool = 10,
+    " short ",
+    " unsigned short ",
+    " long ",                                               // btLong = 13,
+    " unsigned long ",                                      // btULong = 14,
+    " __int8 ",
+    " __int16 ",
+    " __int32 ",
+    " __int64 ",
+    " __int128 ",
+    " unsigned __int8 ",
+    " unsigned __int16 ",
+    " unsigned __int32 ",
+    " unsigned __int64 ",
+    " unsigned __int128 ",
+    " <currency> ",                                         // btCurrency = 25,
+    " <date> ",                                             // btDate = 26,
+    " VARIANT ",                                            // btVariant = 27,
+    " <complex> ",                                          // btComplex = 28,
+    " <bit> ",                                              // btBit = 29,
+    " BSTR ",                                               // btBSTR = 30,
+    " HRESULT "                                             // btHresult = 31
+};
+
+class WheatyExceptionReport
+{
+    public:
+
+        WheatyExceptionReport();
+        ~WheatyExceptionReport();
+
+        // entry point where control comes on an unhandled exception
+        static LONG WINAPI WheatyUnhandledExceptionFilter(
+            PEXCEPTION_POINTERS pExceptionInfo);
+
+        static void printTracesForAllThreads();
+    private:
+        // where report info is extracted and generated
+        static void GenerateExceptionReport(PEXCEPTION_POINTERS pExceptionInfo);
+        static void PrintSystemInfo();
+        static BOOL _GetWindowsVersion(TCHAR* szVersion, DWORD cntMax);
+        static BOOL _GetProcessorName(TCHAR* sProcessorName, DWORD maxcount);
+
+        // Helper functions
+        static LPTSTR GetExceptionString(DWORD dwCode);
+        static BOOL GetLogicalAddress(PVOID addr, PTSTR szModule, DWORD len,
+                                      DWORD& section, DWORD_PTR& offset);
+
+        static void WriteStackDetails(PCONTEXT pContext, bool bWriteVariables, HANDLE pThreadHandle);
+
+        static BOOL CALLBACK EnumerateSymbolsCallback(PSYMBOL_INFO, ULONG, PVOID);
+
+        static bool FormatSymbolValue(PSYMBOL_INFO, STACKFRAME*, char* pszBuffer, unsigned cbBuffer);
+
+        static char* DumpTypeIndex(char*, DWORD64, DWORD, unsigned, DWORD_PTR, bool& , char*);
+
+        static char* FormatOutputValue(char* pszCurrBuffer, BasicType basicType, DWORD64 length, PVOID pAddress);
+
+        static BasicType GetBasicType(DWORD typeIndex, DWORD64 modBase);
+
+        static int __cdecl _tprintf(const TCHAR* format, ...);
+
+        // Variables used by the class
+        static TCHAR m_szLogFileName[MAX_PATH];
+        static LPTOP_LEVEL_EXCEPTION_FILTER m_previousFilter;
+        static HANDLE m_hReportFile;
+        static HANDLE m_hProcess;
+};
+
+extern WheatyExceptionReport g_WheatyExceptionReport;       //  global instance of class
+#endif                                                      // WheatyExceptionReport
diff --git a/shared/revision_data.h.in b/shared/revision_data.h.in
new file mode 100644
index 0000000..fce13ee
--- /dev/null
+++ b/shared/revision_data.h.in
@@ -0,0 +1,57 @@
+/**
+ * MaNGOS is a full featured server for World of Warcraft, supporting
+ * the following clients: 1.12.x, 2.4.3, 3.3.5a, 4.3.4a and 5.4.8
+ *
+ * Copyright (C) 2005-2022 MaNGOS <https://getmangos.eu>
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * World of Warcraft, and all World of Warcraft or Warcraft art, images,
+ * and lore are copyrighted by Blizzard Entertainment, Inc.
+ */
+
+#ifndef REVISION_DATA_H
+#define REVISION_DATA_H
+    #define REVISION_HASH               "@rev_hash@"
+    #define REVISION_DATE               "@rev_date@"
+    #define REVISION_BRANCH             "@rev_branch@"
+
+    #define CMAKE_VERSION               R"(@CMAKE_VERSION@)"
+    #define CMAKE_HOST_SYSTEM           R"(@CMAKE_HOST_SYSTEM_NAME@ @CMAKE_HOST_SYSTEM_VERSION@)"
+
+    #define PROJECT_REVISION_NR "2201075"
+
+    #define REALMD_DB_VERSION_NR        "22"
+    #define REALMD_DB_STRUCTURE_NR      "1"
+    #define REALMD_DB_CONTENT_NR        "1"
+    #define REALMD_DB_UPDATE_DESCRIPT   "Release 22"
+
+    #define CHAR_DB_VERSION_NR          "22"
+    #define CHAR_DB_STRUCTURE_NR        "2"
+    #define CHAR_DB_CONTENT_NR          "1"
+    #define CHAR_DB_UPDATE_DESCRIPT     "add_character_createdDate_col"
+
+    #define WORLD_DB_VERSION_NR         "22"
+    #define WORLD_DB_STRUCTURE_NR       "4"
+    #define WORLD_DB_CONTENT_NR         "2"
+    #define WORLD_DB_UPDATE_DESCRIPT    "Update_conditions_comments"
+
+    #define VER_COMPANY_NAME_STR        "MaNGOS Developers"
+    #define VER_LEGALCOPYRIGHT_STR      "(c)2005-@rev_year@ MaNGOS"
+    #define VER_FILEVERSION             0,0,0
+    #define VER_FILEVERSION_STR         "@rev_hash@ @rev_date@ (@rev_branch@ branch)"
+    #define VER_PRODUCTVERSION          VER_FILEVERSION
+    #define VER_PRODUCTVERSION_STR      VER_FILEVERSION_STR
+#endif
-- 
2.38.1

