mirror of
https://github.com/DarkflameUniverse/DarkflameServer
synced 2024-08-30 18:43:58 +00:00
feat: Improve console output to show packet enum names (magic_enum) (#1344)
* add enum stringification functionality from third party source
* squashed commit
* Macros: Add test and improve speed
Space macros out
utilize cache locality
ensure no lost functionality
* moved stringify code to dCommon
* Rename #defines in stringify enum tests
* Revert "moved stringify code to dCommon"
This reverts commit 33fa5f8d2f
.
* improve macro functionality
change function handle
formatting and function definition tweaks
* typo fixes
* moved code to dCommon/dEnums and tests to dCommonTests/dEnumsTests
* initial magic_enums alternate implementation of enum stringification
* deleted unused tests
* reverted compile flag oopsy and fixed output types
* fixed testing suite
* test formatting improvement
* formatting again :(
* added gm string to "aborting gm!" message
* Push my suggestion for CI tests.
* updated magic enum test
* fix test variable type
* added gm test
* making sure magic_enum is on a release branch
* tidying up console outputs
* re-implemented enum array access for performance
* now it is bugged :(
* nvm, working
* helping out the snowflake compilers
* changed return type too
* optimization too
* formatting too I guess because why not
* being even more painfully specific
* Update WorldServer.cpp to match emo's feedback
* Update MagicEnumTests.cpp to use srand(time(NULL))
* Update eGameMessageType.h - formatting
* Trying to fix the crash but can't actually compile the code to check on my own rn
* Update WorldServer.cpp - third try at this
* Update MagicEnumTests.cpp - use better macro definitions
* Update MagicEnumTests.cpp - c string comparison fix
* addressing all but the cmake feedback
* fixed cmake to the best of my very limited ability
* added tests to verify magic enum arrays are pre-sorted
* updated
---------
Co-authored-by: David Markowitz <EmosewaMC@gmail.com>
Co-authored-by: Jettford <mrjettbradford@gmail.com>
This commit is contained in:
parent
c1e8546d48
commit
fcf4d6c6fa
3
.gitmodules
vendored
3
.gitmodules
vendored
@ -17,3 +17,6 @@
|
||||
[submodule "thirdparty/AccountManager"]
|
||||
path = thirdparty/AccountManager
|
||||
url = https://github.com/DarkflameUniverse/AccountManager
|
||||
[submodule "thirdparty/magic_enum"]
|
||||
path = thirdparty/magic_enum
|
||||
url = https://github.com/Neargye/magic_enum.git
|
||||
|
@ -293,6 +293,7 @@ set(INCLUDED_DIRECTORIES
|
||||
"dScripts/zone/PROPERTY/GF"
|
||||
"dScripts/zone/PROPERTY/NS"
|
||||
|
||||
"thirdparty/magic_enum/include/magic_enum"
|
||||
"thirdparty/raknet/Source"
|
||||
"thirdparty/tinyxml2"
|
||||
"thirdparty/recastnavigation"
|
||||
@ -374,7 +375,7 @@ add_subdirectory(dNavigation)
|
||||
add_subdirectory(dPhysics)
|
||||
|
||||
# Create a list of common libraries shared between all binaries
|
||||
set(COMMON_LIBRARIES "dCommon" "dDatabase" "dNet" "raknet" "mariadbConnCpp")
|
||||
set(COMMON_LIBRARIES "dCommon" "dDatabase" "dNet" "raknet" "mariadbConnCpp" "magic_enum")
|
||||
|
||||
# Add platform specific common libraries
|
||||
if (UNIX)
|
||||
|
29
dCommon/dEnums/StringifiedEnum.h
Normal file
29
dCommon/dEnums/StringifiedEnum.h
Normal file
@ -0,0 +1,29 @@
|
||||
#ifndef __STRINGIFIEDENUM_H__
|
||||
#define __STRINGIFIEDENUM_H__
|
||||
|
||||
#include <string>
|
||||
#include "magic_enum.hpp"
|
||||
|
||||
namespace StringifiedEnum {
|
||||
template<typename T>
|
||||
const std::string_view ToString(const T e) {
|
||||
constexpr auto sv = &magic_enum::enum_entries<T>();
|
||||
std::string_view output;
|
||||
|
||||
const auto it = std::lower_bound(
|
||||
sv->begin(), sv->end(), e,
|
||||
[&](const std::pair<T, std::string_view>& lhs, const T rhs)
|
||||
{ return lhs.first < rhs; }
|
||||
);
|
||||
|
||||
if (it != sv->end() && it->first == e) {
|
||||
output = it->second;
|
||||
}
|
||||
else {
|
||||
output = "UNKNOWN";
|
||||
}
|
||||
return output;
|
||||
}
|
||||
}
|
||||
|
||||
#endif // !__STRINGIFIEDENUM_H__
|
File diff suppressed because it is too large
Load Diff
@ -3,6 +3,8 @@
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
#include "magic_enum.hpp"
|
||||
|
||||
enum class eWorldMessageType : uint32_t {
|
||||
VALIDATION = 1, // Session info
|
||||
CHARACTER_LIST_REQUEST,
|
||||
@ -40,4 +42,10 @@ enum class eWorldMessageType : uint32_t {
|
||||
UI_HELP_TOP_5 = 91
|
||||
};
|
||||
|
||||
template <>
|
||||
struct magic_enum::customize::enum_range<eWorldMessageType> {
|
||||
static constexpr int min = 0;
|
||||
static constexpr int max = 91;
|
||||
};
|
||||
|
||||
#endif //!__EWORLDMESSAGETYPE__H__
|
||||
|
@ -34,10 +34,10 @@
|
||||
#include "eMissionTaskType.h"
|
||||
#include "eReplicaComponentType.h"
|
||||
#include "eConnectionType.h"
|
||||
#include "eGameMessageType.h"
|
||||
#include "ePlayerFlag.h"
|
||||
#include "dConfig.h"
|
||||
|
||||
using namespace std;
|
||||
#include "StringifiedEnum.h"
|
||||
|
||||
void GameMessageHandler::HandleMessage(RakNet::BitStream* inStream, const SystemAddress& sysAddr, LWOOBJID objectID, eGameMessageType messageID) {
|
||||
|
||||
@ -49,11 +49,11 @@ void GameMessageHandler::HandleMessage(RakNet::BitStream* inStream, const System
|
||||
User* usr = UserManager::Instance()->GetUser(sysAddr);
|
||||
|
||||
if (!entity) {
|
||||
LOG("Failed to find associated entity (%llu), aborting GM (%X)!", objectID, messageID);
|
||||
LOG("Failed to find associated entity (%llu), aborting GM: %4i, %s!", objectID, messageID, StringifiedEnum::ToString(messageID).data());
|
||||
return;
|
||||
}
|
||||
|
||||
if (messageID != eGameMessageType::READY_FOR_UPDATES) LOG_DEBUG("received game message ID: %i", messageID);
|
||||
if (messageID != eGameMessageType::READY_FOR_UPDATES) LOG_DEBUG("Received GM with ID and name: %4i, %s", messageID, StringifiedEnum::ToString(messageID).data());
|
||||
|
||||
switch (messageID) {
|
||||
|
||||
@ -344,12 +344,12 @@ void GameMessageHandler::HandleMessage(RakNet::BitStream* inStream, const System
|
||||
|
||||
SyncSkill sync = SyncSkill(inStream); // inStream replaced &bitStream
|
||||
|
||||
ostringstream buffer;
|
||||
std::ostringstream buffer;
|
||||
|
||||
for (unsigned int k = 0; k < sync.sBitStream.size(); k++) {
|
||||
char s;
|
||||
s = sync.sBitStream.at(k);
|
||||
buffer << setw(2) << hex << setfill('0') << (int)s << " ";
|
||||
buffer << std::setw(2) << std::hex << std::setfill('0') << static_cast<int>(s) << " ";
|
||||
}
|
||||
|
||||
if (usr != nullptr) {
|
||||
@ -694,7 +694,7 @@ void GameMessageHandler::HandleMessage(RakNet::BitStream* inStream, const System
|
||||
GameMessages::SendVendorStatusUpdate(entity, sysAddr, true);
|
||||
break;
|
||||
default:
|
||||
LOG_DEBUG("Unknown game message ID: %i", messageID);
|
||||
LOG_DEBUG("Received Unknown GM with ID: %4i, %s", messageID, StringifiedEnum::ToString(messageID).data());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -19,8 +19,7 @@
|
||||
#include "Logger.h"
|
||||
#include "GameMessages.h"
|
||||
#include "CDClientDatabase.h"
|
||||
|
||||
enum class eGameMessageType : uint16_t;
|
||||
#include "eGameMessageType.h"
|
||||
|
||||
namespace GameMessageHandler {
|
||||
void HandleMessage(RakNet::BitStream* inStream, const SystemAddress& sysAddr, LWOOBJID objectID, eGameMessageType messageID);
|
||||
|
@ -76,6 +76,7 @@
|
||||
#include "EntityManager.h"
|
||||
#include "CheatDetection.h"
|
||||
#include "eGameMasterLevel.h"
|
||||
#include "StringifiedEnum.h"
|
||||
|
||||
namespace Game {
|
||||
Logger* logger = nullptr;
|
||||
@ -1244,7 +1245,9 @@ void HandlePacket(Packet* packet) {
|
||||
}
|
||||
|
||||
default:
|
||||
LOG("Unknown world packet received: %i", int(packet->data[3]));
|
||||
const auto messageId = *reinterpret_cast<eWorldMessageType*>(&packet->data[3]);
|
||||
const std::string_view messageIdString = StringifiedEnum::ToString(messageId);
|
||||
LOG("Unknown world packet received: %4i, %s", messageId, messageIdString.data());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -11,6 +11,9 @@ set(DCOMMONTEST_SOURCES
|
||||
"dCommonDependencies.cpp"
|
||||
)
|
||||
|
||||
add_subdirectory(dEnumsTests)
|
||||
list(APPEND DCOMMONTEST_SOURCES ${DENUMS_TESTS})
|
||||
|
||||
# Set our executable
|
||||
add_executable(dCommonTests ${DCOMMONTEST_SOURCES})
|
||||
|
||||
|
10
tests/dCommonTests/dEnumsTests/CMakeLists.txt
Normal file
10
tests/dCommonTests/dEnumsTests/CMakeLists.txt
Normal file
@ -0,0 +1,10 @@
|
||||
set(DENUMS_TESTS
|
||||
"MagicEnumTests.cpp"
|
||||
)
|
||||
|
||||
# Get the folder name and prepend it to the files above
|
||||
get_filename_component(thisFolderName ${CMAKE_CURRENT_SOURCE_DIR} NAME)
|
||||
list(TRANSFORM DENUMS_TESTS PREPEND "${thisFolderName}/")
|
||||
|
||||
# Export to parent scope
|
||||
set(DENUMS_TESTS ${DENUMS_TESTS} PARENT_SCOPE)
|
142
tests/dCommonTests/dEnumsTests/MagicEnumTests.cpp
Normal file
142
tests/dCommonTests/dEnumsTests/MagicEnumTests.cpp
Normal file
@ -0,0 +1,142 @@
|
||||
#include <chrono>
|
||||
#include <string>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include "StringifiedEnum.h"
|
||||
#include "Logger.h"
|
||||
#include "Game.h"
|
||||
#include "eGameMessageType.h"
|
||||
#include "eWorldMessageType.h"
|
||||
#include "magic_enum.hpp"
|
||||
|
||||
#define ENUM_EQ(e, y, z)\
|
||||
LOG("%s %s", StringifiedEnum::ToString(static_cast<e>(y)).data(), #z);\
|
||||
ASSERT_STREQ(StringifiedEnum::ToString(static_cast<e>(y)).data(), #z);
|
||||
|
||||
#define ENUM_NE(e, y)\
|
||||
ENUM_EQ(e, y, UNKNOWN);
|
||||
|
||||
// Test World Message Enum Reflection
|
||||
TEST(MagicEnumTest, eWorldMessageTypeTest) {
|
||||
Game::logger = new Logger("./MagicEnumTest_eWorldMessageTypeTest.log", true, true);
|
||||
|
||||
ENUM_EQ(eWorldMessageType, 1, VALIDATION);
|
||||
ENUM_EQ(eWorldMessageType, 2, CHARACTER_LIST_REQUEST);
|
||||
ENUM_EQ(eWorldMessageType, 3, CHARACTER_CREATE_REQUEST);
|
||||
ENUM_EQ(eWorldMessageType, 4, LOGIN_REQUEST);
|
||||
ENUM_EQ(eWorldMessageType, 5, GAME_MSG);
|
||||
ENUM_EQ(eWorldMessageType, 6, CHARACTER_DELETE_REQUEST);
|
||||
ENUM_EQ(eWorldMessageType, 7, CHARACTER_RENAME_REQUEST);
|
||||
ENUM_EQ(eWorldMessageType, 8, HAPPY_FLOWER_MODE_NOTIFY);
|
||||
ENUM_EQ(eWorldMessageType, 9, SLASH_RELOAD_MAP);
|
||||
ENUM_EQ(eWorldMessageType, 10, SLASH_PUSH_MAP_REQUEST);
|
||||
ENUM_EQ(eWorldMessageType, 11, SLASH_PUSH_MAP);
|
||||
ENUM_EQ(eWorldMessageType, 12, SLASH_PULL_MAP);
|
||||
ENUM_EQ(eWorldMessageType, 13, LOCK_MAP_REQUEST);
|
||||
ENUM_EQ(eWorldMessageType, 14, GENERAL_CHAT_MESSAGE);
|
||||
ENUM_EQ(eWorldMessageType, 15, HTTP_MONITOR_INFO_REQUEST);
|
||||
ENUM_EQ(eWorldMessageType, 16, SLASH_DEBUG_SCRIPTS);
|
||||
ENUM_EQ(eWorldMessageType, 17, MODELS_CLEAR);
|
||||
ENUM_EQ(eWorldMessageType, 18, EXHIBIT_INSERT_MODEL);
|
||||
ENUM_EQ(eWorldMessageType, 19, LEVEL_LOAD_COMPLETE);
|
||||
ENUM_EQ(eWorldMessageType, 20, TMP_GUILD_CREATE);
|
||||
ENUM_EQ(eWorldMessageType, 21, ROUTE_PACKET);
|
||||
ENUM_EQ(eWorldMessageType, 22, POSITION_UPDATE);
|
||||
ENUM_EQ(eWorldMessageType, 23, MAIL);
|
||||
ENUM_EQ(eWorldMessageType, 24, WORD_CHECK);
|
||||
ENUM_EQ(eWorldMessageType, 25, STRING_CHECK);
|
||||
ENUM_EQ(eWorldMessageType, 26, GET_PLAYERS_IN_ZONE);
|
||||
ENUM_EQ(eWorldMessageType, 27, REQUEST_UGC_MANIFEST_INFO);
|
||||
ENUM_EQ(eWorldMessageType, 28, BLUEPRINT_GET_ALL_DATA_REQUEST);
|
||||
ENUM_EQ(eWorldMessageType, 29, CANCEL_MAP_QUEUE);
|
||||
ENUM_EQ(eWorldMessageType, 30, HANDLE_FUNNESS);
|
||||
ENUM_EQ(eWorldMessageType, 31, FAKE_PRG_CSR_MESSAGE);
|
||||
ENUM_EQ(eWorldMessageType, 32, REQUEST_FREE_TRIAL_REFRESH);
|
||||
ENUM_EQ(eWorldMessageType, 33, GM_SET_FREE_TRIAL_STATUS);
|
||||
ENUM_EQ(eWorldMessageType, 91, UI_HELP_TOP_5);
|
||||
ENUM_NE(eWorldMessageType, 37);
|
||||
ENUM_NE(eWorldMessageType, 123);
|
||||
|
||||
srand(time(NULL));
|
||||
auto begin = std::chrono::high_resolution_clock::now();
|
||||
for (int i = 0; i < 10000000; ++i) {
|
||||
volatile auto f = StringifiedEnum::ToString(static_cast<eWorldMessageType>(i)).data();
|
||||
|
||||
// To ensure the compiler doesn't optimize out the call, I print it at random intervals
|
||||
if (rand() % 100000 == 0) LOG("%i, %s", i, f);
|
||||
}
|
||||
auto end = std::chrono::high_resolution_clock::now();
|
||||
LOG("Time: %lld", std::chrono::duration_cast<std::chrono::microseconds>(end - begin).count());
|
||||
|
||||
delete Game::logger;
|
||||
}
|
||||
|
||||
// Test Game Message Enum Reflection
|
||||
TEST(MagicEnumTest, eGameMessageTypeTest) {
|
||||
|
||||
Game::logger = new Logger("./MagicEnumTest_eGameMessageTypeTest.log", true, true);
|
||||
|
||||
// Only doing the first and last 10 for the sake of my sanity
|
||||
ENUM_EQ(eGameMessageType, 0, GET_POSITION);
|
||||
ENUM_EQ(eGameMessageType, 1, GET_ROTATION);
|
||||
ENUM_EQ(eGameMessageType, 2, GET_LINEAR_VELOCITY);
|
||||
ENUM_EQ(eGameMessageType, 3, GET_ANGULAR_VELOCITY);
|
||||
ENUM_EQ(eGameMessageType, 4, GET_FORWARD_VELOCITY);
|
||||
ENUM_EQ(eGameMessageType, 5, GET_PLAYER_FORWARD);
|
||||
ENUM_EQ(eGameMessageType, 6, GET_FORWARD_VECTOR);
|
||||
ENUM_EQ(eGameMessageType, 7, SET_POSITION);
|
||||
ENUM_EQ(eGameMessageType, 8, SET_LOCAL_POSITION);
|
||||
ENUM_EQ(eGameMessageType, 9, SET_ROTATION);
|
||||
ENUM_EQ(eGameMessageType, 10, SET_LINEAR_VELOCITY);
|
||||
ENUM_EQ(eGameMessageType, 1762, USE_SKILL_SET);
|
||||
ENUM_EQ(eGameMessageType, 1763, SET_SKILL_SET_POSSESSOR);
|
||||
ENUM_EQ(eGameMessageType, 1764, POPULATE_ACTION_BAR);
|
||||
ENUM_EQ(eGameMessageType, 1765, GET_COMPONENT_TEMPLATE_ID);
|
||||
ENUM_EQ(eGameMessageType, 1766, GET_POSSESSABLE_SKILL_SET);
|
||||
ENUM_EQ(eGameMessageType, 1767, MARK_INVENTORY_ITEM_AS_ACTIVE);
|
||||
ENUM_EQ(eGameMessageType, 1768, UPDATE_FORGED_ITEM);
|
||||
ENUM_EQ(eGameMessageType, 1769, CAN_ITEMS_BE_REFORGED);
|
||||
ENUM_EQ(eGameMessageType, 1771, NOTIFY_CLIENT_RAIL_START_FAILED);
|
||||
ENUM_EQ(eGameMessageType, 1772, GET_IS_ON_RAIL);
|
||||
ENUM_NE(eGameMessageType, 32);
|
||||
ENUM_NE(eGameMessageType, 1776);
|
||||
|
||||
srand(time(NULL));
|
||||
auto begin = std::chrono::high_resolution_clock::now();
|
||||
for (int i = 0; i < 10000000; ++i) {
|
||||
volatile auto f = StringifiedEnum::ToString(static_cast<eGameMessageType>(i)).data();
|
||||
|
||||
// To ensure the compiler doesn't optimize out the call, I print it at random intervals
|
||||
if (rand() % 100000 == 0) LOG("%i, %s", i, f);
|
||||
}
|
||||
auto end = std::chrono::high_resolution_clock::now();
|
||||
LOG("Time: %lld", std::chrono::duration_cast<std::chrono::microseconds>(end - begin).count());
|
||||
|
||||
delete Game::logger;
|
||||
}
|
||||
|
||||
#define ASSERT_EARRAY_SORTED(EARRAY_VAR)\
|
||||
for (int i = 0; i < EARRAY_VAR->size(); i++) {\
|
||||
const auto entryCurr = EARRAY_VAR->at(i).first;\
|
||||
LOG_EARRAY(EARRAY_VAR, i, entryCurr);\
|
||||
const auto entryNext = EARRAY_VAR->at(++i).first;\
|
||||
LOG_EARRAY(EARRAY_VAR, i, entryNext);\
|
||||
ASSERT_TRUE(entryCurr < entryNext);\
|
||||
};\
|
||||
|
||||
#define LOG_EARRAY(EARRAY_VAR, INDICE, ENTRY)\
|
||||
LOG(#EARRAY_VAR"[%i] = %i, %s", INDICE, ENTRY, magic_enum::enum_name(ENTRY).data());
|
||||
|
||||
// Test that the magic enum arrays are pre-sorted
|
||||
TEST(MagicEnumTest, ArraysAreSorted) {
|
||||
Game::logger = new Logger("./MagicEnumTest_ArraysAreSorted.log", true, true);
|
||||
|
||||
constexpr auto wmArray = &magic_enum::enum_entries<eWorldMessageType>();
|
||||
ASSERT_EARRAY_SORTED(wmArray);
|
||||
|
||||
constexpr auto gmArray = &magic_enum::enum_entries<eGameMessageType>();
|
||||
ASSERT_EARRAY_SORTED(gmArray);
|
||||
|
||||
delete Game::logger;
|
||||
}
|
3
thirdparty/CMakeLists.txt
vendored
3
thirdparty/CMakeLists.txt
vendored
@ -19,6 +19,9 @@ add_library(bcrypt ${SOURCES_LIBBCRYPT})
|
||||
# Source code for sqlite
|
||||
add_subdirectory(SQLite)
|
||||
|
||||
# Source code for magic_enum
|
||||
add_subdirectory(magic_enum)
|
||||
|
||||
# MariaDB C++ Connector
|
||||
include(CMakeMariaDBLists.txt)
|
||||
|
||||
|
1
thirdparty/magic_enum
vendored
Submodule
1
thirdparty/magic_enum
vendored
Submodule
@ -0,0 +1 @@
|
||||
Subproject commit e55b9b54d5cf61f8e117cafb17846d7d742dd3b4
|
Loading…
Reference in New Issue
Block a user